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);
3609 d.animate = false; // do not animate progress, as it may not have finished animating before we close it..
3611 this.updateProgress(0);
3612 activeTextEl.dom.value = opt.value || "";
3614 dlg.setDefaultButton(activeTextEl);
3616 var bs = opt.buttons;
3620 }else if(bs && bs.yes){
3621 db = buttons["yes"];
3623 dlg.setDefaultButton(db);
3625 bwidth = updateButtons(opt.buttons);
3626 this.updateText(opt.msg);
3628 d.el.addClass(opt.cls);
3630 d.proxyDrag = opt.proxyDrag === true;
3631 d.modal = opt.modal !== false;
3632 d.mask = opt.modal !== false ? mask : false;
3634 // force it to the end of the z-index stack so it gets a cursor in FF
3635 document.body.appendChild(dlg.el.dom);
3636 d.animateTarget = null;
3637 d.show(options.animEl);
3643 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
3644 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
3645 * and closing the message box when the process is complete.
3646 * @param {String} title The title bar text
3647 * @param {String} msg The message box body text
3648 * @return {Roo.MessageBox} This message box
3650 progress : function(title, msg){
3657 minWidth: this.minProgressWidth,
3664 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
3665 * If a callback function is passed it will be called after the user clicks the button, and the
3666 * id of the button that was clicked will be passed as the only parameter to the callback
3667 * (could also be the top-right close button).
3668 * @param {String} title The title bar text
3669 * @param {String} msg The message box body text
3670 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3671 * @param {Object} scope (optional) The scope of the callback function
3672 * @return {Roo.MessageBox} This message box
3674 alert : function(title, msg, fn, scope)
3689 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
3690 * interaction while waiting for a long-running process to complete that does not have defined intervals.
3691 * You are responsible for closing the message box when the process is complete.
3692 * @param {String} msg The message box body text
3693 * @param {String} title (optional) The title bar text
3694 * @return {Roo.MessageBox} This message box
3696 wait : function(msg, title){
3707 waitTimer = Roo.TaskMgr.start({
3709 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
3717 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
3718 * If a callback function is passed it will be called after the user clicks either button, and the id of the
3719 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
3720 * @param {String} title The title bar text
3721 * @param {String} msg The message box body text
3722 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3723 * @param {Object} scope (optional) The scope of the callback function
3724 * @return {Roo.MessageBox} This message box
3726 confirm : function(title, msg, fn, scope){
3730 buttons: this.YESNO,
3739 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
3740 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
3741 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
3742 * (could also be the top-right close button) and the text that was entered will be passed as the two
3743 * parameters to the callback.
3744 * @param {String} title The title bar text
3745 * @param {String} msg The message box body text
3746 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3747 * @param {Object} scope (optional) The scope of the callback function
3748 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
3749 * property, or the height in pixels to create the textbox (defaults to false / single-line)
3750 * @return {Roo.MessageBox} This message box
3752 prompt : function(title, msg, fn, scope, multiline){
3756 buttons: this.OKCANCEL,
3761 multiline: multiline,
3768 * Button config that displays a single OK button
3773 * Button config that displays Yes and No buttons
3776 YESNO : {yes:true, no:true},
3778 * Button config that displays OK and Cancel buttons
3781 OKCANCEL : {ok:true, cancel:true},
3783 * Button config that displays Yes, No and Cancel buttons
3786 YESNOCANCEL : {yes:true, no:true, cancel:true},
3789 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3792 defaultTextHeight : 75,
3794 * The maximum width in pixels of the message box (defaults to 600)
3799 * The minimum width in pixels of the message box (defaults to 100)
3804 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3805 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3808 minProgressWidth : 250,
3810 * An object containing the default button text strings that can be overriden for localized language support.
3811 * Supported properties are: ok, cancel, yes and no.
3812 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3825 * Shorthand for {@link Roo.MessageBox}
3827 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3828 Roo.Msg = Roo.Msg || Roo.MessageBox;
3837 * @class Roo.bootstrap.Navbar
3838 * @extends Roo.bootstrap.Component
3839 * Bootstrap Navbar class
3842 * Create a new Navbar
3843 * @param {Object} config The config object
3847 Roo.bootstrap.Navbar = function(config){
3848 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3852 * @event beforetoggle
3853 * Fire before toggle the menu
3854 * @param {Roo.EventObject} e
3856 "beforetoggle" : true
3860 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3869 getAutoCreate : function(){
3872 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3876 initEvents :function ()
3878 //Roo.log(this.el.select('.navbar-toggle',true));
3879 this.el.select('.navbar-toggle',true).on('click', function() {
3880 if(this.fireEvent('beforetoggle', this) !== false){
3881 var ce = this.el.select('.navbar-collapse',true).first();
3882 ce.toggleClass('in'); // old...
3883 if (ce.hasClass('collapse')) {
3885 ce.removeClass('collapse');
3886 ce.addClass('show');
3887 var h = ce.getHeight();
3889 ce.removeClass('show');
3890 // at this point we should be able to see it..
3891 ce.addClass('collapsing');
3893 ce.setHeight(0); // resize it ...
3894 ce.on('transitionend', function() {
3895 Roo.log('done transition');
3896 ce.removeClass('collapsing');
3897 ce.addClass('show');
3898 ce.removeClass('collapse');
3900 ce.dom.style.height = '';
3901 }, this, { single: true} );
3905 ce.setHeight(ce.getHeight());
3906 ce.removeClass('show');
3907 ce.addClass('collapsing');
3909 ce.on('transitionend', function() {
3910 ce.dom.style.height = '';
3911 ce.removeClass('collapsing');
3912 ce.addClass('collapse');
3913 }, this, { single: true} );
3925 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3927 var size = this.el.getSize();
3928 this.maskEl.setSize(size.width, size.height);
3929 this.maskEl.enableDisplayMode("block");
3938 getChildContainer : function()
3940 if (this.el.select('.collapse').getCount()) {
3941 return this.el.select('.collapse',true).first();
3974 * @class Roo.bootstrap.NavSimplebar
3975 * @extends Roo.bootstrap.Navbar
3976 * Bootstrap Sidebar class
3978 * @cfg {Boolean} inverse is inverted color
3980 * @cfg {String} type (nav | pills | tabs)
3981 * @cfg {Boolean} arrangement stacked | justified
3982 * @cfg {String} align (left | right) alignment
3984 * @cfg {Boolean} main (true|false) main nav bar? default false
3985 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3987 * @cfg {String} tag (header|footer|nav|div) default is nav
3989 * @cfg {String} weight (light|primary|secondary|success|danger|warning|info|dark|white) default is light.
3993 * Create a new Sidebar
3994 * @param {Object} config The config object
3998 Roo.bootstrap.NavSimplebar = function(config){
3999 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
4002 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
4018 getAutoCreate : function(){
4022 tag : this.tag || 'div',
4023 cls : 'navbar navbar-expand-lg roo-navbar-simple'
4025 if (['light','white'].indexOf(this.weight) > -1) {
4026 cfg.cls += ['light','white'].indexOf(this.weight) > -1 ? ' navbar-light' : ' navbar-dark';
4028 cfg.cls += ' bg-' + this.weight;
4031 cfg.cls += ' navbar-inverse';
4035 // i'm not actually sure these are really used - normally we add a navGroup to a navbar
4037 //if (Roo.bootstrap.version == 4) {
4049 this.type = this.type || 'nav';
4050 if (['tabs','pills'].indexOf(this.type) != -1) {
4051 cfg.cn[0].cls += ' nav-' + this.type
4055 if (this.type!=='nav') {
4056 Roo.log('nav type must be nav/tabs/pills')
4058 cfg.cn[0].cls += ' navbar-nav'
4064 if (['stacked','justified'].indexOf(this.arrangement) != -1) {
4065 cfg.cn[0].cls += ' nav-' + this.arrangement;
4069 if (this.align === 'right') {
4070 cfg.cn[0].cls += ' navbar-right';
4095 * navbar-expand-md fixed-top
4099 * @class Roo.bootstrap.NavHeaderbar
4100 * @extends Roo.bootstrap.NavSimplebar
4101 * Bootstrap Sidebar class
4103 * @cfg {String} brand what is brand
4104 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
4105 * @cfg {String} brand_href href of the brand
4106 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
4107 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
4108 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
4109 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
4112 * Create a new Sidebar
4113 * @param {Object} config The config object
4117 Roo.bootstrap.NavHeaderbar = function(config){
4118 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
4122 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
4129 desktopCenter : false,
4132 getAutoCreate : function(){
4135 tag: this.nav || 'nav',
4136 cls: 'navbar navbar-expand-md',
4142 if (this.desktopCenter) {
4143 cn.push({cls : 'container', cn : []});
4151 cls: 'navbar-toggle navbar-toggler',
4152 'data-toggle': 'collapse',
4157 html: 'Toggle navigation'
4161 cls: 'icon-bar navbar-toggler-icon'
4174 cn.push( Roo.bootstrap.version == 4 ? btn : {
4176 cls: 'navbar-header',
4185 cls: 'collapse navbar-collapse',
4189 cfg.cls += this.inverse ? ' navbar-inverse navbar-dark bg-dark' : ' navbar-default';
4191 if (['light','white'].indexOf(this.weight) > -1) {
4192 cfg.cls += ['light','white'].indexOf(this.weight) > -1 ? ' navbar-light' : ' navbar-dark';
4194 cfg.cls += ' bg-' + this.weight;
4197 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
4198 cfg.cls += ' navbar-' + this.position + ' ' + this.position ;
4200 // tag can override this..
4202 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
4205 if (this.brand !== '') {
4206 var cp = Roo.bootstrap.version == 4 ? cn : cn[0].cn;
4207 cp.unshift({ // changed from push ?? BS4 needs it at the start? - does this break or exsiting?
4209 href: this.brand_href ? this.brand_href : '#',
4210 cls: 'navbar-brand',
4218 cfg.cls += ' main-nav';
4226 getHeaderChildContainer : function()
4228 if (this.srButton && this.el.select('.navbar-header').getCount()) {
4229 return this.el.select('.navbar-header',true).first();
4232 return this.getChildContainer();
4236 initEvents : function()
4238 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
4240 if (this.autohide) {
4245 Roo.get(document).on('scroll',function(e) {
4246 var ns = Roo.get(document).getScroll().top;
4247 var os = prevScroll;
4251 ft.removeClass('slideDown');
4252 ft.addClass('slideUp');
4255 ft.removeClass('slideUp');
4256 ft.addClass('slideDown');
4277 * @class Roo.bootstrap.NavSidebar
4278 * @extends Roo.bootstrap.Navbar
4279 * Bootstrap Sidebar class
4282 * Create a new Sidebar
4283 * @param {Object} config The config object
4287 Roo.bootstrap.NavSidebar = function(config){
4288 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
4291 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
4293 sidebar : true, // used by Navbar Item and NavbarGroup at present...
4295 getAutoCreate : function(){
4300 cls: 'sidebar sidebar-nav'
4322 * @class Roo.bootstrap.NavGroup
4323 * @extends Roo.bootstrap.Component
4324 * Bootstrap NavGroup class
4325 * @cfg {String} align (left|right)
4326 * @cfg {Boolean} inverse
4327 * @cfg {String} type (nav|pills|tab) default nav
4328 * @cfg {String} navId - reference Id for navbar.
4332 * Create a new nav group
4333 * @param {Object} config The config object
4336 Roo.bootstrap.NavGroup = function(config){
4337 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
4340 Roo.bootstrap.NavGroup.register(this);
4344 * Fires when the active item changes
4345 * @param {Roo.bootstrap.NavGroup} this
4346 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
4347 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
4354 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
4365 getAutoCreate : function()
4367 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
4373 if (Roo.bootstrap.version == 4) {
4374 if (['nav','pills'].indexOf(this.type) != -1) {
4375 cfg.cls = ' navbar-' + this.type;
4378 if (['tabs','pills'].indexOf(this.type) != -1) {
4379 cfg.cls += ' nav-' + this.type
4381 if (this.type !== 'nav') {
4382 Roo.log('nav type must be nav/tabs/pills')
4384 cfg.cls += ' navbar-nav'
4388 if (this.parent() && this.parent().sidebar) {
4391 cls: 'dashboard-menu sidebar-menu'
4397 if (this.form === true) {
4400 cls: 'navbar-form form-inline'
4403 if (this.align === 'right') {
4404 cfg.cls += ' navbar-right ml-md-auto';
4406 cfg.cls += ' navbar-left';
4410 if (this.align === 'right') {
4411 cfg.cls += ' navbar-right ml-md-auto';
4413 cfg.cls += ' mr-auto';
4417 cfg.cls += ' navbar-inverse';
4425 * sets the active Navigation item
4426 * @param {Roo.bootstrap.NavItem} the new current navitem
4428 setActiveItem : function(item)
4431 Roo.each(this.navItems, function(v){
4436 v.setActive(false, true);
4443 item.setActive(true, true);
4444 this.fireEvent('changed', this, item, prev);
4449 * gets the active Navigation item
4450 * @return {Roo.bootstrap.NavItem} the current navitem
4452 getActive : function()
4456 Roo.each(this.navItems, function(v){
4467 indexOfNav : function()
4471 Roo.each(this.navItems, function(v,i){
4482 * adds a Navigation item
4483 * @param {Roo.bootstrap.NavItem} the navitem to add
4485 addItem : function(cfg)
4487 if (this.form && Roo.bootstrap.version == 4) {
4490 var cn = new Roo.bootstrap.NavItem(cfg);
4492 cn.parentId = this.id;
4493 cn.onRender(this.el, null);
4497 * register a Navigation item
4498 * @param {Roo.bootstrap.NavItem} the navitem to add
4500 register : function(item)
4502 this.navItems.push( item);
4503 item.navId = this.navId;
4508 * clear all the Navigation item
4511 clearAll : function()
4514 this.el.dom.innerHTML = '';
4517 getNavItem: function(tabId)
4520 Roo.each(this.navItems, function(e) {
4521 if (e.tabId == tabId) {
4531 setActiveNext : function()
4533 var i = this.indexOfNav(this.getActive());
4534 if (i > this.navItems.length) {
4537 this.setActiveItem(this.navItems[i+1]);
4539 setActivePrev : function()
4541 var i = this.indexOfNav(this.getActive());
4545 this.setActiveItem(this.navItems[i-1]);
4547 clearWasActive : function(except) {
4548 Roo.each(this.navItems, function(e) {
4549 if (e.tabId != except.tabId && e.was_active) {
4550 e.was_active = false;
4557 getWasActive : function ()
4560 Roo.each(this.navItems, function(e) {
4575 Roo.apply(Roo.bootstrap.NavGroup, {
4579 * register a Navigation Group
4580 * @param {Roo.bootstrap.NavGroup} the navgroup to add
4582 register : function(navgrp)
4584 this.groups[navgrp.navId] = navgrp;
4588 * fetch a Navigation Group based on the navigation ID
4589 * @param {string} the navgroup to add
4590 * @returns {Roo.bootstrap.NavGroup} the navgroup
4592 get: function(navId) {
4593 if (typeof(this.groups[navId]) == 'undefined') {
4595 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
4597 return this.groups[navId] ;
4612 * @class Roo.bootstrap.NavItem
4613 * @extends Roo.bootstrap.Component
4614 * Bootstrap Navbar.NavItem class
4615 * @cfg {String} href link to
4616 * @cfg {String} html content of button
4617 * @cfg {String} badge text inside badge
4618 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
4619 * @cfg {String} glyphicon DEPRICATED - use fa
4620 * @cfg {String} icon DEPRICATED - use fa
4621 * @cfg {String} fa - Fontawsome icon name (can add stuff to it like fa-2x)
4622 * @cfg {Boolean} active Is item active
4623 * @cfg {Boolean} disabled Is item disabled
4625 * @cfg {Boolean} preventDefault (true | false) default false
4626 * @cfg {String} tabId the tab that this item activates.
4627 * @cfg {String} tagtype (a|span) render as a href or span?
4628 * @cfg {Boolean} animateRef (true|false) link to element default false
4631 * Create a new Navbar Item
4632 * @param {Object} config The config object
4634 Roo.bootstrap.NavItem = function(config){
4635 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
4640 * The raw click event for the entire grid.
4641 * @param {Roo.EventObject} e
4646 * Fires when the active item active state changes
4647 * @param {Roo.bootstrap.NavItem} this
4648 * @param {boolean} state the new state
4654 * Fires when scroll to element
4655 * @param {Roo.bootstrap.NavItem} this
4656 * @param {Object} options
4657 * @param {Roo.EventObject} e
4665 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
4674 preventDefault : false,
4682 getAutoCreate : function(){
4691 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
4693 if (this.disabled) {
4694 cfg.cls += ' disabled';
4697 if (this.href || this.html || this.glyphicon || this.icon || this.fa) {
4701 href : this.href || "#",
4702 html: this.html || ''
4705 if (this.tagtype == 'a') {
4706 cfg.cn[0].cls = 'nav-link';
4709 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
4712 cfg.cn[0].html = '<i class="fa fas fa-'+this.fa+'"></i> <span>' + cfg.cn[0].html + '</span>'
4714 if(this.glyphicon) {
4715 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
4720 cfg.cn[0].html += " <span class='caret'></span>";
4724 if (this.badge !== '') {
4726 cfg.cn[0].html += ' <span class="badge badge-secondary">' + this.badge + '</span>';
4734 onRender : function(ct, position)
4736 // Roo.log("Call onRender: " + this.xtype);
4737 if (Roo.bootstrap.version == 4 && ct.dom.type != 'ul') {
4741 return Roo.bootstrap.NavItem.superclass.onRender.call(this, ct, position);
4745 initEvents: function()
4747 if (typeof (this.menu) != 'undefined') {
4748 this.menu.parentType = this.xtype;
4749 this.menu.triggerEl = this.el;
4750 this.menu = this.addxtype(Roo.apply({}, this.menu));
4753 this.el.select('a',true).on('click', this.onClick, this);
4755 if(this.tagtype == 'span'){
4756 this.el.select('span',true).on('click', this.onClick, this);
4759 // at this point parent should be available..
4760 this.parent().register(this);
4763 onClick : function(e)
4765 if (e.getTarget('.dropdown-menu-item')) {
4766 // did you click on a menu itemm.... - then don't trigger onclick..
4771 this.preventDefault ||
4774 Roo.log("NavItem - prevent Default?");
4778 if (this.disabled) {
4782 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4783 if (tg && tg.transition) {
4784 Roo.log("waiting for the transitionend");
4790 //Roo.log("fire event clicked");
4791 if(this.fireEvent('click', this, e) === false){
4795 if(this.tagtype == 'span'){
4799 //Roo.log(this.href);
4800 var ael = this.el.select('a',true).first();
4803 if(ael && this.animateRef && this.href.indexOf('#') > -1){
4804 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4805 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4806 return; // ignore... - it's a 'hash' to another page.
4808 Roo.log("NavItem - prevent Default?");
4810 this.scrollToElement(e);
4814 var p = this.parent();
4816 if (['tabs','pills'].indexOf(p.type)!==-1) {
4817 if (typeof(p.setActiveItem) !== 'undefined') {
4818 p.setActiveItem(this);
4822 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4823 if (p.parentType == 'NavHeaderbar' && !this.menu) {
4824 // remove the collapsed menu expand...
4825 p.parent().el.select('.navbar-collapse',true).removeClass('in');
4829 isActive: function () {
4832 setActive : function(state, fire, is_was_active)
4834 if (this.active && !state && this.navId) {
4835 this.was_active = true;
4836 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4838 nv.clearWasActive(this);
4842 this.active = state;
4845 this.el.removeClass('active');
4846 } else if (!this.el.hasClass('active')) {
4847 this.el.addClass('active');
4850 this.fireEvent('changed', this, state);
4853 // show a panel if it's registered and related..
4855 if (!this.navId || !this.tabId || !state || is_was_active) {
4859 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4863 var pan = tg.getPanelByName(this.tabId);
4867 // if we can not flip to new panel - go back to old nav highlight..
4868 if (false == tg.showPanel(pan)) {
4869 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4871 var onav = nv.getWasActive();
4873 onav.setActive(true, false, true);
4882 // this should not be here...
4883 setDisabled : function(state)
4885 this.disabled = state;
4887 this.el.removeClass('disabled');
4888 } else if (!this.el.hasClass('disabled')) {
4889 this.el.addClass('disabled');
4895 * Fetch the element to display the tooltip on.
4896 * @return {Roo.Element} defaults to this.el
4898 tooltipEl : function()
4900 return this.el.select('' + this.tagtype + '', true).first();
4903 scrollToElement : function(e)
4905 var c = document.body;
4908 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
4910 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
4911 c = document.documentElement;
4914 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4920 var o = target.calcOffsetsTo(c);
4927 this.fireEvent('scrollto', this, options, e);
4929 Roo.get(c).scrollTo('top', options.value, true);
4942 * <span> icon </span>
4943 * <span> text </span>
4944 * <span>badge </span>
4948 * @class Roo.bootstrap.NavSidebarItem
4949 * @extends Roo.bootstrap.NavItem
4950 * Bootstrap Navbar.NavSidebarItem class
4951 * {String} badgeWeight (default|primary|success|info|warning|danger)the extra classes for the badge
4952 * {Boolean} open is the menu open
4953 * {Boolean} buttonView use button as the tigger el rather that a (default false)
4954 * {String} buttonWeight (default|primary|success|info|warning|danger)the extra classes for the button
4955 * {String} buttonSize (sm|md|lg)the extra classes for the button
4956 * {Boolean} showArrow show arrow next to the text (default true)
4958 * Create a new Navbar Button
4959 * @param {Object} config The config object
4961 Roo.bootstrap.NavSidebarItem = function(config){
4962 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4967 * The raw click event for the entire grid.
4968 * @param {Roo.EventObject} e
4973 * Fires when the active item active state changes
4974 * @param {Roo.bootstrap.NavSidebarItem} this
4975 * @param {boolean} state the new state
4983 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
4985 badgeWeight : 'default',
4991 buttonWeight : 'default',
4997 getAutoCreate : function(){
5002 href : this.href || '#',
5008 if(this.buttonView){
5011 href : this.href || '#',
5012 cls: 'btn btn-' + this.buttonWeight + ' btn-' + this.buttonSize + 'roo-button-dropdown-toggle',
5025 cfg.cls += ' active';
5028 if (this.disabled) {
5029 cfg.cls += ' disabled';
5032 cfg.cls += ' open x-open';
5035 if (this.glyphicon || this.icon) {
5036 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
5037 a.cn.push({ tag : 'i', cls : c }) ;
5040 if(!this.buttonView){
5043 html : this.html || ''
5050 if (this.badge !== '') {
5051 a.cn.push({ tag: 'span', cls : 'badge pull-right badge-' + this.badgeWeight, html: this.badge });
5057 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
5060 a.cls += ' dropdown-toggle treeview' ;
5066 initEvents : function()
5068 if (typeof (this.menu) != 'undefined') {
5069 this.menu.parentType = this.xtype;
5070 this.menu.triggerEl = this.el;
5071 this.menu = this.addxtype(Roo.apply({}, this.menu));
5074 this.el.on('click', this.onClick, this);
5076 if(this.badge !== ''){
5077 this.badgeEl = this.el.select('.badge', true).first().setVisibilityMode(Roo.Element.DISPLAY);
5082 onClick : function(e)
5089 if(this.preventDefault){
5093 this.fireEvent('click', this);
5096 disable : function()
5098 this.setDisabled(true);
5103 this.setDisabled(false);
5106 setDisabled : function(state)
5108 if(this.disabled == state){
5112 this.disabled = state;
5115 this.el.addClass('disabled');
5119 this.el.removeClass('disabled');
5124 setActive : function(state)
5126 if(this.active == state){
5130 this.active = state;
5133 this.el.addClass('active');
5137 this.el.removeClass('active');
5142 isActive: function ()
5147 setBadge : function(str)
5153 this.badgeEl.dom.innerHTML = str;
5170 * @class Roo.bootstrap.Row
5171 * @extends Roo.bootstrap.Component
5172 * Bootstrap Row class (contains columns...)
5176 * @param {Object} config The config object
5179 Roo.bootstrap.Row = function(config){
5180 Roo.bootstrap.Row.superclass.constructor.call(this, config);
5183 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
5185 getAutoCreate : function(){
5204 * @class Roo.bootstrap.Element
5205 * @extends Roo.bootstrap.Component
5206 * Bootstrap Element class
5207 * @cfg {String} html contents of the element
5208 * @cfg {String} tag tag of the element
5209 * @cfg {String} cls class of the element
5210 * @cfg {Boolean} preventDefault (true|false) default false
5211 * @cfg {Boolean} clickable (true|false) default false
5214 * Create a new Element
5215 * @param {Object} config The config object
5218 Roo.bootstrap.Element = function(config){
5219 Roo.bootstrap.Element.superclass.constructor.call(this, config);
5225 * When a element is chick
5226 * @param {Roo.bootstrap.Element} this
5227 * @param {Roo.EventObject} e
5233 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
5238 preventDefault: false,
5241 getAutoCreate : function(){
5245 // cls: this.cls, double assign in parent class Component.js :: onRender
5252 initEvents: function()
5254 Roo.bootstrap.Element.superclass.initEvents.call(this);
5257 this.el.on('click', this.onClick, this);
5262 onClick : function(e)
5264 if(this.preventDefault){
5268 this.fireEvent('click', this, e);
5271 getValue : function()
5273 return this.el.dom.innerHTML;
5276 setValue : function(value)
5278 this.el.dom.innerHTML = value;
5293 * @class Roo.bootstrap.Pagination
5294 * @extends Roo.bootstrap.Component
5295 * Bootstrap Pagination class
5296 * @cfg {String} size xs | sm | md | lg
5297 * @cfg {Boolean} inverse false | true
5300 * Create a new Pagination
5301 * @param {Object} config The config object
5304 Roo.bootstrap.Pagination = function(config){
5305 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
5308 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
5314 getAutoCreate : function(){
5320 cfg.cls += ' inverse';
5326 cfg.cls += " " + this.cls;
5344 * @class Roo.bootstrap.PaginationItem
5345 * @extends Roo.bootstrap.Component
5346 * Bootstrap PaginationItem class
5347 * @cfg {String} html text
5348 * @cfg {String} href the link
5349 * @cfg {Boolean} preventDefault (true | false) default true
5350 * @cfg {Boolean} active (true | false) default false
5351 * @cfg {Boolean} disabled default false
5355 * Create a new PaginationItem
5356 * @param {Object} config The config object
5360 Roo.bootstrap.PaginationItem = function(config){
5361 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
5366 * The raw click event for the entire grid.
5367 * @param {Roo.EventObject} e
5373 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
5377 preventDefault: true,
5382 getAutoCreate : function(){
5388 href : this.href ? this.href : '#',
5389 html : this.html ? this.html : ''
5399 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
5403 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
5409 initEvents: function() {
5411 this.el.on('click', this.onClick, this);
5414 onClick : function(e)
5416 Roo.log('PaginationItem on click ');
5417 if(this.preventDefault){
5425 this.fireEvent('click', this, e);
5441 * @class Roo.bootstrap.Slider
5442 * @extends Roo.bootstrap.Component
5443 * Bootstrap Slider class
5446 * Create a new Slider
5447 * @param {Object} config The config object
5450 Roo.bootstrap.Slider = function(config){
5451 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
5454 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
5456 getAutoCreate : function(){
5460 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
5464 cls: 'ui-slider-handle ui-state-default ui-corner-all'
5476 * Ext JS Library 1.1.1
5477 * Copyright(c) 2006-2007, Ext JS, LLC.
5479 * Originally Released Under LGPL - original licence link has changed is not relivant.
5482 * <script type="text/javascript">
5487 * @class Roo.grid.ColumnModel
5488 * @extends Roo.util.Observable
5489 * This is the default implementation of a ColumnModel used by the Grid. It defines
5490 * the columns in the grid.
5493 var colModel = new Roo.grid.ColumnModel([
5494 {header: "Ticker", width: 60, sortable: true, locked: true},
5495 {header: "Company Name", width: 150, sortable: true},
5496 {header: "Market Cap.", width: 100, sortable: true},
5497 {header: "$ Sales", width: 100, sortable: true, renderer: money},
5498 {header: "Employees", width: 100, sortable: true, resizable: false}
5503 * The config options listed for this class are options which may appear in each
5504 * individual column definition.
5505 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
5507 * @param {Object} config An Array of column config objects. See this class's
5508 * config objects for details.
5510 Roo.grid.ColumnModel = function(config){
5512 * The config passed into the constructor
5514 this.config = config;
5517 // if no id, create one
5518 // if the column does not have a dataIndex mapping,
5519 // map it to the order it is in the config
5520 for(var i = 0, len = config.length; i < len; i++){
5522 if(typeof c.dataIndex == "undefined"){
5525 if(typeof c.renderer == "string"){
5526 c.renderer = Roo.util.Format[c.renderer];
5528 if(typeof c.id == "undefined"){
5531 if(c.editor && c.editor.xtype){
5532 c.editor = Roo.factory(c.editor, Roo.grid);
5534 if(c.editor && c.editor.isFormField){
5535 c.editor = new Roo.grid.GridEditor(c.editor);
5537 this.lookup[c.id] = c;
5541 * The width of columns which have no width specified (defaults to 100)
5544 this.defaultWidth = 100;
5547 * Default sortable of columns which have no sortable specified (defaults to false)
5550 this.defaultSortable = false;
5554 * @event widthchange
5555 * Fires when the width of a column changes.
5556 * @param {ColumnModel} this
5557 * @param {Number} columnIndex The column index
5558 * @param {Number} newWidth The new width
5560 "widthchange": true,
5562 * @event headerchange
5563 * Fires when the text of a header changes.
5564 * @param {ColumnModel} this
5565 * @param {Number} columnIndex The column index
5566 * @param {Number} newText The new header text
5568 "headerchange": true,
5570 * @event hiddenchange
5571 * Fires when a column is hidden or "unhidden".
5572 * @param {ColumnModel} this
5573 * @param {Number} columnIndex The column index
5574 * @param {Boolean} hidden true if hidden, false otherwise
5576 "hiddenchange": true,
5578 * @event columnmoved
5579 * Fires when a column is moved.
5580 * @param {ColumnModel} this
5581 * @param {Number} oldIndex
5582 * @param {Number} newIndex
5584 "columnmoved" : true,
5586 * @event columlockchange
5587 * Fires when a column's locked state is changed
5588 * @param {ColumnModel} this
5589 * @param {Number} colIndex
5590 * @param {Boolean} locked true if locked
5592 "columnlockchange" : true
5594 Roo.grid.ColumnModel.superclass.constructor.call(this);
5596 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
5598 * @cfg {String} header The header text to display in the Grid view.
5601 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
5602 * {@link Roo.data.Record} definition from which to draw the column's value. If not
5603 * specified, the column's index is used as an index into the Record's data Array.
5606 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
5607 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
5610 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
5611 * Defaults to the value of the {@link #defaultSortable} property.
5612 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
5615 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
5618 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
5621 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
5624 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
5627 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
5628 * given the cell's data value. See {@link #setRenderer}. If not specified, the
5629 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
5630 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
5633 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
5636 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
5639 * @cfg {String} valign (Optional) Set the CSS vertical-align property of the column (eg. middle, top, bottom etc). Defaults to undefined.
5642 * @cfg {String} cursor (Optional)
5645 * @cfg {String} tooltip (Optional)
5648 * @cfg {Number} xs (Optional)
5651 * @cfg {Number} sm (Optional)
5654 * @cfg {Number} md (Optional)
5657 * @cfg {Number} lg (Optional)
5660 * Returns the id of the column at the specified index.
5661 * @param {Number} index The column index
5662 * @return {String} the id
5664 getColumnId : function(index){
5665 return this.config[index].id;
5669 * Returns the column for a specified id.
5670 * @param {String} id The column id
5671 * @return {Object} the column
5673 getColumnById : function(id){
5674 return this.lookup[id];
5679 * Returns the column for a specified dataIndex.
5680 * @param {String} dataIndex The column dataIndex
5681 * @return {Object|Boolean} the column or false if not found
5683 getColumnByDataIndex: function(dataIndex){
5684 var index = this.findColumnIndex(dataIndex);
5685 return index > -1 ? this.config[index] : false;
5689 * Returns the index for a specified column id.
5690 * @param {String} id The column id
5691 * @return {Number} the index, or -1 if not found
5693 getIndexById : function(id){
5694 for(var i = 0, len = this.config.length; i < len; i++){
5695 if(this.config[i].id == id){
5703 * Returns the index for a specified column dataIndex.
5704 * @param {String} dataIndex The column dataIndex
5705 * @return {Number} the index, or -1 if not found
5708 findColumnIndex : function(dataIndex){
5709 for(var i = 0, len = this.config.length; i < len; i++){
5710 if(this.config[i].dataIndex == dataIndex){
5718 moveColumn : function(oldIndex, newIndex){
5719 var c = this.config[oldIndex];
5720 this.config.splice(oldIndex, 1);
5721 this.config.splice(newIndex, 0, c);
5722 this.dataMap = null;
5723 this.fireEvent("columnmoved", this, oldIndex, newIndex);
5726 isLocked : function(colIndex){
5727 return this.config[colIndex].locked === true;
5730 setLocked : function(colIndex, value, suppressEvent){
5731 if(this.isLocked(colIndex) == value){
5734 this.config[colIndex].locked = value;
5736 this.fireEvent("columnlockchange", this, colIndex, value);
5740 getTotalLockedWidth : function(){
5742 for(var i = 0; i < this.config.length; i++){
5743 if(this.isLocked(i) && !this.isHidden(i)){
5744 this.totalWidth += this.getColumnWidth(i);
5750 getLockedCount : function(){
5751 for(var i = 0, len = this.config.length; i < len; i++){
5752 if(!this.isLocked(i)){
5757 return this.config.length;
5761 * Returns the number of columns.
5764 getColumnCount : function(visibleOnly){
5765 if(visibleOnly === true){
5767 for(var i = 0, len = this.config.length; i < len; i++){
5768 if(!this.isHidden(i)){
5774 return this.config.length;
5778 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
5779 * @param {Function} fn
5780 * @param {Object} scope (optional)
5781 * @return {Array} result
5783 getColumnsBy : function(fn, scope){
5785 for(var i = 0, len = this.config.length; i < len; i++){
5786 var c = this.config[i];
5787 if(fn.call(scope||this, c, i) === true){
5795 * Returns true if the specified column is sortable.
5796 * @param {Number} col The column index
5799 isSortable : function(col){
5800 if(typeof this.config[col].sortable == "undefined"){
5801 return this.defaultSortable;
5803 return this.config[col].sortable;
5807 * Returns the rendering (formatting) function defined for the column.
5808 * @param {Number} col The column index.
5809 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
5811 getRenderer : function(col){
5812 if(!this.config[col].renderer){
5813 return Roo.grid.ColumnModel.defaultRenderer;
5815 return this.config[col].renderer;
5819 * Sets the rendering (formatting) function for a column.
5820 * @param {Number} col The column index
5821 * @param {Function} fn The function to use to process the cell's raw data
5822 * to return HTML markup for the grid view. The render function is called with
5823 * the following parameters:<ul>
5824 * <li>Data value.</li>
5825 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
5826 * <li>css A CSS style string to apply to the table cell.</li>
5827 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
5828 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
5829 * <li>Row index</li>
5830 * <li>Column index</li>
5831 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
5833 setRenderer : function(col, fn){
5834 this.config[col].renderer = fn;
5838 * Returns the width for the specified column.
5839 * @param {Number} col The column index
5842 getColumnWidth : function(col){
5843 return this.config[col].width * 1 || this.defaultWidth;
5847 * Sets the width for a column.
5848 * @param {Number} col The column index
5849 * @param {Number} width The new width
5851 setColumnWidth : function(col, width, suppressEvent){
5852 this.config[col].width = width;
5853 this.totalWidth = null;
5855 this.fireEvent("widthchange", this, col, width);
5860 * Returns the total width of all columns.
5861 * @param {Boolean} includeHidden True to include hidden column widths
5864 getTotalWidth : function(includeHidden){
5865 if(!this.totalWidth){
5866 this.totalWidth = 0;
5867 for(var i = 0, len = this.config.length; i < len; i++){
5868 if(includeHidden || !this.isHidden(i)){
5869 this.totalWidth += this.getColumnWidth(i);
5873 return this.totalWidth;
5877 * Returns the header for the specified column.
5878 * @param {Number} col The column index
5881 getColumnHeader : function(col){
5882 return this.config[col].header;
5886 * Sets the header for a column.
5887 * @param {Number} col The column index
5888 * @param {String} header The new header
5890 setColumnHeader : function(col, header){
5891 this.config[col].header = header;
5892 this.fireEvent("headerchange", this, col, header);
5896 * Returns the tooltip for the specified column.
5897 * @param {Number} col The column index
5900 getColumnTooltip : function(col){
5901 return this.config[col].tooltip;
5904 * Sets the tooltip for a column.
5905 * @param {Number} col The column index
5906 * @param {String} tooltip The new tooltip
5908 setColumnTooltip : function(col, tooltip){
5909 this.config[col].tooltip = tooltip;
5913 * Returns the dataIndex for the specified column.
5914 * @param {Number} col The column index
5917 getDataIndex : function(col){
5918 return this.config[col].dataIndex;
5922 * Sets the dataIndex for a column.
5923 * @param {Number} col The column index
5924 * @param {Number} dataIndex The new dataIndex
5926 setDataIndex : function(col, dataIndex){
5927 this.config[col].dataIndex = dataIndex;
5933 * Returns true if the cell is editable.
5934 * @param {Number} colIndex The column index
5935 * @param {Number} rowIndex The row index - this is nto actually used..?
5938 isCellEditable : function(colIndex, rowIndex){
5939 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
5943 * Returns the editor defined for the cell/column.
5944 * return false or null to disable editing.
5945 * @param {Number} colIndex The column index
5946 * @param {Number} rowIndex The row index
5949 getCellEditor : function(colIndex, rowIndex){
5950 return this.config[colIndex].editor;
5954 * Sets if a column is editable.
5955 * @param {Number} col The column index
5956 * @param {Boolean} editable True if the column is editable
5958 setEditable : function(col, editable){
5959 this.config[col].editable = editable;
5964 * Returns true if the column is hidden.
5965 * @param {Number} colIndex The column index
5968 isHidden : function(colIndex){
5969 return this.config[colIndex].hidden;
5974 * Returns true if the column width cannot be changed
5976 isFixed : function(colIndex){
5977 return this.config[colIndex].fixed;
5981 * Returns true if the column can be resized
5984 isResizable : function(colIndex){
5985 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
5988 * Sets if a column is hidden.
5989 * @param {Number} colIndex The column index
5990 * @param {Boolean} hidden True if the column is hidden
5992 setHidden : function(colIndex, hidden){
5993 this.config[colIndex].hidden = hidden;
5994 this.totalWidth = null;
5995 this.fireEvent("hiddenchange", this, colIndex, hidden);
5999 * Sets the editor for a column.
6000 * @param {Number} col The column index
6001 * @param {Object} editor The editor object
6003 setEditor : function(col, editor){
6004 this.config[col].editor = editor;
6008 Roo.grid.ColumnModel.defaultRenderer = function(value)
6010 if(typeof value == "object") {
6013 if(typeof value == "string" && value.length < 1){
6017 return String.format("{0}", value);
6020 // Alias for backwards compatibility
6021 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
6024 * Ext JS Library 1.1.1
6025 * Copyright(c) 2006-2007, Ext JS, LLC.
6027 * Originally Released Under LGPL - original licence link has changed is not relivant.
6030 * <script type="text/javascript">
6034 * @class Roo.LoadMask
6035 * A simple utility class for generically masking elements while loading data. If the element being masked has
6036 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
6037 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
6038 * element's UpdateManager load indicator and will be destroyed after the initial load.
6040 * Create a new LoadMask
6041 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
6042 * @param {Object} config The config object
6044 Roo.LoadMask = function(el, config){
6045 this.el = Roo.get(el);
6046 Roo.apply(this, config);
6048 this.store.on('beforeload', this.onBeforeLoad, this);
6049 this.store.on('load', this.onLoad, this);
6050 this.store.on('loadexception', this.onLoadException, this);
6051 this.removeMask = false;
6053 var um = this.el.getUpdateManager();
6054 um.showLoadIndicator = false; // disable the default indicator
6055 um.on('beforeupdate', this.onBeforeLoad, this);
6056 um.on('update', this.onLoad, this);
6057 um.on('failure', this.onLoad, this);
6058 this.removeMask = true;
6062 Roo.LoadMask.prototype = {
6064 * @cfg {Boolean} removeMask
6065 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
6066 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
6070 * The text to display in a centered loading message box (defaults to 'Loading...')
6074 * @cfg {String} msgCls
6075 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
6077 msgCls : 'x-mask-loading',
6080 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
6086 * Disables the mask to prevent it from being displayed
6088 disable : function(){
6089 this.disabled = true;
6093 * Enables the mask so that it can be displayed
6095 enable : function(){
6096 this.disabled = false;
6099 onLoadException : function()
6103 if (typeof(arguments[3]) != 'undefined') {
6104 Roo.MessageBox.alert("Error loading",arguments[3]);
6108 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
6109 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
6116 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
6121 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
6125 onBeforeLoad : function(){
6127 (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
6132 destroy : function(){
6134 this.store.un('beforeload', this.onBeforeLoad, this);
6135 this.store.un('load', this.onLoad, this);
6136 this.store.un('loadexception', this.onLoadException, this);
6138 var um = this.el.getUpdateManager();
6139 um.un('beforeupdate', this.onBeforeLoad, this);
6140 um.un('update', this.onLoad, this);
6141 um.un('failure', this.onLoad, this);
6152 * @class Roo.bootstrap.Table
6153 * @extends Roo.bootstrap.Component
6154 * Bootstrap Table class
6155 * @cfg {String} cls table class
6156 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
6157 * @cfg {String} bgcolor Specifies the background color for a table
6158 * @cfg {Number} border Specifies whether the table cells should have borders or not
6159 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
6160 * @cfg {Number} cellspacing Specifies the space between cells
6161 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
6162 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
6163 * @cfg {String} sortable Specifies that the table should be sortable
6164 * @cfg {String} summary Specifies a summary of the content of a table
6165 * @cfg {Number} width Specifies the width of a table
6166 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
6168 * @cfg {boolean} striped Should the rows be alternative striped
6169 * @cfg {boolean} bordered Add borders to the table
6170 * @cfg {boolean} hover Add hover highlighting
6171 * @cfg {boolean} condensed Format condensed
6172 * @cfg {boolean} responsive Format condensed
6173 * @cfg {Boolean} loadMask (true|false) default false
6174 * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
6175 * @cfg {Boolean} headerShow (true|false) generate thead, default true
6176 * @cfg {Boolean} rowSelection (true|false) default false
6177 * @cfg {Boolean} cellSelection (true|false) default false
6178 * @cfg {Boolean} scrollBody (true|false) default false - body scrolled / fixed header
6179 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
6180 * @cfg {Boolean} lazyLoad auto load data while scrolling to the end (default false)
6181 * @cfg {Boolean} auto_hide_footer auto hide footer if only one page (default false)
6185 * Create a new Table
6186 * @param {Object} config The config object
6189 Roo.bootstrap.Table = function(config){
6190 Roo.bootstrap.Table.superclass.constructor.call(this, config);
6195 this.rowSelection = (typeof(config.rowSelection) != 'undefined') ? config.rowSelection : this.rowSelection;
6196 this.cellSelection = (typeof(config.cellSelection) != 'undefined') ? config.cellSelection : this.cellSelection;
6197 this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
6198 this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
6200 this.sm = this.sm || {xtype: 'RowSelectionModel'};
6202 this.sm.grid = this;
6203 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
6204 this.sm = this.selModel;
6205 this.sm.xmodule = this.xmodule || false;
6208 if (this.cm && typeof(this.cm.config) == 'undefined') {
6209 this.colModel = new Roo.grid.ColumnModel(this.cm);
6210 this.cm = this.colModel;
6211 this.cm.xmodule = this.xmodule || false;
6214 this.store= Roo.factory(this.store, Roo.data);
6215 this.ds = this.store;
6216 this.ds.xmodule = this.xmodule || false;
6219 if (this.footer && this.store) {
6220 this.footer.dataSource = this.ds;
6221 this.footer = Roo.factory(this.footer);
6228 * Fires when a cell is clicked
6229 * @param {Roo.bootstrap.Table} this
6230 * @param {Roo.Element} el
6231 * @param {Number} rowIndex
6232 * @param {Number} columnIndex
6233 * @param {Roo.EventObject} e
6237 * @event celldblclick
6238 * Fires when a cell is double clicked
6239 * @param {Roo.bootstrap.Table} this
6240 * @param {Roo.Element} el
6241 * @param {Number} rowIndex
6242 * @param {Number} columnIndex
6243 * @param {Roo.EventObject} e
6245 "celldblclick" : true,
6248 * Fires when a row is clicked
6249 * @param {Roo.bootstrap.Table} this
6250 * @param {Roo.Element} el
6251 * @param {Number} rowIndex
6252 * @param {Roo.EventObject} e
6256 * @event rowdblclick
6257 * Fires when a row is double clicked
6258 * @param {Roo.bootstrap.Table} this
6259 * @param {Roo.Element} el
6260 * @param {Number} rowIndex
6261 * @param {Roo.EventObject} e
6263 "rowdblclick" : true,
6266 * Fires when a mouseover occur
6267 * @param {Roo.bootstrap.Table} this
6268 * @param {Roo.Element} el
6269 * @param {Number} rowIndex
6270 * @param {Number} columnIndex
6271 * @param {Roo.EventObject} e
6276 * Fires when a mouseout occur
6277 * @param {Roo.bootstrap.Table} this
6278 * @param {Roo.Element} el
6279 * @param {Number} rowIndex
6280 * @param {Number} columnIndex
6281 * @param {Roo.EventObject} e
6286 * Fires when a row is rendered, so you can change add a style to it.
6287 * @param {Roo.bootstrap.Table} this
6288 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
6292 * @event rowsrendered
6293 * Fires when all the rows have been rendered
6294 * @param {Roo.bootstrap.Table} this
6296 'rowsrendered' : true,
6298 * @event contextmenu
6299 * The raw contextmenu event for the entire grid.
6300 * @param {Roo.EventObject} e
6302 "contextmenu" : true,
6304 * @event rowcontextmenu
6305 * Fires when a row is right clicked
6306 * @param {Roo.bootstrap.Table} this
6307 * @param {Number} rowIndex
6308 * @param {Roo.EventObject} e
6310 "rowcontextmenu" : true,
6312 * @event cellcontextmenu
6313 * Fires when a cell is right clicked
6314 * @param {Roo.bootstrap.Table} this
6315 * @param {Number} rowIndex
6316 * @param {Number} cellIndex
6317 * @param {Roo.EventObject} e
6319 "cellcontextmenu" : true,
6321 * @event headercontextmenu
6322 * Fires when a header is right clicked
6323 * @param {Roo.bootstrap.Table} this
6324 * @param {Number} columnIndex
6325 * @param {Roo.EventObject} e
6327 "headercontextmenu" : true
6331 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
6357 rowSelection : false,
6358 cellSelection : false,
6361 // Roo.Element - the tbody
6363 // Roo.Element - thead element
6366 container: false, // used by gridpanel...
6372 auto_hide_footer : false,
6374 getAutoCreate : function()
6376 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
6383 if (this.scrollBody) {
6384 cfg.cls += ' table-body-fixed';
6387 cfg.cls += ' table-striped';
6391 cfg.cls += ' table-hover';
6393 if (this.bordered) {
6394 cfg.cls += ' table-bordered';
6396 if (this.condensed) {
6397 cfg.cls += ' table-condensed';
6399 if (this.responsive) {
6400 cfg.cls += ' table-responsive';
6404 cfg.cls+= ' ' +this.cls;
6407 // this lot should be simplifed...
6420 ].forEach(function(k) {
6428 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
6431 if(this.store || this.cm){
6432 if(this.headerShow){
6433 cfg.cn.push(this.renderHeader());
6436 cfg.cn.push(this.renderBody());
6438 if(this.footerShow){
6439 cfg.cn.push(this.renderFooter());
6441 // where does this come from?
6442 //cfg.cls+= ' TableGrid';
6445 return { cn : [ cfg ] };
6448 initEvents : function()
6450 if(!this.store || !this.cm){
6453 if (this.selModel) {
6454 this.selModel.initEvents();
6458 //Roo.log('initEvents with ds!!!!');
6460 this.mainBody = this.el.select('tbody', true).first();
6461 this.mainHead = this.el.select('thead', true).first();
6462 this.mainFoot = this.el.select('tfoot', true).first();
6468 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6469 e.on('click', _this.sort, _this);
6472 this.mainBody.on("click", this.onClick, this);
6473 this.mainBody.on("dblclick", this.onDblClick, this);
6475 // why is this done????? = it breaks dialogs??
6476 //this.parent().el.setStyle('position', 'relative');
6480 this.footer.parentId = this.id;
6481 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
6484 this.el.select('tfoot tr td').first().addClass('hide');
6489 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
6492 this.store.on('load', this.onLoad, this);
6493 this.store.on('beforeload', this.onBeforeLoad, this);
6494 this.store.on('update', this.onUpdate, this);
6495 this.store.on('add', this.onAdd, this);
6496 this.store.on("clear", this.clear, this);
6498 this.el.on("contextmenu", this.onContextMenu, this);
6500 this.mainBody.on('scroll', this.onBodyScroll, this);
6502 this.cm.on("headerchange", this.onHeaderChange, this);
6504 this.cm.on("hiddenchange", this.onHiddenChange, this, arguments);
6508 onContextMenu : function(e, t)
6510 this.processEvent("contextmenu", e);
6513 processEvent : function(name, e)
6515 if (name != 'touchstart' ) {
6516 this.fireEvent(name, e);
6519 var t = e.getTarget();
6521 var cell = Roo.get(t);
6527 if(cell.findParent('tfoot', false, true)){
6531 if(cell.findParent('thead', false, true)){
6533 if(e.getTarget().nodeName.toLowerCase() != 'th'){
6534 cell = Roo.get(t).findParent('th', false, true);
6536 Roo.log("failed to find th in thead?");
6537 Roo.log(e.getTarget());
6542 var cellIndex = cell.dom.cellIndex;
6544 var ename = name == 'touchstart' ? 'click' : name;
6545 this.fireEvent("header" + ename, this, cellIndex, e);
6550 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6551 cell = Roo.get(t).findParent('td', false, true);
6553 Roo.log("failed to find th in tbody?");
6554 Roo.log(e.getTarget());
6559 var row = cell.findParent('tr', false, true);
6560 var cellIndex = cell.dom.cellIndex;
6561 var rowIndex = row.dom.rowIndex - 1;
6565 this.fireEvent("row" + name, this, rowIndex, e);
6569 this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
6575 onMouseover : function(e, el)
6577 var cell = Roo.get(el);
6583 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6584 cell = cell.findParent('td', false, true);
6587 var row = cell.findParent('tr', false, true);
6588 var cellIndex = cell.dom.cellIndex;
6589 var rowIndex = row.dom.rowIndex - 1; // start from 0
6591 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
6595 onMouseout : function(e, el)
6597 var cell = Roo.get(el);
6603 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6604 cell = cell.findParent('td', false, true);
6607 var row = cell.findParent('tr', false, true);
6608 var cellIndex = cell.dom.cellIndex;
6609 var rowIndex = row.dom.rowIndex - 1; // start from 0
6611 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
6615 onClick : function(e, el)
6617 var cell = Roo.get(el);
6619 if(!cell || (!this.cellSelection && !this.rowSelection)){
6623 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6624 cell = cell.findParent('td', false, true);
6627 if(!cell || typeof(cell) == 'undefined'){
6631 var row = cell.findParent('tr', false, true);
6633 if(!row || typeof(row) == 'undefined'){
6637 var cellIndex = cell.dom.cellIndex;
6638 var rowIndex = this.getRowIndex(row);
6640 // why??? - should these not be based on SelectionModel?
6641 if(this.cellSelection){
6642 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
6645 if(this.rowSelection){
6646 this.fireEvent('rowclick', this, row, rowIndex, e);
6652 onDblClick : function(e,el)
6654 var cell = Roo.get(el);
6656 if(!cell || (!this.cellSelection && !this.rowSelection)){
6660 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6661 cell = cell.findParent('td', false, true);
6664 if(!cell || typeof(cell) == 'undefined'){
6668 var row = cell.findParent('tr', false, true);
6670 if(!row || typeof(row) == 'undefined'){
6674 var cellIndex = cell.dom.cellIndex;
6675 var rowIndex = this.getRowIndex(row);
6677 if(this.cellSelection){
6678 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
6681 if(this.rowSelection){
6682 this.fireEvent('rowdblclick', this, row, rowIndex, e);
6686 sort : function(e,el)
6688 var col = Roo.get(el);
6690 if(!col.hasClass('sortable')){
6694 var sort = col.attr('sort');
6697 if(col.select('i', true).first().hasClass('glyphicon-arrow-up')){
6701 this.store.sortInfo = {field : sort, direction : dir};
6704 Roo.log("calling footer first");
6705 this.footer.onClick('first');
6708 this.store.load({ params : { start : 0 } });
6712 renderHeader : function()
6720 this.totalWidth = 0;
6722 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6724 var config = cm.config[i];
6728 cls : 'x-hcol-' + i,
6730 html: cm.getColumnHeader(i)
6735 if(typeof(config.sortable) != 'undefined' && config.sortable){
6737 c.html = '<i class="glyphicon"></i>' + c.html;
6740 if(typeof(config.lgHeader) != 'undefined'){
6741 hh += '<span class="hidden-xs hidden-sm hidden-md">' + config.lgHeader + '</span>';
6744 if(typeof(config.mdHeader) != 'undefined'){
6745 hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
6748 if(typeof(config.smHeader) != 'undefined'){
6749 hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
6752 if(typeof(config.xsHeader) != 'undefined'){
6753 hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
6760 if(typeof(config.tooltip) != 'undefined'){
6761 c.tooltip = config.tooltip;
6764 if(typeof(config.colspan) != 'undefined'){
6765 c.colspan = config.colspan;
6768 if(typeof(config.hidden) != 'undefined' && config.hidden){
6769 c.style += ' display:none;';
6772 if(typeof(config.dataIndex) != 'undefined'){
6773 c.sort = config.dataIndex;
6778 if(typeof(config.align) != 'undefined' && config.align.length){
6779 c.style += ' text-align:' + config.align + ';';
6782 if(typeof(config.width) != 'undefined'){
6783 c.style += ' width:' + config.width + 'px;';
6784 this.totalWidth += config.width;
6786 this.totalWidth += 100; // assume minimum of 100 per column?
6789 if(typeof(config.cls) != 'undefined'){
6790 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
6793 ['xs','sm','md','lg'].map(function(size){
6795 if(typeof(config[size]) == 'undefined'){
6799 if (!config[size]) { // 0 = hidden
6800 c.cls += ' hidden-' + size;
6804 c.cls += ' col-' + size + '-' + config[size];
6814 renderBody : function()
6824 colspan : this.cm.getColumnCount()
6834 renderFooter : function()
6844 colspan : this.cm.getColumnCount()
6858 // Roo.log('ds onload');
6863 var ds = this.store;
6865 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6866 e.select('i', true).removeClass(['glyphicon-arrow-up', 'glyphicon-arrow-down']);
6867 if (_this.store.sortInfo) {
6869 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
6870 e.select('i', true).addClass(['glyphicon-arrow-up']);
6873 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
6874 e.select('i', true).addClass(['glyphicon-arrow-down']);
6879 var tbody = this.mainBody;
6881 if(ds.getCount() > 0){
6882 ds.data.each(function(d,rowIndex){
6883 var row = this.renderRow(cm, ds, rowIndex);
6885 tbody.createChild(row);
6889 if(row.cellObjects.length){
6890 Roo.each(row.cellObjects, function(r){
6891 _this.renderCellObject(r);
6898 var tfoot = this.el.select('tfoot', true).first();
6900 if(this.footerShow && this.auto_hide_footer && this.mainFoot){
6902 this.mainFoot.setVisibilityMode(Roo.Element.DISPLAY).hide();
6904 var total = this.ds.getTotalCount();
6906 if(this.footer.pageSize < total){
6907 this.mainFoot.show();
6911 Roo.each(this.el.select('tbody td', true).elements, function(e){
6912 e.on('mouseover', _this.onMouseover, _this);
6915 Roo.each(this.el.select('tbody td', true).elements, function(e){
6916 e.on('mouseout', _this.onMouseout, _this);
6918 this.fireEvent('rowsrendered', this);
6924 onUpdate : function(ds,record)
6926 this.refreshRow(record);
6930 onRemove : function(ds, record, index, isUpdate){
6931 if(isUpdate !== true){
6932 this.fireEvent("beforerowremoved", this, index, record);
6934 var bt = this.mainBody.dom;
6936 var rows = this.el.select('tbody > tr', true).elements;
6938 if(typeof(rows[index]) != 'undefined'){
6939 bt.removeChild(rows[index].dom);
6942 // if(bt.rows[index]){
6943 // bt.removeChild(bt.rows[index]);
6946 if(isUpdate !== true){
6947 //this.stripeRows(index);
6948 //this.syncRowHeights(index, index);
6950 this.fireEvent("rowremoved", this, index, record);
6954 onAdd : function(ds, records, rowIndex)
6956 //Roo.log('on Add called');
6957 // - note this does not handle multiple adding very well..
6958 var bt = this.mainBody.dom;
6959 for (var i =0 ; i < records.length;i++) {
6960 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
6961 //Roo.log(records[i]);
6962 //Roo.log(this.store.getAt(rowIndex+i));
6963 this.insertRow(this.store, rowIndex + i, false);
6970 refreshRow : function(record){
6971 var ds = this.store, index;
6972 if(typeof record == 'number'){
6974 record = ds.getAt(index);
6976 index = ds.indexOf(record);
6978 this.insertRow(ds, index, true);
6980 this.onRemove(ds, record, index+1, true);
6982 //this.syncRowHeights(index, index);
6984 this.fireEvent("rowupdated", this, index, record);
6987 insertRow : function(dm, rowIndex, isUpdate){
6990 this.fireEvent("beforerowsinserted", this, rowIndex);
6992 //var s = this.getScrollState();
6993 var row = this.renderRow(this.cm, this.store, rowIndex);
6994 // insert before rowIndex..
6995 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
6999 if(row.cellObjects.length){
7000 Roo.each(row.cellObjects, function(r){
7001 _this.renderCellObject(r);
7006 this.fireEvent("rowsinserted", this, rowIndex);
7007 //this.syncRowHeights(firstRow, lastRow);
7008 //this.stripeRows(firstRow);
7015 getRowDom : function(rowIndex)
7017 var rows = this.el.select('tbody > tr', true).elements;
7019 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
7022 // returns the object tree for a tr..
7025 renderRow : function(cm, ds, rowIndex)
7027 var d = ds.getAt(rowIndex);
7031 cls : 'x-row-' + rowIndex,
7035 var cellObjects = [];
7037 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
7038 var config = cm.config[i];
7040 var renderer = cm.getRenderer(i);
7044 if(typeof(renderer) !== 'undefined'){
7045 value = renderer(d.data[cm.getDataIndex(i)], false, d);
7047 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
7048 // and are rendered into the cells after the row is rendered - using the id for the element.
7050 if(typeof(value) === 'object'){
7060 rowIndex : rowIndex,
7065 this.fireEvent('rowclass', this, rowcfg);
7069 cls : rowcfg.rowClass + ' x-col-' + i,
7071 html: (typeof(value) === 'object') ? '' : value
7078 if(typeof(config.colspan) != 'undefined'){
7079 td.colspan = config.colspan;
7082 if(typeof(config.hidden) != 'undefined' && config.hidden){
7083 td.style += ' display:none;';
7086 if(typeof(config.align) != 'undefined' && config.align.length){
7087 td.style += ' text-align:' + config.align + ';';
7089 if(typeof(config.valign) != 'undefined' && config.valign.length){
7090 td.style += ' vertical-align:' + config.valign + ';';
7093 if(typeof(config.width) != 'undefined'){
7094 td.style += ' width:' + config.width + 'px;';
7097 if(typeof(config.cursor) != 'undefined'){
7098 td.style += ' cursor:' + config.cursor + ';';
7101 if(typeof(config.cls) != 'undefined'){
7102 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
7105 ['xs','sm','md','lg'].map(function(size){
7107 if(typeof(config[size]) == 'undefined'){
7111 if (!config[size]) { // 0 = hidden
7112 td.cls += ' hidden-' + size;
7116 td.cls += ' col-' + size + '-' + config[size];
7124 row.cellObjects = cellObjects;
7132 onBeforeLoad : function()
7141 this.el.select('tbody', true).first().dom.innerHTML = '';
7144 * Show or hide a row.
7145 * @param {Number} rowIndex to show or hide
7146 * @param {Boolean} state hide
7148 setRowVisibility : function(rowIndex, state)
7150 var bt = this.mainBody.dom;
7152 var rows = this.el.select('tbody > tr', true).elements;
7154 if(typeof(rows[rowIndex]) == 'undefined'){
7157 rows[rowIndex].dom.style.display = state ? '' : 'none';
7161 getSelectionModel : function(){
7163 this.selModel = new Roo.bootstrap.Table.RowSelectionModel({grid: this});
7165 return this.selModel;
7168 * Render the Roo.bootstrap object from renderder
7170 renderCellObject : function(r)
7174 r.cfg.parentId = (typeof(r.container) == 'string') ? r.container : r.container.id;
7176 var t = r.cfg.render(r.container);
7179 Roo.each(r.cfg.cn, function(c){
7181 container: t.getChildContainer(),
7184 _this.renderCellObject(child);
7189 getRowIndex : function(row)
7193 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
7204 * Returns the grid's underlying element = used by panel.Grid
7205 * @return {Element} The element
7207 getGridEl : function(){
7211 * Forces a resize - used by panel.Grid
7212 * @return {Element} The element
7214 autoSize : function()
7216 //var ctr = Roo.get(this.container.dom.parentElement);
7217 var ctr = Roo.get(this.el.dom);
7219 var thd = this.getGridEl().select('thead',true).first();
7220 var tbd = this.getGridEl().select('tbody', true).first();
7221 var tfd = this.getGridEl().select('tfoot', true).first();
7223 var cw = ctr.getWidth();
7227 tbd.setSize(ctr.getWidth(),
7228 ctr.getHeight() - ((thd ? thd.getHeight() : 0) + (tfd ? tfd.getHeight() : 0))
7230 var barsize = (tbd.dom.offsetWidth - tbd.dom.clientWidth);
7233 cw = Math.max(cw, this.totalWidth);
7234 this.getGridEl().select('tr',true).setWidth(cw);
7235 // resize 'expandable coloumn?
7237 return; // we doe not have a view in this design..
7240 onBodyScroll: function()
7242 //Roo.log("body scrolled');" + this.mainBody.dom.scrollLeft);
7244 this.mainHead.setStyle({
7245 'position' : 'relative',
7246 'left': (-1* this.mainBody.dom.scrollLeft) + 'px'
7252 var scrollHeight = this.mainBody.dom.scrollHeight;
7254 var scrollTop = Math.ceil(this.mainBody.getScroll().top);
7256 var height = this.mainBody.getHeight();
7258 if(scrollHeight - height == scrollTop) {
7260 var total = this.ds.getTotalCount();
7262 if(this.footer.cursor + this.footer.pageSize < total){
7264 this.footer.ds.load({
7266 start : this.footer.cursor + this.footer.pageSize,
7267 limit : this.footer.pageSize
7277 onHeaderChange : function()
7279 var header = this.renderHeader();
7280 var table = this.el.select('table', true).first();
7282 this.mainHead.remove();
7283 this.mainHead = table.createChild(header, this.mainBody, false);
7286 onHiddenChange : function(colModel, colIndex, hidden)
7288 var thSelector = '#' + this.id + ' .x-hcol-' + colIndex;
7289 var tdSelector = '#' + this.id + ' .x-col-' + colIndex;
7291 this.CSS.updateRule(thSelector, "display", "");
7292 this.CSS.updateRule(tdSelector, "display", "");
7295 this.CSS.updateRule(thSelector, "display", "none");
7296 this.CSS.updateRule(tdSelector, "display", "none");
7299 this.onHeaderChange();
7303 setColumnWidth: function(col_index, width)
7305 // width = "md-2 xs-2..."
7306 if(!this.colModel.config[col_index]) {
7310 var w = width.split(" ");
7312 var rows = this.el.dom.getElementsByClassName("x-col-"+col_index);
7314 var h_row = this.el.dom.getElementsByClassName("x-hcol-"+col_index);
7317 for(var j = 0; j < w.length; j++) {
7323 var size_cls = w[j].split("-");
7325 if(!Number.isInteger(size_cls[1] * 1)) {
7329 if(!this.colModel.config[col_index][size_cls[0]]) {
7333 if(!h_row[0].classList.contains("col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]])) {
7337 h_row[0].classList.replace(
7338 "col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]],
7339 "col-"+size_cls[0]+"-"+size_cls[1]
7342 for(var i = 0; i < rows.length; i++) {
7344 var size_cls = w[j].split("-");
7346 if(!Number.isInteger(size_cls[1] * 1)) {
7350 if(!this.colModel.config[col_index][size_cls[0]]) {
7354 if(!rows[i].classList.contains("col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]])) {
7358 rows[i].classList.replace(
7359 "col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]],
7360 "col-"+size_cls[0]+"-"+size_cls[1]
7364 this.colModel.config[col_index][size_cls[0]] = size_cls[1];
7379 * @class Roo.bootstrap.TableCell
7380 * @extends Roo.bootstrap.Component
7381 * Bootstrap TableCell class
7382 * @cfg {String} html cell contain text
7383 * @cfg {String} cls cell class
7384 * @cfg {String} tag cell tag (td|th) default td
7385 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
7386 * @cfg {String} align Aligns the content in a cell
7387 * @cfg {String} axis Categorizes cells
7388 * @cfg {String} bgcolor Specifies the background color of a cell
7389 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7390 * @cfg {Number} colspan Specifies the number of columns a cell should span
7391 * @cfg {String} headers Specifies one or more header cells a cell is related to
7392 * @cfg {Number} height Sets the height of a cell
7393 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
7394 * @cfg {Number} rowspan Sets the number of rows a cell should span
7395 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
7396 * @cfg {String} valign Vertical aligns the content in a cell
7397 * @cfg {Number} width Specifies the width of a cell
7400 * Create a new TableCell
7401 * @param {Object} config The config object
7404 Roo.bootstrap.TableCell = function(config){
7405 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
7408 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
7428 getAutoCreate : function(){
7429 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
7449 cfg.align=this.align
7455 cfg.bgcolor=this.bgcolor
7458 cfg.charoff=this.charoff
7461 cfg.colspan=this.colspan
7464 cfg.headers=this.headers
7467 cfg.height=this.height
7470 cfg.nowrap=this.nowrap
7473 cfg.rowspan=this.rowspan
7476 cfg.scope=this.scope
7479 cfg.valign=this.valign
7482 cfg.width=this.width
7501 * @class Roo.bootstrap.TableRow
7502 * @extends Roo.bootstrap.Component
7503 * Bootstrap TableRow class
7504 * @cfg {String} cls row class
7505 * @cfg {String} align Aligns the content in a table row
7506 * @cfg {String} bgcolor Specifies a background color for a table row
7507 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7508 * @cfg {String} valign Vertical aligns the content in a table row
7511 * Create a new TableRow
7512 * @param {Object} config The config object
7515 Roo.bootstrap.TableRow = function(config){
7516 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
7519 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
7527 getAutoCreate : function(){
7528 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
7538 cfg.align = this.align;
7541 cfg.bgcolor = this.bgcolor;
7544 cfg.charoff = this.charoff;
7547 cfg.valign = this.valign;
7565 * @class Roo.bootstrap.TableBody
7566 * @extends Roo.bootstrap.Component
7567 * Bootstrap TableBody class
7568 * @cfg {String} cls element class
7569 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
7570 * @cfg {String} align Aligns the content inside the element
7571 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
7572 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
7575 * Create a new TableBody
7576 * @param {Object} config The config object
7579 Roo.bootstrap.TableBody = function(config){
7580 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
7583 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
7591 getAutoCreate : function(){
7592 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
7606 cfg.align = this.align;
7609 cfg.charoff = this.charoff;
7612 cfg.valign = this.valign;
7619 // initEvents : function()
7626 // this.store = Roo.factory(this.store, Roo.data);
7627 // this.store.on('load', this.onLoad, this);
7629 // this.store.load();
7633 // onLoad: function ()
7635 // this.fireEvent('load', this);
7645 * Ext JS Library 1.1.1
7646 * Copyright(c) 2006-2007, Ext JS, LLC.
7648 * Originally Released Under LGPL - original licence link has changed is not relivant.
7651 * <script type="text/javascript">
7654 // as we use this in bootstrap.
7655 Roo.namespace('Roo.form');
7657 * @class Roo.form.Action
7658 * Internal Class used to handle form actions
7660 * @param {Roo.form.BasicForm} el The form element or its id
7661 * @param {Object} config Configuration options
7666 // define the action interface
7667 Roo.form.Action = function(form, options){
7669 this.options = options || {};
7672 * Client Validation Failed
7675 Roo.form.Action.CLIENT_INVALID = 'client';
7677 * Server Validation Failed
7680 Roo.form.Action.SERVER_INVALID = 'server';
7682 * Connect to Server Failed
7685 Roo.form.Action.CONNECT_FAILURE = 'connect';
7687 * Reading Data from Server Failed
7690 Roo.form.Action.LOAD_FAILURE = 'load';
7692 Roo.form.Action.prototype = {
7694 failureType : undefined,
7695 response : undefined,
7699 run : function(options){
7704 success : function(response){
7709 handleResponse : function(response){
7713 // default connection failure
7714 failure : function(response){
7716 this.response = response;
7717 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7718 this.form.afterAction(this, false);
7721 processResponse : function(response){
7722 this.response = response;
7723 if(!response.responseText){
7726 this.result = this.handleResponse(response);
7730 // utility functions used internally
7731 getUrl : function(appendParams){
7732 var url = this.options.url || this.form.url || this.form.el.dom.action;
7734 var p = this.getParams();
7736 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
7742 getMethod : function(){
7743 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
7746 getParams : function(){
7747 var bp = this.form.baseParams;
7748 var p = this.options.params;
7750 if(typeof p == "object"){
7751 p = Roo.urlEncode(Roo.applyIf(p, bp));
7752 }else if(typeof p == 'string' && bp){
7753 p += '&' + Roo.urlEncode(bp);
7756 p = Roo.urlEncode(bp);
7761 createCallback : function(){
7763 success: this.success,
7764 failure: this.failure,
7766 timeout: (this.form.timeout*1000),
7767 upload: this.form.fileUpload ? this.success : undefined
7772 Roo.form.Action.Submit = function(form, options){
7773 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
7776 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
7779 haveProgress : false,
7780 uploadComplete : false,
7782 // uploadProgress indicator.
7783 uploadProgress : function()
7785 if (!this.form.progressUrl) {
7789 if (!this.haveProgress) {
7790 Roo.MessageBox.progress("Uploading", "Uploading");
7792 if (this.uploadComplete) {
7793 Roo.MessageBox.hide();
7797 this.haveProgress = true;
7799 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
7801 var c = new Roo.data.Connection();
7803 url : this.form.progressUrl,
7808 success : function(req){
7809 //console.log(data);
7813 rdata = Roo.decode(req.responseText)
7815 Roo.log("Invalid data from server..");
7819 if (!rdata || !rdata.success) {
7821 Roo.MessageBox.alert(Roo.encode(rdata));
7824 var data = rdata.data;
7826 if (this.uploadComplete) {
7827 Roo.MessageBox.hide();
7832 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
7833 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
7836 this.uploadProgress.defer(2000,this);
7839 failure: function(data) {
7840 Roo.log('progress url failed ');
7851 // run get Values on the form, so it syncs any secondary forms.
7852 this.form.getValues();
7854 var o = this.options;
7855 var method = this.getMethod();
7856 var isPost = method == 'POST';
7857 if(o.clientValidation === false || this.form.isValid()){
7859 if (this.form.progressUrl) {
7860 this.form.findField('UPLOAD_IDENTIFIER').setValue(
7861 (new Date() * 1) + '' + Math.random());
7866 Roo.Ajax.request(Roo.apply(this.createCallback(), {
7867 form:this.form.el.dom,
7868 url:this.getUrl(!isPost),
7870 params:isPost ? this.getParams() : null,
7871 isUpload: this.form.fileUpload
7874 this.uploadProgress();
7876 }else if (o.clientValidation !== false){ // client validation failed
7877 this.failureType = Roo.form.Action.CLIENT_INVALID;
7878 this.form.afterAction(this, false);
7882 success : function(response)
7884 this.uploadComplete= true;
7885 if (this.haveProgress) {
7886 Roo.MessageBox.hide();
7890 var result = this.processResponse(response);
7891 if(result === true || result.success){
7892 this.form.afterAction(this, true);
7896 this.form.markInvalid(result.errors);
7897 this.failureType = Roo.form.Action.SERVER_INVALID;
7899 this.form.afterAction(this, false);
7901 failure : function(response)
7903 this.uploadComplete= true;
7904 if (this.haveProgress) {
7905 Roo.MessageBox.hide();
7908 this.response = response;
7909 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7910 this.form.afterAction(this, false);
7913 handleResponse : function(response){
7914 if(this.form.errorReader){
7915 var rs = this.form.errorReader.read(response);
7918 for(var i = 0, len = rs.records.length; i < len; i++) {
7919 var r = rs.records[i];
7923 if(errors.length < 1){
7927 success : rs.success,
7933 ret = Roo.decode(response.responseText);
7937 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
7947 Roo.form.Action.Load = function(form, options){
7948 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
7949 this.reader = this.form.reader;
7952 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
7957 Roo.Ajax.request(Roo.apply(
7958 this.createCallback(), {
7959 method:this.getMethod(),
7960 url:this.getUrl(false),
7961 params:this.getParams()
7965 success : function(response){
7967 var result = this.processResponse(response);
7968 if(result === true || !result.success || !result.data){
7969 this.failureType = Roo.form.Action.LOAD_FAILURE;
7970 this.form.afterAction(this, false);
7973 this.form.clearInvalid();
7974 this.form.setValues(result.data);
7975 this.form.afterAction(this, true);
7978 handleResponse : function(response){
7979 if(this.form.reader){
7980 var rs = this.form.reader.read(response);
7981 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
7983 success : rs.success,
7987 return Roo.decode(response.responseText);
7991 Roo.form.Action.ACTION_TYPES = {
7992 'load' : Roo.form.Action.Load,
7993 'submit' : Roo.form.Action.Submit
8002 * @class Roo.bootstrap.Form
8003 * @extends Roo.bootstrap.Component
8004 * Bootstrap Form class
8005 * @cfg {String} method GET | POST (default POST)
8006 * @cfg {String} labelAlign top | left (default top)
8007 * @cfg {String} align left | right - for navbars
8008 * @cfg {Boolean} loadMask load mask when submit (default true)
8013 * @param {Object} config The config object
8017 Roo.bootstrap.Form = function(config){
8019 Roo.bootstrap.Form.superclass.constructor.call(this, config);
8021 Roo.bootstrap.Form.popover.apply();
8025 * @event clientvalidation
8026 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
8027 * @param {Form} this
8028 * @param {Boolean} valid true if the form has passed client-side validation
8030 clientvalidation: true,
8032 * @event beforeaction
8033 * Fires before any action is performed. Return false to cancel the action.
8034 * @param {Form} this
8035 * @param {Action} action The action to be performed
8039 * @event actionfailed
8040 * Fires when an action fails.
8041 * @param {Form} this
8042 * @param {Action} action The action that failed
8044 actionfailed : true,
8046 * @event actioncomplete
8047 * Fires when an action is completed.
8048 * @param {Form} this
8049 * @param {Action} action The action that completed
8051 actioncomplete : true
8055 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
8058 * @cfg {String} method
8059 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
8064 * The URL to use for form actions if one isn't supplied in the action options.
8067 * @cfg {Boolean} fileUpload
8068 * Set to true if this form is a file upload.
8072 * @cfg {Object} baseParams
8073 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
8077 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
8081 * @cfg {Sting} align (left|right) for navbar forms
8086 activeAction : null,
8089 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
8090 * element by passing it or its id or mask the form itself by passing in true.
8093 waitMsgTarget : false,
8098 * @cfg {Boolean} errorMask (true|false) default false
8103 * @cfg {Number} maskOffset Default 100
8108 * @cfg {Boolean} maskBody
8112 getAutoCreate : function(){
8116 method : this.method || 'POST',
8117 id : this.id || Roo.id(),
8120 if (this.parent().xtype.match(/^Nav/)) {
8121 cfg.cls = 'navbar-form form-inline navbar-' + this.align;
8125 if (this.labelAlign == 'left' ) {
8126 cfg.cls += ' form-horizontal';
8132 initEvents : function()
8134 this.el.on('submit', this.onSubmit, this);
8135 // this was added as random key presses on the form where triggering form submit.
8136 this.el.on('keypress', function(e) {
8137 if (e.getCharCode() != 13) {
8140 // we might need to allow it for textareas.. and some other items.
8141 // check e.getTarget().
8143 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
8147 Roo.log("keypress blocked");
8155 onSubmit : function(e){
8160 * Returns true if client-side validation on the form is successful.
8163 isValid : function(){
8164 var items = this.getItems();
8168 items.each(function(f){
8174 Roo.log('invalid field: ' + f.name);
8178 if(!target && f.el.isVisible(true)){
8184 if(this.errorMask && !valid){
8185 Roo.bootstrap.Form.popover.mask(this, target);
8192 * Returns true if any fields in this form have changed since their original load.
8195 isDirty : function(){
8197 var items = this.getItems();
8198 items.each(function(f){
8208 * Performs a predefined action (submit or load) or custom actions you define on this form.
8209 * @param {String} actionName The name of the action type
8210 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
8211 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
8212 * accept other config options):
8214 Property Type Description
8215 ---------------- --------------- ----------------------------------------------------------------------------------
8216 url String The url for the action (defaults to the form's url)
8217 method String The form method to use (defaults to the form's method, or POST if not defined)
8218 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
8219 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
8220 validate the form on the client (defaults to false)
8222 * @return {BasicForm} this
8224 doAction : function(action, options){
8225 if(typeof action == 'string'){
8226 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
8228 if(this.fireEvent('beforeaction', this, action) !== false){
8229 this.beforeAction(action);
8230 action.run.defer(100, action);
8236 beforeAction : function(action){
8237 var o = action.options;
8242 Roo.get(document.body).mask(o.waitMsg || "Sending", 'x-mask-loading')
8244 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
8247 // not really supported yet.. ??
8249 //if(this.waitMsgTarget === true){
8250 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
8251 //}else if(this.waitMsgTarget){
8252 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
8253 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
8255 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
8261 afterAction : function(action, success){
8262 this.activeAction = null;
8263 var o = action.options;
8268 Roo.get(document.body).unmask();
8274 //if(this.waitMsgTarget === true){
8275 // this.el.unmask();
8276 //}else if(this.waitMsgTarget){
8277 // this.waitMsgTarget.unmask();
8279 // Roo.MessageBox.updateProgress(1);
8280 // Roo.MessageBox.hide();
8287 Roo.callback(o.success, o.scope, [this, action]);
8288 this.fireEvent('actioncomplete', this, action);
8292 // failure condition..
8293 // we have a scenario where updates need confirming.
8294 // eg. if a locking scenario exists..
8295 // we look for { errors : { needs_confirm : true }} in the response.
8297 (typeof(action.result) != 'undefined') &&
8298 (typeof(action.result.errors) != 'undefined') &&
8299 (typeof(action.result.errors.needs_confirm) != 'undefined')
8302 Roo.log("not supported yet");
8305 Roo.MessageBox.confirm(
8306 "Change requires confirmation",
8307 action.result.errorMsg,
8312 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
8322 Roo.callback(o.failure, o.scope, [this, action]);
8323 // show an error message if no failed handler is set..
8324 if (!this.hasListener('actionfailed')) {
8325 Roo.log("need to add dialog support");
8327 Roo.MessageBox.alert("Error",
8328 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
8329 action.result.errorMsg :
8330 "Saving Failed, please check your entries or try again"
8335 this.fireEvent('actionfailed', this, action);
8340 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
8341 * @param {String} id The value to search for
8344 findField : function(id){
8345 var items = this.getItems();
8346 var field = items.get(id);
8348 items.each(function(f){
8349 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
8356 return field || null;
8359 * Mark fields in this form invalid in bulk.
8360 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
8361 * @return {BasicForm} this
8363 markInvalid : function(errors){
8364 if(errors instanceof Array){
8365 for(var i = 0, len = errors.length; i < len; i++){
8366 var fieldError = errors[i];
8367 var f = this.findField(fieldError.id);
8369 f.markInvalid(fieldError.msg);
8375 if(typeof errors[id] != 'function' && (field = this.findField(id))){
8376 field.markInvalid(errors[id]);
8380 //Roo.each(this.childForms || [], function (f) {
8381 // f.markInvalid(errors);
8388 * Set values for fields in this form in bulk.
8389 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
8390 * @return {BasicForm} this
8392 setValues : function(values){
8393 if(values instanceof Array){ // array of objects
8394 for(var i = 0, len = values.length; i < len; i++){
8396 var f = this.findField(v.id);
8398 f.setValue(v.value);
8399 if(this.trackResetOnLoad){
8400 f.originalValue = f.getValue();
8404 }else{ // object hash
8407 if(typeof values[id] != 'function' && (field = this.findField(id))){
8409 if (field.setFromData &&
8411 field.displayField &&
8412 // combos' with local stores can
8413 // be queried via setValue()
8414 // to set their value..
8415 (field.store && !field.store.isLocal)
8419 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
8420 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
8421 field.setFromData(sd);
8423 } else if(field.setFromData && (field.store && !field.store.isLocal)) {
8425 field.setFromData(values);
8428 field.setValue(values[id]);
8432 if(this.trackResetOnLoad){
8433 field.originalValue = field.getValue();
8439 //Roo.each(this.childForms || [], function (f) {
8440 // f.setValues(values);
8447 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
8448 * they are returned as an array.
8449 * @param {Boolean} asString
8452 getValues : function(asString){
8453 //if (this.childForms) {
8454 // copy values from the child forms
8455 // Roo.each(this.childForms, function (f) {
8456 // this.setValues(f.getValues());
8462 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
8463 if(asString === true){
8466 return Roo.urlDecode(fs);
8470 * Returns the fields in this form as an object with key/value pairs.
8471 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
8474 getFieldValues : function(with_hidden)
8476 var items = this.getItems();
8478 items.each(function(f){
8484 var v = f.getValue();
8486 if (f.inputType =='radio') {
8487 if (typeof(ret[f.getName()]) == 'undefined') {
8488 ret[f.getName()] = ''; // empty..
8491 if (!f.el.dom.checked) {
8499 if(f.xtype == 'MoneyField'){
8500 ret[f.currencyName] = f.getCurrency();
8503 // not sure if this supported any more..
8504 if ((typeof(v) == 'object') && f.getRawValue) {
8505 v = f.getRawValue() ; // dates..
8507 // combo boxes where name != hiddenName...
8508 if (f.name !== false && f.name != '' && f.name != f.getName()) {
8509 ret[f.name] = f.getRawValue();
8511 ret[f.getName()] = v;
8518 * Clears all invalid messages in this form.
8519 * @return {BasicForm} this
8521 clearInvalid : function(){
8522 var items = this.getItems();
8524 items.each(function(f){
8533 * @return {BasicForm} this
8536 var items = this.getItems();
8537 items.each(function(f){
8541 Roo.each(this.childForms || [], function (f) {
8549 getItems : function()
8551 var r=new Roo.util.MixedCollection(false, function(o){
8552 return o.id || (o.id = Roo.id());
8554 var iter = function(el) {
8561 Roo.each(el.items,function(e) {
8570 hideFields : function(items)
8572 Roo.each(items, function(i){
8574 var f = this.findField(i);
8585 showFields : function(items)
8587 Roo.each(items, function(i){
8589 var f = this.findField(i);
8602 Roo.apply(Roo.bootstrap.Form, {
8629 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
8630 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
8631 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
8632 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
8635 this.maskEl.top.enableDisplayMode("block");
8636 this.maskEl.left.enableDisplayMode("block");
8637 this.maskEl.bottom.enableDisplayMode("block");
8638 this.maskEl.right.enableDisplayMode("block");
8640 this.toolTip = new Roo.bootstrap.Tooltip({
8641 cls : 'roo-form-error-popover',
8643 'left' : ['r-l', [-2,0], 'right'],
8644 'right' : ['l-r', [2,0], 'left'],
8645 'bottom' : ['tl-bl', [0,2], 'top'],
8646 'top' : [ 'bl-tl', [0,-2], 'bottom']
8650 this.toolTip.render(Roo.get(document.body));
8652 this.toolTip.el.enableDisplayMode("block");
8654 Roo.get(document.body).on('click', function(){
8658 Roo.get(document.body).on('touchstart', function(){
8662 this.isApplied = true
8665 mask : function(form, target)
8669 this.target = target;
8671 if(!this.form.errorMask || !target.el){
8675 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.modal', 100, true) || Roo.get(document.body);
8677 Roo.log(scrollable);
8679 var ot = this.target.el.calcOffsetsTo(scrollable);
8681 var scrollTo = ot[1] - this.form.maskOffset;
8683 scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
8685 scrollable.scrollTo('top', scrollTo);
8687 var box = this.target.el.getBox();
8689 var zIndex = Roo.bootstrap.Modal.zIndex++;
8692 this.maskEl.top.setStyle('position', 'absolute');
8693 this.maskEl.top.setStyle('z-index', zIndex);
8694 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
8695 this.maskEl.top.setLeft(0);
8696 this.maskEl.top.setTop(0);
8697 this.maskEl.top.show();
8699 this.maskEl.left.setStyle('position', 'absolute');
8700 this.maskEl.left.setStyle('z-index', zIndex);
8701 this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
8702 this.maskEl.left.setLeft(0);
8703 this.maskEl.left.setTop(box.y - this.padding);
8704 this.maskEl.left.show();
8706 this.maskEl.bottom.setStyle('position', 'absolute');
8707 this.maskEl.bottom.setStyle('z-index', zIndex);
8708 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
8709 this.maskEl.bottom.setLeft(0);
8710 this.maskEl.bottom.setTop(box.bottom + this.padding);
8711 this.maskEl.bottom.show();
8713 this.maskEl.right.setStyle('position', 'absolute');
8714 this.maskEl.right.setStyle('z-index', zIndex);
8715 this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
8716 this.maskEl.right.setLeft(box.right + this.padding);
8717 this.maskEl.right.setTop(box.y - this.padding);
8718 this.maskEl.right.show();
8720 this.toolTip.bindEl = this.target.el;
8722 this.toolTip.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
8724 var tip = this.target.blankText;
8726 if(this.target.getValue() !== '' ) {
8728 if (this.target.invalidText.length) {
8729 tip = this.target.invalidText;
8730 } else if (this.target.regexText.length){
8731 tip = this.target.regexText;
8735 this.toolTip.show(tip);
8737 this.intervalID = window.setInterval(function() {
8738 Roo.bootstrap.Form.popover.unmask();
8741 window.onwheel = function(){ return false;};
8743 (function(){ this.isMasked = true; }).defer(500, this);
8749 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
8753 this.maskEl.top.setStyle('position', 'absolute');
8754 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
8755 this.maskEl.top.hide();
8757 this.maskEl.left.setStyle('position', 'absolute');
8758 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
8759 this.maskEl.left.hide();
8761 this.maskEl.bottom.setStyle('position', 'absolute');
8762 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
8763 this.maskEl.bottom.hide();
8765 this.maskEl.right.setStyle('position', 'absolute');
8766 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
8767 this.maskEl.right.hide();
8769 this.toolTip.hide();
8771 this.toolTip.el.hide();
8773 window.onwheel = function(){ return true;};
8775 if(this.intervalID){
8776 window.clearInterval(this.intervalID);
8777 this.intervalID = false;
8780 this.isMasked = false;
8790 * Ext JS Library 1.1.1
8791 * Copyright(c) 2006-2007, Ext JS, LLC.
8793 * Originally Released Under LGPL - original licence link has changed is not relivant.
8796 * <script type="text/javascript">
8799 * @class Roo.form.VTypes
8800 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
8803 Roo.form.VTypes = function(){
8804 // closure these in so they are only created once.
8805 var alpha = /^[a-zA-Z_]+$/;
8806 var alphanum = /^[a-zA-Z0-9_]+$/;
8807 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
8808 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
8810 // All these messages and functions are configurable
8813 * The function used to validate email addresses
8814 * @param {String} value The email address
8816 'email' : function(v){
8817 return email.test(v);
8820 * The error text to display when the email validation function returns false
8823 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
8825 * The keystroke filter mask to be applied on email input
8828 'emailMask' : /[a-z0-9_\.\-@]/i,
8831 * The function used to validate URLs
8832 * @param {String} value The URL
8834 'url' : function(v){
8838 * The error text to display when the url validation function returns false
8841 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
8844 * The function used to validate alpha values
8845 * @param {String} value The value
8847 'alpha' : function(v){
8848 return alpha.test(v);
8851 * The error text to display when the alpha validation function returns false
8854 'alphaText' : 'This field should only contain letters and _',
8856 * The keystroke filter mask to be applied on alpha input
8859 'alphaMask' : /[a-z_]/i,
8862 * The function used to validate alphanumeric values
8863 * @param {String} value The value
8865 'alphanum' : function(v){
8866 return alphanum.test(v);
8869 * The error text to display when the alphanumeric validation function returns false
8872 'alphanumText' : 'This field should only contain letters, numbers and _',
8874 * The keystroke filter mask to be applied on alphanumeric input
8877 'alphanumMask' : /[a-z0-9_]/i
8887 * @class Roo.bootstrap.Input
8888 * @extends Roo.bootstrap.Component
8889 * Bootstrap Input class
8890 * @cfg {Boolean} disabled is it disabled
8891 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
8892 * @cfg {String} name name of the input
8893 * @cfg {string} fieldLabel - the label associated
8894 * @cfg {string} placeholder - placeholder to put in text.
8895 * @cfg {string} before - input group add on before
8896 * @cfg {string} after - input group add on after
8897 * @cfg {string} size - (lg|sm) or leave empty..
8898 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
8899 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
8900 * @cfg {Number} md colspan out of 12 for computer-sized screens
8901 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
8902 * @cfg {string} value default value of the input
8903 * @cfg {Number} labelWidth set the width of label
8904 * @cfg {Number} labellg set the width of label (1-12)
8905 * @cfg {Number} labelmd set the width of label (1-12)
8906 * @cfg {Number} labelsm set the width of label (1-12)
8907 * @cfg {Number} labelxs set the width of label (1-12)
8908 * @cfg {String} labelAlign (top|left)
8909 * @cfg {Boolean} readOnly Specifies that the field should be read-only
8910 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
8911 * @cfg {String} indicatorpos (left|right) default left
8912 * @cfg {String} capture (user|camera) use for file input only. (default empty)
8913 * @cfg {String} accept (image|video|audio) use for file input only. (default empty)
8915 * @cfg {String} align (left|center|right) Default left
8916 * @cfg {Boolean} forceFeedback (true|false) Default false
8919 * Create a new Input
8920 * @param {Object} config The config object
8923 Roo.bootstrap.Input = function(config){
8925 Roo.bootstrap.Input.superclass.constructor.call(this, config);
8930 * Fires when this field receives input focus.
8931 * @param {Roo.form.Field} this
8936 * Fires when this field loses input focus.
8937 * @param {Roo.form.Field} this
8942 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
8943 * {@link Roo.EventObject#getKey} to determine which key was pressed.
8944 * @param {Roo.form.Field} this
8945 * @param {Roo.EventObject} e The event object
8950 * Fires just before the field blurs if the field value has changed.
8951 * @param {Roo.form.Field} this
8952 * @param {Mixed} newValue The new value
8953 * @param {Mixed} oldValue The original value
8958 * Fires after the field has been marked as invalid.
8959 * @param {Roo.form.Field} this
8960 * @param {String} msg The validation message
8965 * Fires after the field has been validated with no errors.
8966 * @param {Roo.form.Field} this
8971 * Fires after the key up
8972 * @param {Roo.form.Field} this
8973 * @param {Roo.EventObject} e The event Object
8979 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
8981 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
8982 automatic validation (defaults to "keyup").
8984 validationEvent : "keyup",
8986 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
8988 validateOnBlur : true,
8990 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
8992 validationDelay : 250,
8994 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
8996 focusClass : "x-form-focus", // not needed???
9000 * @cfg {String} invalidClass DEPRICATED - code uses BS4 - is-valid / is-invalid
9002 invalidClass : "has-warning",
9005 * @cfg {String} validClass DEPRICATED - code uses BS4 - is-valid / is-invalid
9007 validClass : "has-success",
9010 * @cfg {Boolean} hasFeedback (true|false) default true
9015 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
9017 invalidFeedbackClass : "glyphicon-warning-sign",
9020 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
9022 validFeedbackClass : "glyphicon-ok",
9025 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
9027 selectOnFocus : false,
9030 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
9034 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
9039 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
9041 disableKeyFilter : false,
9044 * @cfg {Boolean} disabled True to disable the field (defaults to false).
9048 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
9052 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
9054 blankText : "Please complete this mandatory field",
9057 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
9061 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
9063 maxLength : Number.MAX_VALUE,
9065 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
9067 minLengthText : "The minimum length for this field is {0}",
9069 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
9071 maxLengthText : "The maximum length for this field is {0}",
9075 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
9076 * If available, this function will be called only after the basic validators all return true, and will be passed the
9077 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
9081 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
9082 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
9083 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
9087 * @cfg {String} regexText -- Depricated - use Invalid Text
9092 * @cfg {String} invalidText The error text to display if {@link #validator} test fails during validation (defaults to "")
9098 autocomplete: false,
9117 formatedValue : false,
9118 forceFeedback : false,
9120 indicatorpos : 'left',
9130 parentLabelAlign : function()
9133 while (parent.parent()) {
9134 parent = parent.parent();
9135 if (typeof(parent.labelAlign) !='undefined') {
9136 return parent.labelAlign;
9143 getAutoCreate : function()
9145 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9151 if(this.inputType != 'hidden'){
9152 cfg.cls = 'form-group' //input-group
9158 type : this.inputType,
9160 cls : 'form-control',
9161 placeholder : this.placeholder || '',
9162 autocomplete : this.autocomplete || 'new-password'
9165 if(this.capture.length){
9166 input.capture = this.capture;
9169 if(this.accept.length){
9170 input.accept = this.accept + "/*";
9174 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
9177 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9178 input.maxLength = this.maxLength;
9181 if (this.disabled) {
9182 input.disabled=true;
9185 if (this.readOnly) {
9186 input.readonly=true;
9190 input.name = this.name;
9194 input.cls += ' input-' + this.size;
9198 ['xs','sm','md','lg'].map(function(size){
9199 if (settings[size]) {
9200 cfg.cls += ' col-' + size + '-' + settings[size];
9204 var inputblock = input;
9208 cls: 'glyphicon form-control-feedback'
9211 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9214 cls : 'has-feedback',
9222 if (this.before || this.after) {
9225 cls : 'input-group',
9229 if (this.before && typeof(this.before) == 'string') {
9231 inputblock.cn.push({
9233 cls : 'roo-input-before input-group-addon input-group-prepend input-group-text',
9237 if (this.before && typeof(this.before) == 'object') {
9238 this.before = Roo.factory(this.before);
9240 inputblock.cn.push({
9242 cls : 'roo-input-before input-group-prepend input-group-text input-group-' +
9243 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
9247 inputblock.cn.push(input);
9249 if (this.after && typeof(this.after) == 'string') {
9250 inputblock.cn.push({
9252 cls : 'roo-input-after input-group-append input-group-text input-group-addon',
9256 if (this.after && typeof(this.after) == 'object') {
9257 this.after = Roo.factory(this.after);
9259 inputblock.cn.push({
9261 cls : 'roo-input-after input-group-append input-group-text input-group-' +
9262 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
9266 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9267 inputblock.cls += ' has-feedback';
9268 inputblock.cn.push(feedback);
9273 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
9274 tooltip : 'This field is required'
9276 if (Roo.bootstrap.version == 4) {
9279 style : 'display-none'
9282 if (align ==='left' && this.fieldLabel.length) {
9284 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
9291 cls : 'control-label col-form-label',
9292 html : this.fieldLabel
9303 var labelCfg = cfg.cn[1];
9304 var contentCfg = cfg.cn[2];
9306 if(this.indicatorpos == 'right'){
9311 cls : 'control-label col-form-label',
9315 html : this.fieldLabel
9329 labelCfg = cfg.cn[0];
9330 contentCfg = cfg.cn[1];
9334 if(this.labelWidth > 12){
9335 labelCfg.style = "width: " + this.labelWidth + 'px';
9338 if(this.labelWidth < 13 && this.labelmd == 0){
9339 this.labelmd = this.labelWidth;
9342 if(this.labellg > 0){
9343 labelCfg.cls += ' col-lg-' + this.labellg;
9344 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
9347 if(this.labelmd > 0){
9348 labelCfg.cls += ' col-md-' + this.labelmd;
9349 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
9352 if(this.labelsm > 0){
9353 labelCfg.cls += ' col-sm-' + this.labelsm;
9354 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
9357 if(this.labelxs > 0){
9358 labelCfg.cls += ' col-xs-' + this.labelxs;
9359 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
9363 } else if ( this.fieldLabel.length) {
9368 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
9369 tooltip : 'This field is required'
9373 //cls : 'input-group-addon',
9374 html : this.fieldLabel
9382 if(this.indicatorpos == 'right'){
9387 //cls : 'input-group-addon',
9388 html : this.fieldLabel
9393 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9394 tooltip : 'This field is required'
9414 if (this.parentType === 'Navbar' && this.parent().bar) {
9415 cfg.cls += ' navbar-form';
9418 if (this.parentType === 'NavGroup' && !(Roo.bootstrap.version == 4 && this.parent().form)) {
9419 // on BS4 we do this only if not form
9420 cfg.cls += ' navbar-form';
9428 * return the real input element.
9430 inputEl: function ()
9432 return this.el.select('input.form-control',true).first();
9435 tooltipEl : function()
9437 return this.inputEl();
9440 indicatorEl : function()
9442 if (Roo.bootstrap.version == 4) {
9443 return false; // not enabled in v4 yet.
9446 var indicator = this.el.select('i.roo-required-indicator',true).first();
9456 setDisabled : function(v)
9458 var i = this.inputEl().dom;
9460 i.removeAttribute('disabled');
9464 i.setAttribute('disabled','true');
9466 initEvents : function()
9469 this.inputEl().on("keydown" , this.fireKey, this);
9470 this.inputEl().on("focus", this.onFocus, this);
9471 this.inputEl().on("blur", this.onBlur, this);
9473 this.inputEl().relayEvent('keyup', this);
9475 this.indicator = this.indicatorEl();
9478 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible'); // changed from invisible??? -
9481 // reference to original value for reset
9482 this.originalValue = this.getValue();
9483 //Roo.form.TextField.superclass.initEvents.call(this);
9484 if(this.validationEvent == 'keyup'){
9485 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
9486 this.inputEl().on('keyup', this.filterValidation, this);
9488 else if(this.validationEvent !== false){
9489 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
9492 if(this.selectOnFocus){
9493 this.on("focus", this.preFocus, this);
9496 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
9497 this.inputEl().on("keypress", this.filterKeys, this);
9499 this.inputEl().relayEvent('keypress', this);
9502 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
9503 this.el.on("click", this.autoSize, this);
9506 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
9507 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
9510 if (typeof(this.before) == 'object') {
9511 this.before.render(this.el.select('.roo-input-before',true).first());
9513 if (typeof(this.after) == 'object') {
9514 this.after.render(this.el.select('.roo-input-after',true).first());
9517 this.inputEl().on('change', this.onChange, this);
9520 filterValidation : function(e){
9521 if(!e.isNavKeyPress()){
9522 this.validationTask.delay(this.validationDelay);
9526 * Validates the field value
9527 * @return {Boolean} True if the value is valid, else false
9529 validate : function(){
9530 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
9531 if(this.disabled || this.validateValue(this.getRawValue())){
9542 * Validates a value according to the field's validation rules and marks the field as invalid
9543 * if the validation fails
9544 * @param {Mixed} value The value to validate
9545 * @return {Boolean} True if the value is valid, else false
9547 validateValue : function(value)
9549 if(this.getVisibilityEl().hasClass('hidden')){
9553 if(value.length < 1) { // if it's blank
9554 if(this.allowBlank){
9560 if(value.length < this.minLength){
9563 if(value.length > this.maxLength){
9567 var vt = Roo.form.VTypes;
9568 if(!vt[this.vtype](value, this)){
9572 if(typeof this.validator == "function"){
9573 var msg = this.validator(value);
9577 if (typeof(msg) == 'string') {
9578 this.invalidText = msg;
9582 if(this.regex && !this.regex.test(value)){
9590 fireKey : function(e){
9591 //Roo.log('field ' + e.getKey());
9592 if(e.isNavKeyPress()){
9593 this.fireEvent("specialkey", this, e);
9596 focus : function (selectText){
9598 this.inputEl().focus();
9599 if(selectText === true){
9600 this.inputEl().dom.select();
9606 onFocus : function(){
9607 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9608 // this.el.addClass(this.focusClass);
9611 this.hasFocus = true;
9612 this.startValue = this.getValue();
9613 this.fireEvent("focus", this);
9617 beforeBlur : Roo.emptyFn,
9621 onBlur : function(){
9623 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9624 //this.el.removeClass(this.focusClass);
9626 this.hasFocus = false;
9627 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
9630 var v = this.getValue();
9631 if(String(v) !== String(this.startValue)){
9632 this.fireEvent('change', this, v, this.startValue);
9634 this.fireEvent("blur", this);
9637 onChange : function(e)
9639 var v = this.getValue();
9640 if(String(v) !== String(this.startValue)){
9641 this.fireEvent('change', this, v, this.startValue);
9647 * Resets the current field value to the originally loaded value and clears any validation messages
9650 this.setValue(this.originalValue);
9654 * Returns the name of the field
9655 * @return {Mixed} name The name field
9657 getName: function(){
9661 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
9662 * @return {Mixed} value The field value
9664 getValue : function(){
9666 var v = this.inputEl().getValue();
9671 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
9672 * @return {Mixed} value The field value
9674 getRawValue : function(){
9675 var v = this.inputEl().getValue();
9681 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
9682 * @param {Mixed} value The value to set
9684 setRawValue : function(v){
9685 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9688 selectText : function(start, end){
9689 var v = this.getRawValue();
9691 start = start === undefined ? 0 : start;
9692 end = end === undefined ? v.length : end;
9693 var d = this.inputEl().dom;
9694 if(d.setSelectionRange){
9695 d.setSelectionRange(start, end);
9696 }else if(d.createTextRange){
9697 var range = d.createTextRange();
9698 range.moveStart("character", start);
9699 range.moveEnd("character", v.length-end);
9706 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
9707 * @param {Mixed} value The value to set
9709 setValue : function(v){
9712 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9718 processValue : function(value){
9719 if(this.stripCharsRe){
9720 var newValue = value.replace(this.stripCharsRe, '');
9721 if(newValue !== value){
9722 this.setRawValue(newValue);
9729 preFocus : function(){
9731 if(this.selectOnFocus){
9732 this.inputEl().dom.select();
9735 filterKeys : function(e){
9737 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
9740 var c = e.getCharCode(), cc = String.fromCharCode(c);
9741 if(Roo.isIE && (e.isSpecialKey() || !cc)){
9744 if(!this.maskRe.test(cc)){
9749 * Clear any invalid styles/messages for this field
9751 clearInvalid : function(){
9753 if(!this.el || this.preventMark){ // not rendered
9758 this.el.removeClass([this.invalidClass, 'is-invalid']);
9760 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9762 var feedback = this.el.select('.form-control-feedback', true).first();
9765 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9771 this.indicator.removeClass('visible');
9772 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9775 this.fireEvent('valid', this);
9779 * Mark this field as valid
9781 markValid : function()
9783 if(!this.el || this.preventMark){ // not rendered...
9787 this.el.removeClass([this.invalidClass, this.validClass]);
9788 this.inputEl().removeClass(['is-valid', 'is-invalid']);
9790 var feedback = this.el.select('.form-control-feedback', true).first();
9793 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9797 this.indicator.removeClass('visible');
9798 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9805 if(this.allowBlank && !this.getRawValue().length){
9808 if (Roo.bootstrap.version == 3) {
9809 this.el.addClass(this.validClass);
9811 this.inputEl().addClass('is-valid');
9814 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9816 var feedback = this.el.select('.form-control-feedback', true).first();
9819 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9820 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9825 this.fireEvent('valid', this);
9829 * Mark this field as invalid
9830 * @param {String} msg The validation message
9832 markInvalid : function(msg)
9834 if(!this.el || this.preventMark){ // not rendered
9838 this.el.removeClass([this.invalidClass, this.validClass]);
9839 this.inputEl().removeClass(['is-valid', 'is-invalid']);
9841 var feedback = this.el.select('.form-control-feedback', true).first();
9844 this.el.select('.form-control-feedback', true).first().removeClass(
9845 [this.invalidFeedbackClass, this.validFeedbackClass]);
9852 if(this.allowBlank && !this.getRawValue().length){
9857 this.indicator.removeClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9858 this.indicator.addClass('visible');
9860 if (Roo.bootstrap.version == 3) {
9861 this.el.addClass(this.invalidClass);
9863 this.inputEl().addClass('is-invalid');
9868 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9870 var feedback = this.el.select('.form-control-feedback', true).first();
9873 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9875 if(this.getValue().length || this.forceFeedback){
9876 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9883 this.fireEvent('invalid', this, msg);
9886 SafariOnKeyDown : function(event)
9888 // this is a workaround for a password hang bug on chrome/ webkit.
9889 if (this.inputEl().dom.type != 'password') {
9893 var isSelectAll = false;
9895 if(this.inputEl().dom.selectionEnd > 0){
9896 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
9898 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
9899 event.preventDefault();
9904 if(isSelectAll && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
9906 event.preventDefault();
9907 // this is very hacky as keydown always get's upper case.
9909 var cc = String.fromCharCode(event.getCharCode());
9910 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
9914 adjustWidth : function(tag, w){
9915 tag = tag.toLowerCase();
9916 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
9917 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
9921 if(tag == 'textarea'){
9924 }else if(Roo.isOpera){
9928 if(tag == 'textarea'){
9936 setFieldLabel : function(v)
9942 if(this.indicatorEl()){
9943 var ar = this.el.select('label > span',true);
9945 if (ar.elements.length) {
9946 this.el.select('label > span',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9947 this.fieldLabel = v;
9951 var br = this.el.select('label',true);
9953 if(br.elements.length) {
9954 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9955 this.fieldLabel = v;
9959 Roo.log('Cannot Found any of label > span || label in input');
9963 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9964 this.fieldLabel = v;
9979 * @class Roo.bootstrap.TextArea
9980 * @extends Roo.bootstrap.Input
9981 * Bootstrap TextArea class
9982 * @cfg {Number} cols Specifies the visible width of a text area
9983 * @cfg {Number} rows Specifies the visible number of lines in a text area
9984 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
9985 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
9986 * @cfg {string} html text
9989 * Create a new TextArea
9990 * @param {Object} config The config object
9993 Roo.bootstrap.TextArea = function(config){
9994 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
9998 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
10008 getAutoCreate : function(){
10010 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
10016 if(this.inputType != 'hidden'){
10017 cfg.cls = 'form-group' //input-group
10025 value : this.value || '',
10026 html: this.html || '',
10027 cls : 'form-control',
10028 placeholder : this.placeholder || ''
10032 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
10033 input.maxLength = this.maxLength;
10037 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
10041 input.cols = this.cols;
10044 if (this.readOnly) {
10045 input.readonly = true;
10049 input.name = this.name;
10053 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
10057 ['xs','sm','md','lg'].map(function(size){
10058 if (settings[size]) {
10059 cfg.cls += ' col-' + size + '-' + settings[size];
10063 var inputblock = input;
10065 if(this.hasFeedback && !this.allowBlank){
10069 cls: 'glyphicon form-control-feedback'
10073 cls : 'has-feedback',
10082 if (this.before || this.after) {
10085 cls : 'input-group',
10089 inputblock.cn.push({
10091 cls : 'input-group-addon',
10096 inputblock.cn.push(input);
10098 if(this.hasFeedback && !this.allowBlank){
10099 inputblock.cls += ' has-feedback';
10100 inputblock.cn.push(feedback);
10104 inputblock.cn.push({
10106 cls : 'input-group-addon',
10113 if (align ==='left' && this.fieldLabel.length) {
10118 cls : 'control-label',
10119 html : this.fieldLabel
10130 if(this.labelWidth > 12){
10131 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
10134 if(this.labelWidth < 13 && this.labelmd == 0){
10135 this.labelmd = this.labelWidth;
10138 if(this.labellg > 0){
10139 cfg.cn[0].cls += ' col-lg-' + this.labellg;
10140 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
10143 if(this.labelmd > 0){
10144 cfg.cn[0].cls += ' col-md-' + this.labelmd;
10145 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
10148 if(this.labelsm > 0){
10149 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
10150 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
10153 if(this.labelxs > 0){
10154 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
10155 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
10158 } else if ( this.fieldLabel.length) {
10163 //cls : 'input-group-addon',
10164 html : this.fieldLabel
10182 if (this.disabled) {
10183 input.disabled=true;
10190 * return the real textarea element.
10192 inputEl: function ()
10194 return this.el.select('textarea.form-control',true).first();
10198 * Clear any invalid styles/messages for this field
10200 clearInvalid : function()
10203 if(!this.el || this.preventMark){ // not rendered
10207 var label = this.el.select('label', true).first();
10208 var icon = this.el.select('i.fa-star', true).first();
10213 this.el.removeClass( this.validClass);
10214 this.inputEl().removeClass('is-invalid');
10216 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10218 var feedback = this.el.select('.form-control-feedback', true).first();
10221 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
10226 this.fireEvent('valid', this);
10230 * Mark this field as valid
10232 markValid : function()
10234 if(!this.el || this.preventMark){ // not rendered
10238 this.el.removeClass([this.invalidClass, this.validClass]);
10239 this.inputEl().removeClass(['is-valid', 'is-invalid']);
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]);
10247 if(this.disabled || this.allowBlank){
10251 var label = this.el.select('label', true).first();
10252 var icon = this.el.select('i.fa-star', true).first();
10257 if (Roo.bootstrap.version == 3) {
10258 this.el.addClass(this.validClass);
10260 this.inputEl().addClass('is-valid');
10264 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
10266 var feedback = this.el.select('.form-control-feedback', true).first();
10269 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10270 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
10275 this.fireEvent('valid', this);
10279 * Mark this field as invalid
10280 * @param {String} msg The validation message
10282 markInvalid : function(msg)
10284 if(!this.el || this.preventMark){ // not rendered
10288 this.el.removeClass([this.invalidClass, this.validClass]);
10289 this.inputEl().removeClass(['is-valid', 'is-invalid']);
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]);
10297 if(this.disabled || this.allowBlank){
10301 var label = this.el.select('label', true).first();
10302 var icon = this.el.select('i.fa-star', true).first();
10304 if(!this.getValue().length && label && !icon){
10305 this.el.createChild({
10307 cls : 'text-danger fa fa-lg fa-star',
10308 tooltip : 'This field is required',
10309 style : 'margin-right:5px;'
10313 if (Roo.bootstrap.version == 3) {
10314 this.el.addClass(this.invalidClass);
10316 this.inputEl().addClass('is-invalid');
10319 // fixme ... this may be depricated need to test..
10320 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10322 var feedback = this.el.select('.form-control-feedback', true).first();
10325 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10327 if(this.getValue().length || this.forceFeedback){
10328 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
10335 this.fireEvent('invalid', this, msg);
10343 * trigger field - base class for combo..
10348 * @class Roo.bootstrap.TriggerField
10349 * @extends Roo.bootstrap.Input
10350 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
10351 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
10352 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
10353 * for which you can provide a custom implementation. For example:
10355 var trigger = new Roo.bootstrap.TriggerField();
10356 trigger.onTriggerClick = myTriggerFn;
10357 trigger.applyTo('my-field');
10360 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
10361 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
10362 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
10363 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
10364 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
10367 * Create a new TriggerField.
10368 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
10369 * to the base TextField)
10371 Roo.bootstrap.TriggerField = function(config){
10372 this.mimicing = false;
10373 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
10376 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
10378 * @cfg {String} triggerClass A CSS class to apply to the trigger
10381 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
10386 * @cfg {Boolean} removable (true|false) special filter default false
10390 /** @cfg {Boolean} grow @hide */
10391 /** @cfg {Number} growMin @hide */
10392 /** @cfg {Number} growMax @hide */
10398 autoSize: Roo.emptyFn,
10402 deferHeight : true,
10405 actionMode : 'wrap',
10410 getAutoCreate : function(){
10412 var align = this.labelAlign || this.parentLabelAlign();
10417 cls: 'form-group' //input-group
10424 type : this.inputType,
10425 cls : 'form-control',
10426 autocomplete: 'new-password',
10427 placeholder : this.placeholder || ''
10431 input.name = this.name;
10434 input.cls += ' input-' + this.size;
10437 if (this.disabled) {
10438 input.disabled=true;
10441 var inputblock = input;
10443 if(this.hasFeedback && !this.allowBlank){
10447 cls: 'glyphicon form-control-feedback'
10450 if(this.removable && !this.editable && !this.tickable){
10452 cls : 'has-feedback',
10458 cls : 'roo-combo-removable-btn close'
10465 cls : 'has-feedback',
10474 if(this.removable && !this.editable && !this.tickable){
10476 cls : 'roo-removable',
10482 cls : 'roo-combo-removable-btn close'
10489 if (this.before || this.after) {
10492 cls : 'input-group',
10496 inputblock.cn.push({
10498 cls : 'input-group-addon input-group-prepend input-group-text',
10503 inputblock.cn.push(input);
10505 if(this.hasFeedback && !this.allowBlank){
10506 inputblock.cls += ' has-feedback';
10507 inputblock.cn.push(feedback);
10511 inputblock.cn.push({
10513 cls : 'input-group-addon input-group-append input-group-text',
10522 var ibwrap = inputblock;
10527 cls: 'roo-select2-choices',
10531 cls: 'roo-select2-search-field',
10543 cls: 'roo-select2-container input-group',
10548 cls: 'form-hidden-field'
10554 if(!this.multiple && this.showToggleBtn){
10560 if (this.caret != false) {
10563 cls: 'fa fa-' + this.caret
10570 cls : 'input-group-addon input-group-append input-group-text btn dropdown-toggle',
10575 cls: 'combobox-clear',
10589 combobox.cls += ' roo-select2-container-multi';
10593 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
10594 tooltip : 'This field is required'
10596 if (Roo.bootstrap.version == 4) {
10599 style : 'display:none'
10604 if (align ==='left' && this.fieldLabel.length) {
10606 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
10613 cls : 'control-label',
10614 html : this.fieldLabel
10626 var labelCfg = cfg.cn[1];
10627 var contentCfg = cfg.cn[2];
10629 if(this.indicatorpos == 'right'){
10634 cls : 'control-label',
10638 html : this.fieldLabel
10652 labelCfg = cfg.cn[0];
10653 contentCfg = cfg.cn[1];
10656 if(this.labelWidth > 12){
10657 labelCfg.style = "width: " + this.labelWidth + 'px';
10660 if(this.labelWidth < 13 && this.labelmd == 0){
10661 this.labelmd = this.labelWidth;
10664 if(this.labellg > 0){
10665 labelCfg.cls += ' col-lg-' + this.labellg;
10666 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
10669 if(this.labelmd > 0){
10670 labelCfg.cls += ' col-md-' + this.labelmd;
10671 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
10674 if(this.labelsm > 0){
10675 labelCfg.cls += ' col-sm-' + this.labelsm;
10676 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
10679 if(this.labelxs > 0){
10680 labelCfg.cls += ' col-xs-' + this.labelxs;
10681 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
10684 } else if ( this.fieldLabel.length) {
10685 // Roo.log(" label");
10690 //cls : 'input-group-addon',
10691 html : this.fieldLabel
10699 if(this.indicatorpos == 'right'){
10707 html : this.fieldLabel
10721 // Roo.log(" no label && no align");
10728 ['xs','sm','md','lg'].map(function(size){
10729 if (settings[size]) {
10730 cfg.cls += ' col-' + size + '-' + settings[size];
10741 onResize : function(w, h){
10742 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
10743 // if(typeof w == 'number'){
10744 // var x = w - this.trigger.getWidth();
10745 // this.inputEl().setWidth(this.adjustWidth('input', x));
10746 // this.trigger.setStyle('left', x+'px');
10751 adjustSize : Roo.BoxComponent.prototype.adjustSize,
10754 getResizeEl : function(){
10755 return this.inputEl();
10759 getPositionEl : function(){
10760 return this.inputEl();
10764 alignErrorIcon : function(){
10765 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
10769 initEvents : function(){
10773 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
10774 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
10775 if(!this.multiple && this.showToggleBtn){
10776 this.trigger = this.el.select('span.dropdown-toggle',true).first();
10777 if(this.hideTrigger){
10778 this.trigger.setDisplayed(false);
10780 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10784 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
10787 if(this.removable && !this.editable && !this.tickable){
10788 var close = this.closeTriggerEl();
10791 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
10792 close.on('click', this.removeBtnClick, this, close);
10796 //this.trigger.addClassOnOver('x-form-trigger-over');
10797 //this.trigger.addClassOnClick('x-form-trigger-click');
10800 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
10804 closeTriggerEl : function()
10806 var close = this.el.select('.roo-combo-removable-btn', true).first();
10807 return close ? close : false;
10810 removeBtnClick : function(e, h, el)
10812 e.preventDefault();
10814 if(this.fireEvent("remove", this) !== false){
10816 this.fireEvent("afterremove", this)
10820 createList : function()
10822 this.list = Roo.get(document.body).createChild({
10823 tag: Roo.bootstrap.version == 4 ? 'div' : 'ul',
10824 cls: 'typeahead typeahead-long dropdown-menu',
10825 style: 'display:none'
10828 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
10833 initTrigger : function(){
10838 onDestroy : function(){
10840 this.trigger.removeAllListeners();
10841 // this.trigger.remove();
10844 // this.wrap.remove();
10846 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
10850 onFocus : function(){
10851 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
10853 if(!this.mimicing){
10854 this.wrap.addClass('x-trigger-wrap-focus');
10855 this.mimicing = true;
10856 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
10857 if(this.monitorTab){
10858 this.el.on("keydown", this.checkTab, this);
10865 checkTab : function(e){
10866 if(e.getKey() == e.TAB){
10867 this.triggerBlur();
10872 onBlur : function(){
10877 mimicBlur : function(e, t){
10879 if(!this.wrap.contains(t) && this.validateBlur()){
10880 this.triggerBlur();
10886 triggerBlur : function(){
10887 this.mimicing = false;
10888 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
10889 if(this.monitorTab){
10890 this.el.un("keydown", this.checkTab, this);
10892 //this.wrap.removeClass('x-trigger-wrap-focus');
10893 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
10897 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
10898 validateBlur : function(e, t){
10903 onDisable : function(){
10904 this.inputEl().dom.disabled = true;
10905 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
10907 // this.wrap.addClass('x-item-disabled');
10912 onEnable : function(){
10913 this.inputEl().dom.disabled = false;
10914 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
10916 // this.el.removeClass('x-item-disabled');
10921 onShow : function(){
10922 var ae = this.getActionEl();
10925 ae.dom.style.display = '';
10926 ae.dom.style.visibility = 'visible';
10932 onHide : function(){
10933 var ae = this.getActionEl();
10934 ae.dom.style.display = 'none';
10938 * The function that should handle the trigger's click event. This method does nothing by default until overridden
10939 * by an implementing function.
10941 * @param {EventObject} e
10943 onTriggerClick : Roo.emptyFn
10947 * Ext JS Library 1.1.1
10948 * Copyright(c) 2006-2007, Ext JS, LLC.
10950 * Originally Released Under LGPL - original licence link has changed is not relivant.
10953 * <script type="text/javascript">
10958 * @class Roo.data.SortTypes
10960 * Defines the default sorting (casting?) comparison functions used when sorting data.
10962 Roo.data.SortTypes = {
10964 * Default sort that does nothing
10965 * @param {Mixed} s The value being converted
10966 * @return {Mixed} The comparison value
10968 none : function(s){
10973 * The regular expression used to strip tags
10977 stripTagsRE : /<\/?[^>]+>/gi,
10980 * Strips all HTML tags to sort on text only
10981 * @param {Mixed} s The value being converted
10982 * @return {String} The comparison value
10984 asText : function(s){
10985 return String(s).replace(this.stripTagsRE, "");
10989 * Strips all HTML tags to sort on text only - Case insensitive
10990 * @param {Mixed} s The value being converted
10991 * @return {String} The comparison value
10993 asUCText : function(s){
10994 return String(s).toUpperCase().replace(this.stripTagsRE, "");
10998 * Case insensitive string
10999 * @param {Mixed} s The value being converted
11000 * @return {String} The comparison value
11002 asUCString : function(s) {
11003 return String(s).toUpperCase();
11008 * @param {Mixed} s The value being converted
11009 * @return {Number} The comparison value
11011 asDate : function(s) {
11015 if(s instanceof Date){
11016 return s.getTime();
11018 return Date.parse(String(s));
11023 * @param {Mixed} s The value being converted
11024 * @return {Float} The comparison value
11026 asFloat : function(s) {
11027 var val = parseFloat(String(s).replace(/,/g, ""));
11036 * @param {Mixed} s The value being converted
11037 * @return {Number} The comparison value
11039 asInt : function(s) {
11040 var val = parseInt(String(s).replace(/,/g, ""));
11048 * Ext JS Library 1.1.1
11049 * Copyright(c) 2006-2007, Ext JS, LLC.
11051 * Originally Released Under LGPL - original licence link has changed is not relivant.
11054 * <script type="text/javascript">
11058 * @class Roo.data.Record
11059 * Instances of this class encapsulate both record <em>definition</em> information, and record
11060 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
11061 * to access Records cached in an {@link Roo.data.Store} object.<br>
11063 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
11064 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
11067 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
11069 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
11070 * {@link #create}. The parameters are the same.
11071 * @param {Array} data An associative Array of data values keyed by the field name.
11072 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
11073 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
11074 * not specified an integer id is generated.
11076 Roo.data.Record = function(data, id){
11077 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
11082 * Generate a constructor for a specific record layout.
11083 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
11084 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
11085 * Each field definition object may contain the following properties: <ul>
11086 * <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,
11087 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
11088 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
11089 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
11090 * is being used, then this is a string containing the javascript expression to reference the data relative to
11091 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
11092 * to the data item relative to the record element. If the mapping expression is the same as the field name,
11093 * this may be omitted.</p></li>
11094 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
11095 * <ul><li>auto (Default, implies no conversion)</li>
11100 * <li>date</li></ul></p></li>
11101 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
11102 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
11103 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
11104 * by the Reader into an object that will be stored in the Record. It is passed the
11105 * following parameters:<ul>
11106 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
11108 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
11110 * <br>usage:<br><pre><code>
11111 var TopicRecord = Roo.data.Record.create(
11112 {name: 'title', mapping: 'topic_title'},
11113 {name: 'author', mapping: 'username'},
11114 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
11115 {name: 'lastPost', mapping: 'post_time', type: 'date'},
11116 {name: 'lastPoster', mapping: 'user2'},
11117 {name: 'excerpt', mapping: 'post_text'}
11120 var myNewRecord = new TopicRecord({
11121 title: 'Do my job please',
11124 lastPost: new Date(),
11125 lastPoster: 'Animal',
11126 excerpt: 'No way dude!'
11128 myStore.add(myNewRecord);
11133 Roo.data.Record.create = function(o){
11134 var f = function(){
11135 f.superclass.constructor.apply(this, arguments);
11137 Roo.extend(f, Roo.data.Record);
11138 var p = f.prototype;
11139 p.fields = new Roo.util.MixedCollection(false, function(field){
11142 for(var i = 0, len = o.length; i < len; i++){
11143 p.fields.add(new Roo.data.Field(o[i]));
11145 f.getField = function(name){
11146 return p.fields.get(name);
11151 Roo.data.Record.AUTO_ID = 1000;
11152 Roo.data.Record.EDIT = 'edit';
11153 Roo.data.Record.REJECT = 'reject';
11154 Roo.data.Record.COMMIT = 'commit';
11156 Roo.data.Record.prototype = {
11158 * Readonly flag - true if this record has been modified.
11167 join : function(store){
11168 this.store = store;
11172 * Set the named field to the specified value.
11173 * @param {String} name The name of the field to set.
11174 * @param {Object} value The value to set the field to.
11176 set : function(name, value){
11177 if(this.data[name] == value){
11181 if(!this.modified){
11182 this.modified = {};
11184 if(typeof this.modified[name] == 'undefined'){
11185 this.modified[name] = this.data[name];
11187 this.data[name] = value;
11188 if(!this.editing && this.store){
11189 this.store.afterEdit(this);
11194 * Get the value of the named field.
11195 * @param {String} name The name of the field to get the value of.
11196 * @return {Object} The value of the field.
11198 get : function(name){
11199 return this.data[name];
11203 beginEdit : function(){
11204 this.editing = true;
11205 this.modified = {};
11209 cancelEdit : function(){
11210 this.editing = false;
11211 delete this.modified;
11215 endEdit : function(){
11216 this.editing = false;
11217 if(this.dirty && this.store){
11218 this.store.afterEdit(this);
11223 * Usually called by the {@link Roo.data.Store} which owns the Record.
11224 * Rejects all changes made to the Record since either creation, or the last commit operation.
11225 * Modified fields are reverted to their original values.
11227 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
11228 * of reject operations.
11230 reject : function(){
11231 var m = this.modified;
11233 if(typeof m[n] != "function"){
11234 this.data[n] = m[n];
11237 this.dirty = false;
11238 delete this.modified;
11239 this.editing = false;
11241 this.store.afterReject(this);
11246 * Usually called by the {@link Roo.data.Store} which owns the Record.
11247 * Commits all changes made to the Record since either creation, or the last commit operation.
11249 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
11250 * of commit operations.
11252 commit : function(){
11253 this.dirty = false;
11254 delete this.modified;
11255 this.editing = false;
11257 this.store.afterCommit(this);
11262 hasError : function(){
11263 return this.error != null;
11267 clearError : function(){
11272 * Creates a copy of this record.
11273 * @param {String} id (optional) A new record id if you don't want to use this record's id
11276 copy : function(newId) {
11277 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
11281 * Ext JS Library 1.1.1
11282 * Copyright(c) 2006-2007, Ext JS, LLC.
11284 * Originally Released Under LGPL - original licence link has changed is not relivant.
11287 * <script type="text/javascript">
11293 * @class Roo.data.Store
11294 * @extends Roo.util.Observable
11295 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
11296 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
11298 * 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
11299 * has no knowledge of the format of the data returned by the Proxy.<br>
11301 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
11302 * instances from the data object. These records are cached and made available through accessor functions.
11304 * Creates a new Store.
11305 * @param {Object} config A config object containing the objects needed for the Store to access data,
11306 * and read the data into Records.
11308 Roo.data.Store = function(config){
11309 this.data = new Roo.util.MixedCollection(false);
11310 this.data.getKey = function(o){
11313 this.baseParams = {};
11315 this.paramNames = {
11320 "multisort" : "_multisort"
11323 if(config && config.data){
11324 this.inlineData = config.data;
11325 delete config.data;
11328 Roo.apply(this, config);
11330 if(this.reader){ // reader passed
11331 this.reader = Roo.factory(this.reader, Roo.data);
11332 this.reader.xmodule = this.xmodule || false;
11333 if(!this.recordType){
11334 this.recordType = this.reader.recordType;
11336 if(this.reader.onMetaChange){
11337 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
11341 if(this.recordType){
11342 this.fields = this.recordType.prototype.fields;
11344 this.modified = [];
11348 * @event datachanged
11349 * Fires when the data cache has changed, and a widget which is using this Store
11350 * as a Record cache should refresh its view.
11351 * @param {Store} this
11353 datachanged : true,
11355 * @event metachange
11356 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
11357 * @param {Store} this
11358 * @param {Object} meta The JSON metadata
11363 * Fires when Records have been added to the Store
11364 * @param {Store} this
11365 * @param {Roo.data.Record[]} records The array of Records added
11366 * @param {Number} index The index at which the record(s) were added
11371 * Fires when a Record has been removed from the Store
11372 * @param {Store} this
11373 * @param {Roo.data.Record} record The Record that was removed
11374 * @param {Number} index The index at which the record was removed
11379 * Fires when a Record has been updated
11380 * @param {Store} this
11381 * @param {Roo.data.Record} record The Record that was updated
11382 * @param {String} operation The update operation being performed. Value may be one of:
11384 Roo.data.Record.EDIT
11385 Roo.data.Record.REJECT
11386 Roo.data.Record.COMMIT
11392 * Fires when the data cache has been cleared.
11393 * @param {Store} this
11397 * @event beforeload
11398 * Fires before a request is made for a new data object. If the beforeload handler returns false
11399 * the load action will be canceled.
11400 * @param {Store} this
11401 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11405 * @event beforeloadadd
11406 * Fires after a new set of Records has been loaded.
11407 * @param {Store} this
11408 * @param {Roo.data.Record[]} records The Records that were loaded
11409 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11411 beforeloadadd : true,
11414 * Fires after a new set of Records has been loaded, before they are added to the store.
11415 * @param {Store} this
11416 * @param {Roo.data.Record[]} records The Records that were loaded
11417 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11418 * @params {Object} return from reader
11422 * @event loadexception
11423 * Fires if an exception occurs in the Proxy during loading.
11424 * Called with the signature of the Proxy's "loadexception" event.
11425 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
11428 * @param {Object} return from JsonData.reader() - success, totalRecords, records
11429 * @param {Object} load options
11430 * @param {Object} jsonData from your request (normally this contains the Exception)
11432 loadexception : true
11436 this.proxy = Roo.factory(this.proxy, Roo.data);
11437 this.proxy.xmodule = this.xmodule || false;
11438 this.relayEvents(this.proxy, ["loadexception"]);
11440 this.sortToggle = {};
11441 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
11443 Roo.data.Store.superclass.constructor.call(this);
11445 if(this.inlineData){
11446 this.loadData(this.inlineData);
11447 delete this.inlineData;
11451 Roo.extend(Roo.data.Store, Roo.util.Observable, {
11453 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
11454 * without a remote query - used by combo/forms at present.
11458 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
11461 * @cfg {Array} data Inline data to be loaded when the store is initialized.
11464 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
11465 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
11468 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
11469 * on any HTTP request
11472 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
11475 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
11479 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
11480 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
11482 remoteSort : false,
11485 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
11486 * loaded or when a record is removed. (defaults to false).
11488 pruneModifiedRecords : false,
11491 lastOptions : null,
11494 * Add Records to the Store and fires the add event.
11495 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11497 add : function(records){
11498 records = [].concat(records);
11499 for(var i = 0, len = records.length; i < len; i++){
11500 records[i].join(this);
11502 var index = this.data.length;
11503 this.data.addAll(records);
11504 this.fireEvent("add", this, records, index);
11508 * Remove a Record from the Store and fires the remove event.
11509 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
11511 remove : function(record){
11512 var index = this.data.indexOf(record);
11513 this.data.removeAt(index);
11515 if(this.pruneModifiedRecords){
11516 this.modified.remove(record);
11518 this.fireEvent("remove", this, record, index);
11522 * Remove all Records from the Store and fires the clear event.
11524 removeAll : function(){
11526 if(this.pruneModifiedRecords){
11527 this.modified = [];
11529 this.fireEvent("clear", this);
11533 * Inserts Records to the Store at the given index and fires the add event.
11534 * @param {Number} index The start index at which to insert the passed Records.
11535 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11537 insert : function(index, records){
11538 records = [].concat(records);
11539 for(var i = 0, len = records.length; i < len; i++){
11540 this.data.insert(index, records[i]);
11541 records[i].join(this);
11543 this.fireEvent("add", this, records, index);
11547 * Get the index within the cache of the passed Record.
11548 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
11549 * @return {Number} The index of the passed Record. Returns -1 if not found.
11551 indexOf : function(record){
11552 return this.data.indexOf(record);
11556 * Get the index within the cache of the Record with the passed id.
11557 * @param {String} id The id of the Record to find.
11558 * @return {Number} The index of the Record. Returns -1 if not found.
11560 indexOfId : function(id){
11561 return this.data.indexOfKey(id);
11565 * Get the Record with the specified id.
11566 * @param {String} id The id of the Record to find.
11567 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
11569 getById : function(id){
11570 return this.data.key(id);
11574 * Get the Record at the specified index.
11575 * @param {Number} index The index of the Record to find.
11576 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
11578 getAt : function(index){
11579 return this.data.itemAt(index);
11583 * Returns a range of Records between specified indices.
11584 * @param {Number} startIndex (optional) The starting index (defaults to 0)
11585 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
11586 * @return {Roo.data.Record[]} An array of Records
11588 getRange : function(start, end){
11589 return this.data.getRange(start, end);
11593 storeOptions : function(o){
11594 o = Roo.apply({}, o);
11597 this.lastOptions = o;
11601 * Loads the Record cache from the configured Proxy using the configured Reader.
11603 * If using remote paging, then the first load call must specify the <em>start</em>
11604 * and <em>limit</em> properties in the options.params property to establish the initial
11605 * position within the dataset, and the number of Records to cache on each read from the Proxy.
11607 * <strong>It is important to note that for remote data sources, loading is asynchronous,
11608 * and this call will return before the new data has been loaded. Perform any post-processing
11609 * in a callback function, or in a "load" event handler.</strong>
11611 * @param {Object} options An object containing properties which control loading options:<ul>
11612 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
11613 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
11614 * passed the following arguments:<ul>
11615 * <li>r : Roo.data.Record[]</li>
11616 * <li>options: Options object from the load call</li>
11617 * <li>success: Boolean success indicator</li></ul></li>
11618 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
11619 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
11622 load : function(options){
11623 options = options || {};
11624 if(this.fireEvent("beforeload", this, options) !== false){
11625 this.storeOptions(options);
11626 var p = Roo.apply(options.params || {}, this.baseParams);
11627 // if meta was not loaded from remote source.. try requesting it.
11628 if (!this.reader.metaFromRemote) {
11629 p._requestMeta = 1;
11631 if(this.sortInfo && this.remoteSort){
11632 var pn = this.paramNames;
11633 p[pn["sort"]] = this.sortInfo.field;
11634 p[pn["dir"]] = this.sortInfo.direction;
11636 if (this.multiSort) {
11637 var pn = this.paramNames;
11638 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
11641 this.proxy.load(p, this.reader, this.loadRecords, this, options);
11646 * Reloads the Record cache from the configured Proxy using the configured Reader and
11647 * the options from the last load operation performed.
11648 * @param {Object} options (optional) An object containing properties which may override the options
11649 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
11650 * the most recently used options are reused).
11652 reload : function(options){
11653 this.load(Roo.applyIf(options||{}, this.lastOptions));
11657 // Called as a callback by the Reader during a load operation.
11658 loadRecords : function(o, options, success){
11659 if(!o || success === false){
11660 if(success !== false){
11661 this.fireEvent("load", this, [], options, o);
11663 if(options.callback){
11664 options.callback.call(options.scope || this, [], options, false);
11668 // if data returned failure - throw an exception.
11669 if (o.success === false) {
11670 // show a message if no listener is registered.
11671 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
11672 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
11674 // loadmask wil be hooked into this..
11675 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
11678 var r = o.records, t = o.totalRecords || r.length;
11680 this.fireEvent("beforeloadadd", this, r, options, o);
11682 if(!options || options.add !== true){
11683 if(this.pruneModifiedRecords){
11684 this.modified = [];
11686 for(var i = 0, len = r.length; i < len; i++){
11690 this.data = this.snapshot;
11691 delete this.snapshot;
11694 this.data.addAll(r);
11695 this.totalLength = t;
11697 this.fireEvent("datachanged", this);
11699 this.totalLength = Math.max(t, this.data.length+r.length);
11703 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
11705 var e = new Roo.data.Record({});
11707 e.set(this.parent.displayField, this.parent.emptyTitle);
11708 e.set(this.parent.valueField, '');
11713 this.fireEvent("load", this, r, options, o);
11714 if(options.callback){
11715 options.callback.call(options.scope || this, r, options, true);
11721 * Loads data from a passed data block. A Reader which understands the format of the data
11722 * must have been configured in the constructor.
11723 * @param {Object} data The data block from which to read the Records. The format of the data expected
11724 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
11725 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
11727 loadData : function(o, append){
11728 var r = this.reader.readRecords(o);
11729 this.loadRecords(r, {add: append}, true);
11733 * Gets the number of cached records.
11735 * <em>If using paging, this may not be the total size of the dataset. If the data object
11736 * used by the Reader contains the dataset size, then the getTotalCount() function returns
11737 * the data set size</em>
11739 getCount : function(){
11740 return this.data.length || 0;
11744 * Gets the total number of records in the dataset as returned by the server.
11746 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
11747 * the dataset size</em>
11749 getTotalCount : function(){
11750 return this.totalLength || 0;
11754 * Returns the sort state of the Store as an object with two properties:
11756 field {String} The name of the field by which the Records are sorted
11757 direction {String} The sort order, "ASC" or "DESC"
11760 getSortState : function(){
11761 return this.sortInfo;
11765 applySort : function(){
11766 if(this.sortInfo && !this.remoteSort){
11767 var s = this.sortInfo, f = s.field;
11768 var st = this.fields.get(f).sortType;
11769 var fn = function(r1, r2){
11770 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
11771 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
11773 this.data.sort(s.direction, fn);
11774 if(this.snapshot && this.snapshot != this.data){
11775 this.snapshot.sort(s.direction, fn);
11781 * Sets the default sort column and order to be used by the next load operation.
11782 * @param {String} fieldName The name of the field to sort by.
11783 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11785 setDefaultSort : function(field, dir){
11786 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
11790 * Sort the Records.
11791 * If remote sorting is used, the sort is performed on the server, and the cache is
11792 * reloaded. If local sorting is used, the cache is sorted internally.
11793 * @param {String} fieldName The name of the field to sort by.
11794 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11796 sort : function(fieldName, dir){
11797 var f = this.fields.get(fieldName);
11799 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
11801 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
11802 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
11807 this.sortToggle[f.name] = dir;
11808 this.sortInfo = {field: f.name, direction: dir};
11809 if(!this.remoteSort){
11811 this.fireEvent("datachanged", this);
11813 this.load(this.lastOptions);
11818 * Calls the specified function for each of the Records in the cache.
11819 * @param {Function} fn The function to call. The Record is passed as the first parameter.
11820 * Returning <em>false</em> aborts and exits the iteration.
11821 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
11823 each : function(fn, scope){
11824 this.data.each(fn, scope);
11828 * Gets all records modified since the last commit. Modified records are persisted across load operations
11829 * (e.g., during paging).
11830 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
11832 getModifiedRecords : function(){
11833 return this.modified;
11837 createFilterFn : function(property, value, anyMatch){
11838 if(!value.exec){ // not a regex
11839 value = String(value);
11840 if(value.length == 0){
11843 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
11845 return function(r){
11846 return value.test(r.data[property]);
11851 * Sums the value of <i>property</i> for each record between start and end and returns the result.
11852 * @param {String} property A field on your records
11853 * @param {Number} start The record index to start at (defaults to 0)
11854 * @param {Number} end The last record index to include (defaults to length - 1)
11855 * @return {Number} The sum
11857 sum : function(property, start, end){
11858 var rs = this.data.items, v = 0;
11859 start = start || 0;
11860 end = (end || end === 0) ? end : rs.length-1;
11862 for(var i = start; i <= end; i++){
11863 v += (rs[i].data[property] || 0);
11869 * Filter the records by a specified property.
11870 * @param {String} field A field on your records
11871 * @param {String/RegExp} value Either a string that the field
11872 * should start with or a RegExp to test against the field
11873 * @param {Boolean} anyMatch True to match any part not just the beginning
11875 filter : function(property, value, anyMatch){
11876 var fn = this.createFilterFn(property, value, anyMatch);
11877 return fn ? this.filterBy(fn) : this.clearFilter();
11881 * Filter by a function. The specified function will be called with each
11882 * record in this data source. If the function returns true the record is included,
11883 * otherwise it is filtered.
11884 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11885 * @param {Object} scope (optional) The scope of the function (defaults to this)
11887 filterBy : function(fn, scope){
11888 this.snapshot = this.snapshot || this.data;
11889 this.data = this.queryBy(fn, scope||this);
11890 this.fireEvent("datachanged", this);
11894 * Query the records by a specified property.
11895 * @param {String} field A field on your records
11896 * @param {String/RegExp} value Either a string that the field
11897 * should start with or a RegExp to test against the field
11898 * @param {Boolean} anyMatch True to match any part not just the beginning
11899 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11901 query : function(property, value, anyMatch){
11902 var fn = this.createFilterFn(property, value, anyMatch);
11903 return fn ? this.queryBy(fn) : this.data.clone();
11907 * Query by a function. The specified function will be called with each
11908 * record in this data source. If the function returns true the record is included
11910 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11911 * @param {Object} scope (optional) The scope of the function (defaults to this)
11912 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11914 queryBy : function(fn, scope){
11915 var data = this.snapshot || this.data;
11916 return data.filterBy(fn, scope||this);
11920 * Collects unique values for a particular dataIndex from this store.
11921 * @param {String} dataIndex The property to collect
11922 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
11923 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
11924 * @return {Array} An array of the unique values
11926 collect : function(dataIndex, allowNull, bypassFilter){
11927 var d = (bypassFilter === true && this.snapshot) ?
11928 this.snapshot.items : this.data.items;
11929 var v, sv, r = [], l = {};
11930 for(var i = 0, len = d.length; i < len; i++){
11931 v = d[i].data[dataIndex];
11933 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
11942 * Revert to a view of the Record cache with no filtering applied.
11943 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
11945 clearFilter : function(suppressEvent){
11946 if(this.snapshot && this.snapshot != this.data){
11947 this.data = this.snapshot;
11948 delete this.snapshot;
11949 if(suppressEvent !== true){
11950 this.fireEvent("datachanged", this);
11956 afterEdit : function(record){
11957 if(this.modified.indexOf(record) == -1){
11958 this.modified.push(record);
11960 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
11964 afterReject : function(record){
11965 this.modified.remove(record);
11966 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
11970 afterCommit : function(record){
11971 this.modified.remove(record);
11972 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
11976 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
11977 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
11979 commitChanges : function(){
11980 var m = this.modified.slice(0);
11981 this.modified = [];
11982 for(var i = 0, len = m.length; i < len; i++){
11988 * Cancel outstanding changes on all changed records.
11990 rejectChanges : function(){
11991 var m = this.modified.slice(0);
11992 this.modified = [];
11993 for(var i = 0, len = m.length; i < len; i++){
11998 onMetaChange : function(meta, rtype, o){
11999 this.recordType = rtype;
12000 this.fields = rtype.prototype.fields;
12001 delete this.snapshot;
12002 this.sortInfo = meta.sortInfo || this.sortInfo;
12003 this.modified = [];
12004 this.fireEvent('metachange', this, this.reader.meta);
12007 moveIndex : function(data, type)
12009 var index = this.indexOf(data);
12011 var newIndex = index + type;
12015 this.insert(newIndex, data);
12020 * Ext JS Library 1.1.1
12021 * Copyright(c) 2006-2007, Ext JS, LLC.
12023 * Originally Released Under LGPL - original licence link has changed is not relivant.
12026 * <script type="text/javascript">
12030 * @class Roo.data.SimpleStore
12031 * @extends Roo.data.Store
12032 * Small helper class to make creating Stores from Array data easier.
12033 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
12034 * @cfg {Array} fields An array of field definition objects, or field name strings.
12035 * @cfg {Array} data The multi-dimensional array of data
12037 * @param {Object} config
12039 Roo.data.SimpleStore = function(config){
12040 Roo.data.SimpleStore.superclass.constructor.call(this, {
12042 reader: new Roo.data.ArrayReader({
12045 Roo.data.Record.create(config.fields)
12047 proxy : new Roo.data.MemoryProxy(config.data)
12051 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
12053 * Ext JS Library 1.1.1
12054 * Copyright(c) 2006-2007, Ext JS, LLC.
12056 * Originally Released Under LGPL - original licence link has changed is not relivant.
12059 * <script type="text/javascript">
12064 * @extends Roo.data.Store
12065 * @class Roo.data.JsonStore
12066 * Small helper class to make creating Stores for JSON data easier. <br/>
12068 var store = new Roo.data.JsonStore({
12069 url: 'get-images.php',
12071 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
12074 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
12075 * JsonReader and HttpProxy (unless inline data is provided).</b>
12076 * @cfg {Array} fields An array of field definition objects, or field name strings.
12078 * @param {Object} config
12080 Roo.data.JsonStore = function(c){
12081 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
12082 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
12083 reader: new Roo.data.JsonReader(c, c.fields)
12086 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
12088 * Ext JS Library 1.1.1
12089 * Copyright(c) 2006-2007, Ext JS, LLC.
12091 * Originally Released Under LGPL - original licence link has changed is not relivant.
12094 * <script type="text/javascript">
12098 Roo.data.Field = function(config){
12099 if(typeof config == "string"){
12100 config = {name: config};
12102 Roo.apply(this, config);
12105 this.type = "auto";
12108 var st = Roo.data.SortTypes;
12109 // named sortTypes are supported, here we look them up
12110 if(typeof this.sortType == "string"){
12111 this.sortType = st[this.sortType];
12114 // set default sortType for strings and dates
12115 if(!this.sortType){
12118 this.sortType = st.asUCString;
12121 this.sortType = st.asDate;
12124 this.sortType = st.none;
12129 var stripRe = /[\$,%]/g;
12131 // prebuilt conversion function for this field, instead of
12132 // switching every time we're reading a value
12134 var cv, dateFormat = this.dateFormat;
12139 cv = function(v){ return v; };
12142 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
12146 return v !== undefined && v !== null && v !== '' ?
12147 parseInt(String(v).replace(stripRe, ""), 10) : '';
12152 return v !== undefined && v !== null && v !== '' ?
12153 parseFloat(String(v).replace(stripRe, ""), 10) : '';
12158 cv = function(v){ return v === true || v === "true" || v == 1; };
12165 if(v instanceof Date){
12169 if(dateFormat == "timestamp"){
12170 return new Date(v*1000);
12172 return Date.parseDate(v, dateFormat);
12174 var parsed = Date.parse(v);
12175 return parsed ? new Date(parsed) : null;
12184 Roo.data.Field.prototype = {
12192 * Ext JS Library 1.1.1
12193 * Copyright(c) 2006-2007, Ext JS, LLC.
12195 * Originally Released Under LGPL - original licence link has changed is not relivant.
12198 * <script type="text/javascript">
12201 // Base class for reading structured data from a data source. This class is intended to be
12202 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
12205 * @class Roo.data.DataReader
12206 * Base class for reading structured data from a data source. This class is intended to be
12207 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
12210 Roo.data.DataReader = function(meta, recordType){
12214 this.recordType = recordType instanceof Array ?
12215 Roo.data.Record.create(recordType) : recordType;
12218 Roo.data.DataReader.prototype = {
12220 * Create an empty record
12221 * @param {Object} data (optional) - overlay some values
12222 * @return {Roo.data.Record} record created.
12224 newRow : function(d) {
12226 this.recordType.prototype.fields.each(function(c) {
12228 case 'int' : da[c.name] = 0; break;
12229 case 'date' : da[c.name] = new Date(); break;
12230 case 'float' : da[c.name] = 0.0; break;
12231 case 'boolean' : da[c.name] = false; break;
12232 default : da[c.name] = ""; break;
12236 return new this.recordType(Roo.apply(da, d));
12241 * Ext JS Library 1.1.1
12242 * Copyright(c) 2006-2007, Ext JS, LLC.
12244 * Originally Released Under LGPL - original licence link has changed is not relivant.
12247 * <script type="text/javascript">
12251 * @class Roo.data.DataProxy
12252 * @extends Roo.data.Observable
12253 * This class is an abstract base class for implementations which provide retrieval of
12254 * unformatted data objects.<br>
12256 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
12257 * (of the appropriate type which knows how to parse the data object) to provide a block of
12258 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
12260 * Custom implementations must implement the load method as described in
12261 * {@link Roo.data.HttpProxy#load}.
12263 Roo.data.DataProxy = function(){
12266 * @event beforeload
12267 * Fires before a network request is made to retrieve a data object.
12268 * @param {Object} This DataProxy object.
12269 * @param {Object} params The params parameter to the load function.
12274 * Fires before the load method's callback is called.
12275 * @param {Object} This DataProxy object.
12276 * @param {Object} o The data object.
12277 * @param {Object} arg The callback argument object passed to the load function.
12281 * @event loadexception
12282 * Fires if an Exception occurs during data retrieval.
12283 * @param {Object} This DataProxy object.
12284 * @param {Object} o The data object.
12285 * @param {Object} arg The callback argument object passed to the load function.
12286 * @param {Object} e The Exception.
12288 loadexception : true
12290 Roo.data.DataProxy.superclass.constructor.call(this);
12293 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
12296 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
12300 * Ext JS Library 1.1.1
12301 * Copyright(c) 2006-2007, Ext JS, LLC.
12303 * Originally Released Under LGPL - original licence link has changed is not relivant.
12306 * <script type="text/javascript">
12309 * @class Roo.data.MemoryProxy
12310 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
12311 * to the Reader when its load method is called.
12313 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
12315 Roo.data.MemoryProxy = function(data){
12319 Roo.data.MemoryProxy.superclass.constructor.call(this);
12323 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
12326 * Load data from the requested source (in this case an in-memory
12327 * data object passed to the constructor), read the data object into
12328 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12329 * process that block using the passed callback.
12330 * @param {Object} params This parameter is not used by the MemoryProxy class.
12331 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12332 * object into a block of Roo.data.Records.
12333 * @param {Function} callback The function into which to pass the block of Roo.data.records.
12334 * The function must be passed <ul>
12335 * <li>The Record block object</li>
12336 * <li>The "arg" argument from the load function</li>
12337 * <li>A boolean success indicator</li>
12339 * @param {Object} scope The scope in which to call the callback
12340 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12342 load : function(params, reader, callback, scope, arg){
12343 params = params || {};
12346 result = reader.readRecords(this.data);
12348 this.fireEvent("loadexception", this, arg, null, e);
12349 callback.call(scope, null, arg, false);
12352 callback.call(scope, result, arg, true);
12356 update : function(params, records){
12361 * Ext JS Library 1.1.1
12362 * Copyright(c) 2006-2007, Ext JS, LLC.
12364 * Originally Released Under LGPL - original licence link has changed is not relivant.
12367 * <script type="text/javascript">
12370 * @class Roo.data.HttpProxy
12371 * @extends Roo.data.DataProxy
12372 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
12373 * configured to reference a certain URL.<br><br>
12375 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
12376 * from which the running page was served.<br><br>
12378 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
12380 * Be aware that to enable the browser to parse an XML document, the server must set
12381 * the Content-Type header in the HTTP response to "text/xml".
12383 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
12384 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
12385 * will be used to make the request.
12387 Roo.data.HttpProxy = function(conn){
12388 Roo.data.HttpProxy.superclass.constructor.call(this);
12389 // is conn a conn config or a real conn?
12391 this.useAjax = !conn || !conn.events;
12395 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
12396 // thse are take from connection...
12399 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
12402 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
12403 * extra parameters to each request made by this object. (defaults to undefined)
12406 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
12407 * to each request made by this object. (defaults to undefined)
12410 * @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)
12413 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
12416 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
12422 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
12426 * Return the {@link Roo.data.Connection} object being used by this Proxy.
12427 * @return {Connection} The Connection object. This object may be used to subscribe to events on
12428 * a finer-grained basis than the DataProxy events.
12430 getConnection : function(){
12431 return this.useAjax ? Roo.Ajax : this.conn;
12435 * Load data from the configured {@link Roo.data.Connection}, read the data object into
12436 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
12437 * process that block using the passed callback.
12438 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12439 * for the request to the remote server.
12440 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12441 * object into a block of Roo.data.Records.
12442 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12443 * The function must be passed <ul>
12444 * <li>The Record block object</li>
12445 * <li>The "arg" argument from the load function</li>
12446 * <li>A boolean success indicator</li>
12448 * @param {Object} scope The scope in which to call the callback
12449 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12451 load : function(params, reader, callback, scope, arg){
12452 if(this.fireEvent("beforeload", this, params) !== false){
12454 params : params || {},
12456 callback : callback,
12461 callback : this.loadResponse,
12465 Roo.applyIf(o, this.conn);
12466 if(this.activeRequest){
12467 Roo.Ajax.abort(this.activeRequest);
12469 this.activeRequest = Roo.Ajax.request(o);
12471 this.conn.request(o);
12474 callback.call(scope||this, null, arg, false);
12479 loadResponse : function(o, success, response){
12480 delete this.activeRequest;
12482 this.fireEvent("loadexception", this, o, response);
12483 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12488 result = o.reader.read(response);
12490 this.fireEvent("loadexception", this, o, response, e);
12491 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12495 this.fireEvent("load", this, o, o.request.arg);
12496 o.request.callback.call(o.request.scope, result, o.request.arg, true);
12500 update : function(dataSet){
12505 updateResponse : function(dataSet){
12510 * Ext JS Library 1.1.1
12511 * Copyright(c) 2006-2007, Ext JS, LLC.
12513 * Originally Released Under LGPL - original licence link has changed is not relivant.
12516 * <script type="text/javascript">
12520 * @class Roo.data.ScriptTagProxy
12521 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
12522 * other than the originating domain of the running page.<br><br>
12524 * <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
12525 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
12527 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
12528 * source code that is used as the source inside a <script> tag.<br><br>
12530 * In order for the browser to process the returned data, the server must wrap the data object
12531 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
12532 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
12533 * depending on whether the callback name was passed:
12536 boolean scriptTag = false;
12537 String cb = request.getParameter("callback");
12540 response.setContentType("text/javascript");
12542 response.setContentType("application/x-json");
12544 Writer out = response.getWriter();
12546 out.write(cb + "(");
12548 out.print(dataBlock.toJsonString());
12555 * @param {Object} config A configuration object.
12557 Roo.data.ScriptTagProxy = function(config){
12558 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
12559 Roo.apply(this, config);
12560 this.head = document.getElementsByTagName("head")[0];
12563 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
12565 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
12567 * @cfg {String} url The URL from which to request the data object.
12570 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
12574 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
12575 * the server the name of the callback function set up by the load call to process the returned data object.
12576 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
12577 * javascript output which calls this named function passing the data object as its only parameter.
12579 callbackParam : "callback",
12581 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
12582 * name to the request.
12587 * Load data from the configured URL, read the data object into
12588 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12589 * process that block using the passed callback.
12590 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12591 * for the request to the remote server.
12592 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12593 * object into a block of Roo.data.Records.
12594 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12595 * The function must be passed <ul>
12596 * <li>The Record block object</li>
12597 * <li>The "arg" argument from the load function</li>
12598 * <li>A boolean success indicator</li>
12600 * @param {Object} scope The scope in which to call the callback
12601 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12603 load : function(params, reader, callback, scope, arg){
12604 if(this.fireEvent("beforeload", this, params) !== false){
12606 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
12608 var url = this.url;
12609 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
12611 url += "&_dc=" + (new Date().getTime());
12613 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
12616 cb : "stcCallback"+transId,
12617 scriptId : "stcScript"+transId,
12621 callback : callback,
12627 window[trans.cb] = function(o){
12628 conn.handleResponse(o, trans);
12631 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
12633 if(this.autoAbort !== false){
12637 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
12639 var script = document.createElement("script");
12640 script.setAttribute("src", url);
12641 script.setAttribute("type", "text/javascript");
12642 script.setAttribute("id", trans.scriptId);
12643 this.head.appendChild(script);
12645 this.trans = trans;
12647 callback.call(scope||this, null, arg, false);
12652 isLoading : function(){
12653 return this.trans ? true : false;
12657 * Abort the current server request.
12659 abort : function(){
12660 if(this.isLoading()){
12661 this.destroyTrans(this.trans);
12666 destroyTrans : function(trans, isLoaded){
12667 this.head.removeChild(document.getElementById(trans.scriptId));
12668 clearTimeout(trans.timeoutId);
12670 window[trans.cb] = undefined;
12672 delete window[trans.cb];
12675 // if hasn't been loaded, wait for load to remove it to prevent script error
12676 window[trans.cb] = function(){
12677 window[trans.cb] = undefined;
12679 delete window[trans.cb];
12686 handleResponse : function(o, trans){
12687 this.trans = false;
12688 this.destroyTrans(trans, true);
12691 result = trans.reader.readRecords(o);
12693 this.fireEvent("loadexception", this, o, trans.arg, e);
12694 trans.callback.call(trans.scope||window, null, trans.arg, false);
12697 this.fireEvent("load", this, o, trans.arg);
12698 trans.callback.call(trans.scope||window, result, trans.arg, true);
12702 handleFailure : function(trans){
12703 this.trans = false;
12704 this.destroyTrans(trans, false);
12705 this.fireEvent("loadexception", this, null, trans.arg);
12706 trans.callback.call(trans.scope||window, null, trans.arg, false);
12710 * Ext JS Library 1.1.1
12711 * Copyright(c) 2006-2007, Ext JS, LLC.
12713 * Originally Released Under LGPL - original licence link has changed is not relivant.
12716 * <script type="text/javascript">
12720 * @class Roo.data.JsonReader
12721 * @extends Roo.data.DataReader
12722 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
12723 * based on mappings in a provided Roo.data.Record constructor.
12725 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
12726 * in the reply previously.
12731 var RecordDef = Roo.data.Record.create([
12732 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
12733 {name: 'occupation'} // This field will use "occupation" as the mapping.
12735 var myReader = new Roo.data.JsonReader({
12736 totalProperty: "results", // The property which contains the total dataset size (optional)
12737 root: "rows", // The property which contains an Array of row objects
12738 id: "id" // The property within each row object that provides an ID for the record (optional)
12742 * This would consume a JSON file like this:
12744 { 'results': 2, 'rows': [
12745 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
12746 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
12749 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
12750 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
12751 * paged from the remote server.
12752 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
12753 * @cfg {String} root name of the property which contains the Array of row objects.
12754 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
12755 * @cfg {Array} fields Array of field definition objects
12757 * Create a new JsonReader
12758 * @param {Object} meta Metadata configuration options
12759 * @param {Object} recordType Either an Array of field definition objects,
12760 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
12762 Roo.data.JsonReader = function(meta, recordType){
12765 // set some defaults:
12766 Roo.applyIf(meta, {
12767 totalProperty: 'total',
12768 successProperty : 'success',
12773 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
12775 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
12778 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
12779 * Used by Store query builder to append _requestMeta to params.
12782 metaFromRemote : false,
12784 * This method is only used by a DataProxy which has retrieved data from a remote server.
12785 * @param {Object} response The XHR object which contains the JSON data in its responseText.
12786 * @return {Object} data A data block which is used by an Roo.data.Store object as
12787 * a cache of Roo.data.Records.
12789 read : function(response){
12790 var json = response.responseText;
12792 var o = /* eval:var:o */ eval("("+json+")");
12794 throw {message: "JsonReader.read: Json object not found"};
12800 this.metaFromRemote = true;
12801 this.meta = o.metaData;
12802 this.recordType = Roo.data.Record.create(o.metaData.fields);
12803 this.onMetaChange(this.meta, this.recordType, o);
12805 return this.readRecords(o);
12808 // private function a store will implement
12809 onMetaChange : function(meta, recordType, o){
12816 simpleAccess: function(obj, subsc) {
12823 getJsonAccessor: function(){
12825 return function(expr) {
12827 return(re.test(expr))
12828 ? new Function("obj", "return obj." + expr)
12833 return Roo.emptyFn;
12838 * Create a data block containing Roo.data.Records from an XML document.
12839 * @param {Object} o An object which contains an Array of row objects in the property specified
12840 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
12841 * which contains the total size of the dataset.
12842 * @return {Object} data A data block which is used by an Roo.data.Store object as
12843 * a cache of Roo.data.Records.
12845 readRecords : function(o){
12847 * After any data loads, the raw JSON data is available for further custom processing.
12851 var s = this.meta, Record = this.recordType,
12852 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
12854 // Generate extraction functions for the totalProperty, the root, the id, and for each field
12856 if(s.totalProperty) {
12857 this.getTotal = this.getJsonAccessor(s.totalProperty);
12859 if(s.successProperty) {
12860 this.getSuccess = this.getJsonAccessor(s.successProperty);
12862 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
12864 var g = this.getJsonAccessor(s.id);
12865 this.getId = function(rec) {
12867 return (r === undefined || r === "") ? null : r;
12870 this.getId = function(){return null;};
12873 for(var jj = 0; jj < fl; jj++){
12875 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
12876 this.ef[jj] = this.getJsonAccessor(map);
12880 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
12881 if(s.totalProperty){
12882 var vt = parseInt(this.getTotal(o), 10);
12887 if(s.successProperty){
12888 var vs = this.getSuccess(o);
12889 if(vs === false || vs === 'false'){
12894 for(var i = 0; i < c; i++){
12897 var id = this.getId(n);
12898 for(var j = 0; j < fl; j++){
12900 var v = this.ef[j](n);
12902 Roo.log('missing convert for ' + f.name);
12906 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
12908 var record = new Record(values, id);
12910 records[i] = record;
12916 totalRecords : totalRecords
12921 * Ext JS Library 1.1.1
12922 * Copyright(c) 2006-2007, Ext JS, LLC.
12924 * Originally Released Under LGPL - original licence link has changed is not relivant.
12927 * <script type="text/javascript">
12931 * @class Roo.data.ArrayReader
12932 * @extends Roo.data.DataReader
12933 * Data reader class to create an Array of Roo.data.Record objects from an Array.
12934 * Each element of that Array represents a row of data fields. The
12935 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
12936 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
12940 var RecordDef = Roo.data.Record.create([
12941 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
12942 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
12944 var myReader = new Roo.data.ArrayReader({
12945 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
12949 * This would consume an Array like this:
12951 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
12953 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
12955 * Create a new JsonReader
12956 * @param {Object} meta Metadata configuration options.
12957 * @param {Object} recordType Either an Array of field definition objects
12958 * as specified to {@link Roo.data.Record#create},
12959 * or an {@link Roo.data.Record} object
12960 * created using {@link Roo.data.Record#create}.
12962 Roo.data.ArrayReader = function(meta, recordType){
12963 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
12966 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
12968 * Create a data block containing Roo.data.Records from an XML document.
12969 * @param {Object} o An Array of row objects which represents the dataset.
12970 * @return {Object} data A data block which is used by an Roo.data.Store object as
12971 * a cache of Roo.data.Records.
12973 readRecords : function(o){
12974 var sid = this.meta ? this.meta.id : null;
12975 var recordType = this.recordType, fields = recordType.prototype.fields;
12978 for(var i = 0; i < root.length; i++){
12981 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
12982 for(var j = 0, jlen = fields.length; j < jlen; j++){
12983 var f = fields.items[j];
12984 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
12985 var v = n[k] !== undefined ? n[k] : f.defaultValue;
12987 values[f.name] = v;
12989 var record = new recordType(values, id);
12991 records[records.length] = record;
12995 totalRecords : records.length
13004 * @class Roo.bootstrap.ComboBox
13005 * @extends Roo.bootstrap.TriggerField
13006 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
13007 * @cfg {Boolean} append (true|false) default false
13008 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
13009 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
13010 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
13011 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
13012 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
13013 * @cfg {Boolean} animate default true
13014 * @cfg {Boolean} emptyResultText only for touch device
13015 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
13016 * @cfg {String} emptyTitle default ''
13018 * Create a new ComboBox.
13019 * @param {Object} config Configuration options
13021 Roo.bootstrap.ComboBox = function(config){
13022 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
13026 * Fires when the dropdown list is expanded
13027 * @param {Roo.bootstrap.ComboBox} combo This combo box
13032 * Fires when the dropdown list is collapsed
13033 * @param {Roo.bootstrap.ComboBox} combo This combo box
13037 * @event beforeselect
13038 * Fires before a list item is selected. Return false to cancel the selection.
13039 * @param {Roo.bootstrap.ComboBox} combo This combo box
13040 * @param {Roo.data.Record} record The data record returned from the underlying store
13041 * @param {Number} index The index of the selected item in the dropdown list
13043 'beforeselect' : true,
13046 * Fires when a list item is selected
13047 * @param {Roo.bootstrap.ComboBox} combo This combo box
13048 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
13049 * @param {Number} index The index of the selected item in the dropdown list
13053 * @event beforequery
13054 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
13055 * The event object passed has these properties:
13056 * @param {Roo.bootstrap.ComboBox} combo This combo box
13057 * @param {String} query The query
13058 * @param {Boolean} forceAll true to force "all" query
13059 * @param {Boolean} cancel true to cancel the query
13060 * @param {Object} e The query event object
13062 'beforequery': true,
13065 * Fires when the 'add' icon is pressed (add a listener to enable add button)
13066 * @param {Roo.bootstrap.ComboBox} combo This combo box
13071 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
13072 * @param {Roo.bootstrap.ComboBox} combo This combo box
13073 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
13078 * Fires when the remove value from the combobox array
13079 * @param {Roo.bootstrap.ComboBox} combo This combo box
13083 * @event afterremove
13084 * Fires when the remove value from the combobox array
13085 * @param {Roo.bootstrap.ComboBox} combo This combo box
13087 'afterremove' : true,
13089 * @event specialfilter
13090 * Fires when specialfilter
13091 * @param {Roo.bootstrap.ComboBox} combo This combo box
13093 'specialfilter' : true,
13096 * Fires when tick the element
13097 * @param {Roo.bootstrap.ComboBox} combo This combo box
13101 * @event touchviewdisplay
13102 * Fires when touch view require special display (default is using displayField)
13103 * @param {Roo.bootstrap.ComboBox} combo This combo box
13104 * @param {Object} cfg set html .
13106 'touchviewdisplay' : true
13111 this.tickItems = [];
13113 this.selectedIndex = -1;
13114 if(this.mode == 'local'){
13115 if(config.queryDelay === undefined){
13116 this.queryDelay = 10;
13118 if(config.minChars === undefined){
13124 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
13127 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
13128 * rendering into an Roo.Editor, defaults to false)
13131 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
13132 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
13135 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
13138 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
13139 * the dropdown list (defaults to undefined, with no header element)
13143 * @cfg {String/Roo.Template} tpl The template to use to render the output
13147 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
13149 listWidth: undefined,
13151 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
13152 * mode = 'remote' or 'text' if mode = 'local')
13154 displayField: undefined,
13157 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
13158 * mode = 'remote' or 'value' if mode = 'local').
13159 * Note: use of a valueField requires the user make a selection
13160 * in order for a value to be mapped.
13162 valueField: undefined,
13164 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
13169 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
13170 * field's data value (defaults to the underlying DOM element's name)
13172 hiddenName: undefined,
13174 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
13178 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
13180 selectedClass: 'active',
13183 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
13187 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
13188 * anchor positions (defaults to 'tl-bl')
13190 listAlign: 'tl-bl?',
13192 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
13196 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
13197 * query specified by the allQuery config option (defaults to 'query')
13199 triggerAction: 'query',
13201 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
13202 * (defaults to 4, does not apply if editable = false)
13206 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
13207 * delay (typeAheadDelay) if it matches a known value (defaults to false)
13211 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
13212 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
13216 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
13217 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
13221 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
13222 * when editable = true (defaults to false)
13224 selectOnFocus:false,
13226 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
13228 queryParam: 'query',
13230 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
13231 * when mode = 'remote' (defaults to 'Loading...')
13233 loadingText: 'Loading...',
13235 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
13239 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
13243 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
13244 * traditional select (defaults to true)
13248 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
13252 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
13256 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
13257 * listWidth has a higher value)
13261 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
13262 * allow the user to set arbitrary text into the field (defaults to false)
13264 forceSelection:false,
13266 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
13267 * if typeAhead = true (defaults to 250)
13269 typeAheadDelay : 250,
13271 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
13272 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
13274 valueNotFoundText : undefined,
13276 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
13278 blockFocus : false,
13281 * @cfg {Boolean} disableClear Disable showing of clear button.
13283 disableClear : false,
13285 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
13287 alwaysQuery : false,
13290 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
13295 * @cfg {String} invalidClass DEPRICATED - uses BS4 is-valid now
13297 invalidClass : "has-warning",
13300 * @cfg {String} validClass DEPRICATED - uses BS4 is-valid now
13302 validClass : "has-success",
13305 * @cfg {Boolean} specialFilter (true|false) special filter default false
13307 specialFilter : false,
13310 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
13312 mobileTouchView : true,
13315 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
13317 useNativeIOS : false,
13320 * @cfg {Boolean} mobile_restrict_height (true|false) restrict height for touch view
13322 mobile_restrict_height : false,
13324 ios_options : false,
13336 btnPosition : 'right',
13337 triggerList : true,
13338 showToggleBtn : true,
13340 emptyResultText: 'Empty',
13341 triggerText : 'Select',
13344 // element that contains real text value.. (when hidden is used..)
13346 getAutoCreate : function()
13351 * Render classic select for iso
13354 if(Roo.isIOS && this.useNativeIOS){
13355 cfg = this.getAutoCreateNativeIOS();
13363 if(Roo.isTouch && this.mobileTouchView){
13364 cfg = this.getAutoCreateTouchView();
13371 if(!this.tickable){
13372 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
13377 * ComboBox with tickable selections
13380 var align = this.labelAlign || this.parentLabelAlign();
13383 cls : 'form-group roo-combobox-tickable' //input-group
13386 var btn_text_select = '';
13387 var btn_text_done = '';
13388 var btn_text_cancel = '';
13390 if (this.btn_text_show) {
13391 btn_text_select = 'Select';
13392 btn_text_done = 'Done';
13393 btn_text_cancel = 'Cancel';
13398 cls : 'tickable-buttons',
13403 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
13404 //html : this.triggerText
13405 html: btn_text_select
13411 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
13413 html: btn_text_done
13419 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
13421 html: btn_text_cancel
13427 buttons.cn.unshift({
13429 cls: 'roo-select2-search-field-input'
13435 Roo.each(buttons.cn, function(c){
13437 c.cls += ' btn-' + _this.size;
13440 if (_this.disabled) {
13447 style : 'display: contents',
13452 cls: 'form-hidden-field'
13456 cls: 'roo-select2-choices',
13460 cls: 'roo-select2-search-field',
13471 cls: 'roo-select2-container input-group roo-select2-container-multi',
13477 // cls: 'typeahead typeahead-long dropdown-menu',
13478 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
13483 if(this.hasFeedback && !this.allowBlank){
13487 cls: 'glyphicon form-control-feedback'
13490 combobox.cn.push(feedback);
13495 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
13496 tooltip : 'This field is required'
13498 if (Roo.bootstrap.version == 4) {
13501 style : 'display:none'
13504 if (align ==='left' && this.fieldLabel.length) {
13506 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
13513 cls : 'control-label col-form-label',
13514 html : this.fieldLabel
13526 var labelCfg = cfg.cn[1];
13527 var contentCfg = cfg.cn[2];
13530 if(this.indicatorpos == 'right'){
13536 cls : 'control-label col-form-label',
13540 html : this.fieldLabel
13556 labelCfg = cfg.cn[0];
13557 contentCfg = cfg.cn[1];
13561 if(this.labelWidth > 12){
13562 labelCfg.style = "width: " + this.labelWidth + 'px';
13565 if(this.labelWidth < 13 && this.labelmd == 0){
13566 this.labelmd = this.labelWidth;
13569 if(this.labellg > 0){
13570 labelCfg.cls += ' col-lg-' + this.labellg;
13571 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
13574 if(this.labelmd > 0){
13575 labelCfg.cls += ' col-md-' + this.labelmd;
13576 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
13579 if(this.labelsm > 0){
13580 labelCfg.cls += ' col-sm-' + this.labelsm;
13581 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
13584 if(this.labelxs > 0){
13585 labelCfg.cls += ' col-xs-' + this.labelxs;
13586 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
13590 } else if ( this.fieldLabel.length) {
13591 // Roo.log(" label");
13596 //cls : 'input-group-addon',
13597 html : this.fieldLabel
13602 if(this.indicatorpos == 'right'){
13606 //cls : 'input-group-addon',
13607 html : this.fieldLabel
13617 // Roo.log(" no label && no align");
13624 ['xs','sm','md','lg'].map(function(size){
13625 if (settings[size]) {
13626 cfg.cls += ' col-' + size + '-' + settings[size];
13634 _initEventsCalled : false,
13637 initEvents: function()
13639 if (this._initEventsCalled) { // as we call render... prevent looping...
13642 this._initEventsCalled = true;
13645 throw "can not find store for combo";
13648 this.indicator = this.indicatorEl();
13650 this.store = Roo.factory(this.store, Roo.data);
13651 this.store.parent = this;
13653 // if we are building from html. then this element is so complex, that we can not really
13654 // use the rendered HTML.
13655 // so we have to trash and replace the previous code.
13656 if (Roo.XComponent.build_from_html) {
13657 // remove this element....
13658 var e = this.el.dom, k=0;
13659 while (e ) { e = e.previousSibling; ++k;}
13664 this.rendered = false;
13666 this.render(this.parent().getChildContainer(true), k);
13669 if(Roo.isIOS && this.useNativeIOS){
13670 this.initIOSView();
13678 if(Roo.isTouch && this.mobileTouchView){
13679 this.initTouchView();
13684 this.initTickableEvents();
13688 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
13690 if(this.hiddenName){
13692 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13694 this.hiddenField.dom.value =
13695 this.hiddenValue !== undefined ? this.hiddenValue :
13696 this.value !== undefined ? this.value : '';
13698 // prevent input submission
13699 this.el.dom.removeAttribute('name');
13700 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13705 // this.el.dom.setAttribute('autocomplete', 'off');
13708 var cls = 'x-combo-list';
13710 //this.list = new Roo.Layer({
13711 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
13717 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13718 _this.list.setWidth(lw);
13721 this.list.on('mouseover', this.onViewOver, this);
13722 this.list.on('mousemove', this.onViewMove, this);
13723 this.list.on('scroll', this.onViewScroll, this);
13726 this.list.swallowEvent('mousewheel');
13727 this.assetHeight = 0;
13730 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
13731 this.assetHeight += this.header.getHeight();
13734 this.innerList = this.list.createChild({cls:cls+'-inner'});
13735 this.innerList.on('mouseover', this.onViewOver, this);
13736 this.innerList.on('mousemove', this.onViewMove, this);
13737 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13739 if(this.allowBlank && !this.pageSize && !this.disableClear){
13740 this.footer = this.list.createChild({cls:cls+'-ft'});
13741 this.pageTb = new Roo.Toolbar(this.footer);
13745 this.footer = this.list.createChild({cls:cls+'-ft'});
13746 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
13747 {pageSize: this.pageSize});
13751 if (this.pageTb && this.allowBlank && !this.disableClear) {
13753 this.pageTb.add(new Roo.Toolbar.Fill(), {
13754 cls: 'x-btn-icon x-btn-clear',
13756 handler: function()
13759 _this.clearValue();
13760 _this.onSelect(false, -1);
13765 this.assetHeight += this.footer.getHeight();
13770 this.tpl = Roo.bootstrap.version == 4 ?
13771 '<a class="dropdown-item" href="#">{' + this.displayField + '}</a>' : // 4 does not need <li> and it get's really confisued.
13772 '<li><a class="dropdown-item" href="#">{' + this.displayField + '}</a></li>';
13775 this.view = new Roo.View(this.list, this.tpl, {
13776 singleSelect:true, store: this.store, selectedClass: this.selectedClass
13778 //this.view.wrapEl.setDisplayed(false);
13779 this.view.on('click', this.onViewClick, this);
13782 this.store.on('beforeload', this.onBeforeLoad, this);
13783 this.store.on('load', this.onLoad, this);
13784 this.store.on('loadexception', this.onLoadException, this);
13786 if(this.resizable){
13787 this.resizer = new Roo.Resizable(this.list, {
13788 pinned:true, handles:'se'
13790 this.resizer.on('resize', function(r, w, h){
13791 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
13792 this.listWidth = w;
13793 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
13794 this.restrictHeight();
13796 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
13799 if(!this.editable){
13800 this.editable = true;
13801 this.setEditable(false);
13806 if (typeof(this.events.add.listeners) != 'undefined') {
13808 this.addicon = this.wrap.createChild(
13809 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
13811 this.addicon.on('click', function(e) {
13812 this.fireEvent('add', this);
13815 if (typeof(this.events.edit.listeners) != 'undefined') {
13817 this.editicon = this.wrap.createChild(
13818 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
13819 if (this.addicon) {
13820 this.editicon.setStyle('margin-left', '40px');
13822 this.editicon.on('click', function(e) {
13824 // we fire even if inothing is selected..
13825 this.fireEvent('edit', this, this.lastData );
13831 this.keyNav = new Roo.KeyNav(this.inputEl(), {
13832 "up" : function(e){
13833 this.inKeyMode = true;
13837 "down" : function(e){
13838 if(!this.isExpanded()){
13839 this.onTriggerClick();
13841 this.inKeyMode = true;
13846 "enter" : function(e){
13847 // this.onViewClick();
13851 if(this.fireEvent("specialkey", this, e)){
13852 this.onViewClick(false);
13858 "esc" : function(e){
13862 "tab" : function(e){
13865 if(this.fireEvent("specialkey", this, e)){
13866 this.onViewClick(false);
13874 doRelay : function(foo, bar, hname){
13875 if(hname == 'down' || this.scope.isExpanded()){
13876 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13885 this.queryDelay = Math.max(this.queryDelay || 10,
13886 this.mode == 'local' ? 10 : 250);
13889 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13891 if(this.typeAhead){
13892 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13894 if(this.editable !== false){
13895 this.inputEl().on("keyup", this.onKeyUp, this);
13897 if(this.forceSelection){
13898 this.inputEl().on('blur', this.doForce, this);
13902 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13903 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13907 initTickableEvents: function()
13911 if(this.hiddenName){
13913 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13915 this.hiddenField.dom.value =
13916 this.hiddenValue !== undefined ? this.hiddenValue :
13917 this.value !== undefined ? this.value : '';
13919 // prevent input submission
13920 this.el.dom.removeAttribute('name');
13921 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13926 // this.list = this.el.select('ul.dropdown-menu',true).first();
13928 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13929 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13930 if(this.triggerList){
13931 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
13934 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
13935 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
13937 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
13938 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
13940 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
13941 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
13943 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
13944 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
13945 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
13948 this.cancelBtn.hide();
13953 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13954 _this.list.setWidth(lw);
13957 this.list.on('mouseover', this.onViewOver, this);
13958 this.list.on('mousemove', this.onViewMove, this);
13960 this.list.on('scroll', this.onViewScroll, this);
13963 this.tpl = '<li class="roo-select2-result"><div class="checkbox"><input id="{roo-id}"' +
13964 'type="checkbox" {roo-data-checked}><label for="{roo-id}"><b>{' + this.displayField + '}</b></label></div></li>';
13967 this.view = new Roo.View(this.list, this.tpl, {
13972 selectedClass: this.selectedClass
13975 //this.view.wrapEl.setDisplayed(false);
13976 this.view.on('click', this.onViewClick, this);
13980 this.store.on('beforeload', this.onBeforeLoad, this);
13981 this.store.on('load', this.onLoad, this);
13982 this.store.on('loadexception', this.onLoadException, this);
13985 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
13986 "up" : function(e){
13987 this.inKeyMode = true;
13991 "down" : function(e){
13992 this.inKeyMode = true;
13996 "enter" : function(e){
13997 if(this.fireEvent("specialkey", this, e)){
13998 this.onViewClick(false);
14004 "esc" : function(e){
14005 this.onTickableFooterButtonClick(e, false, false);
14008 "tab" : function(e){
14009 this.fireEvent("specialkey", this, e);
14011 this.onTickableFooterButtonClick(e, false, false);
14018 doRelay : function(e, fn, key){
14019 if(this.scope.isExpanded()){
14020 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
14029 this.queryDelay = Math.max(this.queryDelay || 10,
14030 this.mode == 'local' ? 10 : 250);
14033 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
14035 if(this.typeAhead){
14036 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
14039 if(this.editable !== false){
14040 this.tickableInputEl().on("keyup", this.onKeyUp, this);
14043 this.indicator = this.indicatorEl();
14045 if(this.indicator){
14046 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
14047 this.indicator.hide();
14052 onDestroy : function(){
14054 this.view.setStore(null);
14055 this.view.el.removeAllListeners();
14056 this.view.el.remove();
14057 this.view.purgeListeners();
14060 this.list.dom.innerHTML = '';
14064 this.store.un('beforeload', this.onBeforeLoad, this);
14065 this.store.un('load', this.onLoad, this);
14066 this.store.un('loadexception', this.onLoadException, this);
14068 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
14072 fireKey : function(e){
14073 if(e.isNavKeyPress() && !this.list.isVisible()){
14074 this.fireEvent("specialkey", this, e);
14079 onResize: function(w, h){
14080 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
14082 // if(typeof w != 'number'){
14083 // // we do not handle it!?!?
14086 // var tw = this.trigger.getWidth();
14087 // // tw += this.addicon ? this.addicon.getWidth() : 0;
14088 // // tw += this.editicon ? this.editicon.getWidth() : 0;
14090 // this.inputEl().setWidth( this.adjustWidth('input', x));
14092 // //this.trigger.setStyle('left', x+'px');
14094 // if(this.list && this.listWidth === undefined){
14095 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
14096 // this.list.setWidth(lw);
14097 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
14105 * Allow or prevent the user from directly editing the field text. If false is passed,
14106 * the user will only be able to select from the items defined in the dropdown list. This method
14107 * is the runtime equivalent of setting the 'editable' config option at config time.
14108 * @param {Boolean} value True to allow the user to directly edit the field text
14110 setEditable : function(value){
14111 if(value == this.editable){
14114 this.editable = value;
14116 this.inputEl().dom.setAttribute('readOnly', true);
14117 this.inputEl().on('mousedown', this.onTriggerClick, this);
14118 this.inputEl().addClass('x-combo-noedit');
14120 this.inputEl().dom.setAttribute('readOnly', false);
14121 this.inputEl().un('mousedown', this.onTriggerClick, this);
14122 this.inputEl().removeClass('x-combo-noedit');
14128 onBeforeLoad : function(combo,opts){
14129 if(!this.hasFocus){
14133 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
14135 this.restrictHeight();
14136 this.selectedIndex = -1;
14140 onLoad : function(){
14142 this.hasQuery = false;
14144 if(!this.hasFocus){
14148 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
14149 this.loading.hide();
14152 if(this.store.getCount() > 0){
14155 this.restrictHeight();
14156 if(this.lastQuery == this.allQuery){
14157 if(this.editable && !this.tickable){
14158 this.inputEl().dom.select();
14162 !this.selectByValue(this.value, true) &&
14165 !this.store.lastOptions ||
14166 typeof(this.store.lastOptions.add) == 'undefined' ||
14167 this.store.lastOptions.add != true
14170 this.select(0, true);
14173 if(this.autoFocus){
14176 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
14177 this.taTask.delay(this.typeAheadDelay);
14181 this.onEmptyResults();
14187 onLoadException : function()
14189 this.hasQuery = false;
14191 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
14192 this.loading.hide();
14195 if(this.tickable && this.editable){
14200 // only causes errors at present
14201 //Roo.log(this.store.reader.jsonData);
14202 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
14204 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
14210 onTypeAhead : function(){
14211 if(this.store.getCount() > 0){
14212 var r = this.store.getAt(0);
14213 var newValue = r.data[this.displayField];
14214 var len = newValue.length;
14215 var selStart = this.getRawValue().length;
14217 if(selStart != len){
14218 this.setRawValue(newValue);
14219 this.selectText(selStart, newValue.length);
14225 onSelect : function(record, index){
14227 if(this.fireEvent('beforeselect', this, record, index) !== false){
14229 this.setFromData(index > -1 ? record.data : false);
14232 this.fireEvent('select', this, record, index);
14237 * Returns the currently selected field value or empty string if no value is set.
14238 * @return {String} value The selected value
14240 getValue : function()
14242 if(Roo.isIOS && this.useNativeIOS){
14243 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
14247 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
14250 if(this.valueField){
14251 return typeof this.value != 'undefined' ? this.value : '';
14253 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
14257 getRawValue : function()
14259 if(Roo.isIOS && this.useNativeIOS){
14260 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
14263 var v = this.inputEl().getValue();
14269 * Clears any text/value currently set in the field
14271 clearValue : function(){
14273 if(this.hiddenField){
14274 this.hiddenField.dom.value = '';
14277 this.setRawValue('');
14278 this.lastSelectionText = '';
14279 this.lastData = false;
14281 var close = this.closeTriggerEl();
14292 * Sets the specified value into the field. If the value finds a match, the corresponding record text
14293 * will be displayed in the field. If the value does not match the data value of an existing item,
14294 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
14295 * Otherwise the field will be blank (although the value will still be set).
14296 * @param {String} value The value to match
14298 setValue : function(v)
14300 if(Roo.isIOS && this.useNativeIOS){
14301 this.setIOSValue(v);
14311 if(this.valueField){
14312 var r = this.findRecord(this.valueField, v);
14314 text = r.data[this.displayField];
14315 }else if(this.valueNotFoundText !== undefined){
14316 text = this.valueNotFoundText;
14319 this.lastSelectionText = text;
14320 if(this.hiddenField){
14321 this.hiddenField.dom.value = v;
14323 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
14326 var close = this.closeTriggerEl();
14329 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
14335 * @property {Object} the last set data for the element
14340 * Sets the value of the field based on a object which is related to the record format for the store.
14341 * @param {Object} value the value to set as. or false on reset?
14343 setFromData : function(o){
14350 var dv = ''; // display value
14351 var vv = ''; // value value..
14353 if (this.displayField) {
14354 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14356 // this is an error condition!!!
14357 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14360 if(this.valueField){
14361 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
14364 var close = this.closeTriggerEl();
14367 if(dv.length || vv * 1 > 0){
14369 this.blockFocus=true;
14375 if(this.hiddenField){
14376 this.hiddenField.dom.value = vv;
14378 this.lastSelectionText = dv;
14379 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14383 // no hidden field.. - we store the value in 'value', but still display
14384 // display field!!!!
14385 this.lastSelectionText = dv;
14386 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14393 reset : function(){
14394 // overridden so that last data is reset..
14401 this.setValue(this.originalValue);
14402 //this.clearInvalid();
14403 this.lastData = false;
14405 this.view.clearSelections();
14411 findRecord : function(prop, value){
14413 if(this.store.getCount() > 0){
14414 this.store.each(function(r){
14415 if(r.data[prop] == value){
14425 getName: function()
14427 // returns hidden if it's set..
14428 if (!this.rendered) {return ''};
14429 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
14433 onViewMove : function(e, t){
14434 this.inKeyMode = false;
14438 onViewOver : function(e, t){
14439 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
14442 var item = this.view.findItemFromChild(t);
14445 var index = this.view.indexOf(item);
14446 this.select(index, false);
14451 onViewClick : function(view, doFocus, el, e)
14453 var index = this.view.getSelectedIndexes()[0];
14455 var r = this.store.getAt(index);
14459 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
14466 Roo.each(this.tickItems, function(v,k){
14468 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
14470 _this.tickItems.splice(k, 1);
14472 if(typeof(e) == 'undefined' && view == false){
14473 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
14485 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
14486 this.tickItems.push(r.data);
14489 if(typeof(e) == 'undefined' && view == false){
14490 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
14497 this.onSelect(r, index);
14499 if(doFocus !== false && !this.blockFocus){
14500 this.inputEl().focus();
14505 restrictHeight : function(){
14506 //this.innerList.dom.style.height = '';
14507 //var inner = this.innerList.dom;
14508 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
14509 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
14510 //this.list.beginUpdate();
14511 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
14512 this.list.alignTo(this.inputEl(), this.listAlign);
14513 this.list.alignTo(this.inputEl(), this.listAlign);
14514 //this.list.endUpdate();
14518 onEmptyResults : function(){
14520 if(this.tickable && this.editable){
14521 this.hasFocus = false;
14522 this.restrictHeight();
14530 * Returns true if the dropdown list is expanded, else false.
14532 isExpanded : function(){
14533 return this.list.isVisible();
14537 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
14538 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14539 * @param {String} value The data value of the item to select
14540 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14541 * selected item if it is not currently in view (defaults to true)
14542 * @return {Boolean} True if the value matched an item in the list, else false
14544 selectByValue : function(v, scrollIntoView){
14545 if(v !== undefined && v !== null){
14546 var r = this.findRecord(this.valueField || this.displayField, v);
14548 this.select(this.store.indexOf(r), scrollIntoView);
14556 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
14557 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14558 * @param {Number} index The zero-based index of the list item to select
14559 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14560 * selected item if it is not currently in view (defaults to true)
14562 select : function(index, scrollIntoView){
14563 this.selectedIndex = index;
14564 this.view.select(index);
14565 if(scrollIntoView !== false){
14566 var el = this.view.getNode(index);
14568 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
14571 this.list.scrollChildIntoView(el, false);
14577 selectNext : function(){
14578 var ct = this.store.getCount();
14580 if(this.selectedIndex == -1){
14582 }else if(this.selectedIndex < ct-1){
14583 this.select(this.selectedIndex+1);
14589 selectPrev : function(){
14590 var ct = this.store.getCount();
14592 if(this.selectedIndex == -1){
14594 }else if(this.selectedIndex != 0){
14595 this.select(this.selectedIndex-1);
14601 onKeyUp : function(e){
14602 if(this.editable !== false && !e.isSpecialKey()){
14603 this.lastKey = e.getKey();
14604 this.dqTask.delay(this.queryDelay);
14609 validateBlur : function(){
14610 return !this.list || !this.list.isVisible();
14614 initQuery : function(){
14616 var v = this.getRawValue();
14618 if(this.tickable && this.editable){
14619 v = this.tickableInputEl().getValue();
14626 doForce : function(){
14627 if(this.inputEl().dom.value.length > 0){
14628 this.inputEl().dom.value =
14629 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
14635 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
14636 * query allowing the query action to be canceled if needed.
14637 * @param {String} query The SQL query to execute
14638 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
14639 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
14640 * saved in the current store (defaults to false)
14642 doQuery : function(q, forceAll){
14644 if(q === undefined || q === null){
14649 forceAll: forceAll,
14653 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
14658 forceAll = qe.forceAll;
14659 if(forceAll === true || (q.length >= this.minChars)){
14661 this.hasQuery = true;
14663 if(this.lastQuery != q || this.alwaysQuery){
14664 this.lastQuery = q;
14665 if(this.mode == 'local'){
14666 this.selectedIndex = -1;
14668 this.store.clearFilter();
14671 if(this.specialFilter){
14672 this.fireEvent('specialfilter', this);
14677 this.store.filter(this.displayField, q);
14680 this.store.fireEvent("datachanged", this.store);
14687 this.store.baseParams[this.queryParam] = q;
14689 var options = {params : this.getParams(q)};
14692 options.add = true;
14693 options.params.start = this.page * this.pageSize;
14696 this.store.load(options);
14699 * this code will make the page width larger, at the beginning, the list not align correctly,
14700 * we should expand the list on onLoad
14701 * so command out it
14706 this.selectedIndex = -1;
14711 this.loadNext = false;
14715 getParams : function(q){
14717 //p[this.queryParam] = q;
14721 p.limit = this.pageSize;
14727 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
14729 collapse : function(){
14730 if(!this.isExpanded()){
14736 this.hasFocus = false;
14740 this.cancelBtn.hide();
14741 this.trigger.show();
14744 this.tickableInputEl().dom.value = '';
14745 this.tickableInputEl().blur();
14750 Roo.get(document).un('mousedown', this.collapseIf, this);
14751 Roo.get(document).un('mousewheel', this.collapseIf, this);
14752 if (!this.editable) {
14753 Roo.get(document).un('keydown', this.listKeyPress, this);
14755 this.fireEvent('collapse', this);
14761 collapseIf : function(e){
14762 var in_combo = e.within(this.el);
14763 var in_list = e.within(this.list);
14764 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
14766 if (in_combo || in_list || is_list) {
14767 //e.stopPropagation();
14772 this.onTickableFooterButtonClick(e, false, false);
14780 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
14782 expand : function(){
14784 if(this.isExpanded() || !this.hasFocus){
14788 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
14789 this.list.setWidth(lw);
14795 this.restrictHeight();
14799 this.tickItems = Roo.apply([], this.item);
14802 this.cancelBtn.show();
14803 this.trigger.hide();
14806 this.tickableInputEl().focus();
14811 Roo.get(document).on('mousedown', this.collapseIf, this);
14812 Roo.get(document).on('mousewheel', this.collapseIf, this);
14813 if (!this.editable) {
14814 Roo.get(document).on('keydown', this.listKeyPress, this);
14817 this.fireEvent('expand', this);
14821 // Implements the default empty TriggerField.onTriggerClick function
14822 onTriggerClick : function(e)
14824 Roo.log('trigger click');
14826 if(this.disabled || !this.triggerList){
14831 this.loadNext = false;
14833 if(this.isExpanded()){
14835 if (!this.blockFocus) {
14836 this.inputEl().focus();
14840 this.hasFocus = true;
14841 if(this.triggerAction == 'all') {
14842 this.doQuery(this.allQuery, true);
14844 this.doQuery(this.getRawValue());
14846 if (!this.blockFocus) {
14847 this.inputEl().focus();
14852 onTickableTriggerClick : function(e)
14859 this.loadNext = false;
14860 this.hasFocus = true;
14862 if(this.triggerAction == 'all') {
14863 this.doQuery(this.allQuery, true);
14865 this.doQuery(this.getRawValue());
14869 onSearchFieldClick : function(e)
14871 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
14872 this.onTickableFooterButtonClick(e, false, false);
14876 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
14881 this.loadNext = false;
14882 this.hasFocus = true;
14884 if(this.triggerAction == 'all') {
14885 this.doQuery(this.allQuery, true);
14887 this.doQuery(this.getRawValue());
14891 listKeyPress : function(e)
14893 //Roo.log('listkeypress');
14894 // scroll to first matching element based on key pres..
14895 if (e.isSpecialKey()) {
14898 var k = String.fromCharCode(e.getKey()).toUpperCase();
14901 var csel = this.view.getSelectedNodes();
14902 var cselitem = false;
14904 var ix = this.view.indexOf(csel[0]);
14905 cselitem = this.store.getAt(ix);
14906 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
14912 this.store.each(function(v) {
14914 // start at existing selection.
14915 if (cselitem.id == v.id) {
14921 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
14922 match = this.store.indexOf(v);
14928 if (match === false) {
14929 return true; // no more action?
14932 this.view.select(match);
14933 var sn = Roo.get(this.view.getSelectedNodes()[0]);
14934 sn.scrollIntoView(sn.dom.parentNode, false);
14937 onViewScroll : function(e, t){
14939 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){
14943 this.hasQuery = true;
14945 this.loading = this.list.select('.loading', true).first();
14947 if(this.loading === null){
14948 this.list.createChild({
14950 cls: 'loading roo-select2-more-results roo-select2-active',
14951 html: 'Loading more results...'
14954 this.loading = this.list.select('.loading', true).first();
14956 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
14958 this.loading.hide();
14961 this.loading.show();
14966 this.loadNext = true;
14968 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
14973 addItem : function(o)
14975 var dv = ''; // display value
14977 if (this.displayField) {
14978 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14980 // this is an error condition!!!
14981 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14988 var choice = this.choices.createChild({
14990 cls: 'roo-select2-search-choice',
14999 cls: 'roo-select2-search-choice-close fa fa-times',
15004 }, this.searchField);
15006 var close = choice.select('a.roo-select2-search-choice-close', true).first();
15008 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
15016 this.inputEl().dom.value = '';
15021 onRemoveItem : function(e, _self, o)
15023 e.preventDefault();
15025 this.lastItem = Roo.apply([], this.item);
15027 var index = this.item.indexOf(o.data) * 1;
15030 Roo.log('not this item?!');
15034 this.item.splice(index, 1);
15039 this.fireEvent('remove', this, e);
15045 syncValue : function()
15047 if(!this.item.length){
15054 Roo.each(this.item, function(i){
15055 if(_this.valueField){
15056 value.push(i[_this.valueField]);
15063 this.value = value.join(',');
15065 if(this.hiddenField){
15066 this.hiddenField.dom.value = this.value;
15069 this.store.fireEvent("datachanged", this.store);
15074 clearItem : function()
15076 if(!this.multiple){
15082 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
15090 if(this.tickable && !Roo.isTouch){
15091 this.view.refresh();
15095 inputEl: function ()
15097 if(Roo.isIOS && this.useNativeIOS){
15098 return this.el.select('select.roo-ios-select', true).first();
15101 if(Roo.isTouch && this.mobileTouchView){
15102 return this.el.select('input.form-control',true).first();
15106 return this.searchField;
15109 return this.el.select('input.form-control',true).first();
15112 onTickableFooterButtonClick : function(e, btn, el)
15114 e.preventDefault();
15116 this.lastItem = Roo.apply([], this.item);
15118 if(btn && btn.name == 'cancel'){
15119 this.tickItems = Roo.apply([], this.item);
15128 Roo.each(this.tickItems, function(o){
15136 validate : function()
15138 if(this.getVisibilityEl().hasClass('hidden')){
15142 var v = this.getRawValue();
15145 v = this.getValue();
15148 if(this.disabled || this.allowBlank || v.length){
15153 this.markInvalid();
15157 tickableInputEl : function()
15159 if(!this.tickable || !this.editable){
15160 return this.inputEl();
15163 return this.inputEl().select('.roo-select2-search-field-input', true).first();
15167 getAutoCreateTouchView : function()
15172 cls: 'form-group' //input-group
15178 type : this.inputType,
15179 cls : 'form-control x-combo-noedit',
15180 autocomplete: 'new-password',
15181 placeholder : this.placeholder || '',
15186 input.name = this.name;
15190 input.cls += ' input-' + this.size;
15193 if (this.disabled) {
15194 input.disabled = true;
15205 inputblock.cls += ' input-group';
15207 inputblock.cn.unshift({
15209 cls : 'input-group-addon input-group-prepend input-group-text',
15214 if(this.removable && !this.multiple){
15215 inputblock.cls += ' roo-removable';
15217 inputblock.cn.push({
15220 cls : 'roo-combo-removable-btn close'
15224 if(this.hasFeedback && !this.allowBlank){
15226 inputblock.cls += ' has-feedback';
15228 inputblock.cn.push({
15230 cls: 'glyphicon form-control-feedback'
15237 inputblock.cls += (this.before) ? '' : ' input-group';
15239 inputblock.cn.push({
15241 cls : 'input-group-addon input-group-append input-group-text',
15247 var ibwrap = inputblock;
15252 cls: 'roo-select2-choices',
15256 cls: 'roo-select2-search-field',
15269 cls: 'roo-select2-container input-group roo-touchview-combobox ',
15274 cls: 'form-hidden-field'
15280 if(!this.multiple && this.showToggleBtn){
15287 if (this.caret != false) {
15290 cls: 'fa fa-' + this.caret
15297 cls : 'input-group-addon input-group-append input-group-text btn dropdown-toggle',
15302 cls: 'combobox-clear',
15316 combobox.cls += ' roo-select2-container-multi';
15319 var align = this.labelAlign || this.parentLabelAlign();
15321 if (align ==='left' && this.fieldLabel.length) {
15326 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15327 tooltip : 'This field is required'
15331 cls : 'control-label col-form-label',
15332 html : this.fieldLabel
15343 var labelCfg = cfg.cn[1];
15344 var contentCfg = cfg.cn[2];
15347 if(this.indicatorpos == 'right'){
15352 cls : 'control-label col-form-label',
15356 html : this.fieldLabel
15360 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15361 tooltip : 'This field is required'
15374 labelCfg = cfg.cn[0];
15375 contentCfg = cfg.cn[1];
15380 if(this.labelWidth > 12){
15381 labelCfg.style = "width: " + this.labelWidth + 'px';
15384 if(this.labelWidth < 13 && this.labelmd == 0){
15385 this.labelmd = this.labelWidth;
15388 if(this.labellg > 0){
15389 labelCfg.cls += ' col-lg-' + this.labellg;
15390 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
15393 if(this.labelmd > 0){
15394 labelCfg.cls += ' col-md-' + this.labelmd;
15395 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
15398 if(this.labelsm > 0){
15399 labelCfg.cls += ' col-sm-' + this.labelsm;
15400 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
15403 if(this.labelxs > 0){
15404 labelCfg.cls += ' col-xs-' + this.labelxs;
15405 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
15409 } else if ( this.fieldLabel.length) {
15413 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15414 tooltip : 'This field is required'
15418 cls : 'control-label',
15419 html : this.fieldLabel
15430 if(this.indicatorpos == 'right'){
15434 cls : 'control-label',
15435 html : this.fieldLabel,
15439 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15440 tooltip : 'This field is required'
15457 var settings = this;
15459 ['xs','sm','md','lg'].map(function(size){
15460 if (settings[size]) {
15461 cfg.cls += ' col-' + size + '-' + settings[size];
15468 initTouchView : function()
15470 this.renderTouchView();
15472 this.touchViewEl.on('scroll', function(){
15473 this.el.dom.scrollTop = 0;
15476 this.originalValue = this.getValue();
15478 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
15480 this.inputEl().on("click", this.showTouchView, this);
15481 if (this.triggerEl) {
15482 this.triggerEl.on("click", this.showTouchView, this);
15486 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
15487 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
15489 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
15491 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
15492 this.store.on('load', this.onTouchViewLoad, this);
15493 this.store.on('loadexception', this.onTouchViewLoadException, this);
15495 if(this.hiddenName){
15497 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
15499 this.hiddenField.dom.value =
15500 this.hiddenValue !== undefined ? this.hiddenValue :
15501 this.value !== undefined ? this.value : '';
15503 this.el.dom.removeAttribute('name');
15504 this.hiddenField.dom.setAttribute('name', this.hiddenName);
15508 this.choices = this.el.select('ul.roo-select2-choices', true).first();
15509 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
15512 if(this.removable && !this.multiple){
15513 var close = this.closeTriggerEl();
15515 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
15516 close.on('click', this.removeBtnClick, this, close);
15520 * fix the bug in Safari iOS8
15522 this.inputEl().on("focus", function(e){
15523 document.activeElement.blur();
15526 this._touchViewMask = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
15533 renderTouchView : function()
15535 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
15536 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15538 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
15539 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15541 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
15542 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15543 this.touchViewBodyEl.setStyle('overflow', 'auto');
15545 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
15546 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15548 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
15549 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15553 showTouchView : function()
15559 this.touchViewHeaderEl.hide();
15561 if(this.modalTitle.length){
15562 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
15563 this.touchViewHeaderEl.show();
15566 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
15567 this.touchViewEl.show();
15569 this.touchViewEl.select('.modal-dialog', true).first().setStyle({ margin : '0px', width : '100%'});
15571 //this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
15572 // Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15574 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15576 if(this.modalTitle.length){
15577 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15580 this.touchViewBodyEl.setHeight(bodyHeight);
15584 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
15586 this.touchViewEl.addClass('in');
15589 if(this._touchViewMask){
15590 Roo.get(document.body).addClass("x-body-masked");
15591 this._touchViewMask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15592 this._touchViewMask.setStyle('z-index', 10000);
15593 this._touchViewMask.addClass('show');
15596 this.doTouchViewQuery();
15600 hideTouchView : function()
15602 this.touchViewEl.removeClass('in');
15606 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
15608 this.touchViewEl.setStyle('display', 'none');
15611 if(this._touchViewMask){
15612 this._touchViewMask.removeClass('show');
15613 Roo.get(document.body).removeClass("x-body-masked");
15617 setTouchViewValue : function()
15624 Roo.each(this.tickItems, function(o){
15629 this.hideTouchView();
15632 doTouchViewQuery : function()
15641 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
15645 if(!this.alwaysQuery || this.mode == 'local'){
15646 this.onTouchViewLoad();
15653 onTouchViewBeforeLoad : function(combo,opts)
15659 onTouchViewLoad : function()
15661 if(this.store.getCount() < 1){
15662 this.onTouchViewEmptyResults();
15666 this.clearTouchView();
15668 var rawValue = this.getRawValue();
15670 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
15672 this.tickItems = [];
15674 this.store.data.each(function(d, rowIndex){
15675 var row = this.touchViewListGroup.createChild(template);
15677 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
15678 row.addClass(d.data.cls);
15681 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15684 html : d.data[this.displayField]
15687 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
15688 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
15691 row.removeClass('selected');
15692 if(!this.multiple && this.valueField &&
15693 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
15696 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15697 row.addClass('selected');
15700 if(this.multiple && this.valueField &&
15701 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
15705 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15706 this.tickItems.push(d.data);
15709 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
15713 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
15715 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15717 if(this.modalTitle.length){
15718 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15721 var listHeight = this.touchViewListGroup.getHeight() + this.touchViewBodyEl.getPadding('tb') * 2;
15723 if(this.mobile_restrict_height && listHeight < bodyHeight){
15724 this.touchViewBodyEl.setHeight(listHeight);
15729 if(firstChecked && listHeight > bodyHeight){
15730 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
15735 onTouchViewLoadException : function()
15737 this.hideTouchView();
15740 onTouchViewEmptyResults : function()
15742 this.clearTouchView();
15744 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
15746 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
15750 clearTouchView : function()
15752 this.touchViewListGroup.dom.innerHTML = '';
15755 onTouchViewClick : function(e, el, o)
15757 e.preventDefault();
15760 var rowIndex = o.rowIndex;
15762 var r = this.store.getAt(rowIndex);
15764 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
15766 if(!this.multiple){
15767 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
15768 c.dom.removeAttribute('checked');
15771 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15773 this.setFromData(r.data);
15775 var close = this.closeTriggerEl();
15781 this.hideTouchView();
15783 this.fireEvent('select', this, r, rowIndex);
15788 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
15789 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
15790 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
15794 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15795 this.addItem(r.data);
15796 this.tickItems.push(r.data);
15800 getAutoCreateNativeIOS : function()
15803 cls: 'form-group' //input-group,
15808 cls : 'roo-ios-select'
15812 combobox.name = this.name;
15815 if (this.disabled) {
15816 combobox.disabled = true;
15819 var settings = this;
15821 ['xs','sm','md','lg'].map(function(size){
15822 if (settings[size]) {
15823 cfg.cls += ' col-' + size + '-' + settings[size];
15833 initIOSView : function()
15835 this.store.on('load', this.onIOSViewLoad, this);
15840 onIOSViewLoad : function()
15842 if(this.store.getCount() < 1){
15846 this.clearIOSView();
15848 if(this.allowBlank) {
15850 var default_text = '-- SELECT --';
15852 if(this.placeholder.length){
15853 default_text = this.placeholder;
15856 if(this.emptyTitle.length){
15857 default_text += ' - ' + this.emptyTitle + ' -';
15860 var opt = this.inputEl().createChild({
15863 html : default_text
15867 o[this.valueField] = 0;
15868 o[this.displayField] = default_text;
15870 this.ios_options.push({
15877 this.store.data.each(function(d, rowIndex){
15881 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15882 html = d.data[this.displayField];
15887 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
15888 value = d.data[this.valueField];
15897 if(this.value == d.data[this.valueField]){
15898 option['selected'] = true;
15901 var opt = this.inputEl().createChild(option);
15903 this.ios_options.push({
15910 this.inputEl().on('change', function(){
15911 this.fireEvent('select', this);
15916 clearIOSView: function()
15918 this.inputEl().dom.innerHTML = '';
15920 this.ios_options = [];
15923 setIOSValue: function(v)
15927 if(!this.ios_options){
15931 Roo.each(this.ios_options, function(opts){
15933 opts.el.dom.removeAttribute('selected');
15935 if(opts.data[this.valueField] != v){
15939 opts.el.dom.setAttribute('selected', true);
15945 * @cfg {Boolean} grow
15949 * @cfg {Number} growMin
15953 * @cfg {Number} growMax
15962 Roo.apply(Roo.bootstrap.ComboBox, {
15966 cls: 'modal-header',
15988 cls: 'list-group-item',
15992 cls: 'roo-combobox-list-group-item-value'
15996 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
16010 listItemCheckbox : {
16012 cls: 'list-group-item',
16016 cls: 'roo-combobox-list-group-item-value'
16020 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
16036 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
16041 cls: 'modal-footer',
16049 cls: 'col-xs-6 text-left',
16052 cls: 'btn btn-danger roo-touch-view-cancel',
16058 cls: 'col-xs-6 text-right',
16061 cls: 'btn btn-success roo-touch-view-ok',
16072 Roo.apply(Roo.bootstrap.ComboBox, {
16074 touchViewTemplate : {
16076 cls: 'modal fade roo-combobox-touch-view',
16080 cls: 'modal-dialog',
16081 style : 'position:fixed', // we have to fix position....
16085 cls: 'modal-content',
16087 Roo.bootstrap.ComboBox.header,
16088 Roo.bootstrap.ComboBox.body,
16089 Roo.bootstrap.ComboBox.footer
16098 * Ext JS Library 1.1.1
16099 * Copyright(c) 2006-2007, Ext JS, LLC.
16101 * Originally Released Under LGPL - original licence link has changed is not relivant.
16104 * <script type="text/javascript">
16109 * @extends Roo.util.Observable
16110 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
16111 * This class also supports single and multi selection modes. <br>
16112 * Create a data model bound view:
16114 var store = new Roo.data.Store(...);
16116 var view = new Roo.View({
16118 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
16120 singleSelect: true,
16121 selectedClass: "ydataview-selected",
16125 // listen for node click?
16126 view.on("click", function(vw, index, node, e){
16127 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
16131 dataModel.load("foobar.xml");
16133 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
16135 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
16136 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
16138 * Note: old style constructor is still suported (container, template, config)
16141 * Create a new View
16142 * @param {Object} config The config object
16145 Roo.View = function(config, depreciated_tpl, depreciated_config){
16147 this.parent = false;
16149 if (typeof(depreciated_tpl) == 'undefined') {
16150 // new way.. - universal constructor.
16151 Roo.apply(this, config);
16152 this.el = Roo.get(this.el);
16155 this.el = Roo.get(config);
16156 this.tpl = depreciated_tpl;
16157 Roo.apply(this, depreciated_config);
16159 this.wrapEl = this.el.wrap().wrap();
16160 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
16163 if(typeof(this.tpl) == "string"){
16164 this.tpl = new Roo.Template(this.tpl);
16166 // support xtype ctors..
16167 this.tpl = new Roo.factory(this.tpl, Roo);
16171 this.tpl.compile();
16176 * @event beforeclick
16177 * Fires before a click is processed. Returns false to cancel the default action.
16178 * @param {Roo.View} this
16179 * @param {Number} index The index of the target node
16180 * @param {HTMLElement} node The target node
16181 * @param {Roo.EventObject} e The raw event object
16183 "beforeclick" : true,
16186 * Fires when a template node is clicked.
16187 * @param {Roo.View} this
16188 * @param {Number} index The index of the target node
16189 * @param {HTMLElement} node The target node
16190 * @param {Roo.EventObject} e The raw event object
16195 * Fires when a template node is double clicked.
16196 * @param {Roo.View} this
16197 * @param {Number} index The index of the target node
16198 * @param {HTMLElement} node The target node
16199 * @param {Roo.EventObject} e The raw event object
16203 * @event contextmenu
16204 * Fires when a template node is right clicked.
16205 * @param {Roo.View} this
16206 * @param {Number} index The index of the target node
16207 * @param {HTMLElement} node The target node
16208 * @param {Roo.EventObject} e The raw event object
16210 "contextmenu" : true,
16212 * @event selectionchange
16213 * Fires when the selected nodes change.
16214 * @param {Roo.View} this
16215 * @param {Array} selections Array of the selected nodes
16217 "selectionchange" : true,
16220 * @event beforeselect
16221 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
16222 * @param {Roo.View} this
16223 * @param {HTMLElement} node The node to be selected
16224 * @param {Array} selections Array of currently selected nodes
16226 "beforeselect" : true,
16228 * @event preparedata
16229 * Fires on every row to render, to allow you to change the data.
16230 * @param {Roo.View} this
16231 * @param {Object} data to be rendered (change this)
16233 "preparedata" : true
16241 "click": this.onClick,
16242 "dblclick": this.onDblClick,
16243 "contextmenu": this.onContextMenu,
16247 this.selections = [];
16249 this.cmp = new Roo.CompositeElementLite([]);
16251 this.store = Roo.factory(this.store, Roo.data);
16252 this.setStore(this.store, true);
16255 if ( this.footer && this.footer.xtype) {
16257 var fctr = this.wrapEl.appendChild(document.createElement("div"));
16259 this.footer.dataSource = this.store;
16260 this.footer.container = fctr;
16261 this.footer = Roo.factory(this.footer, Roo);
16262 fctr.insertFirst(this.el);
16264 // this is a bit insane - as the paging toolbar seems to detach the el..
16265 // dom.parentNode.parentNode.parentNode
16266 // they get detached?
16270 Roo.View.superclass.constructor.call(this);
16275 Roo.extend(Roo.View, Roo.util.Observable, {
16278 * @cfg {Roo.data.Store} store Data store to load data from.
16283 * @cfg {String|Roo.Element} el The container element.
16288 * @cfg {String|Roo.Template} tpl The template used by this View
16292 * @cfg {String} dataName the named area of the template to use as the data area
16293 * Works with domtemplates roo-name="name"
16297 * @cfg {String} selectedClass The css class to add to selected nodes
16299 selectedClass : "x-view-selected",
16301 * @cfg {String} emptyText The empty text to show when nothing is loaded.
16306 * @cfg {String} text to display on mask (default Loading)
16310 * @cfg {Boolean} multiSelect Allow multiple selection
16312 multiSelect : false,
16314 * @cfg {Boolean} singleSelect Allow single selection
16316 singleSelect: false,
16319 * @cfg {Boolean} toggleSelect - selecting
16321 toggleSelect : false,
16324 * @cfg {Boolean} tickable - selecting
16329 * Returns the element this view is bound to.
16330 * @return {Roo.Element}
16332 getEl : function(){
16333 return this.wrapEl;
16339 * Refreshes the view. - called by datachanged on the store. - do not call directly.
16341 refresh : function(){
16342 //Roo.log('refresh');
16345 // if we are using something like 'domtemplate', then
16346 // the what gets used is:
16347 // t.applySubtemplate(NAME, data, wrapping data..)
16348 // the outer template then get' applied with
16349 // the store 'extra data'
16350 // and the body get's added to the
16351 // roo-name="data" node?
16352 // <span class='roo-tpl-{name}'></span> ?????
16356 this.clearSelections();
16357 this.el.update("");
16359 var records = this.store.getRange();
16360 if(records.length < 1) {
16362 // is this valid?? = should it render a template??
16364 this.el.update(this.emptyText);
16368 if (this.dataName) {
16369 this.el.update(t.apply(this.store.meta)); //????
16370 el = this.el.child('.roo-tpl-' + this.dataName);
16373 for(var i = 0, len = records.length; i < len; i++){
16374 var data = this.prepareData(records[i].data, i, records[i]);
16375 this.fireEvent("preparedata", this, data, i, records[i]);
16377 var d = Roo.apply({}, data);
16380 Roo.apply(d, {'roo-id' : Roo.id()});
16384 Roo.each(this.parent.item, function(item){
16385 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
16388 Roo.apply(d, {'roo-data-checked' : 'checked'});
16392 html[html.length] = Roo.util.Format.trim(
16394 t.applySubtemplate(this.dataName, d, this.store.meta) :
16401 el.update(html.join(""));
16402 this.nodes = el.dom.childNodes;
16403 this.updateIndexes(0);
16408 * Function to override to reformat the data that is sent to
16409 * the template for each node.
16410 * DEPRICATED - use the preparedata event handler.
16411 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
16412 * a JSON object for an UpdateManager bound view).
16414 prepareData : function(data, index, record)
16416 this.fireEvent("preparedata", this, data, index, record);
16420 onUpdate : function(ds, record){
16421 // Roo.log('on update');
16422 this.clearSelections();
16423 var index = this.store.indexOf(record);
16424 var n = this.nodes[index];
16425 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
16426 n.parentNode.removeChild(n);
16427 this.updateIndexes(index, index);
16433 onAdd : function(ds, records, index)
16435 //Roo.log(['on Add', ds, records, index] );
16436 this.clearSelections();
16437 if(this.nodes.length == 0){
16441 var n = this.nodes[index];
16442 for(var i = 0, len = records.length; i < len; i++){
16443 var d = this.prepareData(records[i].data, i, records[i]);
16445 this.tpl.insertBefore(n, d);
16448 this.tpl.append(this.el, d);
16451 this.updateIndexes(index);
16454 onRemove : function(ds, record, index){
16455 // Roo.log('onRemove');
16456 this.clearSelections();
16457 var el = this.dataName ?
16458 this.el.child('.roo-tpl-' + this.dataName) :
16461 el.dom.removeChild(this.nodes[index]);
16462 this.updateIndexes(index);
16466 * Refresh an individual node.
16467 * @param {Number} index
16469 refreshNode : function(index){
16470 this.onUpdate(this.store, this.store.getAt(index));
16473 updateIndexes : function(startIndex, endIndex){
16474 var ns = this.nodes;
16475 startIndex = startIndex || 0;
16476 endIndex = endIndex || ns.length - 1;
16477 for(var i = startIndex; i <= endIndex; i++){
16478 ns[i].nodeIndex = i;
16483 * Changes the data store this view uses and refresh the view.
16484 * @param {Store} store
16486 setStore : function(store, initial){
16487 if(!initial && this.store){
16488 this.store.un("datachanged", this.refresh);
16489 this.store.un("add", this.onAdd);
16490 this.store.un("remove", this.onRemove);
16491 this.store.un("update", this.onUpdate);
16492 this.store.un("clear", this.refresh);
16493 this.store.un("beforeload", this.onBeforeLoad);
16494 this.store.un("load", this.onLoad);
16495 this.store.un("loadexception", this.onLoad);
16499 store.on("datachanged", this.refresh, this);
16500 store.on("add", this.onAdd, this);
16501 store.on("remove", this.onRemove, this);
16502 store.on("update", this.onUpdate, this);
16503 store.on("clear", this.refresh, this);
16504 store.on("beforeload", this.onBeforeLoad, this);
16505 store.on("load", this.onLoad, this);
16506 store.on("loadexception", this.onLoad, this);
16514 * onbeforeLoad - masks the loading area.
16517 onBeforeLoad : function(store,opts)
16519 //Roo.log('onBeforeLoad');
16521 this.el.update("");
16523 this.el.mask(this.mask ? this.mask : "Loading" );
16525 onLoad : function ()
16532 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
16533 * @param {HTMLElement} node
16534 * @return {HTMLElement} The template node
16536 findItemFromChild : function(node){
16537 var el = this.dataName ?
16538 this.el.child('.roo-tpl-' + this.dataName,true) :
16541 if(!node || node.parentNode == el){
16544 var p = node.parentNode;
16545 while(p && p != el){
16546 if(p.parentNode == el){
16555 onClick : function(e){
16556 var item = this.findItemFromChild(e.getTarget());
16558 var index = this.indexOf(item);
16559 if(this.onItemClick(item, index, e) !== false){
16560 this.fireEvent("click", this, index, item, e);
16563 this.clearSelections();
16568 onContextMenu : function(e){
16569 var item = this.findItemFromChild(e.getTarget());
16571 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
16576 onDblClick : function(e){
16577 var item = this.findItemFromChild(e.getTarget());
16579 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
16583 onItemClick : function(item, index, e)
16585 if(this.fireEvent("beforeclick", this, index, item, e) === false){
16588 if (this.toggleSelect) {
16589 var m = this.isSelected(item) ? 'unselect' : 'select';
16592 _t[m](item, true, false);
16595 if(this.multiSelect || this.singleSelect){
16596 if(this.multiSelect && e.shiftKey && this.lastSelection){
16597 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
16599 this.select(item, this.multiSelect && e.ctrlKey);
16600 this.lastSelection = item;
16603 if(!this.tickable){
16604 e.preventDefault();
16612 * Get the number of selected nodes.
16615 getSelectionCount : function(){
16616 return this.selections.length;
16620 * Get the currently selected nodes.
16621 * @return {Array} An array of HTMLElements
16623 getSelectedNodes : function(){
16624 return this.selections;
16628 * Get the indexes of the selected nodes.
16631 getSelectedIndexes : function(){
16632 var indexes = [], s = this.selections;
16633 for(var i = 0, len = s.length; i < len; i++){
16634 indexes.push(s[i].nodeIndex);
16640 * Clear all selections
16641 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
16643 clearSelections : function(suppressEvent){
16644 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
16645 this.cmp.elements = this.selections;
16646 this.cmp.removeClass(this.selectedClass);
16647 this.selections = [];
16648 if(!suppressEvent){
16649 this.fireEvent("selectionchange", this, this.selections);
16655 * Returns true if the passed node is selected
16656 * @param {HTMLElement/Number} node The node or node index
16657 * @return {Boolean}
16659 isSelected : function(node){
16660 var s = this.selections;
16664 node = this.getNode(node);
16665 return s.indexOf(node) !== -1;
16670 * @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
16671 * @param {Boolean} keepExisting (optional) true to keep existing selections
16672 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16674 select : function(nodeInfo, keepExisting, suppressEvent){
16675 if(nodeInfo instanceof Array){
16677 this.clearSelections(true);
16679 for(var i = 0, len = nodeInfo.length; i < len; i++){
16680 this.select(nodeInfo[i], true, true);
16684 var node = this.getNode(nodeInfo);
16685 if(!node || this.isSelected(node)){
16686 return; // already selected.
16689 this.clearSelections(true);
16692 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
16693 Roo.fly(node).addClass(this.selectedClass);
16694 this.selections.push(node);
16695 if(!suppressEvent){
16696 this.fireEvent("selectionchange", this, this.selections);
16704 * @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
16705 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
16706 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16708 unselect : function(nodeInfo, keepExisting, suppressEvent)
16710 if(nodeInfo instanceof Array){
16711 Roo.each(this.selections, function(s) {
16712 this.unselect(s, nodeInfo);
16716 var node = this.getNode(nodeInfo);
16717 if(!node || !this.isSelected(node)){
16718 //Roo.log("not selected");
16719 return; // not selected.
16723 Roo.each(this.selections, function(s) {
16725 Roo.fly(node).removeClass(this.selectedClass);
16732 this.selections= ns;
16733 this.fireEvent("selectionchange", this, this.selections);
16737 * Gets a template node.
16738 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16739 * @return {HTMLElement} The node or null if it wasn't found
16741 getNode : function(nodeInfo){
16742 if(typeof nodeInfo == "string"){
16743 return document.getElementById(nodeInfo);
16744 }else if(typeof nodeInfo == "number"){
16745 return this.nodes[nodeInfo];
16751 * Gets a range template nodes.
16752 * @param {Number} startIndex
16753 * @param {Number} endIndex
16754 * @return {Array} An array of nodes
16756 getNodes : function(start, end){
16757 var ns = this.nodes;
16758 start = start || 0;
16759 end = typeof end == "undefined" ? ns.length - 1 : end;
16762 for(var i = start; i <= end; i++){
16766 for(var i = start; i >= end; i--){
16774 * Finds the index of the passed node
16775 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16776 * @return {Number} The index of the node or -1
16778 indexOf : function(node){
16779 node = this.getNode(node);
16780 if(typeof node.nodeIndex == "number"){
16781 return node.nodeIndex;
16783 var ns = this.nodes;
16784 for(var i = 0, len = ns.length; i < len; i++){
16795 * based on jquery fullcalendar
16799 Roo.bootstrap = Roo.bootstrap || {};
16801 * @class Roo.bootstrap.Calendar
16802 * @extends Roo.bootstrap.Component
16803 * Bootstrap Calendar class
16804 * @cfg {Boolean} loadMask (true|false) default false
16805 * @cfg {Object} header generate the user specific header of the calendar, default false
16808 * Create a new Container
16809 * @param {Object} config The config object
16814 Roo.bootstrap.Calendar = function(config){
16815 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
16819 * Fires when a date is selected
16820 * @param {DatePicker} this
16821 * @param {Date} date The selected date
16825 * @event monthchange
16826 * Fires when the displayed month changes
16827 * @param {DatePicker} this
16828 * @param {Date} date The selected month
16830 'monthchange': true,
16832 * @event evententer
16833 * Fires when mouse over an event
16834 * @param {Calendar} this
16835 * @param {event} Event
16837 'evententer': true,
16839 * @event eventleave
16840 * Fires when the mouse leaves an
16841 * @param {Calendar} this
16844 'eventleave': true,
16846 * @event eventclick
16847 * Fires when the mouse click an
16848 * @param {Calendar} this
16857 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
16860 * @cfg {Number} startDay
16861 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16869 getAutoCreate : function(){
16872 var fc_button = function(name, corner, style, content ) {
16873 return Roo.apply({},{
16875 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
16877 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
16880 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
16891 style : 'width:100%',
16898 cls : 'fc-header-left',
16900 fc_button('prev', 'left', 'arrow', '‹' ),
16901 fc_button('next', 'right', 'arrow', '›' ),
16902 { tag: 'span', cls: 'fc-header-space' },
16903 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
16911 cls : 'fc-header-center',
16915 cls: 'fc-header-title',
16918 html : 'month / year'
16926 cls : 'fc-header-right',
16928 /* fc_button('month', 'left', '', 'month' ),
16929 fc_button('week', '', '', 'week' ),
16930 fc_button('day', 'right', '', 'day' )
16942 header = this.header;
16945 var cal_heads = function() {
16947 // fixme - handle this.
16949 for (var i =0; i < Date.dayNames.length; i++) {
16950 var d = Date.dayNames[i];
16953 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
16954 html : d.substring(0,3)
16958 ret[0].cls += ' fc-first';
16959 ret[6].cls += ' fc-last';
16962 var cal_cell = function(n) {
16965 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
16970 cls: 'fc-day-number',
16974 cls: 'fc-day-content',
16978 style: 'position: relative;' // height: 17px;
16990 var cal_rows = function() {
16993 for (var r = 0; r < 6; r++) {
17000 for (var i =0; i < Date.dayNames.length; i++) {
17001 var d = Date.dayNames[i];
17002 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
17005 row.cn[0].cls+=' fc-first';
17006 row.cn[0].cn[0].style = 'min-height:90px';
17007 row.cn[6].cls+=' fc-last';
17011 ret[0].cls += ' fc-first';
17012 ret[4].cls += ' fc-prev-last';
17013 ret[5].cls += ' fc-last';
17020 cls: 'fc-border-separate',
17021 style : 'width:100%',
17029 cls : 'fc-first fc-last',
17047 cls : 'fc-content',
17048 style : "position: relative;",
17051 cls : 'fc-view fc-view-month fc-grid',
17052 style : 'position: relative',
17053 unselectable : 'on',
17056 cls : 'fc-event-container',
17057 style : 'position:absolute;z-index:8;top:0;left:0;'
17075 initEvents : function()
17078 throw "can not find store for calendar";
17084 style: "text-align:center",
17088 style: "background-color:white;width:50%;margin:250 auto",
17092 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
17103 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
17105 var size = this.el.select('.fc-content', true).first().getSize();
17106 this.maskEl.setSize(size.width, size.height);
17107 this.maskEl.enableDisplayMode("block");
17108 if(!this.loadMask){
17109 this.maskEl.hide();
17112 this.store = Roo.factory(this.store, Roo.data);
17113 this.store.on('load', this.onLoad, this);
17114 this.store.on('beforeload', this.onBeforeLoad, this);
17118 this.cells = this.el.select('.fc-day',true);
17119 //Roo.log(this.cells);
17120 this.textNodes = this.el.query('.fc-day-number');
17121 this.cells.addClassOnOver('fc-state-hover');
17123 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
17124 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
17125 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
17126 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
17128 this.on('monthchange', this.onMonthChange, this);
17130 this.update(new Date().clearTime());
17133 resize : function() {
17134 var sz = this.el.getSize();
17136 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
17137 this.el.select('.fc-day-content div',true).setHeight(34);
17142 showPrevMonth : function(e){
17143 this.update(this.activeDate.add("mo", -1));
17145 showToday : function(e){
17146 this.update(new Date().clearTime());
17149 showNextMonth : function(e){
17150 this.update(this.activeDate.add("mo", 1));
17154 showPrevYear : function(){
17155 this.update(this.activeDate.add("y", -1));
17159 showNextYear : function(){
17160 this.update(this.activeDate.add("y", 1));
17165 update : function(date)
17167 var vd = this.activeDate;
17168 this.activeDate = date;
17169 // if(vd && this.el){
17170 // var t = date.getTime();
17171 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
17172 // Roo.log('using add remove');
17174 // this.fireEvent('monthchange', this, date);
17176 // this.cells.removeClass("fc-state-highlight");
17177 // this.cells.each(function(c){
17178 // if(c.dateValue == t){
17179 // c.addClass("fc-state-highlight");
17180 // setTimeout(function(){
17181 // try{c.dom.firstChild.focus();}catch(e){}
17191 var days = date.getDaysInMonth();
17193 var firstOfMonth = date.getFirstDateOfMonth();
17194 var startingPos = firstOfMonth.getDay()-this.startDay;
17196 if(startingPos < this.startDay){
17200 var pm = date.add(Date.MONTH, -1);
17201 var prevStart = pm.getDaysInMonth()-startingPos;
17203 this.cells = this.el.select('.fc-day',true);
17204 this.textNodes = this.el.query('.fc-day-number');
17205 this.cells.addClassOnOver('fc-state-hover');
17207 var cells = this.cells.elements;
17208 var textEls = this.textNodes;
17210 Roo.each(cells, function(cell){
17211 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
17214 days += startingPos;
17216 // convert everything to numbers so it's fast
17217 var day = 86400000;
17218 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
17221 //Roo.log(prevStart);
17223 var today = new Date().clearTime().getTime();
17224 var sel = date.clearTime().getTime();
17225 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
17226 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
17227 var ddMatch = this.disabledDatesRE;
17228 var ddText = this.disabledDatesText;
17229 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
17230 var ddaysText = this.disabledDaysText;
17231 var format = this.format;
17233 var setCellClass = function(cal, cell){
17237 //Roo.log('set Cell Class');
17239 var t = d.getTime();
17243 cell.dateValue = t;
17245 cell.className += " fc-today";
17246 cell.className += " fc-state-highlight";
17247 cell.title = cal.todayText;
17250 // disable highlight in other month..
17251 //cell.className += " fc-state-highlight";
17256 cell.className = " fc-state-disabled";
17257 cell.title = cal.minText;
17261 cell.className = " fc-state-disabled";
17262 cell.title = cal.maxText;
17266 if(ddays.indexOf(d.getDay()) != -1){
17267 cell.title = ddaysText;
17268 cell.className = " fc-state-disabled";
17271 if(ddMatch && format){
17272 var fvalue = d.dateFormat(format);
17273 if(ddMatch.test(fvalue)){
17274 cell.title = ddText.replace("%0", fvalue);
17275 cell.className = " fc-state-disabled";
17279 if (!cell.initialClassName) {
17280 cell.initialClassName = cell.dom.className;
17283 cell.dom.className = cell.initialClassName + ' ' + cell.className;
17288 for(; i < startingPos; i++) {
17289 textEls[i].innerHTML = (++prevStart);
17290 d.setDate(d.getDate()+1);
17292 cells[i].className = "fc-past fc-other-month";
17293 setCellClass(this, cells[i]);
17298 for(; i < days; i++){
17299 intDay = i - startingPos + 1;
17300 textEls[i].innerHTML = (intDay);
17301 d.setDate(d.getDate()+1);
17303 cells[i].className = ''; // "x-date-active";
17304 setCellClass(this, cells[i]);
17308 for(; i < 42; i++) {
17309 textEls[i].innerHTML = (++extraDays);
17310 d.setDate(d.getDate()+1);
17312 cells[i].className = "fc-future fc-other-month";
17313 setCellClass(this, cells[i]);
17316 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
17318 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
17320 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
17321 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
17323 if(totalRows != 6){
17324 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
17325 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
17328 this.fireEvent('monthchange', this, date);
17332 if(!this.internalRender){
17333 var main = this.el.dom.firstChild;
17334 var w = main.offsetWidth;
17335 this.el.setWidth(w + this.el.getBorderWidth("lr"));
17336 Roo.fly(main).setWidth(w);
17337 this.internalRender = true;
17338 // opera does not respect the auto grow header center column
17339 // then, after it gets a width opera refuses to recalculate
17340 // without a second pass
17341 if(Roo.isOpera && !this.secondPass){
17342 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
17343 this.secondPass = true;
17344 this.update.defer(10, this, [date]);
17351 findCell : function(dt) {
17352 dt = dt.clearTime().getTime();
17354 this.cells.each(function(c){
17355 //Roo.log("check " +c.dateValue + '?=' + dt);
17356 if(c.dateValue == dt){
17366 findCells : function(ev) {
17367 var s = ev.start.clone().clearTime().getTime();
17369 var e= ev.end.clone().clearTime().getTime();
17372 this.cells.each(function(c){
17373 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
17375 if(c.dateValue > e){
17378 if(c.dateValue < s){
17387 // findBestRow: function(cells)
17391 // for (var i =0 ; i < cells.length;i++) {
17392 // ret = Math.max(cells[i].rows || 0,ret);
17399 addItem : function(ev)
17401 // look for vertical location slot in
17402 var cells = this.findCells(ev);
17404 // ev.row = this.findBestRow(cells);
17406 // work out the location.
17410 for(var i =0; i < cells.length; i++) {
17412 cells[i].row = cells[0].row;
17415 cells[i].row = cells[i].row + 1;
17425 if (crow.start.getY() == cells[i].getY()) {
17427 crow.end = cells[i];
17444 cells[0].events.push(ev);
17446 this.calevents.push(ev);
17449 clearEvents: function() {
17451 if(!this.calevents){
17455 Roo.each(this.cells.elements, function(c){
17461 Roo.each(this.calevents, function(e) {
17462 Roo.each(e.els, function(el) {
17463 el.un('mouseenter' ,this.onEventEnter, this);
17464 el.un('mouseleave' ,this.onEventLeave, this);
17469 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
17475 renderEvents: function()
17479 this.cells.each(function(c) {
17488 if(c.row != c.events.length){
17489 r = 4 - (4 - (c.row - c.events.length));
17492 c.events = ev.slice(0, r);
17493 c.more = ev.slice(r);
17495 if(c.more.length && c.more.length == 1){
17496 c.events.push(c.more.pop());
17499 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
17503 this.cells.each(function(c) {
17505 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
17508 for (var e = 0; e < c.events.length; e++){
17509 var ev = c.events[e];
17510 var rows = ev.rows;
17512 for(var i = 0; i < rows.length; i++) {
17514 // how many rows should it span..
17517 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
17518 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
17520 unselectable : "on",
17523 cls: 'fc-event-inner',
17527 // cls: 'fc-event-time',
17528 // html : cells.length > 1 ? '' : ev.time
17532 cls: 'fc-event-title',
17533 html : String.format('{0}', ev.title)
17540 cls: 'ui-resizable-handle ui-resizable-e',
17541 html : '  '
17548 cfg.cls += ' fc-event-start';
17550 if ((i+1) == rows.length) {
17551 cfg.cls += ' fc-event-end';
17554 var ctr = _this.el.select('.fc-event-container',true).first();
17555 var cg = ctr.createChild(cfg);
17557 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
17558 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
17560 var r = (c.more.length) ? 1 : 0;
17561 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
17562 cg.setWidth(ebox.right - sbox.x -2);
17564 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
17565 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
17566 cg.on('click', _this.onEventClick, _this, ev);
17577 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
17578 style : 'position: absolute',
17579 unselectable : "on",
17582 cls: 'fc-event-inner',
17586 cls: 'fc-event-title',
17594 cls: 'ui-resizable-handle ui-resizable-e',
17595 html : '  '
17601 var ctr = _this.el.select('.fc-event-container',true).first();
17602 var cg = ctr.createChild(cfg);
17604 var sbox = c.select('.fc-day-content',true).first().getBox();
17605 var ebox = c.select('.fc-day-content',true).first().getBox();
17607 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
17608 cg.setWidth(ebox.right - sbox.x -2);
17610 cg.on('click', _this.onMoreEventClick, _this, c.more);
17620 onEventEnter: function (e, el,event,d) {
17621 this.fireEvent('evententer', this, el, event);
17624 onEventLeave: function (e, el,event,d) {
17625 this.fireEvent('eventleave', this, el, event);
17628 onEventClick: function (e, el,event,d) {
17629 this.fireEvent('eventclick', this, el, event);
17632 onMonthChange: function () {
17636 onMoreEventClick: function(e, el, more)
17640 this.calpopover.placement = 'right';
17641 this.calpopover.setTitle('More');
17643 this.calpopover.setContent('');
17645 var ctr = this.calpopover.el.select('.popover-content', true).first();
17647 Roo.each(more, function(m){
17649 cls : 'fc-event-hori fc-event-draggable',
17652 var cg = ctr.createChild(cfg);
17654 cg.on('click', _this.onEventClick, _this, m);
17657 this.calpopover.show(el);
17662 onLoad: function ()
17664 this.calevents = [];
17667 if(this.store.getCount() > 0){
17668 this.store.data.each(function(d){
17671 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
17672 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
17673 time : d.data.start_time,
17674 title : d.data.title,
17675 description : d.data.description,
17676 venue : d.data.venue
17681 this.renderEvents();
17683 if(this.calevents.length && this.loadMask){
17684 this.maskEl.hide();
17688 onBeforeLoad: function()
17690 this.clearEvents();
17692 this.maskEl.show();
17706 * @class Roo.bootstrap.Popover
17707 * @extends Roo.bootstrap.Component
17708 * Bootstrap Popover class
17709 * @cfg {String} html contents of the popover (or false to use children..)
17710 * @cfg {String} title of popover (or false to hide)
17711 * @cfg {String} placement how it is placed
17712 * @cfg {String} trigger click || hover (or false to trigger manually)
17713 * @cfg {String} over what (parent or false to trigger manually.)
17714 * @cfg {Number} delay - delay before showing
17717 * Create a new Popover
17718 * @param {Object} config The config object
17721 Roo.bootstrap.Popover = function(config){
17722 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
17728 * After the popover show
17730 * @param {Roo.bootstrap.Popover} this
17735 * After the popover hide
17737 * @param {Roo.bootstrap.Popover} this
17743 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
17745 title: 'Fill in a title',
17748 placement : 'right',
17749 trigger : 'hover', // hover
17755 can_build_overlaid : false,
17757 getChildContainer : function()
17759 return this.el.select('.popover-content',true).first();
17762 getAutoCreate : function(){
17765 cls : 'popover roo-dynamic',
17766 style: 'display:block',
17772 cls : 'popover-inner',
17776 cls: 'popover-title popover-header',
17780 cls : 'popover-content popover-body',
17791 setTitle: function(str)
17794 this.el.select('.popover-title',true).first().dom.innerHTML = str;
17796 setContent: function(str)
17799 this.el.select('.popover-content',true).first().dom.innerHTML = str;
17801 // as it get's added to the bottom of the page.
17802 onRender : function(ct, position)
17804 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17806 var cfg = Roo.apply({}, this.getAutoCreate());
17810 cfg.cls += ' ' + this.cls;
17813 cfg.style = this.style;
17815 //Roo.log("adding to ");
17816 this.el = Roo.get(document.body).createChild(cfg, position);
17817 // Roo.log(this.el);
17822 initEvents : function()
17824 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
17825 this.el.enableDisplayMode('block');
17827 if (this.over === false) {
17830 if (this.triggers === false) {
17833 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17834 var triggers = this.trigger ? this.trigger.split(' ') : [];
17835 Roo.each(triggers, function(trigger) {
17837 if (trigger == 'click') {
17838 on_el.on('click', this.toggle, this);
17839 } else if (trigger != 'manual') {
17840 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
17841 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
17843 on_el.on(eventIn ,this.enter, this);
17844 on_el.on(eventOut, this.leave, this);
17855 toggle : function () {
17856 this.hoverState == 'in' ? this.leave() : this.enter();
17859 enter : function () {
17861 clearTimeout(this.timeout);
17863 this.hoverState = 'in';
17865 if (!this.delay || !this.delay.show) {
17870 this.timeout = setTimeout(function () {
17871 if (_t.hoverState == 'in') {
17874 }, this.delay.show)
17877 leave : function() {
17878 clearTimeout(this.timeout);
17880 this.hoverState = 'out';
17882 if (!this.delay || !this.delay.hide) {
17887 this.timeout = setTimeout(function () {
17888 if (_t.hoverState == 'out') {
17891 }, this.delay.hide)
17894 show : function (on_el)
17897 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17901 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
17902 if (this.html !== false) {
17903 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
17905 this.el.removeClass([
17906 'fade','top','bottom', 'left', 'right','in',
17907 'bs-popover-top','bs-popover-bottom', 'bs-popover-left', 'bs-popover-right'
17909 if (!this.title.length) {
17910 this.el.select('.popover-title',true).hide();
17913 var placement = typeof this.placement == 'function' ?
17914 this.placement.call(this, this.el, on_el) :
17917 var autoToken = /\s?auto?\s?/i;
17918 var autoPlace = autoToken.test(placement);
17920 placement = placement.replace(autoToken, '') || 'top';
17924 //this.el.setXY([0,0]);
17926 this.el.dom.style.display='block';
17927 this.el.addClass(placement);
17929 //this.el.appendTo(on_el);
17931 var p = this.getPosition();
17932 var box = this.el.getBox();
17937 var align = Roo.bootstrap.Popover.alignment[placement];
17940 this.el.alignTo(on_el, align[0],align[1]);
17941 //var arrow = this.el.select('.arrow',true).first();
17942 //arrow.set(align[2],
17944 this.el.addClass('in');
17947 if (this.el.hasClass('fade')) {
17951 this.hoverState = 'in';
17953 this.fireEvent('show', this);
17958 this.el.setXY([0,0]);
17959 this.el.removeClass('in');
17961 this.hoverState = null;
17963 this.fireEvent('hide', this);
17968 Roo.bootstrap.Popover.alignment = {
17969 'left' : ['r-l', [-10,0], 'right bs-popover-right'],
17970 'right' : ['l-r', [10,0], 'left bs-popover-left'],
17971 'bottom' : ['t-b', [0,10], 'top bs-popover-top'],
17972 'top' : [ 'b-t', [0,-10], 'bottom bs-popover-bottom']
17983 * @class Roo.bootstrap.Progress
17984 * @extends Roo.bootstrap.Component
17985 * Bootstrap Progress class
17986 * @cfg {Boolean} striped striped of the progress bar
17987 * @cfg {Boolean} active animated of the progress bar
17991 * Create a new Progress
17992 * @param {Object} config The config object
17995 Roo.bootstrap.Progress = function(config){
17996 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
17999 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
18004 getAutoCreate : function(){
18012 cfg.cls += ' progress-striped';
18016 cfg.cls += ' active';
18035 * @class Roo.bootstrap.ProgressBar
18036 * @extends Roo.bootstrap.Component
18037 * Bootstrap ProgressBar class
18038 * @cfg {Number} aria_valuenow aria-value now
18039 * @cfg {Number} aria_valuemin aria-value min
18040 * @cfg {Number} aria_valuemax aria-value max
18041 * @cfg {String} label label for the progress bar
18042 * @cfg {String} panel (success | info | warning | danger )
18043 * @cfg {String} role role of the progress bar
18044 * @cfg {String} sr_only text
18048 * Create a new ProgressBar
18049 * @param {Object} config The config object
18052 Roo.bootstrap.ProgressBar = function(config){
18053 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
18056 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
18060 aria_valuemax : 100,
18066 getAutoCreate : function()
18071 cls: 'progress-bar',
18072 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
18084 cfg.role = this.role;
18087 if(this.aria_valuenow){
18088 cfg['aria-valuenow'] = this.aria_valuenow;
18091 if(this.aria_valuemin){
18092 cfg['aria-valuemin'] = this.aria_valuemin;
18095 if(this.aria_valuemax){
18096 cfg['aria-valuemax'] = this.aria_valuemax;
18099 if(this.label && !this.sr_only){
18100 cfg.html = this.label;
18104 cfg.cls += ' progress-bar-' + this.panel;
18110 update : function(aria_valuenow)
18112 this.aria_valuenow = aria_valuenow;
18114 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
18129 * @class Roo.bootstrap.TabGroup
18130 * @extends Roo.bootstrap.Column
18131 * Bootstrap Column class
18132 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
18133 * @cfg {Boolean} carousel true to make the group behave like a carousel
18134 * @cfg {Boolean} bullets show bullets for the panels
18135 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
18136 * @cfg {Number} timer auto slide timer .. default 0 millisecond
18137 * @cfg {Boolean} showarrow (true|false) show arrow default true
18140 * Create a new TabGroup
18141 * @param {Object} config The config object
18144 Roo.bootstrap.TabGroup = function(config){
18145 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
18147 this.navId = Roo.id();
18150 Roo.bootstrap.TabGroup.register(this);
18154 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
18157 transition : false,
18162 slideOnTouch : false,
18165 getAutoCreate : function()
18167 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
18169 cfg.cls += ' tab-content';
18171 if (this.carousel) {
18172 cfg.cls += ' carousel slide';
18175 cls : 'carousel-inner',
18179 if(this.bullets && !Roo.isTouch){
18182 cls : 'carousel-bullets',
18186 if(this.bullets_cls){
18187 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
18194 cfg.cn[0].cn.push(bullets);
18197 if(this.showarrow){
18198 cfg.cn[0].cn.push({
18200 class : 'carousel-arrow',
18204 class : 'carousel-prev',
18208 class : 'fa fa-chevron-left'
18214 class : 'carousel-next',
18218 class : 'fa fa-chevron-right'
18231 initEvents: function()
18233 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
18234 // this.el.on("touchstart", this.onTouchStart, this);
18237 if(this.autoslide){
18240 this.slideFn = window.setInterval(function() {
18241 _this.showPanelNext();
18245 if(this.showarrow){
18246 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
18247 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
18253 // onTouchStart : function(e, el, o)
18255 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
18259 // this.showPanelNext();
18263 getChildContainer : function()
18265 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
18269 * register a Navigation item
18270 * @param {Roo.bootstrap.NavItem} the navitem to add
18272 register : function(item)
18274 this.tabs.push( item);
18275 item.navId = this.navId; // not really needed..
18280 getActivePanel : function()
18283 Roo.each(this.tabs, function(t) {
18293 getPanelByName : function(n)
18296 Roo.each(this.tabs, function(t) {
18297 if (t.tabId == n) {
18305 indexOfPanel : function(p)
18308 Roo.each(this.tabs, function(t,i) {
18309 if (t.tabId == p.tabId) {
18318 * show a specific panel
18319 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
18320 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
18322 showPanel : function (pan)
18324 if(this.transition || typeof(pan) == 'undefined'){
18325 Roo.log("waiting for the transitionend");
18329 if (typeof(pan) == 'number') {
18330 pan = this.tabs[pan];
18333 if (typeof(pan) == 'string') {
18334 pan = this.getPanelByName(pan);
18337 var cur = this.getActivePanel();
18340 Roo.log('pan or acitve pan is undefined');
18344 if (pan.tabId == this.getActivePanel().tabId) {
18348 if (false === cur.fireEvent('beforedeactivate')) {
18352 if(this.bullets > 0 && !Roo.isTouch){
18353 this.setActiveBullet(this.indexOfPanel(pan));
18356 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
18358 this.transition = true;
18359 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
18360 var lr = dir == 'next' ? 'left' : 'right';
18361 pan.el.addClass(dir); // or prev
18362 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
18363 cur.el.addClass(lr); // or right
18364 pan.el.addClass(lr);
18367 cur.el.on('transitionend', function() {
18368 Roo.log("trans end?");
18370 pan.el.removeClass([lr,dir]);
18371 pan.setActive(true);
18373 cur.el.removeClass([lr]);
18374 cur.setActive(false);
18376 _this.transition = false;
18378 }, this, { single: true } );
18383 cur.setActive(false);
18384 pan.setActive(true);
18389 showPanelNext : function()
18391 var i = this.indexOfPanel(this.getActivePanel());
18393 if (i >= this.tabs.length - 1 && !this.autoslide) {
18397 if (i >= this.tabs.length - 1 && this.autoslide) {
18401 this.showPanel(this.tabs[i+1]);
18404 showPanelPrev : function()
18406 var i = this.indexOfPanel(this.getActivePanel());
18408 if (i < 1 && !this.autoslide) {
18412 if (i < 1 && this.autoslide) {
18413 i = this.tabs.length;
18416 this.showPanel(this.tabs[i-1]);
18420 addBullet: function()
18422 if(!this.bullets || Roo.isTouch){
18425 var ctr = this.el.select('.carousel-bullets',true).first();
18426 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
18427 var bullet = ctr.createChild({
18428 cls : 'bullet bullet-' + i
18429 },ctr.dom.lastChild);
18434 bullet.on('click', (function(e, el, o, ii, t){
18436 e.preventDefault();
18438 this.showPanel(ii);
18440 if(this.autoslide && this.slideFn){
18441 clearInterval(this.slideFn);
18442 this.slideFn = window.setInterval(function() {
18443 _this.showPanelNext();
18447 }).createDelegate(this, [i, bullet], true));
18452 setActiveBullet : function(i)
18458 Roo.each(this.el.select('.bullet', true).elements, function(el){
18459 el.removeClass('selected');
18462 var bullet = this.el.select('.bullet-' + i, true).first();
18468 bullet.addClass('selected');
18479 Roo.apply(Roo.bootstrap.TabGroup, {
18483 * register a Navigation Group
18484 * @param {Roo.bootstrap.NavGroup} the navgroup to add
18486 register : function(navgrp)
18488 this.groups[navgrp.navId] = navgrp;
18492 * fetch a Navigation Group based on the navigation ID
18493 * if one does not exist , it will get created.
18494 * @param {string} the navgroup to add
18495 * @returns {Roo.bootstrap.NavGroup} the navgroup
18497 get: function(navId) {
18498 if (typeof(this.groups[navId]) == 'undefined') {
18499 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
18501 return this.groups[navId] ;
18516 * @class Roo.bootstrap.TabPanel
18517 * @extends Roo.bootstrap.Component
18518 * Bootstrap TabPanel class
18519 * @cfg {Boolean} active panel active
18520 * @cfg {String} html panel content
18521 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
18522 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
18523 * @cfg {String} href click to link..
18527 * Create a new TabPanel
18528 * @param {Object} config The config object
18531 Roo.bootstrap.TabPanel = function(config){
18532 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
18536 * Fires when the active status changes
18537 * @param {Roo.bootstrap.TabPanel} this
18538 * @param {Boolean} state the new state
18543 * @event beforedeactivate
18544 * Fires before a tab is de-activated - can be used to do validation on a form.
18545 * @param {Roo.bootstrap.TabPanel} this
18546 * @return {Boolean} false if there is an error
18549 'beforedeactivate': true
18552 this.tabId = this.tabId || Roo.id();
18556 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
18564 getAutoCreate : function(){
18567 // item is needed for carousel - not sure if it has any effect otherwise
18568 cls: 'tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
18569 html: this.html || ''
18573 cfg.cls += ' active';
18577 cfg.tabId = this.tabId;
18584 initEvents: function()
18586 var p = this.parent();
18588 this.navId = this.navId || p.navId;
18590 if (typeof(this.navId) != 'undefined') {
18591 // not really needed.. but just in case.. parent should be a NavGroup.
18592 var tg = Roo.bootstrap.TabGroup.get(this.navId);
18596 var i = tg.tabs.length - 1;
18598 if(this.active && tg.bullets > 0 && i < tg.bullets){
18599 tg.setActiveBullet(i);
18603 this.el.on('click', this.onClick, this);
18606 this.el.on("touchstart", this.onTouchStart, this);
18607 this.el.on("touchmove", this.onTouchMove, this);
18608 this.el.on("touchend", this.onTouchEnd, this);
18613 onRender : function(ct, position)
18615 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
18618 setActive : function(state)
18620 Roo.log("panel - set active " + this.tabId + "=" + state);
18622 this.active = state;
18624 this.el.removeClass('active');
18626 } else if (!this.el.hasClass('active')) {
18627 this.el.addClass('active');
18630 this.fireEvent('changed', this, state);
18633 onClick : function(e)
18635 e.preventDefault();
18637 if(!this.href.length){
18641 window.location.href = this.href;
18650 onTouchStart : function(e)
18652 this.swiping = false;
18654 this.startX = e.browserEvent.touches[0].clientX;
18655 this.startY = e.browserEvent.touches[0].clientY;
18658 onTouchMove : function(e)
18660 this.swiping = true;
18662 this.endX = e.browserEvent.touches[0].clientX;
18663 this.endY = e.browserEvent.touches[0].clientY;
18666 onTouchEnd : function(e)
18673 var tabGroup = this.parent();
18675 if(this.endX > this.startX){ // swiping right
18676 tabGroup.showPanelPrev();
18680 if(this.startX > this.endX){ // swiping left
18681 tabGroup.showPanelNext();
18700 * @class Roo.bootstrap.DateField
18701 * @extends Roo.bootstrap.Input
18702 * Bootstrap DateField class
18703 * @cfg {Number} weekStart default 0
18704 * @cfg {String} viewMode default empty, (months|years)
18705 * @cfg {String} minViewMode default empty, (months|years)
18706 * @cfg {Number} startDate default -Infinity
18707 * @cfg {Number} endDate default Infinity
18708 * @cfg {Boolean} todayHighlight default false
18709 * @cfg {Boolean} todayBtn default false
18710 * @cfg {Boolean} calendarWeeks default false
18711 * @cfg {Object} daysOfWeekDisabled default empty
18712 * @cfg {Boolean} singleMode default false (true | false)
18714 * @cfg {Boolean} keyboardNavigation default true
18715 * @cfg {String} language default en
18718 * Create a new DateField
18719 * @param {Object} config The config object
18722 Roo.bootstrap.DateField = function(config){
18723 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
18727 * Fires when this field show.
18728 * @param {Roo.bootstrap.DateField} this
18729 * @param {Mixed} date The date value
18734 * Fires when this field hide.
18735 * @param {Roo.bootstrap.DateField} this
18736 * @param {Mixed} date The date value
18741 * Fires when select a date.
18742 * @param {Roo.bootstrap.DateField} this
18743 * @param {Mixed} date The date value
18747 * @event beforeselect
18748 * Fires when before select a date.
18749 * @param {Roo.bootstrap.DateField} this
18750 * @param {Mixed} date The date value
18752 beforeselect : true
18756 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
18759 * @cfg {String} format
18760 * The default date format string which can be overriden for localization support. The format must be
18761 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
18765 * @cfg {String} altFormats
18766 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
18767 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
18769 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
18777 todayHighlight : false,
18783 keyboardNavigation: true,
18785 calendarWeeks: false,
18787 startDate: -Infinity,
18791 daysOfWeekDisabled: [],
18795 singleMode : false,
18797 UTCDate: function()
18799 return new Date(Date.UTC.apply(Date, arguments));
18802 UTCToday: function()
18804 var today = new Date();
18805 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
18808 getDate: function() {
18809 var d = this.getUTCDate();
18810 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
18813 getUTCDate: function() {
18817 setDate: function(d) {
18818 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
18821 setUTCDate: function(d) {
18823 this.setValue(this.formatDate(this.date));
18826 onRender: function(ct, position)
18829 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
18831 this.language = this.language || 'en';
18832 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
18833 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
18835 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
18836 this.format = this.format || 'm/d/y';
18837 this.isInline = false;
18838 this.isInput = true;
18839 this.component = this.el.select('.add-on', true).first() || false;
18840 this.component = (this.component && this.component.length === 0) ? false : this.component;
18841 this.hasInput = this.component && this.inputEl().length;
18843 if (typeof(this.minViewMode === 'string')) {
18844 switch (this.minViewMode) {
18846 this.minViewMode = 1;
18849 this.minViewMode = 2;
18852 this.minViewMode = 0;
18857 if (typeof(this.viewMode === 'string')) {
18858 switch (this.viewMode) {
18871 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
18873 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
18875 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18877 this.picker().on('mousedown', this.onMousedown, this);
18878 this.picker().on('click', this.onClick, this);
18880 this.picker().addClass('datepicker-dropdown');
18882 this.startViewMode = this.viewMode;
18884 if(this.singleMode){
18885 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
18886 v.setVisibilityMode(Roo.Element.DISPLAY);
18890 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
18891 v.setStyle('width', '189px');
18895 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
18896 if(!this.calendarWeeks){
18901 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18902 v.attr('colspan', function(i, val){
18903 return parseInt(val) + 1;
18908 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
18910 this.setStartDate(this.startDate);
18911 this.setEndDate(this.endDate);
18913 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
18920 if(this.isInline) {
18925 picker : function()
18927 return this.pickerEl;
18928 // return this.el.select('.datepicker', true).first();
18931 fillDow: function()
18933 var dowCnt = this.weekStart;
18942 if(this.calendarWeeks){
18950 while (dowCnt < this.weekStart + 7) {
18954 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
18958 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
18961 fillMonths: function()
18964 var months = this.picker().select('>.datepicker-months td', true).first();
18966 months.dom.innerHTML = '';
18972 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
18975 months.createChild(month);
18982 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;
18984 if (this.date < this.startDate) {
18985 this.viewDate = new Date(this.startDate);
18986 } else if (this.date > this.endDate) {
18987 this.viewDate = new Date(this.endDate);
18989 this.viewDate = new Date(this.date);
18997 var d = new Date(this.viewDate),
18998 year = d.getUTCFullYear(),
18999 month = d.getUTCMonth(),
19000 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
19001 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
19002 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
19003 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
19004 currentDate = this.date && this.date.valueOf(),
19005 today = this.UTCToday();
19007 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
19009 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
19011 // this.picker.select('>tfoot th.today').
19012 // .text(dates[this.language].today)
19013 // .toggle(this.todayBtn !== false);
19015 this.updateNavArrows();
19018 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
19020 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
19022 prevMonth.setUTCDate(day);
19024 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
19026 var nextMonth = new Date(prevMonth);
19028 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
19030 nextMonth = nextMonth.valueOf();
19032 var fillMonths = false;
19034 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
19036 while(prevMonth.valueOf() <= nextMonth) {
19039 if (prevMonth.getUTCDay() === this.weekStart) {
19041 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
19049 if(this.calendarWeeks){
19050 // ISO 8601: First week contains first thursday.
19051 // ISO also states week starts on Monday, but we can be more abstract here.
19053 // Start of current week: based on weekstart/current date
19054 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
19055 // Thursday of this week
19056 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
19057 // First Thursday of year, year from thursday
19058 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
19059 // Calendar week: ms between thursdays, div ms per day, div 7 days
19060 calWeek = (th - yth) / 864e5 / 7 + 1;
19062 fillMonths.cn.push({
19070 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
19072 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
19075 if (this.todayHighlight &&
19076 prevMonth.getUTCFullYear() == today.getFullYear() &&
19077 prevMonth.getUTCMonth() == today.getMonth() &&
19078 prevMonth.getUTCDate() == today.getDate()) {
19079 clsName += ' today';
19082 if (currentDate && prevMonth.valueOf() === currentDate) {
19083 clsName += ' active';
19086 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
19087 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
19088 clsName += ' disabled';
19091 fillMonths.cn.push({
19093 cls: 'day ' + clsName,
19094 html: prevMonth.getDate()
19097 prevMonth.setDate(prevMonth.getDate()+1);
19100 var currentYear = this.date && this.date.getUTCFullYear();
19101 var currentMonth = this.date && this.date.getUTCMonth();
19103 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
19105 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
19106 v.removeClass('active');
19108 if(currentYear === year && k === currentMonth){
19109 v.addClass('active');
19112 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
19113 v.addClass('disabled');
19119 year = parseInt(year/10, 10) * 10;
19121 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
19123 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
19126 for (var i = -1; i < 11; i++) {
19127 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
19129 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
19137 showMode: function(dir)
19140 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
19143 Roo.each(this.picker().select('>div',true).elements, function(v){
19144 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19147 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
19152 if(this.isInline) {
19156 this.picker().removeClass(['bottom', 'top']);
19158 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
19160 * place to the top of element!
19164 this.picker().addClass('top');
19165 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
19170 this.picker().addClass('bottom');
19172 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
19175 parseDate : function(value)
19177 if(!value || value instanceof Date){
19180 var v = Date.parseDate(value, this.format);
19181 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
19182 v = Date.parseDate(value, 'Y-m-d');
19184 if(!v && this.altFormats){
19185 if(!this.altFormatsArray){
19186 this.altFormatsArray = this.altFormats.split("|");
19188 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
19189 v = Date.parseDate(value, this.altFormatsArray[i]);
19195 formatDate : function(date, fmt)
19197 return (!date || !(date instanceof Date)) ?
19198 date : date.dateFormat(fmt || this.format);
19201 onFocus : function()
19203 Roo.bootstrap.DateField.superclass.onFocus.call(this);
19207 onBlur : function()
19209 Roo.bootstrap.DateField.superclass.onBlur.call(this);
19211 var d = this.inputEl().getValue();
19218 showPopup : function()
19220 this.picker().show();
19224 this.fireEvent('showpopup', this, this.date);
19227 hidePopup : function()
19229 if(this.isInline) {
19232 this.picker().hide();
19233 this.viewMode = this.startViewMode;
19236 this.fireEvent('hidepopup', this, this.date);
19240 onMousedown: function(e)
19242 e.stopPropagation();
19243 e.preventDefault();
19248 Roo.bootstrap.DateField.superclass.keyup.call(this);
19252 setValue: function(v)
19254 if(this.fireEvent('beforeselect', this, v) !== false){
19255 var d = new Date(this.parseDate(v) ).clearTime();
19257 if(isNaN(d.getTime())){
19258 this.date = this.viewDate = '';
19259 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
19263 v = this.formatDate(d);
19265 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
19267 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
19271 this.fireEvent('select', this, this.date);
19275 getValue: function()
19277 return this.formatDate(this.date);
19280 fireKey: function(e)
19282 if (!this.picker().isVisible()){
19283 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19289 var dateChanged = false,
19291 newDate, newViewDate;
19296 e.preventDefault();
19300 if (!this.keyboardNavigation) {
19303 dir = e.keyCode == 37 ? -1 : 1;
19306 newDate = this.moveYear(this.date, dir);
19307 newViewDate = this.moveYear(this.viewDate, dir);
19308 } else if (e.shiftKey){
19309 newDate = this.moveMonth(this.date, dir);
19310 newViewDate = this.moveMonth(this.viewDate, dir);
19312 newDate = new Date(this.date);
19313 newDate.setUTCDate(this.date.getUTCDate() + dir);
19314 newViewDate = new Date(this.viewDate);
19315 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
19317 if (this.dateWithinRange(newDate)){
19318 this.date = newDate;
19319 this.viewDate = newViewDate;
19320 this.setValue(this.formatDate(this.date));
19322 e.preventDefault();
19323 dateChanged = true;
19328 if (!this.keyboardNavigation) {
19331 dir = e.keyCode == 38 ? -1 : 1;
19333 newDate = this.moveYear(this.date, dir);
19334 newViewDate = this.moveYear(this.viewDate, dir);
19335 } else if (e.shiftKey){
19336 newDate = this.moveMonth(this.date, dir);
19337 newViewDate = this.moveMonth(this.viewDate, dir);
19339 newDate = new Date(this.date);
19340 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
19341 newViewDate = new Date(this.viewDate);
19342 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
19344 if (this.dateWithinRange(newDate)){
19345 this.date = newDate;
19346 this.viewDate = newViewDate;
19347 this.setValue(this.formatDate(this.date));
19349 e.preventDefault();
19350 dateChanged = true;
19354 this.setValue(this.formatDate(this.date));
19356 e.preventDefault();
19359 this.setValue(this.formatDate(this.date));
19373 onClick: function(e)
19375 e.stopPropagation();
19376 e.preventDefault();
19378 var target = e.getTarget();
19380 if(target.nodeName.toLowerCase() === 'i'){
19381 target = Roo.get(target).dom.parentNode;
19384 var nodeName = target.nodeName;
19385 var className = target.className;
19386 var html = target.innerHTML;
19387 //Roo.log(nodeName);
19389 switch(nodeName.toLowerCase()) {
19391 switch(className) {
19397 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
19398 switch(this.viewMode){
19400 this.viewDate = this.moveMonth(this.viewDate, dir);
19404 this.viewDate = this.moveYear(this.viewDate, dir);
19410 var date = new Date();
19411 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
19413 this.setValue(this.formatDate(this.date));
19420 if (className.indexOf('disabled') < 0) {
19421 this.viewDate.setUTCDate(1);
19422 if (className.indexOf('month') > -1) {
19423 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
19425 var year = parseInt(html, 10) || 0;
19426 this.viewDate.setUTCFullYear(year);
19430 if(this.singleMode){
19431 this.setValue(this.formatDate(this.viewDate));
19442 //Roo.log(className);
19443 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
19444 var day = parseInt(html, 10) || 1;
19445 var year = this.viewDate.getUTCFullYear(),
19446 month = this.viewDate.getUTCMonth();
19448 if (className.indexOf('old') > -1) {
19455 } else if (className.indexOf('new') > -1) {
19463 //Roo.log([year,month,day]);
19464 this.date = this.UTCDate(year, month, day,0,0,0,0);
19465 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
19467 //Roo.log(this.formatDate(this.date));
19468 this.setValue(this.formatDate(this.date));
19475 setStartDate: function(startDate)
19477 this.startDate = startDate || -Infinity;
19478 if (this.startDate !== -Infinity) {
19479 this.startDate = this.parseDate(this.startDate);
19482 this.updateNavArrows();
19485 setEndDate: function(endDate)
19487 this.endDate = endDate || Infinity;
19488 if (this.endDate !== Infinity) {
19489 this.endDate = this.parseDate(this.endDate);
19492 this.updateNavArrows();
19495 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
19497 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
19498 if (typeof(this.daysOfWeekDisabled) !== 'object') {
19499 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
19501 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
19502 return parseInt(d, 10);
19505 this.updateNavArrows();
19508 updateNavArrows: function()
19510 if(this.singleMode){
19514 var d = new Date(this.viewDate),
19515 year = d.getUTCFullYear(),
19516 month = d.getUTCMonth();
19518 Roo.each(this.picker().select('.prev', true).elements, function(v){
19520 switch (this.viewMode) {
19523 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
19529 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
19536 Roo.each(this.picker().select('.next', true).elements, function(v){
19538 switch (this.viewMode) {
19541 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
19547 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
19555 moveMonth: function(date, dir)
19560 var new_date = new Date(date.valueOf()),
19561 day = new_date.getUTCDate(),
19562 month = new_date.getUTCMonth(),
19563 mag = Math.abs(dir),
19565 dir = dir > 0 ? 1 : -1;
19568 // If going back one month, make sure month is not current month
19569 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
19571 return new_date.getUTCMonth() == month;
19573 // If going forward one month, make sure month is as expected
19574 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
19576 return new_date.getUTCMonth() != new_month;
19578 new_month = month + dir;
19579 new_date.setUTCMonth(new_month);
19580 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
19581 if (new_month < 0 || new_month > 11) {
19582 new_month = (new_month + 12) % 12;
19585 // For magnitudes >1, move one month at a time...
19586 for (var i=0; i<mag; i++) {
19587 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
19588 new_date = this.moveMonth(new_date, dir);
19590 // ...then reset the day, keeping it in the new month
19591 new_month = new_date.getUTCMonth();
19592 new_date.setUTCDate(day);
19594 return new_month != new_date.getUTCMonth();
19597 // Common date-resetting loop -- if date is beyond end of month, make it
19600 new_date.setUTCDate(--day);
19601 new_date.setUTCMonth(new_month);
19606 moveYear: function(date, dir)
19608 return this.moveMonth(date, dir*12);
19611 dateWithinRange: function(date)
19613 return date >= this.startDate && date <= this.endDate;
19619 this.picker().remove();
19622 validateValue : function(value)
19624 if(this.getVisibilityEl().hasClass('hidden')){
19628 if(value.length < 1) {
19629 if(this.allowBlank){
19635 if(value.length < this.minLength){
19638 if(value.length > this.maxLength){
19642 var vt = Roo.form.VTypes;
19643 if(!vt[this.vtype](value, this)){
19647 if(typeof this.validator == "function"){
19648 var msg = this.validator(value);
19654 if(this.regex && !this.regex.test(value)){
19658 if(typeof(this.parseDate(value)) == 'undefined'){
19662 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
19666 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
19676 this.date = this.viewDate = '';
19678 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
19683 Roo.apply(Roo.bootstrap.DateField, {
19694 html: '<i class="fa fa-arrow-left"/>'
19704 html: '<i class="fa fa-arrow-right"/>'
19746 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
19747 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
19748 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
19749 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19750 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
19763 navFnc: 'FullYear',
19768 navFnc: 'FullYear',
19773 Roo.apply(Roo.bootstrap.DateField, {
19777 cls: 'datepicker dropdown-menu roo-dynamic',
19781 cls: 'datepicker-days',
19785 cls: 'table-condensed',
19787 Roo.bootstrap.DateField.head,
19791 Roo.bootstrap.DateField.footer
19798 cls: 'datepicker-months',
19802 cls: 'table-condensed',
19804 Roo.bootstrap.DateField.head,
19805 Roo.bootstrap.DateField.content,
19806 Roo.bootstrap.DateField.footer
19813 cls: 'datepicker-years',
19817 cls: 'table-condensed',
19819 Roo.bootstrap.DateField.head,
19820 Roo.bootstrap.DateField.content,
19821 Roo.bootstrap.DateField.footer
19840 * @class Roo.bootstrap.TimeField
19841 * @extends Roo.bootstrap.Input
19842 * Bootstrap DateField class
19846 * Create a new TimeField
19847 * @param {Object} config The config object
19850 Roo.bootstrap.TimeField = function(config){
19851 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
19855 * Fires when this field show.
19856 * @param {Roo.bootstrap.DateField} thisthis
19857 * @param {Mixed} date The date value
19862 * Fires when this field hide.
19863 * @param {Roo.bootstrap.DateField} this
19864 * @param {Mixed} date The date value
19869 * Fires when select a date.
19870 * @param {Roo.bootstrap.DateField} this
19871 * @param {Mixed} date The date value
19877 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
19880 * @cfg {String} format
19881 * The default time format string which can be overriden for localization support. The format must be
19882 * valid according to {@link Date#parseDate} (defaults to 'H:i').
19886 onRender: function(ct, position)
19889 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
19891 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
19893 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19895 this.pop = this.picker().select('>.datepicker-time',true).first();
19896 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19898 this.picker().on('mousedown', this.onMousedown, this);
19899 this.picker().on('click', this.onClick, this);
19901 this.picker().addClass('datepicker-dropdown');
19906 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
19907 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
19908 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
19909 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
19910 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
19911 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
19915 fireKey: function(e){
19916 if (!this.picker().isVisible()){
19917 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19923 e.preventDefault();
19931 this.onTogglePeriod();
19934 this.onIncrementMinutes();
19937 this.onDecrementMinutes();
19946 onClick: function(e) {
19947 e.stopPropagation();
19948 e.preventDefault();
19951 picker : function()
19953 return this.el.select('.datepicker', true).first();
19956 fillTime: function()
19958 var time = this.pop.select('tbody', true).first();
19960 time.dom.innerHTML = '';
19975 cls: 'hours-up glyphicon glyphicon-chevron-up'
19995 cls: 'minutes-up glyphicon glyphicon-chevron-up'
20016 cls: 'timepicker-hour',
20031 cls: 'timepicker-minute',
20046 cls: 'btn btn-primary period',
20068 cls: 'hours-down glyphicon glyphicon-chevron-down'
20088 cls: 'minutes-down glyphicon glyphicon-chevron-down'
20106 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
20113 var hours = this.time.getHours();
20114 var minutes = this.time.getMinutes();
20127 hours = hours - 12;
20131 hours = '0' + hours;
20135 minutes = '0' + minutes;
20138 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
20139 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
20140 this.pop.select('button', true).first().dom.innerHTML = period;
20146 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
20148 var cls = ['bottom'];
20150 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
20157 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
20162 this.picker().addClass(cls.join('-'));
20166 Roo.each(cls, function(c){
20168 _this.picker().setTop(_this.inputEl().getHeight());
20172 _this.picker().setTop(0 - _this.picker().getHeight());
20177 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
20181 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
20188 onFocus : function()
20190 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
20194 onBlur : function()
20196 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
20202 this.picker().show();
20207 this.fireEvent('show', this, this.date);
20212 this.picker().hide();
20215 this.fireEvent('hide', this, this.date);
20218 setTime : function()
20221 this.setValue(this.time.format(this.format));
20223 this.fireEvent('select', this, this.date);
20228 onMousedown: function(e){
20229 e.stopPropagation();
20230 e.preventDefault();
20233 onIncrementHours: function()
20235 Roo.log('onIncrementHours');
20236 this.time = this.time.add(Date.HOUR, 1);
20241 onDecrementHours: function()
20243 Roo.log('onDecrementHours');
20244 this.time = this.time.add(Date.HOUR, -1);
20248 onIncrementMinutes: function()
20250 Roo.log('onIncrementMinutes');
20251 this.time = this.time.add(Date.MINUTE, 1);
20255 onDecrementMinutes: function()
20257 Roo.log('onDecrementMinutes');
20258 this.time = this.time.add(Date.MINUTE, -1);
20262 onTogglePeriod: function()
20264 Roo.log('onTogglePeriod');
20265 this.time = this.time.add(Date.HOUR, 12);
20272 Roo.apply(Roo.bootstrap.TimeField, {
20302 cls: 'btn btn-info ok',
20314 Roo.apply(Roo.bootstrap.TimeField, {
20318 cls: 'datepicker dropdown-menu',
20322 cls: 'datepicker-time',
20326 cls: 'table-condensed',
20328 Roo.bootstrap.TimeField.content,
20329 Roo.bootstrap.TimeField.footer
20348 * @class Roo.bootstrap.MonthField
20349 * @extends Roo.bootstrap.Input
20350 * Bootstrap MonthField class
20352 * @cfg {String} language default en
20355 * Create a new MonthField
20356 * @param {Object} config The config object
20359 Roo.bootstrap.MonthField = function(config){
20360 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
20365 * Fires when this field show.
20366 * @param {Roo.bootstrap.MonthField} this
20367 * @param {Mixed} date The date value
20372 * Fires when this field hide.
20373 * @param {Roo.bootstrap.MonthField} this
20374 * @param {Mixed} date The date value
20379 * Fires when select a date.
20380 * @param {Roo.bootstrap.MonthField} this
20381 * @param {String} oldvalue The old value
20382 * @param {String} newvalue The new value
20388 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
20390 onRender: function(ct, position)
20393 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
20395 this.language = this.language || 'en';
20396 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
20397 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
20399 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
20400 this.isInline = false;
20401 this.isInput = true;
20402 this.component = this.el.select('.add-on', true).first() || false;
20403 this.component = (this.component && this.component.length === 0) ? false : this.component;
20404 this.hasInput = this.component && this.inputEL().length;
20406 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
20408 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
20410 this.picker().on('mousedown', this.onMousedown, this);
20411 this.picker().on('click', this.onClick, this);
20413 this.picker().addClass('datepicker-dropdown');
20415 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
20416 v.setStyle('width', '189px');
20423 if(this.isInline) {
20429 setValue: function(v, suppressEvent)
20431 var o = this.getValue();
20433 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
20437 if(suppressEvent !== true){
20438 this.fireEvent('select', this, o, v);
20443 getValue: function()
20448 onClick: function(e)
20450 e.stopPropagation();
20451 e.preventDefault();
20453 var target = e.getTarget();
20455 if(target.nodeName.toLowerCase() === 'i'){
20456 target = Roo.get(target).dom.parentNode;
20459 var nodeName = target.nodeName;
20460 var className = target.className;
20461 var html = target.innerHTML;
20463 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
20467 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
20469 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20475 picker : function()
20477 return this.pickerEl;
20480 fillMonths: function()
20483 var months = this.picker().select('>.datepicker-months td', true).first();
20485 months.dom.innerHTML = '';
20491 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
20494 months.createChild(month);
20503 if(typeof(this.vIndex) == 'undefined' && this.value.length){
20504 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
20507 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
20508 e.removeClass('active');
20510 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
20511 e.addClass('active');
20518 if(this.isInline) {
20522 this.picker().removeClass(['bottom', 'top']);
20524 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
20526 * place to the top of element!
20530 this.picker().addClass('top');
20531 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
20536 this.picker().addClass('bottom');
20538 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
20541 onFocus : function()
20543 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
20547 onBlur : function()
20549 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
20551 var d = this.inputEl().getValue();
20560 this.picker().show();
20561 this.picker().select('>.datepicker-months', true).first().show();
20565 this.fireEvent('show', this, this.date);
20570 if(this.isInline) {
20573 this.picker().hide();
20574 this.fireEvent('hide', this, this.date);
20578 onMousedown: function(e)
20580 e.stopPropagation();
20581 e.preventDefault();
20586 Roo.bootstrap.MonthField.superclass.keyup.call(this);
20590 fireKey: function(e)
20592 if (!this.picker().isVisible()){
20593 if (e.keyCode == 27) {// allow escape to hide and re-show picker
20604 e.preventDefault();
20608 dir = e.keyCode == 37 ? -1 : 1;
20610 this.vIndex = this.vIndex + dir;
20612 if(this.vIndex < 0){
20616 if(this.vIndex > 11){
20620 if(isNaN(this.vIndex)){
20624 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20630 dir = e.keyCode == 38 ? -1 : 1;
20632 this.vIndex = this.vIndex + dir * 4;
20634 if(this.vIndex < 0){
20638 if(this.vIndex > 11){
20642 if(isNaN(this.vIndex)){
20646 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20651 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20652 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20656 e.preventDefault();
20659 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20660 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20676 this.picker().remove();
20681 Roo.apply(Roo.bootstrap.MonthField, {
20700 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
20701 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
20706 Roo.apply(Roo.bootstrap.MonthField, {
20710 cls: 'datepicker dropdown-menu roo-dynamic',
20714 cls: 'datepicker-months',
20718 cls: 'table-condensed',
20720 Roo.bootstrap.DateField.content
20740 * @class Roo.bootstrap.CheckBox
20741 * @extends Roo.bootstrap.Input
20742 * Bootstrap CheckBox class
20744 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
20745 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
20746 * @cfg {String} boxLabel The text that appears beside the checkbox
20747 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
20748 * @cfg {Boolean} checked initnal the element
20749 * @cfg {Boolean} inline inline the element (default false)
20750 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
20751 * @cfg {String} tooltip label tooltip
20754 * Create a new CheckBox
20755 * @param {Object} config The config object
20758 Roo.bootstrap.CheckBox = function(config){
20759 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
20764 * Fires when the element is checked or unchecked.
20765 * @param {Roo.bootstrap.CheckBox} this This input
20766 * @param {Boolean} checked The new checked value
20771 * Fires when the element is click.
20772 * @param {Roo.bootstrap.CheckBox} this This input
20779 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
20781 inputType: 'checkbox',
20790 getAutoCreate : function()
20792 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20798 cfg.cls = 'form-group ' + this.inputType; //input-group
20801 cfg.cls += ' ' + this.inputType + '-inline';
20807 type : this.inputType,
20808 value : this.inputValue,
20809 cls : 'roo-' + this.inputType, //'form-box',
20810 placeholder : this.placeholder || ''
20814 if(this.inputType != 'radio'){
20818 cls : 'roo-hidden-value',
20819 value : this.checked ? this.inputValue : this.valueOff
20824 if (this.weight) { // Validity check?
20825 cfg.cls += " " + this.inputType + "-" + this.weight;
20828 if (this.disabled) {
20829 input.disabled=true;
20833 input.checked = this.checked;
20838 input.name = this.name;
20840 if(this.inputType != 'radio'){
20841 hidden.name = this.name;
20842 input.name = '_hidden_' + this.name;
20847 input.cls += ' input-' + this.size;
20852 ['xs','sm','md','lg'].map(function(size){
20853 if (settings[size]) {
20854 cfg.cls += ' col-' + size + '-' + settings[size];
20858 var inputblock = input;
20860 if (this.before || this.after) {
20863 cls : 'input-group',
20868 inputblock.cn.push({
20870 cls : 'input-group-addon',
20875 inputblock.cn.push(input);
20877 if(this.inputType != 'radio'){
20878 inputblock.cn.push(hidden);
20882 inputblock.cn.push({
20884 cls : 'input-group-addon',
20891 if (align ==='left' && this.fieldLabel.length) {
20892 // Roo.log("left and has label");
20897 cls : 'control-label',
20898 html : this.fieldLabel
20908 if(this.labelWidth > 12){
20909 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
20912 if(this.labelWidth < 13 && this.labelmd == 0){
20913 this.labelmd = this.labelWidth;
20916 if(this.labellg > 0){
20917 cfg.cn[0].cls += ' col-lg-' + this.labellg;
20918 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
20921 if(this.labelmd > 0){
20922 cfg.cn[0].cls += ' col-md-' + this.labelmd;
20923 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
20926 if(this.labelsm > 0){
20927 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
20928 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
20931 if(this.labelxs > 0){
20932 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
20933 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
20936 } else if ( this.fieldLabel.length) {
20937 // Roo.log(" label");
20941 tag: this.boxLabel ? 'span' : 'label',
20943 cls: 'control-label box-input-label',
20944 //cls : 'input-group-addon',
20945 html : this.fieldLabel
20954 // Roo.log(" no label && no align");
20955 cfg.cn = [ inputblock ] ;
20961 var boxLabelCfg = {
20963 //'for': id, // box label is handled by onclick - so no for...
20965 html: this.boxLabel
20969 boxLabelCfg.tooltip = this.tooltip;
20972 cfg.cn.push(boxLabelCfg);
20975 if(this.inputType != 'radio'){
20976 cfg.cn.push(hidden);
20984 * return the real input element.
20986 inputEl: function ()
20988 return this.el.select('input.roo-' + this.inputType,true).first();
20990 hiddenEl: function ()
20992 return this.el.select('input.roo-hidden-value',true).first();
20995 labelEl: function()
20997 return this.el.select('label.control-label',true).first();
20999 /* depricated... */
21003 return this.labelEl();
21006 boxLabelEl: function()
21008 return this.el.select('label.box-label',true).first();
21011 initEvents : function()
21013 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
21015 this.inputEl().on('click', this.onClick, this);
21017 if (this.boxLabel) {
21018 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
21021 this.startValue = this.getValue();
21024 Roo.bootstrap.CheckBox.register(this);
21028 onClick : function(e)
21030 if(this.fireEvent('click', this, e) !== false){
21031 this.setChecked(!this.checked);
21036 setChecked : function(state,suppressEvent)
21038 this.startValue = this.getValue();
21040 if(this.inputType == 'radio'){
21042 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21043 e.dom.checked = false;
21046 this.inputEl().dom.checked = true;
21048 this.inputEl().dom.value = this.inputValue;
21050 if(suppressEvent !== true){
21051 this.fireEvent('check', this, true);
21059 this.checked = state;
21061 this.inputEl().dom.checked = state;
21064 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
21066 if(suppressEvent !== true){
21067 this.fireEvent('check', this, state);
21073 getValue : function()
21075 if(this.inputType == 'radio'){
21076 return this.getGroupValue();
21079 return this.hiddenEl().dom.value;
21083 getGroupValue : function()
21085 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
21089 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
21092 setValue : function(v,suppressEvent)
21094 if(this.inputType == 'radio'){
21095 this.setGroupValue(v, suppressEvent);
21099 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
21104 setGroupValue : function(v, suppressEvent)
21106 this.startValue = this.getValue();
21108 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21109 e.dom.checked = false;
21111 if(e.dom.value == v){
21112 e.dom.checked = true;
21116 if(suppressEvent !== true){
21117 this.fireEvent('check', this, true);
21125 validate : function()
21127 if(this.getVisibilityEl().hasClass('hidden')){
21133 (this.inputType == 'radio' && this.validateRadio()) ||
21134 (this.inputType == 'checkbox' && this.validateCheckbox())
21140 this.markInvalid();
21144 validateRadio : function()
21146 if(this.getVisibilityEl().hasClass('hidden')){
21150 if(this.allowBlank){
21156 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21157 if(!e.dom.checked){
21169 validateCheckbox : function()
21172 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
21173 //return (this.getValue() == this.inputValue) ? true : false;
21176 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21184 for(var i in group){
21185 if(group[i].el.isVisible(true)){
21193 for(var i in group){
21198 r = (group[i].getValue() == group[i].inputValue) ? true : false;
21205 * Mark this field as valid
21207 markValid : function()
21211 this.fireEvent('valid', this);
21213 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21216 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
21223 if(this.inputType == 'radio'){
21224 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21225 var fg = e.findParent('.form-group', false, true);
21226 if (Roo.bootstrap.version == 3) {
21227 fg.removeClass([_this.invalidClass, _this.validClass]);
21228 fg.addClass(_this.validClass);
21230 fg.removeClass(['is-valid', 'is-invalid']);
21231 fg.addClass('is-valid');
21239 var fg = this.el.findParent('.form-group', false, true);
21240 if (Roo.bootstrap.version == 3) {
21241 fg.removeClass([this.invalidClass, this.validClass]);
21242 fg.addClass(this.validClass);
21244 fg.removeClass(['is-valid', 'is-invalid']);
21245 fg.addClass('is-valid');
21250 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21256 for(var i in group){
21257 var fg = group[i].el.findParent('.form-group', false, true);
21258 if (Roo.bootstrap.version == 3) {
21259 fg.removeClass([this.invalidClass, this.validClass]);
21260 fg.addClass(this.validClass);
21262 fg.removeClass(['is-valid', 'is-invalid']);
21263 fg.addClass('is-valid');
21269 * Mark this field as invalid
21270 * @param {String} msg The validation message
21272 markInvalid : function(msg)
21274 if(this.allowBlank){
21280 this.fireEvent('invalid', this, msg);
21282 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21285 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
21289 label.markInvalid();
21292 if(this.inputType == 'radio'){
21294 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21295 var fg = e.findParent('.form-group', false, true);
21296 if (Roo.bootstrap.version == 3) {
21297 fg.removeClass([_this.invalidClass, _this.validClass]);
21298 fg.addClass(_this.invalidClass);
21300 fg.removeClass(['is-invalid', 'is-valid']);
21301 fg.addClass('is-invalid');
21309 var fg = this.el.findParent('.form-group', false, true);
21310 if (Roo.bootstrap.version == 3) {
21311 fg.removeClass([_this.invalidClass, _this.validClass]);
21312 fg.addClass(_this.invalidClass);
21314 fg.removeClass(['is-invalid', 'is-valid']);
21315 fg.addClass('is-invalid');
21320 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21326 for(var i in group){
21327 var fg = group[i].el.findParent('.form-group', false, true);
21328 if (Roo.bootstrap.version == 3) {
21329 fg.removeClass([_this.invalidClass, _this.validClass]);
21330 fg.addClass(_this.invalidClass);
21332 fg.removeClass(['is-invalid', 'is-valid']);
21333 fg.addClass('is-invalid');
21339 clearInvalid : function()
21341 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
21343 // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21345 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21347 if (label && label.iconEl) {
21348 label.iconEl.removeClass([ label.validClass, label.invalidClass ]);
21349 label.iconEl.removeClass(['is-invalid', 'is-valid']);
21353 disable : function()
21355 if(this.inputType != 'radio'){
21356 Roo.bootstrap.CheckBox.superclass.disable.call(this);
21363 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21364 _this.getActionEl().addClass(this.disabledClass);
21365 e.dom.disabled = true;
21369 this.disabled = true;
21370 this.fireEvent("disable", this);
21374 enable : function()
21376 if(this.inputType != 'radio'){
21377 Roo.bootstrap.CheckBox.superclass.enable.call(this);
21384 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21385 _this.getActionEl().removeClass(this.disabledClass);
21386 e.dom.disabled = false;
21390 this.disabled = false;
21391 this.fireEvent("enable", this);
21395 setBoxLabel : function(v)
21400 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21406 Roo.apply(Roo.bootstrap.CheckBox, {
21411 * register a CheckBox Group
21412 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
21414 register : function(checkbox)
21416 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
21417 this.groups[checkbox.groupId] = {};
21420 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
21424 this.groups[checkbox.groupId][checkbox.name] = checkbox;
21428 * fetch a CheckBox Group based on the group ID
21429 * @param {string} the group ID
21430 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
21432 get: function(groupId) {
21433 if (typeof(this.groups[groupId]) == 'undefined') {
21437 return this.groups[groupId] ;
21450 * @class Roo.bootstrap.Radio
21451 * @extends Roo.bootstrap.Component
21452 * Bootstrap Radio class
21453 * @cfg {String} boxLabel - the label associated
21454 * @cfg {String} value - the value of radio
21457 * Create a new Radio
21458 * @param {Object} config The config object
21460 Roo.bootstrap.Radio = function(config){
21461 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
21465 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
21471 getAutoCreate : function()
21475 cls : 'form-group radio',
21480 html : this.boxLabel
21488 initEvents : function()
21490 this.parent().register(this);
21492 this.el.on('click', this.onClick, this);
21496 onClick : function(e)
21498 if(this.parent().fireEvent('click', this.parent(), this, e) !== false){
21499 this.setChecked(true);
21503 setChecked : function(state, suppressEvent)
21505 this.parent().setValue(this.value, suppressEvent);
21509 setBoxLabel : function(v)
21514 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21529 * @class Roo.bootstrap.SecurePass
21530 * @extends Roo.bootstrap.Input
21531 * Bootstrap SecurePass class
21535 * Create a new SecurePass
21536 * @param {Object} config The config object
21539 Roo.bootstrap.SecurePass = function (config) {
21540 // these go here, so the translation tool can replace them..
21542 PwdEmpty: "Please type a password, and then retype it to confirm.",
21543 PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21544 PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21545 PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21546 IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21547 FNInPwd: "Your password can't contain your first name. Please type a different password.",
21548 LNInPwd: "Your password can't contain your last name. Please type a different password.",
21549 TooWeak: "Your password is Too Weak."
21551 this.meterLabel = "Password strength:";
21552 this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
21553 this.meterClass = [
21554 "roo-password-meter-tooweak",
21555 "roo-password-meter-weak",
21556 "roo-password-meter-medium",
21557 "roo-password-meter-strong",
21558 "roo-password-meter-grey"
21563 Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
21566 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
21568 * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
21570 * PwdEmpty: "Please type a password, and then retype it to confirm.",
21571 * PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21572 * PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21573 * PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21574 * IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21575 * FNInPwd: "Your password can't contain your first name. Please type a different password.",
21576 * LNInPwd: "Your password can't contain your last name. Please type a different password."
21586 * @cfg {String/Object} Label for the strength meter (defaults to
21587 * 'Password strength:')
21592 * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
21593 * ['Weak', 'Medium', 'Strong'])
21596 pwdStrengths: false,
21609 initEvents: function ()
21611 Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
21613 if (this.el.is('input[type=password]') && Roo.isSafari) {
21614 this.el.on('keydown', this.SafariOnKeyDown, this);
21617 this.el.on('keyup', this.checkStrength, this, {buffer: 50});
21620 onRender: function (ct, position)
21622 Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
21623 this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
21624 this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
21626 this.trigger.createChild({
21631 cls: 'roo-password-meter-grey col-xs-12',
21634 //width: this.meterWidth + 'px'
21638 cls: 'roo-password-meter-text'
21644 if (this.hideTrigger) {
21645 this.trigger.setDisplayed(false);
21647 this.setSize(this.width || '', this.height || '');
21650 onDestroy: function ()
21652 if (this.trigger) {
21653 this.trigger.removeAllListeners();
21654 this.trigger.remove();
21657 this.wrap.remove();
21659 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
21662 checkStrength: function ()
21664 var pwd = this.inputEl().getValue();
21665 if (pwd == this._lastPwd) {
21670 if (this.ClientSideStrongPassword(pwd)) {
21672 } else if (this.ClientSideMediumPassword(pwd)) {
21674 } else if (this.ClientSideWeakPassword(pwd)) {
21680 Roo.log('strength1: ' + strength);
21682 //var pm = this.trigger.child('div/div/div').dom;
21683 var pm = this.trigger.child('div/div');
21684 pm.removeClass(this.meterClass);
21685 pm.addClass(this.meterClass[strength]);
21688 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21690 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21692 this._lastPwd = pwd;
21696 Roo.bootstrap.SecurePass.superclass.reset.call(this);
21698 this._lastPwd = '';
21700 var pm = this.trigger.child('div/div');
21701 pm.removeClass(this.meterClass);
21702 pm.addClass('roo-password-meter-grey');
21705 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21708 this.inputEl().dom.type='password';
21711 validateValue: function (value)
21714 if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
21717 if (value.length == 0) {
21718 if (this.allowBlank) {
21719 this.clearInvalid();
21723 this.markInvalid(this.errors.PwdEmpty);
21724 this.errorMsg = this.errors.PwdEmpty;
21732 if ('[\x21-\x7e]*'.match(value)) {
21733 this.markInvalid(this.errors.PwdBadChar);
21734 this.errorMsg = this.errors.PwdBadChar;
21737 if (value.length < 6) {
21738 this.markInvalid(this.errors.PwdShort);
21739 this.errorMsg = this.errors.PwdShort;
21742 if (value.length > 16) {
21743 this.markInvalid(this.errors.PwdLong);
21744 this.errorMsg = this.errors.PwdLong;
21748 if (this.ClientSideStrongPassword(value)) {
21750 } else if (this.ClientSideMediumPassword(value)) {
21752 } else if (this.ClientSideWeakPassword(value)) {
21759 if (strength < 2) {
21760 //this.markInvalid(this.errors.TooWeak);
21761 this.errorMsg = this.errors.TooWeak;
21766 console.log('strength2: ' + strength);
21768 //var pm = this.trigger.child('div/div/div').dom;
21770 var pm = this.trigger.child('div/div');
21771 pm.removeClass(this.meterClass);
21772 pm.addClass(this.meterClass[strength]);
21774 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21776 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21778 this.errorMsg = '';
21782 CharacterSetChecks: function (type)
21785 this.fResult = false;
21788 isctype: function (character, type)
21791 case this.kCapitalLetter:
21792 if (character >= 'A' && character <= 'Z') {
21797 case this.kSmallLetter:
21798 if (character >= 'a' && character <= 'z') {
21804 if (character >= '0' && character <= '9') {
21809 case this.kPunctuation:
21810 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
21821 IsLongEnough: function (pwd, size)
21823 return !(pwd == null || isNaN(size) || pwd.length < size);
21826 SpansEnoughCharacterSets: function (word, nb)
21828 if (!this.IsLongEnough(word, nb))
21833 var characterSetChecks = new Array(
21834 new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
21835 new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
21838 for (var index = 0; index < word.length; ++index) {
21839 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21840 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
21841 characterSetChecks[nCharSet].fResult = true;
21848 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21849 if (characterSetChecks[nCharSet].fResult) {
21854 if (nCharSets < nb) {
21860 ClientSideStrongPassword: function (pwd)
21862 return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
21865 ClientSideMediumPassword: function (pwd)
21867 return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
21870 ClientSideWeakPassword: function (pwd)
21872 return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
21875 })//<script type="text/javascript">
21878 * Based Ext JS Library 1.1.1
21879 * Copyright(c) 2006-2007, Ext JS, LLC.
21885 * @class Roo.HtmlEditorCore
21886 * @extends Roo.Component
21887 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
21889 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
21892 Roo.HtmlEditorCore = function(config){
21895 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
21900 * @event initialize
21901 * Fires when the editor is fully initialized (including the iframe)
21902 * @param {Roo.HtmlEditorCore} this
21907 * Fires when the editor is first receives the focus. Any insertion must wait
21908 * until after this event.
21909 * @param {Roo.HtmlEditorCore} this
21913 * @event beforesync
21914 * Fires before the textarea is updated with content from the editor iframe. Return false
21915 * to cancel the sync.
21916 * @param {Roo.HtmlEditorCore} this
21917 * @param {String} html
21921 * @event beforepush
21922 * Fires before the iframe editor is updated with content from the textarea. Return false
21923 * to cancel the push.
21924 * @param {Roo.HtmlEditorCore} this
21925 * @param {String} html
21930 * Fires when the textarea is updated with content from the editor iframe.
21931 * @param {Roo.HtmlEditorCore} this
21932 * @param {String} html
21937 * Fires when the iframe editor is updated with content from the textarea.
21938 * @param {Roo.HtmlEditorCore} this
21939 * @param {String} html
21944 * @event editorevent
21945 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
21946 * @param {Roo.HtmlEditorCore} this
21952 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
21954 // defaults : white / black...
21955 this.applyBlacklists();
21962 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
21966 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
21972 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
21977 * @cfg {Number} height (in pixels)
21981 * @cfg {Number} width (in pixels)
21986 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
21989 stylesheets: false,
21994 // private properties
21995 validationEvent : false,
21997 initialized : false,
21999 sourceEditMode : false,
22000 onFocus : Roo.emptyFn,
22002 hideMode:'offsets',
22006 // blacklist + whitelisted elements..
22013 * Protected method that will not generally be called directly. It
22014 * is called when the editor initializes the iframe with HTML contents. Override this method if you
22015 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
22017 getDocMarkup : function(){
22021 // inherit styels from page...??
22022 if (this.stylesheets === false) {
22024 Roo.get(document.head).select('style').each(function(node) {
22025 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
22028 Roo.get(document.head).select('link').each(function(node) {
22029 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
22032 } else if (!this.stylesheets.length) {
22034 st = '<style type="text/css">' +
22035 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
22038 st = '<style type="text/css">' +
22043 st += '<style type="text/css">' +
22044 'IMG { cursor: pointer } ' +
22047 var cls = 'roo-htmleditor-body';
22049 if(this.bodyCls.length){
22050 cls += ' ' + this.bodyCls;
22053 return '<html><head>' + st +
22054 //<style type="text/css">' +
22055 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
22057 ' </head><body class="' + cls + '"></body></html>';
22061 onRender : function(ct, position)
22064 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
22065 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
22068 this.el.dom.style.border = '0 none';
22069 this.el.dom.setAttribute('tabIndex', -1);
22070 this.el.addClass('x-hidden hide');
22074 if(Roo.isIE){ // fix IE 1px bogus margin
22075 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
22079 this.frameId = Roo.id();
22083 var iframe = this.owner.wrap.createChild({
22085 cls: 'form-control', // bootstrap..
22087 name: this.frameId,
22088 frameBorder : 'no',
22089 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
22094 this.iframe = iframe.dom;
22096 this.assignDocWin();
22098 this.doc.designMode = 'on';
22101 this.doc.write(this.getDocMarkup());
22105 var task = { // must defer to wait for browser to be ready
22107 //console.log("run task?" + this.doc.readyState);
22108 this.assignDocWin();
22109 if(this.doc.body || this.doc.readyState == 'complete'){
22111 this.doc.designMode="on";
22115 Roo.TaskMgr.stop(task);
22116 this.initEditor.defer(10, this);
22123 Roo.TaskMgr.start(task);
22128 onResize : function(w, h)
22130 Roo.log('resize: ' +w + ',' + h );
22131 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
22135 if(typeof w == 'number'){
22137 this.iframe.style.width = w + 'px';
22139 if(typeof h == 'number'){
22141 this.iframe.style.height = h + 'px';
22143 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
22150 * Toggles the editor between standard and source edit mode.
22151 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
22153 toggleSourceEdit : function(sourceEditMode){
22155 this.sourceEditMode = sourceEditMode === true;
22157 if(this.sourceEditMode){
22159 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
22162 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
22163 //this.iframe.className = '';
22166 //this.setSize(this.owner.wrap.getSize());
22167 //this.fireEvent('editmodechange', this, this.sourceEditMode);
22174 * Protected method that will not generally be called directly. If you need/want
22175 * custom HTML cleanup, this is the method you should override.
22176 * @param {String} html The HTML to be cleaned
22177 * return {String} The cleaned HTML
22179 cleanHtml : function(html){
22180 html = String(html);
22181 if(html.length > 5){
22182 if(Roo.isSafari){ // strip safari nonsense
22183 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
22186 if(html == ' '){
22193 * HTML Editor -> Textarea
22194 * Protected method that will not generally be called directly. Syncs the contents
22195 * of the editor iframe with the textarea.
22197 syncValue : function(){
22198 if(this.initialized){
22199 var bd = (this.doc.body || this.doc.documentElement);
22200 //this.cleanUpPaste(); -- this is done else where and causes havoc..
22201 var html = bd.innerHTML;
22203 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
22204 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
22206 html = '<div style="'+m[0]+'">' + html + '</div>';
22209 html = this.cleanHtml(html);
22210 // fix up the special chars.. normaly like back quotes in word...
22211 // however we do not want to do this with chinese..
22212 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
22213 var cc = b.charCodeAt();
22215 (cc >= 0x4E00 && cc < 0xA000 ) ||
22216 (cc >= 0x3400 && cc < 0x4E00 ) ||
22217 (cc >= 0xf900 && cc < 0xfb00 )
22223 if(this.owner.fireEvent('beforesync', this, html) !== false){
22224 this.el.dom.value = html;
22225 this.owner.fireEvent('sync', this, html);
22231 * Protected method that will not generally be called directly. Pushes the value of the textarea
22232 * into the iframe editor.
22234 pushValue : function(){
22235 if(this.initialized){
22236 var v = this.el.dom.value.trim();
22238 // if(v.length < 1){
22242 if(this.owner.fireEvent('beforepush', this, v) !== false){
22243 var d = (this.doc.body || this.doc.documentElement);
22245 this.cleanUpPaste();
22246 this.el.dom.value = d.innerHTML;
22247 this.owner.fireEvent('push', this, v);
22253 deferFocus : function(){
22254 this.focus.defer(10, this);
22258 focus : function(){
22259 if(this.win && !this.sourceEditMode){
22266 assignDocWin: function()
22268 var iframe = this.iframe;
22271 this.doc = iframe.contentWindow.document;
22272 this.win = iframe.contentWindow;
22274 // if (!Roo.get(this.frameId)) {
22277 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
22278 // this.win = Roo.get(this.frameId).dom.contentWindow;
22280 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
22284 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
22285 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
22290 initEditor : function(){
22291 //console.log("INIT EDITOR");
22292 this.assignDocWin();
22296 this.doc.designMode="on";
22298 this.doc.write(this.getDocMarkup());
22301 var dbody = (this.doc.body || this.doc.documentElement);
22302 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
22303 // this copies styles from the containing element into thsi one..
22304 // not sure why we need all of this..
22305 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
22307 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
22308 //ss['background-attachment'] = 'fixed'; // w3c
22309 dbody.bgProperties = 'fixed'; // ie
22310 //Roo.DomHelper.applyStyles(dbody, ss);
22311 Roo.EventManager.on(this.doc, {
22312 //'mousedown': this.onEditorEvent,
22313 'mouseup': this.onEditorEvent,
22314 'dblclick': this.onEditorEvent,
22315 'click': this.onEditorEvent,
22316 'keyup': this.onEditorEvent,
22321 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
22323 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
22324 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
22326 this.initialized = true;
22328 this.owner.fireEvent('initialize', this);
22333 onDestroy : function(){
22339 //for (var i =0; i < this.toolbars.length;i++) {
22340 // // fixme - ask toolbars for heights?
22341 // this.toolbars[i].onDestroy();
22344 //this.wrap.dom.innerHTML = '';
22345 //this.wrap.remove();
22350 onFirstFocus : function(){
22352 this.assignDocWin();
22355 this.activated = true;
22358 if(Roo.isGecko){ // prevent silly gecko errors
22360 var s = this.win.getSelection();
22361 if(!s.focusNode || s.focusNode.nodeType != 3){
22362 var r = s.getRangeAt(0);
22363 r.selectNodeContents((this.doc.body || this.doc.documentElement));
22368 this.execCmd('useCSS', true);
22369 this.execCmd('styleWithCSS', false);
22372 this.owner.fireEvent('activate', this);
22376 adjustFont: function(btn){
22377 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
22378 //if(Roo.isSafari){ // safari
22381 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
22382 if(Roo.isSafari){ // safari
22383 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
22384 v = (v < 10) ? 10 : v;
22385 v = (v > 48) ? 48 : v;
22386 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
22391 v = Math.max(1, v+adjust);
22393 this.execCmd('FontSize', v );
22396 onEditorEvent : function(e)
22398 this.owner.fireEvent('editorevent', this, e);
22399 // this.updateToolbar();
22400 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
22403 insertTag : function(tg)
22405 // could be a bit smarter... -> wrap the current selected tRoo..
22406 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
22408 range = this.createRange(this.getSelection());
22409 var wrappingNode = this.doc.createElement(tg.toLowerCase());
22410 wrappingNode.appendChild(range.extractContents());
22411 range.insertNode(wrappingNode);
22418 this.execCmd("formatblock", tg);
22422 insertText : function(txt)
22426 var range = this.createRange();
22427 range.deleteContents();
22428 //alert(Sender.getAttribute('label'));
22430 range.insertNode(this.doc.createTextNode(txt));
22436 * Executes a Midas editor command on the editor document and performs necessary focus and
22437 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
22438 * @param {String} cmd The Midas command
22439 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22441 relayCmd : function(cmd, value){
22443 this.execCmd(cmd, value);
22444 this.owner.fireEvent('editorevent', this);
22445 //this.updateToolbar();
22446 this.owner.deferFocus();
22450 * Executes a Midas editor command directly on the editor document.
22451 * For visual commands, you should use {@link #relayCmd} instead.
22452 * <b>This should only be called after the editor is initialized.</b>
22453 * @param {String} cmd The Midas command
22454 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22456 execCmd : function(cmd, value){
22457 this.doc.execCommand(cmd, false, value === undefined ? null : value);
22464 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
22466 * @param {String} text | dom node..
22468 insertAtCursor : function(text)
22471 if(!this.activated){
22477 var r = this.doc.selection.createRange();
22488 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
22492 // from jquery ui (MIT licenced)
22494 var win = this.win;
22496 if (win.getSelection && win.getSelection().getRangeAt) {
22497 range = win.getSelection().getRangeAt(0);
22498 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
22499 range.insertNode(node);
22500 } else if (win.document.selection && win.document.selection.createRange) {
22501 // no firefox support
22502 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22503 win.document.selection.createRange().pasteHTML(txt);
22505 // no firefox support
22506 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22507 this.execCmd('InsertHTML', txt);
22516 mozKeyPress : function(e){
22518 var c = e.getCharCode(), cmd;
22521 c = String.fromCharCode(c).toLowerCase();
22535 this.cleanUpPaste.defer(100, this);
22543 e.preventDefault();
22551 fixKeys : function(){ // load time branching for fastest keydown performance
22553 return function(e){
22554 var k = e.getKey(), r;
22557 r = this.doc.selection.createRange();
22560 r.pasteHTML('    ');
22567 r = this.doc.selection.createRange();
22569 var target = r.parentElement();
22570 if(!target || target.tagName.toLowerCase() != 'li'){
22572 r.pasteHTML('<br />');
22578 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22579 this.cleanUpPaste.defer(100, this);
22585 }else if(Roo.isOpera){
22586 return function(e){
22587 var k = e.getKey();
22591 this.execCmd('InsertHTML','    ');
22594 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22595 this.cleanUpPaste.defer(100, this);
22600 }else if(Roo.isSafari){
22601 return function(e){
22602 var k = e.getKey();
22606 this.execCmd('InsertText','\t');
22610 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22611 this.cleanUpPaste.defer(100, this);
22619 getAllAncestors: function()
22621 var p = this.getSelectedNode();
22624 a.push(p); // push blank onto stack..
22625 p = this.getParentElement();
22629 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
22633 a.push(this.doc.body);
22637 lastSelNode : false,
22640 getSelection : function()
22642 this.assignDocWin();
22643 return Roo.isIE ? this.doc.selection : this.win.getSelection();
22646 getSelectedNode: function()
22648 // this may only work on Gecko!!!
22650 // should we cache this!!!!
22655 var range = this.createRange(this.getSelection()).cloneRange();
22658 var parent = range.parentElement();
22660 var testRange = range.duplicate();
22661 testRange.moveToElementText(parent);
22662 if (testRange.inRange(range)) {
22665 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
22668 parent = parent.parentElement;
22673 // is ancestor a text element.
22674 var ac = range.commonAncestorContainer;
22675 if (ac.nodeType == 3) {
22676 ac = ac.parentNode;
22679 var ar = ac.childNodes;
22682 var other_nodes = [];
22683 var has_other_nodes = false;
22684 for (var i=0;i<ar.length;i++) {
22685 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
22688 // fullly contained node.
22690 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
22695 // probably selected..
22696 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
22697 other_nodes.push(ar[i]);
22701 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
22706 has_other_nodes = true;
22708 if (!nodes.length && other_nodes.length) {
22709 nodes= other_nodes;
22711 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
22717 createRange: function(sel)
22719 // this has strange effects when using with
22720 // top toolbar - not sure if it's a great idea.
22721 //this.editor.contentWindow.focus();
22722 if (typeof sel != "undefined") {
22724 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
22726 return this.doc.createRange();
22729 return this.doc.createRange();
22732 getParentElement: function()
22735 this.assignDocWin();
22736 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
22738 var range = this.createRange(sel);
22741 var p = range.commonAncestorContainer;
22742 while (p.nodeType == 3) { // text node
22753 * Range intersection.. the hard stuff...
22757 * [ -- selected range --- ]
22761 * if end is before start or hits it. fail.
22762 * if start is after end or hits it fail.
22764 * if either hits (but other is outside. - then it's not
22770 // @see http://www.thismuchiknow.co.uk/?p=64.
22771 rangeIntersectsNode : function(range, node)
22773 var nodeRange = node.ownerDocument.createRange();
22775 nodeRange.selectNode(node);
22777 nodeRange.selectNodeContents(node);
22780 var rangeStartRange = range.cloneRange();
22781 rangeStartRange.collapse(true);
22783 var rangeEndRange = range.cloneRange();
22784 rangeEndRange.collapse(false);
22786 var nodeStartRange = nodeRange.cloneRange();
22787 nodeStartRange.collapse(true);
22789 var nodeEndRange = nodeRange.cloneRange();
22790 nodeEndRange.collapse(false);
22792 return rangeStartRange.compareBoundaryPoints(
22793 Range.START_TO_START, nodeEndRange) == -1 &&
22794 rangeEndRange.compareBoundaryPoints(
22795 Range.START_TO_START, nodeStartRange) == 1;
22799 rangeCompareNode : function(range, node)
22801 var nodeRange = node.ownerDocument.createRange();
22803 nodeRange.selectNode(node);
22805 nodeRange.selectNodeContents(node);
22809 range.collapse(true);
22811 nodeRange.collapse(true);
22813 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
22814 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
22816 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
22818 var nodeIsBefore = ss == 1;
22819 var nodeIsAfter = ee == -1;
22821 if (nodeIsBefore && nodeIsAfter) {
22824 if (!nodeIsBefore && nodeIsAfter) {
22825 return 1; //right trailed.
22828 if (nodeIsBefore && !nodeIsAfter) {
22829 return 2; // left trailed.
22835 // private? - in a new class?
22836 cleanUpPaste : function()
22838 // cleans up the whole document..
22839 Roo.log('cleanuppaste');
22841 this.cleanUpChildren(this.doc.body);
22842 var clean = this.cleanWordChars(this.doc.body.innerHTML);
22843 if (clean != this.doc.body.innerHTML) {
22844 this.doc.body.innerHTML = clean;
22849 cleanWordChars : function(input) {// change the chars to hex code
22850 var he = Roo.HtmlEditorCore;
22852 var output = input;
22853 Roo.each(he.swapCodes, function(sw) {
22854 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
22856 output = output.replace(swapper, sw[1]);
22863 cleanUpChildren : function (n)
22865 if (!n.childNodes.length) {
22868 for (var i = n.childNodes.length-1; i > -1 ; i--) {
22869 this.cleanUpChild(n.childNodes[i]);
22876 cleanUpChild : function (node)
22879 //console.log(node);
22880 if (node.nodeName == "#text") {
22881 // clean up silly Windows -- stuff?
22884 if (node.nodeName == "#comment") {
22885 node.parentNode.removeChild(node);
22886 // clean up silly Windows -- stuff?
22889 var lcname = node.tagName.toLowerCase();
22890 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
22891 // whitelist of tags..
22893 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
22895 node.parentNode.removeChild(node);
22900 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
22902 // remove <a name=....> as rendering on yahoo mailer is borked with this.
22903 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
22905 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
22906 // remove_keep_children = true;
22909 if (remove_keep_children) {
22910 this.cleanUpChildren(node);
22911 // inserts everything just before this node...
22912 while (node.childNodes.length) {
22913 var cn = node.childNodes[0];
22914 node.removeChild(cn);
22915 node.parentNode.insertBefore(cn, node);
22917 node.parentNode.removeChild(node);
22921 if (!node.attributes || !node.attributes.length) {
22922 this.cleanUpChildren(node);
22926 function cleanAttr(n,v)
22929 if (v.match(/^\./) || v.match(/^\//)) {
22932 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/) || v.match(/^ftp:/)) {
22935 if (v.match(/^#/)) {
22938 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
22939 node.removeAttribute(n);
22943 var cwhite = this.cwhite;
22944 var cblack = this.cblack;
22946 function cleanStyle(n,v)
22948 if (v.match(/expression/)) { //XSS?? should we even bother..
22949 node.removeAttribute(n);
22953 var parts = v.split(/;/);
22956 Roo.each(parts, function(p) {
22957 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
22961 var l = p.split(':').shift().replace(/\s+/g,'');
22962 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
22964 if ( cwhite.length && cblack.indexOf(l) > -1) {
22965 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22966 //node.removeAttribute(n);
22970 // only allow 'c whitelisted system attributes'
22971 if ( cwhite.length && cwhite.indexOf(l) < 0) {
22972 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22973 //node.removeAttribute(n);
22983 if (clean.length) {
22984 node.setAttribute(n, clean.join(';'));
22986 node.removeAttribute(n);
22992 for (var i = node.attributes.length-1; i > -1 ; i--) {
22993 var a = node.attributes[i];
22996 if (a.name.toLowerCase().substr(0,2)=='on') {
22997 node.removeAttribute(a.name);
23000 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
23001 node.removeAttribute(a.name);
23004 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
23005 cleanAttr(a.name,a.value); // fixme..
23008 if (a.name == 'style') {
23009 cleanStyle(a.name,a.value);
23012 /// clean up MS crap..
23013 // tecnically this should be a list of valid class'es..
23016 if (a.name == 'class') {
23017 if (a.value.match(/^Mso/)) {
23018 node.className = '';
23021 if (a.value.match(/^body$/)) {
23022 node.className = '';
23033 this.cleanUpChildren(node);
23039 * Clean up MS wordisms...
23041 cleanWord : function(node)
23046 this.cleanWord(this.doc.body);
23049 if (node.nodeName == "#text") {
23050 // clean up silly Windows -- stuff?
23053 if (node.nodeName == "#comment") {
23054 node.parentNode.removeChild(node);
23055 // clean up silly Windows -- stuff?
23059 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
23060 node.parentNode.removeChild(node);
23064 // remove - but keep children..
23065 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
23066 while (node.childNodes.length) {
23067 var cn = node.childNodes[0];
23068 node.removeChild(cn);
23069 node.parentNode.insertBefore(cn, node);
23071 node.parentNode.removeChild(node);
23072 this.iterateChildren(node, this.cleanWord);
23076 if (node.className.length) {
23078 var cn = node.className.split(/\W+/);
23080 Roo.each(cn, function(cls) {
23081 if (cls.match(/Mso[a-zA-Z]+/)) {
23086 node.className = cna.length ? cna.join(' ') : '';
23088 node.removeAttribute("class");
23092 if (node.hasAttribute("lang")) {
23093 node.removeAttribute("lang");
23096 if (node.hasAttribute("style")) {
23098 var styles = node.getAttribute("style").split(";");
23100 Roo.each(styles, function(s) {
23101 if (!s.match(/:/)) {
23104 var kv = s.split(":");
23105 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
23108 // what ever is left... we allow.
23111 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
23112 if (!nstyle.length) {
23113 node.removeAttribute('style');
23116 this.iterateChildren(node, this.cleanWord);
23122 * iterateChildren of a Node, calling fn each time, using this as the scole..
23123 * @param {DomNode} node node to iterate children of.
23124 * @param {Function} fn method of this class to call on each item.
23126 iterateChildren : function(node, fn)
23128 if (!node.childNodes.length) {
23131 for (var i = node.childNodes.length-1; i > -1 ; i--) {
23132 fn.call(this, node.childNodes[i])
23138 * cleanTableWidths.
23140 * Quite often pasting from word etc.. results in tables with column and widths.
23141 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
23144 cleanTableWidths : function(node)
23149 this.cleanTableWidths(this.doc.body);
23154 if (node.nodeName == "#text" || node.nodeName == "#comment") {
23157 Roo.log(node.tagName);
23158 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
23159 this.iterateChildren(node, this.cleanTableWidths);
23162 if (node.hasAttribute('width')) {
23163 node.removeAttribute('width');
23167 if (node.hasAttribute("style")) {
23170 var styles = node.getAttribute("style").split(";");
23172 Roo.each(styles, function(s) {
23173 if (!s.match(/:/)) {
23176 var kv = s.split(":");
23177 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
23180 // what ever is left... we allow.
23183 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
23184 if (!nstyle.length) {
23185 node.removeAttribute('style');
23189 this.iterateChildren(node, this.cleanTableWidths);
23197 domToHTML : function(currentElement, depth, nopadtext) {
23199 depth = depth || 0;
23200 nopadtext = nopadtext || false;
23202 if (!currentElement) {
23203 return this.domToHTML(this.doc.body);
23206 //Roo.log(currentElement);
23208 var allText = false;
23209 var nodeName = currentElement.nodeName;
23210 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
23212 if (nodeName == '#text') {
23214 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
23219 if (nodeName != 'BODY') {
23222 // Prints the node tagName, such as <A>, <IMG>, etc
23225 for(i = 0; i < currentElement.attributes.length;i++) {
23227 var aname = currentElement.attributes.item(i).name;
23228 if (!currentElement.attributes.item(i).value.length) {
23231 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
23234 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
23243 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
23246 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
23251 // Traverse the tree
23253 var currentElementChild = currentElement.childNodes.item(i);
23254 var allText = true;
23255 var innerHTML = '';
23257 while (currentElementChild) {
23258 // Formatting code (indent the tree so it looks nice on the screen)
23259 var nopad = nopadtext;
23260 if (lastnode == 'SPAN') {
23264 if (currentElementChild.nodeName == '#text') {
23265 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
23266 toadd = nopadtext ? toadd : toadd.trim();
23267 if (!nopad && toadd.length > 80) {
23268 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
23270 innerHTML += toadd;
23273 currentElementChild = currentElement.childNodes.item(i);
23279 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
23281 // Recursively traverse the tree structure of the child node
23282 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
23283 lastnode = currentElementChild.nodeName;
23285 currentElementChild=currentElement.childNodes.item(i);
23291 // The remaining code is mostly for formatting the tree
23292 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
23297 ret+= "</"+tagName+">";
23303 applyBlacklists : function()
23305 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
23306 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
23310 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
23311 if (b.indexOf(tag) > -1) {
23314 this.white.push(tag);
23318 Roo.each(w, function(tag) {
23319 if (b.indexOf(tag) > -1) {
23322 if (this.white.indexOf(tag) > -1) {
23325 this.white.push(tag);
23330 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
23331 if (w.indexOf(tag) > -1) {
23334 this.black.push(tag);
23338 Roo.each(b, function(tag) {
23339 if (w.indexOf(tag) > -1) {
23342 if (this.black.indexOf(tag) > -1) {
23345 this.black.push(tag);
23350 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
23351 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
23355 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
23356 if (b.indexOf(tag) > -1) {
23359 this.cwhite.push(tag);
23363 Roo.each(w, function(tag) {
23364 if (b.indexOf(tag) > -1) {
23367 if (this.cwhite.indexOf(tag) > -1) {
23370 this.cwhite.push(tag);
23375 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
23376 if (w.indexOf(tag) > -1) {
23379 this.cblack.push(tag);
23383 Roo.each(b, function(tag) {
23384 if (w.indexOf(tag) > -1) {
23387 if (this.cblack.indexOf(tag) > -1) {
23390 this.cblack.push(tag);
23395 setStylesheets : function(stylesheets)
23397 if(typeof(stylesheets) == 'string'){
23398 Roo.get(this.iframe.contentDocument.head).createChild({
23400 rel : 'stylesheet',
23409 Roo.each(stylesheets, function(s) {
23414 Roo.get(_this.iframe.contentDocument.head).createChild({
23416 rel : 'stylesheet',
23425 removeStylesheets : function()
23429 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
23434 setStyle : function(style)
23436 Roo.get(this.iframe.contentDocument.head).createChild({
23445 // hide stuff that is not compatible
23459 * @event specialkey
23463 * @cfg {String} fieldClass @hide
23466 * @cfg {String} focusClass @hide
23469 * @cfg {String} autoCreate @hide
23472 * @cfg {String} inputType @hide
23475 * @cfg {String} invalidClass @hide
23478 * @cfg {String} invalidText @hide
23481 * @cfg {String} msgFx @hide
23484 * @cfg {String} validateOnBlur @hide
23488 Roo.HtmlEditorCore.white = [
23489 'area', 'br', 'img', 'input', 'hr', 'wbr',
23491 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
23492 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
23493 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
23494 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
23495 'table', 'ul', 'xmp',
23497 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
23500 'dir', 'menu', 'ol', 'ul', 'dl',
23506 Roo.HtmlEditorCore.black = [
23507 // 'embed', 'object', // enable - backend responsiblity to clean thiese
23509 'base', 'basefont', 'bgsound', 'blink', 'body',
23510 'frame', 'frameset', 'head', 'html', 'ilayer',
23511 'iframe', 'layer', 'link', 'meta', 'object',
23512 'script', 'style' ,'title', 'xml' // clean later..
23514 Roo.HtmlEditorCore.clean = [
23515 'script', 'style', 'title', 'xml'
23517 Roo.HtmlEditorCore.remove = [
23522 Roo.HtmlEditorCore.ablack = [
23526 Roo.HtmlEditorCore.aclean = [
23527 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
23531 Roo.HtmlEditorCore.pwhite= [
23532 'http', 'https', 'mailto'
23535 // white listed style attributes.
23536 Roo.HtmlEditorCore.cwhite= [
23537 // 'text-align', /// default is to allow most things..
23543 // black listed style attributes.
23544 Roo.HtmlEditorCore.cblack= [
23545 // 'font-size' -- this can be set by the project
23549 Roo.HtmlEditorCore.swapCodes =[
23568 * @class Roo.bootstrap.HtmlEditor
23569 * @extends Roo.bootstrap.TextArea
23570 * Bootstrap HtmlEditor class
23573 * Create a new HtmlEditor
23574 * @param {Object} config The config object
23577 Roo.bootstrap.HtmlEditor = function(config){
23578 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
23579 if (!this.toolbars) {
23580 this.toolbars = [];
23583 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
23586 * @event initialize
23587 * Fires when the editor is fully initialized (including the iframe)
23588 * @param {HtmlEditor} this
23593 * Fires when the editor is first receives the focus. Any insertion must wait
23594 * until after this event.
23595 * @param {HtmlEditor} this
23599 * @event beforesync
23600 * Fires before the textarea is updated with content from the editor iframe. Return false
23601 * to cancel the sync.
23602 * @param {HtmlEditor} this
23603 * @param {String} html
23607 * @event beforepush
23608 * Fires before the iframe editor is updated with content from the textarea. Return false
23609 * to cancel the push.
23610 * @param {HtmlEditor} this
23611 * @param {String} html
23616 * Fires when the textarea is updated with content from the editor iframe.
23617 * @param {HtmlEditor} this
23618 * @param {String} html
23623 * Fires when the iframe editor is updated with content from the textarea.
23624 * @param {HtmlEditor} this
23625 * @param {String} html
23629 * @event editmodechange
23630 * Fires when the editor switches edit modes
23631 * @param {HtmlEditor} this
23632 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
23634 editmodechange: true,
23636 * @event editorevent
23637 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
23638 * @param {HtmlEditor} this
23642 * @event firstfocus
23643 * Fires when on first focus - needed by toolbars..
23644 * @param {HtmlEditor} this
23649 * Auto save the htmlEditor value as a file into Events
23650 * @param {HtmlEditor} this
23654 * @event savedpreview
23655 * preview the saved version of htmlEditor
23656 * @param {HtmlEditor} this
23663 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
23667 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
23672 * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
23677 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
23682 * @cfg {Number} height (in pixels)
23686 * @cfg {Number} width (in pixels)
23691 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
23694 stylesheets: false,
23699 // private properties
23700 validationEvent : false,
23702 initialized : false,
23705 onFocus : Roo.emptyFn,
23707 hideMode:'offsets',
23709 tbContainer : false,
23713 toolbarContainer :function() {
23714 return this.wrap.select('.x-html-editor-tb',true).first();
23718 * Protected method that will not generally be called directly. It
23719 * is called when the editor creates its toolbar. Override this method if you need to
23720 * add custom toolbar buttons.
23721 * @param {HtmlEditor} editor
23723 createToolbar : function(){
23724 Roo.log('renewing');
23725 Roo.log("create toolbars");
23727 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
23728 this.toolbars[0].render(this.toolbarContainer());
23732 // if (!editor.toolbars || !editor.toolbars.length) {
23733 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
23736 // for (var i =0 ; i < editor.toolbars.length;i++) {
23737 // editor.toolbars[i] = Roo.factory(
23738 // typeof(editor.toolbars[i]) == 'string' ?
23739 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
23740 // Roo.bootstrap.HtmlEditor);
23741 // editor.toolbars[i].init(editor);
23747 onRender : function(ct, position)
23749 // Roo.log("Call onRender: " + this.xtype);
23751 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
23753 this.wrap = this.inputEl().wrap({
23754 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
23757 this.editorcore.onRender(ct, position);
23759 if (this.resizable) {
23760 this.resizeEl = new Roo.Resizable(this.wrap, {
23764 minHeight : this.height,
23765 height: this.height,
23766 handles : this.resizable,
23769 resize : function(r, w, h) {
23770 _t.onResize(w,h); // -something
23776 this.createToolbar(this);
23779 if(!this.width && this.resizable){
23780 this.setSize(this.wrap.getSize());
23782 if (this.resizeEl) {
23783 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
23784 // should trigger onReize..
23790 onResize : function(w, h)
23792 Roo.log('resize: ' +w + ',' + h );
23793 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
23797 if(this.inputEl() ){
23798 if(typeof w == 'number'){
23799 var aw = w - this.wrap.getFrameWidth('lr');
23800 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
23803 if(typeof h == 'number'){
23804 var tbh = -11; // fixme it needs to tool bar size!
23805 for (var i =0; i < this.toolbars.length;i++) {
23806 // fixme - ask toolbars for heights?
23807 tbh += this.toolbars[i].el.getHeight();
23808 //if (this.toolbars[i].footer) {
23809 // tbh += this.toolbars[i].footer.el.getHeight();
23817 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
23818 ah -= 5; // knock a few pixes off for look..
23819 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
23823 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
23824 this.editorcore.onResize(ew,eh);
23829 * Toggles the editor between standard and source edit mode.
23830 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
23832 toggleSourceEdit : function(sourceEditMode)
23834 this.editorcore.toggleSourceEdit(sourceEditMode);
23836 if(this.editorcore.sourceEditMode){
23837 Roo.log('editor - showing textarea');
23840 // Roo.log(this.syncValue());
23842 this.inputEl().removeClass(['hide', 'x-hidden']);
23843 this.inputEl().dom.removeAttribute('tabIndex');
23844 this.inputEl().focus();
23846 Roo.log('editor - hiding textarea');
23848 // Roo.log(this.pushValue());
23851 this.inputEl().addClass(['hide', 'x-hidden']);
23852 this.inputEl().dom.setAttribute('tabIndex', -1);
23853 //this.deferFocus();
23856 if(this.resizable){
23857 this.setSize(this.wrap.getSize());
23860 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
23863 // private (for BoxComponent)
23864 adjustSize : Roo.BoxComponent.prototype.adjustSize,
23866 // private (for BoxComponent)
23867 getResizeEl : function(){
23871 // private (for BoxComponent)
23872 getPositionEl : function(){
23877 initEvents : function(){
23878 this.originalValue = this.getValue();
23882 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23885 // markInvalid : Roo.emptyFn,
23887 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23890 // clearInvalid : Roo.emptyFn,
23892 setValue : function(v){
23893 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
23894 this.editorcore.pushValue();
23899 deferFocus : function(){
23900 this.focus.defer(10, this);
23904 focus : function(){
23905 this.editorcore.focus();
23911 onDestroy : function(){
23917 for (var i =0; i < this.toolbars.length;i++) {
23918 // fixme - ask toolbars for heights?
23919 this.toolbars[i].onDestroy();
23922 this.wrap.dom.innerHTML = '';
23923 this.wrap.remove();
23928 onFirstFocus : function(){
23929 //Roo.log("onFirstFocus");
23930 this.editorcore.onFirstFocus();
23931 for (var i =0; i < this.toolbars.length;i++) {
23932 this.toolbars[i].onFirstFocus();
23938 syncValue : function()
23940 this.editorcore.syncValue();
23943 pushValue : function()
23945 this.editorcore.pushValue();
23949 // hide stuff that is not compatible
23963 * @event specialkey
23967 * @cfg {String} fieldClass @hide
23970 * @cfg {String} focusClass @hide
23973 * @cfg {String} autoCreate @hide
23976 * @cfg {String} inputType @hide
23980 * @cfg {String} invalidText @hide
23983 * @cfg {String} msgFx @hide
23986 * @cfg {String} validateOnBlur @hide
23995 Roo.namespace('Roo.bootstrap.htmleditor');
23997 * @class Roo.bootstrap.HtmlEditorToolbar1
24002 new Roo.bootstrap.HtmlEditor({
24005 new Roo.bootstrap.HtmlEditorToolbar1({
24006 disable : { fonts: 1 , format: 1, ..., ... , ...],
24012 * @cfg {Object} disable List of elements to disable..
24013 * @cfg {Array} btns List of additional buttons.
24017 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
24020 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
24023 Roo.apply(this, config);
24025 // default disabled, based on 'good practice'..
24026 this.disable = this.disable || {};
24027 Roo.applyIf(this.disable, {
24030 specialElements : true
24032 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
24034 this.editor = config.editor;
24035 this.editorcore = config.editor.editorcore;
24037 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
24039 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
24040 // dont call parent... till later.
24042 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
24047 editorcore : false,
24052 "h1","h2","h3","h4","h5","h6",
24054 "abbr", "acronym", "address", "cite", "samp", "var",
24058 onRender : function(ct, position)
24060 // Roo.log("Call onRender: " + this.xtype);
24062 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
24064 this.el.dom.style.marginBottom = '0';
24066 var editorcore = this.editorcore;
24067 var editor= this.editor;
24070 var btn = function(id,cmd , toggle, handler, html){
24072 var event = toggle ? 'toggle' : 'click';
24077 xns: Roo.bootstrap,
24081 enableToggle:toggle !== false,
24083 pressed : toggle ? false : null,
24086 a.listeners[toggle ? 'toggle' : 'click'] = function() {
24087 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
24093 // var cb_box = function...
24098 xns: Roo.bootstrap,
24103 xns: Roo.bootstrap,
24107 Roo.each(this.formats, function(f) {
24108 style.menu.items.push({
24110 xns: Roo.bootstrap,
24111 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
24116 editorcore.insertTag(this.tagname);
24123 children.push(style);
24125 btn('bold',false,true);
24126 btn('italic',false,true);
24127 btn('align-left', 'justifyleft',true);
24128 btn('align-center', 'justifycenter',true);
24129 btn('align-right' , 'justifyright',true);
24130 btn('link', false, false, function(btn) {
24131 //Roo.log("create link?");
24132 var url = prompt(this.createLinkText, this.defaultLinkValue);
24133 if(url && url != 'http:/'+'/'){
24134 this.editorcore.relayCmd('createlink', url);
24137 btn('list','insertunorderedlist',true);
24138 btn('pencil', false,true, function(btn){
24140 this.toggleSourceEdit(btn.pressed);
24143 if (this.editor.btns.length > 0) {
24144 for (var i = 0; i<this.editor.btns.length; i++) {
24145 children.push(this.editor.btns[i]);
24153 xns: Roo.bootstrap,
24158 xns: Roo.bootstrap,
24163 cog.menu.items.push({
24165 xns: Roo.bootstrap,
24166 html : Clean styles,
24171 editorcore.insertTag(this.tagname);
24180 this.xtype = 'NavSimplebar';
24182 for(var i=0;i< children.length;i++) {
24184 this.buttons.add(this.addxtypeChild(children[i]));
24188 editor.on('editorevent', this.updateToolbar, this);
24190 onBtnClick : function(id)
24192 this.editorcore.relayCmd(id);
24193 this.editorcore.focus();
24197 * Protected method that will not generally be called directly. It triggers
24198 * a toolbar update by reading the markup state of the current selection in the editor.
24200 updateToolbar: function(){
24202 if(!this.editorcore.activated){
24203 this.editor.onFirstFocus(); // is this neeed?
24207 var btns = this.buttons;
24208 var doc = this.editorcore.doc;
24209 btns.get('bold').setActive(doc.queryCommandState('bold'));
24210 btns.get('italic').setActive(doc.queryCommandState('italic'));
24211 //btns.get('underline').setActive(doc.queryCommandState('underline'));
24213 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
24214 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
24215 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
24217 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
24218 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
24221 var ans = this.editorcore.getAllAncestors();
24222 if (this.formatCombo) {
24225 var store = this.formatCombo.store;
24226 this.formatCombo.setValue("");
24227 for (var i =0; i < ans.length;i++) {
24228 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
24230 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
24238 // hides menus... - so this cant be on a menu...
24239 Roo.bootstrap.MenuMgr.hideAll();
24241 Roo.bootstrap.MenuMgr.hideAll();
24242 //this.editorsyncValue();
24244 onFirstFocus: function() {
24245 this.buttons.each(function(item){
24249 toggleSourceEdit : function(sourceEditMode){
24252 if(sourceEditMode){
24253 Roo.log("disabling buttons");
24254 this.buttons.each( function(item){
24255 if(item.cmd != 'pencil'){
24261 Roo.log("enabling buttons");
24262 if(this.editorcore.initialized){
24263 this.buttons.each( function(item){
24269 Roo.log("calling toggole on editor");
24270 // tell the editor that it's been pressed..
24271 this.editor.toggleSourceEdit(sourceEditMode);
24281 * @class Roo.bootstrap.Table.AbstractSelectionModel
24282 * @extends Roo.util.Observable
24283 * Abstract base class for grid SelectionModels. It provides the interface that should be
24284 * implemented by descendant classes. This class should not be directly instantiated.
24287 Roo.bootstrap.Table.AbstractSelectionModel = function(){
24288 this.locked = false;
24289 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
24293 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
24294 /** @ignore Called by the grid automatically. Do not call directly. */
24295 init : function(grid){
24301 * Locks the selections.
24304 this.locked = true;
24308 * Unlocks the selections.
24310 unlock : function(){
24311 this.locked = false;
24315 * Returns true if the selections are locked.
24316 * @return {Boolean}
24318 isLocked : function(){
24319 return this.locked;
24323 * @extends Roo.bootstrap.Table.AbstractSelectionModel
24324 * @class Roo.bootstrap.Table.RowSelectionModel
24325 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
24326 * It supports multiple selections and keyboard selection/navigation.
24328 * @param {Object} config
24331 Roo.bootstrap.Table.RowSelectionModel = function(config){
24332 Roo.apply(this, config);
24333 this.selections = new Roo.util.MixedCollection(false, function(o){
24338 this.lastActive = false;
24342 * @event selectionchange
24343 * Fires when the selection changes
24344 * @param {SelectionModel} this
24346 "selectionchange" : true,
24348 * @event afterselectionchange
24349 * Fires after the selection changes (eg. by key press or clicking)
24350 * @param {SelectionModel} this
24352 "afterselectionchange" : true,
24354 * @event beforerowselect
24355 * Fires when a row is selected being selected, return false to cancel.
24356 * @param {SelectionModel} this
24357 * @param {Number} rowIndex The selected index
24358 * @param {Boolean} keepExisting False if other selections will be cleared
24360 "beforerowselect" : true,
24363 * Fires when a row is selected.
24364 * @param {SelectionModel} this
24365 * @param {Number} rowIndex The selected index
24366 * @param {Roo.data.Record} r The record
24368 "rowselect" : true,
24370 * @event rowdeselect
24371 * Fires when a row is deselected.
24372 * @param {SelectionModel} this
24373 * @param {Number} rowIndex The selected index
24375 "rowdeselect" : true
24377 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
24378 this.locked = false;
24381 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
24383 * @cfg {Boolean} singleSelect
24384 * True to allow selection of only one row at a time (defaults to false)
24386 singleSelect : false,
24389 initEvents : function()
24392 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
24393 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
24394 //}else{ // allow click to work like normal
24395 // this.grid.on("rowclick", this.handleDragableRowClick, this);
24397 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
24398 this.grid.on("rowclick", this.handleMouseDown, this);
24400 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
24401 "up" : function(e){
24403 this.selectPrevious(e.shiftKey);
24404 }else if(this.last !== false && this.lastActive !== false){
24405 var last = this.last;
24406 this.selectRange(this.last, this.lastActive-1);
24407 this.grid.getView().focusRow(this.lastActive);
24408 if(last !== false){
24412 this.selectFirstRow();
24414 this.fireEvent("afterselectionchange", this);
24416 "down" : function(e){
24418 this.selectNext(e.shiftKey);
24419 }else if(this.last !== false && this.lastActive !== false){
24420 var last = this.last;
24421 this.selectRange(this.last, this.lastActive+1);
24422 this.grid.getView().focusRow(this.lastActive);
24423 if(last !== false){
24427 this.selectFirstRow();
24429 this.fireEvent("afterselectionchange", this);
24433 this.grid.store.on('load', function(){
24434 this.selections.clear();
24437 var view = this.grid.view;
24438 view.on("refresh", this.onRefresh, this);
24439 view.on("rowupdated", this.onRowUpdated, this);
24440 view.on("rowremoved", this.onRemove, this);
24445 onRefresh : function()
24447 var ds = this.grid.store, i, v = this.grid.view;
24448 var s = this.selections;
24449 s.each(function(r){
24450 if((i = ds.indexOfId(r.id)) != -1){
24459 onRemove : function(v, index, r){
24460 this.selections.remove(r);
24464 onRowUpdated : function(v, index, r){
24465 if(this.isSelected(r)){
24466 v.onRowSelect(index);
24472 * @param {Array} records The records to select
24473 * @param {Boolean} keepExisting (optional) True to keep existing selections
24475 selectRecords : function(records, keepExisting)
24478 this.clearSelections();
24480 var ds = this.grid.store;
24481 for(var i = 0, len = records.length; i < len; i++){
24482 this.selectRow(ds.indexOf(records[i]), true);
24487 * Gets the number of selected rows.
24490 getCount : function(){
24491 return this.selections.length;
24495 * Selects the first row in the grid.
24497 selectFirstRow : function(){
24502 * Select the last row.
24503 * @param {Boolean} keepExisting (optional) True to keep existing selections
24505 selectLastRow : function(keepExisting){
24506 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
24507 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
24511 * Selects the row immediately following the last selected row.
24512 * @param {Boolean} keepExisting (optional) True to keep existing selections
24514 selectNext : function(keepExisting)
24516 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
24517 this.selectRow(this.last+1, keepExisting);
24518 this.grid.getView().focusRow(this.last);
24523 * Selects the row that precedes the last selected row.
24524 * @param {Boolean} keepExisting (optional) True to keep existing selections
24526 selectPrevious : function(keepExisting){
24528 this.selectRow(this.last-1, keepExisting);
24529 this.grid.getView().focusRow(this.last);
24534 * Returns the selected records
24535 * @return {Array} Array of selected records
24537 getSelections : function(){
24538 return [].concat(this.selections.items);
24542 * Returns the first selected record.
24545 getSelected : function(){
24546 return this.selections.itemAt(0);
24551 * Clears all selections.
24553 clearSelections : function(fast)
24559 var ds = this.grid.store;
24560 var s = this.selections;
24561 s.each(function(r){
24562 this.deselectRow(ds.indexOfId(r.id));
24566 this.selections.clear();
24573 * Selects all rows.
24575 selectAll : function(){
24579 this.selections.clear();
24580 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
24581 this.selectRow(i, true);
24586 * Returns True if there is a selection.
24587 * @return {Boolean}
24589 hasSelection : function(){
24590 return this.selections.length > 0;
24594 * Returns True if the specified row is selected.
24595 * @param {Number/Record} record The record or index of the record to check
24596 * @return {Boolean}
24598 isSelected : function(index){
24599 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
24600 return (r && this.selections.key(r.id) ? true : false);
24604 * Returns True if the specified record id is selected.
24605 * @param {String} id The id of record to check
24606 * @return {Boolean}
24608 isIdSelected : function(id){
24609 return (this.selections.key(id) ? true : false);
24614 handleMouseDBClick : function(e, t){
24618 handleMouseDown : function(e, t)
24620 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
24621 if(this.isLocked() || rowIndex < 0 ){
24624 if(e.shiftKey && this.last !== false){
24625 var last = this.last;
24626 this.selectRange(last, rowIndex, e.ctrlKey);
24627 this.last = last; // reset the last
24631 var isSelected = this.isSelected(rowIndex);
24632 //Roo.log("select row:" + rowIndex);
24634 this.deselectRow(rowIndex);
24636 this.selectRow(rowIndex, true);
24640 if(e.button !== 0 && isSelected){
24641 alert('rowIndex 2: ' + rowIndex);
24642 view.focusRow(rowIndex);
24643 }else if(e.ctrlKey && isSelected){
24644 this.deselectRow(rowIndex);
24645 }else if(!isSelected){
24646 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
24647 view.focusRow(rowIndex);
24651 this.fireEvent("afterselectionchange", this);
24654 handleDragableRowClick : function(grid, rowIndex, e)
24656 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
24657 this.selectRow(rowIndex, false);
24658 grid.view.focusRow(rowIndex);
24659 this.fireEvent("afterselectionchange", this);
24664 * Selects multiple rows.
24665 * @param {Array} rows Array of the indexes of the row to select
24666 * @param {Boolean} keepExisting (optional) True to keep existing selections
24668 selectRows : function(rows, keepExisting){
24670 this.clearSelections();
24672 for(var i = 0, len = rows.length; i < len; i++){
24673 this.selectRow(rows[i], true);
24678 * Selects a range of rows. All rows in between startRow and endRow are also selected.
24679 * @param {Number} startRow The index of the first row in the range
24680 * @param {Number} endRow The index of the last row in the range
24681 * @param {Boolean} keepExisting (optional) True to retain existing selections
24683 selectRange : function(startRow, endRow, keepExisting){
24688 this.clearSelections();
24690 if(startRow <= endRow){
24691 for(var i = startRow; i <= endRow; i++){
24692 this.selectRow(i, true);
24695 for(var i = startRow; i >= endRow; i--){
24696 this.selectRow(i, true);
24702 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
24703 * @param {Number} startRow The index of the first row in the range
24704 * @param {Number} endRow The index of the last row in the range
24706 deselectRange : function(startRow, endRow, preventViewNotify){
24710 for(var i = startRow; i <= endRow; i++){
24711 this.deselectRow(i, preventViewNotify);
24717 * @param {Number} row The index of the row to select
24718 * @param {Boolean} keepExisting (optional) True to keep existing selections
24720 selectRow : function(index, keepExisting, preventViewNotify)
24722 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
24725 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
24726 if(!keepExisting || this.singleSelect){
24727 this.clearSelections();
24730 var r = this.grid.store.getAt(index);
24731 //console.log('selectRow - record id :' + r.id);
24733 this.selections.add(r);
24734 this.last = this.lastActive = index;
24735 if(!preventViewNotify){
24736 var proxy = new Roo.Element(
24737 this.grid.getRowDom(index)
24739 proxy.addClass('bg-info info');
24741 this.fireEvent("rowselect", this, index, r);
24742 this.fireEvent("selectionchange", this);
24748 * @param {Number} row The index of the row to deselect
24750 deselectRow : function(index, preventViewNotify)
24755 if(this.last == index){
24758 if(this.lastActive == index){
24759 this.lastActive = false;
24762 var r = this.grid.store.getAt(index);
24767 this.selections.remove(r);
24768 //.console.log('deselectRow - record id :' + r.id);
24769 if(!preventViewNotify){
24771 var proxy = new Roo.Element(
24772 this.grid.getRowDom(index)
24774 proxy.removeClass('bg-info info');
24776 this.fireEvent("rowdeselect", this, index);
24777 this.fireEvent("selectionchange", this);
24781 restoreLast : function(){
24783 this.last = this._last;
24788 acceptsNav : function(row, col, cm){
24789 return !cm.isHidden(col) && cm.isCellEditable(col, row);
24793 onEditorKey : function(field, e){
24794 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
24799 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
24801 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
24803 }else if(k == e.ENTER && !e.ctrlKey){
24807 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
24809 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
24811 }else if(k == e.ESC){
24815 g.startEditing(newCell[0], newCell[1]);
24821 * Ext JS Library 1.1.1
24822 * Copyright(c) 2006-2007, Ext JS, LLC.
24824 * Originally Released Under LGPL - original licence link has changed is not relivant.
24827 * <script type="text/javascript">
24831 * @class Roo.bootstrap.PagingToolbar
24832 * @extends Roo.bootstrap.NavSimplebar
24833 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
24835 * Create a new PagingToolbar
24836 * @param {Object} config The config object
24837 * @param {Roo.data.Store} store
24839 Roo.bootstrap.PagingToolbar = function(config)
24841 // old args format still supported... - xtype is prefered..
24842 // created from xtype...
24844 this.ds = config.dataSource;
24846 if (config.store && !this.ds) {
24847 this.store= Roo.factory(config.store, Roo.data);
24848 this.ds = this.store;
24849 this.ds.xmodule = this.xmodule || false;
24852 this.toolbarItems = [];
24853 if (config.items) {
24854 this.toolbarItems = config.items;
24857 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
24862 this.bind(this.ds);
24865 if (Roo.bootstrap.version == 4) {
24866 this.navgroup = new Roo.bootstrap.ButtonGroup({ cls: 'pagination' });
24868 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
24873 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
24875 * @cfg {Roo.data.Store} dataSource
24876 * The underlying data store providing the paged data
24879 * @cfg {String/HTMLElement/Element} container
24880 * container The id or element that will contain the toolbar
24883 * @cfg {Boolean} displayInfo
24884 * True to display the displayMsg (defaults to false)
24887 * @cfg {Number} pageSize
24888 * The number of records to display per page (defaults to 20)
24892 * @cfg {String} displayMsg
24893 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
24895 displayMsg : 'Displaying {0} - {1} of {2}',
24897 * @cfg {String} emptyMsg
24898 * The message to display when no records are found (defaults to "No data to display")
24900 emptyMsg : 'No data to display',
24902 * Customizable piece of the default paging text (defaults to "Page")
24905 beforePageText : "Page",
24907 * Customizable piece of the default paging text (defaults to "of %0")
24910 afterPageText : "of {0}",
24912 * Customizable piece of the default paging text (defaults to "First Page")
24915 firstText : "First Page",
24917 * Customizable piece of the default paging text (defaults to "Previous Page")
24920 prevText : "Previous Page",
24922 * Customizable piece of the default paging text (defaults to "Next Page")
24925 nextText : "Next Page",
24927 * Customizable piece of the default paging text (defaults to "Last Page")
24930 lastText : "Last Page",
24932 * Customizable piece of the default paging text (defaults to "Refresh")
24935 refreshText : "Refresh",
24939 onRender : function(ct, position)
24941 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
24942 this.navgroup.parentId = this.id;
24943 this.navgroup.onRender(this.el, null);
24944 // add the buttons to the navgroup
24946 if(this.displayInfo){
24947 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
24948 this.displayEl = this.el.select('.x-paging-info', true).first();
24949 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
24950 // this.displayEl = navel.el.select('span',true).first();
24956 Roo.each(_this.buttons, function(e){ // this might need to use render????
24957 Roo.factory(e).render(_this.el);
24961 Roo.each(_this.toolbarItems, function(e) {
24962 _this.navgroup.addItem(e);
24966 this.first = this.navgroup.addItem({
24967 tooltip: this.firstText,
24968 cls: "prev btn-outline-secondary",
24969 html : ' <i class="fa fa-step-backward"></i>',
24971 preventDefault: true,
24972 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
24975 this.prev = this.navgroup.addItem({
24976 tooltip: this.prevText,
24977 cls: "prev btn-outline-secondary",
24978 html : ' <i class="fa fa-backward"></i>',
24980 preventDefault: true,
24981 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
24983 //this.addSeparator();
24986 var field = this.navgroup.addItem( {
24988 cls : 'x-paging-position btn-outline-secondary',
24990 html : this.beforePageText +
24991 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
24992 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
24995 this.field = field.el.select('input', true).first();
24996 this.field.on("keydown", this.onPagingKeydown, this);
24997 this.field.on("focus", function(){this.dom.select();});
25000 this.afterTextEl = field.el.select('.x-paging-after',true).first();
25001 //this.field.setHeight(18);
25002 //this.addSeparator();
25003 this.next = this.navgroup.addItem({
25004 tooltip: this.nextText,
25005 cls: "next btn-outline-secondary",
25006 html : ' <i class="fa fa-forward"></i>',
25008 preventDefault: true,
25009 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
25011 this.last = this.navgroup.addItem({
25012 tooltip: this.lastText,
25013 html : ' <i class="fa fa-step-forward"></i>',
25014 cls: "next btn-outline-secondary",
25016 preventDefault: true,
25017 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
25019 //this.addSeparator();
25020 this.loading = this.navgroup.addItem({
25021 tooltip: this.refreshText,
25022 cls: "btn-outline-secondary",
25023 html : ' <i class="fa fa-refresh"></i>',
25024 preventDefault: true,
25025 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
25031 updateInfo : function(){
25032 if(this.displayEl){
25033 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
25034 var msg = count == 0 ?
25038 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
25040 this.displayEl.update(msg);
25045 onLoad : function(ds, r, o)
25047 this.cursor = o.params.start ? o.params.start : 0;
25049 var d = this.getPageData(),
25054 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
25055 this.field.dom.value = ap;
25056 this.first.setDisabled(ap == 1);
25057 this.prev.setDisabled(ap == 1);
25058 this.next.setDisabled(ap == ps);
25059 this.last.setDisabled(ap == ps);
25060 this.loading.enable();
25065 getPageData : function(){
25066 var total = this.ds.getTotalCount();
25069 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
25070 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
25075 onLoadError : function(){
25076 this.loading.enable();
25080 onPagingKeydown : function(e){
25081 var k = e.getKey();
25082 var d = this.getPageData();
25084 var v = this.field.dom.value, pageNum;
25085 if(!v || isNaN(pageNum = parseInt(v, 10))){
25086 this.field.dom.value = d.activePage;
25089 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
25090 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
25093 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))
25095 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
25096 this.field.dom.value = pageNum;
25097 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
25100 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
25102 var v = this.field.dom.value, pageNum;
25103 var increment = (e.shiftKey) ? 10 : 1;
25104 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
25107 if(!v || isNaN(pageNum = parseInt(v, 10))) {
25108 this.field.dom.value = d.activePage;
25111 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
25113 this.field.dom.value = parseInt(v, 10) + increment;
25114 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
25115 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
25122 beforeLoad : function(){
25124 this.loading.disable();
25129 onClick : function(which){
25138 ds.load({params:{start: 0, limit: this.pageSize}});
25141 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
25144 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
25147 var total = ds.getTotalCount();
25148 var extra = total % this.pageSize;
25149 var lastStart = extra ? (total - extra) : total-this.pageSize;
25150 ds.load({params:{start: lastStart, limit: this.pageSize}});
25153 ds.load({params:{start: this.cursor, limit: this.pageSize}});
25159 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
25160 * @param {Roo.data.Store} store The data store to unbind
25162 unbind : function(ds){
25163 ds.un("beforeload", this.beforeLoad, this);
25164 ds.un("load", this.onLoad, this);
25165 ds.un("loadexception", this.onLoadError, this);
25166 ds.un("remove", this.updateInfo, this);
25167 ds.un("add", this.updateInfo, this);
25168 this.ds = undefined;
25172 * Binds the paging toolbar to the specified {@link Roo.data.Store}
25173 * @param {Roo.data.Store} store The data store to bind
25175 bind : function(ds){
25176 ds.on("beforeload", this.beforeLoad, this);
25177 ds.on("load", this.onLoad, this);
25178 ds.on("loadexception", this.onLoadError, this);
25179 ds.on("remove", this.updateInfo, this);
25180 ds.on("add", this.updateInfo, this);
25191 * @class Roo.bootstrap.MessageBar
25192 * @extends Roo.bootstrap.Component
25193 * Bootstrap MessageBar class
25194 * @cfg {String} html contents of the MessageBar
25195 * @cfg {String} weight (info | success | warning | danger) default info
25196 * @cfg {String} beforeClass insert the bar before the given class
25197 * @cfg {Boolean} closable (true | false) default false
25198 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
25201 * Create a new Element
25202 * @param {Object} config The config object
25205 Roo.bootstrap.MessageBar = function(config){
25206 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
25209 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
25215 beforeClass: 'bootstrap-sticky-wrap',
25217 getAutoCreate : function(){
25221 cls: 'alert alert-dismissable alert-' + this.weight,
25226 html: this.html || ''
25232 cfg.cls += ' alert-messages-fixed';
25246 onRender : function(ct, position)
25248 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
25251 var cfg = Roo.apply({}, this.getAutoCreate());
25255 cfg.cls += ' ' + this.cls;
25258 cfg.style = this.style;
25260 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
25262 this.el.setVisibilityMode(Roo.Element.DISPLAY);
25265 this.el.select('>button.close').on('click', this.hide, this);
25271 if (!this.rendered) {
25277 this.fireEvent('show', this);
25283 if (!this.rendered) {
25289 this.fireEvent('hide', this);
25292 update : function()
25294 // var e = this.el.dom.firstChild;
25296 // if(this.closable){
25297 // e = e.nextSibling;
25300 // e.data = this.html || '';
25302 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
25318 * @class Roo.bootstrap.Graph
25319 * @extends Roo.bootstrap.Component
25320 * Bootstrap Graph class
25324 @cfg {String} graphtype bar | vbar | pie
25325 @cfg {number} g_x coodinator | centre x (pie)
25326 @cfg {number} g_y coodinator | centre y (pie)
25327 @cfg {number} g_r radius (pie)
25328 @cfg {number} g_height height of the chart (respected by all elements in the set)
25329 @cfg {number} g_width width of the chart (respected by all elements in the set)
25330 @cfg {Object} title The title of the chart
25333 -opts (object) options for the chart
25335 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
25336 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
25338 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.
25339 o stacked (boolean) whether or not to tread values as in a stacked bar chart
25341 o stretch (boolean)
25343 -opts (object) options for the pie
25346 o startAngle (number)
25347 o endAngle (number)
25351 * Create a new Input
25352 * @param {Object} config The config object
25355 Roo.bootstrap.Graph = function(config){
25356 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
25362 * The img click event for the img.
25363 * @param {Roo.EventObject} e
25369 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
25380 //g_colors: this.colors,
25387 getAutoCreate : function(){
25398 onRender : function(ct,position){
25401 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
25403 if (typeof(Raphael) == 'undefined') {
25404 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
25408 this.raphael = Raphael(this.el.dom);
25410 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25411 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25412 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25413 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
25415 r.text(160, 10, "Single Series Chart").attr(txtattr);
25416 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
25417 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
25418 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
25420 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
25421 r.barchart(330, 10, 300, 220, data1);
25422 r.barchart(10, 250, 300, 220, data2, {stacked: true});
25423 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
25426 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25427 // r.barchart(30, 30, 560, 250, xdata, {
25428 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
25429 // axis : "0 0 1 1",
25430 // axisxlabels : xdata
25431 // //yvalues : cols,
25434 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25436 // this.load(null,xdata,{
25437 // axis : "0 0 1 1",
25438 // axisxlabels : xdata
25443 load : function(graphtype,xdata,opts)
25445 this.raphael.clear();
25447 graphtype = this.graphtype;
25452 var r = this.raphael,
25453 fin = function () {
25454 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
25456 fout = function () {
25457 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
25459 pfin = function() {
25460 this.sector.stop();
25461 this.sector.scale(1.1, 1.1, this.cx, this.cy);
25464 this.label[0].stop();
25465 this.label[0].attr({ r: 7.5 });
25466 this.label[1].attr({ "font-weight": 800 });
25469 pfout = function() {
25470 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
25473 this.label[0].animate({ r: 5 }, 500, "bounce");
25474 this.label[1].attr({ "font-weight": 400 });
25480 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25483 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25486 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
25487 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
25489 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
25496 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
25501 setTitle: function(o)
25506 initEvents: function() {
25509 this.el.on('click', this.onClick, this);
25513 onClick : function(e)
25515 Roo.log('img onclick');
25516 this.fireEvent('click', this, e);
25528 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25531 * @class Roo.bootstrap.dash.NumberBox
25532 * @extends Roo.bootstrap.Component
25533 * Bootstrap NumberBox class
25534 * @cfg {String} headline Box headline
25535 * @cfg {String} content Box content
25536 * @cfg {String} icon Box icon
25537 * @cfg {String} footer Footer text
25538 * @cfg {String} fhref Footer href
25541 * Create a new NumberBox
25542 * @param {Object} config The config object
25546 Roo.bootstrap.dash.NumberBox = function(config){
25547 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
25551 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
25560 getAutoCreate : function(){
25564 cls : 'small-box ',
25572 cls : 'roo-headline',
25573 html : this.headline
25577 cls : 'roo-content',
25578 html : this.content
25592 cls : 'ion ' + this.icon
25601 cls : 'small-box-footer',
25602 href : this.fhref || '#',
25606 cfg.cn.push(footer);
25613 onRender : function(ct,position){
25614 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
25621 setHeadline: function (value)
25623 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
25626 setFooter: function (value, href)
25628 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
25631 this.el.select('a.small-box-footer',true).first().attr('href', href);
25636 setContent: function (value)
25638 this.el.select('.roo-content',true).first().dom.innerHTML = value;
25641 initEvents: function()
25655 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25658 * @class Roo.bootstrap.dash.TabBox
25659 * @extends Roo.bootstrap.Component
25660 * Bootstrap TabBox class
25661 * @cfg {String} title Title of the TabBox
25662 * @cfg {String} icon Icon of the TabBox
25663 * @cfg {Boolean} showtabs (true|false) show the tabs default true
25664 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
25667 * Create a new TabBox
25668 * @param {Object} config The config object
25672 Roo.bootstrap.dash.TabBox = function(config){
25673 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
25678 * When a pane is added
25679 * @param {Roo.bootstrap.dash.TabPane} pane
25683 * @event activatepane
25684 * When a pane is activated
25685 * @param {Roo.bootstrap.dash.TabPane} pane
25687 "activatepane" : true
25695 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
25700 tabScrollable : false,
25702 getChildContainer : function()
25704 return this.el.select('.tab-content', true).first();
25707 getAutoCreate : function(){
25711 cls: 'pull-left header',
25719 cls: 'fa ' + this.icon
25725 cls: 'nav nav-tabs pull-right',
25731 if(this.tabScrollable){
25738 cls: 'nav nav-tabs pull-right',
25749 cls: 'nav-tabs-custom',
25754 cls: 'tab-content no-padding',
25762 initEvents : function()
25764 //Roo.log('add add pane handler');
25765 this.on('addpane', this.onAddPane, this);
25768 * Updates the box title
25769 * @param {String} html to set the title to.
25771 setTitle : function(value)
25773 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
25775 onAddPane : function(pane)
25777 this.panes.push(pane);
25778 //Roo.log('addpane');
25780 // tabs are rendere left to right..
25781 if(!this.showtabs){
25785 var ctr = this.el.select('.nav-tabs', true).first();
25788 var existing = ctr.select('.nav-tab',true);
25789 var qty = existing.getCount();;
25792 var tab = ctr.createChild({
25794 cls : 'nav-tab' + (qty ? '' : ' active'),
25802 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
25805 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
25807 pane.el.addClass('active');
25812 onTabClick : function(ev,un,ob,pane)
25814 //Roo.log('tab - prev default');
25815 ev.preventDefault();
25818 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
25819 pane.tab.addClass('active');
25820 //Roo.log(pane.title);
25821 this.getChildContainer().select('.tab-pane',true).removeClass('active');
25822 // technically we should have a deactivate event.. but maybe add later.
25823 // and it should not de-activate the selected tab...
25824 this.fireEvent('activatepane', pane);
25825 pane.el.addClass('active');
25826 pane.fireEvent('activate');
25831 getActivePane : function()
25834 Roo.each(this.panes, function(p) {
25835 if(p.el.hasClass('active')){
25856 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25858 * @class Roo.bootstrap.TabPane
25859 * @extends Roo.bootstrap.Component
25860 * Bootstrap TabPane class
25861 * @cfg {Boolean} active (false | true) Default false
25862 * @cfg {String} title title of panel
25866 * Create a new TabPane
25867 * @param {Object} config The config object
25870 Roo.bootstrap.dash.TabPane = function(config){
25871 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
25877 * When a pane is activated
25878 * @param {Roo.bootstrap.dash.TabPane} pane
25885 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
25890 // the tabBox that this is attached to.
25893 getAutoCreate : function()
25901 cfg.cls += ' active';
25906 initEvents : function()
25908 //Roo.log('trigger add pane handler');
25909 this.parent().fireEvent('addpane', this)
25913 * Updates the tab title
25914 * @param {String} html to set the title to.
25916 setTitle: function(str)
25922 this.tab.select('a', true).first().dom.innerHTML = str;
25939 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25942 * @class Roo.bootstrap.menu.Menu
25943 * @extends Roo.bootstrap.Component
25944 * Bootstrap Menu class - container for Menu
25945 * @cfg {String} html Text of the menu
25946 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
25947 * @cfg {String} icon Font awesome icon
25948 * @cfg {String} pos Menu align to (top | bottom) default bottom
25952 * Create a new Menu
25953 * @param {Object} config The config object
25957 Roo.bootstrap.menu.Menu = function(config){
25958 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
25962 * @event beforeshow
25963 * Fires before this menu is displayed
25964 * @param {Roo.bootstrap.menu.Menu} this
25968 * @event beforehide
25969 * Fires before this menu is hidden
25970 * @param {Roo.bootstrap.menu.Menu} this
25975 * Fires after this menu is displayed
25976 * @param {Roo.bootstrap.menu.Menu} this
25981 * Fires after this menu is hidden
25982 * @param {Roo.bootstrap.menu.Menu} this
25987 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
25988 * @param {Roo.bootstrap.menu.Menu} this
25989 * @param {Roo.EventObject} e
25996 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
26000 weight : 'default',
26005 getChildContainer : function() {
26006 if(this.isSubMenu){
26010 return this.el.select('ul.dropdown-menu', true).first();
26013 getAutoCreate : function()
26018 cls : 'roo-menu-text',
26026 cls : 'fa ' + this.icon
26037 cls : 'dropdown-button btn btn-' + this.weight,
26042 cls : 'dropdown-toggle btn btn-' + this.weight,
26052 cls : 'dropdown-menu'
26058 if(this.pos == 'top'){
26059 cfg.cls += ' dropup';
26062 if(this.isSubMenu){
26065 cls : 'dropdown-menu'
26072 onRender : function(ct, position)
26074 this.isSubMenu = ct.hasClass('dropdown-submenu');
26076 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
26079 initEvents : function()
26081 if(this.isSubMenu){
26085 this.hidden = true;
26087 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
26088 this.triggerEl.on('click', this.onTriggerPress, this);
26090 this.buttonEl = this.el.select('button.dropdown-button', true).first();
26091 this.buttonEl.on('click', this.onClick, this);
26097 if(this.isSubMenu){
26101 return this.el.select('ul.dropdown-menu', true).first();
26104 onClick : function(e)
26106 this.fireEvent("click", this, e);
26109 onTriggerPress : function(e)
26111 if (this.isVisible()) {
26118 isVisible : function(){
26119 return !this.hidden;
26124 this.fireEvent("beforeshow", this);
26126 this.hidden = false;
26127 this.el.addClass('open');
26129 Roo.get(document).on("mouseup", this.onMouseUp, this);
26131 this.fireEvent("show", this);
26138 this.fireEvent("beforehide", this);
26140 this.hidden = true;
26141 this.el.removeClass('open');
26143 Roo.get(document).un("mouseup", this.onMouseUp);
26145 this.fireEvent("hide", this);
26148 onMouseUp : function()
26162 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
26165 * @class Roo.bootstrap.menu.Item
26166 * @extends Roo.bootstrap.Component
26167 * Bootstrap MenuItem class
26168 * @cfg {Boolean} submenu (true | false) default false
26169 * @cfg {String} html text of the item
26170 * @cfg {String} href the link
26171 * @cfg {Boolean} disable (true | false) default false
26172 * @cfg {Boolean} preventDefault (true | false) default true
26173 * @cfg {String} icon Font awesome icon
26174 * @cfg {String} pos Submenu align to (left | right) default right
26178 * Create a new Item
26179 * @param {Object} config The config object
26183 Roo.bootstrap.menu.Item = function(config){
26184 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
26188 * Fires when the mouse is hovering over this menu
26189 * @param {Roo.bootstrap.menu.Item} this
26190 * @param {Roo.EventObject} e
26195 * Fires when the mouse exits this menu
26196 * @param {Roo.bootstrap.menu.Item} this
26197 * @param {Roo.EventObject} e
26203 * The raw click event for the entire grid.
26204 * @param {Roo.EventObject} e
26210 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
26215 preventDefault: true,
26220 getAutoCreate : function()
26225 cls : 'roo-menu-item-text',
26233 cls : 'fa ' + this.icon
26242 href : this.href || '#',
26249 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
26253 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
26255 if(this.pos == 'left'){
26256 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
26263 initEvents : function()
26265 this.el.on('mouseover', this.onMouseOver, this);
26266 this.el.on('mouseout', this.onMouseOut, this);
26268 this.el.select('a', true).first().on('click', this.onClick, this);
26272 onClick : function(e)
26274 if(this.preventDefault){
26275 e.preventDefault();
26278 this.fireEvent("click", this, e);
26281 onMouseOver : function(e)
26283 if(this.submenu && this.pos == 'left'){
26284 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
26287 this.fireEvent("mouseover", this, e);
26290 onMouseOut : function(e)
26292 this.fireEvent("mouseout", this, e);
26304 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
26307 * @class Roo.bootstrap.menu.Separator
26308 * @extends Roo.bootstrap.Component
26309 * Bootstrap Separator class
26312 * Create a new Separator
26313 * @param {Object} config The config object
26317 Roo.bootstrap.menu.Separator = function(config){
26318 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
26321 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
26323 getAutoCreate : function(){
26344 * @class Roo.bootstrap.Tooltip
26345 * Bootstrap Tooltip class
26346 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
26347 * to determine which dom element triggers the tooltip.
26349 * It needs to add support for additional attributes like tooltip-position
26352 * Create a new Toolti
26353 * @param {Object} config The config object
26356 Roo.bootstrap.Tooltip = function(config){
26357 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
26359 this.alignment = Roo.bootstrap.Tooltip.alignment;
26361 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
26362 this.alignment = config.alignment;
26367 Roo.apply(Roo.bootstrap.Tooltip, {
26369 * @function init initialize tooltip monitoring.
26373 currentTip : false,
26374 currentRegion : false,
26380 Roo.get(document).on('mouseover', this.enter ,this);
26381 Roo.get(document).on('mouseout', this.leave, this);
26384 this.currentTip = new Roo.bootstrap.Tooltip();
26387 enter : function(ev)
26389 var dom = ev.getTarget();
26391 //Roo.log(['enter',dom]);
26392 var el = Roo.fly(dom);
26393 if (this.currentEl) {
26395 //Roo.log(this.currentEl);
26396 //Roo.log(this.currentEl.contains(dom));
26397 if (this.currentEl == el) {
26400 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
26406 if (this.currentTip.el) {
26407 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
26411 if(!el || el.dom == document){
26417 // you can not look for children, as if el is the body.. then everythign is the child..
26418 if (!el.attr('tooltip')) { //
26419 if (!el.select("[tooltip]").elements.length) {
26422 // is the mouse over this child...?
26423 bindEl = el.select("[tooltip]").first();
26424 var xy = ev.getXY();
26425 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
26426 //Roo.log("not in region.");
26429 //Roo.log("child element over..");
26432 this.currentEl = bindEl;
26433 this.currentTip.bind(bindEl);
26434 this.currentRegion = Roo.lib.Region.getRegion(dom);
26435 this.currentTip.enter();
26438 leave : function(ev)
26440 var dom = ev.getTarget();
26441 //Roo.log(['leave',dom]);
26442 if (!this.currentEl) {
26447 if (dom != this.currentEl.dom) {
26450 var xy = ev.getXY();
26451 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
26454 // only activate leave if mouse cursor is outside... bounding box..
26459 if (this.currentTip) {
26460 this.currentTip.leave();
26462 //Roo.log('clear currentEl');
26463 this.currentEl = false;
26468 'left' : ['r-l', [-2,0], 'right'],
26469 'right' : ['l-r', [2,0], 'left'],
26470 'bottom' : ['t-b', [0,2], 'top'],
26471 'top' : [ 'b-t', [0,-2], 'bottom']
26477 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
26482 delay : null, // can be { show : 300 , hide: 500}
26486 hoverState : null, //???
26488 placement : 'bottom',
26492 getAutoCreate : function(){
26499 cls : 'tooltip-arrow'
26502 cls : 'tooltip-inner'
26509 bind : function(el)
26515 enter : function () {
26517 if (this.timeout != null) {
26518 clearTimeout(this.timeout);
26521 this.hoverState = 'in';
26522 //Roo.log("enter - show");
26523 if (!this.delay || !this.delay.show) {
26528 this.timeout = setTimeout(function () {
26529 if (_t.hoverState == 'in') {
26532 }, this.delay.show);
26536 clearTimeout(this.timeout);
26538 this.hoverState = 'out';
26539 if (!this.delay || !this.delay.hide) {
26545 this.timeout = setTimeout(function () {
26546 //Roo.log("leave - timeout");
26548 if (_t.hoverState == 'out') {
26550 Roo.bootstrap.Tooltip.currentEl = false;
26555 show : function (msg)
26558 this.render(document.body);
26561 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
26563 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
26565 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
26567 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
26569 var placement = typeof this.placement == 'function' ?
26570 this.placement.call(this, this.el, on_el) :
26573 var autoToken = /\s?auto?\s?/i;
26574 var autoPlace = autoToken.test(placement);
26576 placement = placement.replace(autoToken, '') || 'top';
26580 //this.el.setXY([0,0]);
26582 //this.el.dom.style.display='block';
26584 //this.el.appendTo(on_el);
26586 var p = this.getPosition();
26587 var box = this.el.getBox();
26593 var align = this.alignment[placement];
26595 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
26597 if(placement == 'top' || placement == 'bottom'){
26599 placement = 'right';
26602 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
26603 placement = 'left';
26606 var scroll = Roo.select('body', true).first().getScroll();
26608 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
26612 align = this.alignment[placement];
26615 this.el.alignTo(this.bindEl, align[0],align[1]);
26616 //var arrow = this.el.select('.arrow',true).first();
26617 //arrow.set(align[2],
26619 this.el.addClass(placement);
26621 this.el.addClass('in fade');
26623 this.hoverState = null;
26625 if (this.el.hasClass('fade')) {
26636 //this.el.setXY([0,0]);
26637 this.el.removeClass('in');
26653 * @class Roo.bootstrap.LocationPicker
26654 * @extends Roo.bootstrap.Component
26655 * Bootstrap LocationPicker class
26656 * @cfg {Number} latitude Position when init default 0
26657 * @cfg {Number} longitude Position when init default 0
26658 * @cfg {Number} zoom default 15
26659 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
26660 * @cfg {Boolean} mapTypeControl default false
26661 * @cfg {Boolean} disableDoubleClickZoom default false
26662 * @cfg {Boolean} scrollwheel default true
26663 * @cfg {Boolean} streetViewControl default false
26664 * @cfg {Number} radius default 0
26665 * @cfg {String} locationName
26666 * @cfg {Boolean} draggable default true
26667 * @cfg {Boolean} enableAutocomplete default false
26668 * @cfg {Boolean} enableReverseGeocode default true
26669 * @cfg {String} markerTitle
26672 * Create a new LocationPicker
26673 * @param {Object} config The config object
26677 Roo.bootstrap.LocationPicker = function(config){
26679 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
26684 * Fires when the picker initialized.
26685 * @param {Roo.bootstrap.LocationPicker} this
26686 * @param {Google Location} location
26690 * @event positionchanged
26691 * Fires when the picker position changed.
26692 * @param {Roo.bootstrap.LocationPicker} this
26693 * @param {Google Location} location
26695 positionchanged : true,
26698 * Fires when the map resize.
26699 * @param {Roo.bootstrap.LocationPicker} this
26704 * Fires when the map show.
26705 * @param {Roo.bootstrap.LocationPicker} this
26710 * Fires when the map hide.
26711 * @param {Roo.bootstrap.LocationPicker} this
26716 * Fires when click the map.
26717 * @param {Roo.bootstrap.LocationPicker} this
26718 * @param {Map event} e
26722 * @event mapRightClick
26723 * Fires when right click the map.
26724 * @param {Roo.bootstrap.LocationPicker} this
26725 * @param {Map event} e
26727 mapRightClick : true,
26729 * @event markerClick
26730 * Fires when click the marker.
26731 * @param {Roo.bootstrap.LocationPicker} this
26732 * @param {Map event} e
26734 markerClick : true,
26736 * @event markerRightClick
26737 * Fires when right click the marker.
26738 * @param {Roo.bootstrap.LocationPicker} this
26739 * @param {Map event} e
26741 markerRightClick : true,
26743 * @event OverlayViewDraw
26744 * Fires when OverlayView Draw
26745 * @param {Roo.bootstrap.LocationPicker} this
26747 OverlayViewDraw : true,
26749 * @event OverlayViewOnAdd
26750 * Fires when OverlayView Draw
26751 * @param {Roo.bootstrap.LocationPicker} this
26753 OverlayViewOnAdd : true,
26755 * @event OverlayViewOnRemove
26756 * Fires when OverlayView Draw
26757 * @param {Roo.bootstrap.LocationPicker} this
26759 OverlayViewOnRemove : true,
26761 * @event OverlayViewShow
26762 * Fires when OverlayView Draw
26763 * @param {Roo.bootstrap.LocationPicker} this
26764 * @param {Pixel} cpx
26766 OverlayViewShow : true,
26768 * @event OverlayViewHide
26769 * Fires when OverlayView Draw
26770 * @param {Roo.bootstrap.LocationPicker} this
26772 OverlayViewHide : true,
26774 * @event loadexception
26775 * Fires when load google lib failed.
26776 * @param {Roo.bootstrap.LocationPicker} this
26778 loadexception : true
26783 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
26785 gMapContext: false,
26791 mapTypeControl: false,
26792 disableDoubleClickZoom: false,
26794 streetViewControl: false,
26798 enableAutocomplete: false,
26799 enableReverseGeocode: true,
26802 getAutoCreate: function()
26807 cls: 'roo-location-picker'
26813 initEvents: function(ct, position)
26815 if(!this.el.getWidth() || this.isApplied()){
26819 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26824 initial: function()
26826 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
26827 this.fireEvent('loadexception', this);
26831 if(!this.mapTypeId){
26832 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
26835 this.gMapContext = this.GMapContext();
26837 this.initOverlayView();
26839 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
26843 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
26844 _this.setPosition(_this.gMapContext.marker.position);
26847 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
26848 _this.fireEvent('mapClick', this, event);
26852 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
26853 _this.fireEvent('mapRightClick', this, event);
26857 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
26858 _this.fireEvent('markerClick', this, event);
26862 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
26863 _this.fireEvent('markerRightClick', this, event);
26867 this.setPosition(this.gMapContext.location);
26869 this.fireEvent('initial', this, this.gMapContext.location);
26872 initOverlayView: function()
26876 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
26880 _this.fireEvent('OverlayViewDraw', _this);
26885 _this.fireEvent('OverlayViewOnAdd', _this);
26888 onRemove: function()
26890 _this.fireEvent('OverlayViewOnRemove', _this);
26893 show: function(cpx)
26895 _this.fireEvent('OverlayViewShow', _this, cpx);
26900 _this.fireEvent('OverlayViewHide', _this);
26906 fromLatLngToContainerPixel: function(event)
26908 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
26911 isApplied: function()
26913 return this.getGmapContext() == false ? false : true;
26916 getGmapContext: function()
26918 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
26921 GMapContext: function()
26923 var position = new google.maps.LatLng(this.latitude, this.longitude);
26925 var _map = new google.maps.Map(this.el.dom, {
26928 mapTypeId: this.mapTypeId,
26929 mapTypeControl: this.mapTypeControl,
26930 disableDoubleClickZoom: this.disableDoubleClickZoom,
26931 scrollwheel: this.scrollwheel,
26932 streetViewControl: this.streetViewControl,
26933 locationName: this.locationName,
26934 draggable: this.draggable,
26935 enableAutocomplete: this.enableAutocomplete,
26936 enableReverseGeocode: this.enableReverseGeocode
26939 var _marker = new google.maps.Marker({
26940 position: position,
26942 title: this.markerTitle,
26943 draggable: this.draggable
26950 location: position,
26951 radius: this.radius,
26952 locationName: this.locationName,
26953 addressComponents: {
26954 formatted_address: null,
26955 addressLine1: null,
26956 addressLine2: null,
26958 streetNumber: null,
26962 stateOrProvince: null
26965 domContainer: this.el.dom,
26966 geodecoder: new google.maps.Geocoder()
26970 drawCircle: function(center, radius, options)
26972 if (this.gMapContext.circle != null) {
26973 this.gMapContext.circle.setMap(null);
26977 options = Roo.apply({}, options, {
26978 strokeColor: "#0000FF",
26979 strokeOpacity: .35,
26981 fillColor: "#0000FF",
26985 options.map = this.gMapContext.map;
26986 options.radius = radius;
26987 options.center = center;
26988 this.gMapContext.circle = new google.maps.Circle(options);
26989 return this.gMapContext.circle;
26995 setPosition: function(location)
26997 this.gMapContext.location = location;
26998 this.gMapContext.marker.setPosition(location);
26999 this.gMapContext.map.panTo(location);
27000 this.drawCircle(location, this.gMapContext.radius, {});
27004 if (this.gMapContext.settings.enableReverseGeocode) {
27005 this.gMapContext.geodecoder.geocode({
27006 latLng: this.gMapContext.location
27007 }, function(results, status) {
27009 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
27010 _this.gMapContext.locationName = results[0].formatted_address;
27011 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
27013 _this.fireEvent('positionchanged', this, location);
27020 this.fireEvent('positionchanged', this, location);
27025 google.maps.event.trigger(this.gMapContext.map, "resize");
27027 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
27029 this.fireEvent('resize', this);
27032 setPositionByLatLng: function(latitude, longitude)
27034 this.setPosition(new google.maps.LatLng(latitude, longitude));
27037 getCurrentPosition: function()
27040 latitude: this.gMapContext.location.lat(),
27041 longitude: this.gMapContext.location.lng()
27045 getAddressName: function()
27047 return this.gMapContext.locationName;
27050 getAddressComponents: function()
27052 return this.gMapContext.addressComponents;
27055 address_component_from_google_geocode: function(address_components)
27059 for (var i = 0; i < address_components.length; i++) {
27060 var component = address_components[i];
27061 if (component.types.indexOf("postal_code") >= 0) {
27062 result.postalCode = component.short_name;
27063 } else if (component.types.indexOf("street_number") >= 0) {
27064 result.streetNumber = component.short_name;
27065 } else if (component.types.indexOf("route") >= 0) {
27066 result.streetName = component.short_name;
27067 } else if (component.types.indexOf("neighborhood") >= 0) {
27068 result.city = component.short_name;
27069 } else if (component.types.indexOf("locality") >= 0) {
27070 result.city = component.short_name;
27071 } else if (component.types.indexOf("sublocality") >= 0) {
27072 result.district = component.short_name;
27073 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
27074 result.stateOrProvince = component.short_name;
27075 } else if (component.types.indexOf("country") >= 0) {
27076 result.country = component.short_name;
27080 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
27081 result.addressLine2 = "";
27085 setZoomLevel: function(zoom)
27087 this.gMapContext.map.setZoom(zoom);
27100 this.fireEvent('show', this);
27111 this.fireEvent('hide', this);
27116 Roo.apply(Roo.bootstrap.LocationPicker, {
27118 OverlayView : function(map, options)
27120 options = options || {};
27134 * @class Roo.bootstrap.Alert
27135 * @extends Roo.bootstrap.Component
27136 * Bootstrap Alert class
27137 * @cfg {String} title The title of alert
27138 * @cfg {String} html The content of alert
27139 * @cfg {String} weight ( success | info | warning | danger )
27140 * @cfg {String} faicon font-awesomeicon
27143 * Create a new alert
27144 * @param {Object} config The config object
27148 Roo.bootstrap.Alert = function(config){
27149 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
27153 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
27160 getAutoCreate : function()
27169 cls : 'roo-alert-icon'
27174 cls : 'roo-alert-title',
27179 cls : 'roo-alert-text',
27186 cfg.cn[0].cls += ' fa ' + this.faicon;
27190 cfg.cls += ' alert-' + this.weight;
27196 initEvents: function()
27198 this.el.setVisibilityMode(Roo.Element.DISPLAY);
27201 setTitle : function(str)
27203 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
27206 setText : function(str)
27208 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
27211 setWeight : function(weight)
27214 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
27217 this.weight = weight;
27219 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
27222 setIcon : function(icon)
27225 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
27228 this.faicon = icon;
27230 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
27251 * @class Roo.bootstrap.UploadCropbox
27252 * @extends Roo.bootstrap.Component
27253 * Bootstrap UploadCropbox class
27254 * @cfg {String} emptyText show when image has been loaded
27255 * @cfg {String} rotateNotify show when image too small to rotate
27256 * @cfg {Number} errorTimeout default 3000
27257 * @cfg {Number} minWidth default 300
27258 * @cfg {Number} minHeight default 300
27259 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
27260 * @cfg {Boolean} isDocument (true|false) default false
27261 * @cfg {String} url action url
27262 * @cfg {String} paramName default 'imageUpload'
27263 * @cfg {String} method default POST
27264 * @cfg {Boolean} loadMask (true|false) default true
27265 * @cfg {Boolean} loadingText default 'Loading...'
27268 * Create a new UploadCropbox
27269 * @param {Object} config The config object
27272 Roo.bootstrap.UploadCropbox = function(config){
27273 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
27277 * @event beforeselectfile
27278 * Fire before select file
27279 * @param {Roo.bootstrap.UploadCropbox} this
27281 "beforeselectfile" : true,
27284 * Fire after initEvent
27285 * @param {Roo.bootstrap.UploadCropbox} this
27290 * Fire after initEvent
27291 * @param {Roo.bootstrap.UploadCropbox} this
27292 * @param {String} data
27297 * Fire when preparing the file data
27298 * @param {Roo.bootstrap.UploadCropbox} this
27299 * @param {Object} file
27304 * Fire when get exception
27305 * @param {Roo.bootstrap.UploadCropbox} this
27306 * @param {XMLHttpRequest} xhr
27308 "exception" : true,
27310 * @event beforeloadcanvas
27311 * Fire before load the canvas
27312 * @param {Roo.bootstrap.UploadCropbox} this
27313 * @param {String} src
27315 "beforeloadcanvas" : true,
27318 * Fire when trash image
27319 * @param {Roo.bootstrap.UploadCropbox} this
27324 * Fire when download the image
27325 * @param {Roo.bootstrap.UploadCropbox} this
27329 * @event footerbuttonclick
27330 * Fire when footerbuttonclick
27331 * @param {Roo.bootstrap.UploadCropbox} this
27332 * @param {String} type
27334 "footerbuttonclick" : true,
27338 * @param {Roo.bootstrap.UploadCropbox} this
27343 * Fire when rotate the image
27344 * @param {Roo.bootstrap.UploadCropbox} this
27345 * @param {String} pos
27350 * Fire when inspect the file
27351 * @param {Roo.bootstrap.UploadCropbox} this
27352 * @param {Object} file
27357 * Fire when xhr upload the file
27358 * @param {Roo.bootstrap.UploadCropbox} this
27359 * @param {Object} data
27364 * Fire when arrange the file data
27365 * @param {Roo.bootstrap.UploadCropbox} this
27366 * @param {Object} formData
27371 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
27374 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
27376 emptyText : 'Click to upload image',
27377 rotateNotify : 'Image is too small to rotate',
27378 errorTimeout : 3000,
27392 cropType : 'image/jpeg',
27394 canvasLoaded : false,
27395 isDocument : false,
27397 paramName : 'imageUpload',
27399 loadingText : 'Loading...',
27402 getAutoCreate : function()
27406 cls : 'roo-upload-cropbox',
27410 cls : 'roo-upload-cropbox-selector',
27415 cls : 'roo-upload-cropbox-body',
27416 style : 'cursor:pointer',
27420 cls : 'roo-upload-cropbox-preview'
27424 cls : 'roo-upload-cropbox-thumb'
27428 cls : 'roo-upload-cropbox-empty-notify',
27429 html : this.emptyText
27433 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
27434 html : this.rotateNotify
27440 cls : 'roo-upload-cropbox-footer',
27443 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
27453 onRender : function(ct, position)
27455 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
27457 if (this.buttons.length) {
27459 Roo.each(this.buttons, function(bb) {
27461 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
27463 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
27469 this.maskEl = this.el;
27473 initEvents : function()
27475 this.urlAPI = (window.createObjectURL && window) ||
27476 (window.URL && URL.revokeObjectURL && URL) ||
27477 (window.webkitURL && webkitURL);
27479 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
27480 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27482 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
27483 this.selectorEl.hide();
27485 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
27486 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27488 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
27489 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27490 this.thumbEl.hide();
27492 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
27493 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27495 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
27496 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27497 this.errorEl.hide();
27499 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
27500 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27501 this.footerEl.hide();
27503 this.setThumbBoxSize();
27509 this.fireEvent('initial', this);
27516 window.addEventListener("resize", function() { _this.resize(); } );
27518 this.bodyEl.on('click', this.beforeSelectFile, this);
27521 this.bodyEl.on('touchstart', this.onTouchStart, this);
27522 this.bodyEl.on('touchmove', this.onTouchMove, this);
27523 this.bodyEl.on('touchend', this.onTouchEnd, this);
27527 this.bodyEl.on('mousedown', this.onMouseDown, this);
27528 this.bodyEl.on('mousemove', this.onMouseMove, this);
27529 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
27530 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
27531 Roo.get(document).on('mouseup', this.onMouseUp, this);
27534 this.selectorEl.on('change', this.onFileSelected, this);
27540 this.baseScale = 1;
27542 this.baseRotate = 1;
27543 this.dragable = false;
27544 this.pinching = false;
27547 this.cropData = false;
27548 this.notifyEl.dom.innerHTML = this.emptyText;
27550 this.selectorEl.dom.value = '';
27554 resize : function()
27556 if(this.fireEvent('resize', this) != false){
27557 this.setThumbBoxPosition();
27558 this.setCanvasPosition();
27562 onFooterButtonClick : function(e, el, o, type)
27565 case 'rotate-left' :
27566 this.onRotateLeft(e);
27568 case 'rotate-right' :
27569 this.onRotateRight(e);
27572 this.beforeSelectFile(e);
27587 this.fireEvent('footerbuttonclick', this, type);
27590 beforeSelectFile : function(e)
27592 e.preventDefault();
27594 if(this.fireEvent('beforeselectfile', this) != false){
27595 this.selectorEl.dom.click();
27599 onFileSelected : function(e)
27601 e.preventDefault();
27603 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
27607 var file = this.selectorEl.dom.files[0];
27609 if(this.fireEvent('inspect', this, file) != false){
27610 this.prepare(file);
27615 trash : function(e)
27617 this.fireEvent('trash', this);
27620 download : function(e)
27622 this.fireEvent('download', this);
27625 loadCanvas : function(src)
27627 if(this.fireEvent('beforeloadcanvas', this, src) != false){
27631 this.imageEl = document.createElement('img');
27635 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
27637 this.imageEl.src = src;
27641 onLoadCanvas : function()
27643 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
27644 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
27646 this.bodyEl.un('click', this.beforeSelectFile, this);
27648 this.notifyEl.hide();
27649 this.thumbEl.show();
27650 this.footerEl.show();
27652 this.baseRotateLevel();
27654 if(this.isDocument){
27655 this.setThumbBoxSize();
27658 this.setThumbBoxPosition();
27660 this.baseScaleLevel();
27666 this.canvasLoaded = true;
27669 this.maskEl.unmask();
27674 setCanvasPosition : function()
27676 if(!this.canvasEl){
27680 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
27681 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
27683 this.previewEl.setLeft(pw);
27684 this.previewEl.setTop(ph);
27688 onMouseDown : function(e)
27692 this.dragable = true;
27693 this.pinching = false;
27695 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
27696 this.dragable = false;
27700 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27701 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27705 onMouseMove : function(e)
27709 if(!this.canvasLoaded){
27713 if (!this.dragable){
27717 var minX = Math.ceil(this.thumbEl.getLeft(true));
27718 var minY = Math.ceil(this.thumbEl.getTop(true));
27720 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
27721 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
27723 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27724 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27726 x = x - this.mouseX;
27727 y = y - this.mouseY;
27729 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
27730 var bgY = Math.ceil(y + this.previewEl.getTop(true));
27732 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
27733 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
27735 this.previewEl.setLeft(bgX);
27736 this.previewEl.setTop(bgY);
27738 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27739 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27742 onMouseUp : function(e)
27746 this.dragable = false;
27749 onMouseWheel : function(e)
27753 this.startScale = this.scale;
27755 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
27757 if(!this.zoomable()){
27758 this.scale = this.startScale;
27767 zoomable : function()
27769 var minScale = this.thumbEl.getWidth() / this.minWidth;
27771 if(this.minWidth < this.minHeight){
27772 minScale = this.thumbEl.getHeight() / this.minHeight;
27775 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
27776 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
27780 (this.rotate == 0 || this.rotate == 180) &&
27782 width > this.imageEl.OriginWidth ||
27783 height > this.imageEl.OriginHeight ||
27784 (width < this.minWidth && height < this.minHeight)
27792 (this.rotate == 90 || this.rotate == 270) &&
27794 width > this.imageEl.OriginWidth ||
27795 height > this.imageEl.OriginHeight ||
27796 (width < this.minHeight && height < this.minWidth)
27803 !this.isDocument &&
27804 (this.rotate == 0 || this.rotate == 180) &&
27806 width < this.minWidth ||
27807 width > this.imageEl.OriginWidth ||
27808 height < this.minHeight ||
27809 height > this.imageEl.OriginHeight
27816 !this.isDocument &&
27817 (this.rotate == 90 || this.rotate == 270) &&
27819 width < this.minHeight ||
27820 width > this.imageEl.OriginWidth ||
27821 height < this.minWidth ||
27822 height > this.imageEl.OriginHeight
27832 onRotateLeft : function(e)
27834 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27836 var minScale = this.thumbEl.getWidth() / this.minWidth;
27838 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27839 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27841 this.startScale = this.scale;
27843 while (this.getScaleLevel() < minScale){
27845 this.scale = this.scale + 1;
27847 if(!this.zoomable()){
27852 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27853 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27858 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27865 this.scale = this.startScale;
27867 this.onRotateFail();
27872 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27874 if(this.isDocument){
27875 this.setThumbBoxSize();
27876 this.setThumbBoxPosition();
27877 this.setCanvasPosition();
27882 this.fireEvent('rotate', this, 'left');
27886 onRotateRight : function(e)
27888 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27890 var minScale = this.thumbEl.getWidth() / this.minWidth;
27892 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27893 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27895 this.startScale = this.scale;
27897 while (this.getScaleLevel() < minScale){
27899 this.scale = this.scale + 1;
27901 if(!this.zoomable()){
27906 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27907 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27912 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27919 this.scale = this.startScale;
27921 this.onRotateFail();
27926 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27928 if(this.isDocument){
27929 this.setThumbBoxSize();
27930 this.setThumbBoxPosition();
27931 this.setCanvasPosition();
27936 this.fireEvent('rotate', this, 'right');
27939 onRotateFail : function()
27941 this.errorEl.show(true);
27945 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
27950 this.previewEl.dom.innerHTML = '';
27952 var canvasEl = document.createElement("canvas");
27954 var contextEl = canvasEl.getContext("2d");
27956 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27957 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27958 var center = this.imageEl.OriginWidth / 2;
27960 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
27961 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27962 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27963 center = this.imageEl.OriginHeight / 2;
27966 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
27968 contextEl.translate(center, center);
27969 contextEl.rotate(this.rotate * Math.PI / 180);
27971 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27973 this.canvasEl = document.createElement("canvas");
27975 this.contextEl = this.canvasEl.getContext("2d");
27977 switch (this.rotate) {
27980 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27981 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27983 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27988 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27989 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27991 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27992 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);
27996 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
28001 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
28002 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
28004 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28005 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);
28009 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);
28014 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
28015 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
28017 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28018 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
28022 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);
28029 this.previewEl.appendChild(this.canvasEl);
28031 this.setCanvasPosition();
28036 if(!this.canvasLoaded){
28040 var imageCanvas = document.createElement("canvas");
28042 var imageContext = imageCanvas.getContext("2d");
28044 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
28045 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
28047 var center = imageCanvas.width / 2;
28049 imageContext.translate(center, center);
28051 imageContext.rotate(this.rotate * Math.PI / 180);
28053 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
28055 var canvas = document.createElement("canvas");
28057 var context = canvas.getContext("2d");
28059 canvas.width = this.minWidth;
28060 canvas.height = this.minHeight;
28062 switch (this.rotate) {
28065 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
28066 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
28068 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28069 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28071 var targetWidth = this.minWidth - 2 * x;
28072 var targetHeight = this.minHeight - 2 * y;
28076 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28077 scale = targetWidth / width;
28080 if(x > 0 && y == 0){
28081 scale = targetHeight / height;
28084 if(x > 0 && y > 0){
28085 scale = targetWidth / width;
28087 if(width < height){
28088 scale = targetHeight / height;
28092 context.scale(scale, scale);
28094 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28095 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28097 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28098 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28100 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28105 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
28106 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
28108 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28109 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28111 var targetWidth = this.minWidth - 2 * x;
28112 var targetHeight = this.minHeight - 2 * y;
28116 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28117 scale = targetWidth / width;
28120 if(x > 0 && y == 0){
28121 scale = targetHeight / height;
28124 if(x > 0 && y > 0){
28125 scale = targetWidth / width;
28127 if(width < height){
28128 scale = targetHeight / height;
28132 context.scale(scale, scale);
28134 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28135 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28137 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28138 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28140 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
28142 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28147 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
28148 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
28150 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28151 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28153 var targetWidth = this.minWidth - 2 * x;
28154 var targetHeight = this.minHeight - 2 * y;
28158 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28159 scale = targetWidth / width;
28162 if(x > 0 && y == 0){
28163 scale = targetHeight / height;
28166 if(x > 0 && y > 0){
28167 scale = targetWidth / width;
28169 if(width < height){
28170 scale = targetHeight / height;
28174 context.scale(scale, scale);
28176 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28177 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28179 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28180 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28182 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
28183 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
28185 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28190 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
28191 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
28193 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28194 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28196 var targetWidth = this.minWidth - 2 * x;
28197 var targetHeight = this.minHeight - 2 * y;
28201 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28202 scale = targetWidth / width;
28205 if(x > 0 && y == 0){
28206 scale = targetHeight / height;
28209 if(x > 0 && y > 0){
28210 scale = targetWidth / width;
28212 if(width < height){
28213 scale = targetHeight / height;
28217 context.scale(scale, scale);
28219 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28220 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28222 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28223 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28225 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
28227 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28234 this.cropData = canvas.toDataURL(this.cropType);
28236 if(this.fireEvent('crop', this, this.cropData) !== false){
28237 this.process(this.file, this.cropData);
28244 setThumbBoxSize : function()
28248 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
28249 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
28250 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
28252 this.minWidth = width;
28253 this.minHeight = height;
28255 if(this.rotate == 90 || this.rotate == 270){
28256 this.minWidth = height;
28257 this.minHeight = width;
28262 width = Math.ceil(this.minWidth * height / this.minHeight);
28264 if(this.minWidth > this.minHeight){
28266 height = Math.ceil(this.minHeight * width / this.minWidth);
28269 this.thumbEl.setStyle({
28270 width : width + 'px',
28271 height : height + 'px'
28278 setThumbBoxPosition : function()
28280 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
28281 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
28283 this.thumbEl.setLeft(x);
28284 this.thumbEl.setTop(y);
28288 baseRotateLevel : function()
28290 this.baseRotate = 1;
28293 typeof(this.exif) != 'undefined' &&
28294 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
28295 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
28297 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
28300 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
28304 baseScaleLevel : function()
28308 if(this.isDocument){
28310 if(this.baseRotate == 6 || this.baseRotate == 8){
28312 height = this.thumbEl.getHeight();
28313 this.baseScale = height / this.imageEl.OriginWidth;
28315 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
28316 width = this.thumbEl.getWidth();
28317 this.baseScale = width / this.imageEl.OriginHeight;
28323 height = this.thumbEl.getHeight();
28324 this.baseScale = height / this.imageEl.OriginHeight;
28326 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
28327 width = this.thumbEl.getWidth();
28328 this.baseScale = width / this.imageEl.OriginWidth;
28334 if(this.baseRotate == 6 || this.baseRotate == 8){
28336 width = this.thumbEl.getHeight();
28337 this.baseScale = width / this.imageEl.OriginHeight;
28339 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
28340 height = this.thumbEl.getWidth();
28341 this.baseScale = height / this.imageEl.OriginHeight;
28344 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28345 height = this.thumbEl.getWidth();
28346 this.baseScale = height / this.imageEl.OriginHeight;
28348 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
28349 width = this.thumbEl.getHeight();
28350 this.baseScale = width / this.imageEl.OriginWidth;
28357 width = this.thumbEl.getWidth();
28358 this.baseScale = width / this.imageEl.OriginWidth;
28360 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
28361 height = this.thumbEl.getHeight();
28362 this.baseScale = height / this.imageEl.OriginHeight;
28365 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28367 height = this.thumbEl.getHeight();
28368 this.baseScale = height / this.imageEl.OriginHeight;
28370 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
28371 width = this.thumbEl.getWidth();
28372 this.baseScale = width / this.imageEl.OriginWidth;
28380 getScaleLevel : function()
28382 return this.baseScale * Math.pow(1.1, this.scale);
28385 onTouchStart : function(e)
28387 if(!this.canvasLoaded){
28388 this.beforeSelectFile(e);
28392 var touches = e.browserEvent.touches;
28398 if(touches.length == 1){
28399 this.onMouseDown(e);
28403 if(touches.length != 2){
28409 for(var i = 0, finger; finger = touches[i]; i++){
28410 coords.push(finger.pageX, finger.pageY);
28413 var x = Math.pow(coords[0] - coords[2], 2);
28414 var y = Math.pow(coords[1] - coords[3], 2);
28416 this.startDistance = Math.sqrt(x + y);
28418 this.startScale = this.scale;
28420 this.pinching = true;
28421 this.dragable = false;
28425 onTouchMove : function(e)
28427 if(!this.pinching && !this.dragable){
28431 var touches = e.browserEvent.touches;
28438 this.onMouseMove(e);
28444 for(var i = 0, finger; finger = touches[i]; i++){
28445 coords.push(finger.pageX, finger.pageY);
28448 var x = Math.pow(coords[0] - coords[2], 2);
28449 var y = Math.pow(coords[1] - coords[3], 2);
28451 this.endDistance = Math.sqrt(x + y);
28453 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
28455 if(!this.zoomable()){
28456 this.scale = this.startScale;
28464 onTouchEnd : function(e)
28466 this.pinching = false;
28467 this.dragable = false;
28471 process : function(file, crop)
28474 this.maskEl.mask(this.loadingText);
28477 this.xhr = new XMLHttpRequest();
28479 file.xhr = this.xhr;
28481 this.xhr.open(this.method, this.url, true);
28484 "Accept": "application/json",
28485 "Cache-Control": "no-cache",
28486 "X-Requested-With": "XMLHttpRequest"
28489 for (var headerName in headers) {
28490 var headerValue = headers[headerName];
28492 this.xhr.setRequestHeader(headerName, headerValue);
28498 this.xhr.onload = function()
28500 _this.xhrOnLoad(_this.xhr);
28503 this.xhr.onerror = function()
28505 _this.xhrOnError(_this.xhr);
28508 var formData = new FormData();
28510 formData.append('returnHTML', 'NO');
28513 formData.append('crop', crop);
28516 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
28517 formData.append(this.paramName, file, file.name);
28520 if(typeof(file.filename) != 'undefined'){
28521 formData.append('filename', file.filename);
28524 if(typeof(file.mimetype) != 'undefined'){
28525 formData.append('mimetype', file.mimetype);
28528 if(this.fireEvent('arrange', this, formData) != false){
28529 this.xhr.send(formData);
28533 xhrOnLoad : function(xhr)
28536 this.maskEl.unmask();
28539 if (xhr.readyState !== 4) {
28540 this.fireEvent('exception', this, xhr);
28544 var response = Roo.decode(xhr.responseText);
28546 if(!response.success){
28547 this.fireEvent('exception', this, xhr);
28551 var response = Roo.decode(xhr.responseText);
28553 this.fireEvent('upload', this, response);
28557 xhrOnError : function()
28560 this.maskEl.unmask();
28563 Roo.log('xhr on error');
28565 var response = Roo.decode(xhr.responseText);
28571 prepare : function(file)
28574 this.maskEl.mask(this.loadingText);
28580 if(typeof(file) === 'string'){
28581 this.loadCanvas(file);
28585 if(!file || !this.urlAPI){
28590 this.cropType = file.type;
28594 if(this.fireEvent('prepare', this, this.file) != false){
28596 var reader = new FileReader();
28598 reader.onload = function (e) {
28599 if (e.target.error) {
28600 Roo.log(e.target.error);
28604 var buffer = e.target.result,
28605 dataView = new DataView(buffer),
28607 maxOffset = dataView.byteLength - 4,
28611 if (dataView.getUint16(0) === 0xffd8) {
28612 while (offset < maxOffset) {
28613 markerBytes = dataView.getUint16(offset);
28615 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
28616 markerLength = dataView.getUint16(offset + 2) + 2;
28617 if (offset + markerLength > dataView.byteLength) {
28618 Roo.log('Invalid meta data: Invalid segment size.');
28622 if(markerBytes == 0xffe1){
28623 _this.parseExifData(
28630 offset += markerLength;
28640 var url = _this.urlAPI.createObjectURL(_this.file);
28642 _this.loadCanvas(url);
28647 reader.readAsArrayBuffer(this.file);
28653 parseExifData : function(dataView, offset, length)
28655 var tiffOffset = offset + 10,
28659 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28660 // No Exif data, might be XMP data instead
28664 // Check for the ASCII code for "Exif" (0x45786966):
28665 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28666 // No Exif data, might be XMP data instead
28669 if (tiffOffset + 8 > dataView.byteLength) {
28670 Roo.log('Invalid Exif data: Invalid segment size.');
28673 // Check for the two null bytes:
28674 if (dataView.getUint16(offset + 8) !== 0x0000) {
28675 Roo.log('Invalid Exif data: Missing byte alignment offset.');
28678 // Check the byte alignment:
28679 switch (dataView.getUint16(tiffOffset)) {
28681 littleEndian = true;
28684 littleEndian = false;
28687 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
28690 // Check for the TIFF tag marker (0x002A):
28691 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
28692 Roo.log('Invalid Exif data: Missing TIFF marker.');
28695 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
28696 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
28698 this.parseExifTags(
28701 tiffOffset + dirOffset,
28706 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
28711 if (dirOffset + 6 > dataView.byteLength) {
28712 Roo.log('Invalid Exif data: Invalid directory offset.');
28715 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
28716 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
28717 if (dirEndOffset + 4 > dataView.byteLength) {
28718 Roo.log('Invalid Exif data: Invalid directory size.');
28721 for (i = 0; i < tagsNumber; i += 1) {
28725 dirOffset + 2 + 12 * i, // tag offset
28729 // Return the offset to the next directory:
28730 return dataView.getUint32(dirEndOffset, littleEndian);
28733 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
28735 var tag = dataView.getUint16(offset, littleEndian);
28737 this.exif[tag] = this.getExifValue(
28741 dataView.getUint16(offset + 2, littleEndian), // tag type
28742 dataView.getUint32(offset + 4, littleEndian), // tag length
28747 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
28749 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
28758 Roo.log('Invalid Exif data: Invalid tag type.');
28762 tagSize = tagType.size * length;
28763 // Determine if the value is contained in the dataOffset bytes,
28764 // or if the value at the dataOffset is a pointer to the actual data:
28765 dataOffset = tagSize > 4 ?
28766 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
28767 if (dataOffset + tagSize > dataView.byteLength) {
28768 Roo.log('Invalid Exif data: Invalid data offset.');
28771 if (length === 1) {
28772 return tagType.getValue(dataView, dataOffset, littleEndian);
28775 for (i = 0; i < length; i += 1) {
28776 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
28779 if (tagType.ascii) {
28781 // Concatenate the chars:
28782 for (i = 0; i < values.length; i += 1) {
28784 // Ignore the terminating NULL byte(s):
28785 if (c === '\u0000') {
28797 Roo.apply(Roo.bootstrap.UploadCropbox, {
28799 'Orientation': 0x0112
28803 1: 0, //'top-left',
28805 3: 180, //'bottom-right',
28806 // 4: 'bottom-left',
28808 6: 90, //'right-top',
28809 // 7: 'right-bottom',
28810 8: 270 //'left-bottom'
28814 // byte, 8-bit unsigned int:
28816 getValue: function (dataView, dataOffset) {
28817 return dataView.getUint8(dataOffset);
28821 // ascii, 8-bit byte:
28823 getValue: function (dataView, dataOffset) {
28824 return String.fromCharCode(dataView.getUint8(dataOffset));
28829 // short, 16 bit int:
28831 getValue: function (dataView, dataOffset, littleEndian) {
28832 return dataView.getUint16(dataOffset, littleEndian);
28836 // long, 32 bit int:
28838 getValue: function (dataView, dataOffset, littleEndian) {
28839 return dataView.getUint32(dataOffset, littleEndian);
28843 // rational = two long values, first is numerator, second is denominator:
28845 getValue: function (dataView, dataOffset, littleEndian) {
28846 return dataView.getUint32(dataOffset, littleEndian) /
28847 dataView.getUint32(dataOffset + 4, littleEndian);
28851 // slong, 32 bit signed int:
28853 getValue: function (dataView, dataOffset, littleEndian) {
28854 return dataView.getInt32(dataOffset, littleEndian);
28858 // srational, two slongs, first is numerator, second is denominator:
28860 getValue: function (dataView, dataOffset, littleEndian) {
28861 return dataView.getInt32(dataOffset, littleEndian) /
28862 dataView.getInt32(dataOffset + 4, littleEndian);
28872 cls : 'btn-group roo-upload-cropbox-rotate-left',
28873 action : 'rotate-left',
28877 cls : 'btn btn-default',
28878 html : '<i class="fa fa-undo"></i>'
28884 cls : 'btn-group roo-upload-cropbox-picture',
28885 action : 'picture',
28889 cls : 'btn btn-default',
28890 html : '<i class="fa fa-picture-o"></i>'
28896 cls : 'btn-group roo-upload-cropbox-rotate-right',
28897 action : 'rotate-right',
28901 cls : 'btn btn-default',
28902 html : '<i class="fa fa-repeat"></i>'
28910 cls : 'btn-group roo-upload-cropbox-rotate-left',
28911 action : 'rotate-left',
28915 cls : 'btn btn-default',
28916 html : '<i class="fa fa-undo"></i>'
28922 cls : 'btn-group roo-upload-cropbox-download',
28923 action : 'download',
28927 cls : 'btn btn-default',
28928 html : '<i class="fa fa-download"></i>'
28934 cls : 'btn-group roo-upload-cropbox-crop',
28939 cls : 'btn btn-default',
28940 html : '<i class="fa fa-crop"></i>'
28946 cls : 'btn-group roo-upload-cropbox-trash',
28951 cls : 'btn btn-default',
28952 html : '<i class="fa fa-trash"></i>'
28958 cls : 'btn-group roo-upload-cropbox-rotate-right',
28959 action : 'rotate-right',
28963 cls : 'btn btn-default',
28964 html : '<i class="fa fa-repeat"></i>'
28972 cls : 'btn-group roo-upload-cropbox-rotate-left',
28973 action : 'rotate-left',
28977 cls : 'btn btn-default',
28978 html : '<i class="fa fa-undo"></i>'
28984 cls : 'btn-group roo-upload-cropbox-rotate-right',
28985 action : 'rotate-right',
28989 cls : 'btn btn-default',
28990 html : '<i class="fa fa-repeat"></i>'
29003 * @class Roo.bootstrap.DocumentManager
29004 * @extends Roo.bootstrap.Component
29005 * Bootstrap DocumentManager class
29006 * @cfg {String} paramName default 'imageUpload'
29007 * @cfg {String} toolTipName default 'filename'
29008 * @cfg {String} method default POST
29009 * @cfg {String} url action url
29010 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
29011 * @cfg {Boolean} multiple multiple upload default true
29012 * @cfg {Number} thumbSize default 300
29013 * @cfg {String} fieldLabel
29014 * @cfg {Number} labelWidth default 4
29015 * @cfg {String} labelAlign (left|top) default left
29016 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
29017 * @cfg {Number} labellg set the width of label (1-12)
29018 * @cfg {Number} labelmd set the width of label (1-12)
29019 * @cfg {Number} labelsm set the width of label (1-12)
29020 * @cfg {Number} labelxs set the width of label (1-12)
29023 * Create a new DocumentManager
29024 * @param {Object} config The config object
29027 Roo.bootstrap.DocumentManager = function(config){
29028 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
29031 this.delegates = [];
29036 * Fire when initial the DocumentManager
29037 * @param {Roo.bootstrap.DocumentManager} this
29042 * inspect selected file
29043 * @param {Roo.bootstrap.DocumentManager} this
29044 * @param {File} file
29049 * Fire when xhr load exception
29050 * @param {Roo.bootstrap.DocumentManager} this
29051 * @param {XMLHttpRequest} xhr
29053 "exception" : true,
29055 * @event afterupload
29056 * Fire when xhr load exception
29057 * @param {Roo.bootstrap.DocumentManager} this
29058 * @param {XMLHttpRequest} xhr
29060 "afterupload" : true,
29063 * prepare the form data
29064 * @param {Roo.bootstrap.DocumentManager} this
29065 * @param {Object} formData
29070 * Fire when remove the file
29071 * @param {Roo.bootstrap.DocumentManager} this
29072 * @param {Object} file
29077 * Fire after refresh the file
29078 * @param {Roo.bootstrap.DocumentManager} this
29083 * Fire after click the image
29084 * @param {Roo.bootstrap.DocumentManager} this
29085 * @param {Object} file
29090 * Fire when upload a image and editable set to true
29091 * @param {Roo.bootstrap.DocumentManager} this
29092 * @param {Object} file
29096 * @event beforeselectfile
29097 * Fire before select file
29098 * @param {Roo.bootstrap.DocumentManager} this
29100 "beforeselectfile" : true,
29103 * Fire before process file
29104 * @param {Roo.bootstrap.DocumentManager} this
29105 * @param {Object} file
29109 * @event previewrendered
29110 * Fire when preview rendered
29111 * @param {Roo.bootstrap.DocumentManager} this
29112 * @param {Object} file
29114 "previewrendered" : true,
29117 "previewResize" : true
29122 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
29131 paramName : 'imageUpload',
29132 toolTipName : 'filename',
29135 labelAlign : 'left',
29145 getAutoCreate : function()
29147 var managerWidget = {
29149 cls : 'roo-document-manager',
29153 cls : 'roo-document-manager-selector',
29158 cls : 'roo-document-manager-uploader',
29162 cls : 'roo-document-manager-upload-btn',
29163 html : '<i class="fa fa-plus"></i>'
29174 cls : 'column col-md-12',
29179 if(this.fieldLabel.length){
29184 cls : 'column col-md-12',
29185 html : this.fieldLabel
29189 cls : 'column col-md-12',
29194 if(this.labelAlign == 'left'){
29199 html : this.fieldLabel
29208 if(this.labelWidth > 12){
29209 content[0].style = "width: " + this.labelWidth + 'px';
29212 if(this.labelWidth < 13 && this.labelmd == 0){
29213 this.labelmd = this.labelWidth;
29216 if(this.labellg > 0){
29217 content[0].cls += ' col-lg-' + this.labellg;
29218 content[1].cls += ' col-lg-' + (12 - this.labellg);
29221 if(this.labelmd > 0){
29222 content[0].cls += ' col-md-' + this.labelmd;
29223 content[1].cls += ' col-md-' + (12 - this.labelmd);
29226 if(this.labelsm > 0){
29227 content[0].cls += ' col-sm-' + this.labelsm;
29228 content[1].cls += ' col-sm-' + (12 - this.labelsm);
29231 if(this.labelxs > 0){
29232 content[0].cls += ' col-xs-' + this.labelxs;
29233 content[1].cls += ' col-xs-' + (12 - this.labelxs);
29241 cls : 'row clearfix',
29249 initEvents : function()
29251 this.managerEl = this.el.select('.roo-document-manager', true).first();
29252 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29254 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
29255 this.selectorEl.hide();
29258 this.selectorEl.attr('multiple', 'multiple');
29261 this.selectorEl.on('change', this.onFileSelected, this);
29263 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
29264 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29266 this.uploader.on('click', this.onUploaderClick, this);
29268 this.renderProgressDialog();
29272 window.addEventListener("resize", function() { _this.refresh(); } );
29274 this.fireEvent('initial', this);
29277 renderProgressDialog : function()
29281 this.progressDialog = new Roo.bootstrap.Modal({
29282 cls : 'roo-document-manager-progress-dialog',
29283 allow_close : false,
29294 btnclick : function() {
29295 _this.uploadCancel();
29301 this.progressDialog.render(Roo.get(document.body));
29303 this.progress = new Roo.bootstrap.Progress({
29304 cls : 'roo-document-manager-progress',
29309 this.progress.render(this.progressDialog.getChildContainer());
29311 this.progressBar = new Roo.bootstrap.ProgressBar({
29312 cls : 'roo-document-manager-progress-bar',
29315 aria_valuemax : 12,
29319 this.progressBar.render(this.progress.getChildContainer());
29322 onUploaderClick : function(e)
29324 e.preventDefault();
29326 if(this.fireEvent('beforeselectfile', this) != false){
29327 this.selectorEl.dom.click();
29332 onFileSelected : function(e)
29334 e.preventDefault();
29336 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
29340 Roo.each(this.selectorEl.dom.files, function(file){
29341 if(this.fireEvent('inspect', this, file) != false){
29342 this.files.push(file);
29352 this.selectorEl.dom.value = '';
29354 if(!this.files || !this.files.length){
29358 if(this.boxes > 0 && this.files.length > this.boxes){
29359 this.files = this.files.slice(0, this.boxes);
29362 this.uploader.show();
29364 if(this.boxes > 0 && this.files.length > this.boxes - 1){
29365 this.uploader.hide();
29374 Roo.each(this.files, function(file){
29376 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29377 var f = this.renderPreview(file);
29382 if(file.type.indexOf('image') != -1){
29383 this.delegates.push(
29385 _this.process(file);
29386 }).createDelegate(this)
29394 _this.process(file);
29395 }).createDelegate(this)
29400 this.files = files;
29402 this.delegates = this.delegates.concat(docs);
29404 if(!this.delegates.length){
29409 this.progressBar.aria_valuemax = this.delegates.length;
29416 arrange : function()
29418 if(!this.delegates.length){
29419 this.progressDialog.hide();
29424 var delegate = this.delegates.shift();
29426 this.progressDialog.show();
29428 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
29430 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
29435 refresh : function()
29437 this.uploader.show();
29439 if(this.boxes > 0 && this.files.length > this.boxes - 1){
29440 this.uploader.hide();
29443 Roo.isTouch ? this.closable(false) : this.closable(true);
29445 this.fireEvent('refresh', this);
29448 onRemove : function(e, el, o)
29450 e.preventDefault();
29452 this.fireEvent('remove', this, o);
29456 remove : function(o)
29460 Roo.each(this.files, function(file){
29461 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
29470 this.files = files;
29477 Roo.each(this.files, function(file){
29482 file.target.remove();
29491 onClick : function(e, el, o)
29493 e.preventDefault();
29495 this.fireEvent('click', this, o);
29499 closable : function(closable)
29501 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
29503 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29515 xhrOnLoad : function(xhr)
29517 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29521 if (xhr.readyState !== 4) {
29523 this.fireEvent('exception', this, xhr);
29527 var response = Roo.decode(xhr.responseText);
29529 if(!response.success){
29531 this.fireEvent('exception', this, xhr);
29535 var file = this.renderPreview(response.data);
29537 this.files.push(file);
29541 this.fireEvent('afterupload', this, xhr);
29545 xhrOnError : function(xhr)
29547 Roo.log('xhr on error');
29549 var response = Roo.decode(xhr.responseText);
29556 process : function(file)
29558 if(this.fireEvent('process', this, file) !== false){
29559 if(this.editable && file.type.indexOf('image') != -1){
29560 this.fireEvent('edit', this, file);
29564 this.uploadStart(file, false);
29571 uploadStart : function(file, crop)
29573 this.xhr = new XMLHttpRequest();
29575 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29580 file.xhr = this.xhr;
29582 this.managerEl.createChild({
29584 cls : 'roo-document-manager-loading',
29588 tooltip : file.name,
29589 cls : 'roo-document-manager-thumb',
29590 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29596 this.xhr.open(this.method, this.url, true);
29599 "Accept": "application/json",
29600 "Cache-Control": "no-cache",
29601 "X-Requested-With": "XMLHttpRequest"
29604 for (var headerName in headers) {
29605 var headerValue = headers[headerName];
29607 this.xhr.setRequestHeader(headerName, headerValue);
29613 this.xhr.onload = function()
29615 _this.xhrOnLoad(_this.xhr);
29618 this.xhr.onerror = function()
29620 _this.xhrOnError(_this.xhr);
29623 var formData = new FormData();
29625 formData.append('returnHTML', 'NO');
29628 formData.append('crop', crop);
29631 formData.append(this.paramName, file, file.name);
29638 if(this.fireEvent('prepare', this, formData, options) != false){
29640 if(options.manually){
29644 this.xhr.send(formData);
29648 this.uploadCancel();
29651 uploadCancel : function()
29657 this.delegates = [];
29659 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29666 renderPreview : function(file)
29668 if(typeof(file.target) != 'undefined' && file.target){
29672 var img_src = encodeURI(baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename);
29674 var previewEl = this.managerEl.createChild({
29676 cls : 'roo-document-manager-preview',
29680 tooltip : file[this.toolTipName],
29681 cls : 'roo-document-manager-thumb',
29682 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + img_src + '">'
29687 html : '<i class="fa fa-times-circle"></i>'
29692 var close = previewEl.select('button.close', true).first();
29694 close.on('click', this.onRemove, this, file);
29696 file.target = previewEl;
29698 var image = previewEl.select('img', true).first();
29702 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
29704 image.on('click', this.onClick, this, file);
29706 this.fireEvent('previewrendered', this, file);
29712 onPreviewLoad : function(file, image)
29714 if(typeof(file.target) == 'undefined' || !file.target){
29718 var width = image.dom.naturalWidth || image.dom.width;
29719 var height = image.dom.naturalHeight || image.dom.height;
29721 if(!this.previewResize) {
29725 if(width > height){
29726 file.target.addClass('wide');
29730 file.target.addClass('tall');
29735 uploadFromSource : function(file, crop)
29737 this.xhr = new XMLHttpRequest();
29739 this.managerEl.createChild({
29741 cls : 'roo-document-manager-loading',
29745 tooltip : file.name,
29746 cls : 'roo-document-manager-thumb',
29747 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29753 this.xhr.open(this.method, this.url, true);
29756 "Accept": "application/json",
29757 "Cache-Control": "no-cache",
29758 "X-Requested-With": "XMLHttpRequest"
29761 for (var headerName in headers) {
29762 var headerValue = headers[headerName];
29764 this.xhr.setRequestHeader(headerName, headerValue);
29770 this.xhr.onload = function()
29772 _this.xhrOnLoad(_this.xhr);
29775 this.xhr.onerror = function()
29777 _this.xhrOnError(_this.xhr);
29780 var formData = new FormData();
29782 formData.append('returnHTML', 'NO');
29784 formData.append('crop', crop);
29786 if(typeof(file.filename) != 'undefined'){
29787 formData.append('filename', file.filename);
29790 if(typeof(file.mimetype) != 'undefined'){
29791 formData.append('mimetype', file.mimetype);
29796 if(this.fireEvent('prepare', this, formData) != false){
29797 this.xhr.send(formData);
29807 * @class Roo.bootstrap.DocumentViewer
29808 * @extends Roo.bootstrap.Component
29809 * Bootstrap DocumentViewer class
29810 * @cfg {Boolean} showDownload (true|false) show download button (default true)
29811 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
29814 * Create a new DocumentViewer
29815 * @param {Object} config The config object
29818 Roo.bootstrap.DocumentViewer = function(config){
29819 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
29824 * Fire after initEvent
29825 * @param {Roo.bootstrap.DocumentViewer} this
29831 * @param {Roo.bootstrap.DocumentViewer} this
29836 * Fire after download button
29837 * @param {Roo.bootstrap.DocumentViewer} this
29842 * Fire after trash button
29843 * @param {Roo.bootstrap.DocumentViewer} this
29850 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
29852 showDownload : true,
29856 getAutoCreate : function()
29860 cls : 'roo-document-viewer',
29864 cls : 'roo-document-viewer-body',
29868 cls : 'roo-document-viewer-thumb',
29872 cls : 'roo-document-viewer-image'
29880 cls : 'roo-document-viewer-footer',
29883 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
29887 cls : 'btn-group roo-document-viewer-download',
29891 cls : 'btn btn-default',
29892 html : '<i class="fa fa-download"></i>'
29898 cls : 'btn-group roo-document-viewer-trash',
29902 cls : 'btn btn-default',
29903 html : '<i class="fa fa-trash"></i>'
29916 initEvents : function()
29918 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
29919 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
29921 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
29922 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
29924 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
29925 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
29927 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
29928 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
29930 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
29931 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
29933 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
29934 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
29936 this.bodyEl.on('click', this.onClick, this);
29937 this.downloadBtn.on('click', this.onDownload, this);
29938 this.trashBtn.on('click', this.onTrash, this);
29940 this.downloadBtn.hide();
29941 this.trashBtn.hide();
29943 if(this.showDownload){
29944 this.downloadBtn.show();
29947 if(this.showTrash){
29948 this.trashBtn.show();
29951 if(!this.showDownload && !this.showTrash) {
29952 this.footerEl.hide();
29957 initial : function()
29959 this.fireEvent('initial', this);
29963 onClick : function(e)
29965 e.preventDefault();
29967 this.fireEvent('click', this);
29970 onDownload : function(e)
29972 e.preventDefault();
29974 this.fireEvent('download', this);
29977 onTrash : function(e)
29979 e.preventDefault();
29981 this.fireEvent('trash', this);
29993 * @class Roo.bootstrap.NavProgressBar
29994 * @extends Roo.bootstrap.Component
29995 * Bootstrap NavProgressBar class
29998 * Create a new nav progress bar
29999 * @param {Object} config The config object
30002 Roo.bootstrap.NavProgressBar = function(config){
30003 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
30005 this.bullets = this.bullets || [];
30007 // Roo.bootstrap.NavProgressBar.register(this);
30011 * Fires when the active item changes
30012 * @param {Roo.bootstrap.NavProgressBar} this
30013 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
30014 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
30021 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
30026 getAutoCreate : function()
30028 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
30032 cls : 'roo-navigation-bar-group',
30036 cls : 'roo-navigation-top-bar'
30040 cls : 'roo-navigation-bullets-bar',
30044 cls : 'roo-navigation-bar'
30051 cls : 'roo-navigation-bottom-bar'
30061 initEvents: function()
30066 onRender : function(ct, position)
30068 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30070 if(this.bullets.length){
30071 Roo.each(this.bullets, function(b){
30080 addItem : function(cfg)
30082 var item = new Roo.bootstrap.NavProgressItem(cfg);
30084 item.parentId = this.id;
30085 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
30088 var top = new Roo.bootstrap.Element({
30090 cls : 'roo-navigation-bar-text'
30093 var bottom = new Roo.bootstrap.Element({
30095 cls : 'roo-navigation-bar-text'
30098 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
30099 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
30101 var topText = new Roo.bootstrap.Element({
30103 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
30106 var bottomText = new Roo.bootstrap.Element({
30108 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
30111 topText.onRender(top.el, null);
30112 bottomText.onRender(bottom.el, null);
30115 item.bottomEl = bottom;
30118 this.barItems.push(item);
30123 getActive : function()
30125 var active = false;
30127 Roo.each(this.barItems, function(v){
30129 if (!v.isActive()) {
30141 setActiveItem : function(item)
30145 Roo.each(this.barItems, function(v){
30146 if (v.rid == item.rid) {
30150 if (v.isActive()) {
30151 v.setActive(false);
30156 item.setActive(true);
30158 this.fireEvent('changed', this, item, prev);
30161 getBarItem: function(rid)
30165 Roo.each(this.barItems, function(e) {
30166 if (e.rid != rid) {
30177 indexOfItem : function(item)
30181 Roo.each(this.barItems, function(v, i){
30183 if (v.rid != item.rid) {
30194 setActiveNext : function()
30196 var i = this.indexOfItem(this.getActive());
30198 if (i > this.barItems.length) {
30202 this.setActiveItem(this.barItems[i+1]);
30205 setActivePrev : function()
30207 var i = this.indexOfItem(this.getActive());
30213 this.setActiveItem(this.barItems[i-1]);
30216 format : function()
30218 if(!this.barItems.length){
30222 var width = 100 / this.barItems.length;
30224 Roo.each(this.barItems, function(i){
30225 i.el.setStyle('width', width + '%');
30226 i.topEl.el.setStyle('width', width + '%');
30227 i.bottomEl.el.setStyle('width', width + '%');
30236 * Nav Progress Item
30241 * @class Roo.bootstrap.NavProgressItem
30242 * @extends Roo.bootstrap.Component
30243 * Bootstrap NavProgressItem class
30244 * @cfg {String} rid the reference id
30245 * @cfg {Boolean} active (true|false) Is item active default false
30246 * @cfg {Boolean} disabled (true|false) Is item active default false
30247 * @cfg {String} html
30248 * @cfg {String} position (top|bottom) text position default bottom
30249 * @cfg {String} icon show icon instead of number
30252 * Create a new NavProgressItem
30253 * @param {Object} config The config object
30255 Roo.bootstrap.NavProgressItem = function(config){
30256 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
30261 * The raw click event for the entire grid.
30262 * @param {Roo.bootstrap.NavProgressItem} this
30263 * @param {Roo.EventObject} e
30270 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
30276 position : 'bottom',
30279 getAutoCreate : function()
30281 var iconCls = 'roo-navigation-bar-item-icon';
30283 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
30287 cls: 'roo-navigation-bar-item',
30297 cfg.cls += ' active';
30300 cfg.cls += ' disabled';
30306 disable : function()
30308 this.setDisabled(true);
30311 enable : function()
30313 this.setDisabled(false);
30316 initEvents: function()
30318 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
30320 this.iconEl.on('click', this.onClick, this);
30323 onClick : function(e)
30325 e.preventDefault();
30331 if(this.fireEvent('click', this, e) === false){
30335 this.parent().setActiveItem(this);
30338 isActive: function ()
30340 return this.active;
30343 setActive : function(state)
30345 if(this.active == state){
30349 this.active = state;
30352 this.el.addClass('active');
30356 this.el.removeClass('active');
30361 setDisabled : function(state)
30363 if(this.disabled == state){
30367 this.disabled = state;
30370 this.el.addClass('disabled');
30374 this.el.removeClass('disabled');
30377 tooltipEl : function()
30379 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
30392 * @class Roo.bootstrap.FieldLabel
30393 * @extends Roo.bootstrap.Component
30394 * Bootstrap FieldLabel class
30395 * @cfg {String} html contents of the element
30396 * @cfg {String} tag tag of the element default label
30397 * @cfg {String} cls class of the element
30398 * @cfg {String} target label target
30399 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
30400 * @cfg {String} invalidClass DEPRICATED - BS4 uses is-invalid
30401 * @cfg {String} validClass DEPRICATED - BS4 uses is-valid
30402 * @cfg {String} iconTooltip default "This field is required"
30403 * @cfg {String} indicatorpos (left|right) default left
30406 * Create a new FieldLabel
30407 * @param {Object} config The config object
30410 Roo.bootstrap.FieldLabel = function(config){
30411 Roo.bootstrap.Element.superclass.constructor.call(this, config);
30416 * Fires after the field has been marked as invalid.
30417 * @param {Roo.form.FieldLabel} this
30418 * @param {String} msg The validation message
30423 * Fires after the field has been validated with no errors.
30424 * @param {Roo.form.FieldLabel} this
30430 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
30437 invalidClass : 'has-warning',
30438 validClass : 'has-success',
30439 iconTooltip : 'This field is required',
30440 indicatorpos : 'left',
30442 getAutoCreate : function(){
30445 if (!this.allowBlank) {
30451 cls : 'roo-bootstrap-field-label ' + this.cls,
30456 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star ' + cls,
30457 tooltip : this.iconTooltip
30466 if(this.indicatorpos == 'right'){
30469 cls : 'roo-bootstrap-field-label ' + this.cls,
30478 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star '+ cls,
30479 tooltip : this.iconTooltip
30488 initEvents: function()
30490 Roo.bootstrap.Element.superclass.initEvents.call(this);
30492 this.indicator = this.indicatorEl();
30494 if(this.indicator){
30495 this.indicator.removeClass('visible');
30496 this.indicator.addClass('invisible');
30499 Roo.bootstrap.FieldLabel.register(this);
30502 indicatorEl : function()
30504 var indicator = this.el.select('i.roo-required-indicator',true).first();
30515 * Mark this field as valid
30517 markValid : function()
30519 if(this.indicator){
30520 this.indicator.removeClass('visible');
30521 this.indicator.addClass('invisible');
30523 if (Roo.bootstrap.version == 3) {
30524 this.el.removeClass(this.invalidClass);
30525 this.el.addClass(this.validClass);
30527 this.el.removeClass('is-invalid');
30528 this.el.addClass('is-valid');
30532 this.fireEvent('valid', this);
30536 * Mark this field as invalid
30537 * @param {String} msg The validation message
30539 markInvalid : function(msg)
30541 if(this.indicator){
30542 this.indicator.removeClass('invisible');
30543 this.indicator.addClass('visible');
30545 if (Roo.bootstrap.version == 3) {
30546 this.el.removeClass(this.validClass);
30547 this.el.addClass(this.invalidClass);
30549 this.el.removeClass('is-valid');
30550 this.el.addClass('is-invalid');
30554 this.fireEvent('invalid', this, msg);
30560 Roo.apply(Roo.bootstrap.FieldLabel, {
30565 * register a FieldLabel Group
30566 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
30568 register : function(label)
30570 if(this.groups.hasOwnProperty(label.target)){
30574 this.groups[label.target] = label;
30578 * fetch a FieldLabel Group based on the target
30579 * @param {string} target
30580 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
30582 get: function(target) {
30583 if (typeof(this.groups[target]) == 'undefined') {
30587 return this.groups[target] ;
30596 * page DateSplitField.
30602 * @class Roo.bootstrap.DateSplitField
30603 * @extends Roo.bootstrap.Component
30604 * Bootstrap DateSplitField class
30605 * @cfg {string} fieldLabel - the label associated
30606 * @cfg {Number} labelWidth set the width of label (0-12)
30607 * @cfg {String} labelAlign (top|left)
30608 * @cfg {Boolean} dayAllowBlank (true|false) default false
30609 * @cfg {Boolean} monthAllowBlank (true|false) default false
30610 * @cfg {Boolean} yearAllowBlank (true|false) default false
30611 * @cfg {string} dayPlaceholder
30612 * @cfg {string} monthPlaceholder
30613 * @cfg {string} yearPlaceholder
30614 * @cfg {string} dayFormat default 'd'
30615 * @cfg {string} monthFormat default 'm'
30616 * @cfg {string} yearFormat default 'Y'
30617 * @cfg {Number} labellg set the width of label (1-12)
30618 * @cfg {Number} labelmd set the width of label (1-12)
30619 * @cfg {Number} labelsm set the width of label (1-12)
30620 * @cfg {Number} labelxs set the width of label (1-12)
30624 * Create a new DateSplitField
30625 * @param {Object} config The config object
30628 Roo.bootstrap.DateSplitField = function(config){
30629 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
30635 * getting the data of years
30636 * @param {Roo.bootstrap.DateSplitField} this
30637 * @param {Object} years
30642 * getting the data of days
30643 * @param {Roo.bootstrap.DateSplitField} this
30644 * @param {Object} days
30649 * Fires after the field has been marked as invalid.
30650 * @param {Roo.form.Field} this
30651 * @param {String} msg The validation message
30656 * Fires after the field has been validated with no errors.
30657 * @param {Roo.form.Field} this
30663 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
30666 labelAlign : 'top',
30668 dayAllowBlank : false,
30669 monthAllowBlank : false,
30670 yearAllowBlank : false,
30671 dayPlaceholder : '',
30672 monthPlaceholder : '',
30673 yearPlaceholder : '',
30677 isFormField : true,
30683 getAutoCreate : function()
30687 cls : 'row roo-date-split-field-group',
30692 cls : 'form-hidden-field roo-date-split-field-group-value',
30698 var labelCls = 'col-md-12';
30699 var contentCls = 'col-md-4';
30701 if(this.fieldLabel){
30705 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
30709 html : this.fieldLabel
30714 if(this.labelAlign == 'left'){
30716 if(this.labelWidth > 12){
30717 label.style = "width: " + this.labelWidth + 'px';
30720 if(this.labelWidth < 13 && this.labelmd == 0){
30721 this.labelmd = this.labelWidth;
30724 if(this.labellg > 0){
30725 labelCls = ' col-lg-' + this.labellg;
30726 contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
30729 if(this.labelmd > 0){
30730 labelCls = ' col-md-' + this.labelmd;
30731 contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
30734 if(this.labelsm > 0){
30735 labelCls = ' col-sm-' + this.labelsm;
30736 contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
30739 if(this.labelxs > 0){
30740 labelCls = ' col-xs-' + this.labelxs;
30741 contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
30745 label.cls += ' ' + labelCls;
30747 cfg.cn.push(label);
30750 Roo.each(['day', 'month', 'year'], function(t){
30753 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
30760 inputEl: function ()
30762 return this.el.select('.roo-date-split-field-group-value', true).first();
30765 onRender : function(ct, position)
30769 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30771 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
30773 this.dayField = new Roo.bootstrap.ComboBox({
30774 allowBlank : this.dayAllowBlank,
30775 alwaysQuery : true,
30776 displayField : 'value',
30779 forceSelection : true,
30781 placeholder : this.dayPlaceholder,
30782 selectOnFocus : true,
30783 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30784 triggerAction : 'all',
30786 valueField : 'value',
30787 store : new Roo.data.SimpleStore({
30788 data : (function() {
30790 _this.fireEvent('days', _this, days);
30793 fields : [ 'value' ]
30796 select : function (_self, record, index)
30798 _this.setValue(_this.getValue());
30803 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
30805 this.monthField = new Roo.bootstrap.MonthField({
30806 after : '<i class=\"fa fa-calendar\"></i>',
30807 allowBlank : this.monthAllowBlank,
30808 placeholder : this.monthPlaceholder,
30811 render : function (_self)
30813 this.el.select('span.input-group-addon', true).first().on('click', function(e){
30814 e.preventDefault();
30818 select : function (_self, oldvalue, newvalue)
30820 _this.setValue(_this.getValue());
30825 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
30827 this.yearField = new Roo.bootstrap.ComboBox({
30828 allowBlank : this.yearAllowBlank,
30829 alwaysQuery : true,
30830 displayField : 'value',
30833 forceSelection : true,
30835 placeholder : this.yearPlaceholder,
30836 selectOnFocus : true,
30837 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30838 triggerAction : 'all',
30840 valueField : 'value',
30841 store : new Roo.data.SimpleStore({
30842 data : (function() {
30844 _this.fireEvent('years', _this, years);
30847 fields : [ 'value' ]
30850 select : function (_self, record, index)
30852 _this.setValue(_this.getValue());
30857 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
30860 setValue : function(v, format)
30862 this.inputEl.dom.value = v;
30864 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
30866 var d = Date.parseDate(v, f);
30873 this.setDay(d.format(this.dayFormat));
30874 this.setMonth(d.format(this.monthFormat));
30875 this.setYear(d.format(this.yearFormat));
30882 setDay : function(v)
30884 this.dayField.setValue(v);
30885 this.inputEl.dom.value = this.getValue();
30890 setMonth : function(v)
30892 this.monthField.setValue(v, true);
30893 this.inputEl.dom.value = this.getValue();
30898 setYear : function(v)
30900 this.yearField.setValue(v);
30901 this.inputEl.dom.value = this.getValue();
30906 getDay : function()
30908 return this.dayField.getValue();
30911 getMonth : function()
30913 return this.monthField.getValue();
30916 getYear : function()
30918 return this.yearField.getValue();
30921 getValue : function()
30923 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
30925 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
30935 this.inputEl.dom.value = '';
30940 validate : function()
30942 var d = this.dayField.validate();
30943 var m = this.monthField.validate();
30944 var y = this.yearField.validate();
30949 (!this.dayAllowBlank && !d) ||
30950 (!this.monthAllowBlank && !m) ||
30951 (!this.yearAllowBlank && !y)
30956 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
30965 this.markInvalid();
30970 markValid : function()
30973 var label = this.el.select('label', true).first();
30974 var icon = this.el.select('i.fa-star', true).first();
30980 this.fireEvent('valid', this);
30984 * Mark this field as invalid
30985 * @param {String} msg The validation message
30987 markInvalid : function(msg)
30990 var label = this.el.select('label', true).first();
30991 var icon = this.el.select('i.fa-star', true).first();
30993 if(label && !icon){
30994 this.el.select('.roo-date-split-field-label', true).createChild({
30996 cls : 'text-danger fa fa-lg fa-star',
30997 tooltip : 'This field is required',
30998 style : 'margin-right:5px;'
31002 this.fireEvent('invalid', this, msg);
31005 clearInvalid : function()
31007 var label = this.el.select('label', true).first();
31008 var icon = this.el.select('i.fa-star', true).first();
31014 this.fireEvent('valid', this);
31017 getName: function()
31027 * http://masonry.desandro.com
31029 * The idea is to render all the bricks based on vertical width...
31031 * The original code extends 'outlayer' - we might need to use that....
31037 * @class Roo.bootstrap.LayoutMasonry
31038 * @extends Roo.bootstrap.Component
31039 * Bootstrap Layout Masonry class
31042 * Create a new Element
31043 * @param {Object} config The config object
31046 Roo.bootstrap.LayoutMasonry = function(config){
31048 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
31052 Roo.bootstrap.LayoutMasonry.register(this);
31058 * Fire after layout the items
31059 * @param {Roo.bootstrap.LayoutMasonry} this
31060 * @param {Roo.EventObject} e
31067 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
31070 * @cfg {Boolean} isLayoutInstant = no animation?
31072 isLayoutInstant : false, // needed?
31075 * @cfg {Number} boxWidth width of the columns
31080 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
31085 * @cfg {Number} padWidth padding below box..
31090 * @cfg {Number} gutter gutter width..
31095 * @cfg {Number} maxCols maximum number of columns
31101 * @cfg {Boolean} isAutoInitial defalut true
31103 isAutoInitial : true,
31108 * @cfg {Boolean} isHorizontal defalut false
31110 isHorizontal : false,
31112 currentSize : null,
31118 bricks: null, //CompositeElement
31122 _isLayoutInited : false,
31124 // isAlternative : false, // only use for vertical layout...
31127 * @cfg {Number} alternativePadWidth padding below box..
31129 alternativePadWidth : 50,
31131 selectedBrick : [],
31133 getAutoCreate : function(){
31135 var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
31139 cls: 'blog-masonary-wrapper ' + this.cls,
31141 cls : 'mas-boxes masonary'
31148 getChildContainer: function( )
31150 if (this.boxesEl) {
31151 return this.boxesEl;
31154 this.boxesEl = this.el.select('.mas-boxes').first();
31156 return this.boxesEl;
31160 initEvents : function()
31164 if(this.isAutoInitial){
31165 Roo.log('hook children rendered');
31166 this.on('childrenrendered', function() {
31167 Roo.log('children rendered');
31173 initial : function()
31175 this.selectedBrick = [];
31177 this.currentSize = this.el.getBox(true);
31179 Roo.EventManager.onWindowResize(this.resize, this);
31181 if(!this.isAutoInitial){
31189 //this.layout.defer(500,this);
31193 resize : function()
31195 var cs = this.el.getBox(true);
31198 this.currentSize.width == cs.width &&
31199 this.currentSize.x == cs.x &&
31200 this.currentSize.height == cs.height &&
31201 this.currentSize.y == cs.y
31203 Roo.log("no change in with or X or Y");
31207 this.currentSize = cs;
31213 layout : function()
31215 this._resetLayout();
31217 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
31219 this.layoutItems( isInstant );
31221 this._isLayoutInited = true;
31223 this.fireEvent('layout', this);
31227 _resetLayout : function()
31229 if(this.isHorizontal){
31230 this.horizontalMeasureColumns();
31234 this.verticalMeasureColumns();
31238 verticalMeasureColumns : function()
31240 this.getContainerWidth();
31242 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
31243 // this.colWidth = Math.floor(this.containerWidth * 0.8);
31247 var boxWidth = this.boxWidth + this.padWidth;
31249 if(this.containerWidth < this.boxWidth){
31250 boxWidth = this.containerWidth
31253 var containerWidth = this.containerWidth;
31255 var cols = Math.floor(containerWidth / boxWidth);
31257 this.cols = Math.max( cols, 1 );
31259 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
31261 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
31263 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
31265 this.colWidth = boxWidth + avail - this.padWidth;
31267 this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
31268 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
31271 horizontalMeasureColumns : function()
31273 this.getContainerWidth();
31275 var boxWidth = this.boxWidth;
31277 if(this.containerWidth < boxWidth){
31278 boxWidth = this.containerWidth;
31281 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
31283 this.el.setHeight(boxWidth);
31287 getContainerWidth : function()
31289 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
31292 layoutItems : function( isInstant )
31294 Roo.log(this.bricks);
31296 var items = Roo.apply([], this.bricks);
31298 if(this.isHorizontal){
31299 this._horizontalLayoutItems( items , isInstant );
31303 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
31304 // this._verticalAlternativeLayoutItems( items , isInstant );
31308 this._verticalLayoutItems( items , isInstant );
31312 _verticalLayoutItems : function ( items , isInstant)
31314 if ( !items || !items.length ) {
31319 ['xs', 'xs', 'xs', 'tall'],
31320 ['xs', 'xs', 'tall'],
31321 ['xs', 'xs', 'sm'],
31322 ['xs', 'xs', 'xs'],
31328 ['sm', 'xs', 'xs'],
31332 ['tall', 'xs', 'xs', 'xs'],
31333 ['tall', 'xs', 'xs'],
31345 Roo.each(items, function(item, k){
31347 switch (item.size) {
31348 // these layouts take up a full box,
31359 boxes.push([item]);
31382 var filterPattern = function(box, length)
31390 var pattern = box.slice(0, length);
31394 Roo.each(pattern, function(i){
31395 format.push(i.size);
31398 Roo.each(standard, function(s){
31400 if(String(s) != String(format)){
31409 if(!match && length == 1){
31414 filterPattern(box, length - 1);
31418 queue.push(pattern);
31420 box = box.slice(length, box.length);
31422 filterPattern(box, 4);
31428 Roo.each(boxes, function(box, k){
31434 if(box.length == 1){
31439 filterPattern(box, 4);
31443 this._processVerticalLayoutQueue( queue, isInstant );
31447 // _verticalAlternativeLayoutItems : function( items , isInstant )
31449 // if ( !items || !items.length ) {
31453 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
31457 _horizontalLayoutItems : function ( items , isInstant)
31459 if ( !items || !items.length || items.length < 3) {
31465 var eItems = items.slice(0, 3);
31467 items = items.slice(3, items.length);
31470 ['xs', 'xs', 'xs', 'wide'],
31471 ['xs', 'xs', 'wide'],
31472 ['xs', 'xs', 'sm'],
31473 ['xs', 'xs', 'xs'],
31479 ['sm', 'xs', 'xs'],
31483 ['wide', 'xs', 'xs', 'xs'],
31484 ['wide', 'xs', 'xs'],
31497 Roo.each(items, function(item, k){
31499 switch (item.size) {
31510 boxes.push([item]);
31534 var filterPattern = function(box, length)
31542 var pattern = box.slice(0, length);
31546 Roo.each(pattern, function(i){
31547 format.push(i.size);
31550 Roo.each(standard, function(s){
31552 if(String(s) != String(format)){
31561 if(!match && length == 1){
31566 filterPattern(box, length - 1);
31570 queue.push(pattern);
31572 box = box.slice(length, box.length);
31574 filterPattern(box, 4);
31580 Roo.each(boxes, function(box, k){
31586 if(box.length == 1){
31591 filterPattern(box, 4);
31598 var pos = this.el.getBox(true);
31602 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31604 var hit_end = false;
31606 Roo.each(queue, function(box){
31610 Roo.each(box, function(b){
31612 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31622 Roo.each(box, function(b){
31624 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31627 mx = Math.max(mx, b.x);
31631 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
31635 Roo.each(box, function(b){
31637 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31651 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
31654 /** Sets position of item in DOM
31655 * @param {Element} item
31656 * @param {Number} x - horizontal position
31657 * @param {Number} y - vertical position
31658 * @param {Boolean} isInstant - disables transitions
31660 _processVerticalLayoutQueue : function( queue, isInstant )
31662 var pos = this.el.getBox(true);
31667 for (var i = 0; i < this.cols; i++){
31671 Roo.each(queue, function(box, k){
31673 var col = k % this.cols;
31675 Roo.each(box, function(b,kk){
31677 b.el.position('absolute');
31679 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31680 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31682 if(b.size == 'md-left' || b.size == 'md-right'){
31683 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31684 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31687 b.el.setWidth(width);
31688 b.el.setHeight(height);
31690 b.el.select('iframe',true).setSize(width,height);
31694 for (var i = 0; i < this.cols; i++){
31696 if(maxY[i] < maxY[col]){
31701 col = Math.min(col, i);
31705 x = pos.x + col * (this.colWidth + this.padWidth);
31709 var positions = [];
31711 switch (box.length){
31713 positions = this.getVerticalOneBoxColPositions(x, y, box);
31716 positions = this.getVerticalTwoBoxColPositions(x, y, box);
31719 positions = this.getVerticalThreeBoxColPositions(x, y, box);
31722 positions = this.getVerticalFourBoxColPositions(x, y, box);
31728 Roo.each(box, function(b,kk){
31730 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31732 var sz = b.el.getSize();
31734 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
31742 for (var i = 0; i < this.cols; i++){
31743 mY = Math.max(mY, maxY[i]);
31746 this.el.setHeight(mY - pos.y);
31750 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
31752 // var pos = this.el.getBox(true);
31755 // var maxX = pos.right;
31757 // var maxHeight = 0;
31759 // Roo.each(items, function(item, k){
31763 // item.el.position('absolute');
31765 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
31767 // item.el.setWidth(width);
31769 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
31771 // item.el.setHeight(height);
31774 // item.el.setXY([x, y], isInstant ? false : true);
31776 // item.el.setXY([maxX - width, y], isInstant ? false : true);
31779 // y = y + height + this.alternativePadWidth;
31781 // maxHeight = maxHeight + height + this.alternativePadWidth;
31785 // this.el.setHeight(maxHeight);
31789 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
31791 var pos = this.el.getBox(true);
31796 var maxX = pos.right;
31798 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
31800 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31802 Roo.each(queue, function(box, k){
31804 Roo.each(box, function(b, kk){
31806 b.el.position('absolute');
31808 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31809 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31811 if(b.size == 'md-left' || b.size == 'md-right'){
31812 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31813 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31816 b.el.setWidth(width);
31817 b.el.setHeight(height);
31825 var positions = [];
31827 switch (box.length){
31829 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
31832 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
31835 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
31838 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
31844 Roo.each(box, function(b,kk){
31846 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31848 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
31856 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
31858 Roo.each(eItems, function(b,k){
31860 b.size = (k == 0) ? 'sm' : 'xs';
31861 b.x = (k == 0) ? 2 : 1;
31862 b.y = (k == 0) ? 2 : 1;
31864 b.el.position('absolute');
31866 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31868 b.el.setWidth(width);
31870 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31872 b.el.setHeight(height);
31876 var positions = [];
31879 x : maxX - this.unitWidth * 2 - this.gutter,
31884 x : maxX - this.unitWidth,
31885 y : minY + (this.unitWidth + this.gutter) * 2
31889 x : maxX - this.unitWidth * 3 - this.gutter * 2,
31893 Roo.each(eItems, function(b,k){
31895 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
31901 getVerticalOneBoxColPositions : function(x, y, box)
31905 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
31907 if(box[0].size == 'md-left'){
31911 if(box[0].size == 'md-right'){
31916 x : x + (this.unitWidth + this.gutter) * rand,
31923 getVerticalTwoBoxColPositions : function(x, y, box)
31927 if(box[0].size == 'xs'){
31931 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
31935 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
31949 x : x + (this.unitWidth + this.gutter) * 2,
31950 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
31957 getVerticalThreeBoxColPositions : function(x, y, box)
31961 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31969 x : x + (this.unitWidth + this.gutter) * 1,
31974 x : x + (this.unitWidth + this.gutter) * 2,
31982 if(box[0].size == 'xs' && box[1].size == 'xs'){
31991 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
31995 x : x + (this.unitWidth + this.gutter) * 1,
32009 x : x + (this.unitWidth + this.gutter) * 2,
32014 x : x + (this.unitWidth + this.gutter) * 2,
32015 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
32022 getVerticalFourBoxColPositions : function(x, y, box)
32026 if(box[0].size == 'xs'){
32035 y : y + (this.unitHeight + this.gutter) * 1
32040 y : y + (this.unitHeight + this.gutter) * 2
32044 x : x + (this.unitWidth + this.gutter) * 1,
32058 x : x + (this.unitWidth + this.gutter) * 2,
32063 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
32064 y : y + (this.unitHeight + this.gutter) * 1
32068 x : x + (this.unitWidth + this.gutter) * 2,
32069 y : y + (this.unitWidth + this.gutter) * 2
32076 getHorizontalOneBoxColPositions : function(maxX, minY, box)
32080 if(box[0].size == 'md-left'){
32082 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
32089 if(box[0].size == 'md-right'){
32091 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
32092 y : minY + (this.unitWidth + this.gutter) * 1
32098 var rand = Math.floor(Math.random() * (4 - box[0].y));
32101 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32102 y : minY + (this.unitWidth + this.gutter) * rand
32109 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
32113 if(box[0].size == 'xs'){
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) * (3 - box[1].y)
32130 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32135 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32136 y : minY + (this.unitWidth + this.gutter) * 2
32143 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
32147 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
32150 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32155 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32156 y : minY + (this.unitWidth + this.gutter) * 1
32160 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32161 y : minY + (this.unitWidth + this.gutter) * 2
32168 if(box[0].size == 'xs' && box[1].size == 'xs'){
32171 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32176 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32181 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32182 y : minY + (this.unitWidth + this.gutter) * 1
32190 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32195 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32196 y : minY + (this.unitWidth + this.gutter) * 2
32200 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32201 y : minY + (this.unitWidth + this.gutter) * 2
32208 getHorizontalFourBoxColPositions : function(maxX, minY, box)
32212 if(box[0].size == 'xs'){
32215 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32220 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32225 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32230 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
32231 y : minY + (this.unitWidth + this.gutter) * 1
32239 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32244 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32245 y : minY + (this.unitWidth + this.gutter) * 2
32249 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32250 y : minY + (this.unitWidth + this.gutter) * 2
32254 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),
32255 y : minY + (this.unitWidth + this.gutter) * 2
32263 * remove a Masonry Brick
32264 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
32266 removeBrick : function(brick_id)
32272 for (var i = 0; i<this.bricks.length; i++) {
32273 if (this.bricks[i].id == brick_id) {
32274 this.bricks.splice(i,1);
32275 this.el.dom.removeChild(Roo.get(brick_id).dom);
32282 * adds a Masonry Brick
32283 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32285 addBrick : function(cfg)
32287 var cn = new Roo.bootstrap.MasonryBrick(cfg);
32288 //this.register(cn);
32289 cn.parentId = this.id;
32290 cn.render(this.el);
32295 * register a Masonry Brick
32296 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32299 register : function(brick)
32301 this.bricks.push(brick);
32302 brick.masonryId = this.id;
32306 * clear all the Masonry Brick
32308 clearAll : function()
32311 //this.getChildContainer().dom.innerHTML = "";
32312 this.el.dom.innerHTML = '';
32315 getSelected : function()
32317 if (!this.selectedBrick) {
32321 return this.selectedBrick;
32325 Roo.apply(Roo.bootstrap.LayoutMasonry, {
32329 * register a Masonry Layout
32330 * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
32333 register : function(layout)
32335 this.groups[layout.id] = layout;
32338 * fetch a Masonry Layout based on the masonry layout ID
32339 * @param {string} the masonry layout to add
32340 * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
32343 get: function(layout_id) {
32344 if (typeof(this.groups[layout_id]) == 'undefined') {
32347 return this.groups[layout_id] ;
32359 * http://masonry.desandro.com
32361 * The idea is to render all the bricks based on vertical width...
32363 * The original code extends 'outlayer' - we might need to use that....
32369 * @class Roo.bootstrap.LayoutMasonryAuto
32370 * @extends Roo.bootstrap.Component
32371 * Bootstrap Layout Masonry class
32374 * Create a new Element
32375 * @param {Object} config The config object
32378 Roo.bootstrap.LayoutMasonryAuto = function(config){
32379 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
32382 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
32385 * @cfg {Boolean} isFitWidth - resize the width..
32387 isFitWidth : false, // options..
32389 * @cfg {Boolean} isOriginLeft = left align?
32391 isOriginLeft : true,
32393 * @cfg {Boolean} isOriginTop = top align?
32395 isOriginTop : false,
32397 * @cfg {Boolean} isLayoutInstant = no animation?
32399 isLayoutInstant : false, // needed?
32401 * @cfg {Boolean} isResizingContainer = not sure if this is used..
32403 isResizingContainer : true,
32405 * @cfg {Number} columnWidth width of the columns
32411 * @cfg {Number} maxCols maximum number of columns
32416 * @cfg {Number} padHeight padding below box..
32422 * @cfg {Boolean} isAutoInitial defalut true
32425 isAutoInitial : true,
32431 initialColumnWidth : 0,
32432 currentSize : null,
32434 colYs : null, // array.
32441 bricks: null, //CompositeElement
32442 cols : 0, // array?
32443 // element : null, // wrapped now this.el
32444 _isLayoutInited : null,
32447 getAutoCreate : function(){
32451 cls: 'blog-masonary-wrapper ' + this.cls,
32453 cls : 'mas-boxes masonary'
32460 getChildContainer: function( )
32462 if (this.boxesEl) {
32463 return this.boxesEl;
32466 this.boxesEl = this.el.select('.mas-boxes').first();
32468 return this.boxesEl;
32472 initEvents : function()
32476 if(this.isAutoInitial){
32477 Roo.log('hook children rendered');
32478 this.on('childrenrendered', function() {
32479 Roo.log('children rendered');
32486 initial : function()
32488 this.reloadItems();
32490 this.currentSize = this.el.getBox(true);
32492 /// was window resize... - let's see if this works..
32493 Roo.EventManager.onWindowResize(this.resize, this);
32495 if(!this.isAutoInitial){
32500 this.layout.defer(500,this);
32503 reloadItems: function()
32505 this.bricks = this.el.select('.masonry-brick', true);
32507 this.bricks.each(function(b) {
32508 //Roo.log(b.getSize());
32509 if (!b.attr('originalwidth')) {
32510 b.attr('originalwidth', b.getSize().width);
32515 Roo.log(this.bricks.elements.length);
32518 resize : function()
32521 var cs = this.el.getBox(true);
32523 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
32524 Roo.log("no change in with or X");
32527 this.currentSize = cs;
32531 layout : function()
32534 this._resetLayout();
32535 //this._manageStamps();
32537 // don't animate first layout
32538 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
32539 this.layoutItems( isInstant );
32541 // flag for initalized
32542 this._isLayoutInited = true;
32545 layoutItems : function( isInstant )
32547 //var items = this._getItemsForLayout( this.items );
32548 // original code supports filtering layout items.. we just ignore it..
32550 this._layoutItems( this.bricks , isInstant );
32552 this._postLayout();
32554 _layoutItems : function ( items , isInstant)
32556 //this.fireEvent( 'layout', this, items );
32559 if ( !items || !items.elements.length ) {
32560 // no items, emit event with empty array
32565 items.each(function(item) {
32566 Roo.log("layout item");
32568 // get x/y object from method
32569 var position = this._getItemLayoutPosition( item );
32571 position.item = item;
32572 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
32573 queue.push( position );
32576 this._processLayoutQueue( queue );
32578 /** Sets position of item in DOM
32579 * @param {Element} item
32580 * @param {Number} x - horizontal position
32581 * @param {Number} y - vertical position
32582 * @param {Boolean} isInstant - disables transitions
32584 _processLayoutQueue : function( queue )
32586 for ( var i=0, len = queue.length; i < len; i++ ) {
32587 var obj = queue[i];
32588 obj.item.position('absolute');
32589 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
32595 * Any logic you want to do after each layout,
32596 * i.e. size the container
32598 _postLayout : function()
32600 this.resizeContainer();
32603 resizeContainer : function()
32605 if ( !this.isResizingContainer ) {
32608 var size = this._getContainerSize();
32610 this.el.setSize(size.width,size.height);
32611 this.boxesEl.setSize(size.width,size.height);
32617 _resetLayout : function()
32619 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
32620 this.colWidth = this.el.getWidth();
32621 //this.gutter = this.el.getWidth();
32623 this.measureColumns();
32629 this.colYs.push( 0 );
32635 measureColumns : function()
32637 this.getContainerWidth();
32638 // if columnWidth is 0, default to outerWidth of first item
32639 if ( !this.columnWidth ) {
32640 var firstItem = this.bricks.first();
32641 Roo.log(firstItem);
32642 this.columnWidth = this.containerWidth;
32643 if (firstItem && firstItem.attr('originalwidth') ) {
32644 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
32646 // columnWidth fall back to item of first element
32647 Roo.log("set column width?");
32648 this.initialColumnWidth = this.columnWidth ;
32650 // if first elem has no width, default to size of container
32655 if (this.initialColumnWidth) {
32656 this.columnWidth = this.initialColumnWidth;
32661 // column width is fixed at the top - however if container width get's smaller we should
32664 // this bit calcs how man columns..
32666 var columnWidth = this.columnWidth += this.gutter;
32668 // calculate columns
32669 var containerWidth = this.containerWidth + this.gutter;
32671 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
32672 // fix rounding errors, typically with gutters
32673 var excess = columnWidth - containerWidth % columnWidth;
32676 // if overshoot is less than a pixel, round up, otherwise floor it
32677 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
32678 cols = Math[ mathMethod ]( cols );
32679 this.cols = Math.max( cols, 1 );
32680 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
32682 // padding positioning..
32683 var totalColWidth = this.cols * this.columnWidth;
32684 var padavail = this.containerWidth - totalColWidth;
32685 // so for 2 columns - we need 3 'pads'
32687 var padNeeded = (1+this.cols) * this.padWidth;
32689 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
32691 this.columnWidth += padExtra
32692 //this.padWidth = Math.floor(padavail / ( this.cols));
32694 // adjust colum width so that padding is fixed??
32696 // we have 3 columns ... total = width * 3
32697 // we have X left over... that should be used by
32699 //if (this.expandC) {
32707 getContainerWidth : function()
32709 /* // container is parent if fit width
32710 var container = this.isFitWidth ? this.element.parentNode : this.element;
32711 // check that this.size and size are there
32712 // IE8 triggers resize on body size change, so they might not be
32714 var size = getSize( container ); //FIXME
32715 this.containerWidth = size && size.innerWidth; //FIXME
32718 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
32722 _getItemLayoutPosition : function( item ) // what is item?
32724 // we resize the item to our columnWidth..
32726 item.setWidth(this.columnWidth);
32727 item.autoBoxAdjust = false;
32729 var sz = item.getSize();
32731 // how many columns does this brick span
32732 var remainder = this.containerWidth % this.columnWidth;
32734 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
32735 // round if off by 1 pixel, otherwise use ceil
32736 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
32737 colSpan = Math.min( colSpan, this.cols );
32739 // normally this should be '1' as we dont' currently allow multi width columns..
32741 var colGroup = this._getColGroup( colSpan );
32742 // get the minimum Y value from the columns
32743 var minimumY = Math.min.apply( Math, colGroup );
32744 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32746 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
32748 // position the brick
32750 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
32751 y: this.currentSize.y + minimumY + this.padHeight
32755 // apply setHeight to necessary columns
32756 var setHeight = minimumY + sz.height + this.padHeight;
32757 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32759 var setSpan = this.cols + 1 - colGroup.length;
32760 for ( var i = 0; i < setSpan; i++ ) {
32761 this.colYs[ shortColIndex + i ] = setHeight ;
32768 * @param {Number} colSpan - number of columns the element spans
32769 * @returns {Array} colGroup
32771 _getColGroup : function( colSpan )
32773 if ( colSpan < 2 ) {
32774 // if brick spans only one column, use all the column Ys
32779 // how many different places could this brick fit horizontally
32780 var groupCount = this.cols + 1 - colSpan;
32781 // for each group potential horizontal position
32782 for ( var i = 0; i < groupCount; i++ ) {
32783 // make an array of colY values for that one group
32784 var groupColYs = this.colYs.slice( i, i + colSpan );
32785 // and get the max value of the array
32786 colGroup[i] = Math.max.apply( Math, groupColYs );
32791 _manageStamp : function( stamp )
32793 var stampSize = stamp.getSize();
32794 var offset = stamp.getBox();
32795 // get the columns that this stamp affects
32796 var firstX = this.isOriginLeft ? offset.x : offset.right;
32797 var lastX = firstX + stampSize.width;
32798 var firstCol = Math.floor( firstX / this.columnWidth );
32799 firstCol = Math.max( 0, firstCol );
32801 var lastCol = Math.floor( lastX / this.columnWidth );
32802 // lastCol should not go over if multiple of columnWidth #425
32803 lastCol -= lastX % this.columnWidth ? 0 : 1;
32804 lastCol = Math.min( this.cols - 1, lastCol );
32806 // set colYs to bottom of the stamp
32807 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
32810 for ( var i = firstCol; i <= lastCol; i++ ) {
32811 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
32816 _getContainerSize : function()
32818 this.maxY = Math.max.apply( Math, this.colYs );
32823 if ( this.isFitWidth ) {
32824 size.width = this._getContainerFitWidth();
32830 _getContainerFitWidth : function()
32832 var unusedCols = 0;
32833 // count unused columns
32836 if ( this.colYs[i] !== 0 ) {
32841 // fit container to columns that have been used
32842 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
32845 needsResizeLayout : function()
32847 var previousWidth = this.containerWidth;
32848 this.getContainerWidth();
32849 return previousWidth !== this.containerWidth;
32864 * @class Roo.bootstrap.MasonryBrick
32865 * @extends Roo.bootstrap.Component
32866 * Bootstrap MasonryBrick class
32869 * Create a new MasonryBrick
32870 * @param {Object} config The config object
32873 Roo.bootstrap.MasonryBrick = function(config){
32875 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
32877 Roo.bootstrap.MasonryBrick.register(this);
32883 * When a MasonryBrick is clcik
32884 * @param {Roo.bootstrap.MasonryBrick} this
32885 * @param {Roo.EventObject} e
32891 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
32894 * @cfg {String} title
32898 * @cfg {String} html
32902 * @cfg {String} bgimage
32906 * @cfg {String} videourl
32910 * @cfg {String} cls
32914 * @cfg {String} href
32918 * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
32923 * @cfg {String} placetitle (center|bottom)
32928 * @cfg {Boolean} isFitContainer defalut true
32930 isFitContainer : true,
32933 * @cfg {Boolean} preventDefault defalut false
32935 preventDefault : false,
32938 * @cfg {Boolean} inverse defalut false
32940 maskInverse : false,
32942 getAutoCreate : function()
32944 if(!this.isFitContainer){
32945 return this.getSplitAutoCreate();
32948 var cls = 'masonry-brick masonry-brick-full';
32950 if(this.href.length){
32951 cls += ' masonry-brick-link';
32954 if(this.bgimage.length){
32955 cls += ' masonry-brick-image';
32958 if(this.maskInverse){
32959 cls += ' mask-inverse';
32962 if(!this.html.length && !this.maskInverse && !this.videourl.length){
32963 cls += ' enable-mask';
32967 cls += ' masonry-' + this.size + '-brick';
32970 if(this.placetitle.length){
32972 switch (this.placetitle) {
32974 cls += ' masonry-center-title';
32977 cls += ' masonry-bottom-title';
32984 if(!this.html.length && !this.bgimage.length){
32985 cls += ' masonry-center-title';
32988 if(!this.html.length && this.bgimage.length){
32989 cls += ' masonry-bottom-title';
32994 cls += ' ' + this.cls;
32998 tag: (this.href.length) ? 'a' : 'div',
33003 cls: 'masonry-brick-mask'
33007 cls: 'masonry-brick-paragraph',
33013 if(this.href.length){
33014 cfg.href = this.href;
33017 var cn = cfg.cn[1].cn;
33019 if(this.title.length){
33022 cls: 'masonry-brick-title',
33027 if(this.html.length){
33030 cls: 'masonry-brick-text',
33035 if (!this.title.length && !this.html.length) {
33036 cfg.cn[1].cls += ' hide';
33039 if(this.bgimage.length){
33042 cls: 'masonry-brick-image-view',
33047 if(this.videourl.length){
33048 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
33049 // youtube support only?
33052 cls: 'masonry-brick-image-view',
33055 allowfullscreen : true
33063 getSplitAutoCreate : function()
33065 var cls = 'masonry-brick masonry-brick-split';
33067 if(this.href.length){
33068 cls += ' masonry-brick-link';
33071 if(this.bgimage.length){
33072 cls += ' masonry-brick-image';
33076 cls += ' masonry-' + this.size + '-brick';
33079 switch (this.placetitle) {
33081 cls += ' masonry-center-title';
33084 cls += ' masonry-bottom-title';
33087 if(!this.bgimage.length){
33088 cls += ' masonry-center-title';
33091 if(this.bgimage.length){
33092 cls += ' masonry-bottom-title';
33098 cls += ' ' + this.cls;
33102 tag: (this.href.length) ? 'a' : 'div',
33107 cls: 'masonry-brick-split-head',
33111 cls: 'masonry-brick-paragraph',
33118 cls: 'masonry-brick-split-body',
33124 if(this.href.length){
33125 cfg.href = this.href;
33128 if(this.title.length){
33129 cfg.cn[0].cn[0].cn.push({
33131 cls: 'masonry-brick-title',
33136 if(this.html.length){
33137 cfg.cn[1].cn.push({
33139 cls: 'masonry-brick-text',
33144 if(this.bgimage.length){
33145 cfg.cn[0].cn.push({
33147 cls: 'masonry-brick-image-view',
33152 if(this.videourl.length){
33153 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
33154 // youtube support only?
33155 cfg.cn[0].cn.cn.push({
33157 cls: 'masonry-brick-image-view',
33160 allowfullscreen : true
33167 initEvents: function()
33169 switch (this.size) {
33202 this.el.on('touchstart', this.onTouchStart, this);
33203 this.el.on('touchmove', this.onTouchMove, this);
33204 this.el.on('touchend', this.onTouchEnd, this);
33205 this.el.on('contextmenu', this.onContextMenu, this);
33207 this.el.on('mouseenter' ,this.enter, this);
33208 this.el.on('mouseleave', this.leave, this);
33209 this.el.on('click', this.onClick, this);
33212 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
33213 this.parent().bricks.push(this);
33218 onClick: function(e, el)
33220 var time = this.endTimer - this.startTimer;
33221 // Roo.log(e.preventDefault());
33224 e.preventDefault();
33229 if(!this.preventDefault){
33233 e.preventDefault();
33235 if (this.activeClass != '') {
33236 this.selectBrick();
33239 this.fireEvent('click', this, e);
33242 enter: function(e, el)
33244 e.preventDefault();
33246 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
33250 if(this.bgimage.length && this.html.length){
33251 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
33255 leave: function(e, el)
33257 e.preventDefault();
33259 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
33263 if(this.bgimage.length && this.html.length){
33264 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
33268 onTouchStart: function(e, el)
33270 // e.preventDefault();
33272 this.touchmoved = false;
33274 if(!this.isFitContainer){
33278 if(!this.bgimage.length || !this.html.length){
33282 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
33284 this.timer = new Date().getTime();
33288 onTouchMove: function(e, el)
33290 this.touchmoved = true;
33293 onContextMenu : function(e,el)
33295 e.preventDefault();
33296 e.stopPropagation();
33300 onTouchEnd: function(e, el)
33302 // e.preventDefault();
33304 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
33311 if(!this.bgimage.length || !this.html.length){
33313 if(this.href.length){
33314 window.location.href = this.href;
33320 if(!this.isFitContainer){
33324 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
33326 window.location.href = this.href;
33329 //selection on single brick only
33330 selectBrick : function() {
33332 if (!this.parentId) {
33336 var m = Roo.bootstrap.LayoutMasonry.get(this.parentId);
33337 var index = m.selectedBrick.indexOf(this.id);
33340 m.selectedBrick.splice(index,1);
33341 this.el.removeClass(this.activeClass);
33345 for(var i = 0; i < m.selectedBrick.length; i++) {
33346 var b = Roo.bootstrap.MasonryBrick.get(m.selectedBrick[i]);
33347 b.el.removeClass(b.activeClass);
33350 m.selectedBrick = [];
33352 m.selectedBrick.push(this.id);
33353 this.el.addClass(this.activeClass);
33357 isSelected : function(){
33358 return this.el.hasClass(this.activeClass);
33363 Roo.apply(Roo.bootstrap.MasonryBrick, {
33366 groups : new Roo.util.MixedCollection(false, function(o) { return o.el.id; }),
33368 * register a Masonry Brick
33369 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
33372 register : function(brick)
33374 //this.groups[brick.id] = brick;
33375 this.groups.add(brick.id, brick);
33378 * fetch a masonry brick based on the masonry brick ID
33379 * @param {string} the masonry brick to add
33380 * @returns {Roo.bootstrap.MasonryBrick} the masonry brick
33383 get: function(brick_id)
33385 // if (typeof(this.groups[brick_id]) == 'undefined') {
33388 // return this.groups[brick_id] ;
33390 if(this.groups.key(brick_id)) {
33391 return this.groups.key(brick_id);
33409 * @class Roo.bootstrap.Brick
33410 * @extends Roo.bootstrap.Component
33411 * Bootstrap Brick class
33414 * Create a new Brick
33415 * @param {Object} config The config object
33418 Roo.bootstrap.Brick = function(config){
33419 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
33425 * When a Brick is click
33426 * @param {Roo.bootstrap.Brick} this
33427 * @param {Roo.EventObject} e
33433 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
33436 * @cfg {String} title
33440 * @cfg {String} html
33444 * @cfg {String} bgimage
33448 * @cfg {String} cls
33452 * @cfg {String} href
33456 * @cfg {String} video
33460 * @cfg {Boolean} square
33464 getAutoCreate : function()
33466 var cls = 'roo-brick';
33468 if(this.href.length){
33469 cls += ' roo-brick-link';
33472 if(this.bgimage.length){
33473 cls += ' roo-brick-image';
33476 if(!this.html.length && !this.bgimage.length){
33477 cls += ' roo-brick-center-title';
33480 if(!this.html.length && this.bgimage.length){
33481 cls += ' roo-brick-bottom-title';
33485 cls += ' ' + this.cls;
33489 tag: (this.href.length) ? 'a' : 'div',
33494 cls: 'roo-brick-paragraph',
33500 if(this.href.length){
33501 cfg.href = this.href;
33504 var cn = cfg.cn[0].cn;
33506 if(this.title.length){
33509 cls: 'roo-brick-title',
33514 if(this.html.length){
33517 cls: 'roo-brick-text',
33524 if(this.bgimage.length){
33527 cls: 'roo-brick-image-view',
33535 initEvents: function()
33537 if(this.title.length || this.html.length){
33538 this.el.on('mouseenter' ,this.enter, this);
33539 this.el.on('mouseleave', this.leave, this);
33542 Roo.EventManager.onWindowResize(this.resize, this);
33544 if(this.bgimage.length){
33545 this.imageEl = this.el.select('.roo-brick-image-view', true).first();
33546 this.imageEl.on('load', this.onImageLoad, this);
33553 onImageLoad : function()
33558 resize : function()
33560 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
33562 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
33564 if(this.bgimage.length){
33565 var image = this.el.select('.roo-brick-image-view', true).first();
33567 image.setWidth(paragraph.getWidth());
33570 image.setHeight(paragraph.getWidth());
33573 this.el.setHeight(image.getHeight());
33574 paragraph.setHeight(image.getHeight());
33580 enter: function(e, el)
33582 e.preventDefault();
33584 if(this.bgimage.length){
33585 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
33586 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
33590 leave: function(e, el)
33592 e.preventDefault();
33594 if(this.bgimage.length){
33595 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
33596 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
33611 * @class Roo.bootstrap.NumberField
33612 * @extends Roo.bootstrap.Input
33613 * Bootstrap NumberField class
33619 * Create a new NumberField
33620 * @param {Object} config The config object
33623 Roo.bootstrap.NumberField = function(config){
33624 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
33627 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
33630 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
33632 allowDecimals : true,
33634 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
33636 decimalSeparator : ".",
33638 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
33640 decimalPrecision : 2,
33642 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
33644 allowNegative : true,
33647 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
33651 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
33653 minValue : Number.NEGATIVE_INFINITY,
33655 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
33657 maxValue : Number.MAX_VALUE,
33659 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
33661 minText : "The minimum value for this field is {0}",
33663 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
33665 maxText : "The maximum value for this field is {0}",
33667 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
33668 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
33670 nanText : "{0} is not a valid number",
33672 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
33674 thousandsDelimiter : false,
33676 * @cfg {String} valueAlign alignment of value
33678 valueAlign : "left",
33680 getAutoCreate : function()
33682 var hiddenInput = {
33686 cls: 'hidden-number-input'
33690 hiddenInput.name = this.name;
33695 var cfg = Roo.bootstrap.NumberField.superclass.getAutoCreate.call(this);
33697 this.name = hiddenInput.name;
33699 if(cfg.cn.length > 0) {
33700 cfg.cn.push(hiddenInput);
33707 initEvents : function()
33709 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
33711 var allowed = "0123456789";
33713 if(this.allowDecimals){
33714 allowed += this.decimalSeparator;
33717 if(this.allowNegative){
33721 if(this.thousandsDelimiter) {
33725 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
33727 var keyPress = function(e){
33729 var k = e.getKey();
33731 var c = e.getCharCode();
33734 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
33735 allowed.indexOf(String.fromCharCode(c)) === -1
33741 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
33745 if(allowed.indexOf(String.fromCharCode(c)) === -1){
33750 this.el.on("keypress", keyPress, this);
33753 validateValue : function(value)
33756 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
33760 var num = this.parseValue(value);
33763 this.markInvalid(String.format(this.nanText, value));
33767 if(num < this.minValue){
33768 this.markInvalid(String.format(this.minText, this.minValue));
33772 if(num > this.maxValue){
33773 this.markInvalid(String.format(this.maxText, this.maxValue));
33780 getValue : function()
33782 var v = this.hiddenEl().getValue();
33784 return this.fixPrecision(this.parseValue(v));
33787 parseValue : function(value)
33789 if(this.thousandsDelimiter) {
33791 r = new RegExp(",", "g");
33792 value = value.replace(r, "");
33795 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
33796 return isNaN(value) ? '' : value;
33799 fixPrecision : function(value)
33801 if(this.thousandsDelimiter) {
33803 r = new RegExp(",", "g");
33804 value = value.replace(r, "");
33807 var nan = isNaN(value);
33809 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
33810 return nan ? '' : value;
33812 return parseFloat(value).toFixed(this.decimalPrecision);
33815 setValue : function(v)
33817 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
33823 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
33825 this.inputEl().dom.value = (v == '') ? '' :
33826 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
33828 if(!this.allowZero && v === '0') {
33829 this.hiddenEl().dom.value = '';
33830 this.inputEl().dom.value = '';
33837 decimalPrecisionFcn : function(v)
33839 return Math.floor(v);
33842 beforeBlur : function()
33844 var v = this.parseValue(this.getRawValue());
33846 if(v || v === 0 || v === ''){
33851 hiddenEl : function()
33853 return this.el.select('input.hidden-number-input',true).first();
33865 * @class Roo.bootstrap.DocumentSlider
33866 * @extends Roo.bootstrap.Component
33867 * Bootstrap DocumentSlider class
33870 * Create a new DocumentViewer
33871 * @param {Object} config The config object
33874 Roo.bootstrap.DocumentSlider = function(config){
33875 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
33882 * Fire after initEvent
33883 * @param {Roo.bootstrap.DocumentSlider} this
33888 * Fire after update
33889 * @param {Roo.bootstrap.DocumentSlider} this
33895 * @param {Roo.bootstrap.DocumentSlider} this
33901 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
33907 getAutoCreate : function()
33911 cls : 'roo-document-slider',
33915 cls : 'roo-document-slider-header',
33919 cls : 'roo-document-slider-header-title'
33925 cls : 'roo-document-slider-body',
33929 cls : 'roo-document-slider-prev',
33933 cls : 'fa fa-chevron-left'
33939 cls : 'roo-document-slider-thumb',
33943 cls : 'roo-document-slider-image'
33949 cls : 'roo-document-slider-next',
33953 cls : 'fa fa-chevron-right'
33965 initEvents : function()
33967 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
33968 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
33970 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
33971 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
33973 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
33974 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
33976 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
33977 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
33979 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
33980 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
33982 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
33983 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33985 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
33986 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33988 this.thumbEl.on('click', this.onClick, this);
33990 this.prevIndicator.on('click', this.prev, this);
33992 this.nextIndicator.on('click', this.next, this);
33996 initial : function()
33998 if(this.files.length){
33999 this.indicator = 1;
34003 this.fireEvent('initial', this);
34006 update : function()
34008 this.imageEl.attr('src', this.files[this.indicator - 1]);
34010 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
34012 this.prevIndicator.show();
34014 if(this.indicator == 1){
34015 this.prevIndicator.hide();
34018 this.nextIndicator.show();
34020 if(this.indicator == this.files.length){
34021 this.nextIndicator.hide();
34024 this.thumbEl.scrollTo('top');
34026 this.fireEvent('update', this);
34029 onClick : function(e)
34031 e.preventDefault();
34033 this.fireEvent('click', this);
34038 e.preventDefault();
34040 this.indicator = Math.max(1, this.indicator - 1);
34047 e.preventDefault();
34049 this.indicator = Math.min(this.files.length, this.indicator + 1);
34063 * @class Roo.bootstrap.RadioSet
34064 * @extends Roo.bootstrap.Input
34065 * Bootstrap RadioSet class
34066 * @cfg {String} indicatorpos (left|right) default left
34067 * @cfg {Boolean} inline (true|false) inline the element (default true)
34068 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
34070 * Create a new RadioSet
34071 * @param {Object} config The config object
34074 Roo.bootstrap.RadioSet = function(config){
34076 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
34080 Roo.bootstrap.RadioSet.register(this);
34085 * Fires when the element is checked or unchecked.
34086 * @param {Roo.bootstrap.RadioSet} this This radio
34087 * @param {Roo.bootstrap.Radio} item The checked item
34092 * Fires when the element is click.
34093 * @param {Roo.bootstrap.RadioSet} this This radio set
34094 * @param {Roo.bootstrap.Radio} item The checked item
34095 * @param {Roo.EventObject} e The event object
34102 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
34110 indicatorpos : 'left',
34112 getAutoCreate : function()
34116 cls : 'roo-radio-set-label',
34120 html : this.fieldLabel
34124 if (Roo.bootstrap.version == 3) {
34127 if(this.indicatorpos == 'left'){
34130 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
34131 tooltip : 'This field is required'
34136 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
34137 tooltip : 'This field is required'
34143 cls : 'roo-radio-set-items'
34146 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
34148 if (align === 'left' && this.fieldLabel.length) {
34151 cls : "roo-radio-set-right",
34157 if(this.labelWidth > 12){
34158 label.style = "width: " + this.labelWidth + 'px';
34161 if(this.labelWidth < 13 && this.labelmd == 0){
34162 this.labelmd = this.labelWidth;
34165 if(this.labellg > 0){
34166 label.cls += ' col-lg-' + this.labellg;
34167 items.cls += ' col-lg-' + (12 - this.labellg);
34170 if(this.labelmd > 0){
34171 label.cls += ' col-md-' + this.labelmd;
34172 items.cls += ' col-md-' + (12 - this.labelmd);
34175 if(this.labelsm > 0){
34176 label.cls += ' col-sm-' + this.labelsm;
34177 items.cls += ' col-sm-' + (12 - this.labelsm);
34180 if(this.labelxs > 0){
34181 label.cls += ' col-xs-' + this.labelxs;
34182 items.cls += ' col-xs-' + (12 - this.labelxs);
34188 cls : 'roo-radio-set',
34192 cls : 'roo-radio-set-input',
34195 value : this.value ? this.value : ''
34202 if(this.weight.length){
34203 cfg.cls += ' roo-radio-' + this.weight;
34207 cfg.cls += ' roo-radio-set-inline';
34211 ['xs','sm','md','lg'].map(function(size){
34212 if (settings[size]) {
34213 cfg.cls += ' col-' + size + '-' + settings[size];
34221 initEvents : function()
34223 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
34224 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
34226 if(!this.fieldLabel.length){
34227 this.labelEl.hide();
34230 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
34231 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
34233 this.indicator = this.indicatorEl();
34235 if(this.indicator){
34236 this.indicator.addClass('invisible');
34239 this.originalValue = this.getValue();
34243 inputEl: function ()
34245 return this.el.select('.roo-radio-set-input', true).first();
34248 getChildContainer : function()
34250 return this.itemsEl;
34253 register : function(item)
34255 this.radioes.push(item);
34259 validate : function()
34261 if(this.getVisibilityEl().hasClass('hidden')){
34267 Roo.each(this.radioes, function(i){
34276 if(this.allowBlank) {
34280 if(this.disabled || valid){
34285 this.markInvalid();
34290 markValid : function()
34292 if(this.labelEl.isVisible(true) && this.indicatorEl()){
34293 this.indicatorEl().removeClass('visible');
34294 this.indicatorEl().addClass('invisible');
34298 if (Roo.bootstrap.version == 3) {
34299 this.el.removeClass([this.invalidClass, this.validClass]);
34300 this.el.addClass(this.validClass);
34302 this.el.removeClass(['is-invalid','is-valid']);
34303 this.el.addClass(['is-valid']);
34305 this.fireEvent('valid', this);
34308 markInvalid : function(msg)
34310 if(this.allowBlank || this.disabled){
34314 if(this.labelEl.isVisible(true) && this.indicatorEl()){
34315 this.indicatorEl().removeClass('invisible');
34316 this.indicatorEl().addClass('visible');
34318 if (Roo.bootstrap.version == 3) {
34319 this.el.removeClass([this.invalidClass, this.validClass]);
34320 this.el.addClass(this.invalidClass);
34322 this.el.removeClass(['is-invalid','is-valid']);
34323 this.el.addClass(['is-invalid']);
34326 this.fireEvent('invalid', this, msg);
34330 setValue : function(v, suppressEvent)
34332 if(this.value === v){
34339 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
34342 Roo.each(this.radioes, function(i){
34344 i.el.removeClass('checked');
34347 Roo.each(this.radioes, function(i){
34349 if(i.value === v || i.value.toString() === v.toString()){
34351 i.el.addClass('checked');
34353 if(suppressEvent !== true){
34354 this.fireEvent('check', this, i);
34365 clearInvalid : function(){
34367 if(!this.el || this.preventMark){
34371 this.el.removeClass([this.invalidClass]);
34373 this.fireEvent('valid', this);
34378 Roo.apply(Roo.bootstrap.RadioSet, {
34382 register : function(set)
34384 this.groups[set.name] = set;
34387 get: function(name)
34389 if (typeof(this.groups[name]) == 'undefined') {
34393 return this.groups[name] ;
34399 * Ext JS Library 1.1.1
34400 * Copyright(c) 2006-2007, Ext JS, LLC.
34402 * Originally Released Under LGPL - original licence link has changed is not relivant.
34405 * <script type="text/javascript">
34410 * @class Roo.bootstrap.SplitBar
34411 * @extends Roo.util.Observable
34412 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
34416 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
34417 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
34418 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
34419 split.minSize = 100;
34420 split.maxSize = 600;
34421 split.animate = true;
34422 split.on('moved', splitterMoved);
34425 * Create a new SplitBar
34426 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
34427 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
34428 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34429 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
34430 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
34431 position of the SplitBar).
34433 Roo.bootstrap.SplitBar = function(cfg){
34438 // dragElement : elm
34439 // resizingElement: el,
34441 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
34442 // placement : Roo.bootstrap.SplitBar.LEFT ,
34443 // existingProxy ???
34446 this.el = Roo.get(cfg.dragElement, true);
34447 this.el.dom.unselectable = "on";
34449 this.resizingEl = Roo.get(cfg.resizingElement, true);
34453 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34454 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
34457 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
34460 * The minimum size of the resizing element. (Defaults to 0)
34466 * The maximum size of the resizing element. (Defaults to 2000)
34469 this.maxSize = 2000;
34472 * Whether to animate the transition to the new size
34475 this.animate = false;
34478 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
34481 this.useShim = false;
34486 if(!cfg.existingProxy){
34488 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
34490 this.proxy = Roo.get(cfg.existingProxy).dom;
34493 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
34496 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
34499 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
34502 this.dragSpecs = {};
34505 * @private The adapter to use to positon and resize elements
34507 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34508 this.adapter.init(this);
34510 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34512 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
34513 this.el.addClass("roo-splitbar-h");
34516 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
34517 this.el.addClass("roo-splitbar-v");
34523 * Fires when the splitter is moved (alias for {@link #event-moved})
34524 * @param {Roo.bootstrap.SplitBar} this
34525 * @param {Number} newSize the new width or height
34530 * Fires when the splitter is moved
34531 * @param {Roo.bootstrap.SplitBar} this
34532 * @param {Number} newSize the new width or height
34536 * @event beforeresize
34537 * Fires before the splitter is dragged
34538 * @param {Roo.bootstrap.SplitBar} this
34540 "beforeresize" : true,
34542 "beforeapply" : true
34545 Roo.util.Observable.call(this);
34548 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
34549 onStartProxyDrag : function(x, y){
34550 this.fireEvent("beforeresize", this);
34552 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
34554 o.enableDisplayMode("block");
34555 // all splitbars share the same overlay
34556 Roo.bootstrap.SplitBar.prototype.overlay = o;
34558 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
34559 this.overlay.show();
34560 Roo.get(this.proxy).setDisplayed("block");
34561 var size = this.adapter.getElementSize(this);
34562 this.activeMinSize = this.getMinimumSize();;
34563 this.activeMaxSize = this.getMaximumSize();;
34564 var c1 = size - this.activeMinSize;
34565 var c2 = Math.max(this.activeMaxSize - size, 0);
34566 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34567 this.dd.resetConstraints();
34568 this.dd.setXConstraint(
34569 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
34570 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
34572 this.dd.setYConstraint(0, 0);
34574 this.dd.resetConstraints();
34575 this.dd.setXConstraint(0, 0);
34576 this.dd.setYConstraint(
34577 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
34578 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
34581 this.dragSpecs.startSize = size;
34582 this.dragSpecs.startPoint = [x, y];
34583 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
34587 * @private Called after the drag operation by the DDProxy
34589 onEndProxyDrag : function(e){
34590 Roo.get(this.proxy).setDisplayed(false);
34591 var endPoint = Roo.lib.Event.getXY(e);
34593 this.overlay.hide();
34596 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34597 newSize = this.dragSpecs.startSize +
34598 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
34599 endPoint[0] - this.dragSpecs.startPoint[0] :
34600 this.dragSpecs.startPoint[0] - endPoint[0]
34603 newSize = this.dragSpecs.startSize +
34604 (this.placement == Roo.bootstrap.SplitBar.TOP ?
34605 endPoint[1] - this.dragSpecs.startPoint[1] :
34606 this.dragSpecs.startPoint[1] - endPoint[1]
34609 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
34610 if(newSize != this.dragSpecs.startSize){
34611 if(this.fireEvent('beforeapply', this, newSize) !== false){
34612 this.adapter.setElementSize(this, newSize);
34613 this.fireEvent("moved", this, newSize);
34614 this.fireEvent("resize", this, newSize);
34620 * Get the adapter this SplitBar uses
34621 * @return The adapter object
34623 getAdapter : function(){
34624 return this.adapter;
34628 * Set the adapter this SplitBar uses
34629 * @param {Object} adapter A SplitBar adapter object
34631 setAdapter : function(adapter){
34632 this.adapter = adapter;
34633 this.adapter.init(this);
34637 * Gets the minimum size for the resizing element
34638 * @return {Number} The minimum size
34640 getMinimumSize : function(){
34641 return this.minSize;
34645 * Sets the minimum size for the resizing element
34646 * @param {Number} minSize The minimum size
34648 setMinimumSize : function(minSize){
34649 this.minSize = minSize;
34653 * Gets the maximum size for the resizing element
34654 * @return {Number} The maximum size
34656 getMaximumSize : function(){
34657 return this.maxSize;
34661 * Sets the maximum size for the resizing element
34662 * @param {Number} maxSize The maximum size
34664 setMaximumSize : function(maxSize){
34665 this.maxSize = maxSize;
34669 * Sets the initialize size for the resizing element
34670 * @param {Number} size The initial size
34672 setCurrentSize : function(size){
34673 var oldAnimate = this.animate;
34674 this.animate = false;
34675 this.adapter.setElementSize(this, size);
34676 this.animate = oldAnimate;
34680 * Destroy this splitbar.
34681 * @param {Boolean} removeEl True to remove the element
34683 destroy : function(removeEl){
34685 this.shim.remove();
34688 this.proxy.parentNode.removeChild(this.proxy);
34696 * @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.
34698 Roo.bootstrap.SplitBar.createProxy = function(dir){
34699 var proxy = new Roo.Element(document.createElement("div"));
34700 proxy.unselectable();
34701 var cls = 'roo-splitbar-proxy';
34702 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
34703 document.body.appendChild(proxy.dom);
34708 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
34709 * Default Adapter. It assumes the splitter and resizing element are not positioned
34710 * elements and only gets/sets the width of the element. Generally used for table based layouts.
34712 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
34715 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
34716 // do nothing for now
34717 init : function(s){
34721 * Called before drag operations to get the current size of the resizing element.
34722 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34724 getElementSize : function(s){
34725 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34726 return s.resizingEl.getWidth();
34728 return s.resizingEl.getHeight();
34733 * Called after drag operations to set the size of the resizing element.
34734 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34735 * @param {Number} newSize The new size to set
34736 * @param {Function} onComplete A function to be invoked when resizing is complete
34738 setElementSize : function(s, newSize, onComplete){
34739 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34741 s.resizingEl.setWidth(newSize);
34743 onComplete(s, newSize);
34746 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
34751 s.resizingEl.setHeight(newSize);
34753 onComplete(s, newSize);
34756 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
34763 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
34764 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
34765 * Adapter that moves the splitter element to align with the resized sizing element.
34766 * Used with an absolute positioned SplitBar.
34767 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
34768 * document.body, make sure you assign an id to the body element.
34770 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
34771 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34772 this.container = Roo.get(container);
34775 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
34776 init : function(s){
34777 this.basic.init(s);
34780 getElementSize : function(s){
34781 return this.basic.getElementSize(s);
34784 setElementSize : function(s, newSize, onComplete){
34785 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
34788 moveSplitter : function(s){
34789 var yes = Roo.bootstrap.SplitBar;
34790 switch(s.placement){
34792 s.el.setX(s.resizingEl.getRight());
34795 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
34798 s.el.setY(s.resizingEl.getBottom());
34801 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
34808 * Orientation constant - Create a vertical SplitBar
34812 Roo.bootstrap.SplitBar.VERTICAL = 1;
34815 * Orientation constant - Create a horizontal SplitBar
34819 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
34822 * Placement constant - The resizing element is to the left of the splitter element
34826 Roo.bootstrap.SplitBar.LEFT = 1;
34829 * Placement constant - The resizing element is to the right of the splitter element
34833 Roo.bootstrap.SplitBar.RIGHT = 2;
34836 * Placement constant - The resizing element is positioned above the splitter element
34840 Roo.bootstrap.SplitBar.TOP = 3;
34843 * Placement constant - The resizing element is positioned under splitter element
34847 Roo.bootstrap.SplitBar.BOTTOM = 4;
34848 Roo.namespace("Roo.bootstrap.layout");/*
34850 * Ext JS Library 1.1.1
34851 * Copyright(c) 2006-2007, Ext JS, LLC.
34853 * Originally Released Under LGPL - original licence link has changed is not relivant.
34856 * <script type="text/javascript">
34860 * @class Roo.bootstrap.layout.Manager
34861 * @extends Roo.bootstrap.Component
34862 * Base class for layout managers.
34864 Roo.bootstrap.layout.Manager = function(config)
34866 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
34872 /** false to disable window resize monitoring @type Boolean */
34873 this.monitorWindowResize = true;
34878 * Fires when a layout is performed.
34879 * @param {Roo.LayoutManager} this
34883 * @event regionresized
34884 * Fires when the user resizes a region.
34885 * @param {Roo.LayoutRegion} region The resized region
34886 * @param {Number} newSize The new size (width for east/west, height for north/south)
34888 "regionresized" : true,
34890 * @event regioncollapsed
34891 * Fires when a region is collapsed.
34892 * @param {Roo.LayoutRegion} region The collapsed region
34894 "regioncollapsed" : true,
34896 * @event regionexpanded
34897 * Fires when a region is expanded.
34898 * @param {Roo.LayoutRegion} region The expanded region
34900 "regionexpanded" : true
34902 this.updating = false;
34905 this.el = Roo.get(config.el);
34911 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
34916 monitorWindowResize : true,
34922 onRender : function(ct, position)
34925 this.el = Roo.get(ct);
34928 //this.fireEvent('render',this);
34932 initEvents: function()
34936 // ie scrollbar fix
34937 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
34938 document.body.scroll = "no";
34939 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
34940 this.el.position('relative');
34942 this.id = this.el.id;
34943 this.el.addClass("roo-layout-container");
34944 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
34945 if(this.el.dom != document.body ) {
34946 this.el.on('resize', this.layout,this);
34947 this.el.on('show', this.layout,this);
34953 * Returns true if this layout is currently being updated
34954 * @return {Boolean}
34956 isUpdating : function(){
34957 return this.updating;
34961 * Suspend the LayoutManager from doing auto-layouts while
34962 * making multiple add or remove calls
34964 beginUpdate : function(){
34965 this.updating = true;
34969 * Restore auto-layouts and optionally disable the manager from performing a layout
34970 * @param {Boolean} noLayout true to disable a layout update
34972 endUpdate : function(noLayout){
34973 this.updating = false;
34979 layout: function(){
34983 onRegionResized : function(region, newSize){
34984 this.fireEvent("regionresized", region, newSize);
34988 onRegionCollapsed : function(region){
34989 this.fireEvent("regioncollapsed", region);
34992 onRegionExpanded : function(region){
34993 this.fireEvent("regionexpanded", region);
34997 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
34998 * performs box-model adjustments.
34999 * @return {Object} The size as an object {width: (the width), height: (the height)}
35001 getViewSize : function()
35004 if(this.el.dom != document.body){
35005 size = this.el.getSize();
35007 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
35009 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
35010 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
35015 * Returns the Element this layout is bound to.
35016 * @return {Roo.Element}
35018 getEl : function(){
35023 * Returns the specified region.
35024 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
35025 * @return {Roo.LayoutRegion}
35027 getRegion : function(target){
35028 return this.regions[target.toLowerCase()];
35031 onWindowResize : function(){
35032 if(this.monitorWindowResize){
35039 * Ext JS Library 1.1.1
35040 * Copyright(c) 2006-2007, Ext JS, LLC.
35042 * Originally Released Under LGPL - original licence link has changed is not relivant.
35045 * <script type="text/javascript">
35048 * @class Roo.bootstrap.layout.Border
35049 * @extends Roo.bootstrap.layout.Manager
35050 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
35051 * please see: examples/bootstrap/nested.html<br><br>
35053 <b>The container the layout is rendered into can be either the body element or any other element.
35054 If it is not the body element, the container needs to either be an absolute positioned element,
35055 or you will need to add "position:relative" to the css of the container. You will also need to specify
35056 the container size if it is not the body element.</b>
35059 * Create a new Border
35060 * @param {Object} config Configuration options
35062 Roo.bootstrap.layout.Border = function(config){
35063 config = config || {};
35064 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
35068 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
35069 if(config[region]){
35070 config[region].region = region;
35071 this.addRegion(config[region]);
35077 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
35079 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
35081 * Creates and adds a new region if it doesn't already exist.
35082 * @param {String} target The target region key (north, south, east, west or center).
35083 * @param {Object} config The regions config object
35084 * @return {BorderLayoutRegion} The new region
35086 addRegion : function(config)
35088 if(!this.regions[config.region]){
35089 var r = this.factory(config);
35090 this.bindRegion(r);
35092 return this.regions[config.region];
35096 bindRegion : function(r){
35097 this.regions[r.config.region] = r;
35099 r.on("visibilitychange", this.layout, this);
35100 r.on("paneladded", this.layout, this);
35101 r.on("panelremoved", this.layout, this);
35102 r.on("invalidated", this.layout, this);
35103 r.on("resized", this.onRegionResized, this);
35104 r.on("collapsed", this.onRegionCollapsed, this);
35105 r.on("expanded", this.onRegionExpanded, this);
35109 * Performs a layout update.
35111 layout : function()
35113 if(this.updating) {
35117 // render all the rebions if they have not been done alreayd?
35118 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
35119 if(this.regions[region] && !this.regions[region].bodyEl){
35120 this.regions[region].onRender(this.el)
35124 var size = this.getViewSize();
35125 var w = size.width;
35126 var h = size.height;
35131 //var x = 0, y = 0;
35133 var rs = this.regions;
35134 var north = rs["north"];
35135 var south = rs["south"];
35136 var west = rs["west"];
35137 var east = rs["east"];
35138 var center = rs["center"];
35139 //if(this.hideOnLayout){ // not supported anymore
35140 //c.el.setStyle("display", "none");
35142 if(north && north.isVisible()){
35143 var b = north.getBox();
35144 var m = north.getMargins();
35145 b.width = w - (m.left+m.right);
35148 centerY = b.height + b.y + m.bottom;
35149 centerH -= centerY;
35150 north.updateBox(this.safeBox(b));
35152 if(south && south.isVisible()){
35153 var b = south.getBox();
35154 var m = south.getMargins();
35155 b.width = w - (m.left+m.right);
35157 var totalHeight = (b.height + m.top + m.bottom);
35158 b.y = h - totalHeight + m.top;
35159 centerH -= totalHeight;
35160 south.updateBox(this.safeBox(b));
35162 if(west && west.isVisible()){
35163 var b = west.getBox();
35164 var m = west.getMargins();
35165 b.height = centerH - (m.top+m.bottom);
35167 b.y = centerY + m.top;
35168 var totalWidth = (b.width + m.left + m.right);
35169 centerX += totalWidth;
35170 centerW -= totalWidth;
35171 west.updateBox(this.safeBox(b));
35173 if(east && east.isVisible()){
35174 var b = east.getBox();
35175 var m = east.getMargins();
35176 b.height = centerH - (m.top+m.bottom);
35177 var totalWidth = (b.width + m.left + m.right);
35178 b.x = w - totalWidth + m.left;
35179 b.y = centerY + m.top;
35180 centerW -= totalWidth;
35181 east.updateBox(this.safeBox(b));
35184 var m = center.getMargins();
35186 x: centerX + m.left,
35187 y: centerY + m.top,
35188 width: centerW - (m.left+m.right),
35189 height: centerH - (m.top+m.bottom)
35191 //if(this.hideOnLayout){
35192 //center.el.setStyle("display", "block");
35194 center.updateBox(this.safeBox(centerBox));
35197 this.fireEvent("layout", this);
35201 safeBox : function(box){
35202 box.width = Math.max(0, box.width);
35203 box.height = Math.max(0, box.height);
35208 * Adds a ContentPanel (or subclass) to this layout.
35209 * @param {String} target The target region key (north, south, east, west or center).
35210 * @param {Roo.ContentPanel} panel The panel to add
35211 * @return {Roo.ContentPanel} The added panel
35213 add : function(target, panel){
35215 target = target.toLowerCase();
35216 return this.regions[target].add(panel);
35220 * Remove a ContentPanel (or subclass) to this layout.
35221 * @param {String} target The target region key (north, south, east, west or center).
35222 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
35223 * @return {Roo.ContentPanel} The removed panel
35225 remove : function(target, panel){
35226 target = target.toLowerCase();
35227 return this.regions[target].remove(panel);
35231 * Searches all regions for a panel with the specified id
35232 * @param {String} panelId
35233 * @return {Roo.ContentPanel} The panel or null if it wasn't found
35235 findPanel : function(panelId){
35236 var rs = this.regions;
35237 for(var target in rs){
35238 if(typeof rs[target] != "function"){
35239 var p = rs[target].getPanel(panelId);
35249 * Searches all regions for a panel with the specified id and activates (shows) it.
35250 * @param {String/ContentPanel} panelId The panels id or the panel itself
35251 * @return {Roo.ContentPanel} The shown panel or null
35253 showPanel : function(panelId) {
35254 var rs = this.regions;
35255 for(var target in rs){
35256 var r = rs[target];
35257 if(typeof r != "function"){
35258 if(r.hasPanel(panelId)){
35259 return r.showPanel(panelId);
35267 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
35268 * @param {Roo.state.Provider} provider (optional) An alternate state provider
35271 restoreState : function(provider){
35273 provider = Roo.state.Manager;
35275 var sm = new Roo.LayoutStateManager();
35276 sm.init(this, provider);
35282 * Adds a xtype elements to the layout.
35286 xtype : 'ContentPanel',
35293 xtype : 'NestedLayoutPanel',
35299 items : [ ... list of content panels or nested layout panels.. ]
35303 * @param {Object} cfg Xtype definition of item to add.
35305 addxtype : function(cfg)
35307 // basically accepts a pannel...
35308 // can accept a layout region..!?!?
35309 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
35312 // theory? children can only be panels??
35314 //if (!cfg.xtype.match(/Panel$/)) {
35319 if (typeof(cfg.region) == 'undefined') {
35320 Roo.log("Failed to add Panel, region was not set");
35324 var region = cfg.region;
35330 xitems = cfg.items;
35337 case 'Content': // ContentPanel (el, cfg)
35338 case 'Scroll': // ContentPanel (el, cfg)
35340 cfg.autoCreate = true;
35341 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35343 // var el = this.el.createChild();
35344 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
35347 this.add(region, ret);
35351 case 'TreePanel': // our new panel!
35352 cfg.el = this.el.createChild();
35353 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
35354 this.add(region, ret);
35359 // create a new Layout (which is a Border Layout...
35361 var clayout = cfg.layout;
35362 clayout.el = this.el.createChild();
35363 clayout.items = clayout.items || [];
35367 // replace this exitems with the clayout ones..
35368 xitems = clayout.items;
35370 // force background off if it's in center...
35371 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
35372 cfg.background = false;
35374 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
35377 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35378 //console.log('adding nested layout panel ' + cfg.toSource());
35379 this.add(region, ret);
35380 nb = {}; /// find first...
35385 // needs grid and region
35387 //var el = this.getRegion(region).el.createChild();
35389 *var el = this.el.createChild();
35390 // create the grid first...
35391 cfg.grid.container = el;
35392 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
35395 if (region == 'center' && this.active ) {
35396 cfg.background = false;
35399 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35401 this.add(region, ret);
35403 if (cfg.background) {
35404 // render grid on panel activation (if panel background)
35405 ret.on('activate', function(gp) {
35406 if (!gp.grid.rendered) {
35407 // gp.grid.render(el);
35411 // cfg.grid.render(el);
35417 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
35418 // it was the old xcomponent building that caused this before.
35419 // espeically if border is the top element in the tree.
35429 if (typeof(Roo[cfg.xtype]) != 'undefined') {
35431 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
35432 this.add(region, ret);
35436 throw "Can not add '" + cfg.xtype + "' to Border";
35442 this.beginUpdate();
35446 Roo.each(xitems, function(i) {
35447 region = nb && i.region ? i.region : false;
35449 var add = ret.addxtype(i);
35452 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
35453 if (!i.background) {
35454 abn[region] = nb[region] ;
35461 // make the last non-background panel active..
35462 //if (nb) { Roo.log(abn); }
35465 for(var r in abn) {
35466 region = this.getRegion(r);
35468 // tried using nb[r], but it does not work..
35470 region.showPanel(abn[r]);
35481 factory : function(cfg)
35484 var validRegions = Roo.bootstrap.layout.Border.regions;
35486 var target = cfg.region;
35489 var r = Roo.bootstrap.layout;
35493 return new r.North(cfg);
35495 return new r.South(cfg);
35497 return new r.East(cfg);
35499 return new r.West(cfg);
35501 return new r.Center(cfg);
35503 throw 'Layout region "'+target+'" not supported.';
35510 * Ext JS Library 1.1.1
35511 * Copyright(c) 2006-2007, Ext JS, LLC.
35513 * Originally Released Under LGPL - original licence link has changed is not relivant.
35516 * <script type="text/javascript">
35520 * @class Roo.bootstrap.layout.Basic
35521 * @extends Roo.util.Observable
35522 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
35523 * and does not have a titlebar, tabs or any other features. All it does is size and position
35524 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
35525 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35526 * @cfg {string} region the region that it inhabits..
35527 * @cfg {bool} skipConfig skip config?
35531 Roo.bootstrap.layout.Basic = function(config){
35533 this.mgr = config.mgr;
35535 this.position = config.region;
35537 var skipConfig = config.skipConfig;
35541 * @scope Roo.BasicLayoutRegion
35545 * @event beforeremove
35546 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
35547 * @param {Roo.LayoutRegion} this
35548 * @param {Roo.ContentPanel} panel The panel
35549 * @param {Object} e The cancel event object
35551 "beforeremove" : true,
35553 * @event invalidated
35554 * Fires when the layout for this region is changed.
35555 * @param {Roo.LayoutRegion} this
35557 "invalidated" : true,
35559 * @event visibilitychange
35560 * Fires when this region is shown or hidden
35561 * @param {Roo.LayoutRegion} this
35562 * @param {Boolean} visibility true or false
35564 "visibilitychange" : true,
35566 * @event paneladded
35567 * Fires when a panel is added.
35568 * @param {Roo.LayoutRegion} this
35569 * @param {Roo.ContentPanel} panel The panel
35571 "paneladded" : true,
35573 * @event panelremoved
35574 * Fires when a panel is removed.
35575 * @param {Roo.LayoutRegion} this
35576 * @param {Roo.ContentPanel} panel The panel
35578 "panelremoved" : true,
35580 * @event beforecollapse
35581 * Fires when this region before collapse.
35582 * @param {Roo.LayoutRegion} this
35584 "beforecollapse" : true,
35587 * Fires when this region is collapsed.
35588 * @param {Roo.LayoutRegion} this
35590 "collapsed" : true,
35593 * Fires when this region is expanded.
35594 * @param {Roo.LayoutRegion} this
35599 * Fires when this region is slid into view.
35600 * @param {Roo.LayoutRegion} this
35602 "slideshow" : true,
35605 * Fires when this region slides out of view.
35606 * @param {Roo.LayoutRegion} this
35608 "slidehide" : true,
35610 * @event panelactivated
35611 * Fires when a panel is activated.
35612 * @param {Roo.LayoutRegion} this
35613 * @param {Roo.ContentPanel} panel The activated panel
35615 "panelactivated" : true,
35618 * Fires when the user resizes this region.
35619 * @param {Roo.LayoutRegion} this
35620 * @param {Number} newSize The new size (width for east/west, height for north/south)
35624 /** A collection of panels in this region. @type Roo.util.MixedCollection */
35625 this.panels = new Roo.util.MixedCollection();
35626 this.panels.getKey = this.getPanelId.createDelegate(this);
35628 this.activePanel = null;
35629 // ensure listeners are added...
35631 if (config.listeners || config.events) {
35632 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
35633 listeners : config.listeners || {},
35634 events : config.events || {}
35638 if(skipConfig !== true){
35639 this.applyConfig(config);
35643 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
35645 getPanelId : function(p){
35649 applyConfig : function(config){
35650 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35651 this.config = config;
35656 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
35657 * the width, for horizontal (north, south) the height.
35658 * @param {Number} newSize The new width or height
35660 resizeTo : function(newSize){
35661 var el = this.el ? this.el :
35662 (this.activePanel ? this.activePanel.getEl() : null);
35664 switch(this.position){
35667 el.setWidth(newSize);
35668 this.fireEvent("resized", this, newSize);
35672 el.setHeight(newSize);
35673 this.fireEvent("resized", this, newSize);
35679 getBox : function(){
35680 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
35683 getMargins : function(){
35684 return this.margins;
35687 updateBox : function(box){
35689 var el = this.activePanel.getEl();
35690 el.dom.style.left = box.x + "px";
35691 el.dom.style.top = box.y + "px";
35692 this.activePanel.setSize(box.width, box.height);
35696 * Returns the container element for this region.
35697 * @return {Roo.Element}
35699 getEl : function(){
35700 return this.activePanel;
35704 * Returns true if this region is currently visible.
35705 * @return {Boolean}
35707 isVisible : function(){
35708 return this.activePanel ? true : false;
35711 setActivePanel : function(panel){
35712 panel = this.getPanel(panel);
35713 if(this.activePanel && this.activePanel != panel){
35714 this.activePanel.setActiveState(false);
35715 this.activePanel.getEl().setLeftTop(-10000,-10000);
35717 this.activePanel = panel;
35718 panel.setActiveState(true);
35720 panel.setSize(this.box.width, this.box.height);
35722 this.fireEvent("panelactivated", this, panel);
35723 this.fireEvent("invalidated");
35727 * Show the specified panel.
35728 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
35729 * @return {Roo.ContentPanel} The shown panel or null
35731 showPanel : function(panel){
35732 panel = this.getPanel(panel);
35734 this.setActivePanel(panel);
35740 * Get the active panel for this region.
35741 * @return {Roo.ContentPanel} The active panel or null
35743 getActivePanel : function(){
35744 return this.activePanel;
35748 * Add the passed ContentPanel(s)
35749 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35750 * @return {Roo.ContentPanel} The panel added (if only one was added)
35752 add : function(panel){
35753 if(arguments.length > 1){
35754 for(var i = 0, len = arguments.length; i < len; i++) {
35755 this.add(arguments[i]);
35759 if(this.hasPanel(panel)){
35760 this.showPanel(panel);
35763 var el = panel.getEl();
35764 if(el.dom.parentNode != this.mgr.el.dom){
35765 this.mgr.el.dom.appendChild(el.dom);
35767 if(panel.setRegion){
35768 panel.setRegion(this);
35770 this.panels.add(panel);
35771 el.setStyle("position", "absolute");
35772 if(!panel.background){
35773 this.setActivePanel(panel);
35774 if(this.config.initialSize && this.panels.getCount()==1){
35775 this.resizeTo(this.config.initialSize);
35778 this.fireEvent("paneladded", this, panel);
35783 * Returns true if the panel is in this region.
35784 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35785 * @return {Boolean}
35787 hasPanel : function(panel){
35788 if(typeof panel == "object"){ // must be panel obj
35789 panel = panel.getId();
35791 return this.getPanel(panel) ? true : false;
35795 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35796 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35797 * @param {Boolean} preservePanel Overrides the config preservePanel option
35798 * @return {Roo.ContentPanel} The panel that was removed
35800 remove : function(panel, preservePanel){
35801 panel = this.getPanel(panel);
35806 this.fireEvent("beforeremove", this, panel, e);
35807 if(e.cancel === true){
35810 var panelId = panel.getId();
35811 this.panels.removeKey(panelId);
35816 * Returns the panel specified or null if it's not in this region.
35817 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35818 * @return {Roo.ContentPanel}
35820 getPanel : function(id){
35821 if(typeof id == "object"){ // must be panel obj
35824 return this.panels.get(id);
35828 * Returns this regions position (north/south/east/west/center).
35831 getPosition: function(){
35832 return this.position;
35836 * Ext JS Library 1.1.1
35837 * Copyright(c) 2006-2007, Ext JS, LLC.
35839 * Originally Released Under LGPL - original licence link has changed is not relivant.
35842 * <script type="text/javascript">
35846 * @class Roo.bootstrap.layout.Region
35847 * @extends Roo.bootstrap.layout.Basic
35848 * This class represents a region in a layout manager.
35850 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
35851 * @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})
35852 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
35853 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
35854 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
35855 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
35856 * @cfg {String} title The title for the region (overrides panel titles)
35857 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
35858 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
35859 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
35860 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
35861 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
35862 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
35863 * the space available, similar to FireFox 1.5 tabs (defaults to false)
35864 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
35865 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
35866 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
35868 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
35869 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
35870 * @cfg {Boolean} disableTabTips True to disable tab tooltips
35871 * @cfg {Number} width For East/West panels
35872 * @cfg {Number} height For North/South panels
35873 * @cfg {Boolean} split To show the splitter
35874 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
35876 * @cfg {string} cls Extra CSS classes to add to region
35878 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35879 * @cfg {string} region the region that it inhabits..
35882 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
35883 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
35885 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
35886 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
35887 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
35889 Roo.bootstrap.layout.Region = function(config)
35891 this.applyConfig(config);
35893 var mgr = config.mgr;
35894 var pos = config.region;
35895 config.skipConfig = true;
35896 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
35899 this.onRender(mgr.el);
35902 this.visible = true;
35903 this.collapsed = false;
35904 this.unrendered_panels = [];
35907 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
35909 position: '', // set by wrapper (eg. north/south etc..)
35910 unrendered_panels : null, // unrendered panels.
35911 createBody : function(){
35912 /** This region's body element
35913 * @type Roo.Element */
35914 this.bodyEl = this.el.createChild({
35916 cls: "roo-layout-panel-body tab-content" // bootstrap added...
35920 onRender: function(ctr, pos)
35922 var dh = Roo.DomHelper;
35923 /** This region's container element
35924 * @type Roo.Element */
35925 this.el = dh.append(ctr.dom, {
35927 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
35929 /** This region's title element
35930 * @type Roo.Element */
35932 this.titleEl = dh.append(this.el.dom,
35935 unselectable: "on",
35936 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
35938 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
35939 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
35942 this.titleEl.enableDisplayMode();
35943 /** This region's title text element
35944 * @type HTMLElement */
35945 this.titleTextEl = this.titleEl.dom.firstChild;
35946 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
35948 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
35949 this.closeBtn.enableDisplayMode();
35950 this.closeBtn.on("click", this.closeClicked, this);
35951 this.closeBtn.hide();
35953 this.createBody(this.config);
35954 if(this.config.hideWhenEmpty){
35956 this.on("paneladded", this.validateVisibility, this);
35957 this.on("panelremoved", this.validateVisibility, this);
35959 if(this.autoScroll){
35960 this.bodyEl.setStyle("overflow", "auto");
35962 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
35964 //if(c.titlebar !== false){
35965 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
35966 this.titleEl.hide();
35968 this.titleEl.show();
35969 if(this.config.title){
35970 this.titleTextEl.innerHTML = this.config.title;
35974 if(this.config.collapsed){
35975 this.collapse(true);
35977 if(this.config.hidden){
35981 if (this.unrendered_panels && this.unrendered_panels.length) {
35982 for (var i =0;i< this.unrendered_panels.length; i++) {
35983 this.add(this.unrendered_panels[i]);
35985 this.unrendered_panels = null;
35991 applyConfig : function(c)
35994 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
35995 var dh = Roo.DomHelper;
35996 if(c.titlebar !== false){
35997 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
35998 this.collapseBtn.on("click", this.collapse, this);
35999 this.collapseBtn.enableDisplayMode();
36001 if(c.showPin === true || this.showPin){
36002 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
36003 this.stickBtn.enableDisplayMode();
36004 this.stickBtn.on("click", this.expand, this);
36005 this.stickBtn.hide();
36010 /** This region's collapsed element
36011 * @type Roo.Element */
36014 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
36015 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
36018 if(c.floatable !== false){
36019 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
36020 this.collapsedEl.on("click", this.collapseClick, this);
36023 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
36024 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
36025 id: "message", unselectable: "on", style:{"float":"left"}});
36026 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
36028 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
36029 this.expandBtn.on("click", this.expand, this);
36033 if(this.collapseBtn){
36034 this.collapseBtn.setVisible(c.collapsible == true);
36037 this.cmargins = c.cmargins || this.cmargins ||
36038 (this.position == "west" || this.position == "east" ?
36039 {top: 0, left: 2, right:2, bottom: 0} :
36040 {top: 2, left: 0, right:0, bottom: 2});
36042 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
36045 this.bottomTabs = c.tabPosition != "top";
36047 this.autoScroll = c.autoScroll || false;
36052 this.duration = c.duration || .30;
36053 this.slideDuration = c.slideDuration || .45;
36058 * Returns true if this region is currently visible.
36059 * @return {Boolean}
36061 isVisible : function(){
36062 return this.visible;
36066 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
36067 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
36069 //setCollapsedTitle : function(title){
36070 // title = title || " ";
36071 // if(this.collapsedTitleTextEl){
36072 // this.collapsedTitleTextEl.innerHTML = title;
36076 getBox : function(){
36078 // if(!this.collapsed){
36079 b = this.el.getBox(false, true);
36081 // b = this.collapsedEl.getBox(false, true);
36086 getMargins : function(){
36087 return this.margins;
36088 //return this.collapsed ? this.cmargins : this.margins;
36091 highlight : function(){
36092 this.el.addClass("x-layout-panel-dragover");
36095 unhighlight : function(){
36096 this.el.removeClass("x-layout-panel-dragover");
36099 updateBox : function(box)
36101 if (!this.bodyEl) {
36102 return; // not rendered yet..
36106 if(!this.collapsed){
36107 this.el.dom.style.left = box.x + "px";
36108 this.el.dom.style.top = box.y + "px";
36109 this.updateBody(box.width, box.height);
36111 this.collapsedEl.dom.style.left = box.x + "px";
36112 this.collapsedEl.dom.style.top = box.y + "px";
36113 this.collapsedEl.setSize(box.width, box.height);
36116 this.tabs.autoSizeTabs();
36120 updateBody : function(w, h)
36123 this.el.setWidth(w);
36124 w -= this.el.getBorderWidth("rl");
36125 if(this.config.adjustments){
36126 w += this.config.adjustments[0];
36129 if(h !== null && h > 0){
36130 this.el.setHeight(h);
36131 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
36132 h -= this.el.getBorderWidth("tb");
36133 if(this.config.adjustments){
36134 h += this.config.adjustments[1];
36136 this.bodyEl.setHeight(h);
36138 h = this.tabs.syncHeight(h);
36141 if(this.panelSize){
36142 w = w !== null ? w : this.panelSize.width;
36143 h = h !== null ? h : this.panelSize.height;
36145 if(this.activePanel){
36146 var el = this.activePanel.getEl();
36147 w = w !== null ? w : el.getWidth();
36148 h = h !== null ? h : el.getHeight();
36149 this.panelSize = {width: w, height: h};
36150 this.activePanel.setSize(w, h);
36152 if(Roo.isIE && this.tabs){
36153 this.tabs.el.repaint();
36158 * Returns the container element for this region.
36159 * @return {Roo.Element}
36161 getEl : function(){
36166 * Hides this region.
36169 //if(!this.collapsed){
36170 this.el.dom.style.left = "-2000px";
36173 // this.collapsedEl.dom.style.left = "-2000px";
36174 // this.collapsedEl.hide();
36176 this.visible = false;
36177 this.fireEvent("visibilitychange", this, false);
36181 * Shows this region if it was previously hidden.
36184 //if(!this.collapsed){
36187 // this.collapsedEl.show();
36189 this.visible = true;
36190 this.fireEvent("visibilitychange", this, true);
36193 closeClicked : function(){
36194 if(this.activePanel){
36195 this.remove(this.activePanel);
36199 collapseClick : function(e){
36201 e.stopPropagation();
36204 e.stopPropagation();
36210 * Collapses this region.
36211 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
36214 collapse : function(skipAnim, skipCheck = false){
36215 if(this.collapsed) {
36219 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
36221 this.collapsed = true;
36223 this.split.el.hide();
36225 if(this.config.animate && skipAnim !== true){
36226 this.fireEvent("invalidated", this);
36227 this.animateCollapse();
36229 this.el.setLocation(-20000,-20000);
36231 this.collapsedEl.show();
36232 this.fireEvent("collapsed", this);
36233 this.fireEvent("invalidated", this);
36239 animateCollapse : function(){
36244 * Expands this region if it was previously collapsed.
36245 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
36246 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
36249 expand : function(e, skipAnim){
36251 e.stopPropagation();
36253 if(!this.collapsed || this.el.hasActiveFx()) {
36257 this.afterSlideIn();
36260 this.collapsed = false;
36261 if(this.config.animate && skipAnim !== true){
36262 this.animateExpand();
36266 this.split.el.show();
36268 this.collapsedEl.setLocation(-2000,-2000);
36269 this.collapsedEl.hide();
36270 this.fireEvent("invalidated", this);
36271 this.fireEvent("expanded", this);
36275 animateExpand : function(){
36279 initTabs : function()
36281 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
36283 var ts = new Roo.bootstrap.panel.Tabs({
36284 el: this.bodyEl.dom,
36285 tabPosition: this.bottomTabs ? 'bottom' : 'top',
36286 disableTooltips: this.config.disableTabTips,
36287 toolbar : this.config.toolbar
36290 if(this.config.hideTabs){
36291 ts.stripWrap.setDisplayed(false);
36294 ts.resizeTabs = this.config.resizeTabs === true;
36295 ts.minTabWidth = this.config.minTabWidth || 40;
36296 ts.maxTabWidth = this.config.maxTabWidth || 250;
36297 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
36298 ts.monitorResize = false;
36299 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
36300 ts.bodyEl.addClass('roo-layout-tabs-body');
36301 this.panels.each(this.initPanelAsTab, this);
36304 initPanelAsTab : function(panel){
36305 var ti = this.tabs.addTab(
36309 this.config.closeOnTab && panel.isClosable(),
36312 if(panel.tabTip !== undefined){
36313 ti.setTooltip(panel.tabTip);
36315 ti.on("activate", function(){
36316 this.setActivePanel(panel);
36319 if(this.config.closeOnTab){
36320 ti.on("beforeclose", function(t, e){
36322 this.remove(panel);
36326 panel.tabItem = ti;
36331 updatePanelTitle : function(panel, title)
36333 if(this.activePanel == panel){
36334 this.updateTitle(title);
36337 var ti = this.tabs.getTab(panel.getEl().id);
36339 if(panel.tabTip !== undefined){
36340 ti.setTooltip(panel.tabTip);
36345 updateTitle : function(title){
36346 if(this.titleTextEl && !this.config.title){
36347 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
36351 setActivePanel : function(panel)
36353 panel = this.getPanel(panel);
36354 if(this.activePanel && this.activePanel != panel){
36355 if(this.activePanel.setActiveState(false) === false){
36359 this.activePanel = panel;
36360 panel.setActiveState(true);
36361 if(this.panelSize){
36362 panel.setSize(this.panelSize.width, this.panelSize.height);
36365 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
36367 this.updateTitle(panel.getTitle());
36369 this.fireEvent("invalidated", this);
36371 this.fireEvent("panelactivated", this, panel);
36375 * Shows the specified panel.
36376 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
36377 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
36379 showPanel : function(panel)
36381 panel = this.getPanel(panel);
36384 var tab = this.tabs.getTab(panel.getEl().id);
36385 if(tab.isHidden()){
36386 this.tabs.unhideTab(tab.id);
36390 this.setActivePanel(panel);
36397 * Get the active panel for this region.
36398 * @return {Roo.ContentPanel} The active panel or null
36400 getActivePanel : function(){
36401 return this.activePanel;
36404 validateVisibility : function(){
36405 if(this.panels.getCount() < 1){
36406 this.updateTitle(" ");
36407 this.closeBtn.hide();
36410 if(!this.isVisible()){
36417 * Adds the passed ContentPanel(s) to this region.
36418 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
36419 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
36421 add : function(panel)
36423 if(arguments.length > 1){
36424 for(var i = 0, len = arguments.length; i < len; i++) {
36425 this.add(arguments[i]);
36430 // if we have not been rendered yet, then we can not really do much of this..
36431 if (!this.bodyEl) {
36432 this.unrendered_panels.push(panel);
36439 if(this.hasPanel(panel)){
36440 this.showPanel(panel);
36443 panel.setRegion(this);
36444 this.panels.add(panel);
36445 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
36446 // sinle panel - no tab...?? would it not be better to render it with the tabs,
36447 // and hide them... ???
36448 this.bodyEl.dom.appendChild(panel.getEl().dom);
36449 if(panel.background !== true){
36450 this.setActivePanel(panel);
36452 this.fireEvent("paneladded", this, panel);
36459 this.initPanelAsTab(panel);
36463 if(panel.background !== true){
36464 this.tabs.activate(panel.getEl().id);
36466 this.fireEvent("paneladded", this, panel);
36471 * Hides the tab for the specified panel.
36472 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36474 hidePanel : function(panel){
36475 if(this.tabs && (panel = this.getPanel(panel))){
36476 this.tabs.hideTab(panel.getEl().id);
36481 * Unhides the tab for a previously hidden panel.
36482 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36484 unhidePanel : function(panel){
36485 if(this.tabs && (panel = this.getPanel(panel))){
36486 this.tabs.unhideTab(panel.getEl().id);
36490 clearPanels : function(){
36491 while(this.panels.getCount() > 0){
36492 this.remove(this.panels.first());
36497 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
36498 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36499 * @param {Boolean} preservePanel Overrides the config preservePanel option
36500 * @return {Roo.ContentPanel} The panel that was removed
36502 remove : function(panel, preservePanel)
36504 panel = this.getPanel(panel);
36509 this.fireEvent("beforeremove", this, panel, e);
36510 if(e.cancel === true){
36513 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
36514 var panelId = panel.getId();
36515 this.panels.removeKey(panelId);
36517 document.body.appendChild(panel.getEl().dom);
36520 this.tabs.removeTab(panel.getEl().id);
36521 }else if (!preservePanel){
36522 this.bodyEl.dom.removeChild(panel.getEl().dom);
36524 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
36525 var p = this.panels.first();
36526 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
36527 tempEl.appendChild(p.getEl().dom);
36528 this.bodyEl.update("");
36529 this.bodyEl.dom.appendChild(p.getEl().dom);
36531 this.updateTitle(p.getTitle());
36533 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
36534 this.setActivePanel(p);
36536 panel.setRegion(null);
36537 if(this.activePanel == panel){
36538 this.activePanel = null;
36540 if(this.config.autoDestroy !== false && preservePanel !== true){
36541 try{panel.destroy();}catch(e){}
36543 this.fireEvent("panelremoved", this, panel);
36548 * Returns the TabPanel component used by this region
36549 * @return {Roo.TabPanel}
36551 getTabs : function(){
36555 createTool : function(parentEl, className){
36556 var btn = Roo.DomHelper.append(parentEl, {
36558 cls: "x-layout-tools-button",
36561 cls: "roo-layout-tools-button-inner " + className,
36565 btn.addClassOnOver("roo-layout-tools-button-over");
36570 * Ext JS Library 1.1.1
36571 * Copyright(c) 2006-2007, Ext JS, LLC.
36573 * Originally Released Under LGPL - original licence link has changed is not relivant.
36576 * <script type="text/javascript">
36582 * @class Roo.SplitLayoutRegion
36583 * @extends Roo.LayoutRegion
36584 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
36586 Roo.bootstrap.layout.Split = function(config){
36587 this.cursor = config.cursor;
36588 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
36591 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
36593 splitTip : "Drag to resize.",
36594 collapsibleSplitTip : "Drag to resize. Double click to hide.",
36595 useSplitTips : false,
36597 applyConfig : function(config){
36598 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
36601 onRender : function(ctr,pos) {
36603 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
36604 if(!this.config.split){
36609 var splitEl = Roo.DomHelper.append(ctr.dom, {
36611 id: this.el.id + "-split",
36612 cls: "roo-layout-split roo-layout-split-"+this.position,
36615 /** The SplitBar for this region
36616 * @type Roo.SplitBar */
36617 // does not exist yet...
36618 Roo.log([this.position, this.orientation]);
36620 this.split = new Roo.bootstrap.SplitBar({
36621 dragElement : splitEl,
36622 resizingElement: this.el,
36623 orientation : this.orientation
36626 this.split.on("moved", this.onSplitMove, this);
36627 this.split.useShim = this.config.useShim === true;
36628 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
36629 if(this.useSplitTips){
36630 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
36632 //if(config.collapsible){
36633 // this.split.el.on("dblclick", this.collapse, this);
36636 if(typeof this.config.minSize != "undefined"){
36637 this.split.minSize = this.config.minSize;
36639 if(typeof this.config.maxSize != "undefined"){
36640 this.split.maxSize = this.config.maxSize;
36642 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
36643 this.hideSplitter();
36648 getHMaxSize : function(){
36649 var cmax = this.config.maxSize || 10000;
36650 var center = this.mgr.getRegion("center");
36651 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
36654 getVMaxSize : function(){
36655 var cmax = this.config.maxSize || 10000;
36656 var center = this.mgr.getRegion("center");
36657 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
36660 onSplitMove : function(split, newSize){
36661 this.fireEvent("resized", this, newSize);
36665 * Returns the {@link Roo.SplitBar} for this region.
36666 * @return {Roo.SplitBar}
36668 getSplitBar : function(){
36673 this.hideSplitter();
36674 Roo.bootstrap.layout.Split.superclass.hide.call(this);
36677 hideSplitter : function(){
36679 this.split.el.setLocation(-2000,-2000);
36680 this.split.el.hide();
36686 this.split.el.show();
36688 Roo.bootstrap.layout.Split.superclass.show.call(this);
36691 beforeSlide: function(){
36692 if(Roo.isGecko){// firefox overflow auto bug workaround
36693 this.bodyEl.clip();
36695 this.tabs.bodyEl.clip();
36697 if(this.activePanel){
36698 this.activePanel.getEl().clip();
36700 if(this.activePanel.beforeSlide){
36701 this.activePanel.beforeSlide();
36707 afterSlide : function(){
36708 if(Roo.isGecko){// firefox overflow auto bug workaround
36709 this.bodyEl.unclip();
36711 this.tabs.bodyEl.unclip();
36713 if(this.activePanel){
36714 this.activePanel.getEl().unclip();
36715 if(this.activePanel.afterSlide){
36716 this.activePanel.afterSlide();
36722 initAutoHide : function(){
36723 if(this.autoHide !== false){
36724 if(!this.autoHideHd){
36725 var st = new Roo.util.DelayedTask(this.slideIn, this);
36726 this.autoHideHd = {
36727 "mouseout": function(e){
36728 if(!e.within(this.el, true)){
36732 "mouseover" : function(e){
36738 this.el.on(this.autoHideHd);
36742 clearAutoHide : function(){
36743 if(this.autoHide !== false){
36744 this.el.un("mouseout", this.autoHideHd.mouseout);
36745 this.el.un("mouseover", this.autoHideHd.mouseover);
36749 clearMonitor : function(){
36750 Roo.get(document).un("click", this.slideInIf, this);
36753 // these names are backwards but not changed for compat
36754 slideOut : function(){
36755 if(this.isSlid || this.el.hasActiveFx()){
36758 this.isSlid = true;
36759 if(this.collapseBtn){
36760 this.collapseBtn.hide();
36762 this.closeBtnState = this.closeBtn.getStyle('display');
36763 this.closeBtn.hide();
36765 this.stickBtn.show();
36768 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
36769 this.beforeSlide();
36770 this.el.setStyle("z-index", 10001);
36771 this.el.slideIn(this.getSlideAnchor(), {
36772 callback: function(){
36774 this.initAutoHide();
36775 Roo.get(document).on("click", this.slideInIf, this);
36776 this.fireEvent("slideshow", this);
36783 afterSlideIn : function(){
36784 this.clearAutoHide();
36785 this.isSlid = false;
36786 this.clearMonitor();
36787 this.el.setStyle("z-index", "");
36788 if(this.collapseBtn){
36789 this.collapseBtn.show();
36791 this.closeBtn.setStyle('display', this.closeBtnState);
36793 this.stickBtn.hide();
36795 this.fireEvent("slidehide", this);
36798 slideIn : function(cb){
36799 if(!this.isSlid || this.el.hasActiveFx()){
36803 this.isSlid = false;
36804 this.beforeSlide();
36805 this.el.slideOut(this.getSlideAnchor(), {
36806 callback: function(){
36807 this.el.setLeftTop(-10000, -10000);
36809 this.afterSlideIn();
36817 slideInIf : function(e){
36818 if(!e.within(this.el)){
36823 animateCollapse : function(){
36824 this.beforeSlide();
36825 this.el.setStyle("z-index", 20000);
36826 var anchor = this.getSlideAnchor();
36827 this.el.slideOut(anchor, {
36828 callback : function(){
36829 this.el.setStyle("z-index", "");
36830 this.collapsedEl.slideIn(anchor, {duration:.3});
36832 this.el.setLocation(-10000,-10000);
36834 this.fireEvent("collapsed", this);
36841 animateExpand : function(){
36842 this.beforeSlide();
36843 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
36844 this.el.setStyle("z-index", 20000);
36845 this.collapsedEl.hide({
36848 this.el.slideIn(this.getSlideAnchor(), {
36849 callback : function(){
36850 this.el.setStyle("z-index", "");
36853 this.split.el.show();
36855 this.fireEvent("invalidated", this);
36856 this.fireEvent("expanded", this);
36884 getAnchor : function(){
36885 return this.anchors[this.position];
36888 getCollapseAnchor : function(){
36889 return this.canchors[this.position];
36892 getSlideAnchor : function(){
36893 return this.sanchors[this.position];
36896 getAlignAdj : function(){
36897 var cm = this.cmargins;
36898 switch(this.position){
36914 getExpandAdj : function(){
36915 var c = this.collapsedEl, cm = this.cmargins;
36916 switch(this.position){
36918 return [-(cm.right+c.getWidth()+cm.left), 0];
36921 return [cm.right+c.getWidth()+cm.left, 0];
36924 return [0, -(cm.top+cm.bottom+c.getHeight())];
36927 return [0, cm.top+cm.bottom+c.getHeight()];
36933 * Ext JS Library 1.1.1
36934 * Copyright(c) 2006-2007, Ext JS, LLC.
36936 * Originally Released Under LGPL - original licence link has changed is not relivant.
36939 * <script type="text/javascript">
36942 * These classes are private internal classes
36944 Roo.bootstrap.layout.Center = function(config){
36945 config.region = "center";
36946 Roo.bootstrap.layout.Region.call(this, config);
36947 this.visible = true;
36948 this.minWidth = config.minWidth || 20;
36949 this.minHeight = config.minHeight || 20;
36952 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
36954 // center panel can't be hidden
36958 // center panel can't be hidden
36961 getMinWidth: function(){
36962 return this.minWidth;
36965 getMinHeight: function(){
36966 return this.minHeight;
36979 Roo.bootstrap.layout.North = function(config)
36981 config.region = 'north';
36982 config.cursor = 'n-resize';
36984 Roo.bootstrap.layout.Split.call(this, config);
36988 this.split.placement = Roo.bootstrap.SplitBar.TOP;
36989 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36990 this.split.el.addClass("roo-layout-split-v");
36992 var size = config.initialSize || config.height;
36993 if(typeof size != "undefined"){
36994 this.el.setHeight(size);
36997 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
36999 orientation: Roo.bootstrap.SplitBar.VERTICAL,
37003 getBox : function(){
37004 if(this.collapsed){
37005 return this.collapsedEl.getBox();
37007 var box = this.el.getBox();
37009 box.height += this.split.el.getHeight();
37014 updateBox : function(box){
37015 if(this.split && !this.collapsed){
37016 box.height -= this.split.el.getHeight();
37017 this.split.el.setLeft(box.x);
37018 this.split.el.setTop(box.y+box.height);
37019 this.split.el.setWidth(box.width);
37021 if(this.collapsed){
37022 this.updateBody(box.width, null);
37024 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37032 Roo.bootstrap.layout.South = function(config){
37033 config.region = 'south';
37034 config.cursor = 's-resize';
37035 Roo.bootstrap.layout.Split.call(this, config);
37037 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
37038 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
37039 this.split.el.addClass("roo-layout-split-v");
37041 var size = config.initialSize || config.height;
37042 if(typeof size != "undefined"){
37043 this.el.setHeight(size);
37047 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
37048 orientation: Roo.bootstrap.SplitBar.VERTICAL,
37049 getBox : function(){
37050 if(this.collapsed){
37051 return this.collapsedEl.getBox();
37053 var box = this.el.getBox();
37055 var sh = this.split.el.getHeight();
37062 updateBox : function(box){
37063 if(this.split && !this.collapsed){
37064 var sh = this.split.el.getHeight();
37067 this.split.el.setLeft(box.x);
37068 this.split.el.setTop(box.y-sh);
37069 this.split.el.setWidth(box.width);
37071 if(this.collapsed){
37072 this.updateBody(box.width, null);
37074 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37078 Roo.bootstrap.layout.East = function(config){
37079 config.region = "east";
37080 config.cursor = "e-resize";
37081 Roo.bootstrap.layout.Split.call(this, config);
37083 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
37084 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
37085 this.split.el.addClass("roo-layout-split-h");
37087 var size = config.initialSize || config.width;
37088 if(typeof size != "undefined"){
37089 this.el.setWidth(size);
37092 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
37093 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
37094 getBox : function(){
37095 if(this.collapsed){
37096 return this.collapsedEl.getBox();
37098 var box = this.el.getBox();
37100 var sw = this.split.el.getWidth();
37107 updateBox : function(box){
37108 if(this.split && !this.collapsed){
37109 var sw = this.split.el.getWidth();
37111 this.split.el.setLeft(box.x);
37112 this.split.el.setTop(box.y);
37113 this.split.el.setHeight(box.height);
37116 if(this.collapsed){
37117 this.updateBody(null, box.height);
37119 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37123 Roo.bootstrap.layout.West = function(config){
37124 config.region = "west";
37125 config.cursor = "w-resize";
37127 Roo.bootstrap.layout.Split.call(this, config);
37129 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
37130 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
37131 this.split.el.addClass("roo-layout-split-h");
37135 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
37136 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
37138 onRender: function(ctr, pos)
37140 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
37141 var size = this.config.initialSize || this.config.width;
37142 if(typeof size != "undefined"){
37143 this.el.setWidth(size);
37147 getBox : function(){
37148 if(this.collapsed){
37149 return this.collapsedEl.getBox();
37151 var box = this.el.getBox();
37153 box.width += this.split.el.getWidth();
37158 updateBox : function(box){
37159 if(this.split && !this.collapsed){
37160 var sw = this.split.el.getWidth();
37162 this.split.el.setLeft(box.x+box.width);
37163 this.split.el.setTop(box.y);
37164 this.split.el.setHeight(box.height);
37166 if(this.collapsed){
37167 this.updateBody(null, box.height);
37169 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37172 Roo.namespace("Roo.bootstrap.panel");/*
37174 * Ext JS Library 1.1.1
37175 * Copyright(c) 2006-2007, Ext JS, LLC.
37177 * Originally Released Under LGPL - original licence link has changed is not relivant.
37180 * <script type="text/javascript">
37183 * @class Roo.ContentPanel
37184 * @extends Roo.util.Observable
37185 * A basic ContentPanel element.
37186 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
37187 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
37188 * @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
37189 * @cfg {Boolean} closable True if the panel can be closed/removed
37190 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
37191 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
37192 * @cfg {Toolbar} toolbar A toolbar for this panel
37193 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
37194 * @cfg {String} title The title for this panel
37195 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
37196 * @cfg {String} url Calls {@link #setUrl} with this value
37197 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
37198 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
37199 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
37200 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
37201 * @cfg {Boolean} badges render the badges
37204 * Create a new ContentPanel.
37205 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
37206 * @param {String/Object} config A string to set only the title or a config object
37207 * @param {String} content (optional) Set the HTML content for this panel
37208 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
37210 Roo.bootstrap.panel.Content = function( config){
37212 this.tpl = config.tpl || false;
37214 var el = config.el;
37215 var content = config.content;
37217 if(config.autoCreate){ // xtype is available if this is called from factory
37220 this.el = Roo.get(el);
37221 if(!this.el && config && config.autoCreate){
37222 if(typeof config.autoCreate == "object"){
37223 if(!config.autoCreate.id){
37224 config.autoCreate.id = config.id||el;
37226 this.el = Roo.DomHelper.append(document.body,
37227 config.autoCreate, true);
37229 var elcfg = { tag: "div",
37230 cls: "roo-layout-inactive-content",
37234 elcfg.html = config.html;
37238 this.el = Roo.DomHelper.append(document.body, elcfg , true);
37241 this.closable = false;
37242 this.loaded = false;
37243 this.active = false;
37246 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
37248 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
37250 this.wrapEl = this.el; //this.el.wrap();
37252 if (config.toolbar.items) {
37253 ti = config.toolbar.items ;
37254 delete config.toolbar.items ;
37258 this.toolbar.render(this.wrapEl, 'before');
37259 for(var i =0;i < ti.length;i++) {
37260 // Roo.log(['add child', items[i]]);
37261 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37263 this.toolbar.items = nitems;
37264 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
37265 delete config.toolbar;
37269 // xtype created footer. - not sure if will work as we normally have to render first..
37270 if (this.footer && !this.footer.el && this.footer.xtype) {
37271 if (!this.wrapEl) {
37272 this.wrapEl = this.el.wrap();
37275 this.footer.container = this.wrapEl.createChild();
37277 this.footer = Roo.factory(this.footer, Roo);
37282 if(typeof config == "string"){
37283 this.title = config;
37285 Roo.apply(this, config);
37289 this.resizeEl = Roo.get(this.resizeEl, true);
37291 this.resizeEl = this.el;
37293 // handle view.xtype
37301 * Fires when this panel is activated.
37302 * @param {Roo.ContentPanel} this
37306 * @event deactivate
37307 * Fires when this panel is activated.
37308 * @param {Roo.ContentPanel} this
37310 "deactivate" : true,
37314 * Fires when this panel is resized if fitToFrame is true.
37315 * @param {Roo.ContentPanel} this
37316 * @param {Number} width The width after any component adjustments
37317 * @param {Number} height The height after any component adjustments
37323 * Fires when this tab is created
37324 * @param {Roo.ContentPanel} this
37335 if(this.autoScroll){
37336 this.resizeEl.setStyle("overflow", "auto");
37338 // fix randome scrolling
37339 //this.el.on('scroll', function() {
37340 // Roo.log('fix random scolling');
37341 // this.scrollTo('top',0);
37344 content = content || this.content;
37346 this.setContent(content);
37348 if(config && config.url){
37349 this.setUrl(this.url, this.params, this.loadOnce);
37354 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
37356 if (this.view && typeof(this.view.xtype) != 'undefined') {
37357 this.view.el = this.el.appendChild(document.createElement("div"));
37358 this.view = Roo.factory(this.view);
37359 this.view.render && this.view.render(false, '');
37363 this.fireEvent('render', this);
37366 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
37370 setRegion : function(region){
37371 this.region = region;
37372 this.setActiveClass(region && !this.background);
37376 setActiveClass: function(state)
37379 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
37380 this.el.setStyle('position','relative');
37382 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
37383 this.el.setStyle('position', 'absolute');
37388 * Returns the toolbar for this Panel if one was configured.
37389 * @return {Roo.Toolbar}
37391 getToolbar : function(){
37392 return this.toolbar;
37395 setActiveState : function(active)
37397 this.active = active;
37398 this.setActiveClass(active);
37400 if(this.fireEvent("deactivate", this) === false){
37405 this.fireEvent("activate", this);
37409 * Updates this panel's element
37410 * @param {String} content The new content
37411 * @param {Boolean} loadScripts (optional) true to look for and process scripts
37413 setContent : function(content, loadScripts){
37414 this.el.update(content, loadScripts);
37417 ignoreResize : function(w, h){
37418 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
37421 this.lastSize = {width: w, height: h};
37426 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
37427 * @return {Roo.UpdateManager} The UpdateManager
37429 getUpdateManager : function(){
37430 return this.el.getUpdateManager();
37433 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
37434 * @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:
37437 url: "your-url.php",
37438 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
37439 callback: yourFunction,
37440 scope: yourObject, //(optional scope)
37443 text: "Loading...",
37448 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
37449 * 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.
37450 * @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}
37451 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
37452 * @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.
37453 * @return {Roo.ContentPanel} this
37456 var um = this.el.getUpdateManager();
37457 um.update.apply(um, arguments);
37463 * 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.
37464 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
37465 * @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)
37466 * @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)
37467 * @return {Roo.UpdateManager} The UpdateManager
37469 setUrl : function(url, params, loadOnce){
37470 if(this.refreshDelegate){
37471 this.removeListener("activate", this.refreshDelegate);
37473 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
37474 this.on("activate", this.refreshDelegate);
37475 return this.el.getUpdateManager();
37478 _handleRefresh : function(url, params, loadOnce){
37479 if(!loadOnce || !this.loaded){
37480 var updater = this.el.getUpdateManager();
37481 updater.update(url, params, this._setLoaded.createDelegate(this));
37485 _setLoaded : function(){
37486 this.loaded = true;
37490 * Returns this panel's id
37493 getId : function(){
37498 * Returns this panel's element - used by regiosn to add.
37499 * @return {Roo.Element}
37501 getEl : function(){
37502 return this.wrapEl || this.el;
37507 adjustForComponents : function(width, height)
37509 //Roo.log('adjustForComponents ');
37510 if(this.resizeEl != this.el){
37511 width -= this.el.getFrameWidth('lr');
37512 height -= this.el.getFrameWidth('tb');
37515 var te = this.toolbar.getEl();
37516 te.setWidth(width);
37517 height -= te.getHeight();
37520 var te = this.footer.getEl();
37521 te.setWidth(width);
37522 height -= te.getHeight();
37526 if(this.adjustments){
37527 width += this.adjustments[0];
37528 height += this.adjustments[1];
37530 return {"width": width, "height": height};
37533 setSize : function(width, height){
37534 if(this.fitToFrame && !this.ignoreResize(width, height)){
37535 if(this.fitContainer && this.resizeEl != this.el){
37536 this.el.setSize(width, height);
37538 var size = this.adjustForComponents(width, height);
37539 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
37540 this.fireEvent('resize', this, size.width, size.height);
37545 * Returns this panel's title
37548 getTitle : function(){
37550 if (typeof(this.title) != 'object') {
37555 for (var k in this.title) {
37556 if (!this.title.hasOwnProperty(k)) {
37560 if (k.indexOf('-') >= 0) {
37561 var s = k.split('-');
37562 for (var i = 0; i<s.length; i++) {
37563 t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
37566 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
37573 * Set this panel's title
37574 * @param {String} title
37576 setTitle : function(title){
37577 this.title = title;
37579 this.region.updatePanelTitle(this, title);
37584 * Returns true is this panel was configured to be closable
37585 * @return {Boolean}
37587 isClosable : function(){
37588 return this.closable;
37591 beforeSlide : function(){
37593 this.resizeEl.clip();
37596 afterSlide : function(){
37598 this.resizeEl.unclip();
37602 * Force a content refresh from the URL specified in the {@link #setUrl} method.
37603 * Will fail silently if the {@link #setUrl} method has not been called.
37604 * This does not activate the panel, just updates its content.
37606 refresh : function(){
37607 if(this.refreshDelegate){
37608 this.loaded = false;
37609 this.refreshDelegate();
37614 * Destroys this panel
37616 destroy : function(){
37617 this.el.removeAllListeners();
37618 var tempEl = document.createElement("span");
37619 tempEl.appendChild(this.el.dom);
37620 tempEl.innerHTML = "";
37626 * form - if the content panel contains a form - this is a reference to it.
37627 * @type {Roo.form.Form}
37631 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
37632 * This contains a reference to it.
37638 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
37648 * @param {Object} cfg Xtype definition of item to add.
37652 getChildContainer: function () {
37653 return this.getEl();
37658 var ret = new Roo.factory(cfg);
37663 if (cfg.xtype.match(/^Form$/)) {
37666 //if (this.footer) {
37667 // el = this.footer.container.insertSibling(false, 'before');
37669 el = this.el.createChild();
37672 this.form = new Roo.form.Form(cfg);
37675 if ( this.form.allItems.length) {
37676 this.form.render(el.dom);
37680 // should only have one of theses..
37681 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
37682 // views.. should not be just added - used named prop 'view''
37684 cfg.el = this.el.appendChild(document.createElement("div"));
37687 var ret = new Roo.factory(cfg);
37689 ret.render && ret.render(false, ''); // render blank..
37699 * @class Roo.bootstrap.panel.Grid
37700 * @extends Roo.bootstrap.panel.Content
37702 * Create a new GridPanel.
37703 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
37704 * @param {Object} config A the config object
37710 Roo.bootstrap.panel.Grid = function(config)
37714 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
37715 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
37717 config.el = this.wrapper;
37718 //this.el = this.wrapper;
37720 if (config.container) {
37721 // ctor'ed from a Border/panel.grid
37724 this.wrapper.setStyle("overflow", "hidden");
37725 this.wrapper.addClass('roo-grid-container');
37730 if(config.toolbar){
37731 var tool_el = this.wrapper.createChild();
37732 this.toolbar = Roo.factory(config.toolbar);
37734 if (config.toolbar.items) {
37735 ti = config.toolbar.items ;
37736 delete config.toolbar.items ;
37740 this.toolbar.render(tool_el);
37741 for(var i =0;i < ti.length;i++) {
37742 // Roo.log(['add child', items[i]]);
37743 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37745 this.toolbar.items = nitems;
37747 delete config.toolbar;
37750 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
37751 config.grid.scrollBody = true;;
37752 config.grid.monitorWindowResize = false; // turn off autosizing
37753 config.grid.autoHeight = false;
37754 config.grid.autoWidth = false;
37756 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
37758 if (config.background) {
37759 // render grid on panel activation (if panel background)
37760 this.on('activate', function(gp) {
37761 if (!gp.grid.rendered) {
37762 gp.grid.render(this.wrapper);
37763 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37768 this.grid.render(this.wrapper);
37769 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37772 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
37773 // ??? needed ??? config.el = this.wrapper;
37778 // xtype created footer. - not sure if will work as we normally have to render first..
37779 if (this.footer && !this.footer.el && this.footer.xtype) {
37781 var ctr = this.grid.getView().getFooterPanel(true);
37782 this.footer.dataSource = this.grid.dataSource;
37783 this.footer = Roo.factory(this.footer, Roo);
37784 this.footer.render(ctr);
37794 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
37795 getId : function(){
37796 return this.grid.id;
37800 * Returns the grid for this panel
37801 * @return {Roo.bootstrap.Table}
37803 getGrid : function(){
37807 setSize : function(width, height){
37808 if(!this.ignoreResize(width, height)){
37809 var grid = this.grid;
37810 var size = this.adjustForComponents(width, height);
37811 var gridel = grid.getGridEl();
37812 gridel.setSize(size.width, size.height);
37814 var thd = grid.getGridEl().select('thead',true).first();
37815 var tbd = grid.getGridEl().select('tbody', true).first();
37817 tbd.setSize(width, height - thd.getHeight());
37826 beforeSlide : function(){
37827 this.grid.getView().scroller.clip();
37830 afterSlide : function(){
37831 this.grid.getView().scroller.unclip();
37834 destroy : function(){
37835 this.grid.destroy();
37837 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
37842 * @class Roo.bootstrap.panel.Nest
37843 * @extends Roo.bootstrap.panel.Content
37845 * Create a new Panel, that can contain a layout.Border.
37848 * @param {Roo.BorderLayout} layout The layout for this panel
37849 * @param {String/Object} config A string to set only the title or a config object
37851 Roo.bootstrap.panel.Nest = function(config)
37853 // construct with only one argument..
37854 /* FIXME - implement nicer consturctors
37855 if (layout.layout) {
37857 layout = config.layout;
37858 delete config.layout;
37860 if (layout.xtype && !layout.getEl) {
37861 // then layout needs constructing..
37862 layout = Roo.factory(layout, Roo);
37866 config.el = config.layout.getEl();
37868 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
37870 config.layout.monitorWindowResize = false; // turn off autosizing
37871 this.layout = config.layout;
37872 this.layout.getEl().addClass("roo-layout-nested-layout");
37879 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
37881 setSize : function(width, height){
37882 if(!this.ignoreResize(width, height)){
37883 var size = this.adjustForComponents(width, height);
37884 var el = this.layout.getEl();
37885 if (size.height < 1) {
37886 el.setWidth(size.width);
37888 el.setSize(size.width, size.height);
37890 var touch = el.dom.offsetWidth;
37891 this.layout.layout();
37892 // ie requires a double layout on the first pass
37893 if(Roo.isIE && !this.initialized){
37894 this.initialized = true;
37895 this.layout.layout();
37900 // activate all subpanels if not currently active..
37902 setActiveState : function(active){
37903 this.active = active;
37904 this.setActiveClass(active);
37907 this.fireEvent("deactivate", this);
37911 this.fireEvent("activate", this);
37912 // not sure if this should happen before or after..
37913 if (!this.layout) {
37914 return; // should not happen..
37917 for (var r in this.layout.regions) {
37918 reg = this.layout.getRegion(r);
37919 if (reg.getActivePanel()) {
37920 //reg.showPanel(reg.getActivePanel()); // force it to activate..
37921 reg.setActivePanel(reg.getActivePanel());
37924 if (!reg.panels.length) {
37927 reg.showPanel(reg.getPanel(0));
37936 * Returns the nested BorderLayout for this panel
37937 * @return {Roo.BorderLayout}
37939 getLayout : function(){
37940 return this.layout;
37944 * Adds a xtype elements to the layout of the nested panel
37948 xtype : 'ContentPanel',
37955 xtype : 'NestedLayoutPanel',
37961 items : [ ... list of content panels or nested layout panels.. ]
37965 * @param {Object} cfg Xtype definition of item to add.
37967 addxtype : function(cfg) {
37968 return this.layout.addxtype(cfg);
37973 * Ext JS Library 1.1.1
37974 * Copyright(c) 2006-2007, Ext JS, LLC.
37976 * Originally Released Under LGPL - original licence link has changed is not relivant.
37979 * <script type="text/javascript">
37982 * @class Roo.TabPanel
37983 * @extends Roo.util.Observable
37984 * A lightweight tab container.
37988 // basic tabs 1, built from existing content
37989 var tabs = new Roo.TabPanel("tabs1");
37990 tabs.addTab("script", "View Script");
37991 tabs.addTab("markup", "View Markup");
37992 tabs.activate("script");
37994 // more advanced tabs, built from javascript
37995 var jtabs = new Roo.TabPanel("jtabs");
37996 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
37998 // set up the UpdateManager
37999 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
38000 var updater = tab2.getUpdateManager();
38001 updater.setDefaultUrl("ajax1.htm");
38002 tab2.on('activate', updater.refresh, updater, true);
38004 // Use setUrl for Ajax loading
38005 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
38006 tab3.setUrl("ajax2.htm", null, true);
38009 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
38012 jtabs.activate("jtabs-1");
38015 * Create a new TabPanel.
38016 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
38017 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
38019 Roo.bootstrap.panel.Tabs = function(config){
38021 * The container element for this TabPanel.
38022 * @type Roo.Element
38024 this.el = Roo.get(config.el);
38027 if(typeof config == "boolean"){
38028 this.tabPosition = config ? "bottom" : "top";
38030 Roo.apply(this, config);
38034 if(this.tabPosition == "bottom"){
38035 this.bodyEl = Roo.get(this.createBody(this.el.dom));
38036 this.el.addClass("roo-tabs-bottom");
38038 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
38039 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
38040 this.stripEl.setVisibilityMode(Roo.Element.DISPLAY);
38041 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
38043 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
38045 if(this.tabPosition != "bottom"){
38046 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
38047 * @type Roo.Element
38049 this.bodyEl = Roo.get(this.createBody(this.el.dom));
38050 this.el.addClass("roo-tabs-top");
38054 this.bodyEl.setStyle("position", "relative");
38056 this.active = null;
38057 this.activateDelegate = this.activate.createDelegate(this);
38062 * Fires when the active tab changes
38063 * @param {Roo.TabPanel} this
38064 * @param {Roo.TabPanelItem} activePanel The new active tab
38068 * @event beforetabchange
38069 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
38070 * @param {Roo.TabPanel} this
38071 * @param {Object} e Set cancel to true on this object to cancel the tab change
38072 * @param {Roo.TabPanelItem} tab The tab being changed to
38074 "beforetabchange" : true
38077 Roo.EventManager.onWindowResize(this.onResize, this);
38078 this.cpad = this.el.getPadding("lr");
38079 this.hiddenCount = 0;
38082 // toolbar on the tabbar support...
38083 if (this.toolbar) {
38084 alert("no toolbar support yet");
38085 this.toolbar = false;
38087 var tcfg = this.toolbar;
38088 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
38089 this.toolbar = new Roo.Toolbar(tcfg);
38090 if (Roo.isSafari) {
38091 var tbl = tcfg.container.child('table', true);
38092 tbl.setAttribute('width', '100%');
38100 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
38103 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
38105 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
38107 tabPosition : "top",
38109 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
38111 currentTabWidth : 0,
38113 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
38117 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
38121 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
38123 preferredTabWidth : 175,
38125 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
38127 resizeTabs : false,
38129 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
38131 monitorResize : true,
38133 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
38138 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
38139 * @param {String} id The id of the div to use <b>or create</b>
38140 * @param {String} text The text for the tab
38141 * @param {String} content (optional) Content to put in the TabPanelItem body
38142 * @param {Boolean} closable (optional) True to create a close icon on the tab
38143 * @return {Roo.TabPanelItem} The created TabPanelItem
38145 addTab : function(id, text, content, closable, tpl)
38147 var item = new Roo.bootstrap.panel.TabItem({
38151 closable : closable,
38154 this.addTabItem(item);
38156 item.setContent(content);
38162 * Returns the {@link Roo.TabPanelItem} with the specified id/index
38163 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
38164 * @return {Roo.TabPanelItem}
38166 getTab : function(id){
38167 return this.items[id];
38171 * Hides the {@link Roo.TabPanelItem} with the specified id/index
38172 * @param {String/Number} id The id or index of the TabPanelItem to hide.
38174 hideTab : function(id){
38175 var t = this.items[id];
38178 this.hiddenCount++;
38179 this.autoSizeTabs();
38184 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
38185 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
38187 unhideTab : function(id){
38188 var t = this.items[id];
38190 t.setHidden(false);
38191 this.hiddenCount--;
38192 this.autoSizeTabs();
38197 * Adds an existing {@link Roo.TabPanelItem}.
38198 * @param {Roo.TabPanelItem} item The TabPanelItem to add
38200 addTabItem : function(item)
38202 this.items[item.id] = item;
38203 this.items.push(item);
38204 this.autoSizeTabs();
38205 // if(this.resizeTabs){
38206 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
38207 // this.autoSizeTabs();
38209 // item.autoSize();
38214 * Removes a {@link Roo.TabPanelItem}.
38215 * @param {String/Number} id The id or index of the TabPanelItem to remove.
38217 removeTab : function(id){
38218 var items = this.items;
38219 var tab = items[id];
38220 if(!tab) { return; }
38221 var index = items.indexOf(tab);
38222 if(this.active == tab && items.length > 1){
38223 var newTab = this.getNextAvailable(index);
38228 this.stripEl.dom.removeChild(tab.pnode.dom);
38229 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
38230 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
38232 items.splice(index, 1);
38233 delete this.items[tab.id];
38234 tab.fireEvent("close", tab);
38235 tab.purgeListeners();
38236 this.autoSizeTabs();
38239 getNextAvailable : function(start){
38240 var items = this.items;
38242 // look for a next tab that will slide over to
38243 // replace the one being removed
38244 while(index < items.length){
38245 var item = items[++index];
38246 if(item && !item.isHidden()){
38250 // if one isn't found select the previous tab (on the left)
38253 var item = items[--index];
38254 if(item && !item.isHidden()){
38262 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
38263 * @param {String/Number} id The id or index of the TabPanelItem to disable.
38265 disableTab : function(id){
38266 var tab = this.items[id];
38267 if(tab && this.active != tab){
38273 * Enables a {@link Roo.TabPanelItem} that is disabled.
38274 * @param {String/Number} id The id or index of the TabPanelItem to enable.
38276 enableTab : function(id){
38277 var tab = this.items[id];
38282 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
38283 * @param {String/Number} id The id or index of the TabPanelItem to activate.
38284 * @return {Roo.TabPanelItem} The TabPanelItem.
38286 activate : function(id)
38288 var tab = this.items[id];
38292 if(tab == this.active || tab.disabled){
38296 this.fireEvent("beforetabchange", this, e, tab);
38297 if(e.cancel !== true && !tab.disabled){
38299 this.active.hide();
38301 this.active = this.items[id];
38302 this.active.show();
38303 this.fireEvent("tabchange", this, this.active);
38309 * Gets the active {@link Roo.TabPanelItem}.
38310 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
38312 getActiveTab : function(){
38313 return this.active;
38317 * Updates the tab body element to fit the height of the container element
38318 * for overflow scrolling
38319 * @param {Number} targetHeight (optional) Override the starting height from the elements height
38321 syncHeight : function(targetHeight){
38322 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
38323 var bm = this.bodyEl.getMargins();
38324 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
38325 this.bodyEl.setHeight(newHeight);
38329 onResize : function(){
38330 if(this.monitorResize){
38331 this.autoSizeTabs();
38336 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
38338 beginUpdate : function(){
38339 this.updating = true;
38343 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
38345 endUpdate : function(){
38346 this.updating = false;
38347 this.autoSizeTabs();
38351 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
38353 autoSizeTabs : function()
38355 var count = this.items.length;
38356 var vcount = count - this.hiddenCount;
38359 this.stripEl.hide();
38361 this.stripEl.show();
38364 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
38369 var w = Math.max(this.el.getWidth() - this.cpad, 10);
38370 var availWidth = Math.floor(w / vcount);
38371 var b = this.stripBody;
38372 if(b.getWidth() > w){
38373 var tabs = this.items;
38374 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
38375 if(availWidth < this.minTabWidth){
38376 /*if(!this.sleft){ // incomplete scrolling code
38377 this.createScrollButtons();
38380 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
38383 if(this.currentTabWidth < this.preferredTabWidth){
38384 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
38390 * Returns the number of tabs in this TabPanel.
38393 getCount : function(){
38394 return this.items.length;
38398 * Resizes all the tabs to the passed width
38399 * @param {Number} The new width
38401 setTabWidth : function(width){
38402 this.currentTabWidth = width;
38403 for(var i = 0, len = this.items.length; i < len; i++) {
38404 if(!this.items[i].isHidden()) {
38405 this.items[i].setWidth(width);
38411 * Destroys this TabPanel
38412 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
38414 destroy : function(removeEl){
38415 Roo.EventManager.removeResizeListener(this.onResize, this);
38416 for(var i = 0, len = this.items.length; i < len; i++){
38417 this.items[i].purgeListeners();
38419 if(removeEl === true){
38420 this.el.update("");
38425 createStrip : function(container)
38427 var strip = document.createElement("nav");
38428 strip.className = Roo.bootstrap.version == 4 ?
38429 "navbar-light bg-light" :
38430 "navbar navbar-default"; //"x-tabs-wrap";
38431 container.appendChild(strip);
38435 createStripList : function(strip)
38437 // div wrapper for retard IE
38438 // returns the "tr" element.
38439 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
38440 //'<div class="x-tabs-strip-wrap">'+
38441 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
38442 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
38443 return strip.firstChild; //.firstChild.firstChild.firstChild;
38445 createBody : function(container)
38447 var body = document.createElement("div");
38448 Roo.id(body, "tab-body");
38449 //Roo.fly(body).addClass("x-tabs-body");
38450 Roo.fly(body).addClass("tab-content");
38451 container.appendChild(body);
38454 createItemBody :function(bodyEl, id){
38455 var body = Roo.getDom(id);
38457 body = document.createElement("div");
38460 //Roo.fly(body).addClass("x-tabs-item-body");
38461 Roo.fly(body).addClass("tab-pane");
38462 bodyEl.insertBefore(body, bodyEl.firstChild);
38466 createStripElements : function(stripEl, text, closable, tpl)
38468 var td = document.createElement("li"); // was td..
38469 td.className = 'nav-item';
38471 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
38474 stripEl.appendChild(td);
38476 td.className = "x-tabs-closable";
38477 if(!this.closeTpl){
38478 this.closeTpl = new Roo.Template(
38479 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38480 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
38481 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
38484 var el = this.closeTpl.overwrite(td, {"text": text});
38485 var close = el.getElementsByTagName("div")[0];
38486 var inner = el.getElementsByTagName("em")[0];
38487 return {"el": el, "close": close, "inner": inner};
38490 // not sure what this is..
38491 // if(!this.tabTpl){
38492 //this.tabTpl = new Roo.Template(
38493 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38494 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
38496 // this.tabTpl = new Roo.Template(
38497 // '<a href="#">' +
38498 // '<span unselectable="on"' +
38499 // (this.disableTooltips ? '' : ' title="{text}"') +
38500 // ' >{text}</span></a>'
38506 var template = tpl || this.tabTpl || false;
38509 template = new Roo.Template(
38510 Roo.bootstrap.version == 4 ?
38512 '<a class="nav-link" href="#" unselectable="on"' +
38513 (this.disableTooltips ? '' : ' title="{text}"') +
38516 '<a class="nav-link" href="#">' +
38517 '<span unselectable="on"' +
38518 (this.disableTooltips ? '' : ' title="{text}"') +
38519 ' >{text}</span></a>'
38524 switch (typeof(template)) {
38528 template = new Roo.Template(template);
38534 var el = template.overwrite(td, {"text": text});
38536 var inner = el.getElementsByTagName("span")[0];
38538 return {"el": el, "inner": inner};
38546 * @class Roo.TabPanelItem
38547 * @extends Roo.util.Observable
38548 * Represents an individual item (tab plus body) in a TabPanel.
38549 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
38550 * @param {String} id The id of this TabPanelItem
38551 * @param {String} text The text for the tab of this TabPanelItem
38552 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
38554 Roo.bootstrap.panel.TabItem = function(config){
38556 * The {@link Roo.TabPanel} this TabPanelItem belongs to
38557 * @type Roo.TabPanel
38559 this.tabPanel = config.panel;
38561 * The id for this TabPanelItem
38564 this.id = config.id;
38566 this.disabled = false;
38568 this.text = config.text;
38570 this.loaded = false;
38571 this.closable = config.closable;
38574 * The body element for this TabPanelItem.
38575 * @type Roo.Element
38577 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
38578 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
38579 this.bodyEl.setStyle("display", "block");
38580 this.bodyEl.setStyle("zoom", "1");
38581 //this.hideAction();
38583 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
38585 this.el = Roo.get(els.el);
38586 this.inner = Roo.get(els.inner, true);
38587 this.textEl = Roo.bootstrap.version == 4 ?
38588 this.el : Roo.get(this.el.dom.firstChild, true);
38590 this.pnode = this.linode = Roo.get(els.el.parentNode, true);
38591 this.status_node = Roo.bootstrap.version == 4 ? this.el : this.linode;
38594 // this.el.on("mousedown", this.onTabMouseDown, this);
38595 this.el.on("click", this.onTabClick, this);
38597 if(config.closable){
38598 var c = Roo.get(els.close, true);
38599 c.dom.title = this.closeText;
38600 c.addClassOnOver("close-over");
38601 c.on("click", this.closeClick, this);
38607 * Fires when this tab becomes the active tab.
38608 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38609 * @param {Roo.TabPanelItem} this
38613 * @event beforeclose
38614 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
38615 * @param {Roo.TabPanelItem} this
38616 * @param {Object} e Set cancel to true on this object to cancel the close.
38618 "beforeclose": true,
38621 * Fires when this tab is closed.
38622 * @param {Roo.TabPanelItem} this
38626 * @event deactivate
38627 * Fires when this tab is no longer the active tab.
38628 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38629 * @param {Roo.TabPanelItem} this
38631 "deactivate" : true
38633 this.hidden = false;
38635 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
38638 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
38640 purgeListeners : function(){
38641 Roo.util.Observable.prototype.purgeListeners.call(this);
38642 this.el.removeAllListeners();
38645 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
38648 this.status_node.addClass("active");
38651 this.tabPanel.stripWrap.repaint();
38653 this.fireEvent("activate", this.tabPanel, this);
38657 * Returns true if this tab is the active tab.
38658 * @return {Boolean}
38660 isActive : function(){
38661 return this.tabPanel.getActiveTab() == this;
38665 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
38668 this.status_node.removeClass("active");
38670 this.fireEvent("deactivate", this.tabPanel, this);
38673 hideAction : function(){
38674 this.bodyEl.hide();
38675 this.bodyEl.setStyle("position", "absolute");
38676 this.bodyEl.setLeft("-20000px");
38677 this.bodyEl.setTop("-20000px");
38680 showAction : function(){
38681 this.bodyEl.setStyle("position", "relative");
38682 this.bodyEl.setTop("");
38683 this.bodyEl.setLeft("");
38684 this.bodyEl.show();
38688 * Set the tooltip for the tab.
38689 * @param {String} tooltip The tab's tooltip
38691 setTooltip : function(text){
38692 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
38693 this.textEl.dom.qtip = text;
38694 this.textEl.dom.removeAttribute('title');
38696 this.textEl.dom.title = text;
38700 onTabClick : function(e){
38701 e.preventDefault();
38702 this.tabPanel.activate(this.id);
38705 onTabMouseDown : function(e){
38706 e.preventDefault();
38707 this.tabPanel.activate(this.id);
38710 getWidth : function(){
38711 return this.inner.getWidth();
38714 setWidth : function(width){
38715 var iwidth = width - this.linode.getPadding("lr");
38716 this.inner.setWidth(iwidth);
38717 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
38718 this.linode.setWidth(width);
38722 * Show or hide the tab
38723 * @param {Boolean} hidden True to hide or false to show.
38725 setHidden : function(hidden){
38726 this.hidden = hidden;
38727 this.linode.setStyle("display", hidden ? "none" : "");
38731 * Returns true if this tab is "hidden"
38732 * @return {Boolean}
38734 isHidden : function(){
38735 return this.hidden;
38739 * Returns the text for this tab
38742 getText : function(){
38746 autoSize : function(){
38747 //this.el.beginMeasure();
38748 this.textEl.setWidth(1);
38750 * #2804 [new] Tabs in Roojs
38751 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
38753 //this.setWidth(this.textEl.dom.scrollWidth+this.linode.getPadding("lr")+this.inner.getPadding("lr") + 2);
38754 //this.el.endMeasure();
38758 * Sets the text for the tab (Note: this also sets the tooltip text)
38759 * @param {String} text The tab's text and tooltip
38761 setText : function(text){
38763 this.textEl.update(text);
38764 this.setTooltip(text);
38765 //if(!this.tabPanel.resizeTabs){
38766 // this.autoSize();
38770 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
38772 activate : function(){
38773 this.tabPanel.activate(this.id);
38777 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
38779 disable : function(){
38780 if(this.tabPanel.active != this){
38781 this.disabled = true;
38782 this.status_node.addClass("disabled");
38787 * Enables this TabPanelItem if it was previously disabled.
38789 enable : function(){
38790 this.disabled = false;
38791 this.status_node.removeClass("disabled");
38795 * Sets the content for this TabPanelItem.
38796 * @param {String} content The content
38797 * @param {Boolean} loadScripts true to look for and load scripts
38799 setContent : function(content, loadScripts){
38800 this.bodyEl.update(content, loadScripts);
38804 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
38805 * @return {Roo.UpdateManager} The UpdateManager
38807 getUpdateManager : function(){
38808 return this.bodyEl.getUpdateManager();
38812 * Set a URL to be used to load the content for this TabPanelItem.
38813 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
38814 * @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)
38815 * @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)
38816 * @return {Roo.UpdateManager} The UpdateManager
38818 setUrl : function(url, params, loadOnce){
38819 if(this.refreshDelegate){
38820 this.un('activate', this.refreshDelegate);
38822 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
38823 this.on("activate", this.refreshDelegate);
38824 return this.bodyEl.getUpdateManager();
38828 _handleRefresh : function(url, params, loadOnce){
38829 if(!loadOnce || !this.loaded){
38830 var updater = this.bodyEl.getUpdateManager();
38831 updater.update(url, params, this._setLoaded.createDelegate(this));
38836 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
38837 * Will fail silently if the setUrl method has not been called.
38838 * This does not activate the panel, just updates its content.
38840 refresh : function(){
38841 if(this.refreshDelegate){
38842 this.loaded = false;
38843 this.refreshDelegate();
38848 _setLoaded : function(){
38849 this.loaded = true;
38853 closeClick : function(e){
38856 this.fireEvent("beforeclose", this, o);
38857 if(o.cancel !== true){
38858 this.tabPanel.removeTab(this.id);
38862 * The text displayed in the tooltip for the close icon.
38865 closeText : "Close this tab"
38868 * This script refer to:
38869 * Title: International Telephone Input
38870 * Author: Jack O'Connor
38871 * Code version: v12.1.12
38872 * Availability: https://github.com/jackocnr/intl-tel-input.git
38875 Roo.bootstrap.PhoneInputData = function() {
38878 "Afghanistan (افغانستان)",
38883 "Albania (Shqipëri)",
38888 "Algeria (الجزائر)",
38913 "Antigua and Barbuda",
38923 "Armenia (Հայաստան)",
38939 "Austria (Österreich)",
38944 "Azerbaijan (Azərbaycan)",
38954 "Bahrain (البحرين)",
38959 "Bangladesh (বাংলাদেশ)",
38969 "Belarus (Беларусь)",
38974 "Belgium (België)",
39004 "Bosnia and Herzegovina (Босна и Херцеговина)",
39019 "British Indian Ocean Territory",
39024 "British Virgin Islands",
39034 "Bulgaria (България)",
39044 "Burundi (Uburundi)",
39049 "Cambodia (កម្ពុជា)",
39054 "Cameroon (Cameroun)",
39063 ["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"]
39066 "Cape Verde (Kabu Verdi)",
39071 "Caribbean Netherlands",
39082 "Central African Republic (République centrafricaine)",
39102 "Christmas Island",
39108 "Cocos (Keeling) Islands",
39119 "Comoros (جزر القمر)",
39124 "Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)",
39129 "Congo (Republic) (Congo-Brazzaville)",
39149 "Croatia (Hrvatska)",
39170 "Czech Republic (Česká republika)",
39175 "Denmark (Danmark)",
39190 "Dominican Republic (República Dominicana)",
39194 ["809", "829", "849"]
39212 "Equatorial Guinea (Guinea Ecuatorial)",
39232 "Falkland Islands (Islas Malvinas)",
39237 "Faroe Islands (Føroyar)",
39258 "French Guiana (Guyane française)",
39263 "French Polynesia (Polynésie française)",
39278 "Georgia (საქართველო)",
39283 "Germany (Deutschland)",
39303 "Greenland (Kalaallit Nunaat)",
39340 "Guinea-Bissau (Guiné Bissau)",
39365 "Hungary (Magyarország)",
39370 "Iceland (Ísland)",
39390 "Iraq (العراق)",
39406 "Israel (ישראל)",
39433 "Jordan (الأردن)",
39438 "Kazakhstan (Казахстан)",
39459 "Kuwait (الكويت)",
39464 "Kyrgyzstan (Кыргызстан)",
39474 "Latvia (Latvija)",
39479 "Lebanon (لبنان)",
39494 "Libya (ليبيا)",
39504 "Lithuania (Lietuva)",
39519 "Macedonia (FYROM) (Македонија)",
39524 "Madagascar (Madagasikara)",
39554 "Marshall Islands",
39564 "Mauritania (موريتانيا)",
39569 "Mauritius (Moris)",
39590 "Moldova (Republica Moldova)",
39600 "Mongolia (Монгол)",
39605 "Montenegro (Crna Gora)",
39615 "Morocco (المغرب)",
39621 "Mozambique (Moçambique)",
39626 "Myanmar (Burma) (မြန်မာ)",
39631 "Namibia (Namibië)",
39646 "Netherlands (Nederland)",
39651 "New Caledonia (Nouvelle-Calédonie)",
39686 "North Korea (조선 민주주의 인민 공화국)",
39691 "Northern Mariana Islands",
39707 "Pakistan (پاکستان)",
39717 "Palestine (فلسطين)",
39727 "Papua New Guinea",
39769 "Réunion (La Réunion)",
39775 "Romania (România)",
39791 "Saint Barthélemy",
39802 "Saint Kitts and Nevis",
39812 "Saint Martin (Saint-Martin (partie française))",
39818 "Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)",
39823 "Saint Vincent and the Grenadines",
39838 "São Tomé and Príncipe (São Tomé e Príncipe)",
39843 "Saudi Arabia (المملكة العربية السعودية)",
39848 "Senegal (Sénégal)",
39878 "Slovakia (Slovensko)",
39883 "Slovenia (Slovenija)",
39893 "Somalia (Soomaaliya)",
39903 "South Korea (대한민국)",
39908 "South Sudan (جنوب السودان)",
39918 "Sri Lanka (ශ්රී ලංකාව)",
39923 "Sudan (السودان)",
39933 "Svalbard and Jan Mayen",
39944 "Sweden (Sverige)",
39949 "Switzerland (Schweiz)",
39954 "Syria (سوريا)",
39999 "Trinidad and Tobago",
40004 "Tunisia (تونس)",
40009 "Turkey (Türkiye)",
40019 "Turks and Caicos Islands",
40029 "U.S. Virgin Islands",
40039 "Ukraine (Україна)",
40044 "United Arab Emirates (الإمارات العربية المتحدة)",
40066 "Uzbekistan (Oʻzbekiston)",
40076 "Vatican City (Città del Vaticano)",
40087 "Vietnam (Việt Nam)",
40092 "Wallis and Futuna (Wallis-et-Futuna)",
40097 "Western Sahara (الصحراء الغربية)",
40103 "Yemen (اليمن)",
40127 * This script refer to:
40128 * Title: International Telephone Input
40129 * Author: Jack O'Connor
40130 * Code version: v12.1.12
40131 * Availability: https://github.com/jackocnr/intl-tel-input.git
40135 * @class Roo.bootstrap.PhoneInput
40136 * @extends Roo.bootstrap.TriggerField
40137 * An input with International dial-code selection
40139 * @cfg {String} defaultDialCode default '+852'
40140 * @cfg {Array} preferedCountries default []
40143 * Create a new PhoneInput.
40144 * @param {Object} config Configuration options
40147 Roo.bootstrap.PhoneInput = function(config) {
40148 Roo.bootstrap.PhoneInput.superclass.constructor.call(this, config);
40151 Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
40153 listWidth: undefined,
40155 selectedClass: 'active',
40157 invalidClass : "has-warning",
40159 validClass: 'has-success',
40161 allowed: '0123456789',
40166 * @cfg {String} defaultDialCode The default dial code when initializing the input
40168 defaultDialCode: '+852',
40171 * @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
40173 preferedCountries: false,
40175 getAutoCreate : function()
40177 var data = Roo.bootstrap.PhoneInputData();
40178 var align = this.labelAlign || this.parentLabelAlign();
40181 this.allCountries = [];
40182 this.dialCodeMapping = [];
40184 for (var i = 0; i < data.length; i++) {
40186 this.allCountries[i] = {
40190 priority: c[3] || 0,
40191 areaCodes: c[4] || null
40193 this.dialCodeMapping[c[2]] = {
40196 priority: c[3] || 0,
40197 areaCodes: c[4] || null
40209 // type: 'number', -- do not use number - we get the flaky up/down arrows.
40210 maxlength: this.max_length,
40211 cls : 'form-control tel-input',
40212 autocomplete: 'new-password'
40215 var hiddenInput = {
40218 cls: 'hidden-tel-input'
40222 hiddenInput.name = this.name;
40225 if (this.disabled) {
40226 input.disabled = true;
40229 var flag_container = {
40246 cls: this.hasFeedback ? 'has-feedback' : '',
40252 cls: 'dial-code-holder',
40259 cls: 'roo-select2-container input-group',
40266 if (this.fieldLabel.length) {
40269 tooltip: 'This field is required'
40275 cls: 'control-label',
40281 html: this.fieldLabel
40284 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40290 if(this.indicatorpos == 'right') {
40291 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40298 if(align == 'left') {
40306 if(this.labelWidth > 12){
40307 label.style = "width: " + this.labelWidth + 'px';
40309 if(this.labelWidth < 13 && this.labelmd == 0){
40310 this.labelmd = this.labelWidth;
40312 if(this.labellg > 0){
40313 label.cls += ' col-lg-' + this.labellg;
40314 input.cls += ' col-lg-' + (12 - this.labellg);
40316 if(this.labelmd > 0){
40317 label.cls += ' col-md-' + this.labelmd;
40318 container.cls += ' col-md-' + (12 - this.labelmd);
40320 if(this.labelsm > 0){
40321 label.cls += ' col-sm-' + this.labelsm;
40322 container.cls += ' col-sm-' + (12 - this.labelsm);
40324 if(this.labelxs > 0){
40325 label.cls += ' col-xs-' + this.labelxs;
40326 container.cls += ' col-xs-' + (12 - this.labelxs);
40336 var settings = this;
40338 ['xs','sm','md','lg'].map(function(size){
40339 if (settings[size]) {
40340 cfg.cls += ' col-' + size + '-' + settings[size];
40344 this.store = new Roo.data.Store({
40345 proxy : new Roo.data.MemoryProxy({}),
40346 reader : new Roo.data.JsonReader({
40357 'name' : 'dialCode',
40361 'name' : 'priority',
40365 'name' : 'areaCodes',
40372 if(!this.preferedCountries) {
40373 this.preferedCountries = [
40380 var p = this.preferedCountries.reverse();
40383 for (var i = 0; i < p.length; i++) {
40384 for (var j = 0; j < this.allCountries.length; j++) {
40385 if(this.allCountries[j].iso2 == p[i]) {
40386 var t = this.allCountries[j];
40387 this.allCountries.splice(j,1);
40388 this.allCountries.unshift(t);
40394 this.store.proxy.data = {
40396 data: this.allCountries
40402 initEvents : function()
40405 Roo.bootstrap.PhoneInput.superclass.initEvents.call(this);
40407 this.indicator = this.indicatorEl();
40408 this.flag = this.flagEl();
40409 this.dialCodeHolder = this.dialCodeHolderEl();
40411 this.trigger = this.el.select('div.flag-box',true).first();
40412 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
40417 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40418 _this.list.setWidth(lw);
40421 this.list.on('mouseover', this.onViewOver, this);
40422 this.list.on('mousemove', this.onViewMove, this);
40423 this.inputEl().on("keyup", this.onKeyUp, this);
40424 this.inputEl().on("keypress", this.onKeyPress, this);
40426 this.tpl = '<li><a href="#"><div class="flag {iso2}"></div>{name} <span class="dial-code">+{dialCode}</span></a></li>';
40428 this.view = new Roo.View(this.list, this.tpl, {
40429 singleSelect:true, store: this.store, selectedClass: this.selectedClass
40432 this.view.on('click', this.onViewClick, this);
40433 this.setValue(this.defaultDialCode);
40436 onTriggerClick : function(e)
40438 Roo.log('trigger click');
40443 if(this.isExpanded()){
40445 this.hasFocus = false;
40447 this.store.load({});
40448 this.hasFocus = true;
40453 isExpanded : function()
40455 return this.list.isVisible();
40458 collapse : function()
40460 if(!this.isExpanded()){
40464 Roo.get(document).un('mousedown', this.collapseIf, this);
40465 Roo.get(document).un('mousewheel', this.collapseIf, this);
40466 this.fireEvent('collapse', this);
40470 expand : function()
40474 if(this.isExpanded() || !this.hasFocus){
40478 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
40479 this.list.setWidth(lw);
40482 this.restrictHeight();
40484 Roo.get(document).on('mousedown', this.collapseIf, this);
40485 Roo.get(document).on('mousewheel', this.collapseIf, this);
40487 this.fireEvent('expand', this);
40490 restrictHeight : function()
40492 this.list.alignTo(this.inputEl(), this.listAlign);
40493 this.list.alignTo(this.inputEl(), this.listAlign);
40496 onViewOver : function(e, t)
40498 if(this.inKeyMode){
40501 var item = this.view.findItemFromChild(t);
40504 var index = this.view.indexOf(item);
40505 this.select(index, false);
40510 onViewClick : function(view, doFocus, el, e)
40512 var index = this.view.getSelectedIndexes()[0];
40514 var r = this.store.getAt(index);
40517 this.onSelect(r, index);
40519 if(doFocus !== false && !this.blockFocus){
40520 this.inputEl().focus();
40524 onViewMove : function(e, t)
40526 this.inKeyMode = false;
40529 select : function(index, scrollIntoView)
40531 this.selectedIndex = index;
40532 this.view.select(index);
40533 if(scrollIntoView !== false){
40534 var el = this.view.getNode(index);
40536 this.list.scrollChildIntoView(el, false);
40541 createList : function()
40543 this.list = Roo.get(document.body).createChild({
40545 cls: 'typeahead typeahead-long dropdown-menu tel-list',
40546 style: 'display:none'
40549 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
40552 collapseIf : function(e)
40554 var in_combo = e.within(this.el);
40555 var in_list = e.within(this.list);
40556 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
40558 if (in_combo || in_list || is_list) {
40564 onSelect : function(record, index)
40566 if(this.fireEvent('beforeselect', this, record, index) !== false){
40568 this.setFlagClass(record.data.iso2);
40569 this.setDialCode(record.data.dialCode);
40570 this.hasFocus = false;
40572 this.fireEvent('select', this, record, index);
40576 flagEl : function()
40578 var flag = this.el.select('div.flag',true).first();
40585 dialCodeHolderEl : function()
40587 var d = this.el.select('input.dial-code-holder',true).first();
40594 setDialCode : function(v)
40596 this.dialCodeHolder.dom.value = '+'+v;
40599 setFlagClass : function(n)
40601 this.flag.dom.className = 'flag '+n;
40604 getValue : function()
40606 var v = this.inputEl().getValue();
40607 if(this.dialCodeHolder) {
40608 v = this.dialCodeHolder.dom.value+this.inputEl().getValue();
40613 setValue : function(v)
40615 var d = this.getDialCode(v);
40617 //invalid dial code
40618 if(v.length == 0 || !d || d.length == 0) {
40620 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
40621 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
40627 this.setFlagClass(this.dialCodeMapping[d].iso2);
40628 this.setDialCode(d);
40629 this.inputEl().dom.value = v.replace('+'+d,'');
40630 this.hiddenEl().dom.value = this.getValue();
40635 getDialCode : function(v)
40639 if (v.length == 0) {
40640 return this.dialCodeHolder.dom.value;
40644 if (v.charAt(0) != "+") {
40647 var numericChars = "";
40648 for (var i = 1; i < v.length; i++) {
40649 var c = v.charAt(i);
40652 if (this.dialCodeMapping[numericChars]) {
40653 dialCode = v.substr(1, i);
40655 if (numericChars.length == 4) {
40665 this.setValue(this.defaultDialCode);
40669 hiddenEl : function()
40671 return this.el.select('input.hidden-tel-input',true).first();
40674 // after setting val
40675 onKeyUp : function(e){
40676 this.setValue(this.getValue());
40679 onKeyPress : function(e){
40680 if(this.allowed.indexOf(String.fromCharCode(e.getCharCode())) === -1){
40687 * @class Roo.bootstrap.MoneyField
40688 * @extends Roo.bootstrap.ComboBox
40689 * Bootstrap MoneyField class
40692 * Create a new MoneyField.
40693 * @param {Object} config Configuration options
40696 Roo.bootstrap.MoneyField = function(config) {
40698 Roo.bootstrap.MoneyField.superclass.constructor.call(this, config);
40702 Roo.extend(Roo.bootstrap.MoneyField, Roo.bootstrap.ComboBox, {
40705 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
40707 allowDecimals : true,
40709 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
40711 decimalSeparator : ".",
40713 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
40715 decimalPrecision : 0,
40717 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
40719 allowNegative : true,
40721 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
40725 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
40727 minValue : Number.NEGATIVE_INFINITY,
40729 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
40731 maxValue : Number.MAX_VALUE,
40733 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
40735 minText : "The minimum value for this field is {0}",
40737 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
40739 maxText : "The maximum value for this field is {0}",
40741 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
40742 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
40744 nanText : "{0} is not a valid number",
40746 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
40750 * @cfg {String} defaults currency of the MoneyField
40751 * value should be in lkey
40753 defaultCurrency : false,
40755 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
40757 thousandsDelimiter : false,
40759 * @cfg {Number} max_length Maximum input field length allowed (defaults to Number.MAX_VALUE)
40770 getAutoCreate : function()
40772 var align = this.labelAlign || this.parentLabelAlign();
40784 cls : 'form-control roo-money-amount-input',
40785 autocomplete: 'new-password'
40788 var hiddenInput = {
40792 cls: 'hidden-number-input'
40795 if(this.max_length) {
40796 input.maxlength = this.max_length;
40800 hiddenInput.name = this.name;
40803 if (this.disabled) {
40804 input.disabled = true;
40807 var clg = 12 - this.inputlg;
40808 var cmd = 12 - this.inputmd;
40809 var csm = 12 - this.inputsm;
40810 var cxs = 12 - this.inputxs;
40814 cls : 'row roo-money-field',
40818 cls : 'roo-money-currency column col-lg-' + clg + ' col-md-' + cmd + ' col-sm-' + csm + ' col-xs-' + cxs,
40822 cls: 'roo-select2-container input-group',
40826 cls : 'form-control roo-money-currency-input',
40827 autocomplete: 'new-password',
40829 name : this.currencyName
40833 cls : 'input-group-addon',
40847 cls : 'roo-money-amount column col-lg-' + this.inputlg + ' col-md-' + this.inputmd + ' col-sm-' + this.inputsm + ' col-xs-' + this.inputxs,
40851 cls: this.hasFeedback ? 'has-feedback' : '',
40862 if (this.fieldLabel.length) {
40865 tooltip: 'This field is required'
40871 cls: 'control-label',
40877 html: this.fieldLabel
40880 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40886 if(this.indicatorpos == 'right') {
40887 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40894 if(align == 'left') {
40902 if(this.labelWidth > 12){
40903 label.style = "width: " + this.labelWidth + 'px';
40905 if(this.labelWidth < 13 && this.labelmd == 0){
40906 this.labelmd = this.labelWidth;
40908 if(this.labellg > 0){
40909 label.cls += ' col-lg-' + this.labellg;
40910 input.cls += ' col-lg-' + (12 - this.labellg);
40912 if(this.labelmd > 0){
40913 label.cls += ' col-md-' + this.labelmd;
40914 container.cls += ' col-md-' + (12 - this.labelmd);
40916 if(this.labelsm > 0){
40917 label.cls += ' col-sm-' + this.labelsm;
40918 container.cls += ' col-sm-' + (12 - this.labelsm);
40920 if(this.labelxs > 0){
40921 label.cls += ' col-xs-' + this.labelxs;
40922 container.cls += ' col-xs-' + (12 - this.labelxs);
40933 var settings = this;
40935 ['xs','sm','md','lg'].map(function(size){
40936 if (settings[size]) {
40937 cfg.cls += ' col-' + size + '-' + settings[size];
40944 initEvents : function()
40946 this.indicator = this.indicatorEl();
40948 this.initCurrencyEvent();
40950 this.initNumberEvent();
40953 initCurrencyEvent : function()
40956 throw "can not find store for combo";
40959 this.store = Roo.factory(this.store, Roo.data);
40960 this.store.parent = this;
40964 this.triggerEl = this.el.select('.input-group-addon', true).first();
40966 this.triggerEl.on("click", this.onTriggerClick, this, { preventDefault : true });
40971 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40972 _this.list.setWidth(lw);
40975 this.list.on('mouseover', this.onViewOver, this);
40976 this.list.on('mousemove', this.onViewMove, this);
40977 this.list.on('scroll', this.onViewScroll, this);
40980 this.tpl = '<li><a href="#">{' + this.currencyField + '}</a></li>';
40983 this.view = new Roo.View(this.list, this.tpl, {
40984 singleSelect:true, store: this.store, selectedClass: this.selectedClass
40987 this.view.on('click', this.onViewClick, this);
40989 this.store.on('beforeload', this.onBeforeLoad, this);
40990 this.store.on('load', this.onLoad, this);
40991 this.store.on('loadexception', this.onLoadException, this);
40993 this.keyNav = new Roo.KeyNav(this.currencyEl(), {
40994 "up" : function(e){
40995 this.inKeyMode = true;
40999 "down" : function(e){
41000 if(!this.isExpanded()){
41001 this.onTriggerClick();
41003 this.inKeyMode = true;
41008 "enter" : function(e){
41011 if(this.fireEvent("specialkey", this, e)){
41012 this.onViewClick(false);
41018 "esc" : function(e){
41022 "tab" : function(e){
41025 if(this.fireEvent("specialkey", this, e)){
41026 this.onViewClick(false);
41034 doRelay : function(foo, bar, hname){
41035 if(hname == 'down' || this.scope.isExpanded()){
41036 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
41044 this.currencyEl().on("click", this.onTriggerClick, this, { preventDefault : true });
41048 initNumberEvent : function(e)
41050 this.inputEl().on("keydown" , this.fireKey, this);
41051 this.inputEl().on("focus", this.onFocus, this);
41052 this.inputEl().on("blur", this.onBlur, this);
41054 this.inputEl().relayEvent('keyup', this);
41056 if(this.indicator){
41057 this.indicator.addClass('invisible');
41060 this.originalValue = this.getValue();
41062 if(this.validationEvent == 'keyup'){
41063 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
41064 this.inputEl().on('keyup', this.filterValidation, this);
41066 else if(this.validationEvent !== false){
41067 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
41070 if(this.selectOnFocus){
41071 this.on("focus", this.preFocus, this);
41074 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
41075 this.inputEl().on("keypress", this.filterKeys, this);
41077 this.inputEl().relayEvent('keypress', this);
41080 var allowed = "0123456789";
41082 if(this.allowDecimals){
41083 allowed += this.decimalSeparator;
41086 if(this.allowNegative){
41090 if(this.thousandsDelimiter) {
41094 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
41096 var keyPress = function(e){
41098 var k = e.getKey();
41100 var c = e.getCharCode();
41103 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
41104 allowed.indexOf(String.fromCharCode(c)) === -1
41110 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
41114 if(allowed.indexOf(String.fromCharCode(c)) === -1){
41119 this.inputEl().on("keypress", keyPress, this);
41123 onTriggerClick : function(e)
41130 this.loadNext = false;
41132 if(this.isExpanded()){
41137 this.hasFocus = true;
41139 if(this.triggerAction == 'all') {
41140 this.doQuery(this.allQuery, true);
41144 this.doQuery(this.getRawValue());
41147 getCurrency : function()
41149 var v = this.currencyEl().getValue();
41154 restrictHeight : function()
41156 this.list.alignTo(this.currencyEl(), this.listAlign);
41157 this.list.alignTo(this.currencyEl(), this.listAlign);
41160 onViewClick : function(view, doFocus, el, e)
41162 var index = this.view.getSelectedIndexes()[0];
41164 var r = this.store.getAt(index);
41167 this.onSelect(r, index);
41171 onSelect : function(record, index){
41173 if(this.fireEvent('beforeselect', this, record, index) !== false){
41175 this.setFromCurrencyData(index > -1 ? record.data : false);
41179 this.fireEvent('select', this, record, index);
41183 setFromCurrencyData : function(o)
41187 this.lastCurrency = o;
41189 if (this.currencyField) {
41190 currency = !o || typeof(o[this.currencyField]) == 'undefined' ? '' : o[this.currencyField];
41192 Roo.log('no currencyField value set for '+ (this.name ? this.name : this.id));
41195 this.lastSelectionText = currency;
41197 //setting default currency
41198 if(o[this.currencyField] * 1 == 0 && this.defaultCurrency) {
41199 this.setCurrency(this.defaultCurrency);
41203 this.setCurrency(currency);
41206 setFromData : function(o)
41210 c[this.currencyField] = !o || typeof(o[this.currencyName]) == 'undefined' ? '' : o[this.currencyName];
41212 this.setFromCurrencyData(c);
41217 value = !o || typeof(o[this.name]) == 'undefined' ? '' : o[this.name];
41219 Roo.log('no value set for '+ (this.name ? this.name : this.id));
41222 this.setValue(value);
41226 setCurrency : function(v)
41228 this.currencyValue = v;
41231 this.currencyEl().dom.value = (v === null || v === undefined ? '' : v);
41236 setValue : function(v)
41238 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
41244 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
41246 this.inputEl().dom.value = (v == '') ? '' :
41247 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
41249 if(!this.allowZero && v === '0') {
41250 this.hiddenEl().dom.value = '';
41251 this.inputEl().dom.value = '';
41258 getRawValue : function()
41260 var v = this.inputEl().getValue();
41265 getValue : function()
41267 return this.fixPrecision(this.parseValue(this.getRawValue()));
41270 parseValue : function(value)
41272 if(this.thousandsDelimiter) {
41274 r = new RegExp(",", "g");
41275 value = value.replace(r, "");
41278 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
41279 return isNaN(value) ? '' : value;
41283 fixPrecision : function(value)
41285 if(this.thousandsDelimiter) {
41287 r = new RegExp(",", "g");
41288 value = value.replace(r, "");
41291 var nan = isNaN(value);
41293 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
41294 return nan ? '' : value;
41296 return parseFloat(value).toFixed(this.decimalPrecision);
41299 decimalPrecisionFcn : function(v)
41301 return Math.floor(v);
41304 validateValue : function(value)
41306 if(!Roo.bootstrap.MoneyField.superclass.validateValue.call(this, value)){
41310 var num = this.parseValue(value);
41313 this.markInvalid(String.format(this.nanText, value));
41317 if(num < this.minValue){
41318 this.markInvalid(String.format(this.minText, this.minValue));
41322 if(num > this.maxValue){
41323 this.markInvalid(String.format(this.maxText, this.maxValue));
41330 validate : function()
41332 if(this.disabled || this.allowBlank){
41337 var currency = this.getCurrency();
41339 if(this.validateValue(this.getRawValue()) && currency.length){
41344 this.markInvalid();
41348 getName: function()
41353 beforeBlur : function()
41359 var v = this.parseValue(this.getRawValue());
41366 onBlur : function()
41370 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
41371 //this.el.removeClass(this.focusClass);
41374 this.hasFocus = false;
41376 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
41380 var v = this.getValue();
41382 if(String(v) !== String(this.startValue)){
41383 this.fireEvent('change', this, v, this.startValue);
41386 this.fireEvent("blur", this);
41389 inputEl : function()
41391 return this.el.select('.roo-money-amount-input', true).first();
41394 currencyEl : function()
41396 return this.el.select('.roo-money-currency-input', true).first();
41399 hiddenEl : function()
41401 return this.el.select('input.hidden-number-input',true).first();