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'
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 (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
4192 cfg.cls += ' navbar-' + this.position + ' ' + this.position ;
4194 // tag can override this..
4196 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
4199 if (this.brand !== '') {
4200 var cp = Roo.bootstrap.version == 4 ? cn : cn[0].cn;
4201 cp.unshift({ // changed from push ?? BS4 needs it at the start? - does this break or exsiting?
4203 href: this.brand_href ? this.brand_href : '#',
4204 cls: 'navbar-brand',
4212 cfg.cls += ' main-nav';
4220 getHeaderChildContainer : function()
4222 if (this.srButton && this.el.select('.navbar-header').getCount()) {
4223 return this.el.select('.navbar-header',true).first();
4226 return this.getChildContainer();
4230 initEvents : function()
4232 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
4234 if (this.autohide) {
4239 Roo.get(document).on('scroll',function(e) {
4240 var ns = Roo.get(document).getScroll().top;
4241 var os = prevScroll;
4245 ft.removeClass('slideDown');
4246 ft.addClass('slideUp');
4249 ft.removeClass('slideUp');
4250 ft.addClass('slideDown');
4271 * @class Roo.bootstrap.NavSidebar
4272 * @extends Roo.bootstrap.Navbar
4273 * Bootstrap Sidebar class
4276 * Create a new Sidebar
4277 * @param {Object} config The config object
4281 Roo.bootstrap.NavSidebar = function(config){
4282 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
4285 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
4287 sidebar : true, // used by Navbar Item and NavbarGroup at present...
4289 getAutoCreate : function(){
4294 cls: 'sidebar sidebar-nav'
4316 * @class Roo.bootstrap.NavGroup
4317 * @extends Roo.bootstrap.Component
4318 * Bootstrap NavGroup class
4319 * @cfg {String} align (left|right)
4320 * @cfg {Boolean} inverse
4321 * @cfg {String} type (nav|pills|tab) default nav
4322 * @cfg {String} navId - reference Id for navbar.
4326 * Create a new nav group
4327 * @param {Object} config The config object
4330 Roo.bootstrap.NavGroup = function(config){
4331 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
4334 Roo.bootstrap.NavGroup.register(this);
4338 * Fires when the active item changes
4339 * @param {Roo.bootstrap.NavGroup} this
4340 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
4341 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
4348 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
4359 getAutoCreate : function()
4361 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
4367 if (Roo.bootstrap.version == 4) {
4368 if (this.type == 'pills') {
4369 cfg.cls = ' nav-pills';
4372 if (['tabs','pills'].indexOf(this.type)!==-1) {
4373 cfg.cls += ' nav-' + this.type
4375 if (this.type !== 'nav') {
4376 Roo.log('nav type must be nav/tabs/pills')
4378 cfg.cls += ' navbar-nav'
4382 if (this.parent() && this.parent().sidebar) {
4385 cls: 'dashboard-menu sidebar-menu'
4391 if (this.form === true) {
4394 cls: 'navbar-form form-inline'
4397 if (this.align === 'right') {
4398 cfg.cls += ' navbar-right ml-md-auto';
4400 cfg.cls += ' navbar-left';
4404 if (this.align === 'right') {
4405 cfg.cls += ' navbar-right ml-md-auto';
4407 cfg.cls += ' mr-auto';
4411 cfg.cls += ' navbar-inverse';
4419 * sets the active Navigation item
4420 * @param {Roo.bootstrap.NavItem} the new current navitem
4422 setActiveItem : function(item)
4425 Roo.each(this.navItems, function(v){
4430 v.setActive(false, true);
4437 item.setActive(true, true);
4438 this.fireEvent('changed', this, item, prev);
4443 * gets the active Navigation item
4444 * @return {Roo.bootstrap.NavItem} the current navitem
4446 getActive : function()
4450 Roo.each(this.navItems, function(v){
4461 indexOfNav : function()
4465 Roo.each(this.navItems, function(v,i){
4476 * adds a Navigation item
4477 * @param {Roo.bootstrap.NavItem} the navitem to add
4479 addItem : function(cfg)
4481 if (this.form && Roo.bootstrap.version == 4) {
4484 var cn = new Roo.bootstrap.NavItem(cfg);
4486 cn.parentId = this.id;
4487 cn.onRender(this.el, null);
4491 * register a Navigation item
4492 * @param {Roo.bootstrap.NavItem} the navitem to add
4494 register : function(item)
4496 this.navItems.push( item);
4497 item.navId = this.navId;
4502 * clear all the Navigation item
4505 clearAll : function()
4508 this.el.dom.innerHTML = '';
4511 getNavItem: function(tabId)
4514 Roo.each(this.navItems, function(e) {
4515 if (e.tabId == tabId) {
4525 setActiveNext : function()
4527 var i = this.indexOfNav(this.getActive());
4528 if (i > this.navItems.length) {
4531 this.setActiveItem(this.navItems[i+1]);
4533 setActivePrev : function()
4535 var i = this.indexOfNav(this.getActive());
4539 this.setActiveItem(this.navItems[i-1]);
4541 clearWasActive : function(except) {
4542 Roo.each(this.navItems, function(e) {
4543 if (e.tabId != except.tabId && e.was_active) {
4544 e.was_active = false;
4551 getWasActive : function ()
4554 Roo.each(this.navItems, function(e) {
4569 Roo.apply(Roo.bootstrap.NavGroup, {
4573 * register a Navigation Group
4574 * @param {Roo.bootstrap.NavGroup} the navgroup to add
4576 register : function(navgrp)
4578 this.groups[navgrp.navId] = navgrp;
4582 * fetch a Navigation Group based on the navigation ID
4583 * @param {string} the navgroup to add
4584 * @returns {Roo.bootstrap.NavGroup} the navgroup
4586 get: function(navId) {
4587 if (typeof(this.groups[navId]) == 'undefined') {
4589 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
4591 return this.groups[navId] ;
4606 * @class Roo.bootstrap.NavItem
4607 * @extends Roo.bootstrap.Component
4608 * Bootstrap Navbar.NavItem class
4609 * @cfg {String} href link to
4610 * @cfg {String} html content of button
4611 * @cfg {String} badge text inside badge
4612 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
4613 * @cfg {String} glyphicon DEPRICATED - use fa
4614 * @cfg {String} icon DEPRICATED - use fa
4615 * @cfg {String} fa - Fontawsome icon name (can add stuff to it like fa-2x)
4616 * @cfg {Boolean} active Is item active
4617 * @cfg {Boolean} disabled Is item disabled
4619 * @cfg {Boolean} preventDefault (true | false) default false
4620 * @cfg {String} tabId the tab that this item activates.
4621 * @cfg {String} tagtype (a|span) render as a href or span?
4622 * @cfg {Boolean} animateRef (true|false) link to element default false
4625 * Create a new Navbar Item
4626 * @param {Object} config The config object
4628 Roo.bootstrap.NavItem = function(config){
4629 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
4634 * The raw click event for the entire grid.
4635 * @param {Roo.EventObject} e
4640 * Fires when the active item active state changes
4641 * @param {Roo.bootstrap.NavItem} this
4642 * @param {boolean} state the new state
4648 * Fires when scroll to element
4649 * @param {Roo.bootstrap.NavItem} this
4650 * @param {Object} options
4651 * @param {Roo.EventObject} e
4659 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
4668 preventDefault : false,
4676 getAutoCreate : function(){
4685 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
4687 if (this.disabled) {
4688 cfg.cls += ' disabled';
4691 if (this.href || this.html || this.glyphicon || this.icon || this.fa) {
4695 href : this.href || "#",
4696 html: this.html || ''
4699 if (this.tagtype == 'a') {
4700 cfg.cn[0].cls = 'nav-link';
4703 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
4706 cfg.cn[0].html = '<i class="fa fas fa-'+this.fa+'"></i> <span>' + cfg.cn[0].html + '</span>'
4708 if(this.glyphicon) {
4709 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
4714 cfg.cn[0].html += " <span class='caret'></span>";
4718 if (this.badge !== '') {
4720 cfg.cn[0].html += ' <span class="badge badge-secondary">' + this.badge + '</span>';
4728 onRender : function(ct, position)
4730 // Roo.log("Call onRender: " + this.xtype);
4731 if (Roo.bootstrap.version == 4 && ct.dom.type != 'ul') {
4735 return Roo.bootstrap.NavItem.superclass.onRender.call(this, ct, position);
4739 initEvents: function()
4741 if (typeof (this.menu) != 'undefined') {
4742 this.menu.parentType = this.xtype;
4743 this.menu.triggerEl = this.el;
4744 this.menu = this.addxtype(Roo.apply({}, this.menu));
4747 this.el.select('a',true).on('click', this.onClick, this);
4749 if(this.tagtype == 'span'){
4750 this.el.select('span',true).on('click', this.onClick, this);
4753 // at this point parent should be available..
4754 this.parent().register(this);
4757 onClick : function(e)
4759 if (e.getTarget('.dropdown-menu-item')) {
4760 // did you click on a menu itemm.... - then don't trigger onclick..
4765 this.preventDefault ||
4768 Roo.log("NavItem - prevent Default?");
4772 if (this.disabled) {
4776 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4777 if (tg && tg.transition) {
4778 Roo.log("waiting for the transitionend");
4784 //Roo.log("fire event clicked");
4785 if(this.fireEvent('click', this, e) === false){
4789 if(this.tagtype == 'span'){
4793 //Roo.log(this.href);
4794 var ael = this.el.select('a',true).first();
4797 if(ael && this.animateRef && this.href.indexOf('#') > -1){
4798 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4799 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4800 return; // ignore... - it's a 'hash' to another page.
4802 Roo.log("NavItem - prevent Default?");
4804 this.scrollToElement(e);
4808 var p = this.parent();
4810 if (['tabs','pills'].indexOf(p.type)!==-1) {
4811 if (typeof(p.setActiveItem) !== 'undefined') {
4812 p.setActiveItem(this);
4816 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4817 if (p.parentType == 'NavHeaderbar' && !this.menu) {
4818 // remove the collapsed menu expand...
4819 p.parent().el.select('.navbar-collapse',true).removeClass('in');
4823 isActive: function () {
4826 setActive : function(state, fire, is_was_active)
4828 if (this.active && !state && this.navId) {
4829 this.was_active = true;
4830 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4832 nv.clearWasActive(this);
4836 this.active = state;
4839 this.el.removeClass('active');
4840 } else if (!this.el.hasClass('active')) {
4841 this.el.addClass('active');
4844 this.fireEvent('changed', this, state);
4847 // show a panel if it's registered and related..
4849 if (!this.navId || !this.tabId || !state || is_was_active) {
4853 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4857 var pan = tg.getPanelByName(this.tabId);
4861 // if we can not flip to new panel - go back to old nav highlight..
4862 if (false == tg.showPanel(pan)) {
4863 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4865 var onav = nv.getWasActive();
4867 onav.setActive(true, false, true);
4876 // this should not be here...
4877 setDisabled : function(state)
4879 this.disabled = state;
4881 this.el.removeClass('disabled');
4882 } else if (!this.el.hasClass('disabled')) {
4883 this.el.addClass('disabled');
4889 * Fetch the element to display the tooltip on.
4890 * @return {Roo.Element} defaults to this.el
4892 tooltipEl : function()
4894 return this.el.select('' + this.tagtype + '', true).first();
4897 scrollToElement : function(e)
4899 var c = document.body;
4902 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
4904 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
4905 c = document.documentElement;
4908 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4914 var o = target.calcOffsetsTo(c);
4921 this.fireEvent('scrollto', this, options, e);
4923 Roo.get(c).scrollTo('top', options.value, true);
4936 * <span> icon </span>
4937 * <span> text </span>
4938 * <span>badge </span>
4942 * @class Roo.bootstrap.NavSidebarItem
4943 * @extends Roo.bootstrap.NavItem
4944 * Bootstrap Navbar.NavSidebarItem class
4945 * {String} badgeWeight (default|primary|success|info|warning|danger)the extra classes for the badge
4946 * {Boolean} open is the menu open
4947 * {Boolean} buttonView use button as the tigger el rather that a (default false)
4948 * {String} buttonWeight (default|primary|success|info|warning|danger)the extra classes for the button
4949 * {String} buttonSize (sm|md|lg)the extra classes for the button
4950 * {Boolean} showArrow show arrow next to the text (default true)
4952 * Create a new Navbar Button
4953 * @param {Object} config The config object
4955 Roo.bootstrap.NavSidebarItem = function(config){
4956 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4961 * The raw click event for the entire grid.
4962 * @param {Roo.EventObject} e
4967 * Fires when the active item active state changes
4968 * @param {Roo.bootstrap.NavSidebarItem} this
4969 * @param {boolean} state the new state
4977 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
4979 badgeWeight : 'default',
4985 buttonWeight : 'default',
4991 getAutoCreate : function(){
4996 href : this.href || '#',
5002 if(this.buttonView){
5005 href : this.href || '#',
5006 cls: 'btn btn-' + this.buttonWeight + ' btn-' + this.buttonSize + 'roo-button-dropdown-toggle',
5019 cfg.cls += ' active';
5022 if (this.disabled) {
5023 cfg.cls += ' disabled';
5026 cfg.cls += ' open x-open';
5029 if (this.glyphicon || this.icon) {
5030 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
5031 a.cn.push({ tag : 'i', cls : c }) ;
5034 if(!this.buttonView){
5037 html : this.html || ''
5044 if (this.badge !== '') {
5045 a.cn.push({ tag: 'span', cls : 'badge pull-right badge-' + this.badgeWeight, html: this.badge });
5051 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
5054 a.cls += ' dropdown-toggle treeview' ;
5060 initEvents : function()
5062 if (typeof (this.menu) != 'undefined') {
5063 this.menu.parentType = this.xtype;
5064 this.menu.triggerEl = this.el;
5065 this.menu = this.addxtype(Roo.apply({}, this.menu));
5068 this.el.on('click', this.onClick, this);
5070 if(this.badge !== ''){
5071 this.badgeEl = this.el.select('.badge', true).first().setVisibilityMode(Roo.Element.DISPLAY);
5076 onClick : function(e)
5083 if(this.preventDefault){
5087 this.fireEvent('click', this);
5090 disable : function()
5092 this.setDisabled(true);
5097 this.setDisabled(false);
5100 setDisabled : function(state)
5102 if(this.disabled == state){
5106 this.disabled = state;
5109 this.el.addClass('disabled');
5113 this.el.removeClass('disabled');
5118 setActive : function(state)
5120 if(this.active == state){
5124 this.active = state;
5127 this.el.addClass('active');
5131 this.el.removeClass('active');
5136 isActive: function ()
5141 setBadge : function(str)
5147 this.badgeEl.dom.innerHTML = str;
5164 * @class Roo.bootstrap.Row
5165 * @extends Roo.bootstrap.Component
5166 * Bootstrap Row class (contains columns...)
5170 * @param {Object} config The config object
5173 Roo.bootstrap.Row = function(config){
5174 Roo.bootstrap.Row.superclass.constructor.call(this, config);
5177 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
5179 getAutoCreate : function(){
5198 * @class Roo.bootstrap.Element
5199 * @extends Roo.bootstrap.Component
5200 * Bootstrap Element class
5201 * @cfg {String} html contents of the element
5202 * @cfg {String} tag tag of the element
5203 * @cfg {String} cls class of the element
5204 * @cfg {Boolean} preventDefault (true|false) default false
5205 * @cfg {Boolean} clickable (true|false) default false
5208 * Create a new Element
5209 * @param {Object} config The config object
5212 Roo.bootstrap.Element = function(config){
5213 Roo.bootstrap.Element.superclass.constructor.call(this, config);
5219 * When a element is chick
5220 * @param {Roo.bootstrap.Element} this
5221 * @param {Roo.EventObject} e
5227 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
5232 preventDefault: false,
5235 getAutoCreate : function(){
5239 // cls: this.cls, double assign in parent class Component.js :: onRender
5246 initEvents: function()
5248 Roo.bootstrap.Element.superclass.initEvents.call(this);
5251 this.el.on('click', this.onClick, this);
5256 onClick : function(e)
5258 if(this.preventDefault){
5262 this.fireEvent('click', this, e);
5265 getValue : function()
5267 return this.el.dom.innerHTML;
5270 setValue : function(value)
5272 this.el.dom.innerHTML = value;
5287 * @class Roo.bootstrap.Pagination
5288 * @extends Roo.bootstrap.Component
5289 * Bootstrap Pagination class
5290 * @cfg {String} size xs | sm | md | lg
5291 * @cfg {Boolean} inverse false | true
5294 * Create a new Pagination
5295 * @param {Object} config The config object
5298 Roo.bootstrap.Pagination = function(config){
5299 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
5302 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
5308 getAutoCreate : function(){
5314 cfg.cls += ' inverse';
5320 cfg.cls += " " + this.cls;
5338 * @class Roo.bootstrap.PaginationItem
5339 * @extends Roo.bootstrap.Component
5340 * Bootstrap PaginationItem class
5341 * @cfg {String} html text
5342 * @cfg {String} href the link
5343 * @cfg {Boolean} preventDefault (true | false) default true
5344 * @cfg {Boolean} active (true | false) default false
5345 * @cfg {Boolean} disabled default false
5349 * Create a new PaginationItem
5350 * @param {Object} config The config object
5354 Roo.bootstrap.PaginationItem = function(config){
5355 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
5360 * The raw click event for the entire grid.
5361 * @param {Roo.EventObject} e
5367 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
5371 preventDefault: true,
5376 getAutoCreate : function(){
5382 href : this.href ? this.href : '#',
5383 html : this.html ? this.html : ''
5393 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
5397 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
5403 initEvents: function() {
5405 this.el.on('click', this.onClick, this);
5408 onClick : function(e)
5410 Roo.log('PaginationItem on click ');
5411 if(this.preventDefault){
5419 this.fireEvent('click', this, e);
5435 * @class Roo.bootstrap.Slider
5436 * @extends Roo.bootstrap.Component
5437 * Bootstrap Slider class
5440 * Create a new Slider
5441 * @param {Object} config The config object
5444 Roo.bootstrap.Slider = function(config){
5445 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
5448 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
5450 getAutoCreate : function(){
5454 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
5458 cls: 'ui-slider-handle ui-state-default ui-corner-all'
5470 * Ext JS Library 1.1.1
5471 * Copyright(c) 2006-2007, Ext JS, LLC.
5473 * Originally Released Under LGPL - original licence link has changed is not relivant.
5476 * <script type="text/javascript">
5481 * @class Roo.grid.ColumnModel
5482 * @extends Roo.util.Observable
5483 * This is the default implementation of a ColumnModel used by the Grid. It defines
5484 * the columns in the grid.
5487 var colModel = new Roo.grid.ColumnModel([
5488 {header: "Ticker", width: 60, sortable: true, locked: true},
5489 {header: "Company Name", width: 150, sortable: true},
5490 {header: "Market Cap.", width: 100, sortable: true},
5491 {header: "$ Sales", width: 100, sortable: true, renderer: money},
5492 {header: "Employees", width: 100, sortable: true, resizable: false}
5497 * The config options listed for this class are options which may appear in each
5498 * individual column definition.
5499 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
5501 * @param {Object} config An Array of column config objects. See this class's
5502 * config objects for details.
5504 Roo.grid.ColumnModel = function(config){
5506 * The config passed into the constructor
5508 this.config = config;
5511 // if no id, create one
5512 // if the column does not have a dataIndex mapping,
5513 // map it to the order it is in the config
5514 for(var i = 0, len = config.length; i < len; i++){
5516 if(typeof c.dataIndex == "undefined"){
5519 if(typeof c.renderer == "string"){
5520 c.renderer = Roo.util.Format[c.renderer];
5522 if(typeof c.id == "undefined"){
5525 if(c.editor && c.editor.xtype){
5526 c.editor = Roo.factory(c.editor, Roo.grid);
5528 if(c.editor && c.editor.isFormField){
5529 c.editor = new Roo.grid.GridEditor(c.editor);
5531 this.lookup[c.id] = c;
5535 * The width of columns which have no width specified (defaults to 100)
5538 this.defaultWidth = 100;
5541 * Default sortable of columns which have no sortable specified (defaults to false)
5544 this.defaultSortable = false;
5548 * @event widthchange
5549 * Fires when the width of a column changes.
5550 * @param {ColumnModel} this
5551 * @param {Number} columnIndex The column index
5552 * @param {Number} newWidth The new width
5554 "widthchange": true,
5556 * @event headerchange
5557 * Fires when the text of a header changes.
5558 * @param {ColumnModel} this
5559 * @param {Number} columnIndex The column index
5560 * @param {Number} newText The new header text
5562 "headerchange": true,
5564 * @event hiddenchange
5565 * Fires when a column is hidden or "unhidden".
5566 * @param {ColumnModel} this
5567 * @param {Number} columnIndex The column index
5568 * @param {Boolean} hidden true if hidden, false otherwise
5570 "hiddenchange": true,
5572 * @event columnmoved
5573 * Fires when a column is moved.
5574 * @param {ColumnModel} this
5575 * @param {Number} oldIndex
5576 * @param {Number} newIndex
5578 "columnmoved" : true,
5580 * @event columlockchange
5581 * Fires when a column's locked state is changed
5582 * @param {ColumnModel} this
5583 * @param {Number} colIndex
5584 * @param {Boolean} locked true if locked
5586 "columnlockchange" : true
5588 Roo.grid.ColumnModel.superclass.constructor.call(this);
5590 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
5592 * @cfg {String} header The header text to display in the Grid view.
5595 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
5596 * {@link Roo.data.Record} definition from which to draw the column's value. If not
5597 * specified, the column's index is used as an index into the Record's data Array.
5600 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
5601 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
5604 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
5605 * Defaults to the value of the {@link #defaultSortable} property.
5606 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
5609 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
5612 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
5615 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
5618 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
5621 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
5622 * given the cell's data value. See {@link #setRenderer}. If not specified, the
5623 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
5624 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
5627 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
5630 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
5633 * @cfg {String} valign (Optional) Set the CSS vertical-align property of the column (eg. middle, top, bottom etc). Defaults to undefined.
5636 * @cfg {String} cursor (Optional)
5639 * @cfg {String} tooltip (Optional)
5642 * @cfg {Number} xs (Optional)
5645 * @cfg {Number} sm (Optional)
5648 * @cfg {Number} md (Optional)
5651 * @cfg {Number} lg (Optional)
5654 * Returns the id of the column at the specified index.
5655 * @param {Number} index The column index
5656 * @return {String} the id
5658 getColumnId : function(index){
5659 return this.config[index].id;
5663 * Returns the column for a specified id.
5664 * @param {String} id The column id
5665 * @return {Object} the column
5667 getColumnById : function(id){
5668 return this.lookup[id];
5673 * Returns the column for a specified dataIndex.
5674 * @param {String} dataIndex The column dataIndex
5675 * @return {Object|Boolean} the column or false if not found
5677 getColumnByDataIndex: function(dataIndex){
5678 var index = this.findColumnIndex(dataIndex);
5679 return index > -1 ? this.config[index] : false;
5683 * Returns the index for a specified column id.
5684 * @param {String} id The column id
5685 * @return {Number} the index, or -1 if not found
5687 getIndexById : function(id){
5688 for(var i = 0, len = this.config.length; i < len; i++){
5689 if(this.config[i].id == id){
5697 * Returns the index for a specified column dataIndex.
5698 * @param {String} dataIndex The column dataIndex
5699 * @return {Number} the index, or -1 if not found
5702 findColumnIndex : function(dataIndex){
5703 for(var i = 0, len = this.config.length; i < len; i++){
5704 if(this.config[i].dataIndex == dataIndex){
5712 moveColumn : function(oldIndex, newIndex){
5713 var c = this.config[oldIndex];
5714 this.config.splice(oldIndex, 1);
5715 this.config.splice(newIndex, 0, c);
5716 this.dataMap = null;
5717 this.fireEvent("columnmoved", this, oldIndex, newIndex);
5720 isLocked : function(colIndex){
5721 return this.config[colIndex].locked === true;
5724 setLocked : function(colIndex, value, suppressEvent){
5725 if(this.isLocked(colIndex) == value){
5728 this.config[colIndex].locked = value;
5730 this.fireEvent("columnlockchange", this, colIndex, value);
5734 getTotalLockedWidth : function(){
5736 for(var i = 0; i < this.config.length; i++){
5737 if(this.isLocked(i) && !this.isHidden(i)){
5738 this.totalWidth += this.getColumnWidth(i);
5744 getLockedCount : function(){
5745 for(var i = 0, len = this.config.length; i < len; i++){
5746 if(!this.isLocked(i)){
5751 return this.config.length;
5755 * Returns the number of columns.
5758 getColumnCount : function(visibleOnly){
5759 if(visibleOnly === true){
5761 for(var i = 0, len = this.config.length; i < len; i++){
5762 if(!this.isHidden(i)){
5768 return this.config.length;
5772 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
5773 * @param {Function} fn
5774 * @param {Object} scope (optional)
5775 * @return {Array} result
5777 getColumnsBy : function(fn, scope){
5779 for(var i = 0, len = this.config.length; i < len; i++){
5780 var c = this.config[i];
5781 if(fn.call(scope||this, c, i) === true){
5789 * Returns true if the specified column is sortable.
5790 * @param {Number} col The column index
5793 isSortable : function(col){
5794 if(typeof this.config[col].sortable == "undefined"){
5795 return this.defaultSortable;
5797 return this.config[col].sortable;
5801 * Returns the rendering (formatting) function defined for the column.
5802 * @param {Number} col The column index.
5803 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
5805 getRenderer : function(col){
5806 if(!this.config[col].renderer){
5807 return Roo.grid.ColumnModel.defaultRenderer;
5809 return this.config[col].renderer;
5813 * Sets the rendering (formatting) function for a column.
5814 * @param {Number} col The column index
5815 * @param {Function} fn The function to use to process the cell's raw data
5816 * to return HTML markup for the grid view. The render function is called with
5817 * the following parameters:<ul>
5818 * <li>Data value.</li>
5819 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
5820 * <li>css A CSS style string to apply to the table cell.</li>
5821 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
5822 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
5823 * <li>Row index</li>
5824 * <li>Column index</li>
5825 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
5827 setRenderer : function(col, fn){
5828 this.config[col].renderer = fn;
5832 * Returns the width for the specified column.
5833 * @param {Number} col The column index
5836 getColumnWidth : function(col){
5837 return this.config[col].width * 1 || this.defaultWidth;
5841 * Sets the width for a column.
5842 * @param {Number} col The column index
5843 * @param {Number} width The new width
5845 setColumnWidth : function(col, width, suppressEvent){
5846 this.config[col].width = width;
5847 this.totalWidth = null;
5849 this.fireEvent("widthchange", this, col, width);
5854 * Returns the total width of all columns.
5855 * @param {Boolean} includeHidden True to include hidden column widths
5858 getTotalWidth : function(includeHidden){
5859 if(!this.totalWidth){
5860 this.totalWidth = 0;
5861 for(var i = 0, len = this.config.length; i < len; i++){
5862 if(includeHidden || !this.isHidden(i)){
5863 this.totalWidth += this.getColumnWidth(i);
5867 return this.totalWidth;
5871 * Returns the header for the specified column.
5872 * @param {Number} col The column index
5875 getColumnHeader : function(col){
5876 return this.config[col].header;
5880 * Sets the header for a column.
5881 * @param {Number} col The column index
5882 * @param {String} header The new header
5884 setColumnHeader : function(col, header){
5885 this.config[col].header = header;
5886 this.fireEvent("headerchange", this, col, header);
5890 * Returns the tooltip for the specified column.
5891 * @param {Number} col The column index
5894 getColumnTooltip : function(col){
5895 return this.config[col].tooltip;
5898 * Sets the tooltip for a column.
5899 * @param {Number} col The column index
5900 * @param {String} tooltip The new tooltip
5902 setColumnTooltip : function(col, tooltip){
5903 this.config[col].tooltip = tooltip;
5907 * Returns the dataIndex for the specified column.
5908 * @param {Number} col The column index
5911 getDataIndex : function(col){
5912 return this.config[col].dataIndex;
5916 * Sets the dataIndex for a column.
5917 * @param {Number} col The column index
5918 * @param {Number} dataIndex The new dataIndex
5920 setDataIndex : function(col, dataIndex){
5921 this.config[col].dataIndex = dataIndex;
5927 * Returns true if the cell is editable.
5928 * @param {Number} colIndex The column index
5929 * @param {Number} rowIndex The row index - this is nto actually used..?
5932 isCellEditable : function(colIndex, rowIndex){
5933 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
5937 * Returns the editor defined for the cell/column.
5938 * return false or null to disable editing.
5939 * @param {Number} colIndex The column index
5940 * @param {Number} rowIndex The row index
5943 getCellEditor : function(colIndex, rowIndex){
5944 return this.config[colIndex].editor;
5948 * Sets if a column is editable.
5949 * @param {Number} col The column index
5950 * @param {Boolean} editable True if the column is editable
5952 setEditable : function(col, editable){
5953 this.config[col].editable = editable;
5958 * Returns true if the column is hidden.
5959 * @param {Number} colIndex The column index
5962 isHidden : function(colIndex){
5963 return this.config[colIndex].hidden;
5968 * Returns true if the column width cannot be changed
5970 isFixed : function(colIndex){
5971 return this.config[colIndex].fixed;
5975 * Returns true if the column can be resized
5978 isResizable : function(colIndex){
5979 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
5982 * Sets if a column is hidden.
5983 * @param {Number} colIndex The column index
5984 * @param {Boolean} hidden True if the column is hidden
5986 setHidden : function(colIndex, hidden){
5987 this.config[colIndex].hidden = hidden;
5988 this.totalWidth = null;
5989 this.fireEvent("hiddenchange", this, colIndex, hidden);
5993 * Sets the editor for a column.
5994 * @param {Number} col The column index
5995 * @param {Object} editor The editor object
5997 setEditor : function(col, editor){
5998 this.config[col].editor = editor;
6002 Roo.grid.ColumnModel.defaultRenderer = function(value)
6004 if(typeof value == "object") {
6007 if(typeof value == "string" && value.length < 1){
6011 return String.format("{0}", value);
6014 // Alias for backwards compatibility
6015 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
6018 * Ext JS Library 1.1.1
6019 * Copyright(c) 2006-2007, Ext JS, LLC.
6021 * Originally Released Under LGPL - original licence link has changed is not relivant.
6024 * <script type="text/javascript">
6028 * @class Roo.LoadMask
6029 * A simple utility class for generically masking elements while loading data. If the element being masked has
6030 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
6031 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
6032 * element's UpdateManager load indicator and will be destroyed after the initial load.
6034 * Create a new LoadMask
6035 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
6036 * @param {Object} config The config object
6038 Roo.LoadMask = function(el, config){
6039 this.el = Roo.get(el);
6040 Roo.apply(this, config);
6042 this.store.on('beforeload', this.onBeforeLoad, this);
6043 this.store.on('load', this.onLoad, this);
6044 this.store.on('loadexception', this.onLoadException, this);
6045 this.removeMask = false;
6047 var um = this.el.getUpdateManager();
6048 um.showLoadIndicator = false; // disable the default indicator
6049 um.on('beforeupdate', this.onBeforeLoad, this);
6050 um.on('update', this.onLoad, this);
6051 um.on('failure', this.onLoad, this);
6052 this.removeMask = true;
6056 Roo.LoadMask.prototype = {
6058 * @cfg {Boolean} removeMask
6059 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
6060 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
6064 * The text to display in a centered loading message box (defaults to 'Loading...')
6068 * @cfg {String} msgCls
6069 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
6071 msgCls : 'x-mask-loading',
6074 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
6080 * Disables the mask to prevent it from being displayed
6082 disable : function(){
6083 this.disabled = true;
6087 * Enables the mask so that it can be displayed
6089 enable : function(){
6090 this.disabled = false;
6093 onLoadException : function()
6097 if (typeof(arguments[3]) != 'undefined') {
6098 Roo.MessageBox.alert("Error loading",arguments[3]);
6102 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
6103 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
6110 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
6115 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
6119 onBeforeLoad : function(){
6121 (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
6126 destroy : function(){
6128 this.store.un('beforeload', this.onBeforeLoad, this);
6129 this.store.un('load', this.onLoad, this);
6130 this.store.un('loadexception', this.onLoadException, this);
6132 var um = this.el.getUpdateManager();
6133 um.un('beforeupdate', this.onBeforeLoad, this);
6134 um.un('update', this.onLoad, this);
6135 um.un('failure', this.onLoad, this);
6146 * @class Roo.bootstrap.Table
6147 * @extends Roo.bootstrap.Component
6148 * Bootstrap Table class
6149 * @cfg {String} cls table class
6150 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
6151 * @cfg {String} bgcolor Specifies the background color for a table
6152 * @cfg {Number} border Specifies whether the table cells should have borders or not
6153 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
6154 * @cfg {Number} cellspacing Specifies the space between cells
6155 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
6156 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
6157 * @cfg {String} sortable Specifies that the table should be sortable
6158 * @cfg {String} summary Specifies a summary of the content of a table
6159 * @cfg {Number} width Specifies the width of a table
6160 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
6162 * @cfg {boolean} striped Should the rows be alternative striped
6163 * @cfg {boolean} bordered Add borders to the table
6164 * @cfg {boolean} hover Add hover highlighting
6165 * @cfg {boolean} condensed Format condensed
6166 * @cfg {boolean} responsive Format condensed
6167 * @cfg {Boolean} loadMask (true|false) default false
6168 * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
6169 * @cfg {Boolean} headerShow (true|false) generate thead, default true
6170 * @cfg {Boolean} rowSelection (true|false) default false
6171 * @cfg {Boolean} cellSelection (true|false) default false
6172 * @cfg {Boolean} scrollBody (true|false) default false - body scrolled / fixed header
6173 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
6174 * @cfg {Boolean} lazyLoad auto load data while scrolling to the end (default false)
6175 * @cfg {Boolean} auto_hide_footer auto hide footer if only one page (default false)
6179 * Create a new Table
6180 * @param {Object} config The config object
6183 Roo.bootstrap.Table = function(config){
6184 Roo.bootstrap.Table.superclass.constructor.call(this, config);
6189 this.rowSelection = (typeof(config.rowSelection) != 'undefined') ? config.rowSelection : this.rowSelection;
6190 this.cellSelection = (typeof(config.cellSelection) != 'undefined') ? config.cellSelection : this.cellSelection;
6191 this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
6192 this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
6194 this.sm = this.sm || {xtype: 'RowSelectionModel'};
6196 this.sm.grid = this;
6197 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
6198 this.sm = this.selModel;
6199 this.sm.xmodule = this.xmodule || false;
6202 if (this.cm && typeof(this.cm.config) == 'undefined') {
6203 this.colModel = new Roo.grid.ColumnModel(this.cm);
6204 this.cm = this.colModel;
6205 this.cm.xmodule = this.xmodule || false;
6208 this.store= Roo.factory(this.store, Roo.data);
6209 this.ds = this.store;
6210 this.ds.xmodule = this.xmodule || false;
6213 if (this.footer && this.store) {
6214 this.footer.dataSource = this.ds;
6215 this.footer = Roo.factory(this.footer);
6222 * Fires when a cell is clicked
6223 * @param {Roo.bootstrap.Table} this
6224 * @param {Roo.Element} el
6225 * @param {Number} rowIndex
6226 * @param {Number} columnIndex
6227 * @param {Roo.EventObject} e
6231 * @event celldblclick
6232 * Fires when a cell is double clicked
6233 * @param {Roo.bootstrap.Table} this
6234 * @param {Roo.Element} el
6235 * @param {Number} rowIndex
6236 * @param {Number} columnIndex
6237 * @param {Roo.EventObject} e
6239 "celldblclick" : true,
6242 * Fires when a row is clicked
6243 * @param {Roo.bootstrap.Table} this
6244 * @param {Roo.Element} el
6245 * @param {Number} rowIndex
6246 * @param {Roo.EventObject} e
6250 * @event rowdblclick
6251 * Fires when a row is double clicked
6252 * @param {Roo.bootstrap.Table} this
6253 * @param {Roo.Element} el
6254 * @param {Number} rowIndex
6255 * @param {Roo.EventObject} e
6257 "rowdblclick" : true,
6260 * Fires when a mouseover occur
6261 * @param {Roo.bootstrap.Table} this
6262 * @param {Roo.Element} el
6263 * @param {Number} rowIndex
6264 * @param {Number} columnIndex
6265 * @param {Roo.EventObject} e
6270 * Fires when a mouseout occur
6271 * @param {Roo.bootstrap.Table} this
6272 * @param {Roo.Element} el
6273 * @param {Number} rowIndex
6274 * @param {Number} columnIndex
6275 * @param {Roo.EventObject} e
6280 * Fires when a row is rendered, so you can change add a style to it.
6281 * @param {Roo.bootstrap.Table} this
6282 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
6286 * @event rowsrendered
6287 * Fires when all the rows have been rendered
6288 * @param {Roo.bootstrap.Table} this
6290 'rowsrendered' : true,
6292 * @event contextmenu
6293 * The raw contextmenu event for the entire grid.
6294 * @param {Roo.EventObject} e
6296 "contextmenu" : true,
6298 * @event rowcontextmenu
6299 * Fires when a row is right clicked
6300 * @param {Roo.bootstrap.Table} this
6301 * @param {Number} rowIndex
6302 * @param {Roo.EventObject} e
6304 "rowcontextmenu" : true,
6306 * @event cellcontextmenu
6307 * Fires when a cell is right clicked
6308 * @param {Roo.bootstrap.Table} this
6309 * @param {Number} rowIndex
6310 * @param {Number} cellIndex
6311 * @param {Roo.EventObject} e
6313 "cellcontextmenu" : true,
6315 * @event headercontextmenu
6316 * Fires when a header is right clicked
6317 * @param {Roo.bootstrap.Table} this
6318 * @param {Number} columnIndex
6319 * @param {Roo.EventObject} e
6321 "headercontextmenu" : true
6325 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
6351 rowSelection : false,
6352 cellSelection : false,
6355 // Roo.Element - the tbody
6357 // Roo.Element - thead element
6360 container: false, // used by gridpanel...
6366 auto_hide_footer : false,
6368 getAutoCreate : function()
6370 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
6377 if (this.scrollBody) {
6378 cfg.cls += ' table-body-fixed';
6381 cfg.cls += ' table-striped';
6385 cfg.cls += ' table-hover';
6387 if (this.bordered) {
6388 cfg.cls += ' table-bordered';
6390 if (this.condensed) {
6391 cfg.cls += ' table-condensed';
6393 if (this.responsive) {
6394 cfg.cls += ' table-responsive';
6398 cfg.cls+= ' ' +this.cls;
6401 // this lot should be simplifed...
6414 ].forEach(function(k) {
6422 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
6425 if(this.store || this.cm){
6426 if(this.headerShow){
6427 cfg.cn.push(this.renderHeader());
6430 cfg.cn.push(this.renderBody());
6432 if(this.footerShow){
6433 cfg.cn.push(this.renderFooter());
6435 // where does this come from?
6436 //cfg.cls+= ' TableGrid';
6439 return { cn : [ cfg ] };
6442 initEvents : function()
6444 if(!this.store || !this.cm){
6447 if (this.selModel) {
6448 this.selModel.initEvents();
6452 //Roo.log('initEvents with ds!!!!');
6454 this.mainBody = this.el.select('tbody', true).first();
6455 this.mainHead = this.el.select('thead', true).first();
6456 this.mainFoot = this.el.select('tfoot', true).first();
6462 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6463 e.on('click', _this.sort, _this);
6466 this.mainBody.on("click", this.onClick, this);
6467 this.mainBody.on("dblclick", this.onDblClick, this);
6469 // why is this done????? = it breaks dialogs??
6470 //this.parent().el.setStyle('position', 'relative');
6474 this.footer.parentId = this.id;
6475 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
6478 this.el.select('tfoot tr td').first().addClass('hide');
6483 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
6486 this.store.on('load', this.onLoad, this);
6487 this.store.on('beforeload', this.onBeforeLoad, this);
6488 this.store.on('update', this.onUpdate, this);
6489 this.store.on('add', this.onAdd, this);
6490 this.store.on("clear", this.clear, this);
6492 this.el.on("contextmenu", this.onContextMenu, this);
6494 this.mainBody.on('scroll', this.onBodyScroll, this);
6496 this.cm.on("headerchange", this.onHeaderChange, this);
6498 this.cm.on("hiddenchange", this.onHiddenChange, this, arguments);
6502 onContextMenu : function(e, t)
6504 this.processEvent("contextmenu", e);
6507 processEvent : function(name, e)
6509 if (name != 'touchstart' ) {
6510 this.fireEvent(name, e);
6513 var t = e.getTarget();
6515 var cell = Roo.get(t);
6521 if(cell.findParent('tfoot', false, true)){
6525 if(cell.findParent('thead', false, true)){
6527 if(e.getTarget().nodeName.toLowerCase() != 'th'){
6528 cell = Roo.get(t).findParent('th', false, true);
6530 Roo.log("failed to find th in thead?");
6531 Roo.log(e.getTarget());
6536 var cellIndex = cell.dom.cellIndex;
6538 var ename = name == 'touchstart' ? 'click' : name;
6539 this.fireEvent("header" + ename, this, cellIndex, e);
6544 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6545 cell = Roo.get(t).findParent('td', false, true);
6547 Roo.log("failed to find th in tbody?");
6548 Roo.log(e.getTarget());
6553 var row = cell.findParent('tr', false, true);
6554 var cellIndex = cell.dom.cellIndex;
6555 var rowIndex = row.dom.rowIndex - 1;
6559 this.fireEvent("row" + name, this, rowIndex, e);
6563 this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
6569 onMouseover : function(e, el)
6571 var cell = Roo.get(el);
6577 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6578 cell = cell.findParent('td', false, true);
6581 var row = cell.findParent('tr', false, true);
6582 var cellIndex = cell.dom.cellIndex;
6583 var rowIndex = row.dom.rowIndex - 1; // start from 0
6585 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
6589 onMouseout : function(e, el)
6591 var cell = Roo.get(el);
6597 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6598 cell = cell.findParent('td', false, true);
6601 var row = cell.findParent('tr', false, true);
6602 var cellIndex = cell.dom.cellIndex;
6603 var rowIndex = row.dom.rowIndex - 1; // start from 0
6605 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
6609 onClick : function(e, el)
6611 var cell = Roo.get(el);
6613 if(!cell || (!this.cellSelection && !this.rowSelection)){
6617 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6618 cell = cell.findParent('td', false, true);
6621 if(!cell || typeof(cell) == 'undefined'){
6625 var row = cell.findParent('tr', false, true);
6627 if(!row || typeof(row) == 'undefined'){
6631 var cellIndex = cell.dom.cellIndex;
6632 var rowIndex = this.getRowIndex(row);
6634 // why??? - should these not be based on SelectionModel?
6635 if(this.cellSelection){
6636 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
6639 if(this.rowSelection){
6640 this.fireEvent('rowclick', this, row, rowIndex, e);
6646 onDblClick : function(e,el)
6648 var cell = Roo.get(el);
6650 if(!cell || (!this.cellSelection && !this.rowSelection)){
6654 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6655 cell = cell.findParent('td', false, true);
6658 if(!cell || typeof(cell) == 'undefined'){
6662 var row = cell.findParent('tr', false, true);
6664 if(!row || typeof(row) == 'undefined'){
6668 var cellIndex = cell.dom.cellIndex;
6669 var rowIndex = this.getRowIndex(row);
6671 if(this.cellSelection){
6672 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
6675 if(this.rowSelection){
6676 this.fireEvent('rowdblclick', this, row, rowIndex, e);
6680 sort : function(e,el)
6682 var col = Roo.get(el);
6684 if(!col.hasClass('sortable')){
6688 var sort = col.attr('sort');
6691 if(col.select('i', true).first().hasClass('glyphicon-arrow-up')){
6695 this.store.sortInfo = {field : sort, direction : dir};
6698 Roo.log("calling footer first");
6699 this.footer.onClick('first');
6702 this.store.load({ params : { start : 0 } });
6706 renderHeader : function()
6714 this.totalWidth = 0;
6716 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6718 var config = cm.config[i];
6722 cls : 'x-hcol-' + i,
6724 html: cm.getColumnHeader(i)
6729 if(typeof(config.sortable) != 'undefined' && config.sortable){
6731 c.html = '<i class="glyphicon"></i>' + c.html;
6734 if(typeof(config.lgHeader) != 'undefined'){
6735 hh += '<span class="hidden-xs hidden-sm hidden-md">' + config.lgHeader + '</span>';
6738 if(typeof(config.mdHeader) != 'undefined'){
6739 hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
6742 if(typeof(config.smHeader) != 'undefined'){
6743 hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
6746 if(typeof(config.xsHeader) != 'undefined'){
6747 hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
6754 if(typeof(config.tooltip) != 'undefined'){
6755 c.tooltip = config.tooltip;
6758 if(typeof(config.colspan) != 'undefined'){
6759 c.colspan = config.colspan;
6762 if(typeof(config.hidden) != 'undefined' && config.hidden){
6763 c.style += ' display:none;';
6766 if(typeof(config.dataIndex) != 'undefined'){
6767 c.sort = config.dataIndex;
6772 if(typeof(config.align) != 'undefined' && config.align.length){
6773 c.style += ' text-align:' + config.align + ';';
6776 if(typeof(config.width) != 'undefined'){
6777 c.style += ' width:' + config.width + 'px;';
6778 this.totalWidth += config.width;
6780 this.totalWidth += 100; // assume minimum of 100 per column?
6783 if(typeof(config.cls) != 'undefined'){
6784 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
6787 ['xs','sm','md','lg'].map(function(size){
6789 if(typeof(config[size]) == 'undefined'){
6793 if (!config[size]) { // 0 = hidden
6794 c.cls += ' hidden-' + size;
6798 c.cls += ' col-' + size + '-' + config[size];
6808 renderBody : function()
6818 colspan : this.cm.getColumnCount()
6828 renderFooter : function()
6838 colspan : this.cm.getColumnCount()
6852 // Roo.log('ds onload');
6857 var ds = this.store;
6859 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6860 e.select('i', true).removeClass(['glyphicon-arrow-up', 'glyphicon-arrow-down']);
6861 if (_this.store.sortInfo) {
6863 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
6864 e.select('i', true).addClass(['glyphicon-arrow-up']);
6867 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
6868 e.select('i', true).addClass(['glyphicon-arrow-down']);
6873 var tbody = this.mainBody;
6875 if(ds.getCount() > 0){
6876 ds.data.each(function(d,rowIndex){
6877 var row = this.renderRow(cm, ds, rowIndex);
6879 tbody.createChild(row);
6883 if(row.cellObjects.length){
6884 Roo.each(row.cellObjects, function(r){
6885 _this.renderCellObject(r);
6892 var tfoot = this.el.select('tfoot', true).first();
6894 if(this.footerShow && this.auto_hide_footer && this.mainFoot){
6896 this.mainFoot.setVisibilityMode(Roo.Element.DISPLAY).hide();
6898 var total = this.ds.getTotalCount();
6900 if(this.footer.pageSize < total){
6901 this.mainFoot.show();
6905 Roo.each(this.el.select('tbody td', true).elements, function(e){
6906 e.on('mouseover', _this.onMouseover, _this);
6909 Roo.each(this.el.select('tbody td', true).elements, function(e){
6910 e.on('mouseout', _this.onMouseout, _this);
6912 this.fireEvent('rowsrendered', this);
6918 onUpdate : function(ds,record)
6920 this.refreshRow(record);
6924 onRemove : function(ds, record, index, isUpdate){
6925 if(isUpdate !== true){
6926 this.fireEvent("beforerowremoved", this, index, record);
6928 var bt = this.mainBody.dom;
6930 var rows = this.el.select('tbody > tr', true).elements;
6932 if(typeof(rows[index]) != 'undefined'){
6933 bt.removeChild(rows[index].dom);
6936 // if(bt.rows[index]){
6937 // bt.removeChild(bt.rows[index]);
6940 if(isUpdate !== true){
6941 //this.stripeRows(index);
6942 //this.syncRowHeights(index, index);
6944 this.fireEvent("rowremoved", this, index, record);
6948 onAdd : function(ds, records, rowIndex)
6950 //Roo.log('on Add called');
6951 // - note this does not handle multiple adding very well..
6952 var bt = this.mainBody.dom;
6953 for (var i =0 ; i < records.length;i++) {
6954 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
6955 //Roo.log(records[i]);
6956 //Roo.log(this.store.getAt(rowIndex+i));
6957 this.insertRow(this.store, rowIndex + i, false);
6964 refreshRow : function(record){
6965 var ds = this.store, index;
6966 if(typeof record == 'number'){
6968 record = ds.getAt(index);
6970 index = ds.indexOf(record);
6972 this.insertRow(ds, index, true);
6974 this.onRemove(ds, record, index+1, true);
6976 //this.syncRowHeights(index, index);
6978 this.fireEvent("rowupdated", this, index, record);
6981 insertRow : function(dm, rowIndex, isUpdate){
6984 this.fireEvent("beforerowsinserted", this, rowIndex);
6986 //var s = this.getScrollState();
6987 var row = this.renderRow(this.cm, this.store, rowIndex);
6988 // insert before rowIndex..
6989 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
6993 if(row.cellObjects.length){
6994 Roo.each(row.cellObjects, function(r){
6995 _this.renderCellObject(r);
7000 this.fireEvent("rowsinserted", this, rowIndex);
7001 //this.syncRowHeights(firstRow, lastRow);
7002 //this.stripeRows(firstRow);
7009 getRowDom : function(rowIndex)
7011 var rows = this.el.select('tbody > tr', true).elements;
7013 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
7016 // returns the object tree for a tr..
7019 renderRow : function(cm, ds, rowIndex)
7021 var d = ds.getAt(rowIndex);
7025 cls : 'x-row-' + rowIndex,
7029 var cellObjects = [];
7031 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
7032 var config = cm.config[i];
7034 var renderer = cm.getRenderer(i);
7038 if(typeof(renderer) !== 'undefined'){
7039 value = renderer(d.data[cm.getDataIndex(i)], false, d);
7041 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
7042 // and are rendered into the cells after the row is rendered - using the id for the element.
7044 if(typeof(value) === 'object'){
7054 rowIndex : rowIndex,
7059 this.fireEvent('rowclass', this, rowcfg);
7063 cls : rowcfg.rowClass + ' x-col-' + i,
7065 html: (typeof(value) === 'object') ? '' : value
7072 if(typeof(config.colspan) != 'undefined'){
7073 td.colspan = config.colspan;
7076 if(typeof(config.hidden) != 'undefined' && config.hidden){
7077 td.style += ' display:none;';
7080 if(typeof(config.align) != 'undefined' && config.align.length){
7081 td.style += ' text-align:' + config.align + ';';
7083 if(typeof(config.valign) != 'undefined' && config.valign.length){
7084 td.style += ' vertical-align:' + config.valign + ';';
7087 if(typeof(config.width) != 'undefined'){
7088 td.style += ' width:' + config.width + 'px;';
7091 if(typeof(config.cursor) != 'undefined'){
7092 td.style += ' cursor:' + config.cursor + ';';
7095 if(typeof(config.cls) != 'undefined'){
7096 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
7099 ['xs','sm','md','lg'].map(function(size){
7101 if(typeof(config[size]) == 'undefined'){
7105 if (!config[size]) { // 0 = hidden
7106 td.cls += ' hidden-' + size;
7110 td.cls += ' col-' + size + '-' + config[size];
7118 row.cellObjects = cellObjects;
7126 onBeforeLoad : function()
7135 this.el.select('tbody', true).first().dom.innerHTML = '';
7138 * Show or hide a row.
7139 * @param {Number} rowIndex to show or hide
7140 * @param {Boolean} state hide
7142 setRowVisibility : function(rowIndex, state)
7144 var bt = this.mainBody.dom;
7146 var rows = this.el.select('tbody > tr', true).elements;
7148 if(typeof(rows[rowIndex]) == 'undefined'){
7151 rows[rowIndex].dom.style.display = state ? '' : 'none';
7155 getSelectionModel : function(){
7157 this.selModel = new Roo.bootstrap.Table.RowSelectionModel({grid: this});
7159 return this.selModel;
7162 * Render the Roo.bootstrap object from renderder
7164 renderCellObject : function(r)
7168 r.cfg.parentId = (typeof(r.container) == 'string') ? r.container : r.container.id;
7170 var t = r.cfg.render(r.container);
7173 Roo.each(r.cfg.cn, function(c){
7175 container: t.getChildContainer(),
7178 _this.renderCellObject(child);
7183 getRowIndex : function(row)
7187 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
7198 * Returns the grid's underlying element = used by panel.Grid
7199 * @return {Element} The element
7201 getGridEl : function(){
7205 * Forces a resize - used by panel.Grid
7206 * @return {Element} The element
7208 autoSize : function()
7210 //var ctr = Roo.get(this.container.dom.parentElement);
7211 var ctr = Roo.get(this.el.dom);
7213 var thd = this.getGridEl().select('thead',true).first();
7214 var tbd = this.getGridEl().select('tbody', true).first();
7215 var tfd = this.getGridEl().select('tfoot', true).first();
7217 var cw = ctr.getWidth();
7221 tbd.setSize(ctr.getWidth(),
7222 ctr.getHeight() - ((thd ? thd.getHeight() : 0) + (tfd ? tfd.getHeight() : 0))
7224 var barsize = (tbd.dom.offsetWidth - tbd.dom.clientWidth);
7227 cw = Math.max(cw, this.totalWidth);
7228 this.getGridEl().select('tr',true).setWidth(cw);
7229 // resize 'expandable coloumn?
7231 return; // we doe not have a view in this design..
7234 onBodyScroll: function()
7236 //Roo.log("body scrolled');" + this.mainBody.dom.scrollLeft);
7238 this.mainHead.setStyle({
7239 'position' : 'relative',
7240 'left': (-1* this.mainBody.dom.scrollLeft) + 'px'
7246 var scrollHeight = this.mainBody.dom.scrollHeight;
7248 var scrollTop = Math.ceil(this.mainBody.getScroll().top);
7250 var height = this.mainBody.getHeight();
7252 if(scrollHeight - height == scrollTop) {
7254 var total = this.ds.getTotalCount();
7256 if(this.footer.cursor + this.footer.pageSize < total){
7258 this.footer.ds.load({
7260 start : this.footer.cursor + this.footer.pageSize,
7261 limit : this.footer.pageSize
7271 onHeaderChange : function()
7273 var header = this.renderHeader();
7274 var table = this.el.select('table', true).first();
7276 this.mainHead.remove();
7277 this.mainHead = table.createChild(header, this.mainBody, false);
7280 onHiddenChange : function(colModel, colIndex, hidden)
7282 var thSelector = '#' + this.id + ' .x-hcol-' + colIndex;
7283 var tdSelector = '#' + this.id + ' .x-col-' + colIndex;
7285 this.CSS.updateRule(thSelector, "display", "");
7286 this.CSS.updateRule(tdSelector, "display", "");
7289 this.CSS.updateRule(thSelector, "display", "none");
7290 this.CSS.updateRule(tdSelector, "display", "none");
7293 this.onHeaderChange();
7297 setColumnWidth: function(col_index, width)
7299 // width = "md-2 xs-2..."
7300 if(!this.colModel.config[col_index]) {
7304 var w = width.split(" ");
7306 var rows = this.el.dom.getElementsByClassName("x-col-"+col_index);
7308 var h_row = this.el.dom.getElementsByClassName("x-hcol-"+col_index);
7311 for(var j = 0; j < w.length; j++) {
7317 var size_cls = w[j].split("-");
7319 if(!Number.isInteger(size_cls[1] * 1)) {
7323 if(!this.colModel.config[col_index][size_cls[0]]) {
7327 if(!h_row[0].classList.contains("col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]])) {
7331 h_row[0].classList.replace(
7332 "col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]],
7333 "col-"+size_cls[0]+"-"+size_cls[1]
7336 for(var i = 0; i < rows.length; i++) {
7338 var size_cls = w[j].split("-");
7340 if(!Number.isInteger(size_cls[1] * 1)) {
7344 if(!this.colModel.config[col_index][size_cls[0]]) {
7348 if(!rows[i].classList.contains("col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]])) {
7352 rows[i].classList.replace(
7353 "col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]],
7354 "col-"+size_cls[0]+"-"+size_cls[1]
7358 this.colModel.config[col_index][size_cls[0]] = size_cls[1];
7373 * @class Roo.bootstrap.TableCell
7374 * @extends Roo.bootstrap.Component
7375 * Bootstrap TableCell class
7376 * @cfg {String} html cell contain text
7377 * @cfg {String} cls cell class
7378 * @cfg {String} tag cell tag (td|th) default td
7379 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
7380 * @cfg {String} align Aligns the content in a cell
7381 * @cfg {String} axis Categorizes cells
7382 * @cfg {String} bgcolor Specifies the background color of a cell
7383 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7384 * @cfg {Number} colspan Specifies the number of columns a cell should span
7385 * @cfg {String} headers Specifies one or more header cells a cell is related to
7386 * @cfg {Number} height Sets the height of a cell
7387 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
7388 * @cfg {Number} rowspan Sets the number of rows a cell should span
7389 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
7390 * @cfg {String} valign Vertical aligns the content in a cell
7391 * @cfg {Number} width Specifies the width of a cell
7394 * Create a new TableCell
7395 * @param {Object} config The config object
7398 Roo.bootstrap.TableCell = function(config){
7399 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
7402 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
7422 getAutoCreate : function(){
7423 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
7443 cfg.align=this.align
7449 cfg.bgcolor=this.bgcolor
7452 cfg.charoff=this.charoff
7455 cfg.colspan=this.colspan
7458 cfg.headers=this.headers
7461 cfg.height=this.height
7464 cfg.nowrap=this.nowrap
7467 cfg.rowspan=this.rowspan
7470 cfg.scope=this.scope
7473 cfg.valign=this.valign
7476 cfg.width=this.width
7495 * @class Roo.bootstrap.TableRow
7496 * @extends Roo.bootstrap.Component
7497 * Bootstrap TableRow class
7498 * @cfg {String} cls row class
7499 * @cfg {String} align Aligns the content in a table row
7500 * @cfg {String} bgcolor Specifies a background color for a table row
7501 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7502 * @cfg {String} valign Vertical aligns the content in a table row
7505 * Create a new TableRow
7506 * @param {Object} config The config object
7509 Roo.bootstrap.TableRow = function(config){
7510 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
7513 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
7521 getAutoCreate : function(){
7522 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
7532 cfg.align = this.align;
7535 cfg.bgcolor = this.bgcolor;
7538 cfg.charoff = this.charoff;
7541 cfg.valign = this.valign;
7559 * @class Roo.bootstrap.TableBody
7560 * @extends Roo.bootstrap.Component
7561 * Bootstrap TableBody class
7562 * @cfg {String} cls element class
7563 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
7564 * @cfg {String} align Aligns the content inside the element
7565 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
7566 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
7569 * Create a new TableBody
7570 * @param {Object} config The config object
7573 Roo.bootstrap.TableBody = function(config){
7574 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
7577 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
7585 getAutoCreate : function(){
7586 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
7600 cfg.align = this.align;
7603 cfg.charoff = this.charoff;
7606 cfg.valign = this.valign;
7613 // initEvents : function()
7620 // this.store = Roo.factory(this.store, Roo.data);
7621 // this.store.on('load', this.onLoad, this);
7623 // this.store.load();
7627 // onLoad: function ()
7629 // this.fireEvent('load', this);
7639 * Ext JS Library 1.1.1
7640 * Copyright(c) 2006-2007, Ext JS, LLC.
7642 * Originally Released Under LGPL - original licence link has changed is not relivant.
7645 * <script type="text/javascript">
7648 // as we use this in bootstrap.
7649 Roo.namespace('Roo.form');
7651 * @class Roo.form.Action
7652 * Internal Class used to handle form actions
7654 * @param {Roo.form.BasicForm} el The form element or its id
7655 * @param {Object} config Configuration options
7660 // define the action interface
7661 Roo.form.Action = function(form, options){
7663 this.options = options || {};
7666 * Client Validation Failed
7669 Roo.form.Action.CLIENT_INVALID = 'client';
7671 * Server Validation Failed
7674 Roo.form.Action.SERVER_INVALID = 'server';
7676 * Connect to Server Failed
7679 Roo.form.Action.CONNECT_FAILURE = 'connect';
7681 * Reading Data from Server Failed
7684 Roo.form.Action.LOAD_FAILURE = 'load';
7686 Roo.form.Action.prototype = {
7688 failureType : undefined,
7689 response : undefined,
7693 run : function(options){
7698 success : function(response){
7703 handleResponse : function(response){
7707 // default connection failure
7708 failure : function(response){
7710 this.response = response;
7711 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7712 this.form.afterAction(this, false);
7715 processResponse : function(response){
7716 this.response = response;
7717 if(!response.responseText){
7720 this.result = this.handleResponse(response);
7724 // utility functions used internally
7725 getUrl : function(appendParams){
7726 var url = this.options.url || this.form.url || this.form.el.dom.action;
7728 var p = this.getParams();
7730 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
7736 getMethod : function(){
7737 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
7740 getParams : function(){
7741 var bp = this.form.baseParams;
7742 var p = this.options.params;
7744 if(typeof p == "object"){
7745 p = Roo.urlEncode(Roo.applyIf(p, bp));
7746 }else if(typeof p == 'string' && bp){
7747 p += '&' + Roo.urlEncode(bp);
7750 p = Roo.urlEncode(bp);
7755 createCallback : function(){
7757 success: this.success,
7758 failure: this.failure,
7760 timeout: (this.form.timeout*1000),
7761 upload: this.form.fileUpload ? this.success : undefined
7766 Roo.form.Action.Submit = function(form, options){
7767 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
7770 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
7773 haveProgress : false,
7774 uploadComplete : false,
7776 // uploadProgress indicator.
7777 uploadProgress : function()
7779 if (!this.form.progressUrl) {
7783 if (!this.haveProgress) {
7784 Roo.MessageBox.progress("Uploading", "Uploading");
7786 if (this.uploadComplete) {
7787 Roo.MessageBox.hide();
7791 this.haveProgress = true;
7793 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
7795 var c = new Roo.data.Connection();
7797 url : this.form.progressUrl,
7802 success : function(req){
7803 //console.log(data);
7807 rdata = Roo.decode(req.responseText)
7809 Roo.log("Invalid data from server..");
7813 if (!rdata || !rdata.success) {
7815 Roo.MessageBox.alert(Roo.encode(rdata));
7818 var data = rdata.data;
7820 if (this.uploadComplete) {
7821 Roo.MessageBox.hide();
7826 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
7827 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
7830 this.uploadProgress.defer(2000,this);
7833 failure: function(data) {
7834 Roo.log('progress url failed ');
7845 // run get Values on the form, so it syncs any secondary forms.
7846 this.form.getValues();
7848 var o = this.options;
7849 var method = this.getMethod();
7850 var isPost = method == 'POST';
7851 if(o.clientValidation === false || this.form.isValid()){
7853 if (this.form.progressUrl) {
7854 this.form.findField('UPLOAD_IDENTIFIER').setValue(
7855 (new Date() * 1) + '' + Math.random());
7860 Roo.Ajax.request(Roo.apply(this.createCallback(), {
7861 form:this.form.el.dom,
7862 url:this.getUrl(!isPost),
7864 params:isPost ? this.getParams() : null,
7865 isUpload: this.form.fileUpload
7868 this.uploadProgress();
7870 }else if (o.clientValidation !== false){ // client validation failed
7871 this.failureType = Roo.form.Action.CLIENT_INVALID;
7872 this.form.afterAction(this, false);
7876 success : function(response)
7878 this.uploadComplete= true;
7879 if (this.haveProgress) {
7880 Roo.MessageBox.hide();
7884 var result = this.processResponse(response);
7885 if(result === true || result.success){
7886 this.form.afterAction(this, true);
7890 this.form.markInvalid(result.errors);
7891 this.failureType = Roo.form.Action.SERVER_INVALID;
7893 this.form.afterAction(this, false);
7895 failure : function(response)
7897 this.uploadComplete= true;
7898 if (this.haveProgress) {
7899 Roo.MessageBox.hide();
7902 this.response = response;
7903 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7904 this.form.afterAction(this, false);
7907 handleResponse : function(response){
7908 if(this.form.errorReader){
7909 var rs = this.form.errorReader.read(response);
7912 for(var i = 0, len = rs.records.length; i < len; i++) {
7913 var r = rs.records[i];
7917 if(errors.length < 1){
7921 success : rs.success,
7927 ret = Roo.decode(response.responseText);
7931 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
7941 Roo.form.Action.Load = function(form, options){
7942 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
7943 this.reader = this.form.reader;
7946 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
7951 Roo.Ajax.request(Roo.apply(
7952 this.createCallback(), {
7953 method:this.getMethod(),
7954 url:this.getUrl(false),
7955 params:this.getParams()
7959 success : function(response){
7961 var result = this.processResponse(response);
7962 if(result === true || !result.success || !result.data){
7963 this.failureType = Roo.form.Action.LOAD_FAILURE;
7964 this.form.afterAction(this, false);
7967 this.form.clearInvalid();
7968 this.form.setValues(result.data);
7969 this.form.afterAction(this, true);
7972 handleResponse : function(response){
7973 if(this.form.reader){
7974 var rs = this.form.reader.read(response);
7975 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
7977 success : rs.success,
7981 return Roo.decode(response.responseText);
7985 Roo.form.Action.ACTION_TYPES = {
7986 'load' : Roo.form.Action.Load,
7987 'submit' : Roo.form.Action.Submit
7996 * @class Roo.bootstrap.Form
7997 * @extends Roo.bootstrap.Component
7998 * Bootstrap Form class
7999 * @cfg {String} method GET | POST (default POST)
8000 * @cfg {String} labelAlign top | left (default top)
8001 * @cfg {String} align left | right - for navbars
8002 * @cfg {Boolean} loadMask load mask when submit (default true)
8007 * @param {Object} config The config object
8011 Roo.bootstrap.Form = function(config){
8013 Roo.bootstrap.Form.superclass.constructor.call(this, config);
8015 Roo.bootstrap.Form.popover.apply();
8019 * @event clientvalidation
8020 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
8021 * @param {Form} this
8022 * @param {Boolean} valid true if the form has passed client-side validation
8024 clientvalidation: true,
8026 * @event beforeaction
8027 * Fires before any action is performed. Return false to cancel the action.
8028 * @param {Form} this
8029 * @param {Action} action The action to be performed
8033 * @event actionfailed
8034 * Fires when an action fails.
8035 * @param {Form} this
8036 * @param {Action} action The action that failed
8038 actionfailed : true,
8040 * @event actioncomplete
8041 * Fires when an action is completed.
8042 * @param {Form} this
8043 * @param {Action} action The action that completed
8045 actioncomplete : true
8049 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
8052 * @cfg {String} method
8053 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
8058 * The URL to use for form actions if one isn't supplied in the action options.
8061 * @cfg {Boolean} fileUpload
8062 * Set to true if this form is a file upload.
8066 * @cfg {Object} baseParams
8067 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
8071 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
8075 * @cfg {Sting} align (left|right) for navbar forms
8080 activeAction : null,
8083 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
8084 * element by passing it or its id or mask the form itself by passing in true.
8087 waitMsgTarget : false,
8092 * @cfg {Boolean} errorMask (true|false) default false
8097 * @cfg {Number} maskOffset Default 100
8102 * @cfg {Boolean} maskBody
8106 getAutoCreate : function(){
8110 method : this.method || 'POST',
8111 id : this.id || Roo.id(),
8114 if (this.parent().xtype.match(/^Nav/)) {
8115 cfg.cls = 'navbar-form form-inline navbar-' + this.align;
8119 if (this.labelAlign == 'left' ) {
8120 cfg.cls += ' form-horizontal';
8126 initEvents : function()
8128 this.el.on('submit', this.onSubmit, this);
8129 // this was added as random key presses on the form where triggering form submit.
8130 this.el.on('keypress', function(e) {
8131 if (e.getCharCode() != 13) {
8134 // we might need to allow it for textareas.. and some other items.
8135 // check e.getTarget().
8137 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
8141 Roo.log("keypress blocked");
8149 onSubmit : function(e){
8154 * Returns true if client-side validation on the form is successful.
8157 isValid : function(){
8158 var items = this.getItems();
8162 items.each(function(f){
8168 Roo.log('invalid field: ' + f.name);
8172 if(!target && f.el.isVisible(true)){
8178 if(this.errorMask && !valid){
8179 Roo.bootstrap.Form.popover.mask(this, target);
8186 * Returns true if any fields in this form have changed since their original load.
8189 isDirty : function(){
8191 var items = this.getItems();
8192 items.each(function(f){
8202 * Performs a predefined action (submit or load) or custom actions you define on this form.
8203 * @param {String} actionName The name of the action type
8204 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
8205 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
8206 * accept other config options):
8208 Property Type Description
8209 ---------------- --------------- ----------------------------------------------------------------------------------
8210 url String The url for the action (defaults to the form's url)
8211 method String The form method to use (defaults to the form's method, or POST if not defined)
8212 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
8213 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
8214 validate the form on the client (defaults to false)
8216 * @return {BasicForm} this
8218 doAction : function(action, options){
8219 if(typeof action == 'string'){
8220 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
8222 if(this.fireEvent('beforeaction', this, action) !== false){
8223 this.beforeAction(action);
8224 action.run.defer(100, action);
8230 beforeAction : function(action){
8231 var o = action.options;
8236 Roo.get(document.body).mask(o.waitMsg || "Sending", 'x-mask-loading')
8238 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
8241 // not really supported yet.. ??
8243 //if(this.waitMsgTarget === true){
8244 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
8245 //}else if(this.waitMsgTarget){
8246 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
8247 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
8249 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
8255 afterAction : function(action, success){
8256 this.activeAction = null;
8257 var o = action.options;
8262 Roo.get(document.body).unmask();
8268 //if(this.waitMsgTarget === true){
8269 // this.el.unmask();
8270 //}else if(this.waitMsgTarget){
8271 // this.waitMsgTarget.unmask();
8273 // Roo.MessageBox.updateProgress(1);
8274 // Roo.MessageBox.hide();
8281 Roo.callback(o.success, o.scope, [this, action]);
8282 this.fireEvent('actioncomplete', this, action);
8286 // failure condition..
8287 // we have a scenario where updates need confirming.
8288 // eg. if a locking scenario exists..
8289 // we look for { errors : { needs_confirm : true }} in the response.
8291 (typeof(action.result) != 'undefined') &&
8292 (typeof(action.result.errors) != 'undefined') &&
8293 (typeof(action.result.errors.needs_confirm) != 'undefined')
8296 Roo.log("not supported yet");
8299 Roo.MessageBox.confirm(
8300 "Change requires confirmation",
8301 action.result.errorMsg,
8306 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
8316 Roo.callback(o.failure, o.scope, [this, action]);
8317 // show an error message if no failed handler is set..
8318 if (!this.hasListener('actionfailed')) {
8319 Roo.log("need to add dialog support");
8321 Roo.MessageBox.alert("Error",
8322 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
8323 action.result.errorMsg :
8324 "Saving Failed, please check your entries or try again"
8329 this.fireEvent('actionfailed', this, action);
8334 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
8335 * @param {String} id The value to search for
8338 findField : function(id){
8339 var items = this.getItems();
8340 var field = items.get(id);
8342 items.each(function(f){
8343 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
8350 return field || null;
8353 * Mark fields in this form invalid in bulk.
8354 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
8355 * @return {BasicForm} this
8357 markInvalid : function(errors){
8358 if(errors instanceof Array){
8359 for(var i = 0, len = errors.length; i < len; i++){
8360 var fieldError = errors[i];
8361 var f = this.findField(fieldError.id);
8363 f.markInvalid(fieldError.msg);
8369 if(typeof errors[id] != 'function' && (field = this.findField(id))){
8370 field.markInvalid(errors[id]);
8374 //Roo.each(this.childForms || [], function (f) {
8375 // f.markInvalid(errors);
8382 * Set values for fields in this form in bulk.
8383 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
8384 * @return {BasicForm} this
8386 setValues : function(values){
8387 if(values instanceof Array){ // array of objects
8388 for(var i = 0, len = values.length; i < len; i++){
8390 var f = this.findField(v.id);
8392 f.setValue(v.value);
8393 if(this.trackResetOnLoad){
8394 f.originalValue = f.getValue();
8398 }else{ // object hash
8401 if(typeof values[id] != 'function' && (field = this.findField(id))){
8403 if (field.setFromData &&
8405 field.displayField &&
8406 // combos' with local stores can
8407 // be queried via setValue()
8408 // to set their value..
8409 (field.store && !field.store.isLocal)
8413 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
8414 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
8415 field.setFromData(sd);
8417 } else if(field.setFromData && (field.store && !field.store.isLocal)) {
8419 field.setFromData(values);
8422 field.setValue(values[id]);
8426 if(this.trackResetOnLoad){
8427 field.originalValue = field.getValue();
8433 //Roo.each(this.childForms || [], function (f) {
8434 // f.setValues(values);
8441 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
8442 * they are returned as an array.
8443 * @param {Boolean} asString
8446 getValues : function(asString){
8447 //if (this.childForms) {
8448 // copy values from the child forms
8449 // Roo.each(this.childForms, function (f) {
8450 // this.setValues(f.getValues());
8456 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
8457 if(asString === true){
8460 return Roo.urlDecode(fs);
8464 * Returns the fields in this form as an object with key/value pairs.
8465 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
8468 getFieldValues : function(with_hidden)
8470 var items = this.getItems();
8472 items.each(function(f){
8478 var v = f.getValue();
8480 if (f.inputType =='radio') {
8481 if (typeof(ret[f.getName()]) == 'undefined') {
8482 ret[f.getName()] = ''; // empty..
8485 if (!f.el.dom.checked) {
8493 if(f.xtype == 'MoneyField'){
8494 ret[f.currencyName] = f.getCurrency();
8497 // not sure if this supported any more..
8498 if ((typeof(v) == 'object') && f.getRawValue) {
8499 v = f.getRawValue() ; // dates..
8501 // combo boxes where name != hiddenName...
8502 if (f.name !== false && f.name != '' && f.name != f.getName()) {
8503 ret[f.name] = f.getRawValue();
8505 ret[f.getName()] = v;
8512 * Clears all invalid messages in this form.
8513 * @return {BasicForm} this
8515 clearInvalid : function(){
8516 var items = this.getItems();
8518 items.each(function(f){
8527 * @return {BasicForm} this
8530 var items = this.getItems();
8531 items.each(function(f){
8535 Roo.each(this.childForms || [], function (f) {
8543 getItems : function()
8545 var r=new Roo.util.MixedCollection(false, function(o){
8546 return o.id || (o.id = Roo.id());
8548 var iter = function(el) {
8555 Roo.each(el.items,function(e) {
8564 hideFields : function(items)
8566 Roo.each(items, function(i){
8568 var f = this.findField(i);
8579 showFields : function(items)
8581 Roo.each(items, function(i){
8583 var f = this.findField(i);
8596 Roo.apply(Roo.bootstrap.Form, {
8623 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
8624 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
8625 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
8626 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
8629 this.maskEl.top.enableDisplayMode("block");
8630 this.maskEl.left.enableDisplayMode("block");
8631 this.maskEl.bottom.enableDisplayMode("block");
8632 this.maskEl.right.enableDisplayMode("block");
8634 this.toolTip = new Roo.bootstrap.Tooltip({
8635 cls : 'roo-form-error-popover',
8637 'left' : ['r-l', [-2,0], 'right'],
8638 'right' : ['l-r', [2,0], 'left'],
8639 'bottom' : ['tl-bl', [0,2], 'top'],
8640 'top' : [ 'bl-tl', [0,-2], 'bottom']
8644 this.toolTip.render(Roo.get(document.body));
8646 this.toolTip.el.enableDisplayMode("block");
8648 Roo.get(document.body).on('click', function(){
8652 Roo.get(document.body).on('touchstart', function(){
8656 this.isApplied = true
8659 mask : function(form, target)
8663 this.target = target;
8665 if(!this.form.errorMask || !target.el){
8669 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.modal', 100, true) || Roo.get(document.body);
8671 Roo.log(scrollable);
8673 var ot = this.target.el.calcOffsetsTo(scrollable);
8675 var scrollTo = ot[1] - this.form.maskOffset;
8677 scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
8679 scrollable.scrollTo('top', scrollTo);
8681 var box = this.target.el.getBox();
8683 var zIndex = Roo.bootstrap.Modal.zIndex++;
8686 this.maskEl.top.setStyle('position', 'absolute');
8687 this.maskEl.top.setStyle('z-index', zIndex);
8688 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
8689 this.maskEl.top.setLeft(0);
8690 this.maskEl.top.setTop(0);
8691 this.maskEl.top.show();
8693 this.maskEl.left.setStyle('position', 'absolute');
8694 this.maskEl.left.setStyle('z-index', zIndex);
8695 this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
8696 this.maskEl.left.setLeft(0);
8697 this.maskEl.left.setTop(box.y - this.padding);
8698 this.maskEl.left.show();
8700 this.maskEl.bottom.setStyle('position', 'absolute');
8701 this.maskEl.bottom.setStyle('z-index', zIndex);
8702 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
8703 this.maskEl.bottom.setLeft(0);
8704 this.maskEl.bottom.setTop(box.bottom + this.padding);
8705 this.maskEl.bottom.show();
8707 this.maskEl.right.setStyle('position', 'absolute');
8708 this.maskEl.right.setStyle('z-index', zIndex);
8709 this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
8710 this.maskEl.right.setLeft(box.right + this.padding);
8711 this.maskEl.right.setTop(box.y - this.padding);
8712 this.maskEl.right.show();
8714 this.toolTip.bindEl = this.target.el;
8716 this.toolTip.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
8718 var tip = this.target.blankText;
8720 if(this.target.getValue() !== '' ) {
8722 if (this.target.invalidText.length) {
8723 tip = this.target.invalidText;
8724 } else if (this.target.regexText.length){
8725 tip = this.target.regexText;
8729 this.toolTip.show(tip);
8731 this.intervalID = window.setInterval(function() {
8732 Roo.bootstrap.Form.popover.unmask();
8735 window.onwheel = function(){ return false;};
8737 (function(){ this.isMasked = true; }).defer(500, this);
8743 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
8747 this.maskEl.top.setStyle('position', 'absolute');
8748 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
8749 this.maskEl.top.hide();
8751 this.maskEl.left.setStyle('position', 'absolute');
8752 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
8753 this.maskEl.left.hide();
8755 this.maskEl.bottom.setStyle('position', 'absolute');
8756 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
8757 this.maskEl.bottom.hide();
8759 this.maskEl.right.setStyle('position', 'absolute');
8760 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
8761 this.maskEl.right.hide();
8763 this.toolTip.hide();
8765 this.toolTip.el.hide();
8767 window.onwheel = function(){ return true;};
8769 if(this.intervalID){
8770 window.clearInterval(this.intervalID);
8771 this.intervalID = false;
8774 this.isMasked = false;
8784 * Ext JS Library 1.1.1
8785 * Copyright(c) 2006-2007, Ext JS, LLC.
8787 * Originally Released Under LGPL - original licence link has changed is not relivant.
8790 * <script type="text/javascript">
8793 * @class Roo.form.VTypes
8794 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
8797 Roo.form.VTypes = function(){
8798 // closure these in so they are only created once.
8799 var alpha = /^[a-zA-Z_]+$/;
8800 var alphanum = /^[a-zA-Z0-9_]+$/;
8801 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
8802 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
8804 // All these messages and functions are configurable
8807 * The function used to validate email addresses
8808 * @param {String} value The email address
8810 'email' : function(v){
8811 return email.test(v);
8814 * The error text to display when the email validation function returns false
8817 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
8819 * The keystroke filter mask to be applied on email input
8822 'emailMask' : /[a-z0-9_\.\-@]/i,
8825 * The function used to validate URLs
8826 * @param {String} value The URL
8828 'url' : function(v){
8832 * The error text to display when the url validation function returns false
8835 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
8838 * The function used to validate alpha values
8839 * @param {String} value The value
8841 'alpha' : function(v){
8842 return alpha.test(v);
8845 * The error text to display when the alpha validation function returns false
8848 'alphaText' : 'This field should only contain letters and _',
8850 * The keystroke filter mask to be applied on alpha input
8853 'alphaMask' : /[a-z_]/i,
8856 * The function used to validate alphanumeric values
8857 * @param {String} value The value
8859 'alphanum' : function(v){
8860 return alphanum.test(v);
8863 * The error text to display when the alphanumeric validation function returns false
8866 'alphanumText' : 'This field should only contain letters, numbers and _',
8868 * The keystroke filter mask to be applied on alphanumeric input
8871 'alphanumMask' : /[a-z0-9_]/i
8881 * @class Roo.bootstrap.Input
8882 * @extends Roo.bootstrap.Component
8883 * Bootstrap Input class
8884 * @cfg {Boolean} disabled is it disabled
8885 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
8886 * @cfg {String} name name of the input
8887 * @cfg {string} fieldLabel - the label associated
8888 * @cfg {string} placeholder - placeholder to put in text.
8889 * @cfg {string} before - input group add on before
8890 * @cfg {string} after - input group add on after
8891 * @cfg {string} size - (lg|sm) or leave empty..
8892 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
8893 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
8894 * @cfg {Number} md colspan out of 12 for computer-sized screens
8895 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
8896 * @cfg {string} value default value of the input
8897 * @cfg {Number} labelWidth set the width of label
8898 * @cfg {Number} labellg set the width of label (1-12)
8899 * @cfg {Number} labelmd set the width of label (1-12)
8900 * @cfg {Number} labelsm set the width of label (1-12)
8901 * @cfg {Number} labelxs set the width of label (1-12)
8902 * @cfg {String} labelAlign (top|left)
8903 * @cfg {Boolean} readOnly Specifies that the field should be read-only
8904 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
8905 * @cfg {String} indicatorpos (left|right) default left
8906 * @cfg {String} capture (user|camera) use for file input only. (default empty)
8907 * @cfg {String} accept (image|video|audio) use for file input only. (default empty)
8909 * @cfg {String} align (left|center|right) Default left
8910 * @cfg {Boolean} forceFeedback (true|false) Default false
8913 * Create a new Input
8914 * @param {Object} config The config object
8917 Roo.bootstrap.Input = function(config){
8919 Roo.bootstrap.Input.superclass.constructor.call(this, config);
8924 * Fires when this field receives input focus.
8925 * @param {Roo.form.Field} this
8930 * Fires when this field loses input focus.
8931 * @param {Roo.form.Field} this
8936 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
8937 * {@link Roo.EventObject#getKey} to determine which key was pressed.
8938 * @param {Roo.form.Field} this
8939 * @param {Roo.EventObject} e The event object
8944 * Fires just before the field blurs if the field value has changed.
8945 * @param {Roo.form.Field} this
8946 * @param {Mixed} newValue The new value
8947 * @param {Mixed} oldValue The original value
8952 * Fires after the field has been marked as invalid.
8953 * @param {Roo.form.Field} this
8954 * @param {String} msg The validation message
8959 * Fires after the field has been validated with no errors.
8960 * @param {Roo.form.Field} this
8965 * Fires after the key up
8966 * @param {Roo.form.Field} this
8967 * @param {Roo.EventObject} e The event Object
8973 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
8975 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
8976 automatic validation (defaults to "keyup").
8978 validationEvent : "keyup",
8980 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
8982 validateOnBlur : true,
8984 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
8986 validationDelay : 250,
8988 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
8990 focusClass : "x-form-focus", // not needed???
8994 * @cfg {String} invalidClass DEPRICATED - code uses BS4 - is-valid / is-invalid
8996 invalidClass : "has-warning",
8999 * @cfg {String} validClass DEPRICATED - code uses BS4 - is-valid / is-invalid
9001 validClass : "has-success",
9004 * @cfg {Boolean} hasFeedback (true|false) default true
9009 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
9011 invalidFeedbackClass : "glyphicon-warning-sign",
9014 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
9016 validFeedbackClass : "glyphicon-ok",
9019 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
9021 selectOnFocus : false,
9024 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
9028 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
9033 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
9035 disableKeyFilter : false,
9038 * @cfg {Boolean} disabled True to disable the field (defaults to false).
9042 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
9046 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
9048 blankText : "Please complete this mandatory field",
9051 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
9055 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
9057 maxLength : Number.MAX_VALUE,
9059 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
9061 minLengthText : "The minimum length for this field is {0}",
9063 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
9065 maxLengthText : "The maximum length for this field is {0}",
9069 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
9070 * If available, this function will be called only after the basic validators all return true, and will be passed the
9071 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
9075 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
9076 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
9077 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
9081 * @cfg {String} regexText -- Depricated - use Invalid Text
9086 * @cfg {String} invalidText The error text to display if {@link #validator} test fails during validation (defaults to "")
9092 autocomplete: false,
9111 formatedValue : false,
9112 forceFeedback : false,
9114 indicatorpos : 'left',
9124 parentLabelAlign : function()
9127 while (parent.parent()) {
9128 parent = parent.parent();
9129 if (typeof(parent.labelAlign) !='undefined') {
9130 return parent.labelAlign;
9137 getAutoCreate : function()
9139 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9145 if(this.inputType != 'hidden'){
9146 cfg.cls = 'form-group' //input-group
9152 type : this.inputType,
9154 cls : 'form-control',
9155 placeholder : this.placeholder || '',
9156 autocomplete : this.autocomplete || 'new-password'
9159 if(this.capture.length){
9160 input.capture = this.capture;
9163 if(this.accept.length){
9164 input.accept = this.accept + "/*";
9168 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
9171 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9172 input.maxLength = this.maxLength;
9175 if (this.disabled) {
9176 input.disabled=true;
9179 if (this.readOnly) {
9180 input.readonly=true;
9184 input.name = this.name;
9188 input.cls += ' input-' + this.size;
9192 ['xs','sm','md','lg'].map(function(size){
9193 if (settings[size]) {
9194 cfg.cls += ' col-' + size + '-' + settings[size];
9198 var inputblock = input;
9202 cls: 'glyphicon form-control-feedback'
9205 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9208 cls : 'has-feedback',
9216 if (this.before || this.after) {
9219 cls : 'input-group',
9223 if (this.before && typeof(this.before) == 'string') {
9225 inputblock.cn.push({
9227 cls : 'roo-input-before input-group-addon input-group-prepend input-group-text',
9231 if (this.before && typeof(this.before) == 'object') {
9232 this.before = Roo.factory(this.before);
9234 inputblock.cn.push({
9236 cls : 'roo-input-before input-group-prepend input-group-text input-group-' +
9237 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
9241 inputblock.cn.push(input);
9243 if (this.after && typeof(this.after) == 'string') {
9244 inputblock.cn.push({
9246 cls : 'roo-input-after input-group-append input-group-text input-group-addon',
9250 if (this.after && typeof(this.after) == 'object') {
9251 this.after = Roo.factory(this.after);
9253 inputblock.cn.push({
9255 cls : 'roo-input-after input-group-append input-group-text input-group-' +
9256 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
9260 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9261 inputblock.cls += ' has-feedback';
9262 inputblock.cn.push(feedback);
9267 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
9268 tooltip : 'This field is required'
9270 if (Roo.bootstrap.version == 4) {
9273 style : 'display-none'
9276 if (align ==='left' && this.fieldLabel.length) {
9278 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
9285 cls : 'control-label col-form-label',
9286 html : this.fieldLabel
9297 var labelCfg = cfg.cn[1];
9298 var contentCfg = cfg.cn[2];
9300 if(this.indicatorpos == 'right'){
9305 cls : 'control-label col-form-label',
9309 html : this.fieldLabel
9323 labelCfg = cfg.cn[0];
9324 contentCfg = cfg.cn[1];
9328 if(this.labelWidth > 12){
9329 labelCfg.style = "width: " + this.labelWidth + 'px';
9332 if(this.labelWidth < 13 && this.labelmd == 0){
9333 this.labelmd = this.labelWidth;
9336 if(this.labellg > 0){
9337 labelCfg.cls += ' col-lg-' + this.labellg;
9338 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
9341 if(this.labelmd > 0){
9342 labelCfg.cls += ' col-md-' + this.labelmd;
9343 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
9346 if(this.labelsm > 0){
9347 labelCfg.cls += ' col-sm-' + this.labelsm;
9348 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
9351 if(this.labelxs > 0){
9352 labelCfg.cls += ' col-xs-' + this.labelxs;
9353 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
9357 } else if ( this.fieldLabel.length) {
9362 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
9363 tooltip : 'This field is required'
9367 //cls : 'input-group-addon',
9368 html : this.fieldLabel
9376 if(this.indicatorpos == 'right'){
9381 //cls : 'input-group-addon',
9382 html : this.fieldLabel
9387 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9388 tooltip : 'This field is required'
9408 if (this.parentType === 'Navbar' && this.parent().bar) {
9409 cfg.cls += ' navbar-form';
9412 if (this.parentType === 'NavGroup' && !(Roo.bootstrap.version == 4 && this.parent().form)) {
9413 // on BS4 we do this only if not form
9414 cfg.cls += ' navbar-form';
9422 * return the real input element.
9424 inputEl: function ()
9426 return this.el.select('input.form-control',true).first();
9429 tooltipEl : function()
9431 return this.inputEl();
9434 indicatorEl : function()
9436 if (Roo.bootstrap.version == 4) {
9437 return false; // not enabled in v4 yet.
9440 var indicator = this.el.select('i.roo-required-indicator',true).first();
9450 setDisabled : function(v)
9452 var i = this.inputEl().dom;
9454 i.removeAttribute('disabled');
9458 i.setAttribute('disabled','true');
9460 initEvents : function()
9463 this.inputEl().on("keydown" , this.fireKey, this);
9464 this.inputEl().on("focus", this.onFocus, this);
9465 this.inputEl().on("blur", this.onBlur, this);
9467 this.inputEl().relayEvent('keyup', this);
9469 this.indicator = this.indicatorEl();
9472 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible'); // changed from invisible??? -
9475 // reference to original value for reset
9476 this.originalValue = this.getValue();
9477 //Roo.form.TextField.superclass.initEvents.call(this);
9478 if(this.validationEvent == 'keyup'){
9479 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
9480 this.inputEl().on('keyup', this.filterValidation, this);
9482 else if(this.validationEvent !== false){
9483 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
9486 if(this.selectOnFocus){
9487 this.on("focus", this.preFocus, this);
9490 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
9491 this.inputEl().on("keypress", this.filterKeys, this);
9493 this.inputEl().relayEvent('keypress', this);
9496 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
9497 this.el.on("click", this.autoSize, this);
9500 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
9501 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
9504 if (typeof(this.before) == 'object') {
9505 this.before.render(this.el.select('.roo-input-before',true).first());
9507 if (typeof(this.after) == 'object') {
9508 this.after.render(this.el.select('.roo-input-after',true).first());
9511 this.inputEl().on('change', this.onChange, this);
9514 filterValidation : function(e){
9515 if(!e.isNavKeyPress()){
9516 this.validationTask.delay(this.validationDelay);
9520 * Validates the field value
9521 * @return {Boolean} True if the value is valid, else false
9523 validate : function(){
9524 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
9525 if(this.disabled || this.validateValue(this.getRawValue())){
9536 * Validates a value according to the field's validation rules and marks the field as invalid
9537 * if the validation fails
9538 * @param {Mixed} value The value to validate
9539 * @return {Boolean} True if the value is valid, else false
9541 validateValue : function(value)
9543 if(this.getVisibilityEl().hasClass('hidden')){
9547 if(value.length < 1) { // if it's blank
9548 if(this.allowBlank){
9554 if(value.length < this.minLength){
9557 if(value.length > this.maxLength){
9561 var vt = Roo.form.VTypes;
9562 if(!vt[this.vtype](value, this)){
9566 if(typeof this.validator == "function"){
9567 var msg = this.validator(value);
9571 if (typeof(msg) == 'string') {
9572 this.invalidText = msg;
9576 if(this.regex && !this.regex.test(value)){
9584 fireKey : function(e){
9585 //Roo.log('field ' + e.getKey());
9586 if(e.isNavKeyPress()){
9587 this.fireEvent("specialkey", this, e);
9590 focus : function (selectText){
9592 this.inputEl().focus();
9593 if(selectText === true){
9594 this.inputEl().dom.select();
9600 onFocus : function(){
9601 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9602 // this.el.addClass(this.focusClass);
9605 this.hasFocus = true;
9606 this.startValue = this.getValue();
9607 this.fireEvent("focus", this);
9611 beforeBlur : Roo.emptyFn,
9615 onBlur : function(){
9617 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9618 //this.el.removeClass(this.focusClass);
9620 this.hasFocus = false;
9621 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
9624 var v = this.getValue();
9625 if(String(v) !== String(this.startValue)){
9626 this.fireEvent('change', this, v, this.startValue);
9628 this.fireEvent("blur", this);
9631 onChange : function(e)
9633 var v = this.getValue();
9634 if(String(v) !== String(this.startValue)){
9635 this.fireEvent('change', this, v, this.startValue);
9641 * Resets the current field value to the originally loaded value and clears any validation messages
9644 this.setValue(this.originalValue);
9648 * Returns the name of the field
9649 * @return {Mixed} name The name field
9651 getName: function(){
9655 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
9656 * @return {Mixed} value The field value
9658 getValue : function(){
9660 var v = this.inputEl().getValue();
9665 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
9666 * @return {Mixed} value The field value
9668 getRawValue : function(){
9669 var v = this.inputEl().getValue();
9675 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
9676 * @param {Mixed} value The value to set
9678 setRawValue : function(v){
9679 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9682 selectText : function(start, end){
9683 var v = this.getRawValue();
9685 start = start === undefined ? 0 : start;
9686 end = end === undefined ? v.length : end;
9687 var d = this.inputEl().dom;
9688 if(d.setSelectionRange){
9689 d.setSelectionRange(start, end);
9690 }else if(d.createTextRange){
9691 var range = d.createTextRange();
9692 range.moveStart("character", start);
9693 range.moveEnd("character", v.length-end);
9700 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
9701 * @param {Mixed} value The value to set
9703 setValue : function(v){
9706 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9712 processValue : function(value){
9713 if(this.stripCharsRe){
9714 var newValue = value.replace(this.stripCharsRe, '');
9715 if(newValue !== value){
9716 this.setRawValue(newValue);
9723 preFocus : function(){
9725 if(this.selectOnFocus){
9726 this.inputEl().dom.select();
9729 filterKeys : function(e){
9731 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
9734 var c = e.getCharCode(), cc = String.fromCharCode(c);
9735 if(Roo.isIE && (e.isSpecialKey() || !cc)){
9738 if(!this.maskRe.test(cc)){
9743 * Clear any invalid styles/messages for this field
9745 clearInvalid : function(){
9747 if(!this.el || this.preventMark){ // not rendered
9752 this.el.removeClass([this.invalidClass, 'is-invalid']);
9754 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9756 var feedback = this.el.select('.form-control-feedback', true).first();
9759 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9765 this.indicator.removeClass('visible');
9766 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9769 this.fireEvent('valid', this);
9773 * Mark this field as valid
9775 markValid : function()
9777 if(!this.el || this.preventMark){ // not rendered...
9781 this.el.removeClass([this.invalidClass, this.validClass]);
9782 this.inputEl().removeClass(['is-valid', 'is-invalid']);
9784 var feedback = this.el.select('.form-control-feedback', true).first();
9787 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9791 this.indicator.removeClass('visible');
9792 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9799 if(this.allowBlank && !this.getRawValue().length){
9802 if (Roo.bootstrap.version == 3) {
9803 this.el.addClass(this.validClass);
9805 this.inputEl().addClass('is-valid');
9808 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9810 var feedback = this.el.select('.form-control-feedback', true).first();
9813 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9814 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9819 this.fireEvent('valid', this);
9823 * Mark this field as invalid
9824 * @param {String} msg The validation message
9826 markInvalid : function(msg)
9828 if(!this.el || this.preventMark){ // not rendered
9832 this.el.removeClass([this.invalidClass, this.validClass]);
9833 this.inputEl().removeClass(['is-valid', 'is-invalid']);
9835 var feedback = this.el.select('.form-control-feedback', true).first();
9838 this.el.select('.form-control-feedback', true).first().removeClass(
9839 [this.invalidFeedbackClass, this.validFeedbackClass]);
9846 if(this.allowBlank && !this.getRawValue().length){
9851 this.indicator.removeClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9852 this.indicator.addClass('visible');
9854 if (Roo.bootstrap.version == 3) {
9855 this.el.addClass(this.invalidClass);
9857 this.inputEl().addClass('is-invalid');
9862 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9864 var feedback = this.el.select('.form-control-feedback', true).first();
9867 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9869 if(this.getValue().length || this.forceFeedback){
9870 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9877 this.fireEvent('invalid', this, msg);
9880 SafariOnKeyDown : function(event)
9882 // this is a workaround for a password hang bug on chrome/ webkit.
9883 if (this.inputEl().dom.type != 'password') {
9887 var isSelectAll = false;
9889 if(this.inputEl().dom.selectionEnd > 0){
9890 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
9892 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
9893 event.preventDefault();
9898 if(isSelectAll && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
9900 event.preventDefault();
9901 // this is very hacky as keydown always get's upper case.
9903 var cc = String.fromCharCode(event.getCharCode());
9904 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
9908 adjustWidth : function(tag, w){
9909 tag = tag.toLowerCase();
9910 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
9911 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
9915 if(tag == 'textarea'){
9918 }else if(Roo.isOpera){
9922 if(tag == 'textarea'){
9930 setFieldLabel : function(v)
9936 if(this.indicatorEl()){
9937 var ar = this.el.select('label > span',true);
9939 if (ar.elements.length) {
9940 this.el.select('label > span',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9941 this.fieldLabel = v;
9945 var br = this.el.select('label',true);
9947 if(br.elements.length) {
9948 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9949 this.fieldLabel = v;
9953 Roo.log('Cannot Found any of label > span || label in input');
9957 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9958 this.fieldLabel = v;
9973 * @class Roo.bootstrap.TextArea
9974 * @extends Roo.bootstrap.Input
9975 * Bootstrap TextArea class
9976 * @cfg {Number} cols Specifies the visible width of a text area
9977 * @cfg {Number} rows Specifies the visible number of lines in a text area
9978 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
9979 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
9980 * @cfg {string} html text
9983 * Create a new TextArea
9984 * @param {Object} config The config object
9987 Roo.bootstrap.TextArea = function(config){
9988 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
9992 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
10002 getAutoCreate : function(){
10004 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
10010 if(this.inputType != 'hidden'){
10011 cfg.cls = 'form-group' //input-group
10019 value : this.value || '',
10020 html: this.html || '',
10021 cls : 'form-control',
10022 placeholder : this.placeholder || ''
10026 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
10027 input.maxLength = this.maxLength;
10031 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
10035 input.cols = this.cols;
10038 if (this.readOnly) {
10039 input.readonly = true;
10043 input.name = this.name;
10047 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
10051 ['xs','sm','md','lg'].map(function(size){
10052 if (settings[size]) {
10053 cfg.cls += ' col-' + size + '-' + settings[size];
10057 var inputblock = input;
10059 if(this.hasFeedback && !this.allowBlank){
10063 cls: 'glyphicon form-control-feedback'
10067 cls : 'has-feedback',
10076 if (this.before || this.after) {
10079 cls : 'input-group',
10083 inputblock.cn.push({
10085 cls : 'input-group-addon',
10090 inputblock.cn.push(input);
10092 if(this.hasFeedback && !this.allowBlank){
10093 inputblock.cls += ' has-feedback';
10094 inputblock.cn.push(feedback);
10098 inputblock.cn.push({
10100 cls : 'input-group-addon',
10107 if (align ==='left' && this.fieldLabel.length) {
10112 cls : 'control-label',
10113 html : this.fieldLabel
10124 if(this.labelWidth > 12){
10125 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
10128 if(this.labelWidth < 13 && this.labelmd == 0){
10129 this.labelmd = this.labelWidth;
10132 if(this.labellg > 0){
10133 cfg.cn[0].cls += ' col-lg-' + this.labellg;
10134 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
10137 if(this.labelmd > 0){
10138 cfg.cn[0].cls += ' col-md-' + this.labelmd;
10139 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
10142 if(this.labelsm > 0){
10143 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
10144 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
10147 if(this.labelxs > 0){
10148 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
10149 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
10152 } else if ( this.fieldLabel.length) {
10157 //cls : 'input-group-addon',
10158 html : this.fieldLabel
10176 if (this.disabled) {
10177 input.disabled=true;
10184 * return the real textarea element.
10186 inputEl: function ()
10188 return this.el.select('textarea.form-control',true).first();
10192 * Clear any invalid styles/messages for this field
10194 clearInvalid : function()
10197 if(!this.el || this.preventMark){ // not rendered
10201 var label = this.el.select('label', true).first();
10202 var icon = this.el.select('i.fa-star', true).first();
10207 this.el.removeClass( this.validClass);
10208 this.inputEl().removeClass('is-invalid');
10210 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10212 var feedback = this.el.select('.form-control-feedback', true).first();
10215 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
10220 this.fireEvent('valid', this);
10224 * Mark this field as valid
10226 markValid : function()
10228 if(!this.el || this.preventMark){ // not rendered
10232 this.el.removeClass([this.invalidClass, this.validClass]);
10233 this.inputEl().removeClass(['is-valid', 'is-invalid']);
10235 var feedback = this.el.select('.form-control-feedback', true).first();
10238 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10241 if(this.disabled || this.allowBlank){
10245 var label = this.el.select('label', true).first();
10246 var icon = this.el.select('i.fa-star', true).first();
10251 if (Roo.bootstrap.version == 3) {
10252 this.el.addClass(this.validClass);
10254 this.inputEl().addClass('is-valid');
10258 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
10260 var feedback = this.el.select('.form-control-feedback', true).first();
10263 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10264 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
10269 this.fireEvent('valid', this);
10273 * Mark this field as invalid
10274 * @param {String} msg The validation message
10276 markInvalid : function(msg)
10278 if(!this.el || this.preventMark){ // not rendered
10282 this.el.removeClass([this.invalidClass, this.validClass]);
10283 this.inputEl().removeClass(['is-valid', 'is-invalid']);
10285 var feedback = this.el.select('.form-control-feedback', true).first();
10288 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10291 if(this.disabled || this.allowBlank){
10295 var label = this.el.select('label', true).first();
10296 var icon = this.el.select('i.fa-star', true).first();
10298 if(!this.getValue().length && label && !icon){
10299 this.el.createChild({
10301 cls : 'text-danger fa fa-lg fa-star',
10302 tooltip : 'This field is required',
10303 style : 'margin-right:5px;'
10307 if (Roo.bootstrap.version == 3) {
10308 this.el.addClass(this.invalidClass);
10310 this.inputEl().addClass('is-invalid');
10313 // fixme ... this may be depricated need to test..
10314 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10316 var feedback = this.el.select('.form-control-feedback', true).first();
10319 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10321 if(this.getValue().length || this.forceFeedback){
10322 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
10329 this.fireEvent('invalid', this, msg);
10337 * trigger field - base class for combo..
10342 * @class Roo.bootstrap.TriggerField
10343 * @extends Roo.bootstrap.Input
10344 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
10345 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
10346 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
10347 * for which you can provide a custom implementation. For example:
10349 var trigger = new Roo.bootstrap.TriggerField();
10350 trigger.onTriggerClick = myTriggerFn;
10351 trigger.applyTo('my-field');
10354 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
10355 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
10356 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
10357 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
10358 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
10361 * Create a new TriggerField.
10362 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
10363 * to the base TextField)
10365 Roo.bootstrap.TriggerField = function(config){
10366 this.mimicing = false;
10367 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
10370 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
10372 * @cfg {String} triggerClass A CSS class to apply to the trigger
10375 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
10380 * @cfg {Boolean} removable (true|false) special filter default false
10384 /** @cfg {Boolean} grow @hide */
10385 /** @cfg {Number} growMin @hide */
10386 /** @cfg {Number} growMax @hide */
10392 autoSize: Roo.emptyFn,
10396 deferHeight : true,
10399 actionMode : 'wrap',
10404 getAutoCreate : function(){
10406 var align = this.labelAlign || this.parentLabelAlign();
10411 cls: 'form-group' //input-group
10418 type : this.inputType,
10419 cls : 'form-control',
10420 autocomplete: 'new-password',
10421 placeholder : this.placeholder || ''
10425 input.name = this.name;
10428 input.cls += ' input-' + this.size;
10431 if (this.disabled) {
10432 input.disabled=true;
10435 var inputblock = input;
10437 if(this.hasFeedback && !this.allowBlank){
10441 cls: 'glyphicon form-control-feedback'
10444 if(this.removable && !this.editable && !this.tickable){
10446 cls : 'has-feedback',
10452 cls : 'roo-combo-removable-btn close'
10459 cls : 'has-feedback',
10468 if(this.removable && !this.editable && !this.tickable){
10470 cls : 'roo-removable',
10476 cls : 'roo-combo-removable-btn close'
10483 if (this.before || this.after) {
10486 cls : 'input-group',
10490 inputblock.cn.push({
10492 cls : 'input-group-addon input-group-prepend input-group-text',
10497 inputblock.cn.push(input);
10499 if(this.hasFeedback && !this.allowBlank){
10500 inputblock.cls += ' has-feedback';
10501 inputblock.cn.push(feedback);
10505 inputblock.cn.push({
10507 cls : 'input-group-addon input-group-append input-group-text',
10516 var ibwrap = inputblock;
10521 cls: 'roo-select2-choices',
10525 cls: 'roo-select2-search-field',
10537 cls: 'roo-select2-container input-group',
10542 cls: 'form-hidden-field'
10548 if(!this.multiple && this.showToggleBtn){
10554 if (this.caret != false) {
10557 cls: 'fa fa-' + this.caret
10564 cls : 'input-group-addon input-group-append input-group-text btn dropdown-toggle',
10569 cls: 'combobox-clear',
10583 combobox.cls += ' roo-select2-container-multi';
10587 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
10588 tooltip : 'This field is required'
10590 if (Roo.bootstrap.version == 4) {
10593 style : 'display:none'
10598 if (align ==='left' && this.fieldLabel.length) {
10600 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
10607 cls : 'control-label',
10608 html : this.fieldLabel
10620 var labelCfg = cfg.cn[1];
10621 var contentCfg = cfg.cn[2];
10623 if(this.indicatorpos == 'right'){
10628 cls : 'control-label',
10632 html : this.fieldLabel
10646 labelCfg = cfg.cn[0];
10647 contentCfg = cfg.cn[1];
10650 if(this.labelWidth > 12){
10651 labelCfg.style = "width: " + this.labelWidth + 'px';
10654 if(this.labelWidth < 13 && this.labelmd == 0){
10655 this.labelmd = this.labelWidth;
10658 if(this.labellg > 0){
10659 labelCfg.cls += ' col-lg-' + this.labellg;
10660 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
10663 if(this.labelmd > 0){
10664 labelCfg.cls += ' col-md-' + this.labelmd;
10665 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
10668 if(this.labelsm > 0){
10669 labelCfg.cls += ' col-sm-' + this.labelsm;
10670 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
10673 if(this.labelxs > 0){
10674 labelCfg.cls += ' col-xs-' + this.labelxs;
10675 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
10678 } else if ( this.fieldLabel.length) {
10679 // Roo.log(" label");
10684 //cls : 'input-group-addon',
10685 html : this.fieldLabel
10693 if(this.indicatorpos == 'right'){
10701 html : this.fieldLabel
10715 // Roo.log(" no label && no align");
10722 ['xs','sm','md','lg'].map(function(size){
10723 if (settings[size]) {
10724 cfg.cls += ' col-' + size + '-' + settings[size];
10735 onResize : function(w, h){
10736 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
10737 // if(typeof w == 'number'){
10738 // var x = w - this.trigger.getWidth();
10739 // this.inputEl().setWidth(this.adjustWidth('input', x));
10740 // this.trigger.setStyle('left', x+'px');
10745 adjustSize : Roo.BoxComponent.prototype.adjustSize,
10748 getResizeEl : function(){
10749 return this.inputEl();
10753 getPositionEl : function(){
10754 return this.inputEl();
10758 alignErrorIcon : function(){
10759 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
10763 initEvents : function(){
10767 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
10768 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
10769 if(!this.multiple && this.showToggleBtn){
10770 this.trigger = this.el.select('span.dropdown-toggle',true).first();
10771 if(this.hideTrigger){
10772 this.trigger.setDisplayed(false);
10774 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10778 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
10781 if(this.removable && !this.editable && !this.tickable){
10782 var close = this.closeTriggerEl();
10785 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
10786 close.on('click', this.removeBtnClick, this, close);
10790 //this.trigger.addClassOnOver('x-form-trigger-over');
10791 //this.trigger.addClassOnClick('x-form-trigger-click');
10794 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
10798 closeTriggerEl : function()
10800 var close = this.el.select('.roo-combo-removable-btn', true).first();
10801 return close ? close : false;
10804 removeBtnClick : function(e, h, el)
10806 e.preventDefault();
10808 if(this.fireEvent("remove", this) !== false){
10810 this.fireEvent("afterremove", this)
10814 createList : function()
10816 this.list = Roo.get(document.body).createChild({
10817 tag: Roo.bootstrap.version == 4 ? 'div' : 'ul',
10818 cls: 'typeahead typeahead-long dropdown-menu',
10819 style: 'display:none'
10822 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
10827 initTrigger : function(){
10832 onDestroy : function(){
10834 this.trigger.removeAllListeners();
10835 // this.trigger.remove();
10838 // this.wrap.remove();
10840 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
10844 onFocus : function(){
10845 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
10847 if(!this.mimicing){
10848 this.wrap.addClass('x-trigger-wrap-focus');
10849 this.mimicing = true;
10850 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
10851 if(this.monitorTab){
10852 this.el.on("keydown", this.checkTab, this);
10859 checkTab : function(e){
10860 if(e.getKey() == e.TAB){
10861 this.triggerBlur();
10866 onBlur : function(){
10871 mimicBlur : function(e, t){
10873 if(!this.wrap.contains(t) && this.validateBlur()){
10874 this.triggerBlur();
10880 triggerBlur : function(){
10881 this.mimicing = false;
10882 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
10883 if(this.monitorTab){
10884 this.el.un("keydown", this.checkTab, this);
10886 //this.wrap.removeClass('x-trigger-wrap-focus');
10887 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
10891 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
10892 validateBlur : function(e, t){
10897 onDisable : function(){
10898 this.inputEl().dom.disabled = true;
10899 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
10901 // this.wrap.addClass('x-item-disabled');
10906 onEnable : function(){
10907 this.inputEl().dom.disabled = false;
10908 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
10910 // this.el.removeClass('x-item-disabled');
10915 onShow : function(){
10916 var ae = this.getActionEl();
10919 ae.dom.style.display = '';
10920 ae.dom.style.visibility = 'visible';
10926 onHide : function(){
10927 var ae = this.getActionEl();
10928 ae.dom.style.display = 'none';
10932 * The function that should handle the trigger's click event. This method does nothing by default until overridden
10933 * by an implementing function.
10935 * @param {EventObject} e
10937 onTriggerClick : Roo.emptyFn
10941 * Ext JS Library 1.1.1
10942 * Copyright(c) 2006-2007, Ext JS, LLC.
10944 * Originally Released Under LGPL - original licence link has changed is not relivant.
10947 * <script type="text/javascript">
10952 * @class Roo.data.SortTypes
10954 * Defines the default sorting (casting?) comparison functions used when sorting data.
10956 Roo.data.SortTypes = {
10958 * Default sort that does nothing
10959 * @param {Mixed} s The value being converted
10960 * @return {Mixed} The comparison value
10962 none : function(s){
10967 * The regular expression used to strip tags
10971 stripTagsRE : /<\/?[^>]+>/gi,
10974 * Strips all HTML tags to sort on text only
10975 * @param {Mixed} s The value being converted
10976 * @return {String} The comparison value
10978 asText : function(s){
10979 return String(s).replace(this.stripTagsRE, "");
10983 * Strips all HTML tags to sort on text only - Case insensitive
10984 * @param {Mixed} s The value being converted
10985 * @return {String} The comparison value
10987 asUCText : function(s){
10988 return String(s).toUpperCase().replace(this.stripTagsRE, "");
10992 * Case insensitive string
10993 * @param {Mixed} s The value being converted
10994 * @return {String} The comparison value
10996 asUCString : function(s) {
10997 return String(s).toUpperCase();
11002 * @param {Mixed} s The value being converted
11003 * @return {Number} The comparison value
11005 asDate : function(s) {
11009 if(s instanceof Date){
11010 return s.getTime();
11012 return Date.parse(String(s));
11017 * @param {Mixed} s The value being converted
11018 * @return {Float} The comparison value
11020 asFloat : function(s) {
11021 var val = parseFloat(String(s).replace(/,/g, ""));
11030 * @param {Mixed} s The value being converted
11031 * @return {Number} The comparison value
11033 asInt : function(s) {
11034 var val = parseInt(String(s).replace(/,/g, ""));
11042 * Ext JS Library 1.1.1
11043 * Copyright(c) 2006-2007, Ext JS, LLC.
11045 * Originally Released Under LGPL - original licence link has changed is not relivant.
11048 * <script type="text/javascript">
11052 * @class Roo.data.Record
11053 * Instances of this class encapsulate both record <em>definition</em> information, and record
11054 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
11055 * to access Records cached in an {@link Roo.data.Store} object.<br>
11057 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
11058 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
11061 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
11063 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
11064 * {@link #create}. The parameters are the same.
11065 * @param {Array} data An associative Array of data values keyed by the field name.
11066 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
11067 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
11068 * not specified an integer id is generated.
11070 Roo.data.Record = function(data, id){
11071 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
11076 * Generate a constructor for a specific record layout.
11077 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
11078 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
11079 * Each field definition object may contain the following properties: <ul>
11080 * <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,
11081 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
11082 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
11083 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
11084 * is being used, then this is a string containing the javascript expression to reference the data relative to
11085 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
11086 * to the data item relative to the record element. If the mapping expression is the same as the field name,
11087 * this may be omitted.</p></li>
11088 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
11089 * <ul><li>auto (Default, implies no conversion)</li>
11094 * <li>date</li></ul></p></li>
11095 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
11096 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
11097 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
11098 * by the Reader into an object that will be stored in the Record. It is passed the
11099 * following parameters:<ul>
11100 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
11102 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
11104 * <br>usage:<br><pre><code>
11105 var TopicRecord = Roo.data.Record.create(
11106 {name: 'title', mapping: 'topic_title'},
11107 {name: 'author', mapping: 'username'},
11108 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
11109 {name: 'lastPost', mapping: 'post_time', type: 'date'},
11110 {name: 'lastPoster', mapping: 'user2'},
11111 {name: 'excerpt', mapping: 'post_text'}
11114 var myNewRecord = new TopicRecord({
11115 title: 'Do my job please',
11118 lastPost: new Date(),
11119 lastPoster: 'Animal',
11120 excerpt: 'No way dude!'
11122 myStore.add(myNewRecord);
11127 Roo.data.Record.create = function(o){
11128 var f = function(){
11129 f.superclass.constructor.apply(this, arguments);
11131 Roo.extend(f, Roo.data.Record);
11132 var p = f.prototype;
11133 p.fields = new Roo.util.MixedCollection(false, function(field){
11136 for(var i = 0, len = o.length; i < len; i++){
11137 p.fields.add(new Roo.data.Field(o[i]));
11139 f.getField = function(name){
11140 return p.fields.get(name);
11145 Roo.data.Record.AUTO_ID = 1000;
11146 Roo.data.Record.EDIT = 'edit';
11147 Roo.data.Record.REJECT = 'reject';
11148 Roo.data.Record.COMMIT = 'commit';
11150 Roo.data.Record.prototype = {
11152 * Readonly flag - true if this record has been modified.
11161 join : function(store){
11162 this.store = store;
11166 * Set the named field to the specified value.
11167 * @param {String} name The name of the field to set.
11168 * @param {Object} value The value to set the field to.
11170 set : function(name, value){
11171 if(this.data[name] == value){
11175 if(!this.modified){
11176 this.modified = {};
11178 if(typeof this.modified[name] == 'undefined'){
11179 this.modified[name] = this.data[name];
11181 this.data[name] = value;
11182 if(!this.editing && this.store){
11183 this.store.afterEdit(this);
11188 * Get the value of the named field.
11189 * @param {String} name The name of the field to get the value of.
11190 * @return {Object} The value of the field.
11192 get : function(name){
11193 return this.data[name];
11197 beginEdit : function(){
11198 this.editing = true;
11199 this.modified = {};
11203 cancelEdit : function(){
11204 this.editing = false;
11205 delete this.modified;
11209 endEdit : function(){
11210 this.editing = false;
11211 if(this.dirty && this.store){
11212 this.store.afterEdit(this);
11217 * Usually called by the {@link Roo.data.Store} which owns the Record.
11218 * Rejects all changes made to the Record since either creation, or the last commit operation.
11219 * Modified fields are reverted to their original values.
11221 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
11222 * of reject operations.
11224 reject : function(){
11225 var m = this.modified;
11227 if(typeof m[n] != "function"){
11228 this.data[n] = m[n];
11231 this.dirty = false;
11232 delete this.modified;
11233 this.editing = false;
11235 this.store.afterReject(this);
11240 * Usually called by the {@link Roo.data.Store} which owns the Record.
11241 * Commits all changes made to the Record since either creation, or the last commit operation.
11243 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
11244 * of commit operations.
11246 commit : function(){
11247 this.dirty = false;
11248 delete this.modified;
11249 this.editing = false;
11251 this.store.afterCommit(this);
11256 hasError : function(){
11257 return this.error != null;
11261 clearError : function(){
11266 * Creates a copy of this record.
11267 * @param {String} id (optional) A new record id if you don't want to use this record's id
11270 copy : function(newId) {
11271 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
11275 * Ext JS Library 1.1.1
11276 * Copyright(c) 2006-2007, Ext JS, LLC.
11278 * Originally Released Under LGPL - original licence link has changed is not relivant.
11281 * <script type="text/javascript">
11287 * @class Roo.data.Store
11288 * @extends Roo.util.Observable
11289 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
11290 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
11292 * 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
11293 * has no knowledge of the format of the data returned by the Proxy.<br>
11295 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
11296 * instances from the data object. These records are cached and made available through accessor functions.
11298 * Creates a new Store.
11299 * @param {Object} config A config object containing the objects needed for the Store to access data,
11300 * and read the data into Records.
11302 Roo.data.Store = function(config){
11303 this.data = new Roo.util.MixedCollection(false);
11304 this.data.getKey = function(o){
11307 this.baseParams = {};
11309 this.paramNames = {
11314 "multisort" : "_multisort"
11317 if(config && config.data){
11318 this.inlineData = config.data;
11319 delete config.data;
11322 Roo.apply(this, config);
11324 if(this.reader){ // reader passed
11325 this.reader = Roo.factory(this.reader, Roo.data);
11326 this.reader.xmodule = this.xmodule || false;
11327 if(!this.recordType){
11328 this.recordType = this.reader.recordType;
11330 if(this.reader.onMetaChange){
11331 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
11335 if(this.recordType){
11336 this.fields = this.recordType.prototype.fields;
11338 this.modified = [];
11342 * @event datachanged
11343 * Fires when the data cache has changed, and a widget which is using this Store
11344 * as a Record cache should refresh its view.
11345 * @param {Store} this
11347 datachanged : true,
11349 * @event metachange
11350 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
11351 * @param {Store} this
11352 * @param {Object} meta The JSON metadata
11357 * Fires when Records have been added to the Store
11358 * @param {Store} this
11359 * @param {Roo.data.Record[]} records The array of Records added
11360 * @param {Number} index The index at which the record(s) were added
11365 * Fires when a Record has been removed from the Store
11366 * @param {Store} this
11367 * @param {Roo.data.Record} record The Record that was removed
11368 * @param {Number} index The index at which the record was removed
11373 * Fires when a Record has been updated
11374 * @param {Store} this
11375 * @param {Roo.data.Record} record The Record that was updated
11376 * @param {String} operation The update operation being performed. Value may be one of:
11378 Roo.data.Record.EDIT
11379 Roo.data.Record.REJECT
11380 Roo.data.Record.COMMIT
11386 * Fires when the data cache has been cleared.
11387 * @param {Store} this
11391 * @event beforeload
11392 * Fires before a request is made for a new data object. If the beforeload handler returns false
11393 * the load action will be canceled.
11394 * @param {Store} this
11395 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11399 * @event beforeloadadd
11400 * Fires after a new set of Records has been loaded.
11401 * @param {Store} this
11402 * @param {Roo.data.Record[]} records The Records that were loaded
11403 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11405 beforeloadadd : true,
11408 * Fires after a new set of Records has been loaded, before they are added to the store.
11409 * @param {Store} this
11410 * @param {Roo.data.Record[]} records The Records that were loaded
11411 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11412 * @params {Object} return from reader
11416 * @event loadexception
11417 * Fires if an exception occurs in the Proxy during loading.
11418 * Called with the signature of the Proxy's "loadexception" event.
11419 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
11422 * @param {Object} return from JsonData.reader() - success, totalRecords, records
11423 * @param {Object} load options
11424 * @param {Object} jsonData from your request (normally this contains the Exception)
11426 loadexception : true
11430 this.proxy = Roo.factory(this.proxy, Roo.data);
11431 this.proxy.xmodule = this.xmodule || false;
11432 this.relayEvents(this.proxy, ["loadexception"]);
11434 this.sortToggle = {};
11435 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
11437 Roo.data.Store.superclass.constructor.call(this);
11439 if(this.inlineData){
11440 this.loadData(this.inlineData);
11441 delete this.inlineData;
11445 Roo.extend(Roo.data.Store, Roo.util.Observable, {
11447 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
11448 * without a remote query - used by combo/forms at present.
11452 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
11455 * @cfg {Array} data Inline data to be loaded when the store is initialized.
11458 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
11459 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
11462 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
11463 * on any HTTP request
11466 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
11469 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
11473 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
11474 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
11476 remoteSort : false,
11479 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
11480 * loaded or when a record is removed. (defaults to false).
11482 pruneModifiedRecords : false,
11485 lastOptions : null,
11488 * Add Records to the Store and fires the add event.
11489 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11491 add : function(records){
11492 records = [].concat(records);
11493 for(var i = 0, len = records.length; i < len; i++){
11494 records[i].join(this);
11496 var index = this.data.length;
11497 this.data.addAll(records);
11498 this.fireEvent("add", this, records, index);
11502 * Remove a Record from the Store and fires the remove event.
11503 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
11505 remove : function(record){
11506 var index = this.data.indexOf(record);
11507 this.data.removeAt(index);
11509 if(this.pruneModifiedRecords){
11510 this.modified.remove(record);
11512 this.fireEvent("remove", this, record, index);
11516 * Remove all Records from the Store and fires the clear event.
11518 removeAll : function(){
11520 if(this.pruneModifiedRecords){
11521 this.modified = [];
11523 this.fireEvent("clear", this);
11527 * Inserts Records to the Store at the given index and fires the add event.
11528 * @param {Number} index The start index at which to insert the passed Records.
11529 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11531 insert : function(index, records){
11532 records = [].concat(records);
11533 for(var i = 0, len = records.length; i < len; i++){
11534 this.data.insert(index, records[i]);
11535 records[i].join(this);
11537 this.fireEvent("add", this, records, index);
11541 * Get the index within the cache of the passed Record.
11542 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
11543 * @return {Number} The index of the passed Record. Returns -1 if not found.
11545 indexOf : function(record){
11546 return this.data.indexOf(record);
11550 * Get the index within the cache of the Record with the passed id.
11551 * @param {String} id The id of the Record to find.
11552 * @return {Number} The index of the Record. Returns -1 if not found.
11554 indexOfId : function(id){
11555 return this.data.indexOfKey(id);
11559 * Get the Record with the specified id.
11560 * @param {String} id The id of the Record to find.
11561 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
11563 getById : function(id){
11564 return this.data.key(id);
11568 * Get the Record at the specified index.
11569 * @param {Number} index The index of the Record to find.
11570 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
11572 getAt : function(index){
11573 return this.data.itemAt(index);
11577 * Returns a range of Records between specified indices.
11578 * @param {Number} startIndex (optional) The starting index (defaults to 0)
11579 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
11580 * @return {Roo.data.Record[]} An array of Records
11582 getRange : function(start, end){
11583 return this.data.getRange(start, end);
11587 storeOptions : function(o){
11588 o = Roo.apply({}, o);
11591 this.lastOptions = o;
11595 * Loads the Record cache from the configured Proxy using the configured Reader.
11597 * If using remote paging, then the first load call must specify the <em>start</em>
11598 * and <em>limit</em> properties in the options.params property to establish the initial
11599 * position within the dataset, and the number of Records to cache on each read from the Proxy.
11601 * <strong>It is important to note that for remote data sources, loading is asynchronous,
11602 * and this call will return before the new data has been loaded. Perform any post-processing
11603 * in a callback function, or in a "load" event handler.</strong>
11605 * @param {Object} options An object containing properties which control loading options:<ul>
11606 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
11607 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
11608 * passed the following arguments:<ul>
11609 * <li>r : Roo.data.Record[]</li>
11610 * <li>options: Options object from the load call</li>
11611 * <li>success: Boolean success indicator</li></ul></li>
11612 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
11613 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
11616 load : function(options){
11617 options = options || {};
11618 if(this.fireEvent("beforeload", this, options) !== false){
11619 this.storeOptions(options);
11620 var p = Roo.apply(options.params || {}, this.baseParams);
11621 // if meta was not loaded from remote source.. try requesting it.
11622 if (!this.reader.metaFromRemote) {
11623 p._requestMeta = 1;
11625 if(this.sortInfo && this.remoteSort){
11626 var pn = this.paramNames;
11627 p[pn["sort"]] = this.sortInfo.field;
11628 p[pn["dir"]] = this.sortInfo.direction;
11630 if (this.multiSort) {
11631 var pn = this.paramNames;
11632 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
11635 this.proxy.load(p, this.reader, this.loadRecords, this, options);
11640 * Reloads the Record cache from the configured Proxy using the configured Reader and
11641 * the options from the last load operation performed.
11642 * @param {Object} options (optional) An object containing properties which may override the options
11643 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
11644 * the most recently used options are reused).
11646 reload : function(options){
11647 this.load(Roo.applyIf(options||{}, this.lastOptions));
11651 // Called as a callback by the Reader during a load operation.
11652 loadRecords : function(o, options, success){
11653 if(!o || success === false){
11654 if(success !== false){
11655 this.fireEvent("load", this, [], options, o);
11657 if(options.callback){
11658 options.callback.call(options.scope || this, [], options, false);
11662 // if data returned failure - throw an exception.
11663 if (o.success === false) {
11664 // show a message if no listener is registered.
11665 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
11666 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
11668 // loadmask wil be hooked into this..
11669 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
11672 var r = o.records, t = o.totalRecords || r.length;
11674 this.fireEvent("beforeloadadd", this, r, options, o);
11676 if(!options || options.add !== true){
11677 if(this.pruneModifiedRecords){
11678 this.modified = [];
11680 for(var i = 0, len = r.length; i < len; i++){
11684 this.data = this.snapshot;
11685 delete this.snapshot;
11688 this.data.addAll(r);
11689 this.totalLength = t;
11691 this.fireEvent("datachanged", this);
11693 this.totalLength = Math.max(t, this.data.length+r.length);
11697 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
11699 var e = new Roo.data.Record({});
11701 e.set(this.parent.displayField, this.parent.emptyTitle);
11702 e.set(this.parent.valueField, '');
11707 this.fireEvent("load", this, r, options, o);
11708 if(options.callback){
11709 options.callback.call(options.scope || this, r, options, true);
11715 * Loads data from a passed data block. A Reader which understands the format of the data
11716 * must have been configured in the constructor.
11717 * @param {Object} data The data block from which to read the Records. The format of the data expected
11718 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
11719 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
11721 loadData : function(o, append){
11722 var r = this.reader.readRecords(o);
11723 this.loadRecords(r, {add: append}, true);
11727 * Gets the number of cached records.
11729 * <em>If using paging, this may not be the total size of the dataset. If the data object
11730 * used by the Reader contains the dataset size, then the getTotalCount() function returns
11731 * the data set size</em>
11733 getCount : function(){
11734 return this.data.length || 0;
11738 * Gets the total number of records in the dataset as returned by the server.
11740 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
11741 * the dataset size</em>
11743 getTotalCount : function(){
11744 return this.totalLength || 0;
11748 * Returns the sort state of the Store as an object with two properties:
11750 field {String} The name of the field by which the Records are sorted
11751 direction {String} The sort order, "ASC" or "DESC"
11754 getSortState : function(){
11755 return this.sortInfo;
11759 applySort : function(){
11760 if(this.sortInfo && !this.remoteSort){
11761 var s = this.sortInfo, f = s.field;
11762 var st = this.fields.get(f).sortType;
11763 var fn = function(r1, r2){
11764 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
11765 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
11767 this.data.sort(s.direction, fn);
11768 if(this.snapshot && this.snapshot != this.data){
11769 this.snapshot.sort(s.direction, fn);
11775 * Sets the default sort column and order to be used by the next load operation.
11776 * @param {String} fieldName The name of the field to sort by.
11777 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11779 setDefaultSort : function(field, dir){
11780 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
11784 * Sort the Records.
11785 * If remote sorting is used, the sort is performed on the server, and the cache is
11786 * reloaded. If local sorting is used, the cache is sorted internally.
11787 * @param {String} fieldName The name of the field to sort by.
11788 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11790 sort : function(fieldName, dir){
11791 var f = this.fields.get(fieldName);
11793 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
11795 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
11796 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
11801 this.sortToggle[f.name] = dir;
11802 this.sortInfo = {field: f.name, direction: dir};
11803 if(!this.remoteSort){
11805 this.fireEvent("datachanged", this);
11807 this.load(this.lastOptions);
11812 * Calls the specified function for each of the Records in the cache.
11813 * @param {Function} fn The function to call. The Record is passed as the first parameter.
11814 * Returning <em>false</em> aborts and exits the iteration.
11815 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
11817 each : function(fn, scope){
11818 this.data.each(fn, scope);
11822 * Gets all records modified since the last commit. Modified records are persisted across load operations
11823 * (e.g., during paging).
11824 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
11826 getModifiedRecords : function(){
11827 return this.modified;
11831 createFilterFn : function(property, value, anyMatch){
11832 if(!value.exec){ // not a regex
11833 value = String(value);
11834 if(value.length == 0){
11837 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
11839 return function(r){
11840 return value.test(r.data[property]);
11845 * Sums the value of <i>property</i> for each record between start and end and returns the result.
11846 * @param {String} property A field on your records
11847 * @param {Number} start The record index to start at (defaults to 0)
11848 * @param {Number} end The last record index to include (defaults to length - 1)
11849 * @return {Number} The sum
11851 sum : function(property, start, end){
11852 var rs = this.data.items, v = 0;
11853 start = start || 0;
11854 end = (end || end === 0) ? end : rs.length-1;
11856 for(var i = start; i <= end; i++){
11857 v += (rs[i].data[property] || 0);
11863 * Filter the records by a specified property.
11864 * @param {String} field A field on your records
11865 * @param {String/RegExp} value Either a string that the field
11866 * should start with or a RegExp to test against the field
11867 * @param {Boolean} anyMatch True to match any part not just the beginning
11869 filter : function(property, value, anyMatch){
11870 var fn = this.createFilterFn(property, value, anyMatch);
11871 return fn ? this.filterBy(fn) : this.clearFilter();
11875 * Filter by a function. The specified function will be called with each
11876 * record in this data source. If the function returns true the record is included,
11877 * otherwise it is filtered.
11878 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11879 * @param {Object} scope (optional) The scope of the function (defaults to this)
11881 filterBy : function(fn, scope){
11882 this.snapshot = this.snapshot || this.data;
11883 this.data = this.queryBy(fn, scope||this);
11884 this.fireEvent("datachanged", this);
11888 * Query the records by a specified property.
11889 * @param {String} field A field on your records
11890 * @param {String/RegExp} value Either a string that the field
11891 * should start with or a RegExp to test against the field
11892 * @param {Boolean} anyMatch True to match any part not just the beginning
11893 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11895 query : function(property, value, anyMatch){
11896 var fn = this.createFilterFn(property, value, anyMatch);
11897 return fn ? this.queryBy(fn) : this.data.clone();
11901 * Query by a function. The specified function will be called with each
11902 * record in this data source. If the function returns true the record is included
11904 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11905 * @param {Object} scope (optional) The scope of the function (defaults to this)
11906 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11908 queryBy : function(fn, scope){
11909 var data = this.snapshot || this.data;
11910 return data.filterBy(fn, scope||this);
11914 * Collects unique values for a particular dataIndex from this store.
11915 * @param {String} dataIndex The property to collect
11916 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
11917 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
11918 * @return {Array} An array of the unique values
11920 collect : function(dataIndex, allowNull, bypassFilter){
11921 var d = (bypassFilter === true && this.snapshot) ?
11922 this.snapshot.items : this.data.items;
11923 var v, sv, r = [], l = {};
11924 for(var i = 0, len = d.length; i < len; i++){
11925 v = d[i].data[dataIndex];
11927 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
11936 * Revert to a view of the Record cache with no filtering applied.
11937 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
11939 clearFilter : function(suppressEvent){
11940 if(this.snapshot && this.snapshot != this.data){
11941 this.data = this.snapshot;
11942 delete this.snapshot;
11943 if(suppressEvent !== true){
11944 this.fireEvent("datachanged", this);
11950 afterEdit : function(record){
11951 if(this.modified.indexOf(record) == -1){
11952 this.modified.push(record);
11954 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
11958 afterReject : function(record){
11959 this.modified.remove(record);
11960 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
11964 afterCommit : function(record){
11965 this.modified.remove(record);
11966 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
11970 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
11971 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
11973 commitChanges : function(){
11974 var m = this.modified.slice(0);
11975 this.modified = [];
11976 for(var i = 0, len = m.length; i < len; i++){
11982 * Cancel outstanding changes on all changed records.
11984 rejectChanges : function(){
11985 var m = this.modified.slice(0);
11986 this.modified = [];
11987 for(var i = 0, len = m.length; i < len; i++){
11992 onMetaChange : function(meta, rtype, o){
11993 this.recordType = rtype;
11994 this.fields = rtype.prototype.fields;
11995 delete this.snapshot;
11996 this.sortInfo = meta.sortInfo || this.sortInfo;
11997 this.modified = [];
11998 this.fireEvent('metachange', this, this.reader.meta);
12001 moveIndex : function(data, type)
12003 var index = this.indexOf(data);
12005 var newIndex = index + type;
12009 this.insert(newIndex, data);
12014 * Ext JS Library 1.1.1
12015 * Copyright(c) 2006-2007, Ext JS, LLC.
12017 * Originally Released Under LGPL - original licence link has changed is not relivant.
12020 * <script type="text/javascript">
12024 * @class Roo.data.SimpleStore
12025 * @extends Roo.data.Store
12026 * Small helper class to make creating Stores from Array data easier.
12027 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
12028 * @cfg {Array} fields An array of field definition objects, or field name strings.
12029 * @cfg {Array} data The multi-dimensional array of data
12031 * @param {Object} config
12033 Roo.data.SimpleStore = function(config){
12034 Roo.data.SimpleStore.superclass.constructor.call(this, {
12036 reader: new Roo.data.ArrayReader({
12039 Roo.data.Record.create(config.fields)
12041 proxy : new Roo.data.MemoryProxy(config.data)
12045 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
12047 * Ext JS Library 1.1.1
12048 * Copyright(c) 2006-2007, Ext JS, LLC.
12050 * Originally Released Under LGPL - original licence link has changed is not relivant.
12053 * <script type="text/javascript">
12058 * @extends Roo.data.Store
12059 * @class Roo.data.JsonStore
12060 * Small helper class to make creating Stores for JSON data easier. <br/>
12062 var store = new Roo.data.JsonStore({
12063 url: 'get-images.php',
12065 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
12068 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
12069 * JsonReader and HttpProxy (unless inline data is provided).</b>
12070 * @cfg {Array} fields An array of field definition objects, or field name strings.
12072 * @param {Object} config
12074 Roo.data.JsonStore = function(c){
12075 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
12076 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
12077 reader: new Roo.data.JsonReader(c, c.fields)
12080 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
12082 * Ext JS Library 1.1.1
12083 * Copyright(c) 2006-2007, Ext JS, LLC.
12085 * Originally Released Under LGPL - original licence link has changed is not relivant.
12088 * <script type="text/javascript">
12092 Roo.data.Field = function(config){
12093 if(typeof config == "string"){
12094 config = {name: config};
12096 Roo.apply(this, config);
12099 this.type = "auto";
12102 var st = Roo.data.SortTypes;
12103 // named sortTypes are supported, here we look them up
12104 if(typeof this.sortType == "string"){
12105 this.sortType = st[this.sortType];
12108 // set default sortType for strings and dates
12109 if(!this.sortType){
12112 this.sortType = st.asUCString;
12115 this.sortType = st.asDate;
12118 this.sortType = st.none;
12123 var stripRe = /[\$,%]/g;
12125 // prebuilt conversion function for this field, instead of
12126 // switching every time we're reading a value
12128 var cv, dateFormat = this.dateFormat;
12133 cv = function(v){ return v; };
12136 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
12140 return v !== undefined && v !== null && v !== '' ?
12141 parseInt(String(v).replace(stripRe, ""), 10) : '';
12146 return v !== undefined && v !== null && v !== '' ?
12147 parseFloat(String(v).replace(stripRe, ""), 10) : '';
12152 cv = function(v){ return v === true || v === "true" || v == 1; };
12159 if(v instanceof Date){
12163 if(dateFormat == "timestamp"){
12164 return new Date(v*1000);
12166 return Date.parseDate(v, dateFormat);
12168 var parsed = Date.parse(v);
12169 return parsed ? new Date(parsed) : null;
12178 Roo.data.Field.prototype = {
12186 * Ext JS Library 1.1.1
12187 * Copyright(c) 2006-2007, Ext JS, LLC.
12189 * Originally Released Under LGPL - original licence link has changed is not relivant.
12192 * <script type="text/javascript">
12195 // Base class for reading structured data from a data source. This class is intended to be
12196 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
12199 * @class Roo.data.DataReader
12200 * Base class for reading structured data from a data source. This class is intended to be
12201 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
12204 Roo.data.DataReader = function(meta, recordType){
12208 this.recordType = recordType instanceof Array ?
12209 Roo.data.Record.create(recordType) : recordType;
12212 Roo.data.DataReader.prototype = {
12214 * Create an empty record
12215 * @param {Object} data (optional) - overlay some values
12216 * @return {Roo.data.Record} record created.
12218 newRow : function(d) {
12220 this.recordType.prototype.fields.each(function(c) {
12222 case 'int' : da[c.name] = 0; break;
12223 case 'date' : da[c.name] = new Date(); break;
12224 case 'float' : da[c.name] = 0.0; break;
12225 case 'boolean' : da[c.name] = false; break;
12226 default : da[c.name] = ""; break;
12230 return new this.recordType(Roo.apply(da, d));
12235 * Ext JS Library 1.1.1
12236 * Copyright(c) 2006-2007, Ext JS, LLC.
12238 * Originally Released Under LGPL - original licence link has changed is not relivant.
12241 * <script type="text/javascript">
12245 * @class Roo.data.DataProxy
12246 * @extends Roo.data.Observable
12247 * This class is an abstract base class for implementations which provide retrieval of
12248 * unformatted data objects.<br>
12250 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
12251 * (of the appropriate type which knows how to parse the data object) to provide a block of
12252 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
12254 * Custom implementations must implement the load method as described in
12255 * {@link Roo.data.HttpProxy#load}.
12257 Roo.data.DataProxy = function(){
12260 * @event beforeload
12261 * Fires before a network request is made to retrieve a data object.
12262 * @param {Object} This DataProxy object.
12263 * @param {Object} params The params parameter to the load function.
12268 * Fires before the load method's callback is called.
12269 * @param {Object} This DataProxy object.
12270 * @param {Object} o The data object.
12271 * @param {Object} arg The callback argument object passed to the load function.
12275 * @event loadexception
12276 * Fires if an Exception occurs during data retrieval.
12277 * @param {Object} This DataProxy object.
12278 * @param {Object} o The data object.
12279 * @param {Object} arg The callback argument object passed to the load function.
12280 * @param {Object} e The Exception.
12282 loadexception : true
12284 Roo.data.DataProxy.superclass.constructor.call(this);
12287 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
12290 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
12294 * Ext JS Library 1.1.1
12295 * Copyright(c) 2006-2007, Ext JS, LLC.
12297 * Originally Released Under LGPL - original licence link has changed is not relivant.
12300 * <script type="text/javascript">
12303 * @class Roo.data.MemoryProxy
12304 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
12305 * to the Reader when its load method is called.
12307 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
12309 Roo.data.MemoryProxy = function(data){
12313 Roo.data.MemoryProxy.superclass.constructor.call(this);
12317 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
12320 * Load data from the requested source (in this case an in-memory
12321 * data object passed to the constructor), read the data object into
12322 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12323 * process that block using the passed callback.
12324 * @param {Object} params This parameter is not used by the MemoryProxy class.
12325 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12326 * object into a block of Roo.data.Records.
12327 * @param {Function} callback The function into which to pass the block of Roo.data.records.
12328 * The function must be passed <ul>
12329 * <li>The Record block object</li>
12330 * <li>The "arg" argument from the load function</li>
12331 * <li>A boolean success indicator</li>
12333 * @param {Object} scope The scope in which to call the callback
12334 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12336 load : function(params, reader, callback, scope, arg){
12337 params = params || {};
12340 result = reader.readRecords(this.data);
12342 this.fireEvent("loadexception", this, arg, null, e);
12343 callback.call(scope, null, arg, false);
12346 callback.call(scope, result, arg, true);
12350 update : function(params, records){
12355 * Ext JS Library 1.1.1
12356 * Copyright(c) 2006-2007, Ext JS, LLC.
12358 * Originally Released Under LGPL - original licence link has changed is not relivant.
12361 * <script type="text/javascript">
12364 * @class Roo.data.HttpProxy
12365 * @extends Roo.data.DataProxy
12366 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
12367 * configured to reference a certain URL.<br><br>
12369 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
12370 * from which the running page was served.<br><br>
12372 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
12374 * Be aware that to enable the browser to parse an XML document, the server must set
12375 * the Content-Type header in the HTTP response to "text/xml".
12377 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
12378 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
12379 * will be used to make the request.
12381 Roo.data.HttpProxy = function(conn){
12382 Roo.data.HttpProxy.superclass.constructor.call(this);
12383 // is conn a conn config or a real conn?
12385 this.useAjax = !conn || !conn.events;
12389 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
12390 // thse are take from connection...
12393 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
12396 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
12397 * extra parameters to each request made by this object. (defaults to undefined)
12400 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
12401 * to each request made by this object. (defaults to undefined)
12404 * @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)
12407 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
12410 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
12416 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
12420 * Return the {@link Roo.data.Connection} object being used by this Proxy.
12421 * @return {Connection} The Connection object. This object may be used to subscribe to events on
12422 * a finer-grained basis than the DataProxy events.
12424 getConnection : function(){
12425 return this.useAjax ? Roo.Ajax : this.conn;
12429 * Load data from the configured {@link Roo.data.Connection}, read the data object into
12430 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
12431 * process that block using the passed callback.
12432 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12433 * for the request to the remote server.
12434 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12435 * object into a block of Roo.data.Records.
12436 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12437 * The function must be passed <ul>
12438 * <li>The Record block object</li>
12439 * <li>The "arg" argument from the load function</li>
12440 * <li>A boolean success indicator</li>
12442 * @param {Object} scope The scope in which to call the callback
12443 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12445 load : function(params, reader, callback, scope, arg){
12446 if(this.fireEvent("beforeload", this, params) !== false){
12448 params : params || {},
12450 callback : callback,
12455 callback : this.loadResponse,
12459 Roo.applyIf(o, this.conn);
12460 if(this.activeRequest){
12461 Roo.Ajax.abort(this.activeRequest);
12463 this.activeRequest = Roo.Ajax.request(o);
12465 this.conn.request(o);
12468 callback.call(scope||this, null, arg, false);
12473 loadResponse : function(o, success, response){
12474 delete this.activeRequest;
12476 this.fireEvent("loadexception", this, o, response);
12477 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12482 result = o.reader.read(response);
12484 this.fireEvent("loadexception", this, o, response, e);
12485 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12489 this.fireEvent("load", this, o, o.request.arg);
12490 o.request.callback.call(o.request.scope, result, o.request.arg, true);
12494 update : function(dataSet){
12499 updateResponse : function(dataSet){
12504 * Ext JS Library 1.1.1
12505 * Copyright(c) 2006-2007, Ext JS, LLC.
12507 * Originally Released Under LGPL - original licence link has changed is not relivant.
12510 * <script type="text/javascript">
12514 * @class Roo.data.ScriptTagProxy
12515 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
12516 * other than the originating domain of the running page.<br><br>
12518 * <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
12519 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
12521 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
12522 * source code that is used as the source inside a <script> tag.<br><br>
12524 * In order for the browser to process the returned data, the server must wrap the data object
12525 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
12526 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
12527 * depending on whether the callback name was passed:
12530 boolean scriptTag = false;
12531 String cb = request.getParameter("callback");
12534 response.setContentType("text/javascript");
12536 response.setContentType("application/x-json");
12538 Writer out = response.getWriter();
12540 out.write(cb + "(");
12542 out.print(dataBlock.toJsonString());
12549 * @param {Object} config A configuration object.
12551 Roo.data.ScriptTagProxy = function(config){
12552 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
12553 Roo.apply(this, config);
12554 this.head = document.getElementsByTagName("head")[0];
12557 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
12559 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
12561 * @cfg {String} url The URL from which to request the data object.
12564 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
12568 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
12569 * the server the name of the callback function set up by the load call to process the returned data object.
12570 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
12571 * javascript output which calls this named function passing the data object as its only parameter.
12573 callbackParam : "callback",
12575 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
12576 * name to the request.
12581 * Load data from the configured URL, read the data object into
12582 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12583 * process that block using the passed callback.
12584 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12585 * for the request to the remote server.
12586 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12587 * object into a block of Roo.data.Records.
12588 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12589 * The function must be passed <ul>
12590 * <li>The Record block object</li>
12591 * <li>The "arg" argument from the load function</li>
12592 * <li>A boolean success indicator</li>
12594 * @param {Object} scope The scope in which to call the callback
12595 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12597 load : function(params, reader, callback, scope, arg){
12598 if(this.fireEvent("beforeload", this, params) !== false){
12600 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
12602 var url = this.url;
12603 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
12605 url += "&_dc=" + (new Date().getTime());
12607 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
12610 cb : "stcCallback"+transId,
12611 scriptId : "stcScript"+transId,
12615 callback : callback,
12621 window[trans.cb] = function(o){
12622 conn.handleResponse(o, trans);
12625 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
12627 if(this.autoAbort !== false){
12631 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
12633 var script = document.createElement("script");
12634 script.setAttribute("src", url);
12635 script.setAttribute("type", "text/javascript");
12636 script.setAttribute("id", trans.scriptId);
12637 this.head.appendChild(script);
12639 this.trans = trans;
12641 callback.call(scope||this, null, arg, false);
12646 isLoading : function(){
12647 return this.trans ? true : false;
12651 * Abort the current server request.
12653 abort : function(){
12654 if(this.isLoading()){
12655 this.destroyTrans(this.trans);
12660 destroyTrans : function(trans, isLoaded){
12661 this.head.removeChild(document.getElementById(trans.scriptId));
12662 clearTimeout(trans.timeoutId);
12664 window[trans.cb] = undefined;
12666 delete window[trans.cb];
12669 // if hasn't been loaded, wait for load to remove it to prevent script error
12670 window[trans.cb] = function(){
12671 window[trans.cb] = undefined;
12673 delete window[trans.cb];
12680 handleResponse : function(o, trans){
12681 this.trans = false;
12682 this.destroyTrans(trans, true);
12685 result = trans.reader.readRecords(o);
12687 this.fireEvent("loadexception", this, o, trans.arg, e);
12688 trans.callback.call(trans.scope||window, null, trans.arg, false);
12691 this.fireEvent("load", this, o, trans.arg);
12692 trans.callback.call(trans.scope||window, result, trans.arg, true);
12696 handleFailure : function(trans){
12697 this.trans = false;
12698 this.destroyTrans(trans, false);
12699 this.fireEvent("loadexception", this, null, trans.arg);
12700 trans.callback.call(trans.scope||window, null, trans.arg, false);
12704 * Ext JS Library 1.1.1
12705 * Copyright(c) 2006-2007, Ext JS, LLC.
12707 * Originally Released Under LGPL - original licence link has changed is not relivant.
12710 * <script type="text/javascript">
12714 * @class Roo.data.JsonReader
12715 * @extends Roo.data.DataReader
12716 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
12717 * based on mappings in a provided Roo.data.Record constructor.
12719 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
12720 * in the reply previously.
12725 var RecordDef = Roo.data.Record.create([
12726 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
12727 {name: 'occupation'} // This field will use "occupation" as the mapping.
12729 var myReader = new Roo.data.JsonReader({
12730 totalProperty: "results", // The property which contains the total dataset size (optional)
12731 root: "rows", // The property which contains an Array of row objects
12732 id: "id" // The property within each row object that provides an ID for the record (optional)
12736 * This would consume a JSON file like this:
12738 { 'results': 2, 'rows': [
12739 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
12740 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
12743 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
12744 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
12745 * paged from the remote server.
12746 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
12747 * @cfg {String} root name of the property which contains the Array of row objects.
12748 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
12749 * @cfg {Array} fields Array of field definition objects
12751 * Create a new JsonReader
12752 * @param {Object} meta Metadata configuration options
12753 * @param {Object} recordType Either an Array of field definition objects,
12754 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
12756 Roo.data.JsonReader = function(meta, recordType){
12759 // set some defaults:
12760 Roo.applyIf(meta, {
12761 totalProperty: 'total',
12762 successProperty : 'success',
12767 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
12769 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
12772 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
12773 * Used by Store query builder to append _requestMeta to params.
12776 metaFromRemote : false,
12778 * This method is only used by a DataProxy which has retrieved data from a remote server.
12779 * @param {Object} response The XHR object which contains the JSON data in its responseText.
12780 * @return {Object} data A data block which is used by an Roo.data.Store object as
12781 * a cache of Roo.data.Records.
12783 read : function(response){
12784 var json = response.responseText;
12786 var o = /* eval:var:o */ eval("("+json+")");
12788 throw {message: "JsonReader.read: Json object not found"};
12794 this.metaFromRemote = true;
12795 this.meta = o.metaData;
12796 this.recordType = Roo.data.Record.create(o.metaData.fields);
12797 this.onMetaChange(this.meta, this.recordType, o);
12799 return this.readRecords(o);
12802 // private function a store will implement
12803 onMetaChange : function(meta, recordType, o){
12810 simpleAccess: function(obj, subsc) {
12817 getJsonAccessor: function(){
12819 return function(expr) {
12821 return(re.test(expr))
12822 ? new Function("obj", "return obj." + expr)
12827 return Roo.emptyFn;
12832 * Create a data block containing Roo.data.Records from an XML document.
12833 * @param {Object} o An object which contains an Array of row objects in the property specified
12834 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
12835 * which contains the total size of the dataset.
12836 * @return {Object} data A data block which is used by an Roo.data.Store object as
12837 * a cache of Roo.data.Records.
12839 readRecords : function(o){
12841 * After any data loads, the raw JSON data is available for further custom processing.
12845 var s = this.meta, Record = this.recordType,
12846 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
12848 // Generate extraction functions for the totalProperty, the root, the id, and for each field
12850 if(s.totalProperty) {
12851 this.getTotal = this.getJsonAccessor(s.totalProperty);
12853 if(s.successProperty) {
12854 this.getSuccess = this.getJsonAccessor(s.successProperty);
12856 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
12858 var g = this.getJsonAccessor(s.id);
12859 this.getId = function(rec) {
12861 return (r === undefined || r === "") ? null : r;
12864 this.getId = function(){return null;};
12867 for(var jj = 0; jj < fl; jj++){
12869 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
12870 this.ef[jj] = this.getJsonAccessor(map);
12874 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
12875 if(s.totalProperty){
12876 var vt = parseInt(this.getTotal(o), 10);
12881 if(s.successProperty){
12882 var vs = this.getSuccess(o);
12883 if(vs === false || vs === 'false'){
12888 for(var i = 0; i < c; i++){
12891 var id = this.getId(n);
12892 for(var j = 0; j < fl; j++){
12894 var v = this.ef[j](n);
12896 Roo.log('missing convert for ' + f.name);
12900 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
12902 var record = new Record(values, id);
12904 records[i] = record;
12910 totalRecords : totalRecords
12915 * Ext JS Library 1.1.1
12916 * Copyright(c) 2006-2007, Ext JS, LLC.
12918 * Originally Released Under LGPL - original licence link has changed is not relivant.
12921 * <script type="text/javascript">
12925 * @class Roo.data.ArrayReader
12926 * @extends Roo.data.DataReader
12927 * Data reader class to create an Array of Roo.data.Record objects from an Array.
12928 * Each element of that Array represents a row of data fields. The
12929 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
12930 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
12934 var RecordDef = Roo.data.Record.create([
12935 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
12936 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
12938 var myReader = new Roo.data.ArrayReader({
12939 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
12943 * This would consume an Array like this:
12945 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
12947 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
12949 * Create a new JsonReader
12950 * @param {Object} meta Metadata configuration options.
12951 * @param {Object} recordType Either an Array of field definition objects
12952 * as specified to {@link Roo.data.Record#create},
12953 * or an {@link Roo.data.Record} object
12954 * created using {@link Roo.data.Record#create}.
12956 Roo.data.ArrayReader = function(meta, recordType){
12957 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
12960 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
12962 * Create a data block containing Roo.data.Records from an XML document.
12963 * @param {Object} o An Array of row objects which represents the dataset.
12964 * @return {Object} data A data block which is used by an Roo.data.Store object as
12965 * a cache of Roo.data.Records.
12967 readRecords : function(o){
12968 var sid = this.meta ? this.meta.id : null;
12969 var recordType = this.recordType, fields = recordType.prototype.fields;
12972 for(var i = 0; i < root.length; i++){
12975 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
12976 for(var j = 0, jlen = fields.length; j < jlen; j++){
12977 var f = fields.items[j];
12978 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
12979 var v = n[k] !== undefined ? n[k] : f.defaultValue;
12981 values[f.name] = v;
12983 var record = new recordType(values, id);
12985 records[records.length] = record;
12989 totalRecords : records.length
12998 * @class Roo.bootstrap.ComboBox
12999 * @extends Roo.bootstrap.TriggerField
13000 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
13001 * @cfg {Boolean} append (true|false) default false
13002 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
13003 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
13004 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
13005 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
13006 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
13007 * @cfg {Boolean} animate default true
13008 * @cfg {Boolean} emptyResultText only for touch device
13009 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
13010 * @cfg {String} emptyTitle default ''
13012 * Create a new ComboBox.
13013 * @param {Object} config Configuration options
13015 Roo.bootstrap.ComboBox = function(config){
13016 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
13020 * Fires when the dropdown list is expanded
13021 * @param {Roo.bootstrap.ComboBox} combo This combo box
13026 * Fires when the dropdown list is collapsed
13027 * @param {Roo.bootstrap.ComboBox} combo This combo box
13031 * @event beforeselect
13032 * Fires before a list item is selected. Return false to cancel the selection.
13033 * @param {Roo.bootstrap.ComboBox} combo This combo box
13034 * @param {Roo.data.Record} record The data record returned from the underlying store
13035 * @param {Number} index The index of the selected item in the dropdown list
13037 'beforeselect' : true,
13040 * Fires when a list item is selected
13041 * @param {Roo.bootstrap.ComboBox} combo This combo box
13042 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
13043 * @param {Number} index The index of the selected item in the dropdown list
13047 * @event beforequery
13048 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
13049 * The event object passed has these properties:
13050 * @param {Roo.bootstrap.ComboBox} combo This combo box
13051 * @param {String} query The query
13052 * @param {Boolean} forceAll true to force "all" query
13053 * @param {Boolean} cancel true to cancel the query
13054 * @param {Object} e The query event object
13056 'beforequery': true,
13059 * Fires when the 'add' icon is pressed (add a listener to enable add button)
13060 * @param {Roo.bootstrap.ComboBox} combo This combo box
13065 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
13066 * @param {Roo.bootstrap.ComboBox} combo This combo box
13067 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
13072 * Fires when the remove value from the combobox array
13073 * @param {Roo.bootstrap.ComboBox} combo This combo box
13077 * @event afterremove
13078 * Fires when the remove value from the combobox array
13079 * @param {Roo.bootstrap.ComboBox} combo This combo box
13081 'afterremove' : true,
13083 * @event specialfilter
13084 * Fires when specialfilter
13085 * @param {Roo.bootstrap.ComboBox} combo This combo box
13087 'specialfilter' : true,
13090 * Fires when tick the element
13091 * @param {Roo.bootstrap.ComboBox} combo This combo box
13095 * @event touchviewdisplay
13096 * Fires when touch view require special display (default is using displayField)
13097 * @param {Roo.bootstrap.ComboBox} combo This combo box
13098 * @param {Object} cfg set html .
13100 'touchviewdisplay' : true
13105 this.tickItems = [];
13107 this.selectedIndex = -1;
13108 if(this.mode == 'local'){
13109 if(config.queryDelay === undefined){
13110 this.queryDelay = 10;
13112 if(config.minChars === undefined){
13118 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
13121 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
13122 * rendering into an Roo.Editor, defaults to false)
13125 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
13126 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
13129 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
13132 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
13133 * the dropdown list (defaults to undefined, with no header element)
13137 * @cfg {String/Roo.Template} tpl The template to use to render the output
13141 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
13143 listWidth: undefined,
13145 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
13146 * mode = 'remote' or 'text' if mode = 'local')
13148 displayField: undefined,
13151 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
13152 * mode = 'remote' or 'value' if mode = 'local').
13153 * Note: use of a valueField requires the user make a selection
13154 * in order for a value to be mapped.
13156 valueField: undefined,
13158 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
13163 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
13164 * field's data value (defaults to the underlying DOM element's name)
13166 hiddenName: undefined,
13168 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
13172 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
13174 selectedClass: 'active',
13177 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
13181 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
13182 * anchor positions (defaults to 'tl-bl')
13184 listAlign: 'tl-bl?',
13186 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
13190 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
13191 * query specified by the allQuery config option (defaults to 'query')
13193 triggerAction: 'query',
13195 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
13196 * (defaults to 4, does not apply if editable = false)
13200 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
13201 * delay (typeAheadDelay) if it matches a known value (defaults to false)
13205 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
13206 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
13210 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
13211 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
13215 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
13216 * when editable = true (defaults to false)
13218 selectOnFocus:false,
13220 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
13222 queryParam: 'query',
13224 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
13225 * when mode = 'remote' (defaults to 'Loading...')
13227 loadingText: 'Loading...',
13229 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
13233 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
13237 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
13238 * traditional select (defaults to true)
13242 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
13246 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
13250 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
13251 * listWidth has a higher value)
13255 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
13256 * allow the user to set arbitrary text into the field (defaults to false)
13258 forceSelection:false,
13260 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
13261 * if typeAhead = true (defaults to 250)
13263 typeAheadDelay : 250,
13265 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
13266 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
13268 valueNotFoundText : undefined,
13270 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
13272 blockFocus : false,
13275 * @cfg {Boolean} disableClear Disable showing of clear button.
13277 disableClear : false,
13279 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
13281 alwaysQuery : false,
13284 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
13289 * @cfg {String} invalidClass DEPRICATED - uses BS4 is-valid now
13291 invalidClass : "has-warning",
13294 * @cfg {String} validClass DEPRICATED - uses BS4 is-valid now
13296 validClass : "has-success",
13299 * @cfg {Boolean} specialFilter (true|false) special filter default false
13301 specialFilter : false,
13304 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
13306 mobileTouchView : true,
13309 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
13311 useNativeIOS : false,
13314 * @cfg {Boolean} mobile_restrict_height (true|false) restrict height for touch view
13316 mobile_restrict_height : false,
13318 ios_options : false,
13330 btnPosition : 'right',
13331 triggerList : true,
13332 showToggleBtn : true,
13334 emptyResultText: 'Empty',
13335 triggerText : 'Select',
13338 // element that contains real text value.. (when hidden is used..)
13340 getAutoCreate : function()
13345 * Render classic select for iso
13348 if(Roo.isIOS && this.useNativeIOS){
13349 cfg = this.getAutoCreateNativeIOS();
13357 if(Roo.isTouch && this.mobileTouchView){
13358 cfg = this.getAutoCreateTouchView();
13365 if(!this.tickable){
13366 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
13371 * ComboBox with tickable selections
13374 var align = this.labelAlign || this.parentLabelAlign();
13377 cls : 'form-group roo-combobox-tickable' //input-group
13380 var btn_text_select = '';
13381 var btn_text_done = '';
13382 var btn_text_cancel = '';
13384 if (this.btn_text_show) {
13385 btn_text_select = 'Select';
13386 btn_text_done = 'Done';
13387 btn_text_cancel = 'Cancel';
13392 cls : 'tickable-buttons',
13397 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
13398 //html : this.triggerText
13399 html: btn_text_select
13405 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
13407 html: btn_text_done
13413 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
13415 html: btn_text_cancel
13421 buttons.cn.unshift({
13423 cls: 'roo-select2-search-field-input'
13429 Roo.each(buttons.cn, function(c){
13431 c.cls += ' btn-' + _this.size;
13434 if (_this.disabled) {
13441 style : 'display: contents',
13446 cls: 'form-hidden-field'
13450 cls: 'roo-select2-choices',
13454 cls: 'roo-select2-search-field',
13465 cls: 'roo-select2-container input-group roo-select2-container-multi',
13471 // cls: 'typeahead typeahead-long dropdown-menu',
13472 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
13477 if(this.hasFeedback && !this.allowBlank){
13481 cls: 'glyphicon form-control-feedback'
13484 combobox.cn.push(feedback);
13489 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
13490 tooltip : 'This field is required'
13492 if (Roo.bootstrap.version == 4) {
13495 style : 'display:none'
13498 if (align ==='left' && this.fieldLabel.length) {
13500 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
13507 cls : 'control-label col-form-label',
13508 html : this.fieldLabel
13520 var labelCfg = cfg.cn[1];
13521 var contentCfg = cfg.cn[2];
13524 if(this.indicatorpos == 'right'){
13530 cls : 'control-label col-form-label',
13534 html : this.fieldLabel
13550 labelCfg = cfg.cn[0];
13551 contentCfg = cfg.cn[1];
13555 if(this.labelWidth > 12){
13556 labelCfg.style = "width: " + this.labelWidth + 'px';
13559 if(this.labelWidth < 13 && this.labelmd == 0){
13560 this.labelmd = this.labelWidth;
13563 if(this.labellg > 0){
13564 labelCfg.cls += ' col-lg-' + this.labellg;
13565 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
13568 if(this.labelmd > 0){
13569 labelCfg.cls += ' col-md-' + this.labelmd;
13570 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
13573 if(this.labelsm > 0){
13574 labelCfg.cls += ' col-sm-' + this.labelsm;
13575 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
13578 if(this.labelxs > 0){
13579 labelCfg.cls += ' col-xs-' + this.labelxs;
13580 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
13584 } else if ( this.fieldLabel.length) {
13585 // Roo.log(" label");
13590 //cls : 'input-group-addon',
13591 html : this.fieldLabel
13596 if(this.indicatorpos == 'right'){
13600 //cls : 'input-group-addon',
13601 html : this.fieldLabel
13611 // Roo.log(" no label && no align");
13618 ['xs','sm','md','lg'].map(function(size){
13619 if (settings[size]) {
13620 cfg.cls += ' col-' + size + '-' + settings[size];
13628 _initEventsCalled : false,
13631 initEvents: function()
13633 if (this._initEventsCalled) { // as we call render... prevent looping...
13636 this._initEventsCalled = true;
13639 throw "can not find store for combo";
13642 this.indicator = this.indicatorEl();
13644 this.store = Roo.factory(this.store, Roo.data);
13645 this.store.parent = this;
13647 // if we are building from html. then this element is so complex, that we can not really
13648 // use the rendered HTML.
13649 // so we have to trash and replace the previous code.
13650 if (Roo.XComponent.build_from_html) {
13651 // remove this element....
13652 var e = this.el.dom, k=0;
13653 while (e ) { e = e.previousSibling; ++k;}
13658 this.rendered = false;
13660 this.render(this.parent().getChildContainer(true), k);
13663 if(Roo.isIOS && this.useNativeIOS){
13664 this.initIOSView();
13672 if(Roo.isTouch && this.mobileTouchView){
13673 this.initTouchView();
13678 this.initTickableEvents();
13682 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
13684 if(this.hiddenName){
13686 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13688 this.hiddenField.dom.value =
13689 this.hiddenValue !== undefined ? this.hiddenValue :
13690 this.value !== undefined ? this.value : '';
13692 // prevent input submission
13693 this.el.dom.removeAttribute('name');
13694 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13699 // this.el.dom.setAttribute('autocomplete', 'off');
13702 var cls = 'x-combo-list';
13704 //this.list = new Roo.Layer({
13705 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
13711 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13712 _this.list.setWidth(lw);
13715 this.list.on('mouseover', this.onViewOver, this);
13716 this.list.on('mousemove', this.onViewMove, this);
13717 this.list.on('scroll', this.onViewScroll, this);
13720 this.list.swallowEvent('mousewheel');
13721 this.assetHeight = 0;
13724 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
13725 this.assetHeight += this.header.getHeight();
13728 this.innerList = this.list.createChild({cls:cls+'-inner'});
13729 this.innerList.on('mouseover', this.onViewOver, this);
13730 this.innerList.on('mousemove', this.onViewMove, this);
13731 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13733 if(this.allowBlank && !this.pageSize && !this.disableClear){
13734 this.footer = this.list.createChild({cls:cls+'-ft'});
13735 this.pageTb = new Roo.Toolbar(this.footer);
13739 this.footer = this.list.createChild({cls:cls+'-ft'});
13740 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
13741 {pageSize: this.pageSize});
13745 if (this.pageTb && this.allowBlank && !this.disableClear) {
13747 this.pageTb.add(new Roo.Toolbar.Fill(), {
13748 cls: 'x-btn-icon x-btn-clear',
13750 handler: function()
13753 _this.clearValue();
13754 _this.onSelect(false, -1);
13759 this.assetHeight += this.footer.getHeight();
13764 this.tpl = Roo.bootstrap.version == 4 ?
13765 '<a class="dropdown-item" href="#">{' + this.displayField + '}</a>' : // 4 does not need <li> and it get's really confisued.
13766 '<li><a class="dropdown-item" href="#">{' + this.displayField + '}</a></li>';
13769 this.view = new Roo.View(this.list, this.tpl, {
13770 singleSelect:true, store: this.store, selectedClass: this.selectedClass
13772 //this.view.wrapEl.setDisplayed(false);
13773 this.view.on('click', this.onViewClick, this);
13776 this.store.on('beforeload', this.onBeforeLoad, this);
13777 this.store.on('load', this.onLoad, this);
13778 this.store.on('loadexception', this.onLoadException, this);
13780 if(this.resizable){
13781 this.resizer = new Roo.Resizable(this.list, {
13782 pinned:true, handles:'se'
13784 this.resizer.on('resize', function(r, w, h){
13785 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
13786 this.listWidth = w;
13787 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
13788 this.restrictHeight();
13790 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
13793 if(!this.editable){
13794 this.editable = true;
13795 this.setEditable(false);
13800 if (typeof(this.events.add.listeners) != 'undefined') {
13802 this.addicon = this.wrap.createChild(
13803 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
13805 this.addicon.on('click', function(e) {
13806 this.fireEvent('add', this);
13809 if (typeof(this.events.edit.listeners) != 'undefined') {
13811 this.editicon = this.wrap.createChild(
13812 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
13813 if (this.addicon) {
13814 this.editicon.setStyle('margin-left', '40px');
13816 this.editicon.on('click', function(e) {
13818 // we fire even if inothing is selected..
13819 this.fireEvent('edit', this, this.lastData );
13825 this.keyNav = new Roo.KeyNav(this.inputEl(), {
13826 "up" : function(e){
13827 this.inKeyMode = true;
13831 "down" : function(e){
13832 if(!this.isExpanded()){
13833 this.onTriggerClick();
13835 this.inKeyMode = true;
13840 "enter" : function(e){
13841 // this.onViewClick();
13845 if(this.fireEvent("specialkey", this, e)){
13846 this.onViewClick(false);
13852 "esc" : function(e){
13856 "tab" : function(e){
13859 if(this.fireEvent("specialkey", this, e)){
13860 this.onViewClick(false);
13868 doRelay : function(foo, bar, hname){
13869 if(hname == 'down' || this.scope.isExpanded()){
13870 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13879 this.queryDelay = Math.max(this.queryDelay || 10,
13880 this.mode == 'local' ? 10 : 250);
13883 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13885 if(this.typeAhead){
13886 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13888 if(this.editable !== false){
13889 this.inputEl().on("keyup", this.onKeyUp, this);
13891 if(this.forceSelection){
13892 this.inputEl().on('blur', this.doForce, this);
13896 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13897 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13901 initTickableEvents: function()
13905 if(this.hiddenName){
13907 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13909 this.hiddenField.dom.value =
13910 this.hiddenValue !== undefined ? this.hiddenValue :
13911 this.value !== undefined ? this.value : '';
13913 // prevent input submission
13914 this.el.dom.removeAttribute('name');
13915 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13920 // this.list = this.el.select('ul.dropdown-menu',true).first();
13922 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13923 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13924 if(this.triggerList){
13925 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
13928 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
13929 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
13931 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
13932 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
13934 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
13935 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
13937 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
13938 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
13939 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
13942 this.cancelBtn.hide();
13947 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13948 _this.list.setWidth(lw);
13951 this.list.on('mouseover', this.onViewOver, this);
13952 this.list.on('mousemove', this.onViewMove, this);
13954 this.list.on('scroll', this.onViewScroll, this);
13957 this.tpl = '<li class="roo-select2-result"><div class="checkbox"><input id="{roo-id}"' +
13958 'type="checkbox" {roo-data-checked}><label for="{roo-id}"><b>{' + this.displayField + '}</b></label></div></li>';
13961 this.view = new Roo.View(this.list, this.tpl, {
13966 selectedClass: this.selectedClass
13969 //this.view.wrapEl.setDisplayed(false);
13970 this.view.on('click', this.onViewClick, this);
13974 this.store.on('beforeload', this.onBeforeLoad, this);
13975 this.store.on('load', this.onLoad, this);
13976 this.store.on('loadexception', this.onLoadException, this);
13979 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
13980 "up" : function(e){
13981 this.inKeyMode = true;
13985 "down" : function(e){
13986 this.inKeyMode = true;
13990 "enter" : function(e){
13991 if(this.fireEvent("specialkey", this, e)){
13992 this.onViewClick(false);
13998 "esc" : function(e){
13999 this.onTickableFooterButtonClick(e, false, false);
14002 "tab" : function(e){
14003 this.fireEvent("specialkey", this, e);
14005 this.onTickableFooterButtonClick(e, false, false);
14012 doRelay : function(e, fn, key){
14013 if(this.scope.isExpanded()){
14014 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
14023 this.queryDelay = Math.max(this.queryDelay || 10,
14024 this.mode == 'local' ? 10 : 250);
14027 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
14029 if(this.typeAhead){
14030 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
14033 if(this.editable !== false){
14034 this.tickableInputEl().on("keyup", this.onKeyUp, this);
14037 this.indicator = this.indicatorEl();
14039 if(this.indicator){
14040 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
14041 this.indicator.hide();
14046 onDestroy : function(){
14048 this.view.setStore(null);
14049 this.view.el.removeAllListeners();
14050 this.view.el.remove();
14051 this.view.purgeListeners();
14054 this.list.dom.innerHTML = '';
14058 this.store.un('beforeload', this.onBeforeLoad, this);
14059 this.store.un('load', this.onLoad, this);
14060 this.store.un('loadexception', this.onLoadException, this);
14062 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
14066 fireKey : function(e){
14067 if(e.isNavKeyPress() && !this.list.isVisible()){
14068 this.fireEvent("specialkey", this, e);
14073 onResize: function(w, h){
14074 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
14076 // if(typeof w != 'number'){
14077 // // we do not handle it!?!?
14080 // var tw = this.trigger.getWidth();
14081 // // tw += this.addicon ? this.addicon.getWidth() : 0;
14082 // // tw += this.editicon ? this.editicon.getWidth() : 0;
14084 // this.inputEl().setWidth( this.adjustWidth('input', x));
14086 // //this.trigger.setStyle('left', x+'px');
14088 // if(this.list && this.listWidth === undefined){
14089 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
14090 // this.list.setWidth(lw);
14091 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
14099 * Allow or prevent the user from directly editing the field text. If false is passed,
14100 * the user will only be able to select from the items defined in the dropdown list. This method
14101 * is the runtime equivalent of setting the 'editable' config option at config time.
14102 * @param {Boolean} value True to allow the user to directly edit the field text
14104 setEditable : function(value){
14105 if(value == this.editable){
14108 this.editable = value;
14110 this.inputEl().dom.setAttribute('readOnly', true);
14111 this.inputEl().on('mousedown', this.onTriggerClick, this);
14112 this.inputEl().addClass('x-combo-noedit');
14114 this.inputEl().dom.setAttribute('readOnly', false);
14115 this.inputEl().un('mousedown', this.onTriggerClick, this);
14116 this.inputEl().removeClass('x-combo-noedit');
14122 onBeforeLoad : function(combo,opts){
14123 if(!this.hasFocus){
14127 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
14129 this.restrictHeight();
14130 this.selectedIndex = -1;
14134 onLoad : function(){
14136 this.hasQuery = false;
14138 if(!this.hasFocus){
14142 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
14143 this.loading.hide();
14146 if(this.store.getCount() > 0){
14149 this.restrictHeight();
14150 if(this.lastQuery == this.allQuery){
14151 if(this.editable && !this.tickable){
14152 this.inputEl().dom.select();
14156 !this.selectByValue(this.value, true) &&
14159 !this.store.lastOptions ||
14160 typeof(this.store.lastOptions.add) == 'undefined' ||
14161 this.store.lastOptions.add != true
14164 this.select(0, true);
14167 if(this.autoFocus){
14170 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
14171 this.taTask.delay(this.typeAheadDelay);
14175 this.onEmptyResults();
14181 onLoadException : function()
14183 this.hasQuery = false;
14185 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
14186 this.loading.hide();
14189 if(this.tickable && this.editable){
14194 // only causes errors at present
14195 //Roo.log(this.store.reader.jsonData);
14196 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
14198 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
14204 onTypeAhead : function(){
14205 if(this.store.getCount() > 0){
14206 var r = this.store.getAt(0);
14207 var newValue = r.data[this.displayField];
14208 var len = newValue.length;
14209 var selStart = this.getRawValue().length;
14211 if(selStart != len){
14212 this.setRawValue(newValue);
14213 this.selectText(selStart, newValue.length);
14219 onSelect : function(record, index){
14221 if(this.fireEvent('beforeselect', this, record, index) !== false){
14223 this.setFromData(index > -1 ? record.data : false);
14226 this.fireEvent('select', this, record, index);
14231 * Returns the currently selected field value or empty string if no value is set.
14232 * @return {String} value The selected value
14234 getValue : function()
14236 if(Roo.isIOS && this.useNativeIOS){
14237 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
14241 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
14244 if(this.valueField){
14245 return typeof this.value != 'undefined' ? this.value : '';
14247 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
14251 getRawValue : function()
14253 if(Roo.isIOS && this.useNativeIOS){
14254 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
14257 var v = this.inputEl().getValue();
14263 * Clears any text/value currently set in the field
14265 clearValue : function(){
14267 if(this.hiddenField){
14268 this.hiddenField.dom.value = '';
14271 this.setRawValue('');
14272 this.lastSelectionText = '';
14273 this.lastData = false;
14275 var close = this.closeTriggerEl();
14286 * Sets the specified value into the field. If the value finds a match, the corresponding record text
14287 * will be displayed in the field. If the value does not match the data value of an existing item,
14288 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
14289 * Otherwise the field will be blank (although the value will still be set).
14290 * @param {String} value The value to match
14292 setValue : function(v)
14294 if(Roo.isIOS && this.useNativeIOS){
14295 this.setIOSValue(v);
14305 if(this.valueField){
14306 var r = this.findRecord(this.valueField, v);
14308 text = r.data[this.displayField];
14309 }else if(this.valueNotFoundText !== undefined){
14310 text = this.valueNotFoundText;
14313 this.lastSelectionText = text;
14314 if(this.hiddenField){
14315 this.hiddenField.dom.value = v;
14317 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
14320 var close = this.closeTriggerEl();
14323 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
14329 * @property {Object} the last set data for the element
14334 * Sets the value of the field based on a object which is related to the record format for the store.
14335 * @param {Object} value the value to set as. or false on reset?
14337 setFromData : function(o){
14344 var dv = ''; // display value
14345 var vv = ''; // value value..
14347 if (this.displayField) {
14348 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14350 // this is an error condition!!!
14351 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14354 if(this.valueField){
14355 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
14358 var close = this.closeTriggerEl();
14361 if(dv.length || vv * 1 > 0){
14363 this.blockFocus=true;
14369 if(this.hiddenField){
14370 this.hiddenField.dom.value = vv;
14372 this.lastSelectionText = dv;
14373 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14377 // no hidden field.. - we store the value in 'value', but still display
14378 // display field!!!!
14379 this.lastSelectionText = dv;
14380 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14387 reset : function(){
14388 // overridden so that last data is reset..
14395 this.setValue(this.originalValue);
14396 //this.clearInvalid();
14397 this.lastData = false;
14399 this.view.clearSelections();
14405 findRecord : function(prop, value){
14407 if(this.store.getCount() > 0){
14408 this.store.each(function(r){
14409 if(r.data[prop] == value){
14419 getName: function()
14421 // returns hidden if it's set..
14422 if (!this.rendered) {return ''};
14423 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
14427 onViewMove : function(e, t){
14428 this.inKeyMode = false;
14432 onViewOver : function(e, t){
14433 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
14436 var item = this.view.findItemFromChild(t);
14439 var index = this.view.indexOf(item);
14440 this.select(index, false);
14445 onViewClick : function(view, doFocus, el, e)
14447 var index = this.view.getSelectedIndexes()[0];
14449 var r = this.store.getAt(index);
14453 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
14460 Roo.each(this.tickItems, function(v,k){
14462 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
14464 _this.tickItems.splice(k, 1);
14466 if(typeof(e) == 'undefined' && view == false){
14467 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
14479 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
14480 this.tickItems.push(r.data);
14483 if(typeof(e) == 'undefined' && view == false){
14484 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
14491 this.onSelect(r, index);
14493 if(doFocus !== false && !this.blockFocus){
14494 this.inputEl().focus();
14499 restrictHeight : function(){
14500 //this.innerList.dom.style.height = '';
14501 //var inner = this.innerList.dom;
14502 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
14503 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
14504 //this.list.beginUpdate();
14505 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
14506 this.list.alignTo(this.inputEl(), this.listAlign);
14507 this.list.alignTo(this.inputEl(), this.listAlign);
14508 //this.list.endUpdate();
14512 onEmptyResults : function(){
14514 if(this.tickable && this.editable){
14515 this.hasFocus = false;
14516 this.restrictHeight();
14524 * Returns true if the dropdown list is expanded, else false.
14526 isExpanded : function(){
14527 return this.list.isVisible();
14531 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
14532 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14533 * @param {String} value The data value of the item to select
14534 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14535 * selected item if it is not currently in view (defaults to true)
14536 * @return {Boolean} True if the value matched an item in the list, else false
14538 selectByValue : function(v, scrollIntoView){
14539 if(v !== undefined && v !== null){
14540 var r = this.findRecord(this.valueField || this.displayField, v);
14542 this.select(this.store.indexOf(r), scrollIntoView);
14550 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
14551 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14552 * @param {Number} index The zero-based index of the list item to select
14553 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14554 * selected item if it is not currently in view (defaults to true)
14556 select : function(index, scrollIntoView){
14557 this.selectedIndex = index;
14558 this.view.select(index);
14559 if(scrollIntoView !== false){
14560 var el = this.view.getNode(index);
14562 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
14565 this.list.scrollChildIntoView(el, false);
14571 selectNext : function(){
14572 var ct = this.store.getCount();
14574 if(this.selectedIndex == -1){
14576 }else if(this.selectedIndex < ct-1){
14577 this.select(this.selectedIndex+1);
14583 selectPrev : function(){
14584 var ct = this.store.getCount();
14586 if(this.selectedIndex == -1){
14588 }else if(this.selectedIndex != 0){
14589 this.select(this.selectedIndex-1);
14595 onKeyUp : function(e){
14596 if(this.editable !== false && !e.isSpecialKey()){
14597 this.lastKey = e.getKey();
14598 this.dqTask.delay(this.queryDelay);
14603 validateBlur : function(){
14604 return !this.list || !this.list.isVisible();
14608 initQuery : function(){
14610 var v = this.getRawValue();
14612 if(this.tickable && this.editable){
14613 v = this.tickableInputEl().getValue();
14620 doForce : function(){
14621 if(this.inputEl().dom.value.length > 0){
14622 this.inputEl().dom.value =
14623 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
14629 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
14630 * query allowing the query action to be canceled if needed.
14631 * @param {String} query The SQL query to execute
14632 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
14633 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
14634 * saved in the current store (defaults to false)
14636 doQuery : function(q, forceAll){
14638 if(q === undefined || q === null){
14643 forceAll: forceAll,
14647 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
14652 forceAll = qe.forceAll;
14653 if(forceAll === true || (q.length >= this.minChars)){
14655 this.hasQuery = true;
14657 if(this.lastQuery != q || this.alwaysQuery){
14658 this.lastQuery = q;
14659 if(this.mode == 'local'){
14660 this.selectedIndex = -1;
14662 this.store.clearFilter();
14665 if(this.specialFilter){
14666 this.fireEvent('specialfilter', this);
14671 this.store.filter(this.displayField, q);
14674 this.store.fireEvent("datachanged", this.store);
14681 this.store.baseParams[this.queryParam] = q;
14683 var options = {params : this.getParams(q)};
14686 options.add = true;
14687 options.params.start = this.page * this.pageSize;
14690 this.store.load(options);
14693 * this code will make the page width larger, at the beginning, the list not align correctly,
14694 * we should expand the list on onLoad
14695 * so command out it
14700 this.selectedIndex = -1;
14705 this.loadNext = false;
14709 getParams : function(q){
14711 //p[this.queryParam] = q;
14715 p.limit = this.pageSize;
14721 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
14723 collapse : function(){
14724 if(!this.isExpanded()){
14730 this.hasFocus = false;
14734 this.cancelBtn.hide();
14735 this.trigger.show();
14738 this.tickableInputEl().dom.value = '';
14739 this.tickableInputEl().blur();
14744 Roo.get(document).un('mousedown', this.collapseIf, this);
14745 Roo.get(document).un('mousewheel', this.collapseIf, this);
14746 if (!this.editable) {
14747 Roo.get(document).un('keydown', this.listKeyPress, this);
14749 this.fireEvent('collapse', this);
14755 collapseIf : function(e){
14756 var in_combo = e.within(this.el);
14757 var in_list = e.within(this.list);
14758 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
14760 if (in_combo || in_list || is_list) {
14761 //e.stopPropagation();
14766 this.onTickableFooterButtonClick(e, false, false);
14774 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
14776 expand : function(){
14778 if(this.isExpanded() || !this.hasFocus){
14782 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
14783 this.list.setWidth(lw);
14789 this.restrictHeight();
14793 this.tickItems = Roo.apply([], this.item);
14796 this.cancelBtn.show();
14797 this.trigger.hide();
14800 this.tickableInputEl().focus();
14805 Roo.get(document).on('mousedown', this.collapseIf, this);
14806 Roo.get(document).on('mousewheel', this.collapseIf, this);
14807 if (!this.editable) {
14808 Roo.get(document).on('keydown', this.listKeyPress, this);
14811 this.fireEvent('expand', this);
14815 // Implements the default empty TriggerField.onTriggerClick function
14816 onTriggerClick : function(e)
14818 Roo.log('trigger click');
14820 if(this.disabled || !this.triggerList){
14825 this.loadNext = false;
14827 if(this.isExpanded()){
14829 if (!this.blockFocus) {
14830 this.inputEl().focus();
14834 this.hasFocus = true;
14835 if(this.triggerAction == 'all') {
14836 this.doQuery(this.allQuery, true);
14838 this.doQuery(this.getRawValue());
14840 if (!this.blockFocus) {
14841 this.inputEl().focus();
14846 onTickableTriggerClick : function(e)
14853 this.loadNext = false;
14854 this.hasFocus = true;
14856 if(this.triggerAction == 'all') {
14857 this.doQuery(this.allQuery, true);
14859 this.doQuery(this.getRawValue());
14863 onSearchFieldClick : function(e)
14865 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
14866 this.onTickableFooterButtonClick(e, false, false);
14870 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
14875 this.loadNext = false;
14876 this.hasFocus = true;
14878 if(this.triggerAction == 'all') {
14879 this.doQuery(this.allQuery, true);
14881 this.doQuery(this.getRawValue());
14885 listKeyPress : function(e)
14887 //Roo.log('listkeypress');
14888 // scroll to first matching element based on key pres..
14889 if (e.isSpecialKey()) {
14892 var k = String.fromCharCode(e.getKey()).toUpperCase();
14895 var csel = this.view.getSelectedNodes();
14896 var cselitem = false;
14898 var ix = this.view.indexOf(csel[0]);
14899 cselitem = this.store.getAt(ix);
14900 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
14906 this.store.each(function(v) {
14908 // start at existing selection.
14909 if (cselitem.id == v.id) {
14915 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
14916 match = this.store.indexOf(v);
14922 if (match === false) {
14923 return true; // no more action?
14926 this.view.select(match);
14927 var sn = Roo.get(this.view.getSelectedNodes()[0]);
14928 sn.scrollIntoView(sn.dom.parentNode, false);
14931 onViewScroll : function(e, t){
14933 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){
14937 this.hasQuery = true;
14939 this.loading = this.list.select('.loading', true).first();
14941 if(this.loading === null){
14942 this.list.createChild({
14944 cls: 'loading roo-select2-more-results roo-select2-active',
14945 html: 'Loading more results...'
14948 this.loading = this.list.select('.loading', true).first();
14950 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
14952 this.loading.hide();
14955 this.loading.show();
14960 this.loadNext = true;
14962 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
14967 addItem : function(o)
14969 var dv = ''; // display value
14971 if (this.displayField) {
14972 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14974 // this is an error condition!!!
14975 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14982 var choice = this.choices.createChild({
14984 cls: 'roo-select2-search-choice',
14993 cls: 'roo-select2-search-choice-close fa fa-times',
14998 }, this.searchField);
15000 var close = choice.select('a.roo-select2-search-choice-close', true).first();
15002 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
15010 this.inputEl().dom.value = '';
15015 onRemoveItem : function(e, _self, o)
15017 e.preventDefault();
15019 this.lastItem = Roo.apply([], this.item);
15021 var index = this.item.indexOf(o.data) * 1;
15024 Roo.log('not this item?!');
15028 this.item.splice(index, 1);
15033 this.fireEvent('remove', this, e);
15039 syncValue : function()
15041 if(!this.item.length){
15048 Roo.each(this.item, function(i){
15049 if(_this.valueField){
15050 value.push(i[_this.valueField]);
15057 this.value = value.join(',');
15059 if(this.hiddenField){
15060 this.hiddenField.dom.value = this.value;
15063 this.store.fireEvent("datachanged", this.store);
15068 clearItem : function()
15070 if(!this.multiple){
15076 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
15084 if(this.tickable && !Roo.isTouch){
15085 this.view.refresh();
15089 inputEl: function ()
15091 if(Roo.isIOS && this.useNativeIOS){
15092 return this.el.select('select.roo-ios-select', true).first();
15095 if(Roo.isTouch && this.mobileTouchView){
15096 return this.el.select('input.form-control',true).first();
15100 return this.searchField;
15103 return this.el.select('input.form-control',true).first();
15106 onTickableFooterButtonClick : function(e, btn, el)
15108 e.preventDefault();
15110 this.lastItem = Roo.apply([], this.item);
15112 if(btn && btn.name == 'cancel'){
15113 this.tickItems = Roo.apply([], this.item);
15122 Roo.each(this.tickItems, function(o){
15130 validate : function()
15132 if(this.getVisibilityEl().hasClass('hidden')){
15136 var v = this.getRawValue();
15139 v = this.getValue();
15142 if(this.disabled || this.allowBlank || v.length){
15147 this.markInvalid();
15151 tickableInputEl : function()
15153 if(!this.tickable || !this.editable){
15154 return this.inputEl();
15157 return this.inputEl().select('.roo-select2-search-field-input', true).first();
15161 getAutoCreateTouchView : function()
15166 cls: 'form-group' //input-group
15172 type : this.inputType,
15173 cls : 'form-control x-combo-noedit',
15174 autocomplete: 'new-password',
15175 placeholder : this.placeholder || '',
15180 input.name = this.name;
15184 input.cls += ' input-' + this.size;
15187 if (this.disabled) {
15188 input.disabled = true;
15199 inputblock.cls += ' input-group';
15201 inputblock.cn.unshift({
15203 cls : 'input-group-addon input-group-prepend input-group-text',
15208 if(this.removable && !this.multiple){
15209 inputblock.cls += ' roo-removable';
15211 inputblock.cn.push({
15214 cls : 'roo-combo-removable-btn close'
15218 if(this.hasFeedback && !this.allowBlank){
15220 inputblock.cls += ' has-feedback';
15222 inputblock.cn.push({
15224 cls: 'glyphicon form-control-feedback'
15231 inputblock.cls += (this.before) ? '' : ' input-group';
15233 inputblock.cn.push({
15235 cls : 'input-group-addon input-group-append input-group-text',
15241 var ibwrap = inputblock;
15246 cls: 'roo-select2-choices',
15250 cls: 'roo-select2-search-field',
15263 cls: 'roo-select2-container input-group roo-touchview-combobox ',
15268 cls: 'form-hidden-field'
15274 if(!this.multiple && this.showToggleBtn){
15281 if (this.caret != false) {
15284 cls: 'fa fa-' + this.caret
15291 cls : 'input-group-addon input-group-append input-group-text btn dropdown-toggle',
15296 cls: 'combobox-clear',
15310 combobox.cls += ' roo-select2-container-multi';
15313 var align = this.labelAlign || this.parentLabelAlign();
15315 if (align ==='left' && this.fieldLabel.length) {
15320 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15321 tooltip : 'This field is required'
15325 cls : 'control-label col-form-label',
15326 html : this.fieldLabel
15337 var labelCfg = cfg.cn[1];
15338 var contentCfg = cfg.cn[2];
15341 if(this.indicatorpos == 'right'){
15346 cls : 'control-label col-form-label',
15350 html : this.fieldLabel
15354 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15355 tooltip : 'This field is required'
15368 labelCfg = cfg.cn[0];
15369 contentCfg = cfg.cn[1];
15374 if(this.labelWidth > 12){
15375 labelCfg.style = "width: " + this.labelWidth + 'px';
15378 if(this.labelWidth < 13 && this.labelmd == 0){
15379 this.labelmd = this.labelWidth;
15382 if(this.labellg > 0){
15383 labelCfg.cls += ' col-lg-' + this.labellg;
15384 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
15387 if(this.labelmd > 0){
15388 labelCfg.cls += ' col-md-' + this.labelmd;
15389 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
15392 if(this.labelsm > 0){
15393 labelCfg.cls += ' col-sm-' + this.labelsm;
15394 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
15397 if(this.labelxs > 0){
15398 labelCfg.cls += ' col-xs-' + this.labelxs;
15399 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
15403 } else if ( this.fieldLabel.length) {
15407 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15408 tooltip : 'This field is required'
15412 cls : 'control-label',
15413 html : this.fieldLabel
15424 if(this.indicatorpos == 'right'){
15428 cls : 'control-label',
15429 html : this.fieldLabel,
15433 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15434 tooltip : 'This field is required'
15451 var settings = this;
15453 ['xs','sm','md','lg'].map(function(size){
15454 if (settings[size]) {
15455 cfg.cls += ' col-' + size + '-' + settings[size];
15462 initTouchView : function()
15464 this.renderTouchView();
15466 this.touchViewEl.on('scroll', function(){
15467 this.el.dom.scrollTop = 0;
15470 this.originalValue = this.getValue();
15472 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
15474 this.inputEl().on("click", this.showTouchView, this);
15475 if (this.triggerEl) {
15476 this.triggerEl.on("click", this.showTouchView, this);
15480 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
15481 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
15483 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
15485 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
15486 this.store.on('load', this.onTouchViewLoad, this);
15487 this.store.on('loadexception', this.onTouchViewLoadException, this);
15489 if(this.hiddenName){
15491 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
15493 this.hiddenField.dom.value =
15494 this.hiddenValue !== undefined ? this.hiddenValue :
15495 this.value !== undefined ? this.value : '';
15497 this.el.dom.removeAttribute('name');
15498 this.hiddenField.dom.setAttribute('name', this.hiddenName);
15502 this.choices = this.el.select('ul.roo-select2-choices', true).first();
15503 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
15506 if(this.removable && !this.multiple){
15507 var close = this.closeTriggerEl();
15509 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
15510 close.on('click', this.removeBtnClick, this, close);
15514 * fix the bug in Safari iOS8
15516 this.inputEl().on("focus", function(e){
15517 document.activeElement.blur();
15520 this._touchViewMask = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
15527 renderTouchView : function()
15529 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
15530 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15532 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
15533 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15535 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
15536 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15537 this.touchViewBodyEl.setStyle('overflow', 'auto');
15539 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
15540 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15542 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
15543 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15547 showTouchView : function()
15553 this.touchViewHeaderEl.hide();
15555 if(this.modalTitle.length){
15556 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
15557 this.touchViewHeaderEl.show();
15560 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
15561 this.touchViewEl.show();
15563 this.touchViewEl.select('.modal-dialog', true).first().setStyle({ margin : '0px', width : '100%'});
15565 //this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
15566 // Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15568 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15570 if(this.modalTitle.length){
15571 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15574 this.touchViewBodyEl.setHeight(bodyHeight);
15578 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
15580 this.touchViewEl.addClass('in');
15583 if(this._touchViewMask){
15584 Roo.get(document.body).addClass("x-body-masked");
15585 this._touchViewMask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15586 this._touchViewMask.setStyle('z-index', 10000);
15587 this._touchViewMask.addClass('show');
15590 this.doTouchViewQuery();
15594 hideTouchView : function()
15596 this.touchViewEl.removeClass('in');
15600 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
15602 this.touchViewEl.setStyle('display', 'none');
15605 if(this._touchViewMask){
15606 this._touchViewMask.removeClass('show');
15607 Roo.get(document.body).removeClass("x-body-masked");
15611 setTouchViewValue : function()
15618 Roo.each(this.tickItems, function(o){
15623 this.hideTouchView();
15626 doTouchViewQuery : function()
15635 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
15639 if(!this.alwaysQuery || this.mode == 'local'){
15640 this.onTouchViewLoad();
15647 onTouchViewBeforeLoad : function(combo,opts)
15653 onTouchViewLoad : function()
15655 if(this.store.getCount() < 1){
15656 this.onTouchViewEmptyResults();
15660 this.clearTouchView();
15662 var rawValue = this.getRawValue();
15664 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
15666 this.tickItems = [];
15668 this.store.data.each(function(d, rowIndex){
15669 var row = this.touchViewListGroup.createChild(template);
15671 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
15672 row.addClass(d.data.cls);
15675 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15678 html : d.data[this.displayField]
15681 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
15682 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
15685 row.removeClass('selected');
15686 if(!this.multiple && this.valueField &&
15687 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
15690 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15691 row.addClass('selected');
15694 if(this.multiple && this.valueField &&
15695 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
15699 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15700 this.tickItems.push(d.data);
15703 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
15707 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
15709 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15711 if(this.modalTitle.length){
15712 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15715 var listHeight = this.touchViewListGroup.getHeight() + this.touchViewBodyEl.getPadding('tb') * 2;
15717 if(this.mobile_restrict_height && listHeight < bodyHeight){
15718 this.touchViewBodyEl.setHeight(listHeight);
15723 if(firstChecked && listHeight > bodyHeight){
15724 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
15729 onTouchViewLoadException : function()
15731 this.hideTouchView();
15734 onTouchViewEmptyResults : function()
15736 this.clearTouchView();
15738 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
15740 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
15744 clearTouchView : function()
15746 this.touchViewListGroup.dom.innerHTML = '';
15749 onTouchViewClick : function(e, el, o)
15751 e.preventDefault();
15754 var rowIndex = o.rowIndex;
15756 var r = this.store.getAt(rowIndex);
15758 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
15760 if(!this.multiple){
15761 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
15762 c.dom.removeAttribute('checked');
15765 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15767 this.setFromData(r.data);
15769 var close = this.closeTriggerEl();
15775 this.hideTouchView();
15777 this.fireEvent('select', this, r, rowIndex);
15782 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
15783 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
15784 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
15788 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15789 this.addItem(r.data);
15790 this.tickItems.push(r.data);
15794 getAutoCreateNativeIOS : function()
15797 cls: 'form-group' //input-group,
15802 cls : 'roo-ios-select'
15806 combobox.name = this.name;
15809 if (this.disabled) {
15810 combobox.disabled = true;
15813 var settings = this;
15815 ['xs','sm','md','lg'].map(function(size){
15816 if (settings[size]) {
15817 cfg.cls += ' col-' + size + '-' + settings[size];
15827 initIOSView : function()
15829 this.store.on('load', this.onIOSViewLoad, this);
15834 onIOSViewLoad : function()
15836 if(this.store.getCount() < 1){
15840 this.clearIOSView();
15842 if(this.allowBlank) {
15844 var default_text = '-- SELECT --';
15846 if(this.placeholder.length){
15847 default_text = this.placeholder;
15850 if(this.emptyTitle.length){
15851 default_text += ' - ' + this.emptyTitle + ' -';
15854 var opt = this.inputEl().createChild({
15857 html : default_text
15861 o[this.valueField] = 0;
15862 o[this.displayField] = default_text;
15864 this.ios_options.push({
15871 this.store.data.each(function(d, rowIndex){
15875 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15876 html = d.data[this.displayField];
15881 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
15882 value = d.data[this.valueField];
15891 if(this.value == d.data[this.valueField]){
15892 option['selected'] = true;
15895 var opt = this.inputEl().createChild(option);
15897 this.ios_options.push({
15904 this.inputEl().on('change', function(){
15905 this.fireEvent('select', this);
15910 clearIOSView: function()
15912 this.inputEl().dom.innerHTML = '';
15914 this.ios_options = [];
15917 setIOSValue: function(v)
15921 if(!this.ios_options){
15925 Roo.each(this.ios_options, function(opts){
15927 opts.el.dom.removeAttribute('selected');
15929 if(opts.data[this.valueField] != v){
15933 opts.el.dom.setAttribute('selected', true);
15939 * @cfg {Boolean} grow
15943 * @cfg {Number} growMin
15947 * @cfg {Number} growMax
15956 Roo.apply(Roo.bootstrap.ComboBox, {
15960 cls: 'modal-header',
15982 cls: 'list-group-item',
15986 cls: 'roo-combobox-list-group-item-value'
15990 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
16004 listItemCheckbox : {
16006 cls: 'list-group-item',
16010 cls: 'roo-combobox-list-group-item-value'
16014 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
16030 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
16035 cls: 'modal-footer',
16043 cls: 'col-xs-6 text-left',
16046 cls: 'btn btn-danger roo-touch-view-cancel',
16052 cls: 'col-xs-6 text-right',
16055 cls: 'btn btn-success roo-touch-view-ok',
16066 Roo.apply(Roo.bootstrap.ComboBox, {
16068 touchViewTemplate : {
16070 cls: 'modal fade roo-combobox-touch-view',
16074 cls: 'modal-dialog',
16075 style : 'position:fixed', // we have to fix position....
16079 cls: 'modal-content',
16081 Roo.bootstrap.ComboBox.header,
16082 Roo.bootstrap.ComboBox.body,
16083 Roo.bootstrap.ComboBox.footer
16092 * Ext JS Library 1.1.1
16093 * Copyright(c) 2006-2007, Ext JS, LLC.
16095 * Originally Released Under LGPL - original licence link has changed is not relivant.
16098 * <script type="text/javascript">
16103 * @extends Roo.util.Observable
16104 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
16105 * This class also supports single and multi selection modes. <br>
16106 * Create a data model bound view:
16108 var store = new Roo.data.Store(...);
16110 var view = new Roo.View({
16112 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
16114 singleSelect: true,
16115 selectedClass: "ydataview-selected",
16119 // listen for node click?
16120 view.on("click", function(vw, index, node, e){
16121 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
16125 dataModel.load("foobar.xml");
16127 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
16129 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
16130 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
16132 * Note: old style constructor is still suported (container, template, config)
16135 * Create a new View
16136 * @param {Object} config The config object
16139 Roo.View = function(config, depreciated_tpl, depreciated_config){
16141 this.parent = false;
16143 if (typeof(depreciated_tpl) == 'undefined') {
16144 // new way.. - universal constructor.
16145 Roo.apply(this, config);
16146 this.el = Roo.get(this.el);
16149 this.el = Roo.get(config);
16150 this.tpl = depreciated_tpl;
16151 Roo.apply(this, depreciated_config);
16153 this.wrapEl = this.el.wrap().wrap();
16154 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
16157 if(typeof(this.tpl) == "string"){
16158 this.tpl = new Roo.Template(this.tpl);
16160 // support xtype ctors..
16161 this.tpl = new Roo.factory(this.tpl, Roo);
16165 this.tpl.compile();
16170 * @event beforeclick
16171 * Fires before a click is processed. Returns false to cancel the default action.
16172 * @param {Roo.View} this
16173 * @param {Number} index The index of the target node
16174 * @param {HTMLElement} node The target node
16175 * @param {Roo.EventObject} e The raw event object
16177 "beforeclick" : true,
16180 * Fires when a template node is clicked.
16181 * @param {Roo.View} this
16182 * @param {Number} index The index of the target node
16183 * @param {HTMLElement} node The target node
16184 * @param {Roo.EventObject} e The raw event object
16189 * Fires when a template node is double clicked.
16190 * @param {Roo.View} this
16191 * @param {Number} index The index of the target node
16192 * @param {HTMLElement} node The target node
16193 * @param {Roo.EventObject} e The raw event object
16197 * @event contextmenu
16198 * Fires when a template node is right clicked.
16199 * @param {Roo.View} this
16200 * @param {Number} index The index of the target node
16201 * @param {HTMLElement} node The target node
16202 * @param {Roo.EventObject} e The raw event object
16204 "contextmenu" : true,
16206 * @event selectionchange
16207 * Fires when the selected nodes change.
16208 * @param {Roo.View} this
16209 * @param {Array} selections Array of the selected nodes
16211 "selectionchange" : true,
16214 * @event beforeselect
16215 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
16216 * @param {Roo.View} this
16217 * @param {HTMLElement} node The node to be selected
16218 * @param {Array} selections Array of currently selected nodes
16220 "beforeselect" : true,
16222 * @event preparedata
16223 * Fires on every row to render, to allow you to change the data.
16224 * @param {Roo.View} this
16225 * @param {Object} data to be rendered (change this)
16227 "preparedata" : true
16235 "click": this.onClick,
16236 "dblclick": this.onDblClick,
16237 "contextmenu": this.onContextMenu,
16241 this.selections = [];
16243 this.cmp = new Roo.CompositeElementLite([]);
16245 this.store = Roo.factory(this.store, Roo.data);
16246 this.setStore(this.store, true);
16249 if ( this.footer && this.footer.xtype) {
16251 var fctr = this.wrapEl.appendChild(document.createElement("div"));
16253 this.footer.dataSource = this.store;
16254 this.footer.container = fctr;
16255 this.footer = Roo.factory(this.footer, Roo);
16256 fctr.insertFirst(this.el);
16258 // this is a bit insane - as the paging toolbar seems to detach the el..
16259 // dom.parentNode.parentNode.parentNode
16260 // they get detached?
16264 Roo.View.superclass.constructor.call(this);
16269 Roo.extend(Roo.View, Roo.util.Observable, {
16272 * @cfg {Roo.data.Store} store Data store to load data from.
16277 * @cfg {String|Roo.Element} el The container element.
16282 * @cfg {String|Roo.Template} tpl The template used by this View
16286 * @cfg {String} dataName the named area of the template to use as the data area
16287 * Works with domtemplates roo-name="name"
16291 * @cfg {String} selectedClass The css class to add to selected nodes
16293 selectedClass : "x-view-selected",
16295 * @cfg {String} emptyText The empty text to show when nothing is loaded.
16300 * @cfg {String} text to display on mask (default Loading)
16304 * @cfg {Boolean} multiSelect Allow multiple selection
16306 multiSelect : false,
16308 * @cfg {Boolean} singleSelect Allow single selection
16310 singleSelect: false,
16313 * @cfg {Boolean} toggleSelect - selecting
16315 toggleSelect : false,
16318 * @cfg {Boolean} tickable - selecting
16323 * Returns the element this view is bound to.
16324 * @return {Roo.Element}
16326 getEl : function(){
16327 return this.wrapEl;
16333 * Refreshes the view. - called by datachanged on the store. - do not call directly.
16335 refresh : function(){
16336 //Roo.log('refresh');
16339 // if we are using something like 'domtemplate', then
16340 // the what gets used is:
16341 // t.applySubtemplate(NAME, data, wrapping data..)
16342 // the outer template then get' applied with
16343 // the store 'extra data'
16344 // and the body get's added to the
16345 // roo-name="data" node?
16346 // <span class='roo-tpl-{name}'></span> ?????
16350 this.clearSelections();
16351 this.el.update("");
16353 var records = this.store.getRange();
16354 if(records.length < 1) {
16356 // is this valid?? = should it render a template??
16358 this.el.update(this.emptyText);
16362 if (this.dataName) {
16363 this.el.update(t.apply(this.store.meta)); //????
16364 el = this.el.child('.roo-tpl-' + this.dataName);
16367 for(var i = 0, len = records.length; i < len; i++){
16368 var data = this.prepareData(records[i].data, i, records[i]);
16369 this.fireEvent("preparedata", this, data, i, records[i]);
16371 var d = Roo.apply({}, data);
16374 Roo.apply(d, {'roo-id' : Roo.id()});
16378 Roo.each(this.parent.item, function(item){
16379 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
16382 Roo.apply(d, {'roo-data-checked' : 'checked'});
16386 html[html.length] = Roo.util.Format.trim(
16388 t.applySubtemplate(this.dataName, d, this.store.meta) :
16395 el.update(html.join(""));
16396 this.nodes = el.dom.childNodes;
16397 this.updateIndexes(0);
16402 * Function to override to reformat the data that is sent to
16403 * the template for each node.
16404 * DEPRICATED - use the preparedata event handler.
16405 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
16406 * a JSON object for an UpdateManager bound view).
16408 prepareData : function(data, index, record)
16410 this.fireEvent("preparedata", this, data, index, record);
16414 onUpdate : function(ds, record){
16415 // Roo.log('on update');
16416 this.clearSelections();
16417 var index = this.store.indexOf(record);
16418 var n = this.nodes[index];
16419 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
16420 n.parentNode.removeChild(n);
16421 this.updateIndexes(index, index);
16427 onAdd : function(ds, records, index)
16429 //Roo.log(['on Add', ds, records, index] );
16430 this.clearSelections();
16431 if(this.nodes.length == 0){
16435 var n = this.nodes[index];
16436 for(var i = 0, len = records.length; i < len; i++){
16437 var d = this.prepareData(records[i].data, i, records[i]);
16439 this.tpl.insertBefore(n, d);
16442 this.tpl.append(this.el, d);
16445 this.updateIndexes(index);
16448 onRemove : function(ds, record, index){
16449 // Roo.log('onRemove');
16450 this.clearSelections();
16451 var el = this.dataName ?
16452 this.el.child('.roo-tpl-' + this.dataName) :
16455 el.dom.removeChild(this.nodes[index]);
16456 this.updateIndexes(index);
16460 * Refresh an individual node.
16461 * @param {Number} index
16463 refreshNode : function(index){
16464 this.onUpdate(this.store, this.store.getAt(index));
16467 updateIndexes : function(startIndex, endIndex){
16468 var ns = this.nodes;
16469 startIndex = startIndex || 0;
16470 endIndex = endIndex || ns.length - 1;
16471 for(var i = startIndex; i <= endIndex; i++){
16472 ns[i].nodeIndex = i;
16477 * Changes the data store this view uses and refresh the view.
16478 * @param {Store} store
16480 setStore : function(store, initial){
16481 if(!initial && this.store){
16482 this.store.un("datachanged", this.refresh);
16483 this.store.un("add", this.onAdd);
16484 this.store.un("remove", this.onRemove);
16485 this.store.un("update", this.onUpdate);
16486 this.store.un("clear", this.refresh);
16487 this.store.un("beforeload", this.onBeforeLoad);
16488 this.store.un("load", this.onLoad);
16489 this.store.un("loadexception", this.onLoad);
16493 store.on("datachanged", this.refresh, this);
16494 store.on("add", this.onAdd, this);
16495 store.on("remove", this.onRemove, this);
16496 store.on("update", this.onUpdate, this);
16497 store.on("clear", this.refresh, this);
16498 store.on("beforeload", this.onBeforeLoad, this);
16499 store.on("load", this.onLoad, this);
16500 store.on("loadexception", this.onLoad, this);
16508 * onbeforeLoad - masks the loading area.
16511 onBeforeLoad : function(store,opts)
16513 //Roo.log('onBeforeLoad');
16515 this.el.update("");
16517 this.el.mask(this.mask ? this.mask : "Loading" );
16519 onLoad : function ()
16526 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
16527 * @param {HTMLElement} node
16528 * @return {HTMLElement} The template node
16530 findItemFromChild : function(node){
16531 var el = this.dataName ?
16532 this.el.child('.roo-tpl-' + this.dataName,true) :
16535 if(!node || node.parentNode == el){
16538 var p = node.parentNode;
16539 while(p && p != el){
16540 if(p.parentNode == el){
16549 onClick : function(e){
16550 var item = this.findItemFromChild(e.getTarget());
16552 var index = this.indexOf(item);
16553 if(this.onItemClick(item, index, e) !== false){
16554 this.fireEvent("click", this, index, item, e);
16557 this.clearSelections();
16562 onContextMenu : function(e){
16563 var item = this.findItemFromChild(e.getTarget());
16565 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
16570 onDblClick : function(e){
16571 var item = this.findItemFromChild(e.getTarget());
16573 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
16577 onItemClick : function(item, index, e)
16579 if(this.fireEvent("beforeclick", this, index, item, e) === false){
16582 if (this.toggleSelect) {
16583 var m = this.isSelected(item) ? 'unselect' : 'select';
16586 _t[m](item, true, false);
16589 if(this.multiSelect || this.singleSelect){
16590 if(this.multiSelect && e.shiftKey && this.lastSelection){
16591 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
16593 this.select(item, this.multiSelect && e.ctrlKey);
16594 this.lastSelection = item;
16597 if(!this.tickable){
16598 e.preventDefault();
16606 * Get the number of selected nodes.
16609 getSelectionCount : function(){
16610 return this.selections.length;
16614 * Get the currently selected nodes.
16615 * @return {Array} An array of HTMLElements
16617 getSelectedNodes : function(){
16618 return this.selections;
16622 * Get the indexes of the selected nodes.
16625 getSelectedIndexes : function(){
16626 var indexes = [], s = this.selections;
16627 for(var i = 0, len = s.length; i < len; i++){
16628 indexes.push(s[i].nodeIndex);
16634 * Clear all selections
16635 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
16637 clearSelections : function(suppressEvent){
16638 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
16639 this.cmp.elements = this.selections;
16640 this.cmp.removeClass(this.selectedClass);
16641 this.selections = [];
16642 if(!suppressEvent){
16643 this.fireEvent("selectionchange", this, this.selections);
16649 * Returns true if the passed node is selected
16650 * @param {HTMLElement/Number} node The node or node index
16651 * @return {Boolean}
16653 isSelected : function(node){
16654 var s = this.selections;
16658 node = this.getNode(node);
16659 return s.indexOf(node) !== -1;
16664 * @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
16665 * @param {Boolean} keepExisting (optional) true to keep existing selections
16666 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16668 select : function(nodeInfo, keepExisting, suppressEvent){
16669 if(nodeInfo instanceof Array){
16671 this.clearSelections(true);
16673 for(var i = 0, len = nodeInfo.length; i < len; i++){
16674 this.select(nodeInfo[i], true, true);
16678 var node = this.getNode(nodeInfo);
16679 if(!node || this.isSelected(node)){
16680 return; // already selected.
16683 this.clearSelections(true);
16686 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
16687 Roo.fly(node).addClass(this.selectedClass);
16688 this.selections.push(node);
16689 if(!suppressEvent){
16690 this.fireEvent("selectionchange", this, this.selections);
16698 * @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
16699 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
16700 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16702 unselect : function(nodeInfo, keepExisting, suppressEvent)
16704 if(nodeInfo instanceof Array){
16705 Roo.each(this.selections, function(s) {
16706 this.unselect(s, nodeInfo);
16710 var node = this.getNode(nodeInfo);
16711 if(!node || !this.isSelected(node)){
16712 //Roo.log("not selected");
16713 return; // not selected.
16717 Roo.each(this.selections, function(s) {
16719 Roo.fly(node).removeClass(this.selectedClass);
16726 this.selections= ns;
16727 this.fireEvent("selectionchange", this, this.selections);
16731 * Gets a template node.
16732 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16733 * @return {HTMLElement} The node or null if it wasn't found
16735 getNode : function(nodeInfo){
16736 if(typeof nodeInfo == "string"){
16737 return document.getElementById(nodeInfo);
16738 }else if(typeof nodeInfo == "number"){
16739 return this.nodes[nodeInfo];
16745 * Gets a range template nodes.
16746 * @param {Number} startIndex
16747 * @param {Number} endIndex
16748 * @return {Array} An array of nodes
16750 getNodes : function(start, end){
16751 var ns = this.nodes;
16752 start = start || 0;
16753 end = typeof end == "undefined" ? ns.length - 1 : end;
16756 for(var i = start; i <= end; i++){
16760 for(var i = start; i >= end; i--){
16768 * Finds the index of the passed node
16769 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16770 * @return {Number} The index of the node or -1
16772 indexOf : function(node){
16773 node = this.getNode(node);
16774 if(typeof node.nodeIndex == "number"){
16775 return node.nodeIndex;
16777 var ns = this.nodes;
16778 for(var i = 0, len = ns.length; i < len; i++){
16789 * based on jquery fullcalendar
16793 Roo.bootstrap = Roo.bootstrap || {};
16795 * @class Roo.bootstrap.Calendar
16796 * @extends Roo.bootstrap.Component
16797 * Bootstrap Calendar class
16798 * @cfg {Boolean} loadMask (true|false) default false
16799 * @cfg {Object} header generate the user specific header of the calendar, default false
16802 * Create a new Container
16803 * @param {Object} config The config object
16808 Roo.bootstrap.Calendar = function(config){
16809 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
16813 * Fires when a date is selected
16814 * @param {DatePicker} this
16815 * @param {Date} date The selected date
16819 * @event monthchange
16820 * Fires when the displayed month changes
16821 * @param {DatePicker} this
16822 * @param {Date} date The selected month
16824 'monthchange': true,
16826 * @event evententer
16827 * Fires when mouse over an event
16828 * @param {Calendar} this
16829 * @param {event} Event
16831 'evententer': true,
16833 * @event eventleave
16834 * Fires when the mouse leaves an
16835 * @param {Calendar} this
16838 'eventleave': true,
16840 * @event eventclick
16841 * Fires when the mouse click an
16842 * @param {Calendar} this
16851 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
16854 * @cfg {Number} startDay
16855 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16863 getAutoCreate : function(){
16866 var fc_button = function(name, corner, style, content ) {
16867 return Roo.apply({},{
16869 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
16871 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
16874 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
16885 style : 'width:100%',
16892 cls : 'fc-header-left',
16894 fc_button('prev', 'left', 'arrow', '‹' ),
16895 fc_button('next', 'right', 'arrow', '›' ),
16896 { tag: 'span', cls: 'fc-header-space' },
16897 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
16905 cls : 'fc-header-center',
16909 cls: 'fc-header-title',
16912 html : 'month / year'
16920 cls : 'fc-header-right',
16922 /* fc_button('month', 'left', '', 'month' ),
16923 fc_button('week', '', '', 'week' ),
16924 fc_button('day', 'right', '', 'day' )
16936 header = this.header;
16939 var cal_heads = function() {
16941 // fixme - handle this.
16943 for (var i =0; i < Date.dayNames.length; i++) {
16944 var d = Date.dayNames[i];
16947 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
16948 html : d.substring(0,3)
16952 ret[0].cls += ' fc-first';
16953 ret[6].cls += ' fc-last';
16956 var cal_cell = function(n) {
16959 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
16964 cls: 'fc-day-number',
16968 cls: 'fc-day-content',
16972 style: 'position: relative;' // height: 17px;
16984 var cal_rows = function() {
16987 for (var r = 0; r < 6; r++) {
16994 for (var i =0; i < Date.dayNames.length; i++) {
16995 var d = Date.dayNames[i];
16996 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
16999 row.cn[0].cls+=' fc-first';
17000 row.cn[0].cn[0].style = 'min-height:90px';
17001 row.cn[6].cls+=' fc-last';
17005 ret[0].cls += ' fc-first';
17006 ret[4].cls += ' fc-prev-last';
17007 ret[5].cls += ' fc-last';
17014 cls: 'fc-border-separate',
17015 style : 'width:100%',
17023 cls : 'fc-first fc-last',
17041 cls : 'fc-content',
17042 style : "position: relative;",
17045 cls : 'fc-view fc-view-month fc-grid',
17046 style : 'position: relative',
17047 unselectable : 'on',
17050 cls : 'fc-event-container',
17051 style : 'position:absolute;z-index:8;top:0;left:0;'
17069 initEvents : function()
17072 throw "can not find store for calendar";
17078 style: "text-align:center",
17082 style: "background-color:white;width:50%;margin:250 auto",
17086 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
17097 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
17099 var size = this.el.select('.fc-content', true).first().getSize();
17100 this.maskEl.setSize(size.width, size.height);
17101 this.maskEl.enableDisplayMode("block");
17102 if(!this.loadMask){
17103 this.maskEl.hide();
17106 this.store = Roo.factory(this.store, Roo.data);
17107 this.store.on('load', this.onLoad, this);
17108 this.store.on('beforeload', this.onBeforeLoad, this);
17112 this.cells = this.el.select('.fc-day',true);
17113 //Roo.log(this.cells);
17114 this.textNodes = this.el.query('.fc-day-number');
17115 this.cells.addClassOnOver('fc-state-hover');
17117 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
17118 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
17119 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
17120 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
17122 this.on('monthchange', this.onMonthChange, this);
17124 this.update(new Date().clearTime());
17127 resize : function() {
17128 var sz = this.el.getSize();
17130 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
17131 this.el.select('.fc-day-content div',true).setHeight(34);
17136 showPrevMonth : function(e){
17137 this.update(this.activeDate.add("mo", -1));
17139 showToday : function(e){
17140 this.update(new Date().clearTime());
17143 showNextMonth : function(e){
17144 this.update(this.activeDate.add("mo", 1));
17148 showPrevYear : function(){
17149 this.update(this.activeDate.add("y", -1));
17153 showNextYear : function(){
17154 this.update(this.activeDate.add("y", 1));
17159 update : function(date)
17161 var vd = this.activeDate;
17162 this.activeDate = date;
17163 // if(vd && this.el){
17164 // var t = date.getTime();
17165 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
17166 // Roo.log('using add remove');
17168 // this.fireEvent('monthchange', this, date);
17170 // this.cells.removeClass("fc-state-highlight");
17171 // this.cells.each(function(c){
17172 // if(c.dateValue == t){
17173 // c.addClass("fc-state-highlight");
17174 // setTimeout(function(){
17175 // try{c.dom.firstChild.focus();}catch(e){}
17185 var days = date.getDaysInMonth();
17187 var firstOfMonth = date.getFirstDateOfMonth();
17188 var startingPos = firstOfMonth.getDay()-this.startDay;
17190 if(startingPos < this.startDay){
17194 var pm = date.add(Date.MONTH, -1);
17195 var prevStart = pm.getDaysInMonth()-startingPos;
17197 this.cells = this.el.select('.fc-day',true);
17198 this.textNodes = this.el.query('.fc-day-number');
17199 this.cells.addClassOnOver('fc-state-hover');
17201 var cells = this.cells.elements;
17202 var textEls = this.textNodes;
17204 Roo.each(cells, function(cell){
17205 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
17208 days += startingPos;
17210 // convert everything to numbers so it's fast
17211 var day = 86400000;
17212 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
17215 //Roo.log(prevStart);
17217 var today = new Date().clearTime().getTime();
17218 var sel = date.clearTime().getTime();
17219 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
17220 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
17221 var ddMatch = this.disabledDatesRE;
17222 var ddText = this.disabledDatesText;
17223 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
17224 var ddaysText = this.disabledDaysText;
17225 var format = this.format;
17227 var setCellClass = function(cal, cell){
17231 //Roo.log('set Cell Class');
17233 var t = d.getTime();
17237 cell.dateValue = t;
17239 cell.className += " fc-today";
17240 cell.className += " fc-state-highlight";
17241 cell.title = cal.todayText;
17244 // disable highlight in other month..
17245 //cell.className += " fc-state-highlight";
17250 cell.className = " fc-state-disabled";
17251 cell.title = cal.minText;
17255 cell.className = " fc-state-disabled";
17256 cell.title = cal.maxText;
17260 if(ddays.indexOf(d.getDay()) != -1){
17261 cell.title = ddaysText;
17262 cell.className = " fc-state-disabled";
17265 if(ddMatch && format){
17266 var fvalue = d.dateFormat(format);
17267 if(ddMatch.test(fvalue)){
17268 cell.title = ddText.replace("%0", fvalue);
17269 cell.className = " fc-state-disabled";
17273 if (!cell.initialClassName) {
17274 cell.initialClassName = cell.dom.className;
17277 cell.dom.className = cell.initialClassName + ' ' + cell.className;
17282 for(; i < startingPos; i++) {
17283 textEls[i].innerHTML = (++prevStart);
17284 d.setDate(d.getDate()+1);
17286 cells[i].className = "fc-past fc-other-month";
17287 setCellClass(this, cells[i]);
17292 for(; i < days; i++){
17293 intDay = i - startingPos + 1;
17294 textEls[i].innerHTML = (intDay);
17295 d.setDate(d.getDate()+1);
17297 cells[i].className = ''; // "x-date-active";
17298 setCellClass(this, cells[i]);
17302 for(; i < 42; i++) {
17303 textEls[i].innerHTML = (++extraDays);
17304 d.setDate(d.getDate()+1);
17306 cells[i].className = "fc-future fc-other-month";
17307 setCellClass(this, cells[i]);
17310 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
17312 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
17314 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
17315 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
17317 if(totalRows != 6){
17318 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
17319 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
17322 this.fireEvent('monthchange', this, date);
17326 if(!this.internalRender){
17327 var main = this.el.dom.firstChild;
17328 var w = main.offsetWidth;
17329 this.el.setWidth(w + this.el.getBorderWidth("lr"));
17330 Roo.fly(main).setWidth(w);
17331 this.internalRender = true;
17332 // opera does not respect the auto grow header center column
17333 // then, after it gets a width opera refuses to recalculate
17334 // without a second pass
17335 if(Roo.isOpera && !this.secondPass){
17336 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
17337 this.secondPass = true;
17338 this.update.defer(10, this, [date]);
17345 findCell : function(dt) {
17346 dt = dt.clearTime().getTime();
17348 this.cells.each(function(c){
17349 //Roo.log("check " +c.dateValue + '?=' + dt);
17350 if(c.dateValue == dt){
17360 findCells : function(ev) {
17361 var s = ev.start.clone().clearTime().getTime();
17363 var e= ev.end.clone().clearTime().getTime();
17366 this.cells.each(function(c){
17367 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
17369 if(c.dateValue > e){
17372 if(c.dateValue < s){
17381 // findBestRow: function(cells)
17385 // for (var i =0 ; i < cells.length;i++) {
17386 // ret = Math.max(cells[i].rows || 0,ret);
17393 addItem : function(ev)
17395 // look for vertical location slot in
17396 var cells = this.findCells(ev);
17398 // ev.row = this.findBestRow(cells);
17400 // work out the location.
17404 for(var i =0; i < cells.length; i++) {
17406 cells[i].row = cells[0].row;
17409 cells[i].row = cells[i].row + 1;
17419 if (crow.start.getY() == cells[i].getY()) {
17421 crow.end = cells[i];
17438 cells[0].events.push(ev);
17440 this.calevents.push(ev);
17443 clearEvents: function() {
17445 if(!this.calevents){
17449 Roo.each(this.cells.elements, function(c){
17455 Roo.each(this.calevents, function(e) {
17456 Roo.each(e.els, function(el) {
17457 el.un('mouseenter' ,this.onEventEnter, this);
17458 el.un('mouseleave' ,this.onEventLeave, this);
17463 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
17469 renderEvents: function()
17473 this.cells.each(function(c) {
17482 if(c.row != c.events.length){
17483 r = 4 - (4 - (c.row - c.events.length));
17486 c.events = ev.slice(0, r);
17487 c.more = ev.slice(r);
17489 if(c.more.length && c.more.length == 1){
17490 c.events.push(c.more.pop());
17493 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
17497 this.cells.each(function(c) {
17499 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
17502 for (var e = 0; e < c.events.length; e++){
17503 var ev = c.events[e];
17504 var rows = ev.rows;
17506 for(var i = 0; i < rows.length; i++) {
17508 // how many rows should it span..
17511 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
17512 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
17514 unselectable : "on",
17517 cls: 'fc-event-inner',
17521 // cls: 'fc-event-time',
17522 // html : cells.length > 1 ? '' : ev.time
17526 cls: 'fc-event-title',
17527 html : String.format('{0}', ev.title)
17534 cls: 'ui-resizable-handle ui-resizable-e',
17535 html : '  '
17542 cfg.cls += ' fc-event-start';
17544 if ((i+1) == rows.length) {
17545 cfg.cls += ' fc-event-end';
17548 var ctr = _this.el.select('.fc-event-container',true).first();
17549 var cg = ctr.createChild(cfg);
17551 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
17552 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
17554 var r = (c.more.length) ? 1 : 0;
17555 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
17556 cg.setWidth(ebox.right - sbox.x -2);
17558 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
17559 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
17560 cg.on('click', _this.onEventClick, _this, ev);
17571 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
17572 style : 'position: absolute',
17573 unselectable : "on",
17576 cls: 'fc-event-inner',
17580 cls: 'fc-event-title',
17588 cls: 'ui-resizable-handle ui-resizable-e',
17589 html : '  '
17595 var ctr = _this.el.select('.fc-event-container',true).first();
17596 var cg = ctr.createChild(cfg);
17598 var sbox = c.select('.fc-day-content',true).first().getBox();
17599 var ebox = c.select('.fc-day-content',true).first().getBox();
17601 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
17602 cg.setWidth(ebox.right - sbox.x -2);
17604 cg.on('click', _this.onMoreEventClick, _this, c.more);
17614 onEventEnter: function (e, el,event,d) {
17615 this.fireEvent('evententer', this, el, event);
17618 onEventLeave: function (e, el,event,d) {
17619 this.fireEvent('eventleave', this, el, event);
17622 onEventClick: function (e, el,event,d) {
17623 this.fireEvent('eventclick', this, el, event);
17626 onMonthChange: function () {
17630 onMoreEventClick: function(e, el, more)
17634 this.calpopover.placement = 'right';
17635 this.calpopover.setTitle('More');
17637 this.calpopover.setContent('');
17639 var ctr = this.calpopover.el.select('.popover-content', true).first();
17641 Roo.each(more, function(m){
17643 cls : 'fc-event-hori fc-event-draggable',
17646 var cg = ctr.createChild(cfg);
17648 cg.on('click', _this.onEventClick, _this, m);
17651 this.calpopover.show(el);
17656 onLoad: function ()
17658 this.calevents = [];
17661 if(this.store.getCount() > 0){
17662 this.store.data.each(function(d){
17665 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
17666 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
17667 time : d.data.start_time,
17668 title : d.data.title,
17669 description : d.data.description,
17670 venue : d.data.venue
17675 this.renderEvents();
17677 if(this.calevents.length && this.loadMask){
17678 this.maskEl.hide();
17682 onBeforeLoad: function()
17684 this.clearEvents();
17686 this.maskEl.show();
17700 * @class Roo.bootstrap.Popover
17701 * @extends Roo.bootstrap.Component
17702 * Bootstrap Popover class
17703 * @cfg {String} html contents of the popover (or false to use children..)
17704 * @cfg {String} title of popover (or false to hide)
17705 * @cfg {String} placement how it is placed
17706 * @cfg {String} trigger click || hover (or false to trigger manually)
17707 * @cfg {String} over what (parent or false to trigger manually.)
17708 * @cfg {Number} delay - delay before showing
17711 * Create a new Popover
17712 * @param {Object} config The config object
17715 Roo.bootstrap.Popover = function(config){
17716 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
17722 * After the popover show
17724 * @param {Roo.bootstrap.Popover} this
17729 * After the popover hide
17731 * @param {Roo.bootstrap.Popover} this
17737 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
17739 title: 'Fill in a title',
17742 placement : 'right',
17743 trigger : 'hover', // hover
17749 can_build_overlaid : false,
17751 getChildContainer : function()
17753 return this.el.select('.popover-content',true).first();
17756 getAutoCreate : function(){
17759 cls : 'popover roo-dynamic',
17760 style: 'display:block',
17766 cls : 'popover-inner',
17770 cls: 'popover-title popover-header',
17774 cls : 'popover-content popover-body',
17785 setTitle: function(str)
17788 this.el.select('.popover-title',true).first().dom.innerHTML = str;
17790 setContent: function(str)
17793 this.el.select('.popover-content',true).first().dom.innerHTML = str;
17795 // as it get's added to the bottom of the page.
17796 onRender : function(ct, position)
17798 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17800 var cfg = Roo.apply({}, this.getAutoCreate());
17804 cfg.cls += ' ' + this.cls;
17807 cfg.style = this.style;
17809 //Roo.log("adding to ");
17810 this.el = Roo.get(document.body).createChild(cfg, position);
17811 // Roo.log(this.el);
17816 initEvents : function()
17818 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
17819 this.el.enableDisplayMode('block');
17821 if (this.over === false) {
17824 if (this.triggers === false) {
17827 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17828 var triggers = this.trigger ? this.trigger.split(' ') : [];
17829 Roo.each(triggers, function(trigger) {
17831 if (trigger == 'click') {
17832 on_el.on('click', this.toggle, this);
17833 } else if (trigger != 'manual') {
17834 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
17835 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
17837 on_el.on(eventIn ,this.enter, this);
17838 on_el.on(eventOut, this.leave, this);
17849 toggle : function () {
17850 this.hoverState == 'in' ? this.leave() : this.enter();
17853 enter : function () {
17855 clearTimeout(this.timeout);
17857 this.hoverState = 'in';
17859 if (!this.delay || !this.delay.show) {
17864 this.timeout = setTimeout(function () {
17865 if (_t.hoverState == 'in') {
17868 }, this.delay.show)
17871 leave : function() {
17872 clearTimeout(this.timeout);
17874 this.hoverState = 'out';
17876 if (!this.delay || !this.delay.hide) {
17881 this.timeout = setTimeout(function () {
17882 if (_t.hoverState == 'out') {
17885 }, this.delay.hide)
17888 show : function (on_el)
17891 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17895 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
17896 if (this.html !== false) {
17897 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
17899 this.el.removeClass([
17900 'fade','top','bottom', 'left', 'right','in',
17901 'bs-popover-top','bs-popover-bottom', 'bs-popover-left', 'bs-popover-right'
17903 if (!this.title.length) {
17904 this.el.select('.popover-title',true).hide();
17907 var placement = typeof this.placement == 'function' ?
17908 this.placement.call(this, this.el, on_el) :
17911 var autoToken = /\s?auto?\s?/i;
17912 var autoPlace = autoToken.test(placement);
17914 placement = placement.replace(autoToken, '') || 'top';
17918 //this.el.setXY([0,0]);
17920 this.el.dom.style.display='block';
17921 this.el.addClass(placement);
17923 //this.el.appendTo(on_el);
17925 var p = this.getPosition();
17926 var box = this.el.getBox();
17931 var align = Roo.bootstrap.Popover.alignment[placement];
17934 this.el.alignTo(on_el, align[0],align[1]);
17935 //var arrow = this.el.select('.arrow',true).first();
17936 //arrow.set(align[2],
17938 this.el.addClass('in');
17941 if (this.el.hasClass('fade')) {
17945 this.hoverState = 'in';
17947 this.fireEvent('show', this);
17952 this.el.setXY([0,0]);
17953 this.el.removeClass('in');
17955 this.hoverState = null;
17957 this.fireEvent('hide', this);
17962 Roo.bootstrap.Popover.alignment = {
17963 'left' : ['r-l', [-10,0], 'right bs-popover-right'],
17964 'right' : ['l-r', [10,0], 'left bs-popover-left'],
17965 'bottom' : ['t-b', [0,10], 'top bs-popover-top'],
17966 'top' : [ 'b-t', [0,-10], 'bottom bs-popover-bottom']
17977 * @class Roo.bootstrap.Progress
17978 * @extends Roo.bootstrap.Component
17979 * Bootstrap Progress class
17980 * @cfg {Boolean} striped striped of the progress bar
17981 * @cfg {Boolean} active animated of the progress bar
17985 * Create a new Progress
17986 * @param {Object} config The config object
17989 Roo.bootstrap.Progress = function(config){
17990 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
17993 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
17998 getAutoCreate : function(){
18006 cfg.cls += ' progress-striped';
18010 cfg.cls += ' active';
18029 * @class Roo.bootstrap.ProgressBar
18030 * @extends Roo.bootstrap.Component
18031 * Bootstrap ProgressBar class
18032 * @cfg {Number} aria_valuenow aria-value now
18033 * @cfg {Number} aria_valuemin aria-value min
18034 * @cfg {Number} aria_valuemax aria-value max
18035 * @cfg {String} label label for the progress bar
18036 * @cfg {String} panel (success | info | warning | danger )
18037 * @cfg {String} role role of the progress bar
18038 * @cfg {String} sr_only text
18042 * Create a new ProgressBar
18043 * @param {Object} config The config object
18046 Roo.bootstrap.ProgressBar = function(config){
18047 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
18050 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
18054 aria_valuemax : 100,
18060 getAutoCreate : function()
18065 cls: 'progress-bar',
18066 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
18078 cfg.role = this.role;
18081 if(this.aria_valuenow){
18082 cfg['aria-valuenow'] = this.aria_valuenow;
18085 if(this.aria_valuemin){
18086 cfg['aria-valuemin'] = this.aria_valuemin;
18089 if(this.aria_valuemax){
18090 cfg['aria-valuemax'] = this.aria_valuemax;
18093 if(this.label && !this.sr_only){
18094 cfg.html = this.label;
18098 cfg.cls += ' progress-bar-' + this.panel;
18104 update : function(aria_valuenow)
18106 this.aria_valuenow = aria_valuenow;
18108 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
18123 * @class Roo.bootstrap.TabGroup
18124 * @extends Roo.bootstrap.Column
18125 * Bootstrap Column class
18126 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
18127 * @cfg {Boolean} carousel true to make the group behave like a carousel
18128 * @cfg {Boolean} bullets show bullets for the panels
18129 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
18130 * @cfg {Number} timer auto slide timer .. default 0 millisecond
18131 * @cfg {Boolean} showarrow (true|false) show arrow default true
18134 * Create a new TabGroup
18135 * @param {Object} config The config object
18138 Roo.bootstrap.TabGroup = function(config){
18139 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
18141 this.navId = Roo.id();
18144 Roo.bootstrap.TabGroup.register(this);
18148 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
18151 transition : false,
18156 slideOnTouch : false,
18159 getAutoCreate : function()
18161 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
18163 cfg.cls += ' tab-content';
18165 if (this.carousel) {
18166 cfg.cls += ' carousel slide';
18169 cls : 'carousel-inner',
18173 if(this.bullets && !Roo.isTouch){
18176 cls : 'carousel-bullets',
18180 if(this.bullets_cls){
18181 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
18188 cfg.cn[0].cn.push(bullets);
18191 if(this.showarrow){
18192 cfg.cn[0].cn.push({
18194 class : 'carousel-arrow',
18198 class : 'carousel-prev',
18202 class : 'fa fa-chevron-left'
18208 class : 'carousel-next',
18212 class : 'fa fa-chevron-right'
18225 initEvents: function()
18227 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
18228 // this.el.on("touchstart", this.onTouchStart, this);
18231 if(this.autoslide){
18234 this.slideFn = window.setInterval(function() {
18235 _this.showPanelNext();
18239 if(this.showarrow){
18240 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
18241 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
18247 // onTouchStart : function(e, el, o)
18249 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
18253 // this.showPanelNext();
18257 getChildContainer : function()
18259 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
18263 * register a Navigation item
18264 * @param {Roo.bootstrap.NavItem} the navitem to add
18266 register : function(item)
18268 this.tabs.push( item);
18269 item.navId = this.navId; // not really needed..
18274 getActivePanel : function()
18277 Roo.each(this.tabs, function(t) {
18287 getPanelByName : function(n)
18290 Roo.each(this.tabs, function(t) {
18291 if (t.tabId == n) {
18299 indexOfPanel : function(p)
18302 Roo.each(this.tabs, function(t,i) {
18303 if (t.tabId == p.tabId) {
18312 * show a specific panel
18313 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
18314 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
18316 showPanel : function (pan)
18318 if(this.transition || typeof(pan) == 'undefined'){
18319 Roo.log("waiting for the transitionend");
18323 if (typeof(pan) == 'number') {
18324 pan = this.tabs[pan];
18327 if (typeof(pan) == 'string') {
18328 pan = this.getPanelByName(pan);
18331 var cur = this.getActivePanel();
18334 Roo.log('pan or acitve pan is undefined');
18338 if (pan.tabId == this.getActivePanel().tabId) {
18342 if (false === cur.fireEvent('beforedeactivate')) {
18346 if(this.bullets > 0 && !Roo.isTouch){
18347 this.setActiveBullet(this.indexOfPanel(pan));
18350 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
18352 this.transition = true;
18353 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
18354 var lr = dir == 'next' ? 'left' : 'right';
18355 pan.el.addClass(dir); // or prev
18356 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
18357 cur.el.addClass(lr); // or right
18358 pan.el.addClass(lr);
18361 cur.el.on('transitionend', function() {
18362 Roo.log("trans end?");
18364 pan.el.removeClass([lr,dir]);
18365 pan.setActive(true);
18367 cur.el.removeClass([lr]);
18368 cur.setActive(false);
18370 _this.transition = false;
18372 }, this, { single: true } );
18377 cur.setActive(false);
18378 pan.setActive(true);
18383 showPanelNext : function()
18385 var i = this.indexOfPanel(this.getActivePanel());
18387 if (i >= this.tabs.length - 1 && !this.autoslide) {
18391 if (i >= this.tabs.length - 1 && this.autoslide) {
18395 this.showPanel(this.tabs[i+1]);
18398 showPanelPrev : function()
18400 var i = this.indexOfPanel(this.getActivePanel());
18402 if (i < 1 && !this.autoslide) {
18406 if (i < 1 && this.autoslide) {
18407 i = this.tabs.length;
18410 this.showPanel(this.tabs[i-1]);
18414 addBullet: function()
18416 if(!this.bullets || Roo.isTouch){
18419 var ctr = this.el.select('.carousel-bullets',true).first();
18420 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
18421 var bullet = ctr.createChild({
18422 cls : 'bullet bullet-' + i
18423 },ctr.dom.lastChild);
18428 bullet.on('click', (function(e, el, o, ii, t){
18430 e.preventDefault();
18432 this.showPanel(ii);
18434 if(this.autoslide && this.slideFn){
18435 clearInterval(this.slideFn);
18436 this.slideFn = window.setInterval(function() {
18437 _this.showPanelNext();
18441 }).createDelegate(this, [i, bullet], true));
18446 setActiveBullet : function(i)
18452 Roo.each(this.el.select('.bullet', true).elements, function(el){
18453 el.removeClass('selected');
18456 var bullet = this.el.select('.bullet-' + i, true).first();
18462 bullet.addClass('selected');
18473 Roo.apply(Roo.bootstrap.TabGroup, {
18477 * register a Navigation Group
18478 * @param {Roo.bootstrap.NavGroup} the navgroup to add
18480 register : function(navgrp)
18482 this.groups[navgrp.navId] = navgrp;
18486 * fetch a Navigation Group based on the navigation ID
18487 * if one does not exist , it will get created.
18488 * @param {string} the navgroup to add
18489 * @returns {Roo.bootstrap.NavGroup} the navgroup
18491 get: function(navId) {
18492 if (typeof(this.groups[navId]) == 'undefined') {
18493 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
18495 return this.groups[navId] ;
18510 * @class Roo.bootstrap.TabPanel
18511 * @extends Roo.bootstrap.Component
18512 * Bootstrap TabPanel class
18513 * @cfg {Boolean} active panel active
18514 * @cfg {String} html panel content
18515 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
18516 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
18517 * @cfg {String} href click to link..
18521 * Create a new TabPanel
18522 * @param {Object} config The config object
18525 Roo.bootstrap.TabPanel = function(config){
18526 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
18530 * Fires when the active status changes
18531 * @param {Roo.bootstrap.TabPanel} this
18532 * @param {Boolean} state the new state
18537 * @event beforedeactivate
18538 * Fires before a tab is de-activated - can be used to do validation on a form.
18539 * @param {Roo.bootstrap.TabPanel} this
18540 * @return {Boolean} false if there is an error
18543 'beforedeactivate': true
18546 this.tabId = this.tabId || Roo.id();
18550 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
18558 getAutoCreate : function(){
18561 // item is needed for carousel - not sure if it has any effect otherwise
18562 cls: 'tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
18563 html: this.html || ''
18567 cfg.cls += ' active';
18571 cfg.tabId = this.tabId;
18578 initEvents: function()
18580 var p = this.parent();
18582 this.navId = this.navId || p.navId;
18584 if (typeof(this.navId) != 'undefined') {
18585 // not really needed.. but just in case.. parent should be a NavGroup.
18586 var tg = Roo.bootstrap.TabGroup.get(this.navId);
18590 var i = tg.tabs.length - 1;
18592 if(this.active && tg.bullets > 0 && i < tg.bullets){
18593 tg.setActiveBullet(i);
18597 this.el.on('click', this.onClick, this);
18600 this.el.on("touchstart", this.onTouchStart, this);
18601 this.el.on("touchmove", this.onTouchMove, this);
18602 this.el.on("touchend", this.onTouchEnd, this);
18607 onRender : function(ct, position)
18609 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
18612 setActive : function(state)
18614 Roo.log("panel - set active " + this.tabId + "=" + state);
18616 this.active = state;
18618 this.el.removeClass('active');
18620 } else if (!this.el.hasClass('active')) {
18621 this.el.addClass('active');
18624 this.fireEvent('changed', this, state);
18627 onClick : function(e)
18629 e.preventDefault();
18631 if(!this.href.length){
18635 window.location.href = this.href;
18644 onTouchStart : function(e)
18646 this.swiping = false;
18648 this.startX = e.browserEvent.touches[0].clientX;
18649 this.startY = e.browserEvent.touches[0].clientY;
18652 onTouchMove : function(e)
18654 this.swiping = true;
18656 this.endX = e.browserEvent.touches[0].clientX;
18657 this.endY = e.browserEvent.touches[0].clientY;
18660 onTouchEnd : function(e)
18667 var tabGroup = this.parent();
18669 if(this.endX > this.startX){ // swiping right
18670 tabGroup.showPanelPrev();
18674 if(this.startX > this.endX){ // swiping left
18675 tabGroup.showPanelNext();
18694 * @class Roo.bootstrap.DateField
18695 * @extends Roo.bootstrap.Input
18696 * Bootstrap DateField class
18697 * @cfg {Number} weekStart default 0
18698 * @cfg {String} viewMode default empty, (months|years)
18699 * @cfg {String} minViewMode default empty, (months|years)
18700 * @cfg {Number} startDate default -Infinity
18701 * @cfg {Number} endDate default Infinity
18702 * @cfg {Boolean} todayHighlight default false
18703 * @cfg {Boolean} todayBtn default false
18704 * @cfg {Boolean} calendarWeeks default false
18705 * @cfg {Object} daysOfWeekDisabled default empty
18706 * @cfg {Boolean} singleMode default false (true | false)
18708 * @cfg {Boolean} keyboardNavigation default true
18709 * @cfg {String} language default en
18712 * Create a new DateField
18713 * @param {Object} config The config object
18716 Roo.bootstrap.DateField = function(config){
18717 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
18721 * Fires when this field show.
18722 * @param {Roo.bootstrap.DateField} this
18723 * @param {Mixed} date The date value
18728 * Fires when this field hide.
18729 * @param {Roo.bootstrap.DateField} this
18730 * @param {Mixed} date The date value
18735 * Fires when select a date.
18736 * @param {Roo.bootstrap.DateField} this
18737 * @param {Mixed} date The date value
18741 * @event beforeselect
18742 * Fires when before select a date.
18743 * @param {Roo.bootstrap.DateField} this
18744 * @param {Mixed} date The date value
18746 beforeselect : true
18750 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
18753 * @cfg {String} format
18754 * The default date format string which can be overriden for localization support. The format must be
18755 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
18759 * @cfg {String} altFormats
18760 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
18761 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
18763 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
18771 todayHighlight : false,
18777 keyboardNavigation: true,
18779 calendarWeeks: false,
18781 startDate: -Infinity,
18785 daysOfWeekDisabled: [],
18789 singleMode : false,
18791 UTCDate: function()
18793 return new Date(Date.UTC.apply(Date, arguments));
18796 UTCToday: function()
18798 var today = new Date();
18799 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
18802 getDate: function() {
18803 var d = this.getUTCDate();
18804 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
18807 getUTCDate: function() {
18811 setDate: function(d) {
18812 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
18815 setUTCDate: function(d) {
18817 this.setValue(this.formatDate(this.date));
18820 onRender: function(ct, position)
18823 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
18825 this.language = this.language || 'en';
18826 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
18827 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
18829 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
18830 this.format = this.format || 'm/d/y';
18831 this.isInline = false;
18832 this.isInput = true;
18833 this.component = this.el.select('.add-on', true).first() || false;
18834 this.component = (this.component && this.component.length === 0) ? false : this.component;
18835 this.hasInput = this.component && this.inputEl().length;
18837 if (typeof(this.minViewMode === 'string')) {
18838 switch (this.minViewMode) {
18840 this.minViewMode = 1;
18843 this.minViewMode = 2;
18846 this.minViewMode = 0;
18851 if (typeof(this.viewMode === 'string')) {
18852 switch (this.viewMode) {
18865 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
18867 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
18869 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18871 this.picker().on('mousedown', this.onMousedown, this);
18872 this.picker().on('click', this.onClick, this);
18874 this.picker().addClass('datepicker-dropdown');
18876 this.startViewMode = this.viewMode;
18878 if(this.singleMode){
18879 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
18880 v.setVisibilityMode(Roo.Element.DISPLAY);
18884 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
18885 v.setStyle('width', '189px');
18889 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
18890 if(!this.calendarWeeks){
18895 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18896 v.attr('colspan', function(i, val){
18897 return parseInt(val) + 1;
18902 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
18904 this.setStartDate(this.startDate);
18905 this.setEndDate(this.endDate);
18907 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
18914 if(this.isInline) {
18919 picker : function()
18921 return this.pickerEl;
18922 // return this.el.select('.datepicker', true).first();
18925 fillDow: function()
18927 var dowCnt = this.weekStart;
18936 if(this.calendarWeeks){
18944 while (dowCnt < this.weekStart + 7) {
18948 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
18952 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
18955 fillMonths: function()
18958 var months = this.picker().select('>.datepicker-months td', true).first();
18960 months.dom.innerHTML = '';
18966 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
18969 months.createChild(month);
18976 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;
18978 if (this.date < this.startDate) {
18979 this.viewDate = new Date(this.startDate);
18980 } else if (this.date > this.endDate) {
18981 this.viewDate = new Date(this.endDate);
18983 this.viewDate = new Date(this.date);
18991 var d = new Date(this.viewDate),
18992 year = d.getUTCFullYear(),
18993 month = d.getUTCMonth(),
18994 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
18995 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
18996 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
18997 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
18998 currentDate = this.date && this.date.valueOf(),
18999 today = this.UTCToday();
19001 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
19003 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
19005 // this.picker.select('>tfoot th.today').
19006 // .text(dates[this.language].today)
19007 // .toggle(this.todayBtn !== false);
19009 this.updateNavArrows();
19012 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
19014 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
19016 prevMonth.setUTCDate(day);
19018 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
19020 var nextMonth = new Date(prevMonth);
19022 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
19024 nextMonth = nextMonth.valueOf();
19026 var fillMonths = false;
19028 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
19030 while(prevMonth.valueOf() <= nextMonth) {
19033 if (prevMonth.getUTCDay() === this.weekStart) {
19035 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
19043 if(this.calendarWeeks){
19044 // ISO 8601: First week contains first thursday.
19045 // ISO also states week starts on Monday, but we can be more abstract here.
19047 // Start of current week: based on weekstart/current date
19048 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
19049 // Thursday of this week
19050 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
19051 // First Thursday of year, year from thursday
19052 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
19053 // Calendar week: ms between thursdays, div ms per day, div 7 days
19054 calWeek = (th - yth) / 864e5 / 7 + 1;
19056 fillMonths.cn.push({
19064 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
19066 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
19069 if (this.todayHighlight &&
19070 prevMonth.getUTCFullYear() == today.getFullYear() &&
19071 prevMonth.getUTCMonth() == today.getMonth() &&
19072 prevMonth.getUTCDate() == today.getDate()) {
19073 clsName += ' today';
19076 if (currentDate && prevMonth.valueOf() === currentDate) {
19077 clsName += ' active';
19080 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
19081 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
19082 clsName += ' disabled';
19085 fillMonths.cn.push({
19087 cls: 'day ' + clsName,
19088 html: prevMonth.getDate()
19091 prevMonth.setDate(prevMonth.getDate()+1);
19094 var currentYear = this.date && this.date.getUTCFullYear();
19095 var currentMonth = this.date && this.date.getUTCMonth();
19097 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
19099 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
19100 v.removeClass('active');
19102 if(currentYear === year && k === currentMonth){
19103 v.addClass('active');
19106 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
19107 v.addClass('disabled');
19113 year = parseInt(year/10, 10) * 10;
19115 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
19117 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
19120 for (var i = -1; i < 11; i++) {
19121 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
19123 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
19131 showMode: function(dir)
19134 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
19137 Roo.each(this.picker().select('>div',true).elements, function(v){
19138 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19141 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
19146 if(this.isInline) {
19150 this.picker().removeClass(['bottom', 'top']);
19152 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
19154 * place to the top of element!
19158 this.picker().addClass('top');
19159 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
19164 this.picker().addClass('bottom');
19166 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
19169 parseDate : function(value)
19171 if(!value || value instanceof Date){
19174 var v = Date.parseDate(value, this.format);
19175 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
19176 v = Date.parseDate(value, 'Y-m-d');
19178 if(!v && this.altFormats){
19179 if(!this.altFormatsArray){
19180 this.altFormatsArray = this.altFormats.split("|");
19182 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
19183 v = Date.parseDate(value, this.altFormatsArray[i]);
19189 formatDate : function(date, fmt)
19191 return (!date || !(date instanceof Date)) ?
19192 date : date.dateFormat(fmt || this.format);
19195 onFocus : function()
19197 Roo.bootstrap.DateField.superclass.onFocus.call(this);
19201 onBlur : function()
19203 Roo.bootstrap.DateField.superclass.onBlur.call(this);
19205 var d = this.inputEl().getValue();
19212 showPopup : function()
19214 this.picker().show();
19218 this.fireEvent('showpopup', this, this.date);
19221 hidePopup : function()
19223 if(this.isInline) {
19226 this.picker().hide();
19227 this.viewMode = this.startViewMode;
19230 this.fireEvent('hidepopup', this, this.date);
19234 onMousedown: function(e)
19236 e.stopPropagation();
19237 e.preventDefault();
19242 Roo.bootstrap.DateField.superclass.keyup.call(this);
19246 setValue: function(v)
19248 if(this.fireEvent('beforeselect', this, v) !== false){
19249 var d = new Date(this.parseDate(v) ).clearTime();
19251 if(isNaN(d.getTime())){
19252 this.date = this.viewDate = '';
19253 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
19257 v = this.formatDate(d);
19259 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
19261 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
19265 this.fireEvent('select', this, this.date);
19269 getValue: function()
19271 return this.formatDate(this.date);
19274 fireKey: function(e)
19276 if (!this.picker().isVisible()){
19277 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19283 var dateChanged = false,
19285 newDate, newViewDate;
19290 e.preventDefault();
19294 if (!this.keyboardNavigation) {
19297 dir = e.keyCode == 37 ? -1 : 1;
19300 newDate = this.moveYear(this.date, dir);
19301 newViewDate = this.moveYear(this.viewDate, dir);
19302 } else if (e.shiftKey){
19303 newDate = this.moveMonth(this.date, dir);
19304 newViewDate = this.moveMonth(this.viewDate, dir);
19306 newDate = new Date(this.date);
19307 newDate.setUTCDate(this.date.getUTCDate() + dir);
19308 newViewDate = new Date(this.viewDate);
19309 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
19311 if (this.dateWithinRange(newDate)){
19312 this.date = newDate;
19313 this.viewDate = newViewDate;
19314 this.setValue(this.formatDate(this.date));
19316 e.preventDefault();
19317 dateChanged = true;
19322 if (!this.keyboardNavigation) {
19325 dir = e.keyCode == 38 ? -1 : 1;
19327 newDate = this.moveYear(this.date, dir);
19328 newViewDate = this.moveYear(this.viewDate, dir);
19329 } else if (e.shiftKey){
19330 newDate = this.moveMonth(this.date, dir);
19331 newViewDate = this.moveMonth(this.viewDate, dir);
19333 newDate = new Date(this.date);
19334 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
19335 newViewDate = new Date(this.viewDate);
19336 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
19338 if (this.dateWithinRange(newDate)){
19339 this.date = newDate;
19340 this.viewDate = newViewDate;
19341 this.setValue(this.formatDate(this.date));
19343 e.preventDefault();
19344 dateChanged = true;
19348 this.setValue(this.formatDate(this.date));
19350 e.preventDefault();
19353 this.setValue(this.formatDate(this.date));
19367 onClick: function(e)
19369 e.stopPropagation();
19370 e.preventDefault();
19372 var target = e.getTarget();
19374 if(target.nodeName.toLowerCase() === 'i'){
19375 target = Roo.get(target).dom.parentNode;
19378 var nodeName = target.nodeName;
19379 var className = target.className;
19380 var html = target.innerHTML;
19381 //Roo.log(nodeName);
19383 switch(nodeName.toLowerCase()) {
19385 switch(className) {
19391 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
19392 switch(this.viewMode){
19394 this.viewDate = this.moveMonth(this.viewDate, dir);
19398 this.viewDate = this.moveYear(this.viewDate, dir);
19404 var date = new Date();
19405 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
19407 this.setValue(this.formatDate(this.date));
19414 if (className.indexOf('disabled') < 0) {
19415 this.viewDate.setUTCDate(1);
19416 if (className.indexOf('month') > -1) {
19417 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
19419 var year = parseInt(html, 10) || 0;
19420 this.viewDate.setUTCFullYear(year);
19424 if(this.singleMode){
19425 this.setValue(this.formatDate(this.viewDate));
19436 //Roo.log(className);
19437 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
19438 var day = parseInt(html, 10) || 1;
19439 var year = this.viewDate.getUTCFullYear(),
19440 month = this.viewDate.getUTCMonth();
19442 if (className.indexOf('old') > -1) {
19449 } else if (className.indexOf('new') > -1) {
19457 //Roo.log([year,month,day]);
19458 this.date = this.UTCDate(year, month, day,0,0,0,0);
19459 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
19461 //Roo.log(this.formatDate(this.date));
19462 this.setValue(this.formatDate(this.date));
19469 setStartDate: function(startDate)
19471 this.startDate = startDate || -Infinity;
19472 if (this.startDate !== -Infinity) {
19473 this.startDate = this.parseDate(this.startDate);
19476 this.updateNavArrows();
19479 setEndDate: function(endDate)
19481 this.endDate = endDate || Infinity;
19482 if (this.endDate !== Infinity) {
19483 this.endDate = this.parseDate(this.endDate);
19486 this.updateNavArrows();
19489 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
19491 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
19492 if (typeof(this.daysOfWeekDisabled) !== 'object') {
19493 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
19495 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
19496 return parseInt(d, 10);
19499 this.updateNavArrows();
19502 updateNavArrows: function()
19504 if(this.singleMode){
19508 var d = new Date(this.viewDate),
19509 year = d.getUTCFullYear(),
19510 month = d.getUTCMonth();
19512 Roo.each(this.picker().select('.prev', true).elements, function(v){
19514 switch (this.viewMode) {
19517 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
19523 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
19530 Roo.each(this.picker().select('.next', true).elements, function(v){
19532 switch (this.viewMode) {
19535 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
19541 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
19549 moveMonth: function(date, dir)
19554 var new_date = new Date(date.valueOf()),
19555 day = new_date.getUTCDate(),
19556 month = new_date.getUTCMonth(),
19557 mag = Math.abs(dir),
19559 dir = dir > 0 ? 1 : -1;
19562 // If going back one month, make sure month is not current month
19563 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
19565 return new_date.getUTCMonth() == month;
19567 // If going forward one month, make sure month is as expected
19568 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
19570 return new_date.getUTCMonth() != new_month;
19572 new_month = month + dir;
19573 new_date.setUTCMonth(new_month);
19574 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
19575 if (new_month < 0 || new_month > 11) {
19576 new_month = (new_month + 12) % 12;
19579 // For magnitudes >1, move one month at a time...
19580 for (var i=0; i<mag; i++) {
19581 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
19582 new_date = this.moveMonth(new_date, dir);
19584 // ...then reset the day, keeping it in the new month
19585 new_month = new_date.getUTCMonth();
19586 new_date.setUTCDate(day);
19588 return new_month != new_date.getUTCMonth();
19591 // Common date-resetting loop -- if date is beyond end of month, make it
19594 new_date.setUTCDate(--day);
19595 new_date.setUTCMonth(new_month);
19600 moveYear: function(date, dir)
19602 return this.moveMonth(date, dir*12);
19605 dateWithinRange: function(date)
19607 return date >= this.startDate && date <= this.endDate;
19613 this.picker().remove();
19616 validateValue : function(value)
19618 if(this.getVisibilityEl().hasClass('hidden')){
19622 if(value.length < 1) {
19623 if(this.allowBlank){
19629 if(value.length < this.minLength){
19632 if(value.length > this.maxLength){
19636 var vt = Roo.form.VTypes;
19637 if(!vt[this.vtype](value, this)){
19641 if(typeof this.validator == "function"){
19642 var msg = this.validator(value);
19648 if(this.regex && !this.regex.test(value)){
19652 if(typeof(this.parseDate(value)) == 'undefined'){
19656 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
19660 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
19670 this.date = this.viewDate = '';
19672 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
19677 Roo.apply(Roo.bootstrap.DateField, {
19688 html: '<i class="fa fa-arrow-left"/>'
19698 html: '<i class="fa fa-arrow-right"/>'
19740 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
19741 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
19742 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
19743 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19744 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
19757 navFnc: 'FullYear',
19762 navFnc: 'FullYear',
19767 Roo.apply(Roo.bootstrap.DateField, {
19771 cls: 'datepicker dropdown-menu roo-dynamic',
19775 cls: 'datepicker-days',
19779 cls: 'table-condensed',
19781 Roo.bootstrap.DateField.head,
19785 Roo.bootstrap.DateField.footer
19792 cls: 'datepicker-months',
19796 cls: 'table-condensed',
19798 Roo.bootstrap.DateField.head,
19799 Roo.bootstrap.DateField.content,
19800 Roo.bootstrap.DateField.footer
19807 cls: 'datepicker-years',
19811 cls: 'table-condensed',
19813 Roo.bootstrap.DateField.head,
19814 Roo.bootstrap.DateField.content,
19815 Roo.bootstrap.DateField.footer
19834 * @class Roo.bootstrap.TimeField
19835 * @extends Roo.bootstrap.Input
19836 * Bootstrap DateField class
19840 * Create a new TimeField
19841 * @param {Object} config The config object
19844 Roo.bootstrap.TimeField = function(config){
19845 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
19849 * Fires when this field show.
19850 * @param {Roo.bootstrap.DateField} thisthis
19851 * @param {Mixed} date The date value
19856 * Fires when this field hide.
19857 * @param {Roo.bootstrap.DateField} this
19858 * @param {Mixed} date The date value
19863 * Fires when select a date.
19864 * @param {Roo.bootstrap.DateField} this
19865 * @param {Mixed} date The date value
19871 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
19874 * @cfg {String} format
19875 * The default time format string which can be overriden for localization support. The format must be
19876 * valid according to {@link Date#parseDate} (defaults to 'H:i').
19880 onRender: function(ct, position)
19883 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
19885 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
19887 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19889 this.pop = this.picker().select('>.datepicker-time',true).first();
19890 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19892 this.picker().on('mousedown', this.onMousedown, this);
19893 this.picker().on('click', this.onClick, this);
19895 this.picker().addClass('datepicker-dropdown');
19900 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
19901 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
19902 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
19903 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
19904 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
19905 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
19909 fireKey: function(e){
19910 if (!this.picker().isVisible()){
19911 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19917 e.preventDefault();
19925 this.onTogglePeriod();
19928 this.onIncrementMinutes();
19931 this.onDecrementMinutes();
19940 onClick: function(e) {
19941 e.stopPropagation();
19942 e.preventDefault();
19945 picker : function()
19947 return this.el.select('.datepicker', true).first();
19950 fillTime: function()
19952 var time = this.pop.select('tbody', true).first();
19954 time.dom.innerHTML = '';
19969 cls: 'hours-up glyphicon glyphicon-chevron-up'
19989 cls: 'minutes-up glyphicon glyphicon-chevron-up'
20010 cls: 'timepicker-hour',
20025 cls: 'timepicker-minute',
20040 cls: 'btn btn-primary period',
20062 cls: 'hours-down glyphicon glyphicon-chevron-down'
20082 cls: 'minutes-down glyphicon glyphicon-chevron-down'
20100 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
20107 var hours = this.time.getHours();
20108 var minutes = this.time.getMinutes();
20121 hours = hours - 12;
20125 hours = '0' + hours;
20129 minutes = '0' + minutes;
20132 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
20133 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
20134 this.pop.select('button', true).first().dom.innerHTML = period;
20140 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
20142 var cls = ['bottom'];
20144 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
20151 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
20156 this.picker().addClass(cls.join('-'));
20160 Roo.each(cls, function(c){
20162 _this.picker().setTop(_this.inputEl().getHeight());
20166 _this.picker().setTop(0 - _this.picker().getHeight());
20171 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
20175 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
20182 onFocus : function()
20184 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
20188 onBlur : function()
20190 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
20196 this.picker().show();
20201 this.fireEvent('show', this, this.date);
20206 this.picker().hide();
20209 this.fireEvent('hide', this, this.date);
20212 setTime : function()
20215 this.setValue(this.time.format(this.format));
20217 this.fireEvent('select', this, this.date);
20222 onMousedown: function(e){
20223 e.stopPropagation();
20224 e.preventDefault();
20227 onIncrementHours: function()
20229 Roo.log('onIncrementHours');
20230 this.time = this.time.add(Date.HOUR, 1);
20235 onDecrementHours: function()
20237 Roo.log('onDecrementHours');
20238 this.time = this.time.add(Date.HOUR, -1);
20242 onIncrementMinutes: function()
20244 Roo.log('onIncrementMinutes');
20245 this.time = this.time.add(Date.MINUTE, 1);
20249 onDecrementMinutes: function()
20251 Roo.log('onDecrementMinutes');
20252 this.time = this.time.add(Date.MINUTE, -1);
20256 onTogglePeriod: function()
20258 Roo.log('onTogglePeriod');
20259 this.time = this.time.add(Date.HOUR, 12);
20266 Roo.apply(Roo.bootstrap.TimeField, {
20296 cls: 'btn btn-info ok',
20308 Roo.apply(Roo.bootstrap.TimeField, {
20312 cls: 'datepicker dropdown-menu',
20316 cls: 'datepicker-time',
20320 cls: 'table-condensed',
20322 Roo.bootstrap.TimeField.content,
20323 Roo.bootstrap.TimeField.footer
20342 * @class Roo.bootstrap.MonthField
20343 * @extends Roo.bootstrap.Input
20344 * Bootstrap MonthField class
20346 * @cfg {String} language default en
20349 * Create a new MonthField
20350 * @param {Object} config The config object
20353 Roo.bootstrap.MonthField = function(config){
20354 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
20359 * Fires when this field show.
20360 * @param {Roo.bootstrap.MonthField} this
20361 * @param {Mixed} date The date value
20366 * Fires when this field hide.
20367 * @param {Roo.bootstrap.MonthField} this
20368 * @param {Mixed} date The date value
20373 * Fires when select a date.
20374 * @param {Roo.bootstrap.MonthField} this
20375 * @param {String} oldvalue The old value
20376 * @param {String} newvalue The new value
20382 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
20384 onRender: function(ct, position)
20387 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
20389 this.language = this.language || 'en';
20390 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
20391 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
20393 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
20394 this.isInline = false;
20395 this.isInput = true;
20396 this.component = this.el.select('.add-on', true).first() || false;
20397 this.component = (this.component && this.component.length === 0) ? false : this.component;
20398 this.hasInput = this.component && this.inputEL().length;
20400 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
20402 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
20404 this.picker().on('mousedown', this.onMousedown, this);
20405 this.picker().on('click', this.onClick, this);
20407 this.picker().addClass('datepicker-dropdown');
20409 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
20410 v.setStyle('width', '189px');
20417 if(this.isInline) {
20423 setValue: function(v, suppressEvent)
20425 var o = this.getValue();
20427 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
20431 if(suppressEvent !== true){
20432 this.fireEvent('select', this, o, v);
20437 getValue: function()
20442 onClick: function(e)
20444 e.stopPropagation();
20445 e.preventDefault();
20447 var target = e.getTarget();
20449 if(target.nodeName.toLowerCase() === 'i'){
20450 target = Roo.get(target).dom.parentNode;
20453 var nodeName = target.nodeName;
20454 var className = target.className;
20455 var html = target.innerHTML;
20457 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
20461 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
20463 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20469 picker : function()
20471 return this.pickerEl;
20474 fillMonths: function()
20477 var months = this.picker().select('>.datepicker-months td', true).first();
20479 months.dom.innerHTML = '';
20485 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
20488 months.createChild(month);
20497 if(typeof(this.vIndex) == 'undefined' && this.value.length){
20498 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
20501 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
20502 e.removeClass('active');
20504 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
20505 e.addClass('active');
20512 if(this.isInline) {
20516 this.picker().removeClass(['bottom', 'top']);
20518 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
20520 * place to the top of element!
20524 this.picker().addClass('top');
20525 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
20530 this.picker().addClass('bottom');
20532 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
20535 onFocus : function()
20537 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
20541 onBlur : function()
20543 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
20545 var d = this.inputEl().getValue();
20554 this.picker().show();
20555 this.picker().select('>.datepicker-months', true).first().show();
20559 this.fireEvent('show', this, this.date);
20564 if(this.isInline) {
20567 this.picker().hide();
20568 this.fireEvent('hide', this, this.date);
20572 onMousedown: function(e)
20574 e.stopPropagation();
20575 e.preventDefault();
20580 Roo.bootstrap.MonthField.superclass.keyup.call(this);
20584 fireKey: function(e)
20586 if (!this.picker().isVisible()){
20587 if (e.keyCode == 27) {// allow escape to hide and re-show picker
20598 e.preventDefault();
20602 dir = e.keyCode == 37 ? -1 : 1;
20604 this.vIndex = this.vIndex + dir;
20606 if(this.vIndex < 0){
20610 if(this.vIndex > 11){
20614 if(isNaN(this.vIndex)){
20618 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20624 dir = e.keyCode == 38 ? -1 : 1;
20626 this.vIndex = this.vIndex + dir * 4;
20628 if(this.vIndex < 0){
20632 if(this.vIndex > 11){
20636 if(isNaN(this.vIndex)){
20640 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20645 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20646 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20650 e.preventDefault();
20653 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20654 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20670 this.picker().remove();
20675 Roo.apply(Roo.bootstrap.MonthField, {
20694 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
20695 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
20700 Roo.apply(Roo.bootstrap.MonthField, {
20704 cls: 'datepicker dropdown-menu roo-dynamic',
20708 cls: 'datepicker-months',
20712 cls: 'table-condensed',
20714 Roo.bootstrap.DateField.content
20734 * @class Roo.bootstrap.CheckBox
20735 * @extends Roo.bootstrap.Input
20736 * Bootstrap CheckBox class
20738 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
20739 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
20740 * @cfg {String} boxLabel The text that appears beside the checkbox
20741 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
20742 * @cfg {Boolean} checked initnal the element
20743 * @cfg {Boolean} inline inline the element (default false)
20744 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
20745 * @cfg {String} tooltip label tooltip
20748 * Create a new CheckBox
20749 * @param {Object} config The config object
20752 Roo.bootstrap.CheckBox = function(config){
20753 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
20758 * Fires when the element is checked or unchecked.
20759 * @param {Roo.bootstrap.CheckBox} this This input
20760 * @param {Boolean} checked The new checked value
20765 * Fires when the element is click.
20766 * @param {Roo.bootstrap.CheckBox} this This input
20773 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
20775 inputType: 'checkbox',
20784 getAutoCreate : function()
20786 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20792 cfg.cls = 'form-group ' + this.inputType; //input-group
20795 cfg.cls += ' ' + this.inputType + '-inline';
20801 type : this.inputType,
20802 value : this.inputValue,
20803 cls : 'roo-' + this.inputType, //'form-box',
20804 placeholder : this.placeholder || ''
20808 if(this.inputType != 'radio'){
20812 cls : 'roo-hidden-value',
20813 value : this.checked ? this.inputValue : this.valueOff
20818 if (this.weight) { // Validity check?
20819 cfg.cls += " " + this.inputType + "-" + this.weight;
20822 if (this.disabled) {
20823 input.disabled=true;
20827 input.checked = this.checked;
20832 input.name = this.name;
20834 if(this.inputType != 'radio'){
20835 hidden.name = this.name;
20836 input.name = '_hidden_' + this.name;
20841 input.cls += ' input-' + this.size;
20846 ['xs','sm','md','lg'].map(function(size){
20847 if (settings[size]) {
20848 cfg.cls += ' col-' + size + '-' + settings[size];
20852 var inputblock = input;
20854 if (this.before || this.after) {
20857 cls : 'input-group',
20862 inputblock.cn.push({
20864 cls : 'input-group-addon',
20869 inputblock.cn.push(input);
20871 if(this.inputType != 'radio'){
20872 inputblock.cn.push(hidden);
20876 inputblock.cn.push({
20878 cls : 'input-group-addon',
20885 if (align ==='left' && this.fieldLabel.length) {
20886 // Roo.log("left and has label");
20891 cls : 'control-label',
20892 html : this.fieldLabel
20902 if(this.labelWidth > 12){
20903 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
20906 if(this.labelWidth < 13 && this.labelmd == 0){
20907 this.labelmd = this.labelWidth;
20910 if(this.labellg > 0){
20911 cfg.cn[0].cls += ' col-lg-' + this.labellg;
20912 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
20915 if(this.labelmd > 0){
20916 cfg.cn[0].cls += ' col-md-' + this.labelmd;
20917 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
20920 if(this.labelsm > 0){
20921 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
20922 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
20925 if(this.labelxs > 0){
20926 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
20927 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
20930 } else if ( this.fieldLabel.length) {
20931 // Roo.log(" label");
20935 tag: this.boxLabel ? 'span' : 'label',
20937 cls: 'control-label box-input-label',
20938 //cls : 'input-group-addon',
20939 html : this.fieldLabel
20948 // Roo.log(" no label && no align");
20949 cfg.cn = [ inputblock ] ;
20955 var boxLabelCfg = {
20957 //'for': id, // box label is handled by onclick - so no for...
20959 html: this.boxLabel
20963 boxLabelCfg.tooltip = this.tooltip;
20966 cfg.cn.push(boxLabelCfg);
20969 if(this.inputType != 'radio'){
20970 cfg.cn.push(hidden);
20978 * return the real input element.
20980 inputEl: function ()
20982 return this.el.select('input.roo-' + this.inputType,true).first();
20984 hiddenEl: function ()
20986 return this.el.select('input.roo-hidden-value',true).first();
20989 labelEl: function()
20991 return this.el.select('label.control-label',true).first();
20993 /* depricated... */
20997 return this.labelEl();
21000 boxLabelEl: function()
21002 return this.el.select('label.box-label',true).first();
21005 initEvents : function()
21007 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
21009 this.inputEl().on('click', this.onClick, this);
21011 if (this.boxLabel) {
21012 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
21015 this.startValue = this.getValue();
21018 Roo.bootstrap.CheckBox.register(this);
21022 onClick : function(e)
21024 if(this.fireEvent('click', this, e) !== false){
21025 this.setChecked(!this.checked);
21030 setChecked : function(state,suppressEvent)
21032 this.startValue = this.getValue();
21034 if(this.inputType == 'radio'){
21036 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21037 e.dom.checked = false;
21040 this.inputEl().dom.checked = true;
21042 this.inputEl().dom.value = this.inputValue;
21044 if(suppressEvent !== true){
21045 this.fireEvent('check', this, true);
21053 this.checked = state;
21055 this.inputEl().dom.checked = state;
21058 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
21060 if(suppressEvent !== true){
21061 this.fireEvent('check', this, state);
21067 getValue : function()
21069 if(this.inputType == 'radio'){
21070 return this.getGroupValue();
21073 return this.hiddenEl().dom.value;
21077 getGroupValue : function()
21079 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
21083 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
21086 setValue : function(v,suppressEvent)
21088 if(this.inputType == 'radio'){
21089 this.setGroupValue(v, suppressEvent);
21093 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
21098 setGroupValue : function(v, suppressEvent)
21100 this.startValue = this.getValue();
21102 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21103 e.dom.checked = false;
21105 if(e.dom.value == v){
21106 e.dom.checked = true;
21110 if(suppressEvent !== true){
21111 this.fireEvent('check', this, true);
21119 validate : function()
21121 if(this.getVisibilityEl().hasClass('hidden')){
21127 (this.inputType == 'radio' && this.validateRadio()) ||
21128 (this.inputType == 'checkbox' && this.validateCheckbox())
21134 this.markInvalid();
21138 validateRadio : function()
21140 if(this.getVisibilityEl().hasClass('hidden')){
21144 if(this.allowBlank){
21150 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21151 if(!e.dom.checked){
21163 validateCheckbox : function()
21166 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
21167 //return (this.getValue() == this.inputValue) ? true : false;
21170 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21178 for(var i in group){
21179 if(group[i].el.isVisible(true)){
21187 for(var i in group){
21192 r = (group[i].getValue() == group[i].inputValue) ? true : false;
21199 * Mark this field as valid
21201 markValid : function()
21205 this.fireEvent('valid', this);
21207 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21210 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
21217 if(this.inputType == 'radio'){
21218 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21219 var fg = e.findParent('.form-group', false, true);
21220 if (Roo.bootstrap.version == 3) {
21221 fg.removeClass([_this.invalidClass, _this.validClass]);
21222 fg.addClass(_this.validClass);
21224 fg.removeClass(['is-valid', 'is-invalid']);
21225 fg.addClass('is-valid');
21233 var fg = this.el.findParent('.form-group', false, true);
21234 if (Roo.bootstrap.version == 3) {
21235 fg.removeClass([this.invalidClass, this.validClass]);
21236 fg.addClass(this.validClass);
21238 fg.removeClass(['is-valid', 'is-invalid']);
21239 fg.addClass('is-valid');
21244 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21250 for(var i in group){
21251 var fg = group[i].el.findParent('.form-group', false, true);
21252 if (Roo.bootstrap.version == 3) {
21253 fg.removeClass([this.invalidClass, this.validClass]);
21254 fg.addClass(this.validClass);
21256 fg.removeClass(['is-valid', 'is-invalid']);
21257 fg.addClass('is-valid');
21263 * Mark this field as invalid
21264 * @param {String} msg The validation message
21266 markInvalid : function(msg)
21268 if(this.allowBlank){
21274 this.fireEvent('invalid', this, msg);
21276 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21279 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
21283 label.markInvalid();
21286 if(this.inputType == 'radio'){
21288 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21289 var fg = e.findParent('.form-group', false, true);
21290 if (Roo.bootstrap.version == 3) {
21291 fg.removeClass([_this.invalidClass, _this.validClass]);
21292 fg.addClass(_this.invalidClass);
21294 fg.removeClass(['is-invalid', 'is-valid']);
21295 fg.addClass('is-invalid');
21303 var fg = this.el.findParent('.form-group', false, true);
21304 if (Roo.bootstrap.version == 3) {
21305 fg.removeClass([_this.invalidClass, _this.validClass]);
21306 fg.addClass(_this.invalidClass);
21308 fg.removeClass(['is-invalid', 'is-valid']);
21309 fg.addClass('is-invalid');
21314 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21320 for(var i in group){
21321 var fg = group[i].el.findParent('.form-group', false, true);
21322 if (Roo.bootstrap.version == 3) {
21323 fg.removeClass([_this.invalidClass, _this.validClass]);
21324 fg.addClass(_this.invalidClass);
21326 fg.removeClass(['is-invalid', 'is-valid']);
21327 fg.addClass('is-invalid');
21333 clearInvalid : function()
21335 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
21337 // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21339 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21341 if (label && label.iconEl) {
21342 label.iconEl.removeClass([ label.validClass, label.invalidClass ]);
21343 label.iconEl.removeClass(['is-invalid', 'is-valid']);
21347 disable : function()
21349 if(this.inputType != 'radio'){
21350 Roo.bootstrap.CheckBox.superclass.disable.call(this);
21357 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21358 _this.getActionEl().addClass(this.disabledClass);
21359 e.dom.disabled = true;
21363 this.disabled = true;
21364 this.fireEvent("disable", this);
21368 enable : function()
21370 if(this.inputType != 'radio'){
21371 Roo.bootstrap.CheckBox.superclass.enable.call(this);
21378 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21379 _this.getActionEl().removeClass(this.disabledClass);
21380 e.dom.disabled = false;
21384 this.disabled = false;
21385 this.fireEvent("enable", this);
21389 setBoxLabel : function(v)
21394 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21400 Roo.apply(Roo.bootstrap.CheckBox, {
21405 * register a CheckBox Group
21406 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
21408 register : function(checkbox)
21410 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
21411 this.groups[checkbox.groupId] = {};
21414 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
21418 this.groups[checkbox.groupId][checkbox.name] = checkbox;
21422 * fetch a CheckBox Group based on the group ID
21423 * @param {string} the group ID
21424 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
21426 get: function(groupId) {
21427 if (typeof(this.groups[groupId]) == 'undefined') {
21431 return this.groups[groupId] ;
21444 * @class Roo.bootstrap.Radio
21445 * @extends Roo.bootstrap.Component
21446 * Bootstrap Radio class
21447 * @cfg {String} boxLabel - the label associated
21448 * @cfg {String} value - the value of radio
21451 * Create a new Radio
21452 * @param {Object} config The config object
21454 Roo.bootstrap.Radio = function(config){
21455 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
21459 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
21465 getAutoCreate : function()
21469 cls : 'form-group radio',
21474 html : this.boxLabel
21482 initEvents : function()
21484 this.parent().register(this);
21486 this.el.on('click', this.onClick, this);
21490 onClick : function(e)
21492 if(this.parent().fireEvent('click', this.parent(), this, e) !== false){
21493 this.setChecked(true);
21497 setChecked : function(state, suppressEvent)
21499 this.parent().setValue(this.value, suppressEvent);
21503 setBoxLabel : function(v)
21508 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21523 * @class Roo.bootstrap.SecurePass
21524 * @extends Roo.bootstrap.Input
21525 * Bootstrap SecurePass class
21529 * Create a new SecurePass
21530 * @param {Object} config The config object
21533 Roo.bootstrap.SecurePass = function (config) {
21534 // these go here, so the translation tool can replace them..
21536 PwdEmpty: "Please type a password, and then retype it to confirm.",
21537 PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21538 PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21539 PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21540 IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21541 FNInPwd: "Your password can't contain your first name. Please type a different password.",
21542 LNInPwd: "Your password can't contain your last name. Please type a different password.",
21543 TooWeak: "Your password is Too Weak."
21545 this.meterLabel = "Password strength:";
21546 this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
21547 this.meterClass = [
21548 "roo-password-meter-tooweak",
21549 "roo-password-meter-weak",
21550 "roo-password-meter-medium",
21551 "roo-password-meter-strong",
21552 "roo-password-meter-grey"
21557 Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
21560 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
21562 * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
21564 * PwdEmpty: "Please type a password, and then retype it to confirm.",
21565 * PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21566 * PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21567 * PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21568 * IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21569 * FNInPwd: "Your password can't contain your first name. Please type a different password.",
21570 * LNInPwd: "Your password can't contain your last name. Please type a different password."
21580 * @cfg {String/Object} Label for the strength meter (defaults to
21581 * 'Password strength:')
21586 * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
21587 * ['Weak', 'Medium', 'Strong'])
21590 pwdStrengths: false,
21603 initEvents: function ()
21605 Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
21607 if (this.el.is('input[type=password]') && Roo.isSafari) {
21608 this.el.on('keydown', this.SafariOnKeyDown, this);
21611 this.el.on('keyup', this.checkStrength, this, {buffer: 50});
21614 onRender: function (ct, position)
21616 Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
21617 this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
21618 this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
21620 this.trigger.createChild({
21625 cls: 'roo-password-meter-grey col-xs-12',
21628 //width: this.meterWidth + 'px'
21632 cls: 'roo-password-meter-text'
21638 if (this.hideTrigger) {
21639 this.trigger.setDisplayed(false);
21641 this.setSize(this.width || '', this.height || '');
21644 onDestroy: function ()
21646 if (this.trigger) {
21647 this.trigger.removeAllListeners();
21648 this.trigger.remove();
21651 this.wrap.remove();
21653 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
21656 checkStrength: function ()
21658 var pwd = this.inputEl().getValue();
21659 if (pwd == this._lastPwd) {
21664 if (this.ClientSideStrongPassword(pwd)) {
21666 } else if (this.ClientSideMediumPassword(pwd)) {
21668 } else if (this.ClientSideWeakPassword(pwd)) {
21674 Roo.log('strength1: ' + strength);
21676 //var pm = this.trigger.child('div/div/div').dom;
21677 var pm = this.trigger.child('div/div');
21678 pm.removeClass(this.meterClass);
21679 pm.addClass(this.meterClass[strength]);
21682 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21684 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21686 this._lastPwd = pwd;
21690 Roo.bootstrap.SecurePass.superclass.reset.call(this);
21692 this._lastPwd = '';
21694 var pm = this.trigger.child('div/div');
21695 pm.removeClass(this.meterClass);
21696 pm.addClass('roo-password-meter-grey');
21699 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21702 this.inputEl().dom.type='password';
21705 validateValue: function (value)
21708 if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
21711 if (value.length == 0) {
21712 if (this.allowBlank) {
21713 this.clearInvalid();
21717 this.markInvalid(this.errors.PwdEmpty);
21718 this.errorMsg = this.errors.PwdEmpty;
21726 if ('[\x21-\x7e]*'.match(value)) {
21727 this.markInvalid(this.errors.PwdBadChar);
21728 this.errorMsg = this.errors.PwdBadChar;
21731 if (value.length < 6) {
21732 this.markInvalid(this.errors.PwdShort);
21733 this.errorMsg = this.errors.PwdShort;
21736 if (value.length > 16) {
21737 this.markInvalid(this.errors.PwdLong);
21738 this.errorMsg = this.errors.PwdLong;
21742 if (this.ClientSideStrongPassword(value)) {
21744 } else if (this.ClientSideMediumPassword(value)) {
21746 } else if (this.ClientSideWeakPassword(value)) {
21753 if (strength < 2) {
21754 //this.markInvalid(this.errors.TooWeak);
21755 this.errorMsg = this.errors.TooWeak;
21760 console.log('strength2: ' + strength);
21762 //var pm = this.trigger.child('div/div/div').dom;
21764 var pm = this.trigger.child('div/div');
21765 pm.removeClass(this.meterClass);
21766 pm.addClass(this.meterClass[strength]);
21768 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21770 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21772 this.errorMsg = '';
21776 CharacterSetChecks: function (type)
21779 this.fResult = false;
21782 isctype: function (character, type)
21785 case this.kCapitalLetter:
21786 if (character >= 'A' && character <= 'Z') {
21791 case this.kSmallLetter:
21792 if (character >= 'a' && character <= 'z') {
21798 if (character >= '0' && character <= '9') {
21803 case this.kPunctuation:
21804 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
21815 IsLongEnough: function (pwd, size)
21817 return !(pwd == null || isNaN(size) || pwd.length < size);
21820 SpansEnoughCharacterSets: function (word, nb)
21822 if (!this.IsLongEnough(word, nb))
21827 var characterSetChecks = new Array(
21828 new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
21829 new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
21832 for (var index = 0; index < word.length; ++index) {
21833 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21834 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
21835 characterSetChecks[nCharSet].fResult = true;
21842 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21843 if (characterSetChecks[nCharSet].fResult) {
21848 if (nCharSets < nb) {
21854 ClientSideStrongPassword: function (pwd)
21856 return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
21859 ClientSideMediumPassword: function (pwd)
21861 return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
21864 ClientSideWeakPassword: function (pwd)
21866 return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
21869 })//<script type="text/javascript">
21872 * Based Ext JS Library 1.1.1
21873 * Copyright(c) 2006-2007, Ext JS, LLC.
21879 * @class Roo.HtmlEditorCore
21880 * @extends Roo.Component
21881 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
21883 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
21886 Roo.HtmlEditorCore = function(config){
21889 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
21894 * @event initialize
21895 * Fires when the editor is fully initialized (including the iframe)
21896 * @param {Roo.HtmlEditorCore} this
21901 * Fires when the editor is first receives the focus. Any insertion must wait
21902 * until after this event.
21903 * @param {Roo.HtmlEditorCore} this
21907 * @event beforesync
21908 * Fires before the textarea is updated with content from the editor iframe. Return false
21909 * to cancel the sync.
21910 * @param {Roo.HtmlEditorCore} this
21911 * @param {String} html
21915 * @event beforepush
21916 * Fires before the iframe editor is updated with content from the textarea. Return false
21917 * to cancel the push.
21918 * @param {Roo.HtmlEditorCore} this
21919 * @param {String} html
21924 * Fires when the textarea is updated with content from the editor iframe.
21925 * @param {Roo.HtmlEditorCore} this
21926 * @param {String} html
21931 * Fires when the iframe editor is updated with content from the textarea.
21932 * @param {Roo.HtmlEditorCore} this
21933 * @param {String} html
21938 * @event editorevent
21939 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
21940 * @param {Roo.HtmlEditorCore} this
21946 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
21948 // defaults : white / black...
21949 this.applyBlacklists();
21956 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
21960 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
21966 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
21971 * @cfg {Number} height (in pixels)
21975 * @cfg {Number} width (in pixels)
21980 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
21983 stylesheets: false,
21988 // private properties
21989 validationEvent : false,
21991 initialized : false,
21993 sourceEditMode : false,
21994 onFocus : Roo.emptyFn,
21996 hideMode:'offsets',
22000 // blacklist + whitelisted elements..
22007 * Protected method that will not generally be called directly. It
22008 * is called when the editor initializes the iframe with HTML contents. Override this method if you
22009 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
22011 getDocMarkup : function(){
22015 // inherit styels from page...??
22016 if (this.stylesheets === false) {
22018 Roo.get(document.head).select('style').each(function(node) {
22019 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
22022 Roo.get(document.head).select('link').each(function(node) {
22023 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
22026 } else if (!this.stylesheets.length) {
22028 st = '<style type="text/css">' +
22029 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
22032 st = '<style type="text/css">' +
22037 st += '<style type="text/css">' +
22038 'IMG { cursor: pointer } ' +
22041 var cls = 'roo-htmleditor-body';
22043 if(this.bodyCls.length){
22044 cls += ' ' + this.bodyCls;
22047 return '<html><head>' + st +
22048 //<style type="text/css">' +
22049 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
22051 ' </head><body class="' + cls + '"></body></html>';
22055 onRender : function(ct, position)
22058 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
22059 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
22062 this.el.dom.style.border = '0 none';
22063 this.el.dom.setAttribute('tabIndex', -1);
22064 this.el.addClass('x-hidden hide');
22068 if(Roo.isIE){ // fix IE 1px bogus margin
22069 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
22073 this.frameId = Roo.id();
22077 var iframe = this.owner.wrap.createChild({
22079 cls: 'form-control', // bootstrap..
22081 name: this.frameId,
22082 frameBorder : 'no',
22083 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
22088 this.iframe = iframe.dom;
22090 this.assignDocWin();
22092 this.doc.designMode = 'on';
22095 this.doc.write(this.getDocMarkup());
22099 var task = { // must defer to wait for browser to be ready
22101 //console.log("run task?" + this.doc.readyState);
22102 this.assignDocWin();
22103 if(this.doc.body || this.doc.readyState == 'complete'){
22105 this.doc.designMode="on";
22109 Roo.TaskMgr.stop(task);
22110 this.initEditor.defer(10, this);
22117 Roo.TaskMgr.start(task);
22122 onResize : function(w, h)
22124 Roo.log('resize: ' +w + ',' + h );
22125 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
22129 if(typeof w == 'number'){
22131 this.iframe.style.width = w + 'px';
22133 if(typeof h == 'number'){
22135 this.iframe.style.height = h + 'px';
22137 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
22144 * Toggles the editor between standard and source edit mode.
22145 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
22147 toggleSourceEdit : function(sourceEditMode){
22149 this.sourceEditMode = sourceEditMode === true;
22151 if(this.sourceEditMode){
22153 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
22156 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
22157 //this.iframe.className = '';
22160 //this.setSize(this.owner.wrap.getSize());
22161 //this.fireEvent('editmodechange', this, this.sourceEditMode);
22168 * Protected method that will not generally be called directly. If you need/want
22169 * custom HTML cleanup, this is the method you should override.
22170 * @param {String} html The HTML to be cleaned
22171 * return {String} The cleaned HTML
22173 cleanHtml : function(html){
22174 html = String(html);
22175 if(html.length > 5){
22176 if(Roo.isSafari){ // strip safari nonsense
22177 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
22180 if(html == ' '){
22187 * HTML Editor -> Textarea
22188 * Protected method that will not generally be called directly. Syncs the contents
22189 * of the editor iframe with the textarea.
22191 syncValue : function(){
22192 if(this.initialized){
22193 var bd = (this.doc.body || this.doc.documentElement);
22194 //this.cleanUpPaste(); -- this is done else where and causes havoc..
22195 var html = bd.innerHTML;
22197 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
22198 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
22200 html = '<div style="'+m[0]+'">' + html + '</div>';
22203 html = this.cleanHtml(html);
22204 // fix up the special chars.. normaly like back quotes in word...
22205 // however we do not want to do this with chinese..
22206 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
22207 var cc = b.charCodeAt();
22209 (cc >= 0x4E00 && cc < 0xA000 ) ||
22210 (cc >= 0x3400 && cc < 0x4E00 ) ||
22211 (cc >= 0xf900 && cc < 0xfb00 )
22217 if(this.owner.fireEvent('beforesync', this, html) !== false){
22218 this.el.dom.value = html;
22219 this.owner.fireEvent('sync', this, html);
22225 * Protected method that will not generally be called directly. Pushes the value of the textarea
22226 * into the iframe editor.
22228 pushValue : function(){
22229 if(this.initialized){
22230 var v = this.el.dom.value.trim();
22232 // if(v.length < 1){
22236 if(this.owner.fireEvent('beforepush', this, v) !== false){
22237 var d = (this.doc.body || this.doc.documentElement);
22239 this.cleanUpPaste();
22240 this.el.dom.value = d.innerHTML;
22241 this.owner.fireEvent('push', this, v);
22247 deferFocus : function(){
22248 this.focus.defer(10, this);
22252 focus : function(){
22253 if(this.win && !this.sourceEditMode){
22260 assignDocWin: function()
22262 var iframe = this.iframe;
22265 this.doc = iframe.contentWindow.document;
22266 this.win = iframe.contentWindow;
22268 // if (!Roo.get(this.frameId)) {
22271 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
22272 // this.win = Roo.get(this.frameId).dom.contentWindow;
22274 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
22278 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
22279 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
22284 initEditor : function(){
22285 //console.log("INIT EDITOR");
22286 this.assignDocWin();
22290 this.doc.designMode="on";
22292 this.doc.write(this.getDocMarkup());
22295 var dbody = (this.doc.body || this.doc.documentElement);
22296 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
22297 // this copies styles from the containing element into thsi one..
22298 // not sure why we need all of this..
22299 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
22301 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
22302 //ss['background-attachment'] = 'fixed'; // w3c
22303 dbody.bgProperties = 'fixed'; // ie
22304 //Roo.DomHelper.applyStyles(dbody, ss);
22305 Roo.EventManager.on(this.doc, {
22306 //'mousedown': this.onEditorEvent,
22307 'mouseup': this.onEditorEvent,
22308 'dblclick': this.onEditorEvent,
22309 'click': this.onEditorEvent,
22310 'keyup': this.onEditorEvent,
22315 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
22317 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
22318 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
22320 this.initialized = true;
22322 this.owner.fireEvent('initialize', this);
22327 onDestroy : function(){
22333 //for (var i =0; i < this.toolbars.length;i++) {
22334 // // fixme - ask toolbars for heights?
22335 // this.toolbars[i].onDestroy();
22338 //this.wrap.dom.innerHTML = '';
22339 //this.wrap.remove();
22344 onFirstFocus : function(){
22346 this.assignDocWin();
22349 this.activated = true;
22352 if(Roo.isGecko){ // prevent silly gecko errors
22354 var s = this.win.getSelection();
22355 if(!s.focusNode || s.focusNode.nodeType != 3){
22356 var r = s.getRangeAt(0);
22357 r.selectNodeContents((this.doc.body || this.doc.documentElement));
22362 this.execCmd('useCSS', true);
22363 this.execCmd('styleWithCSS', false);
22366 this.owner.fireEvent('activate', this);
22370 adjustFont: function(btn){
22371 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
22372 //if(Roo.isSafari){ // safari
22375 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
22376 if(Roo.isSafari){ // safari
22377 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
22378 v = (v < 10) ? 10 : v;
22379 v = (v > 48) ? 48 : v;
22380 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
22385 v = Math.max(1, v+adjust);
22387 this.execCmd('FontSize', v );
22390 onEditorEvent : function(e)
22392 this.owner.fireEvent('editorevent', this, e);
22393 // this.updateToolbar();
22394 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
22397 insertTag : function(tg)
22399 // could be a bit smarter... -> wrap the current selected tRoo..
22400 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
22402 range = this.createRange(this.getSelection());
22403 var wrappingNode = this.doc.createElement(tg.toLowerCase());
22404 wrappingNode.appendChild(range.extractContents());
22405 range.insertNode(wrappingNode);
22412 this.execCmd("formatblock", tg);
22416 insertText : function(txt)
22420 var range = this.createRange();
22421 range.deleteContents();
22422 //alert(Sender.getAttribute('label'));
22424 range.insertNode(this.doc.createTextNode(txt));
22430 * Executes a Midas editor command on the editor document and performs necessary focus and
22431 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
22432 * @param {String} cmd The Midas command
22433 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22435 relayCmd : function(cmd, value){
22437 this.execCmd(cmd, value);
22438 this.owner.fireEvent('editorevent', this);
22439 //this.updateToolbar();
22440 this.owner.deferFocus();
22444 * Executes a Midas editor command directly on the editor document.
22445 * For visual commands, you should use {@link #relayCmd} instead.
22446 * <b>This should only be called after the editor is initialized.</b>
22447 * @param {String} cmd The Midas command
22448 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22450 execCmd : function(cmd, value){
22451 this.doc.execCommand(cmd, false, value === undefined ? null : value);
22458 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
22460 * @param {String} text | dom node..
22462 insertAtCursor : function(text)
22465 if(!this.activated){
22471 var r = this.doc.selection.createRange();
22482 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
22486 // from jquery ui (MIT licenced)
22488 var win = this.win;
22490 if (win.getSelection && win.getSelection().getRangeAt) {
22491 range = win.getSelection().getRangeAt(0);
22492 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
22493 range.insertNode(node);
22494 } else if (win.document.selection && win.document.selection.createRange) {
22495 // no firefox support
22496 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22497 win.document.selection.createRange().pasteHTML(txt);
22499 // no firefox support
22500 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22501 this.execCmd('InsertHTML', txt);
22510 mozKeyPress : function(e){
22512 var c = e.getCharCode(), cmd;
22515 c = String.fromCharCode(c).toLowerCase();
22529 this.cleanUpPaste.defer(100, this);
22537 e.preventDefault();
22545 fixKeys : function(){ // load time branching for fastest keydown performance
22547 return function(e){
22548 var k = e.getKey(), r;
22551 r = this.doc.selection.createRange();
22554 r.pasteHTML('    ');
22561 r = this.doc.selection.createRange();
22563 var target = r.parentElement();
22564 if(!target || target.tagName.toLowerCase() != 'li'){
22566 r.pasteHTML('<br />');
22572 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22573 this.cleanUpPaste.defer(100, this);
22579 }else if(Roo.isOpera){
22580 return function(e){
22581 var k = e.getKey();
22585 this.execCmd('InsertHTML','    ');
22588 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22589 this.cleanUpPaste.defer(100, this);
22594 }else if(Roo.isSafari){
22595 return function(e){
22596 var k = e.getKey();
22600 this.execCmd('InsertText','\t');
22604 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22605 this.cleanUpPaste.defer(100, this);
22613 getAllAncestors: function()
22615 var p = this.getSelectedNode();
22618 a.push(p); // push blank onto stack..
22619 p = this.getParentElement();
22623 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
22627 a.push(this.doc.body);
22631 lastSelNode : false,
22634 getSelection : function()
22636 this.assignDocWin();
22637 return Roo.isIE ? this.doc.selection : this.win.getSelection();
22640 getSelectedNode: function()
22642 // this may only work on Gecko!!!
22644 // should we cache this!!!!
22649 var range = this.createRange(this.getSelection()).cloneRange();
22652 var parent = range.parentElement();
22654 var testRange = range.duplicate();
22655 testRange.moveToElementText(parent);
22656 if (testRange.inRange(range)) {
22659 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
22662 parent = parent.parentElement;
22667 // is ancestor a text element.
22668 var ac = range.commonAncestorContainer;
22669 if (ac.nodeType == 3) {
22670 ac = ac.parentNode;
22673 var ar = ac.childNodes;
22676 var other_nodes = [];
22677 var has_other_nodes = false;
22678 for (var i=0;i<ar.length;i++) {
22679 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
22682 // fullly contained node.
22684 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
22689 // probably selected..
22690 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
22691 other_nodes.push(ar[i]);
22695 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
22700 has_other_nodes = true;
22702 if (!nodes.length && other_nodes.length) {
22703 nodes= other_nodes;
22705 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
22711 createRange: function(sel)
22713 // this has strange effects when using with
22714 // top toolbar - not sure if it's a great idea.
22715 //this.editor.contentWindow.focus();
22716 if (typeof sel != "undefined") {
22718 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
22720 return this.doc.createRange();
22723 return this.doc.createRange();
22726 getParentElement: function()
22729 this.assignDocWin();
22730 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
22732 var range = this.createRange(sel);
22735 var p = range.commonAncestorContainer;
22736 while (p.nodeType == 3) { // text node
22747 * Range intersection.. the hard stuff...
22751 * [ -- selected range --- ]
22755 * if end is before start or hits it. fail.
22756 * if start is after end or hits it fail.
22758 * if either hits (but other is outside. - then it's not
22764 // @see http://www.thismuchiknow.co.uk/?p=64.
22765 rangeIntersectsNode : function(range, node)
22767 var nodeRange = node.ownerDocument.createRange();
22769 nodeRange.selectNode(node);
22771 nodeRange.selectNodeContents(node);
22774 var rangeStartRange = range.cloneRange();
22775 rangeStartRange.collapse(true);
22777 var rangeEndRange = range.cloneRange();
22778 rangeEndRange.collapse(false);
22780 var nodeStartRange = nodeRange.cloneRange();
22781 nodeStartRange.collapse(true);
22783 var nodeEndRange = nodeRange.cloneRange();
22784 nodeEndRange.collapse(false);
22786 return rangeStartRange.compareBoundaryPoints(
22787 Range.START_TO_START, nodeEndRange) == -1 &&
22788 rangeEndRange.compareBoundaryPoints(
22789 Range.START_TO_START, nodeStartRange) == 1;
22793 rangeCompareNode : function(range, node)
22795 var nodeRange = node.ownerDocument.createRange();
22797 nodeRange.selectNode(node);
22799 nodeRange.selectNodeContents(node);
22803 range.collapse(true);
22805 nodeRange.collapse(true);
22807 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
22808 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
22810 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
22812 var nodeIsBefore = ss == 1;
22813 var nodeIsAfter = ee == -1;
22815 if (nodeIsBefore && nodeIsAfter) {
22818 if (!nodeIsBefore && nodeIsAfter) {
22819 return 1; //right trailed.
22822 if (nodeIsBefore && !nodeIsAfter) {
22823 return 2; // left trailed.
22829 // private? - in a new class?
22830 cleanUpPaste : function()
22832 // cleans up the whole document..
22833 Roo.log('cleanuppaste');
22835 this.cleanUpChildren(this.doc.body);
22836 var clean = this.cleanWordChars(this.doc.body.innerHTML);
22837 if (clean != this.doc.body.innerHTML) {
22838 this.doc.body.innerHTML = clean;
22843 cleanWordChars : function(input) {// change the chars to hex code
22844 var he = Roo.HtmlEditorCore;
22846 var output = input;
22847 Roo.each(he.swapCodes, function(sw) {
22848 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
22850 output = output.replace(swapper, sw[1]);
22857 cleanUpChildren : function (n)
22859 if (!n.childNodes.length) {
22862 for (var i = n.childNodes.length-1; i > -1 ; i--) {
22863 this.cleanUpChild(n.childNodes[i]);
22870 cleanUpChild : function (node)
22873 //console.log(node);
22874 if (node.nodeName == "#text") {
22875 // clean up silly Windows -- stuff?
22878 if (node.nodeName == "#comment") {
22879 node.parentNode.removeChild(node);
22880 // clean up silly Windows -- stuff?
22883 var lcname = node.tagName.toLowerCase();
22884 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
22885 // whitelist of tags..
22887 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
22889 node.parentNode.removeChild(node);
22894 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
22896 // remove <a name=....> as rendering on yahoo mailer is borked with this.
22897 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
22899 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
22900 // remove_keep_children = true;
22903 if (remove_keep_children) {
22904 this.cleanUpChildren(node);
22905 // inserts everything just before this node...
22906 while (node.childNodes.length) {
22907 var cn = node.childNodes[0];
22908 node.removeChild(cn);
22909 node.parentNode.insertBefore(cn, node);
22911 node.parentNode.removeChild(node);
22915 if (!node.attributes || !node.attributes.length) {
22916 this.cleanUpChildren(node);
22920 function cleanAttr(n,v)
22923 if (v.match(/^\./) || v.match(/^\//)) {
22926 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/) || v.match(/^ftp:/)) {
22929 if (v.match(/^#/)) {
22932 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
22933 node.removeAttribute(n);
22937 var cwhite = this.cwhite;
22938 var cblack = this.cblack;
22940 function cleanStyle(n,v)
22942 if (v.match(/expression/)) { //XSS?? should we even bother..
22943 node.removeAttribute(n);
22947 var parts = v.split(/;/);
22950 Roo.each(parts, function(p) {
22951 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
22955 var l = p.split(':').shift().replace(/\s+/g,'');
22956 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
22958 if ( cwhite.length && cblack.indexOf(l) > -1) {
22959 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22960 //node.removeAttribute(n);
22964 // only allow 'c whitelisted system attributes'
22965 if ( cwhite.length && cwhite.indexOf(l) < 0) {
22966 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22967 //node.removeAttribute(n);
22977 if (clean.length) {
22978 node.setAttribute(n, clean.join(';'));
22980 node.removeAttribute(n);
22986 for (var i = node.attributes.length-1; i > -1 ; i--) {
22987 var a = node.attributes[i];
22990 if (a.name.toLowerCase().substr(0,2)=='on') {
22991 node.removeAttribute(a.name);
22994 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
22995 node.removeAttribute(a.name);
22998 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
22999 cleanAttr(a.name,a.value); // fixme..
23002 if (a.name == 'style') {
23003 cleanStyle(a.name,a.value);
23006 /// clean up MS crap..
23007 // tecnically this should be a list of valid class'es..
23010 if (a.name == 'class') {
23011 if (a.value.match(/^Mso/)) {
23012 node.className = '';
23015 if (a.value.match(/^body$/)) {
23016 node.className = '';
23027 this.cleanUpChildren(node);
23033 * Clean up MS wordisms...
23035 cleanWord : function(node)
23040 this.cleanWord(this.doc.body);
23043 if (node.nodeName == "#text") {
23044 // clean up silly Windows -- stuff?
23047 if (node.nodeName == "#comment") {
23048 node.parentNode.removeChild(node);
23049 // clean up silly Windows -- stuff?
23053 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
23054 node.parentNode.removeChild(node);
23058 // remove - but keep children..
23059 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
23060 while (node.childNodes.length) {
23061 var cn = node.childNodes[0];
23062 node.removeChild(cn);
23063 node.parentNode.insertBefore(cn, node);
23065 node.parentNode.removeChild(node);
23066 this.iterateChildren(node, this.cleanWord);
23070 if (node.className.length) {
23072 var cn = node.className.split(/\W+/);
23074 Roo.each(cn, function(cls) {
23075 if (cls.match(/Mso[a-zA-Z]+/)) {
23080 node.className = cna.length ? cna.join(' ') : '';
23082 node.removeAttribute("class");
23086 if (node.hasAttribute("lang")) {
23087 node.removeAttribute("lang");
23090 if (node.hasAttribute("style")) {
23092 var styles = node.getAttribute("style").split(";");
23094 Roo.each(styles, function(s) {
23095 if (!s.match(/:/)) {
23098 var kv = s.split(":");
23099 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
23102 // what ever is left... we allow.
23105 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
23106 if (!nstyle.length) {
23107 node.removeAttribute('style');
23110 this.iterateChildren(node, this.cleanWord);
23116 * iterateChildren of a Node, calling fn each time, using this as the scole..
23117 * @param {DomNode} node node to iterate children of.
23118 * @param {Function} fn method of this class to call on each item.
23120 iterateChildren : function(node, fn)
23122 if (!node.childNodes.length) {
23125 for (var i = node.childNodes.length-1; i > -1 ; i--) {
23126 fn.call(this, node.childNodes[i])
23132 * cleanTableWidths.
23134 * Quite often pasting from word etc.. results in tables with column and widths.
23135 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
23138 cleanTableWidths : function(node)
23143 this.cleanTableWidths(this.doc.body);
23148 if (node.nodeName == "#text" || node.nodeName == "#comment") {
23151 Roo.log(node.tagName);
23152 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
23153 this.iterateChildren(node, this.cleanTableWidths);
23156 if (node.hasAttribute('width')) {
23157 node.removeAttribute('width');
23161 if (node.hasAttribute("style")) {
23164 var styles = node.getAttribute("style").split(";");
23166 Roo.each(styles, function(s) {
23167 if (!s.match(/:/)) {
23170 var kv = s.split(":");
23171 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
23174 // what ever is left... we allow.
23177 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
23178 if (!nstyle.length) {
23179 node.removeAttribute('style');
23183 this.iterateChildren(node, this.cleanTableWidths);
23191 domToHTML : function(currentElement, depth, nopadtext) {
23193 depth = depth || 0;
23194 nopadtext = nopadtext || false;
23196 if (!currentElement) {
23197 return this.domToHTML(this.doc.body);
23200 //Roo.log(currentElement);
23202 var allText = false;
23203 var nodeName = currentElement.nodeName;
23204 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
23206 if (nodeName == '#text') {
23208 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
23213 if (nodeName != 'BODY') {
23216 // Prints the node tagName, such as <A>, <IMG>, etc
23219 for(i = 0; i < currentElement.attributes.length;i++) {
23221 var aname = currentElement.attributes.item(i).name;
23222 if (!currentElement.attributes.item(i).value.length) {
23225 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
23228 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
23237 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
23240 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
23245 // Traverse the tree
23247 var currentElementChild = currentElement.childNodes.item(i);
23248 var allText = true;
23249 var innerHTML = '';
23251 while (currentElementChild) {
23252 // Formatting code (indent the tree so it looks nice on the screen)
23253 var nopad = nopadtext;
23254 if (lastnode == 'SPAN') {
23258 if (currentElementChild.nodeName == '#text') {
23259 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
23260 toadd = nopadtext ? toadd : toadd.trim();
23261 if (!nopad && toadd.length > 80) {
23262 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
23264 innerHTML += toadd;
23267 currentElementChild = currentElement.childNodes.item(i);
23273 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
23275 // Recursively traverse the tree structure of the child node
23276 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
23277 lastnode = currentElementChild.nodeName;
23279 currentElementChild=currentElement.childNodes.item(i);
23285 // The remaining code is mostly for formatting the tree
23286 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
23291 ret+= "</"+tagName+">";
23297 applyBlacklists : function()
23299 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
23300 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
23304 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
23305 if (b.indexOf(tag) > -1) {
23308 this.white.push(tag);
23312 Roo.each(w, function(tag) {
23313 if (b.indexOf(tag) > -1) {
23316 if (this.white.indexOf(tag) > -1) {
23319 this.white.push(tag);
23324 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
23325 if (w.indexOf(tag) > -1) {
23328 this.black.push(tag);
23332 Roo.each(b, function(tag) {
23333 if (w.indexOf(tag) > -1) {
23336 if (this.black.indexOf(tag) > -1) {
23339 this.black.push(tag);
23344 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
23345 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
23349 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
23350 if (b.indexOf(tag) > -1) {
23353 this.cwhite.push(tag);
23357 Roo.each(w, function(tag) {
23358 if (b.indexOf(tag) > -1) {
23361 if (this.cwhite.indexOf(tag) > -1) {
23364 this.cwhite.push(tag);
23369 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
23370 if (w.indexOf(tag) > -1) {
23373 this.cblack.push(tag);
23377 Roo.each(b, function(tag) {
23378 if (w.indexOf(tag) > -1) {
23381 if (this.cblack.indexOf(tag) > -1) {
23384 this.cblack.push(tag);
23389 setStylesheets : function(stylesheets)
23391 if(typeof(stylesheets) == 'string'){
23392 Roo.get(this.iframe.contentDocument.head).createChild({
23394 rel : 'stylesheet',
23403 Roo.each(stylesheets, function(s) {
23408 Roo.get(_this.iframe.contentDocument.head).createChild({
23410 rel : 'stylesheet',
23419 removeStylesheets : function()
23423 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
23428 setStyle : function(style)
23430 Roo.get(this.iframe.contentDocument.head).createChild({
23439 // hide stuff that is not compatible
23453 * @event specialkey
23457 * @cfg {String} fieldClass @hide
23460 * @cfg {String} focusClass @hide
23463 * @cfg {String} autoCreate @hide
23466 * @cfg {String} inputType @hide
23469 * @cfg {String} invalidClass @hide
23472 * @cfg {String} invalidText @hide
23475 * @cfg {String} msgFx @hide
23478 * @cfg {String} validateOnBlur @hide
23482 Roo.HtmlEditorCore.white = [
23483 'area', 'br', 'img', 'input', 'hr', 'wbr',
23485 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
23486 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
23487 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
23488 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
23489 'table', 'ul', 'xmp',
23491 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
23494 'dir', 'menu', 'ol', 'ul', 'dl',
23500 Roo.HtmlEditorCore.black = [
23501 // 'embed', 'object', // enable - backend responsiblity to clean thiese
23503 'base', 'basefont', 'bgsound', 'blink', 'body',
23504 'frame', 'frameset', 'head', 'html', 'ilayer',
23505 'iframe', 'layer', 'link', 'meta', 'object',
23506 'script', 'style' ,'title', 'xml' // clean later..
23508 Roo.HtmlEditorCore.clean = [
23509 'script', 'style', 'title', 'xml'
23511 Roo.HtmlEditorCore.remove = [
23516 Roo.HtmlEditorCore.ablack = [
23520 Roo.HtmlEditorCore.aclean = [
23521 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
23525 Roo.HtmlEditorCore.pwhite= [
23526 'http', 'https', 'mailto'
23529 // white listed style attributes.
23530 Roo.HtmlEditorCore.cwhite= [
23531 // 'text-align', /// default is to allow most things..
23537 // black listed style attributes.
23538 Roo.HtmlEditorCore.cblack= [
23539 // 'font-size' -- this can be set by the project
23543 Roo.HtmlEditorCore.swapCodes =[
23562 * @class Roo.bootstrap.HtmlEditor
23563 * @extends Roo.bootstrap.TextArea
23564 * Bootstrap HtmlEditor class
23567 * Create a new HtmlEditor
23568 * @param {Object} config The config object
23571 Roo.bootstrap.HtmlEditor = function(config){
23572 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
23573 if (!this.toolbars) {
23574 this.toolbars = [];
23577 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
23580 * @event initialize
23581 * Fires when the editor is fully initialized (including the iframe)
23582 * @param {HtmlEditor} this
23587 * Fires when the editor is first receives the focus. Any insertion must wait
23588 * until after this event.
23589 * @param {HtmlEditor} this
23593 * @event beforesync
23594 * Fires before the textarea is updated with content from the editor iframe. Return false
23595 * to cancel the sync.
23596 * @param {HtmlEditor} this
23597 * @param {String} html
23601 * @event beforepush
23602 * Fires before the iframe editor is updated with content from the textarea. Return false
23603 * to cancel the push.
23604 * @param {HtmlEditor} this
23605 * @param {String} html
23610 * Fires when the textarea is updated with content from the editor iframe.
23611 * @param {HtmlEditor} this
23612 * @param {String} html
23617 * Fires when the iframe editor is updated with content from the textarea.
23618 * @param {HtmlEditor} this
23619 * @param {String} html
23623 * @event editmodechange
23624 * Fires when the editor switches edit modes
23625 * @param {HtmlEditor} this
23626 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
23628 editmodechange: true,
23630 * @event editorevent
23631 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
23632 * @param {HtmlEditor} this
23636 * @event firstfocus
23637 * Fires when on first focus - needed by toolbars..
23638 * @param {HtmlEditor} this
23643 * Auto save the htmlEditor value as a file into Events
23644 * @param {HtmlEditor} this
23648 * @event savedpreview
23649 * preview the saved version of htmlEditor
23650 * @param {HtmlEditor} this
23657 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
23661 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
23666 * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
23671 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
23676 * @cfg {Number} height (in pixels)
23680 * @cfg {Number} width (in pixels)
23685 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
23688 stylesheets: false,
23693 // private properties
23694 validationEvent : false,
23696 initialized : false,
23699 onFocus : Roo.emptyFn,
23701 hideMode:'offsets',
23703 tbContainer : false,
23707 toolbarContainer :function() {
23708 return this.wrap.select('.x-html-editor-tb',true).first();
23712 * Protected method that will not generally be called directly. It
23713 * is called when the editor creates its toolbar. Override this method if you need to
23714 * add custom toolbar buttons.
23715 * @param {HtmlEditor} editor
23717 createToolbar : function(){
23718 Roo.log('renewing');
23719 Roo.log("create toolbars");
23721 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
23722 this.toolbars[0].render(this.toolbarContainer());
23726 // if (!editor.toolbars || !editor.toolbars.length) {
23727 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
23730 // for (var i =0 ; i < editor.toolbars.length;i++) {
23731 // editor.toolbars[i] = Roo.factory(
23732 // typeof(editor.toolbars[i]) == 'string' ?
23733 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
23734 // Roo.bootstrap.HtmlEditor);
23735 // editor.toolbars[i].init(editor);
23741 onRender : function(ct, position)
23743 // Roo.log("Call onRender: " + this.xtype);
23745 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
23747 this.wrap = this.inputEl().wrap({
23748 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
23751 this.editorcore.onRender(ct, position);
23753 if (this.resizable) {
23754 this.resizeEl = new Roo.Resizable(this.wrap, {
23758 minHeight : this.height,
23759 height: this.height,
23760 handles : this.resizable,
23763 resize : function(r, w, h) {
23764 _t.onResize(w,h); // -something
23770 this.createToolbar(this);
23773 if(!this.width && this.resizable){
23774 this.setSize(this.wrap.getSize());
23776 if (this.resizeEl) {
23777 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
23778 // should trigger onReize..
23784 onResize : function(w, h)
23786 Roo.log('resize: ' +w + ',' + h );
23787 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
23791 if(this.inputEl() ){
23792 if(typeof w == 'number'){
23793 var aw = w - this.wrap.getFrameWidth('lr');
23794 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
23797 if(typeof h == 'number'){
23798 var tbh = -11; // fixme it needs to tool bar size!
23799 for (var i =0; i < this.toolbars.length;i++) {
23800 // fixme - ask toolbars for heights?
23801 tbh += this.toolbars[i].el.getHeight();
23802 //if (this.toolbars[i].footer) {
23803 // tbh += this.toolbars[i].footer.el.getHeight();
23811 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
23812 ah -= 5; // knock a few pixes off for look..
23813 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
23817 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
23818 this.editorcore.onResize(ew,eh);
23823 * Toggles the editor between standard and source edit mode.
23824 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
23826 toggleSourceEdit : function(sourceEditMode)
23828 this.editorcore.toggleSourceEdit(sourceEditMode);
23830 if(this.editorcore.sourceEditMode){
23831 Roo.log('editor - showing textarea');
23834 // Roo.log(this.syncValue());
23836 this.inputEl().removeClass(['hide', 'x-hidden']);
23837 this.inputEl().dom.removeAttribute('tabIndex');
23838 this.inputEl().focus();
23840 Roo.log('editor - hiding textarea');
23842 // Roo.log(this.pushValue());
23845 this.inputEl().addClass(['hide', 'x-hidden']);
23846 this.inputEl().dom.setAttribute('tabIndex', -1);
23847 //this.deferFocus();
23850 if(this.resizable){
23851 this.setSize(this.wrap.getSize());
23854 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
23857 // private (for BoxComponent)
23858 adjustSize : Roo.BoxComponent.prototype.adjustSize,
23860 // private (for BoxComponent)
23861 getResizeEl : function(){
23865 // private (for BoxComponent)
23866 getPositionEl : function(){
23871 initEvents : function(){
23872 this.originalValue = this.getValue();
23876 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23879 // markInvalid : Roo.emptyFn,
23881 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23884 // clearInvalid : Roo.emptyFn,
23886 setValue : function(v){
23887 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
23888 this.editorcore.pushValue();
23893 deferFocus : function(){
23894 this.focus.defer(10, this);
23898 focus : function(){
23899 this.editorcore.focus();
23905 onDestroy : function(){
23911 for (var i =0; i < this.toolbars.length;i++) {
23912 // fixme - ask toolbars for heights?
23913 this.toolbars[i].onDestroy();
23916 this.wrap.dom.innerHTML = '';
23917 this.wrap.remove();
23922 onFirstFocus : function(){
23923 //Roo.log("onFirstFocus");
23924 this.editorcore.onFirstFocus();
23925 for (var i =0; i < this.toolbars.length;i++) {
23926 this.toolbars[i].onFirstFocus();
23932 syncValue : function()
23934 this.editorcore.syncValue();
23937 pushValue : function()
23939 this.editorcore.pushValue();
23943 // hide stuff that is not compatible
23957 * @event specialkey
23961 * @cfg {String} fieldClass @hide
23964 * @cfg {String} focusClass @hide
23967 * @cfg {String} autoCreate @hide
23970 * @cfg {String} inputType @hide
23974 * @cfg {String} invalidText @hide
23977 * @cfg {String} msgFx @hide
23980 * @cfg {String} validateOnBlur @hide
23989 Roo.namespace('Roo.bootstrap.htmleditor');
23991 * @class Roo.bootstrap.HtmlEditorToolbar1
23996 new Roo.bootstrap.HtmlEditor({
23999 new Roo.bootstrap.HtmlEditorToolbar1({
24000 disable : { fonts: 1 , format: 1, ..., ... , ...],
24006 * @cfg {Object} disable List of elements to disable..
24007 * @cfg {Array} btns List of additional buttons.
24011 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
24014 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
24017 Roo.apply(this, config);
24019 // default disabled, based on 'good practice'..
24020 this.disable = this.disable || {};
24021 Roo.applyIf(this.disable, {
24024 specialElements : true
24026 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
24028 this.editor = config.editor;
24029 this.editorcore = config.editor.editorcore;
24031 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
24033 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
24034 // dont call parent... till later.
24036 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
24041 editorcore : false,
24046 "h1","h2","h3","h4","h5","h6",
24048 "abbr", "acronym", "address", "cite", "samp", "var",
24052 onRender : function(ct, position)
24054 // Roo.log("Call onRender: " + this.xtype);
24056 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
24058 this.el.dom.style.marginBottom = '0';
24060 var editorcore = this.editorcore;
24061 var editor= this.editor;
24064 var btn = function(id,cmd , toggle, handler, html){
24066 var event = toggle ? 'toggle' : 'click';
24071 xns: Roo.bootstrap,
24075 enableToggle:toggle !== false,
24077 pressed : toggle ? false : null,
24080 a.listeners[toggle ? 'toggle' : 'click'] = function() {
24081 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
24087 // var cb_box = function...
24092 xns: Roo.bootstrap,
24097 xns: Roo.bootstrap,
24101 Roo.each(this.formats, function(f) {
24102 style.menu.items.push({
24104 xns: Roo.bootstrap,
24105 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
24110 editorcore.insertTag(this.tagname);
24117 children.push(style);
24119 btn('bold',false,true);
24120 btn('italic',false,true);
24121 btn('align-left', 'justifyleft',true);
24122 btn('align-center', 'justifycenter',true);
24123 btn('align-right' , 'justifyright',true);
24124 btn('link', false, false, function(btn) {
24125 //Roo.log("create link?");
24126 var url = prompt(this.createLinkText, this.defaultLinkValue);
24127 if(url && url != 'http:/'+'/'){
24128 this.editorcore.relayCmd('createlink', url);
24131 btn('list','insertunorderedlist',true);
24132 btn('pencil', false,true, function(btn){
24134 this.toggleSourceEdit(btn.pressed);
24137 if (this.editor.btns.length > 0) {
24138 for (var i = 0; i<this.editor.btns.length; i++) {
24139 children.push(this.editor.btns[i]);
24147 xns: Roo.bootstrap,
24152 xns: Roo.bootstrap,
24157 cog.menu.items.push({
24159 xns: Roo.bootstrap,
24160 html : Clean styles,
24165 editorcore.insertTag(this.tagname);
24174 this.xtype = 'NavSimplebar';
24176 for(var i=0;i< children.length;i++) {
24178 this.buttons.add(this.addxtypeChild(children[i]));
24182 editor.on('editorevent', this.updateToolbar, this);
24184 onBtnClick : function(id)
24186 this.editorcore.relayCmd(id);
24187 this.editorcore.focus();
24191 * Protected method that will not generally be called directly. It triggers
24192 * a toolbar update by reading the markup state of the current selection in the editor.
24194 updateToolbar: function(){
24196 if(!this.editorcore.activated){
24197 this.editor.onFirstFocus(); // is this neeed?
24201 var btns = this.buttons;
24202 var doc = this.editorcore.doc;
24203 btns.get('bold').setActive(doc.queryCommandState('bold'));
24204 btns.get('italic').setActive(doc.queryCommandState('italic'));
24205 //btns.get('underline').setActive(doc.queryCommandState('underline'));
24207 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
24208 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
24209 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
24211 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
24212 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
24215 var ans = this.editorcore.getAllAncestors();
24216 if (this.formatCombo) {
24219 var store = this.formatCombo.store;
24220 this.formatCombo.setValue("");
24221 for (var i =0; i < ans.length;i++) {
24222 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
24224 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
24232 // hides menus... - so this cant be on a menu...
24233 Roo.bootstrap.MenuMgr.hideAll();
24235 Roo.bootstrap.MenuMgr.hideAll();
24236 //this.editorsyncValue();
24238 onFirstFocus: function() {
24239 this.buttons.each(function(item){
24243 toggleSourceEdit : function(sourceEditMode){
24246 if(sourceEditMode){
24247 Roo.log("disabling buttons");
24248 this.buttons.each( function(item){
24249 if(item.cmd != 'pencil'){
24255 Roo.log("enabling buttons");
24256 if(this.editorcore.initialized){
24257 this.buttons.each( function(item){
24263 Roo.log("calling toggole on editor");
24264 // tell the editor that it's been pressed..
24265 this.editor.toggleSourceEdit(sourceEditMode);
24275 * @class Roo.bootstrap.Table.AbstractSelectionModel
24276 * @extends Roo.util.Observable
24277 * Abstract base class for grid SelectionModels. It provides the interface that should be
24278 * implemented by descendant classes. This class should not be directly instantiated.
24281 Roo.bootstrap.Table.AbstractSelectionModel = function(){
24282 this.locked = false;
24283 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
24287 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
24288 /** @ignore Called by the grid automatically. Do not call directly. */
24289 init : function(grid){
24295 * Locks the selections.
24298 this.locked = true;
24302 * Unlocks the selections.
24304 unlock : function(){
24305 this.locked = false;
24309 * Returns true if the selections are locked.
24310 * @return {Boolean}
24312 isLocked : function(){
24313 return this.locked;
24317 * @extends Roo.bootstrap.Table.AbstractSelectionModel
24318 * @class Roo.bootstrap.Table.RowSelectionModel
24319 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
24320 * It supports multiple selections and keyboard selection/navigation.
24322 * @param {Object} config
24325 Roo.bootstrap.Table.RowSelectionModel = function(config){
24326 Roo.apply(this, config);
24327 this.selections = new Roo.util.MixedCollection(false, function(o){
24332 this.lastActive = false;
24336 * @event selectionchange
24337 * Fires when the selection changes
24338 * @param {SelectionModel} this
24340 "selectionchange" : true,
24342 * @event afterselectionchange
24343 * Fires after the selection changes (eg. by key press or clicking)
24344 * @param {SelectionModel} this
24346 "afterselectionchange" : true,
24348 * @event beforerowselect
24349 * Fires when a row is selected being selected, return false to cancel.
24350 * @param {SelectionModel} this
24351 * @param {Number} rowIndex The selected index
24352 * @param {Boolean} keepExisting False if other selections will be cleared
24354 "beforerowselect" : true,
24357 * Fires when a row is selected.
24358 * @param {SelectionModel} this
24359 * @param {Number} rowIndex The selected index
24360 * @param {Roo.data.Record} r The record
24362 "rowselect" : true,
24364 * @event rowdeselect
24365 * Fires when a row is deselected.
24366 * @param {SelectionModel} this
24367 * @param {Number} rowIndex The selected index
24369 "rowdeselect" : true
24371 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
24372 this.locked = false;
24375 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
24377 * @cfg {Boolean} singleSelect
24378 * True to allow selection of only one row at a time (defaults to false)
24380 singleSelect : false,
24383 initEvents : function()
24386 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
24387 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
24388 //}else{ // allow click to work like normal
24389 // this.grid.on("rowclick", this.handleDragableRowClick, this);
24391 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
24392 this.grid.on("rowclick", this.handleMouseDown, this);
24394 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
24395 "up" : function(e){
24397 this.selectPrevious(e.shiftKey);
24398 }else if(this.last !== false && this.lastActive !== false){
24399 var last = this.last;
24400 this.selectRange(this.last, this.lastActive-1);
24401 this.grid.getView().focusRow(this.lastActive);
24402 if(last !== false){
24406 this.selectFirstRow();
24408 this.fireEvent("afterselectionchange", this);
24410 "down" : function(e){
24412 this.selectNext(e.shiftKey);
24413 }else if(this.last !== false && this.lastActive !== false){
24414 var last = this.last;
24415 this.selectRange(this.last, this.lastActive+1);
24416 this.grid.getView().focusRow(this.lastActive);
24417 if(last !== false){
24421 this.selectFirstRow();
24423 this.fireEvent("afterselectionchange", this);
24427 this.grid.store.on('load', function(){
24428 this.selections.clear();
24431 var view = this.grid.view;
24432 view.on("refresh", this.onRefresh, this);
24433 view.on("rowupdated", this.onRowUpdated, this);
24434 view.on("rowremoved", this.onRemove, this);
24439 onRefresh : function()
24441 var ds = this.grid.store, i, v = this.grid.view;
24442 var s = this.selections;
24443 s.each(function(r){
24444 if((i = ds.indexOfId(r.id)) != -1){
24453 onRemove : function(v, index, r){
24454 this.selections.remove(r);
24458 onRowUpdated : function(v, index, r){
24459 if(this.isSelected(r)){
24460 v.onRowSelect(index);
24466 * @param {Array} records The records to select
24467 * @param {Boolean} keepExisting (optional) True to keep existing selections
24469 selectRecords : function(records, keepExisting)
24472 this.clearSelections();
24474 var ds = this.grid.store;
24475 for(var i = 0, len = records.length; i < len; i++){
24476 this.selectRow(ds.indexOf(records[i]), true);
24481 * Gets the number of selected rows.
24484 getCount : function(){
24485 return this.selections.length;
24489 * Selects the first row in the grid.
24491 selectFirstRow : function(){
24496 * Select the last row.
24497 * @param {Boolean} keepExisting (optional) True to keep existing selections
24499 selectLastRow : function(keepExisting){
24500 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
24501 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
24505 * Selects the row immediately following the last selected row.
24506 * @param {Boolean} keepExisting (optional) True to keep existing selections
24508 selectNext : function(keepExisting)
24510 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
24511 this.selectRow(this.last+1, keepExisting);
24512 this.grid.getView().focusRow(this.last);
24517 * Selects the row that precedes the last selected row.
24518 * @param {Boolean} keepExisting (optional) True to keep existing selections
24520 selectPrevious : function(keepExisting){
24522 this.selectRow(this.last-1, keepExisting);
24523 this.grid.getView().focusRow(this.last);
24528 * Returns the selected records
24529 * @return {Array} Array of selected records
24531 getSelections : function(){
24532 return [].concat(this.selections.items);
24536 * Returns the first selected record.
24539 getSelected : function(){
24540 return this.selections.itemAt(0);
24545 * Clears all selections.
24547 clearSelections : function(fast)
24553 var ds = this.grid.store;
24554 var s = this.selections;
24555 s.each(function(r){
24556 this.deselectRow(ds.indexOfId(r.id));
24560 this.selections.clear();
24567 * Selects all rows.
24569 selectAll : function(){
24573 this.selections.clear();
24574 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
24575 this.selectRow(i, true);
24580 * Returns True if there is a selection.
24581 * @return {Boolean}
24583 hasSelection : function(){
24584 return this.selections.length > 0;
24588 * Returns True if the specified row is selected.
24589 * @param {Number/Record} record The record or index of the record to check
24590 * @return {Boolean}
24592 isSelected : function(index){
24593 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
24594 return (r && this.selections.key(r.id) ? true : false);
24598 * Returns True if the specified record id is selected.
24599 * @param {String} id The id of record to check
24600 * @return {Boolean}
24602 isIdSelected : function(id){
24603 return (this.selections.key(id) ? true : false);
24608 handleMouseDBClick : function(e, t){
24612 handleMouseDown : function(e, t)
24614 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
24615 if(this.isLocked() || rowIndex < 0 ){
24618 if(e.shiftKey && this.last !== false){
24619 var last = this.last;
24620 this.selectRange(last, rowIndex, e.ctrlKey);
24621 this.last = last; // reset the last
24625 var isSelected = this.isSelected(rowIndex);
24626 //Roo.log("select row:" + rowIndex);
24628 this.deselectRow(rowIndex);
24630 this.selectRow(rowIndex, true);
24634 if(e.button !== 0 && isSelected){
24635 alert('rowIndex 2: ' + rowIndex);
24636 view.focusRow(rowIndex);
24637 }else if(e.ctrlKey && isSelected){
24638 this.deselectRow(rowIndex);
24639 }else if(!isSelected){
24640 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
24641 view.focusRow(rowIndex);
24645 this.fireEvent("afterselectionchange", this);
24648 handleDragableRowClick : function(grid, rowIndex, e)
24650 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
24651 this.selectRow(rowIndex, false);
24652 grid.view.focusRow(rowIndex);
24653 this.fireEvent("afterselectionchange", this);
24658 * Selects multiple rows.
24659 * @param {Array} rows Array of the indexes of the row to select
24660 * @param {Boolean} keepExisting (optional) True to keep existing selections
24662 selectRows : function(rows, keepExisting){
24664 this.clearSelections();
24666 for(var i = 0, len = rows.length; i < len; i++){
24667 this.selectRow(rows[i], true);
24672 * Selects a range of rows. All rows in between startRow and endRow are also selected.
24673 * @param {Number} startRow The index of the first row in the range
24674 * @param {Number} endRow The index of the last row in the range
24675 * @param {Boolean} keepExisting (optional) True to retain existing selections
24677 selectRange : function(startRow, endRow, keepExisting){
24682 this.clearSelections();
24684 if(startRow <= endRow){
24685 for(var i = startRow; i <= endRow; i++){
24686 this.selectRow(i, true);
24689 for(var i = startRow; i >= endRow; i--){
24690 this.selectRow(i, true);
24696 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
24697 * @param {Number} startRow The index of the first row in the range
24698 * @param {Number} endRow The index of the last row in the range
24700 deselectRange : function(startRow, endRow, preventViewNotify){
24704 for(var i = startRow; i <= endRow; i++){
24705 this.deselectRow(i, preventViewNotify);
24711 * @param {Number} row The index of the row to select
24712 * @param {Boolean} keepExisting (optional) True to keep existing selections
24714 selectRow : function(index, keepExisting, preventViewNotify)
24716 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
24719 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
24720 if(!keepExisting || this.singleSelect){
24721 this.clearSelections();
24724 var r = this.grid.store.getAt(index);
24725 //console.log('selectRow - record id :' + r.id);
24727 this.selections.add(r);
24728 this.last = this.lastActive = index;
24729 if(!preventViewNotify){
24730 var proxy = new Roo.Element(
24731 this.grid.getRowDom(index)
24733 proxy.addClass('bg-info info');
24735 this.fireEvent("rowselect", this, index, r);
24736 this.fireEvent("selectionchange", this);
24742 * @param {Number} row The index of the row to deselect
24744 deselectRow : function(index, preventViewNotify)
24749 if(this.last == index){
24752 if(this.lastActive == index){
24753 this.lastActive = false;
24756 var r = this.grid.store.getAt(index);
24761 this.selections.remove(r);
24762 //.console.log('deselectRow - record id :' + r.id);
24763 if(!preventViewNotify){
24765 var proxy = new Roo.Element(
24766 this.grid.getRowDom(index)
24768 proxy.removeClass('bg-info info');
24770 this.fireEvent("rowdeselect", this, index);
24771 this.fireEvent("selectionchange", this);
24775 restoreLast : function(){
24777 this.last = this._last;
24782 acceptsNav : function(row, col, cm){
24783 return !cm.isHidden(col) && cm.isCellEditable(col, row);
24787 onEditorKey : function(field, e){
24788 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
24793 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
24795 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
24797 }else if(k == e.ENTER && !e.ctrlKey){
24801 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
24803 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
24805 }else if(k == e.ESC){
24809 g.startEditing(newCell[0], newCell[1]);
24815 * Ext JS Library 1.1.1
24816 * Copyright(c) 2006-2007, Ext JS, LLC.
24818 * Originally Released Under LGPL - original licence link has changed is not relivant.
24821 * <script type="text/javascript">
24825 * @class Roo.bootstrap.PagingToolbar
24826 * @extends Roo.bootstrap.NavSimplebar
24827 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
24829 * Create a new PagingToolbar
24830 * @param {Object} config The config object
24831 * @param {Roo.data.Store} store
24833 Roo.bootstrap.PagingToolbar = function(config)
24835 // old args format still supported... - xtype is prefered..
24836 // created from xtype...
24838 this.ds = config.dataSource;
24840 if (config.store && !this.ds) {
24841 this.store= Roo.factory(config.store, Roo.data);
24842 this.ds = this.store;
24843 this.ds.xmodule = this.xmodule || false;
24846 this.toolbarItems = [];
24847 if (config.items) {
24848 this.toolbarItems = config.items;
24851 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
24856 this.bind(this.ds);
24859 if (Roo.bootstrap.version == 4) {
24860 this.navgroup = new Roo.bootstrap.ButtonGroup({ cls: 'pagination' });
24862 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
24867 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
24869 * @cfg {Roo.data.Store} dataSource
24870 * The underlying data store providing the paged data
24873 * @cfg {String/HTMLElement/Element} container
24874 * container The id or element that will contain the toolbar
24877 * @cfg {Boolean} displayInfo
24878 * True to display the displayMsg (defaults to false)
24881 * @cfg {Number} pageSize
24882 * The number of records to display per page (defaults to 20)
24886 * @cfg {String} displayMsg
24887 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
24889 displayMsg : 'Displaying {0} - {1} of {2}',
24891 * @cfg {String} emptyMsg
24892 * The message to display when no records are found (defaults to "No data to display")
24894 emptyMsg : 'No data to display',
24896 * Customizable piece of the default paging text (defaults to "Page")
24899 beforePageText : "Page",
24901 * Customizable piece of the default paging text (defaults to "of %0")
24904 afterPageText : "of {0}",
24906 * Customizable piece of the default paging text (defaults to "First Page")
24909 firstText : "First Page",
24911 * Customizable piece of the default paging text (defaults to "Previous Page")
24914 prevText : "Previous Page",
24916 * Customizable piece of the default paging text (defaults to "Next Page")
24919 nextText : "Next Page",
24921 * Customizable piece of the default paging text (defaults to "Last Page")
24924 lastText : "Last Page",
24926 * Customizable piece of the default paging text (defaults to "Refresh")
24929 refreshText : "Refresh",
24933 onRender : function(ct, position)
24935 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
24936 this.navgroup.parentId = this.id;
24937 this.navgroup.onRender(this.el, null);
24938 // add the buttons to the navgroup
24940 if(this.displayInfo){
24941 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
24942 this.displayEl = this.el.select('.x-paging-info', true).first();
24943 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
24944 // this.displayEl = navel.el.select('span',true).first();
24950 Roo.each(_this.buttons, function(e){ // this might need to use render????
24951 Roo.factory(e).render(_this.el);
24955 Roo.each(_this.toolbarItems, function(e) {
24956 _this.navgroup.addItem(e);
24960 this.first = this.navgroup.addItem({
24961 tooltip: this.firstText,
24962 cls: "prev btn-outline-secondary",
24963 html : ' <i class="fa fa-step-backward"></i>',
24965 preventDefault: true,
24966 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
24969 this.prev = this.navgroup.addItem({
24970 tooltip: this.prevText,
24971 cls: "prev btn-outline-secondary",
24972 html : ' <i class="fa fa-backward"></i>',
24974 preventDefault: true,
24975 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
24977 //this.addSeparator();
24980 var field = this.navgroup.addItem( {
24982 cls : 'x-paging-position btn-outline-secondary',
24984 html : this.beforePageText +
24985 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
24986 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
24989 this.field = field.el.select('input', true).first();
24990 this.field.on("keydown", this.onPagingKeydown, this);
24991 this.field.on("focus", function(){this.dom.select();});
24994 this.afterTextEl = field.el.select('.x-paging-after',true).first();
24995 //this.field.setHeight(18);
24996 //this.addSeparator();
24997 this.next = this.navgroup.addItem({
24998 tooltip: this.nextText,
24999 cls: "next btn-outline-secondary",
25000 html : ' <i class="fa fa-forward"></i>',
25002 preventDefault: true,
25003 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
25005 this.last = this.navgroup.addItem({
25006 tooltip: this.lastText,
25007 html : ' <i class="fa fa-step-forward"></i>',
25008 cls: "next btn-outline-secondary",
25010 preventDefault: true,
25011 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
25013 //this.addSeparator();
25014 this.loading = this.navgroup.addItem({
25015 tooltip: this.refreshText,
25016 cls: "btn-outline-secondary",
25017 html : ' <i class="fa fa-refresh"></i>',
25018 preventDefault: true,
25019 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
25025 updateInfo : function(){
25026 if(this.displayEl){
25027 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
25028 var msg = count == 0 ?
25032 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
25034 this.displayEl.update(msg);
25039 onLoad : function(ds, r, o)
25041 this.cursor = o.params.start ? o.params.start : 0;
25043 var d = this.getPageData(),
25048 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
25049 this.field.dom.value = ap;
25050 this.first.setDisabled(ap == 1);
25051 this.prev.setDisabled(ap == 1);
25052 this.next.setDisabled(ap == ps);
25053 this.last.setDisabled(ap == ps);
25054 this.loading.enable();
25059 getPageData : function(){
25060 var total = this.ds.getTotalCount();
25063 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
25064 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
25069 onLoadError : function(){
25070 this.loading.enable();
25074 onPagingKeydown : function(e){
25075 var k = e.getKey();
25076 var d = this.getPageData();
25078 var v = this.field.dom.value, pageNum;
25079 if(!v || isNaN(pageNum = parseInt(v, 10))){
25080 this.field.dom.value = d.activePage;
25083 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
25084 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
25087 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))
25089 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
25090 this.field.dom.value = pageNum;
25091 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
25094 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
25096 var v = this.field.dom.value, pageNum;
25097 var increment = (e.shiftKey) ? 10 : 1;
25098 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
25101 if(!v || isNaN(pageNum = parseInt(v, 10))) {
25102 this.field.dom.value = d.activePage;
25105 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
25107 this.field.dom.value = parseInt(v, 10) + increment;
25108 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
25109 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
25116 beforeLoad : function(){
25118 this.loading.disable();
25123 onClick : function(which){
25132 ds.load({params:{start: 0, limit: this.pageSize}});
25135 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
25138 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
25141 var total = ds.getTotalCount();
25142 var extra = total % this.pageSize;
25143 var lastStart = extra ? (total - extra) : total-this.pageSize;
25144 ds.load({params:{start: lastStart, limit: this.pageSize}});
25147 ds.load({params:{start: this.cursor, limit: this.pageSize}});
25153 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
25154 * @param {Roo.data.Store} store The data store to unbind
25156 unbind : function(ds){
25157 ds.un("beforeload", this.beforeLoad, this);
25158 ds.un("load", this.onLoad, this);
25159 ds.un("loadexception", this.onLoadError, this);
25160 ds.un("remove", this.updateInfo, this);
25161 ds.un("add", this.updateInfo, this);
25162 this.ds = undefined;
25166 * Binds the paging toolbar to the specified {@link Roo.data.Store}
25167 * @param {Roo.data.Store} store The data store to bind
25169 bind : function(ds){
25170 ds.on("beforeload", this.beforeLoad, this);
25171 ds.on("load", this.onLoad, this);
25172 ds.on("loadexception", this.onLoadError, this);
25173 ds.on("remove", this.updateInfo, this);
25174 ds.on("add", this.updateInfo, this);
25185 * @class Roo.bootstrap.MessageBar
25186 * @extends Roo.bootstrap.Component
25187 * Bootstrap MessageBar class
25188 * @cfg {String} html contents of the MessageBar
25189 * @cfg {String} weight (info | success | warning | danger) default info
25190 * @cfg {String} beforeClass insert the bar before the given class
25191 * @cfg {Boolean} closable (true | false) default false
25192 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
25195 * Create a new Element
25196 * @param {Object} config The config object
25199 Roo.bootstrap.MessageBar = function(config){
25200 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
25203 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
25209 beforeClass: 'bootstrap-sticky-wrap',
25211 getAutoCreate : function(){
25215 cls: 'alert alert-dismissable alert-' + this.weight,
25220 html: this.html || ''
25226 cfg.cls += ' alert-messages-fixed';
25240 onRender : function(ct, position)
25242 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
25245 var cfg = Roo.apply({}, this.getAutoCreate());
25249 cfg.cls += ' ' + this.cls;
25252 cfg.style = this.style;
25254 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
25256 this.el.setVisibilityMode(Roo.Element.DISPLAY);
25259 this.el.select('>button.close').on('click', this.hide, this);
25265 if (!this.rendered) {
25271 this.fireEvent('show', this);
25277 if (!this.rendered) {
25283 this.fireEvent('hide', this);
25286 update : function()
25288 // var e = this.el.dom.firstChild;
25290 // if(this.closable){
25291 // e = e.nextSibling;
25294 // e.data = this.html || '';
25296 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
25312 * @class Roo.bootstrap.Graph
25313 * @extends Roo.bootstrap.Component
25314 * Bootstrap Graph class
25318 @cfg {String} graphtype bar | vbar | pie
25319 @cfg {number} g_x coodinator | centre x (pie)
25320 @cfg {number} g_y coodinator | centre y (pie)
25321 @cfg {number} g_r radius (pie)
25322 @cfg {number} g_height height of the chart (respected by all elements in the set)
25323 @cfg {number} g_width width of the chart (respected by all elements in the set)
25324 @cfg {Object} title The title of the chart
25327 -opts (object) options for the chart
25329 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
25330 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
25332 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.
25333 o stacked (boolean) whether or not to tread values as in a stacked bar chart
25335 o stretch (boolean)
25337 -opts (object) options for the pie
25340 o startAngle (number)
25341 o endAngle (number)
25345 * Create a new Input
25346 * @param {Object} config The config object
25349 Roo.bootstrap.Graph = function(config){
25350 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
25356 * The img click event for the img.
25357 * @param {Roo.EventObject} e
25363 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
25374 //g_colors: this.colors,
25381 getAutoCreate : function(){
25392 onRender : function(ct,position){
25395 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
25397 if (typeof(Raphael) == 'undefined') {
25398 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
25402 this.raphael = Raphael(this.el.dom);
25404 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25405 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25406 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25407 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
25409 r.text(160, 10, "Single Series Chart").attr(txtattr);
25410 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
25411 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
25412 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
25414 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
25415 r.barchart(330, 10, 300, 220, data1);
25416 r.barchart(10, 250, 300, 220, data2, {stacked: true});
25417 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
25420 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25421 // r.barchart(30, 30, 560, 250, xdata, {
25422 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
25423 // axis : "0 0 1 1",
25424 // axisxlabels : xdata
25425 // //yvalues : cols,
25428 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25430 // this.load(null,xdata,{
25431 // axis : "0 0 1 1",
25432 // axisxlabels : xdata
25437 load : function(graphtype,xdata,opts)
25439 this.raphael.clear();
25441 graphtype = this.graphtype;
25446 var r = this.raphael,
25447 fin = function () {
25448 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
25450 fout = function () {
25451 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
25453 pfin = function() {
25454 this.sector.stop();
25455 this.sector.scale(1.1, 1.1, this.cx, this.cy);
25458 this.label[0].stop();
25459 this.label[0].attr({ r: 7.5 });
25460 this.label[1].attr({ "font-weight": 800 });
25463 pfout = function() {
25464 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
25467 this.label[0].animate({ r: 5 }, 500, "bounce");
25468 this.label[1].attr({ "font-weight": 400 });
25474 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25477 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25480 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
25481 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
25483 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
25490 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
25495 setTitle: function(o)
25500 initEvents: function() {
25503 this.el.on('click', this.onClick, this);
25507 onClick : function(e)
25509 Roo.log('img onclick');
25510 this.fireEvent('click', this, e);
25522 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25525 * @class Roo.bootstrap.dash.NumberBox
25526 * @extends Roo.bootstrap.Component
25527 * Bootstrap NumberBox class
25528 * @cfg {String} headline Box headline
25529 * @cfg {String} content Box content
25530 * @cfg {String} icon Box icon
25531 * @cfg {String} footer Footer text
25532 * @cfg {String} fhref Footer href
25535 * Create a new NumberBox
25536 * @param {Object} config The config object
25540 Roo.bootstrap.dash.NumberBox = function(config){
25541 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
25545 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
25554 getAutoCreate : function(){
25558 cls : 'small-box ',
25566 cls : 'roo-headline',
25567 html : this.headline
25571 cls : 'roo-content',
25572 html : this.content
25586 cls : 'ion ' + this.icon
25595 cls : 'small-box-footer',
25596 href : this.fhref || '#',
25600 cfg.cn.push(footer);
25607 onRender : function(ct,position){
25608 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
25615 setHeadline: function (value)
25617 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
25620 setFooter: function (value, href)
25622 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
25625 this.el.select('a.small-box-footer',true).first().attr('href', href);
25630 setContent: function (value)
25632 this.el.select('.roo-content',true).first().dom.innerHTML = value;
25635 initEvents: function()
25649 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25652 * @class Roo.bootstrap.dash.TabBox
25653 * @extends Roo.bootstrap.Component
25654 * Bootstrap TabBox class
25655 * @cfg {String} title Title of the TabBox
25656 * @cfg {String} icon Icon of the TabBox
25657 * @cfg {Boolean} showtabs (true|false) show the tabs default true
25658 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
25661 * Create a new TabBox
25662 * @param {Object} config The config object
25666 Roo.bootstrap.dash.TabBox = function(config){
25667 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
25672 * When a pane is added
25673 * @param {Roo.bootstrap.dash.TabPane} pane
25677 * @event activatepane
25678 * When a pane is activated
25679 * @param {Roo.bootstrap.dash.TabPane} pane
25681 "activatepane" : true
25689 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
25694 tabScrollable : false,
25696 getChildContainer : function()
25698 return this.el.select('.tab-content', true).first();
25701 getAutoCreate : function(){
25705 cls: 'pull-left header',
25713 cls: 'fa ' + this.icon
25719 cls: 'nav nav-tabs pull-right',
25725 if(this.tabScrollable){
25732 cls: 'nav nav-tabs pull-right',
25743 cls: 'nav-tabs-custom',
25748 cls: 'tab-content no-padding',
25756 initEvents : function()
25758 //Roo.log('add add pane handler');
25759 this.on('addpane', this.onAddPane, this);
25762 * Updates the box title
25763 * @param {String} html to set the title to.
25765 setTitle : function(value)
25767 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
25769 onAddPane : function(pane)
25771 this.panes.push(pane);
25772 //Roo.log('addpane');
25774 // tabs are rendere left to right..
25775 if(!this.showtabs){
25779 var ctr = this.el.select('.nav-tabs', true).first();
25782 var existing = ctr.select('.nav-tab',true);
25783 var qty = existing.getCount();;
25786 var tab = ctr.createChild({
25788 cls : 'nav-tab' + (qty ? '' : ' active'),
25796 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
25799 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
25801 pane.el.addClass('active');
25806 onTabClick : function(ev,un,ob,pane)
25808 //Roo.log('tab - prev default');
25809 ev.preventDefault();
25812 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
25813 pane.tab.addClass('active');
25814 //Roo.log(pane.title);
25815 this.getChildContainer().select('.tab-pane',true).removeClass('active');
25816 // technically we should have a deactivate event.. but maybe add later.
25817 // and it should not de-activate the selected tab...
25818 this.fireEvent('activatepane', pane);
25819 pane.el.addClass('active');
25820 pane.fireEvent('activate');
25825 getActivePane : function()
25828 Roo.each(this.panes, function(p) {
25829 if(p.el.hasClass('active')){
25850 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25852 * @class Roo.bootstrap.TabPane
25853 * @extends Roo.bootstrap.Component
25854 * Bootstrap TabPane class
25855 * @cfg {Boolean} active (false | true) Default false
25856 * @cfg {String} title title of panel
25860 * Create a new TabPane
25861 * @param {Object} config The config object
25864 Roo.bootstrap.dash.TabPane = function(config){
25865 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
25871 * When a pane is activated
25872 * @param {Roo.bootstrap.dash.TabPane} pane
25879 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
25884 // the tabBox that this is attached to.
25887 getAutoCreate : function()
25895 cfg.cls += ' active';
25900 initEvents : function()
25902 //Roo.log('trigger add pane handler');
25903 this.parent().fireEvent('addpane', this)
25907 * Updates the tab title
25908 * @param {String} html to set the title to.
25910 setTitle: function(str)
25916 this.tab.select('a', true).first().dom.innerHTML = str;
25933 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25936 * @class Roo.bootstrap.menu.Menu
25937 * @extends Roo.bootstrap.Component
25938 * Bootstrap Menu class - container for Menu
25939 * @cfg {String} html Text of the menu
25940 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
25941 * @cfg {String} icon Font awesome icon
25942 * @cfg {String} pos Menu align to (top | bottom) default bottom
25946 * Create a new Menu
25947 * @param {Object} config The config object
25951 Roo.bootstrap.menu.Menu = function(config){
25952 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
25956 * @event beforeshow
25957 * Fires before this menu is displayed
25958 * @param {Roo.bootstrap.menu.Menu} this
25962 * @event beforehide
25963 * Fires before this menu is hidden
25964 * @param {Roo.bootstrap.menu.Menu} this
25969 * Fires after this menu is displayed
25970 * @param {Roo.bootstrap.menu.Menu} this
25975 * Fires after this menu is hidden
25976 * @param {Roo.bootstrap.menu.Menu} this
25981 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
25982 * @param {Roo.bootstrap.menu.Menu} this
25983 * @param {Roo.EventObject} e
25990 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
25994 weight : 'default',
25999 getChildContainer : function() {
26000 if(this.isSubMenu){
26004 return this.el.select('ul.dropdown-menu', true).first();
26007 getAutoCreate : function()
26012 cls : 'roo-menu-text',
26020 cls : 'fa ' + this.icon
26031 cls : 'dropdown-button btn btn-' + this.weight,
26036 cls : 'dropdown-toggle btn btn-' + this.weight,
26046 cls : 'dropdown-menu'
26052 if(this.pos == 'top'){
26053 cfg.cls += ' dropup';
26056 if(this.isSubMenu){
26059 cls : 'dropdown-menu'
26066 onRender : function(ct, position)
26068 this.isSubMenu = ct.hasClass('dropdown-submenu');
26070 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
26073 initEvents : function()
26075 if(this.isSubMenu){
26079 this.hidden = true;
26081 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
26082 this.triggerEl.on('click', this.onTriggerPress, this);
26084 this.buttonEl = this.el.select('button.dropdown-button', true).first();
26085 this.buttonEl.on('click', this.onClick, this);
26091 if(this.isSubMenu){
26095 return this.el.select('ul.dropdown-menu', true).first();
26098 onClick : function(e)
26100 this.fireEvent("click", this, e);
26103 onTriggerPress : function(e)
26105 if (this.isVisible()) {
26112 isVisible : function(){
26113 return !this.hidden;
26118 this.fireEvent("beforeshow", this);
26120 this.hidden = false;
26121 this.el.addClass('open');
26123 Roo.get(document).on("mouseup", this.onMouseUp, this);
26125 this.fireEvent("show", this);
26132 this.fireEvent("beforehide", this);
26134 this.hidden = true;
26135 this.el.removeClass('open');
26137 Roo.get(document).un("mouseup", this.onMouseUp);
26139 this.fireEvent("hide", this);
26142 onMouseUp : function()
26156 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
26159 * @class Roo.bootstrap.menu.Item
26160 * @extends Roo.bootstrap.Component
26161 * Bootstrap MenuItem class
26162 * @cfg {Boolean} submenu (true | false) default false
26163 * @cfg {String} html text of the item
26164 * @cfg {String} href the link
26165 * @cfg {Boolean} disable (true | false) default false
26166 * @cfg {Boolean} preventDefault (true | false) default true
26167 * @cfg {String} icon Font awesome icon
26168 * @cfg {String} pos Submenu align to (left | right) default right
26172 * Create a new Item
26173 * @param {Object} config The config object
26177 Roo.bootstrap.menu.Item = function(config){
26178 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
26182 * Fires when the mouse is hovering over this menu
26183 * @param {Roo.bootstrap.menu.Item} this
26184 * @param {Roo.EventObject} e
26189 * Fires when the mouse exits this menu
26190 * @param {Roo.bootstrap.menu.Item} this
26191 * @param {Roo.EventObject} e
26197 * The raw click event for the entire grid.
26198 * @param {Roo.EventObject} e
26204 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
26209 preventDefault: true,
26214 getAutoCreate : function()
26219 cls : 'roo-menu-item-text',
26227 cls : 'fa ' + this.icon
26236 href : this.href || '#',
26243 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
26247 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
26249 if(this.pos == 'left'){
26250 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
26257 initEvents : function()
26259 this.el.on('mouseover', this.onMouseOver, this);
26260 this.el.on('mouseout', this.onMouseOut, this);
26262 this.el.select('a', true).first().on('click', this.onClick, this);
26266 onClick : function(e)
26268 if(this.preventDefault){
26269 e.preventDefault();
26272 this.fireEvent("click", this, e);
26275 onMouseOver : function(e)
26277 if(this.submenu && this.pos == 'left'){
26278 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
26281 this.fireEvent("mouseover", this, e);
26284 onMouseOut : function(e)
26286 this.fireEvent("mouseout", this, e);
26298 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
26301 * @class Roo.bootstrap.menu.Separator
26302 * @extends Roo.bootstrap.Component
26303 * Bootstrap Separator class
26306 * Create a new Separator
26307 * @param {Object} config The config object
26311 Roo.bootstrap.menu.Separator = function(config){
26312 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
26315 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
26317 getAutoCreate : function(){
26338 * @class Roo.bootstrap.Tooltip
26339 * Bootstrap Tooltip class
26340 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
26341 * to determine which dom element triggers the tooltip.
26343 * It needs to add support for additional attributes like tooltip-position
26346 * Create a new Toolti
26347 * @param {Object} config The config object
26350 Roo.bootstrap.Tooltip = function(config){
26351 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
26353 this.alignment = Roo.bootstrap.Tooltip.alignment;
26355 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
26356 this.alignment = config.alignment;
26361 Roo.apply(Roo.bootstrap.Tooltip, {
26363 * @function init initialize tooltip monitoring.
26367 currentTip : false,
26368 currentRegion : false,
26374 Roo.get(document).on('mouseover', this.enter ,this);
26375 Roo.get(document).on('mouseout', this.leave, this);
26378 this.currentTip = new Roo.bootstrap.Tooltip();
26381 enter : function(ev)
26383 var dom = ev.getTarget();
26385 //Roo.log(['enter',dom]);
26386 var el = Roo.fly(dom);
26387 if (this.currentEl) {
26389 //Roo.log(this.currentEl);
26390 //Roo.log(this.currentEl.contains(dom));
26391 if (this.currentEl == el) {
26394 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
26400 if (this.currentTip.el) {
26401 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
26405 if(!el || el.dom == document){
26411 // you can not look for children, as if el is the body.. then everythign is the child..
26412 if (!el.attr('tooltip')) { //
26413 if (!el.select("[tooltip]").elements.length) {
26416 // is the mouse over this child...?
26417 bindEl = el.select("[tooltip]").first();
26418 var xy = ev.getXY();
26419 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
26420 //Roo.log("not in region.");
26423 //Roo.log("child element over..");
26426 this.currentEl = bindEl;
26427 this.currentTip.bind(bindEl);
26428 this.currentRegion = Roo.lib.Region.getRegion(dom);
26429 this.currentTip.enter();
26432 leave : function(ev)
26434 var dom = ev.getTarget();
26435 //Roo.log(['leave',dom]);
26436 if (!this.currentEl) {
26441 if (dom != this.currentEl.dom) {
26444 var xy = ev.getXY();
26445 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
26448 // only activate leave if mouse cursor is outside... bounding box..
26453 if (this.currentTip) {
26454 this.currentTip.leave();
26456 //Roo.log('clear currentEl');
26457 this.currentEl = false;
26462 'left' : ['r-l', [-2,0], 'right'],
26463 'right' : ['l-r', [2,0], 'left'],
26464 'bottom' : ['t-b', [0,2], 'top'],
26465 'top' : [ 'b-t', [0,-2], 'bottom']
26471 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
26476 delay : null, // can be { show : 300 , hide: 500}
26480 hoverState : null, //???
26482 placement : 'bottom',
26486 getAutoCreate : function(){
26493 cls : 'tooltip-arrow'
26496 cls : 'tooltip-inner'
26503 bind : function(el)
26509 enter : function () {
26511 if (this.timeout != null) {
26512 clearTimeout(this.timeout);
26515 this.hoverState = 'in';
26516 //Roo.log("enter - show");
26517 if (!this.delay || !this.delay.show) {
26522 this.timeout = setTimeout(function () {
26523 if (_t.hoverState == 'in') {
26526 }, this.delay.show);
26530 clearTimeout(this.timeout);
26532 this.hoverState = 'out';
26533 if (!this.delay || !this.delay.hide) {
26539 this.timeout = setTimeout(function () {
26540 //Roo.log("leave - timeout");
26542 if (_t.hoverState == 'out') {
26544 Roo.bootstrap.Tooltip.currentEl = false;
26549 show : function (msg)
26552 this.render(document.body);
26555 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
26557 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
26559 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
26561 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
26563 var placement = typeof this.placement == 'function' ?
26564 this.placement.call(this, this.el, on_el) :
26567 var autoToken = /\s?auto?\s?/i;
26568 var autoPlace = autoToken.test(placement);
26570 placement = placement.replace(autoToken, '') || 'top';
26574 //this.el.setXY([0,0]);
26576 //this.el.dom.style.display='block';
26578 //this.el.appendTo(on_el);
26580 var p = this.getPosition();
26581 var box = this.el.getBox();
26587 var align = this.alignment[placement];
26589 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
26591 if(placement == 'top' || placement == 'bottom'){
26593 placement = 'right';
26596 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
26597 placement = 'left';
26600 var scroll = Roo.select('body', true).first().getScroll();
26602 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
26606 align = this.alignment[placement];
26609 this.el.alignTo(this.bindEl, align[0],align[1]);
26610 //var arrow = this.el.select('.arrow',true).first();
26611 //arrow.set(align[2],
26613 this.el.addClass(placement);
26615 this.el.addClass('in fade');
26617 this.hoverState = null;
26619 if (this.el.hasClass('fade')) {
26630 //this.el.setXY([0,0]);
26631 this.el.removeClass('in');
26647 * @class Roo.bootstrap.LocationPicker
26648 * @extends Roo.bootstrap.Component
26649 * Bootstrap LocationPicker class
26650 * @cfg {Number} latitude Position when init default 0
26651 * @cfg {Number} longitude Position when init default 0
26652 * @cfg {Number} zoom default 15
26653 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
26654 * @cfg {Boolean} mapTypeControl default false
26655 * @cfg {Boolean} disableDoubleClickZoom default false
26656 * @cfg {Boolean} scrollwheel default true
26657 * @cfg {Boolean} streetViewControl default false
26658 * @cfg {Number} radius default 0
26659 * @cfg {String} locationName
26660 * @cfg {Boolean} draggable default true
26661 * @cfg {Boolean} enableAutocomplete default false
26662 * @cfg {Boolean} enableReverseGeocode default true
26663 * @cfg {String} markerTitle
26666 * Create a new LocationPicker
26667 * @param {Object} config The config object
26671 Roo.bootstrap.LocationPicker = function(config){
26673 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
26678 * Fires when the picker initialized.
26679 * @param {Roo.bootstrap.LocationPicker} this
26680 * @param {Google Location} location
26684 * @event positionchanged
26685 * Fires when the picker position changed.
26686 * @param {Roo.bootstrap.LocationPicker} this
26687 * @param {Google Location} location
26689 positionchanged : true,
26692 * Fires when the map resize.
26693 * @param {Roo.bootstrap.LocationPicker} this
26698 * Fires when the map show.
26699 * @param {Roo.bootstrap.LocationPicker} this
26704 * Fires when the map hide.
26705 * @param {Roo.bootstrap.LocationPicker} this
26710 * Fires when click the map.
26711 * @param {Roo.bootstrap.LocationPicker} this
26712 * @param {Map event} e
26716 * @event mapRightClick
26717 * Fires when right click the map.
26718 * @param {Roo.bootstrap.LocationPicker} this
26719 * @param {Map event} e
26721 mapRightClick : true,
26723 * @event markerClick
26724 * Fires when click the marker.
26725 * @param {Roo.bootstrap.LocationPicker} this
26726 * @param {Map event} e
26728 markerClick : true,
26730 * @event markerRightClick
26731 * Fires when right click the marker.
26732 * @param {Roo.bootstrap.LocationPicker} this
26733 * @param {Map event} e
26735 markerRightClick : true,
26737 * @event OverlayViewDraw
26738 * Fires when OverlayView Draw
26739 * @param {Roo.bootstrap.LocationPicker} this
26741 OverlayViewDraw : true,
26743 * @event OverlayViewOnAdd
26744 * Fires when OverlayView Draw
26745 * @param {Roo.bootstrap.LocationPicker} this
26747 OverlayViewOnAdd : true,
26749 * @event OverlayViewOnRemove
26750 * Fires when OverlayView Draw
26751 * @param {Roo.bootstrap.LocationPicker} this
26753 OverlayViewOnRemove : true,
26755 * @event OverlayViewShow
26756 * Fires when OverlayView Draw
26757 * @param {Roo.bootstrap.LocationPicker} this
26758 * @param {Pixel} cpx
26760 OverlayViewShow : true,
26762 * @event OverlayViewHide
26763 * Fires when OverlayView Draw
26764 * @param {Roo.bootstrap.LocationPicker} this
26766 OverlayViewHide : true,
26768 * @event loadexception
26769 * Fires when load google lib failed.
26770 * @param {Roo.bootstrap.LocationPicker} this
26772 loadexception : true
26777 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
26779 gMapContext: false,
26785 mapTypeControl: false,
26786 disableDoubleClickZoom: false,
26788 streetViewControl: false,
26792 enableAutocomplete: false,
26793 enableReverseGeocode: true,
26796 getAutoCreate: function()
26801 cls: 'roo-location-picker'
26807 initEvents: function(ct, position)
26809 if(!this.el.getWidth() || this.isApplied()){
26813 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26818 initial: function()
26820 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
26821 this.fireEvent('loadexception', this);
26825 if(!this.mapTypeId){
26826 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
26829 this.gMapContext = this.GMapContext();
26831 this.initOverlayView();
26833 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
26837 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
26838 _this.setPosition(_this.gMapContext.marker.position);
26841 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
26842 _this.fireEvent('mapClick', this, event);
26846 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
26847 _this.fireEvent('mapRightClick', this, event);
26851 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
26852 _this.fireEvent('markerClick', this, event);
26856 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
26857 _this.fireEvent('markerRightClick', this, event);
26861 this.setPosition(this.gMapContext.location);
26863 this.fireEvent('initial', this, this.gMapContext.location);
26866 initOverlayView: function()
26870 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
26874 _this.fireEvent('OverlayViewDraw', _this);
26879 _this.fireEvent('OverlayViewOnAdd', _this);
26882 onRemove: function()
26884 _this.fireEvent('OverlayViewOnRemove', _this);
26887 show: function(cpx)
26889 _this.fireEvent('OverlayViewShow', _this, cpx);
26894 _this.fireEvent('OverlayViewHide', _this);
26900 fromLatLngToContainerPixel: function(event)
26902 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
26905 isApplied: function()
26907 return this.getGmapContext() == false ? false : true;
26910 getGmapContext: function()
26912 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
26915 GMapContext: function()
26917 var position = new google.maps.LatLng(this.latitude, this.longitude);
26919 var _map = new google.maps.Map(this.el.dom, {
26922 mapTypeId: this.mapTypeId,
26923 mapTypeControl: this.mapTypeControl,
26924 disableDoubleClickZoom: this.disableDoubleClickZoom,
26925 scrollwheel: this.scrollwheel,
26926 streetViewControl: this.streetViewControl,
26927 locationName: this.locationName,
26928 draggable: this.draggable,
26929 enableAutocomplete: this.enableAutocomplete,
26930 enableReverseGeocode: this.enableReverseGeocode
26933 var _marker = new google.maps.Marker({
26934 position: position,
26936 title: this.markerTitle,
26937 draggable: this.draggable
26944 location: position,
26945 radius: this.radius,
26946 locationName: this.locationName,
26947 addressComponents: {
26948 formatted_address: null,
26949 addressLine1: null,
26950 addressLine2: null,
26952 streetNumber: null,
26956 stateOrProvince: null
26959 domContainer: this.el.dom,
26960 geodecoder: new google.maps.Geocoder()
26964 drawCircle: function(center, radius, options)
26966 if (this.gMapContext.circle != null) {
26967 this.gMapContext.circle.setMap(null);
26971 options = Roo.apply({}, options, {
26972 strokeColor: "#0000FF",
26973 strokeOpacity: .35,
26975 fillColor: "#0000FF",
26979 options.map = this.gMapContext.map;
26980 options.radius = radius;
26981 options.center = center;
26982 this.gMapContext.circle = new google.maps.Circle(options);
26983 return this.gMapContext.circle;
26989 setPosition: function(location)
26991 this.gMapContext.location = location;
26992 this.gMapContext.marker.setPosition(location);
26993 this.gMapContext.map.panTo(location);
26994 this.drawCircle(location, this.gMapContext.radius, {});
26998 if (this.gMapContext.settings.enableReverseGeocode) {
26999 this.gMapContext.geodecoder.geocode({
27000 latLng: this.gMapContext.location
27001 }, function(results, status) {
27003 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
27004 _this.gMapContext.locationName = results[0].formatted_address;
27005 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
27007 _this.fireEvent('positionchanged', this, location);
27014 this.fireEvent('positionchanged', this, location);
27019 google.maps.event.trigger(this.gMapContext.map, "resize");
27021 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
27023 this.fireEvent('resize', this);
27026 setPositionByLatLng: function(latitude, longitude)
27028 this.setPosition(new google.maps.LatLng(latitude, longitude));
27031 getCurrentPosition: function()
27034 latitude: this.gMapContext.location.lat(),
27035 longitude: this.gMapContext.location.lng()
27039 getAddressName: function()
27041 return this.gMapContext.locationName;
27044 getAddressComponents: function()
27046 return this.gMapContext.addressComponents;
27049 address_component_from_google_geocode: function(address_components)
27053 for (var i = 0; i < address_components.length; i++) {
27054 var component = address_components[i];
27055 if (component.types.indexOf("postal_code") >= 0) {
27056 result.postalCode = component.short_name;
27057 } else if (component.types.indexOf("street_number") >= 0) {
27058 result.streetNumber = component.short_name;
27059 } else if (component.types.indexOf("route") >= 0) {
27060 result.streetName = component.short_name;
27061 } else if (component.types.indexOf("neighborhood") >= 0) {
27062 result.city = component.short_name;
27063 } else if (component.types.indexOf("locality") >= 0) {
27064 result.city = component.short_name;
27065 } else if (component.types.indexOf("sublocality") >= 0) {
27066 result.district = component.short_name;
27067 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
27068 result.stateOrProvince = component.short_name;
27069 } else if (component.types.indexOf("country") >= 0) {
27070 result.country = component.short_name;
27074 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
27075 result.addressLine2 = "";
27079 setZoomLevel: function(zoom)
27081 this.gMapContext.map.setZoom(zoom);
27094 this.fireEvent('show', this);
27105 this.fireEvent('hide', this);
27110 Roo.apply(Roo.bootstrap.LocationPicker, {
27112 OverlayView : function(map, options)
27114 options = options || {};
27128 * @class Roo.bootstrap.Alert
27129 * @extends Roo.bootstrap.Component
27130 * Bootstrap Alert class
27131 * @cfg {String} title The title of alert
27132 * @cfg {String} html The content of alert
27133 * @cfg {String} weight ( success | info | warning | danger )
27134 * @cfg {String} faicon font-awesomeicon
27137 * Create a new alert
27138 * @param {Object} config The config object
27142 Roo.bootstrap.Alert = function(config){
27143 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
27147 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
27154 getAutoCreate : function()
27163 cls : 'roo-alert-icon'
27168 cls : 'roo-alert-title',
27173 cls : 'roo-alert-text',
27180 cfg.cn[0].cls += ' fa ' + this.faicon;
27184 cfg.cls += ' alert-' + this.weight;
27190 initEvents: function()
27192 this.el.setVisibilityMode(Roo.Element.DISPLAY);
27195 setTitle : function(str)
27197 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
27200 setText : function(str)
27202 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
27205 setWeight : function(weight)
27208 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
27211 this.weight = weight;
27213 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
27216 setIcon : function(icon)
27219 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
27222 this.faicon = icon;
27224 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
27245 * @class Roo.bootstrap.UploadCropbox
27246 * @extends Roo.bootstrap.Component
27247 * Bootstrap UploadCropbox class
27248 * @cfg {String} emptyText show when image has been loaded
27249 * @cfg {String} rotateNotify show when image too small to rotate
27250 * @cfg {Number} errorTimeout default 3000
27251 * @cfg {Number} minWidth default 300
27252 * @cfg {Number} minHeight default 300
27253 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
27254 * @cfg {Boolean} isDocument (true|false) default false
27255 * @cfg {String} url action url
27256 * @cfg {String} paramName default 'imageUpload'
27257 * @cfg {String} method default POST
27258 * @cfg {Boolean} loadMask (true|false) default true
27259 * @cfg {Boolean} loadingText default 'Loading...'
27262 * Create a new UploadCropbox
27263 * @param {Object} config The config object
27266 Roo.bootstrap.UploadCropbox = function(config){
27267 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
27271 * @event beforeselectfile
27272 * Fire before select file
27273 * @param {Roo.bootstrap.UploadCropbox} this
27275 "beforeselectfile" : true,
27278 * Fire after initEvent
27279 * @param {Roo.bootstrap.UploadCropbox} this
27284 * Fire after initEvent
27285 * @param {Roo.bootstrap.UploadCropbox} this
27286 * @param {String} data
27291 * Fire when preparing the file data
27292 * @param {Roo.bootstrap.UploadCropbox} this
27293 * @param {Object} file
27298 * Fire when get exception
27299 * @param {Roo.bootstrap.UploadCropbox} this
27300 * @param {XMLHttpRequest} xhr
27302 "exception" : true,
27304 * @event beforeloadcanvas
27305 * Fire before load the canvas
27306 * @param {Roo.bootstrap.UploadCropbox} this
27307 * @param {String} src
27309 "beforeloadcanvas" : true,
27312 * Fire when trash image
27313 * @param {Roo.bootstrap.UploadCropbox} this
27318 * Fire when download the image
27319 * @param {Roo.bootstrap.UploadCropbox} this
27323 * @event footerbuttonclick
27324 * Fire when footerbuttonclick
27325 * @param {Roo.bootstrap.UploadCropbox} this
27326 * @param {String} type
27328 "footerbuttonclick" : true,
27332 * @param {Roo.bootstrap.UploadCropbox} this
27337 * Fire when rotate the image
27338 * @param {Roo.bootstrap.UploadCropbox} this
27339 * @param {String} pos
27344 * Fire when inspect the file
27345 * @param {Roo.bootstrap.UploadCropbox} this
27346 * @param {Object} file
27351 * Fire when xhr upload the file
27352 * @param {Roo.bootstrap.UploadCropbox} this
27353 * @param {Object} data
27358 * Fire when arrange the file data
27359 * @param {Roo.bootstrap.UploadCropbox} this
27360 * @param {Object} formData
27365 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
27368 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
27370 emptyText : 'Click to upload image',
27371 rotateNotify : 'Image is too small to rotate',
27372 errorTimeout : 3000,
27386 cropType : 'image/jpeg',
27388 canvasLoaded : false,
27389 isDocument : false,
27391 paramName : 'imageUpload',
27393 loadingText : 'Loading...',
27396 getAutoCreate : function()
27400 cls : 'roo-upload-cropbox',
27404 cls : 'roo-upload-cropbox-selector',
27409 cls : 'roo-upload-cropbox-body',
27410 style : 'cursor:pointer',
27414 cls : 'roo-upload-cropbox-preview'
27418 cls : 'roo-upload-cropbox-thumb'
27422 cls : 'roo-upload-cropbox-empty-notify',
27423 html : this.emptyText
27427 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
27428 html : this.rotateNotify
27434 cls : 'roo-upload-cropbox-footer',
27437 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
27447 onRender : function(ct, position)
27449 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
27451 if (this.buttons.length) {
27453 Roo.each(this.buttons, function(bb) {
27455 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
27457 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
27463 this.maskEl = this.el;
27467 initEvents : function()
27469 this.urlAPI = (window.createObjectURL && window) ||
27470 (window.URL && URL.revokeObjectURL && URL) ||
27471 (window.webkitURL && webkitURL);
27473 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
27474 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27476 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
27477 this.selectorEl.hide();
27479 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
27480 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27482 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
27483 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27484 this.thumbEl.hide();
27486 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
27487 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27489 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
27490 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27491 this.errorEl.hide();
27493 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
27494 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27495 this.footerEl.hide();
27497 this.setThumbBoxSize();
27503 this.fireEvent('initial', this);
27510 window.addEventListener("resize", function() { _this.resize(); } );
27512 this.bodyEl.on('click', this.beforeSelectFile, this);
27515 this.bodyEl.on('touchstart', this.onTouchStart, this);
27516 this.bodyEl.on('touchmove', this.onTouchMove, this);
27517 this.bodyEl.on('touchend', this.onTouchEnd, this);
27521 this.bodyEl.on('mousedown', this.onMouseDown, this);
27522 this.bodyEl.on('mousemove', this.onMouseMove, this);
27523 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
27524 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
27525 Roo.get(document).on('mouseup', this.onMouseUp, this);
27528 this.selectorEl.on('change', this.onFileSelected, this);
27534 this.baseScale = 1;
27536 this.baseRotate = 1;
27537 this.dragable = false;
27538 this.pinching = false;
27541 this.cropData = false;
27542 this.notifyEl.dom.innerHTML = this.emptyText;
27544 this.selectorEl.dom.value = '';
27548 resize : function()
27550 if(this.fireEvent('resize', this) != false){
27551 this.setThumbBoxPosition();
27552 this.setCanvasPosition();
27556 onFooterButtonClick : function(e, el, o, type)
27559 case 'rotate-left' :
27560 this.onRotateLeft(e);
27562 case 'rotate-right' :
27563 this.onRotateRight(e);
27566 this.beforeSelectFile(e);
27581 this.fireEvent('footerbuttonclick', this, type);
27584 beforeSelectFile : function(e)
27586 e.preventDefault();
27588 if(this.fireEvent('beforeselectfile', this) != false){
27589 this.selectorEl.dom.click();
27593 onFileSelected : function(e)
27595 e.preventDefault();
27597 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
27601 var file = this.selectorEl.dom.files[0];
27603 if(this.fireEvent('inspect', this, file) != false){
27604 this.prepare(file);
27609 trash : function(e)
27611 this.fireEvent('trash', this);
27614 download : function(e)
27616 this.fireEvent('download', this);
27619 loadCanvas : function(src)
27621 if(this.fireEvent('beforeloadcanvas', this, src) != false){
27625 this.imageEl = document.createElement('img');
27629 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
27631 this.imageEl.src = src;
27635 onLoadCanvas : function()
27637 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
27638 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
27640 this.bodyEl.un('click', this.beforeSelectFile, this);
27642 this.notifyEl.hide();
27643 this.thumbEl.show();
27644 this.footerEl.show();
27646 this.baseRotateLevel();
27648 if(this.isDocument){
27649 this.setThumbBoxSize();
27652 this.setThumbBoxPosition();
27654 this.baseScaleLevel();
27660 this.canvasLoaded = true;
27663 this.maskEl.unmask();
27668 setCanvasPosition : function()
27670 if(!this.canvasEl){
27674 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
27675 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
27677 this.previewEl.setLeft(pw);
27678 this.previewEl.setTop(ph);
27682 onMouseDown : function(e)
27686 this.dragable = true;
27687 this.pinching = false;
27689 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
27690 this.dragable = false;
27694 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27695 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27699 onMouseMove : function(e)
27703 if(!this.canvasLoaded){
27707 if (!this.dragable){
27711 var minX = Math.ceil(this.thumbEl.getLeft(true));
27712 var minY = Math.ceil(this.thumbEl.getTop(true));
27714 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
27715 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
27717 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27718 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27720 x = x - this.mouseX;
27721 y = y - this.mouseY;
27723 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
27724 var bgY = Math.ceil(y + this.previewEl.getTop(true));
27726 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
27727 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
27729 this.previewEl.setLeft(bgX);
27730 this.previewEl.setTop(bgY);
27732 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27733 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27736 onMouseUp : function(e)
27740 this.dragable = false;
27743 onMouseWheel : function(e)
27747 this.startScale = this.scale;
27749 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
27751 if(!this.zoomable()){
27752 this.scale = this.startScale;
27761 zoomable : function()
27763 var minScale = this.thumbEl.getWidth() / this.minWidth;
27765 if(this.minWidth < this.minHeight){
27766 minScale = this.thumbEl.getHeight() / this.minHeight;
27769 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
27770 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
27774 (this.rotate == 0 || this.rotate == 180) &&
27776 width > this.imageEl.OriginWidth ||
27777 height > this.imageEl.OriginHeight ||
27778 (width < this.minWidth && height < this.minHeight)
27786 (this.rotate == 90 || this.rotate == 270) &&
27788 width > this.imageEl.OriginWidth ||
27789 height > this.imageEl.OriginHeight ||
27790 (width < this.minHeight && height < this.minWidth)
27797 !this.isDocument &&
27798 (this.rotate == 0 || this.rotate == 180) &&
27800 width < this.minWidth ||
27801 width > this.imageEl.OriginWidth ||
27802 height < this.minHeight ||
27803 height > this.imageEl.OriginHeight
27810 !this.isDocument &&
27811 (this.rotate == 90 || this.rotate == 270) &&
27813 width < this.minHeight ||
27814 width > this.imageEl.OriginWidth ||
27815 height < this.minWidth ||
27816 height > this.imageEl.OriginHeight
27826 onRotateLeft : function(e)
27828 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27830 var minScale = this.thumbEl.getWidth() / this.minWidth;
27832 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27833 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27835 this.startScale = this.scale;
27837 while (this.getScaleLevel() < minScale){
27839 this.scale = this.scale + 1;
27841 if(!this.zoomable()){
27846 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27847 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27852 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27859 this.scale = this.startScale;
27861 this.onRotateFail();
27866 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27868 if(this.isDocument){
27869 this.setThumbBoxSize();
27870 this.setThumbBoxPosition();
27871 this.setCanvasPosition();
27876 this.fireEvent('rotate', this, 'left');
27880 onRotateRight : function(e)
27882 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27884 var minScale = this.thumbEl.getWidth() / this.minWidth;
27886 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27887 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27889 this.startScale = this.scale;
27891 while (this.getScaleLevel() < minScale){
27893 this.scale = this.scale + 1;
27895 if(!this.zoomable()){
27900 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27901 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27906 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27913 this.scale = this.startScale;
27915 this.onRotateFail();
27920 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27922 if(this.isDocument){
27923 this.setThumbBoxSize();
27924 this.setThumbBoxPosition();
27925 this.setCanvasPosition();
27930 this.fireEvent('rotate', this, 'right');
27933 onRotateFail : function()
27935 this.errorEl.show(true);
27939 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
27944 this.previewEl.dom.innerHTML = '';
27946 var canvasEl = document.createElement("canvas");
27948 var contextEl = canvasEl.getContext("2d");
27950 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27951 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27952 var center = this.imageEl.OriginWidth / 2;
27954 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
27955 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27956 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27957 center = this.imageEl.OriginHeight / 2;
27960 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
27962 contextEl.translate(center, center);
27963 contextEl.rotate(this.rotate * Math.PI / 180);
27965 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27967 this.canvasEl = document.createElement("canvas");
27969 this.contextEl = this.canvasEl.getContext("2d");
27971 switch (this.rotate) {
27974 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27975 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27977 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27982 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27983 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27985 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27986 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);
27990 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27995 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27996 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27998 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27999 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);
28003 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);
28008 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
28009 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
28011 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28012 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
28016 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);
28023 this.previewEl.appendChild(this.canvasEl);
28025 this.setCanvasPosition();
28030 if(!this.canvasLoaded){
28034 var imageCanvas = document.createElement("canvas");
28036 var imageContext = imageCanvas.getContext("2d");
28038 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
28039 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
28041 var center = imageCanvas.width / 2;
28043 imageContext.translate(center, center);
28045 imageContext.rotate(this.rotate * Math.PI / 180);
28047 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
28049 var canvas = document.createElement("canvas");
28051 var context = canvas.getContext("2d");
28053 canvas.width = this.minWidth;
28054 canvas.height = this.minHeight;
28056 switch (this.rotate) {
28059 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
28060 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
28062 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28063 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28065 var targetWidth = this.minWidth - 2 * x;
28066 var targetHeight = this.minHeight - 2 * y;
28070 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28071 scale = targetWidth / width;
28074 if(x > 0 && y == 0){
28075 scale = targetHeight / height;
28078 if(x > 0 && y > 0){
28079 scale = targetWidth / width;
28081 if(width < height){
28082 scale = targetHeight / height;
28086 context.scale(scale, scale);
28088 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28089 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28091 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28092 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28094 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28099 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
28100 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
28102 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28103 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28105 var targetWidth = this.minWidth - 2 * x;
28106 var targetHeight = this.minHeight - 2 * y;
28110 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28111 scale = targetWidth / width;
28114 if(x > 0 && y == 0){
28115 scale = targetHeight / height;
28118 if(x > 0 && y > 0){
28119 scale = targetWidth / width;
28121 if(width < height){
28122 scale = targetHeight / height;
28126 context.scale(scale, scale);
28128 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28129 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28131 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28132 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28134 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
28136 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28141 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
28142 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
28144 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28145 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28147 var targetWidth = this.minWidth - 2 * x;
28148 var targetHeight = this.minHeight - 2 * y;
28152 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28153 scale = targetWidth / width;
28156 if(x > 0 && y == 0){
28157 scale = targetHeight / height;
28160 if(x > 0 && y > 0){
28161 scale = targetWidth / width;
28163 if(width < height){
28164 scale = targetHeight / height;
28168 context.scale(scale, scale);
28170 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28171 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28173 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28174 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28176 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
28177 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
28179 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28184 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
28185 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
28187 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28188 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28190 var targetWidth = this.minWidth - 2 * x;
28191 var targetHeight = this.minHeight - 2 * y;
28195 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28196 scale = targetWidth / width;
28199 if(x > 0 && y == 0){
28200 scale = targetHeight / height;
28203 if(x > 0 && y > 0){
28204 scale = targetWidth / width;
28206 if(width < height){
28207 scale = targetHeight / height;
28211 context.scale(scale, scale);
28213 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28214 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28216 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28217 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28219 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
28221 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28228 this.cropData = canvas.toDataURL(this.cropType);
28230 if(this.fireEvent('crop', this, this.cropData) !== false){
28231 this.process(this.file, this.cropData);
28238 setThumbBoxSize : function()
28242 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
28243 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
28244 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
28246 this.minWidth = width;
28247 this.minHeight = height;
28249 if(this.rotate == 90 || this.rotate == 270){
28250 this.minWidth = height;
28251 this.minHeight = width;
28256 width = Math.ceil(this.minWidth * height / this.minHeight);
28258 if(this.minWidth > this.minHeight){
28260 height = Math.ceil(this.minHeight * width / this.minWidth);
28263 this.thumbEl.setStyle({
28264 width : width + 'px',
28265 height : height + 'px'
28272 setThumbBoxPosition : function()
28274 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
28275 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
28277 this.thumbEl.setLeft(x);
28278 this.thumbEl.setTop(y);
28282 baseRotateLevel : function()
28284 this.baseRotate = 1;
28287 typeof(this.exif) != 'undefined' &&
28288 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
28289 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
28291 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
28294 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
28298 baseScaleLevel : function()
28302 if(this.isDocument){
28304 if(this.baseRotate == 6 || this.baseRotate == 8){
28306 height = this.thumbEl.getHeight();
28307 this.baseScale = height / this.imageEl.OriginWidth;
28309 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
28310 width = this.thumbEl.getWidth();
28311 this.baseScale = width / this.imageEl.OriginHeight;
28317 height = this.thumbEl.getHeight();
28318 this.baseScale = height / this.imageEl.OriginHeight;
28320 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
28321 width = this.thumbEl.getWidth();
28322 this.baseScale = width / this.imageEl.OriginWidth;
28328 if(this.baseRotate == 6 || this.baseRotate == 8){
28330 width = this.thumbEl.getHeight();
28331 this.baseScale = width / this.imageEl.OriginHeight;
28333 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
28334 height = this.thumbEl.getWidth();
28335 this.baseScale = height / this.imageEl.OriginHeight;
28338 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28339 height = this.thumbEl.getWidth();
28340 this.baseScale = height / this.imageEl.OriginHeight;
28342 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
28343 width = this.thumbEl.getHeight();
28344 this.baseScale = width / this.imageEl.OriginWidth;
28351 width = this.thumbEl.getWidth();
28352 this.baseScale = width / this.imageEl.OriginWidth;
28354 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
28355 height = this.thumbEl.getHeight();
28356 this.baseScale = height / this.imageEl.OriginHeight;
28359 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28361 height = this.thumbEl.getHeight();
28362 this.baseScale = height / this.imageEl.OriginHeight;
28364 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
28365 width = this.thumbEl.getWidth();
28366 this.baseScale = width / this.imageEl.OriginWidth;
28374 getScaleLevel : function()
28376 return this.baseScale * Math.pow(1.1, this.scale);
28379 onTouchStart : function(e)
28381 if(!this.canvasLoaded){
28382 this.beforeSelectFile(e);
28386 var touches = e.browserEvent.touches;
28392 if(touches.length == 1){
28393 this.onMouseDown(e);
28397 if(touches.length != 2){
28403 for(var i = 0, finger; finger = touches[i]; i++){
28404 coords.push(finger.pageX, finger.pageY);
28407 var x = Math.pow(coords[0] - coords[2], 2);
28408 var y = Math.pow(coords[1] - coords[3], 2);
28410 this.startDistance = Math.sqrt(x + y);
28412 this.startScale = this.scale;
28414 this.pinching = true;
28415 this.dragable = false;
28419 onTouchMove : function(e)
28421 if(!this.pinching && !this.dragable){
28425 var touches = e.browserEvent.touches;
28432 this.onMouseMove(e);
28438 for(var i = 0, finger; finger = touches[i]; i++){
28439 coords.push(finger.pageX, finger.pageY);
28442 var x = Math.pow(coords[0] - coords[2], 2);
28443 var y = Math.pow(coords[1] - coords[3], 2);
28445 this.endDistance = Math.sqrt(x + y);
28447 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
28449 if(!this.zoomable()){
28450 this.scale = this.startScale;
28458 onTouchEnd : function(e)
28460 this.pinching = false;
28461 this.dragable = false;
28465 process : function(file, crop)
28468 this.maskEl.mask(this.loadingText);
28471 this.xhr = new XMLHttpRequest();
28473 file.xhr = this.xhr;
28475 this.xhr.open(this.method, this.url, true);
28478 "Accept": "application/json",
28479 "Cache-Control": "no-cache",
28480 "X-Requested-With": "XMLHttpRequest"
28483 for (var headerName in headers) {
28484 var headerValue = headers[headerName];
28486 this.xhr.setRequestHeader(headerName, headerValue);
28492 this.xhr.onload = function()
28494 _this.xhrOnLoad(_this.xhr);
28497 this.xhr.onerror = function()
28499 _this.xhrOnError(_this.xhr);
28502 var formData = new FormData();
28504 formData.append('returnHTML', 'NO');
28507 formData.append('crop', crop);
28510 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
28511 formData.append(this.paramName, file, file.name);
28514 if(typeof(file.filename) != 'undefined'){
28515 formData.append('filename', file.filename);
28518 if(typeof(file.mimetype) != 'undefined'){
28519 formData.append('mimetype', file.mimetype);
28522 if(this.fireEvent('arrange', this, formData) != false){
28523 this.xhr.send(formData);
28527 xhrOnLoad : function(xhr)
28530 this.maskEl.unmask();
28533 if (xhr.readyState !== 4) {
28534 this.fireEvent('exception', this, xhr);
28538 var response = Roo.decode(xhr.responseText);
28540 if(!response.success){
28541 this.fireEvent('exception', this, xhr);
28545 var response = Roo.decode(xhr.responseText);
28547 this.fireEvent('upload', this, response);
28551 xhrOnError : function()
28554 this.maskEl.unmask();
28557 Roo.log('xhr on error');
28559 var response = Roo.decode(xhr.responseText);
28565 prepare : function(file)
28568 this.maskEl.mask(this.loadingText);
28574 if(typeof(file) === 'string'){
28575 this.loadCanvas(file);
28579 if(!file || !this.urlAPI){
28584 this.cropType = file.type;
28588 if(this.fireEvent('prepare', this, this.file) != false){
28590 var reader = new FileReader();
28592 reader.onload = function (e) {
28593 if (e.target.error) {
28594 Roo.log(e.target.error);
28598 var buffer = e.target.result,
28599 dataView = new DataView(buffer),
28601 maxOffset = dataView.byteLength - 4,
28605 if (dataView.getUint16(0) === 0xffd8) {
28606 while (offset < maxOffset) {
28607 markerBytes = dataView.getUint16(offset);
28609 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
28610 markerLength = dataView.getUint16(offset + 2) + 2;
28611 if (offset + markerLength > dataView.byteLength) {
28612 Roo.log('Invalid meta data: Invalid segment size.');
28616 if(markerBytes == 0xffe1){
28617 _this.parseExifData(
28624 offset += markerLength;
28634 var url = _this.urlAPI.createObjectURL(_this.file);
28636 _this.loadCanvas(url);
28641 reader.readAsArrayBuffer(this.file);
28647 parseExifData : function(dataView, offset, length)
28649 var tiffOffset = offset + 10,
28653 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28654 // No Exif data, might be XMP data instead
28658 // Check for the ASCII code for "Exif" (0x45786966):
28659 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28660 // No Exif data, might be XMP data instead
28663 if (tiffOffset + 8 > dataView.byteLength) {
28664 Roo.log('Invalid Exif data: Invalid segment size.');
28667 // Check for the two null bytes:
28668 if (dataView.getUint16(offset + 8) !== 0x0000) {
28669 Roo.log('Invalid Exif data: Missing byte alignment offset.');
28672 // Check the byte alignment:
28673 switch (dataView.getUint16(tiffOffset)) {
28675 littleEndian = true;
28678 littleEndian = false;
28681 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
28684 // Check for the TIFF tag marker (0x002A):
28685 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
28686 Roo.log('Invalid Exif data: Missing TIFF marker.');
28689 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
28690 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
28692 this.parseExifTags(
28695 tiffOffset + dirOffset,
28700 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
28705 if (dirOffset + 6 > dataView.byteLength) {
28706 Roo.log('Invalid Exif data: Invalid directory offset.');
28709 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
28710 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
28711 if (dirEndOffset + 4 > dataView.byteLength) {
28712 Roo.log('Invalid Exif data: Invalid directory size.');
28715 for (i = 0; i < tagsNumber; i += 1) {
28719 dirOffset + 2 + 12 * i, // tag offset
28723 // Return the offset to the next directory:
28724 return dataView.getUint32(dirEndOffset, littleEndian);
28727 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
28729 var tag = dataView.getUint16(offset, littleEndian);
28731 this.exif[tag] = this.getExifValue(
28735 dataView.getUint16(offset + 2, littleEndian), // tag type
28736 dataView.getUint32(offset + 4, littleEndian), // tag length
28741 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
28743 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
28752 Roo.log('Invalid Exif data: Invalid tag type.');
28756 tagSize = tagType.size * length;
28757 // Determine if the value is contained in the dataOffset bytes,
28758 // or if the value at the dataOffset is a pointer to the actual data:
28759 dataOffset = tagSize > 4 ?
28760 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
28761 if (dataOffset + tagSize > dataView.byteLength) {
28762 Roo.log('Invalid Exif data: Invalid data offset.');
28765 if (length === 1) {
28766 return tagType.getValue(dataView, dataOffset, littleEndian);
28769 for (i = 0; i < length; i += 1) {
28770 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
28773 if (tagType.ascii) {
28775 // Concatenate the chars:
28776 for (i = 0; i < values.length; i += 1) {
28778 // Ignore the terminating NULL byte(s):
28779 if (c === '\u0000') {
28791 Roo.apply(Roo.bootstrap.UploadCropbox, {
28793 'Orientation': 0x0112
28797 1: 0, //'top-left',
28799 3: 180, //'bottom-right',
28800 // 4: 'bottom-left',
28802 6: 90, //'right-top',
28803 // 7: 'right-bottom',
28804 8: 270 //'left-bottom'
28808 // byte, 8-bit unsigned int:
28810 getValue: function (dataView, dataOffset) {
28811 return dataView.getUint8(dataOffset);
28815 // ascii, 8-bit byte:
28817 getValue: function (dataView, dataOffset) {
28818 return String.fromCharCode(dataView.getUint8(dataOffset));
28823 // short, 16 bit int:
28825 getValue: function (dataView, dataOffset, littleEndian) {
28826 return dataView.getUint16(dataOffset, littleEndian);
28830 // long, 32 bit int:
28832 getValue: function (dataView, dataOffset, littleEndian) {
28833 return dataView.getUint32(dataOffset, littleEndian);
28837 // rational = two long values, first is numerator, second is denominator:
28839 getValue: function (dataView, dataOffset, littleEndian) {
28840 return dataView.getUint32(dataOffset, littleEndian) /
28841 dataView.getUint32(dataOffset + 4, littleEndian);
28845 // slong, 32 bit signed int:
28847 getValue: function (dataView, dataOffset, littleEndian) {
28848 return dataView.getInt32(dataOffset, littleEndian);
28852 // srational, two slongs, first is numerator, second is denominator:
28854 getValue: function (dataView, dataOffset, littleEndian) {
28855 return dataView.getInt32(dataOffset, littleEndian) /
28856 dataView.getInt32(dataOffset + 4, littleEndian);
28866 cls : 'btn-group roo-upload-cropbox-rotate-left',
28867 action : 'rotate-left',
28871 cls : 'btn btn-default',
28872 html : '<i class="fa fa-undo"></i>'
28878 cls : 'btn-group roo-upload-cropbox-picture',
28879 action : 'picture',
28883 cls : 'btn btn-default',
28884 html : '<i class="fa fa-picture-o"></i>'
28890 cls : 'btn-group roo-upload-cropbox-rotate-right',
28891 action : 'rotate-right',
28895 cls : 'btn btn-default',
28896 html : '<i class="fa fa-repeat"></i>'
28904 cls : 'btn-group roo-upload-cropbox-rotate-left',
28905 action : 'rotate-left',
28909 cls : 'btn btn-default',
28910 html : '<i class="fa fa-undo"></i>'
28916 cls : 'btn-group roo-upload-cropbox-download',
28917 action : 'download',
28921 cls : 'btn btn-default',
28922 html : '<i class="fa fa-download"></i>'
28928 cls : 'btn-group roo-upload-cropbox-crop',
28933 cls : 'btn btn-default',
28934 html : '<i class="fa fa-crop"></i>'
28940 cls : 'btn-group roo-upload-cropbox-trash',
28945 cls : 'btn btn-default',
28946 html : '<i class="fa fa-trash"></i>'
28952 cls : 'btn-group roo-upload-cropbox-rotate-right',
28953 action : 'rotate-right',
28957 cls : 'btn btn-default',
28958 html : '<i class="fa fa-repeat"></i>'
28966 cls : 'btn-group roo-upload-cropbox-rotate-left',
28967 action : 'rotate-left',
28971 cls : 'btn btn-default',
28972 html : '<i class="fa fa-undo"></i>'
28978 cls : 'btn-group roo-upload-cropbox-rotate-right',
28979 action : 'rotate-right',
28983 cls : 'btn btn-default',
28984 html : '<i class="fa fa-repeat"></i>'
28997 * @class Roo.bootstrap.DocumentManager
28998 * @extends Roo.bootstrap.Component
28999 * Bootstrap DocumentManager class
29000 * @cfg {String} paramName default 'imageUpload'
29001 * @cfg {String} toolTipName default 'filename'
29002 * @cfg {String} method default POST
29003 * @cfg {String} url action url
29004 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
29005 * @cfg {Boolean} multiple multiple upload default true
29006 * @cfg {Number} thumbSize default 300
29007 * @cfg {String} fieldLabel
29008 * @cfg {Number} labelWidth default 4
29009 * @cfg {String} labelAlign (left|top) default left
29010 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
29011 * @cfg {Number} labellg set the width of label (1-12)
29012 * @cfg {Number} labelmd set the width of label (1-12)
29013 * @cfg {Number} labelsm set the width of label (1-12)
29014 * @cfg {Number} labelxs set the width of label (1-12)
29017 * Create a new DocumentManager
29018 * @param {Object} config The config object
29021 Roo.bootstrap.DocumentManager = function(config){
29022 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
29025 this.delegates = [];
29030 * Fire when initial the DocumentManager
29031 * @param {Roo.bootstrap.DocumentManager} this
29036 * inspect selected file
29037 * @param {Roo.bootstrap.DocumentManager} this
29038 * @param {File} file
29043 * Fire when xhr load exception
29044 * @param {Roo.bootstrap.DocumentManager} this
29045 * @param {XMLHttpRequest} xhr
29047 "exception" : true,
29049 * @event afterupload
29050 * Fire when xhr load exception
29051 * @param {Roo.bootstrap.DocumentManager} this
29052 * @param {XMLHttpRequest} xhr
29054 "afterupload" : true,
29057 * prepare the form data
29058 * @param {Roo.bootstrap.DocumentManager} this
29059 * @param {Object} formData
29064 * Fire when remove the file
29065 * @param {Roo.bootstrap.DocumentManager} this
29066 * @param {Object} file
29071 * Fire after refresh the file
29072 * @param {Roo.bootstrap.DocumentManager} this
29077 * Fire after click the image
29078 * @param {Roo.bootstrap.DocumentManager} this
29079 * @param {Object} file
29084 * Fire when upload a image and editable set to true
29085 * @param {Roo.bootstrap.DocumentManager} this
29086 * @param {Object} file
29090 * @event beforeselectfile
29091 * Fire before select file
29092 * @param {Roo.bootstrap.DocumentManager} this
29094 "beforeselectfile" : true,
29097 * Fire before process file
29098 * @param {Roo.bootstrap.DocumentManager} this
29099 * @param {Object} file
29103 * @event previewrendered
29104 * Fire when preview rendered
29105 * @param {Roo.bootstrap.DocumentManager} this
29106 * @param {Object} file
29108 "previewrendered" : true,
29111 "previewResize" : true
29116 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
29125 paramName : 'imageUpload',
29126 toolTipName : 'filename',
29129 labelAlign : 'left',
29139 getAutoCreate : function()
29141 var managerWidget = {
29143 cls : 'roo-document-manager',
29147 cls : 'roo-document-manager-selector',
29152 cls : 'roo-document-manager-uploader',
29156 cls : 'roo-document-manager-upload-btn',
29157 html : '<i class="fa fa-plus"></i>'
29168 cls : 'column col-md-12',
29173 if(this.fieldLabel.length){
29178 cls : 'column col-md-12',
29179 html : this.fieldLabel
29183 cls : 'column col-md-12',
29188 if(this.labelAlign == 'left'){
29193 html : this.fieldLabel
29202 if(this.labelWidth > 12){
29203 content[0].style = "width: " + this.labelWidth + 'px';
29206 if(this.labelWidth < 13 && this.labelmd == 0){
29207 this.labelmd = this.labelWidth;
29210 if(this.labellg > 0){
29211 content[0].cls += ' col-lg-' + this.labellg;
29212 content[1].cls += ' col-lg-' + (12 - this.labellg);
29215 if(this.labelmd > 0){
29216 content[0].cls += ' col-md-' + this.labelmd;
29217 content[1].cls += ' col-md-' + (12 - this.labelmd);
29220 if(this.labelsm > 0){
29221 content[0].cls += ' col-sm-' + this.labelsm;
29222 content[1].cls += ' col-sm-' + (12 - this.labelsm);
29225 if(this.labelxs > 0){
29226 content[0].cls += ' col-xs-' + this.labelxs;
29227 content[1].cls += ' col-xs-' + (12 - this.labelxs);
29235 cls : 'row clearfix',
29243 initEvents : function()
29245 this.managerEl = this.el.select('.roo-document-manager', true).first();
29246 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29248 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
29249 this.selectorEl.hide();
29252 this.selectorEl.attr('multiple', 'multiple');
29255 this.selectorEl.on('change', this.onFileSelected, this);
29257 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
29258 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29260 this.uploader.on('click', this.onUploaderClick, this);
29262 this.renderProgressDialog();
29266 window.addEventListener("resize", function() { _this.refresh(); } );
29268 this.fireEvent('initial', this);
29271 renderProgressDialog : function()
29275 this.progressDialog = new Roo.bootstrap.Modal({
29276 cls : 'roo-document-manager-progress-dialog',
29277 allow_close : false,
29288 btnclick : function() {
29289 _this.uploadCancel();
29295 this.progressDialog.render(Roo.get(document.body));
29297 this.progress = new Roo.bootstrap.Progress({
29298 cls : 'roo-document-manager-progress',
29303 this.progress.render(this.progressDialog.getChildContainer());
29305 this.progressBar = new Roo.bootstrap.ProgressBar({
29306 cls : 'roo-document-manager-progress-bar',
29309 aria_valuemax : 12,
29313 this.progressBar.render(this.progress.getChildContainer());
29316 onUploaderClick : function(e)
29318 e.preventDefault();
29320 if(this.fireEvent('beforeselectfile', this) != false){
29321 this.selectorEl.dom.click();
29326 onFileSelected : function(e)
29328 e.preventDefault();
29330 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
29334 Roo.each(this.selectorEl.dom.files, function(file){
29335 if(this.fireEvent('inspect', this, file) != false){
29336 this.files.push(file);
29346 this.selectorEl.dom.value = '';
29348 if(!this.files || !this.files.length){
29352 if(this.boxes > 0 && this.files.length > this.boxes){
29353 this.files = this.files.slice(0, this.boxes);
29356 this.uploader.show();
29358 if(this.boxes > 0 && this.files.length > this.boxes - 1){
29359 this.uploader.hide();
29368 Roo.each(this.files, function(file){
29370 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29371 var f = this.renderPreview(file);
29376 if(file.type.indexOf('image') != -1){
29377 this.delegates.push(
29379 _this.process(file);
29380 }).createDelegate(this)
29388 _this.process(file);
29389 }).createDelegate(this)
29394 this.files = files;
29396 this.delegates = this.delegates.concat(docs);
29398 if(!this.delegates.length){
29403 this.progressBar.aria_valuemax = this.delegates.length;
29410 arrange : function()
29412 if(!this.delegates.length){
29413 this.progressDialog.hide();
29418 var delegate = this.delegates.shift();
29420 this.progressDialog.show();
29422 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
29424 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
29429 refresh : function()
29431 this.uploader.show();
29433 if(this.boxes > 0 && this.files.length > this.boxes - 1){
29434 this.uploader.hide();
29437 Roo.isTouch ? this.closable(false) : this.closable(true);
29439 this.fireEvent('refresh', this);
29442 onRemove : function(e, el, o)
29444 e.preventDefault();
29446 this.fireEvent('remove', this, o);
29450 remove : function(o)
29454 Roo.each(this.files, function(file){
29455 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
29464 this.files = files;
29471 Roo.each(this.files, function(file){
29476 file.target.remove();
29485 onClick : function(e, el, o)
29487 e.preventDefault();
29489 this.fireEvent('click', this, o);
29493 closable : function(closable)
29495 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
29497 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29509 xhrOnLoad : function(xhr)
29511 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29515 if (xhr.readyState !== 4) {
29517 this.fireEvent('exception', this, xhr);
29521 var response = Roo.decode(xhr.responseText);
29523 if(!response.success){
29525 this.fireEvent('exception', this, xhr);
29529 var file = this.renderPreview(response.data);
29531 this.files.push(file);
29535 this.fireEvent('afterupload', this, xhr);
29539 xhrOnError : function(xhr)
29541 Roo.log('xhr on error');
29543 var response = Roo.decode(xhr.responseText);
29550 process : function(file)
29552 if(this.fireEvent('process', this, file) !== false){
29553 if(this.editable && file.type.indexOf('image') != -1){
29554 this.fireEvent('edit', this, file);
29558 this.uploadStart(file, false);
29565 uploadStart : function(file, crop)
29567 this.xhr = new XMLHttpRequest();
29569 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29574 file.xhr = this.xhr;
29576 this.managerEl.createChild({
29578 cls : 'roo-document-manager-loading',
29582 tooltip : file.name,
29583 cls : 'roo-document-manager-thumb',
29584 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29590 this.xhr.open(this.method, this.url, true);
29593 "Accept": "application/json",
29594 "Cache-Control": "no-cache",
29595 "X-Requested-With": "XMLHttpRequest"
29598 for (var headerName in headers) {
29599 var headerValue = headers[headerName];
29601 this.xhr.setRequestHeader(headerName, headerValue);
29607 this.xhr.onload = function()
29609 _this.xhrOnLoad(_this.xhr);
29612 this.xhr.onerror = function()
29614 _this.xhrOnError(_this.xhr);
29617 var formData = new FormData();
29619 formData.append('returnHTML', 'NO');
29622 formData.append('crop', crop);
29625 formData.append(this.paramName, file, file.name);
29632 if(this.fireEvent('prepare', this, formData, options) != false){
29634 if(options.manually){
29638 this.xhr.send(formData);
29642 this.uploadCancel();
29645 uploadCancel : function()
29651 this.delegates = [];
29653 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29660 renderPreview : function(file)
29662 if(typeof(file.target) != 'undefined' && file.target){
29666 var img_src = encodeURI(baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename);
29668 var previewEl = this.managerEl.createChild({
29670 cls : 'roo-document-manager-preview',
29674 tooltip : file[this.toolTipName],
29675 cls : 'roo-document-manager-thumb',
29676 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + img_src + '">'
29681 html : '<i class="fa fa-times-circle"></i>'
29686 var close = previewEl.select('button.close', true).first();
29688 close.on('click', this.onRemove, this, file);
29690 file.target = previewEl;
29692 var image = previewEl.select('img', true).first();
29696 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
29698 image.on('click', this.onClick, this, file);
29700 this.fireEvent('previewrendered', this, file);
29706 onPreviewLoad : function(file, image)
29708 if(typeof(file.target) == 'undefined' || !file.target){
29712 var width = image.dom.naturalWidth || image.dom.width;
29713 var height = image.dom.naturalHeight || image.dom.height;
29715 if(!this.previewResize) {
29719 if(width > height){
29720 file.target.addClass('wide');
29724 file.target.addClass('tall');
29729 uploadFromSource : function(file, crop)
29731 this.xhr = new XMLHttpRequest();
29733 this.managerEl.createChild({
29735 cls : 'roo-document-manager-loading',
29739 tooltip : file.name,
29740 cls : 'roo-document-manager-thumb',
29741 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29747 this.xhr.open(this.method, this.url, true);
29750 "Accept": "application/json",
29751 "Cache-Control": "no-cache",
29752 "X-Requested-With": "XMLHttpRequest"
29755 for (var headerName in headers) {
29756 var headerValue = headers[headerName];
29758 this.xhr.setRequestHeader(headerName, headerValue);
29764 this.xhr.onload = function()
29766 _this.xhrOnLoad(_this.xhr);
29769 this.xhr.onerror = function()
29771 _this.xhrOnError(_this.xhr);
29774 var formData = new FormData();
29776 formData.append('returnHTML', 'NO');
29778 formData.append('crop', crop);
29780 if(typeof(file.filename) != 'undefined'){
29781 formData.append('filename', file.filename);
29784 if(typeof(file.mimetype) != 'undefined'){
29785 formData.append('mimetype', file.mimetype);
29790 if(this.fireEvent('prepare', this, formData) != false){
29791 this.xhr.send(formData);
29801 * @class Roo.bootstrap.DocumentViewer
29802 * @extends Roo.bootstrap.Component
29803 * Bootstrap DocumentViewer class
29804 * @cfg {Boolean} showDownload (true|false) show download button (default true)
29805 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
29808 * Create a new DocumentViewer
29809 * @param {Object} config The config object
29812 Roo.bootstrap.DocumentViewer = function(config){
29813 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
29818 * Fire after initEvent
29819 * @param {Roo.bootstrap.DocumentViewer} this
29825 * @param {Roo.bootstrap.DocumentViewer} this
29830 * Fire after download button
29831 * @param {Roo.bootstrap.DocumentViewer} this
29836 * Fire after trash button
29837 * @param {Roo.bootstrap.DocumentViewer} this
29844 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
29846 showDownload : true,
29850 getAutoCreate : function()
29854 cls : 'roo-document-viewer',
29858 cls : 'roo-document-viewer-body',
29862 cls : 'roo-document-viewer-thumb',
29866 cls : 'roo-document-viewer-image'
29874 cls : 'roo-document-viewer-footer',
29877 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
29881 cls : 'btn-group roo-document-viewer-download',
29885 cls : 'btn btn-default',
29886 html : '<i class="fa fa-download"></i>'
29892 cls : 'btn-group roo-document-viewer-trash',
29896 cls : 'btn btn-default',
29897 html : '<i class="fa fa-trash"></i>'
29910 initEvents : function()
29912 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
29913 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
29915 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
29916 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
29918 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
29919 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
29921 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
29922 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
29924 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
29925 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
29927 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
29928 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
29930 this.bodyEl.on('click', this.onClick, this);
29931 this.downloadBtn.on('click', this.onDownload, this);
29932 this.trashBtn.on('click', this.onTrash, this);
29934 this.downloadBtn.hide();
29935 this.trashBtn.hide();
29937 if(this.showDownload){
29938 this.downloadBtn.show();
29941 if(this.showTrash){
29942 this.trashBtn.show();
29945 if(!this.showDownload && !this.showTrash) {
29946 this.footerEl.hide();
29951 initial : function()
29953 this.fireEvent('initial', this);
29957 onClick : function(e)
29959 e.preventDefault();
29961 this.fireEvent('click', this);
29964 onDownload : function(e)
29966 e.preventDefault();
29968 this.fireEvent('download', this);
29971 onTrash : function(e)
29973 e.preventDefault();
29975 this.fireEvent('trash', this);
29987 * @class Roo.bootstrap.NavProgressBar
29988 * @extends Roo.bootstrap.Component
29989 * Bootstrap NavProgressBar class
29992 * Create a new nav progress bar
29993 * @param {Object} config The config object
29996 Roo.bootstrap.NavProgressBar = function(config){
29997 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
29999 this.bullets = this.bullets || [];
30001 // Roo.bootstrap.NavProgressBar.register(this);
30005 * Fires when the active item changes
30006 * @param {Roo.bootstrap.NavProgressBar} this
30007 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
30008 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
30015 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
30020 getAutoCreate : function()
30022 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
30026 cls : 'roo-navigation-bar-group',
30030 cls : 'roo-navigation-top-bar'
30034 cls : 'roo-navigation-bullets-bar',
30038 cls : 'roo-navigation-bar'
30045 cls : 'roo-navigation-bottom-bar'
30055 initEvents: function()
30060 onRender : function(ct, position)
30062 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30064 if(this.bullets.length){
30065 Roo.each(this.bullets, function(b){
30074 addItem : function(cfg)
30076 var item = new Roo.bootstrap.NavProgressItem(cfg);
30078 item.parentId = this.id;
30079 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
30082 var top = new Roo.bootstrap.Element({
30084 cls : 'roo-navigation-bar-text'
30087 var bottom = new Roo.bootstrap.Element({
30089 cls : 'roo-navigation-bar-text'
30092 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
30093 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
30095 var topText = new Roo.bootstrap.Element({
30097 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
30100 var bottomText = new Roo.bootstrap.Element({
30102 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
30105 topText.onRender(top.el, null);
30106 bottomText.onRender(bottom.el, null);
30109 item.bottomEl = bottom;
30112 this.barItems.push(item);
30117 getActive : function()
30119 var active = false;
30121 Roo.each(this.barItems, function(v){
30123 if (!v.isActive()) {
30135 setActiveItem : function(item)
30139 Roo.each(this.barItems, function(v){
30140 if (v.rid == item.rid) {
30144 if (v.isActive()) {
30145 v.setActive(false);
30150 item.setActive(true);
30152 this.fireEvent('changed', this, item, prev);
30155 getBarItem: function(rid)
30159 Roo.each(this.barItems, function(e) {
30160 if (e.rid != rid) {
30171 indexOfItem : function(item)
30175 Roo.each(this.barItems, function(v, i){
30177 if (v.rid != item.rid) {
30188 setActiveNext : function()
30190 var i = this.indexOfItem(this.getActive());
30192 if (i > this.barItems.length) {
30196 this.setActiveItem(this.barItems[i+1]);
30199 setActivePrev : function()
30201 var i = this.indexOfItem(this.getActive());
30207 this.setActiveItem(this.barItems[i-1]);
30210 format : function()
30212 if(!this.barItems.length){
30216 var width = 100 / this.barItems.length;
30218 Roo.each(this.barItems, function(i){
30219 i.el.setStyle('width', width + '%');
30220 i.topEl.el.setStyle('width', width + '%');
30221 i.bottomEl.el.setStyle('width', width + '%');
30230 * Nav Progress Item
30235 * @class Roo.bootstrap.NavProgressItem
30236 * @extends Roo.bootstrap.Component
30237 * Bootstrap NavProgressItem class
30238 * @cfg {String} rid the reference id
30239 * @cfg {Boolean} active (true|false) Is item active default false
30240 * @cfg {Boolean} disabled (true|false) Is item active default false
30241 * @cfg {String} html
30242 * @cfg {String} position (top|bottom) text position default bottom
30243 * @cfg {String} icon show icon instead of number
30246 * Create a new NavProgressItem
30247 * @param {Object} config The config object
30249 Roo.bootstrap.NavProgressItem = function(config){
30250 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
30255 * The raw click event for the entire grid.
30256 * @param {Roo.bootstrap.NavProgressItem} this
30257 * @param {Roo.EventObject} e
30264 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
30270 position : 'bottom',
30273 getAutoCreate : function()
30275 var iconCls = 'roo-navigation-bar-item-icon';
30277 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
30281 cls: 'roo-navigation-bar-item',
30291 cfg.cls += ' active';
30294 cfg.cls += ' disabled';
30300 disable : function()
30302 this.setDisabled(true);
30305 enable : function()
30307 this.setDisabled(false);
30310 initEvents: function()
30312 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
30314 this.iconEl.on('click', this.onClick, this);
30317 onClick : function(e)
30319 e.preventDefault();
30325 if(this.fireEvent('click', this, e) === false){
30329 this.parent().setActiveItem(this);
30332 isActive: function ()
30334 return this.active;
30337 setActive : function(state)
30339 if(this.active == state){
30343 this.active = state;
30346 this.el.addClass('active');
30350 this.el.removeClass('active');
30355 setDisabled : function(state)
30357 if(this.disabled == state){
30361 this.disabled = state;
30364 this.el.addClass('disabled');
30368 this.el.removeClass('disabled');
30371 tooltipEl : function()
30373 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
30386 * @class Roo.bootstrap.FieldLabel
30387 * @extends Roo.bootstrap.Component
30388 * Bootstrap FieldLabel class
30389 * @cfg {String} html contents of the element
30390 * @cfg {String} tag tag of the element default label
30391 * @cfg {String} cls class of the element
30392 * @cfg {String} target label target
30393 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
30394 * @cfg {String} invalidClass DEPRICATED - BS4 uses is-invalid
30395 * @cfg {String} validClass DEPRICATED - BS4 uses is-valid
30396 * @cfg {String} iconTooltip default "This field is required"
30397 * @cfg {String} indicatorpos (left|right) default left
30400 * Create a new FieldLabel
30401 * @param {Object} config The config object
30404 Roo.bootstrap.FieldLabel = function(config){
30405 Roo.bootstrap.Element.superclass.constructor.call(this, config);
30410 * Fires after the field has been marked as invalid.
30411 * @param {Roo.form.FieldLabel} this
30412 * @param {String} msg The validation message
30417 * Fires after the field has been validated with no errors.
30418 * @param {Roo.form.FieldLabel} this
30424 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
30431 invalidClass : 'has-warning',
30432 validClass : 'has-success',
30433 iconTooltip : 'This field is required',
30434 indicatorpos : 'left',
30436 getAutoCreate : function(){
30439 if (!this.allowBlank) {
30445 cls : 'roo-bootstrap-field-label ' + this.cls,
30450 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star ' + cls,
30451 tooltip : this.iconTooltip
30460 if(this.indicatorpos == 'right'){
30463 cls : 'roo-bootstrap-field-label ' + this.cls,
30472 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star '+ cls,
30473 tooltip : this.iconTooltip
30482 initEvents: function()
30484 Roo.bootstrap.Element.superclass.initEvents.call(this);
30486 this.indicator = this.indicatorEl();
30488 if(this.indicator){
30489 this.indicator.removeClass('visible');
30490 this.indicator.addClass('invisible');
30493 Roo.bootstrap.FieldLabel.register(this);
30496 indicatorEl : function()
30498 var indicator = this.el.select('i.roo-required-indicator',true).first();
30509 * Mark this field as valid
30511 markValid : function()
30513 if(this.indicator){
30514 this.indicator.removeClass('visible');
30515 this.indicator.addClass('invisible');
30517 if (Roo.bootstrap.version == 3) {
30518 this.el.removeClass(this.invalidClass);
30519 this.el.addClass(this.validClass);
30521 this.el.removeClass('is-invalid');
30522 this.el.addClass('is-valid');
30526 this.fireEvent('valid', this);
30530 * Mark this field as invalid
30531 * @param {String} msg The validation message
30533 markInvalid : function(msg)
30535 if(this.indicator){
30536 this.indicator.removeClass('invisible');
30537 this.indicator.addClass('visible');
30539 if (Roo.bootstrap.version == 3) {
30540 this.el.removeClass(this.validClass);
30541 this.el.addClass(this.invalidClass);
30543 this.el.removeClass('is-valid');
30544 this.el.addClass('is-invalid');
30548 this.fireEvent('invalid', this, msg);
30554 Roo.apply(Roo.bootstrap.FieldLabel, {
30559 * register a FieldLabel Group
30560 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
30562 register : function(label)
30564 if(this.groups.hasOwnProperty(label.target)){
30568 this.groups[label.target] = label;
30572 * fetch a FieldLabel Group based on the target
30573 * @param {string} target
30574 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
30576 get: function(target) {
30577 if (typeof(this.groups[target]) == 'undefined') {
30581 return this.groups[target] ;
30590 * page DateSplitField.
30596 * @class Roo.bootstrap.DateSplitField
30597 * @extends Roo.bootstrap.Component
30598 * Bootstrap DateSplitField class
30599 * @cfg {string} fieldLabel - the label associated
30600 * @cfg {Number} labelWidth set the width of label (0-12)
30601 * @cfg {String} labelAlign (top|left)
30602 * @cfg {Boolean} dayAllowBlank (true|false) default false
30603 * @cfg {Boolean} monthAllowBlank (true|false) default false
30604 * @cfg {Boolean} yearAllowBlank (true|false) default false
30605 * @cfg {string} dayPlaceholder
30606 * @cfg {string} monthPlaceholder
30607 * @cfg {string} yearPlaceholder
30608 * @cfg {string} dayFormat default 'd'
30609 * @cfg {string} monthFormat default 'm'
30610 * @cfg {string} yearFormat default 'Y'
30611 * @cfg {Number} labellg set the width of label (1-12)
30612 * @cfg {Number} labelmd set the width of label (1-12)
30613 * @cfg {Number} labelsm set the width of label (1-12)
30614 * @cfg {Number} labelxs set the width of label (1-12)
30618 * Create a new DateSplitField
30619 * @param {Object} config The config object
30622 Roo.bootstrap.DateSplitField = function(config){
30623 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
30629 * getting the data of years
30630 * @param {Roo.bootstrap.DateSplitField} this
30631 * @param {Object} years
30636 * getting the data of days
30637 * @param {Roo.bootstrap.DateSplitField} this
30638 * @param {Object} days
30643 * Fires after the field has been marked as invalid.
30644 * @param {Roo.form.Field} this
30645 * @param {String} msg The validation message
30650 * Fires after the field has been validated with no errors.
30651 * @param {Roo.form.Field} this
30657 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
30660 labelAlign : 'top',
30662 dayAllowBlank : false,
30663 monthAllowBlank : false,
30664 yearAllowBlank : false,
30665 dayPlaceholder : '',
30666 monthPlaceholder : '',
30667 yearPlaceholder : '',
30671 isFormField : true,
30677 getAutoCreate : function()
30681 cls : 'row roo-date-split-field-group',
30686 cls : 'form-hidden-field roo-date-split-field-group-value',
30692 var labelCls = 'col-md-12';
30693 var contentCls = 'col-md-4';
30695 if(this.fieldLabel){
30699 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
30703 html : this.fieldLabel
30708 if(this.labelAlign == 'left'){
30710 if(this.labelWidth > 12){
30711 label.style = "width: " + this.labelWidth + 'px';
30714 if(this.labelWidth < 13 && this.labelmd == 0){
30715 this.labelmd = this.labelWidth;
30718 if(this.labellg > 0){
30719 labelCls = ' col-lg-' + this.labellg;
30720 contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
30723 if(this.labelmd > 0){
30724 labelCls = ' col-md-' + this.labelmd;
30725 contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
30728 if(this.labelsm > 0){
30729 labelCls = ' col-sm-' + this.labelsm;
30730 contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
30733 if(this.labelxs > 0){
30734 labelCls = ' col-xs-' + this.labelxs;
30735 contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
30739 label.cls += ' ' + labelCls;
30741 cfg.cn.push(label);
30744 Roo.each(['day', 'month', 'year'], function(t){
30747 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
30754 inputEl: function ()
30756 return this.el.select('.roo-date-split-field-group-value', true).first();
30759 onRender : function(ct, position)
30763 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30765 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
30767 this.dayField = new Roo.bootstrap.ComboBox({
30768 allowBlank : this.dayAllowBlank,
30769 alwaysQuery : true,
30770 displayField : 'value',
30773 forceSelection : true,
30775 placeholder : this.dayPlaceholder,
30776 selectOnFocus : true,
30777 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30778 triggerAction : 'all',
30780 valueField : 'value',
30781 store : new Roo.data.SimpleStore({
30782 data : (function() {
30784 _this.fireEvent('days', _this, days);
30787 fields : [ 'value' ]
30790 select : function (_self, record, index)
30792 _this.setValue(_this.getValue());
30797 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
30799 this.monthField = new Roo.bootstrap.MonthField({
30800 after : '<i class=\"fa fa-calendar\"></i>',
30801 allowBlank : this.monthAllowBlank,
30802 placeholder : this.monthPlaceholder,
30805 render : function (_self)
30807 this.el.select('span.input-group-addon', true).first().on('click', function(e){
30808 e.preventDefault();
30812 select : function (_self, oldvalue, newvalue)
30814 _this.setValue(_this.getValue());
30819 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
30821 this.yearField = new Roo.bootstrap.ComboBox({
30822 allowBlank : this.yearAllowBlank,
30823 alwaysQuery : true,
30824 displayField : 'value',
30827 forceSelection : true,
30829 placeholder : this.yearPlaceholder,
30830 selectOnFocus : true,
30831 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30832 triggerAction : 'all',
30834 valueField : 'value',
30835 store : new Roo.data.SimpleStore({
30836 data : (function() {
30838 _this.fireEvent('years', _this, years);
30841 fields : [ 'value' ]
30844 select : function (_self, record, index)
30846 _this.setValue(_this.getValue());
30851 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
30854 setValue : function(v, format)
30856 this.inputEl.dom.value = v;
30858 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
30860 var d = Date.parseDate(v, f);
30867 this.setDay(d.format(this.dayFormat));
30868 this.setMonth(d.format(this.monthFormat));
30869 this.setYear(d.format(this.yearFormat));
30876 setDay : function(v)
30878 this.dayField.setValue(v);
30879 this.inputEl.dom.value = this.getValue();
30884 setMonth : function(v)
30886 this.monthField.setValue(v, true);
30887 this.inputEl.dom.value = this.getValue();
30892 setYear : function(v)
30894 this.yearField.setValue(v);
30895 this.inputEl.dom.value = this.getValue();
30900 getDay : function()
30902 return this.dayField.getValue();
30905 getMonth : function()
30907 return this.monthField.getValue();
30910 getYear : function()
30912 return this.yearField.getValue();
30915 getValue : function()
30917 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
30919 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
30929 this.inputEl.dom.value = '';
30934 validate : function()
30936 var d = this.dayField.validate();
30937 var m = this.monthField.validate();
30938 var y = this.yearField.validate();
30943 (!this.dayAllowBlank && !d) ||
30944 (!this.monthAllowBlank && !m) ||
30945 (!this.yearAllowBlank && !y)
30950 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
30959 this.markInvalid();
30964 markValid : function()
30967 var label = this.el.select('label', true).first();
30968 var icon = this.el.select('i.fa-star', true).first();
30974 this.fireEvent('valid', this);
30978 * Mark this field as invalid
30979 * @param {String} msg The validation message
30981 markInvalid : function(msg)
30984 var label = this.el.select('label', true).first();
30985 var icon = this.el.select('i.fa-star', true).first();
30987 if(label && !icon){
30988 this.el.select('.roo-date-split-field-label', true).createChild({
30990 cls : 'text-danger fa fa-lg fa-star',
30991 tooltip : 'This field is required',
30992 style : 'margin-right:5px;'
30996 this.fireEvent('invalid', this, msg);
30999 clearInvalid : function()
31001 var label = this.el.select('label', true).first();
31002 var icon = this.el.select('i.fa-star', true).first();
31008 this.fireEvent('valid', this);
31011 getName: function()
31021 * http://masonry.desandro.com
31023 * The idea is to render all the bricks based on vertical width...
31025 * The original code extends 'outlayer' - we might need to use that....
31031 * @class Roo.bootstrap.LayoutMasonry
31032 * @extends Roo.bootstrap.Component
31033 * Bootstrap Layout Masonry class
31036 * Create a new Element
31037 * @param {Object} config The config object
31040 Roo.bootstrap.LayoutMasonry = function(config){
31042 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
31046 Roo.bootstrap.LayoutMasonry.register(this);
31052 * Fire after layout the items
31053 * @param {Roo.bootstrap.LayoutMasonry} this
31054 * @param {Roo.EventObject} e
31061 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
31064 * @cfg {Boolean} isLayoutInstant = no animation?
31066 isLayoutInstant : false, // needed?
31069 * @cfg {Number} boxWidth width of the columns
31074 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
31079 * @cfg {Number} padWidth padding below box..
31084 * @cfg {Number} gutter gutter width..
31089 * @cfg {Number} maxCols maximum number of columns
31095 * @cfg {Boolean} isAutoInitial defalut true
31097 isAutoInitial : true,
31102 * @cfg {Boolean} isHorizontal defalut false
31104 isHorizontal : false,
31106 currentSize : null,
31112 bricks: null, //CompositeElement
31116 _isLayoutInited : false,
31118 // isAlternative : false, // only use for vertical layout...
31121 * @cfg {Number} alternativePadWidth padding below box..
31123 alternativePadWidth : 50,
31125 selectedBrick : [],
31127 getAutoCreate : function(){
31129 var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
31133 cls: 'blog-masonary-wrapper ' + this.cls,
31135 cls : 'mas-boxes masonary'
31142 getChildContainer: function( )
31144 if (this.boxesEl) {
31145 return this.boxesEl;
31148 this.boxesEl = this.el.select('.mas-boxes').first();
31150 return this.boxesEl;
31154 initEvents : function()
31158 if(this.isAutoInitial){
31159 Roo.log('hook children rendered');
31160 this.on('childrenrendered', function() {
31161 Roo.log('children rendered');
31167 initial : function()
31169 this.selectedBrick = [];
31171 this.currentSize = this.el.getBox(true);
31173 Roo.EventManager.onWindowResize(this.resize, this);
31175 if(!this.isAutoInitial){
31183 //this.layout.defer(500,this);
31187 resize : function()
31189 var cs = this.el.getBox(true);
31192 this.currentSize.width == cs.width &&
31193 this.currentSize.x == cs.x &&
31194 this.currentSize.height == cs.height &&
31195 this.currentSize.y == cs.y
31197 Roo.log("no change in with or X or Y");
31201 this.currentSize = cs;
31207 layout : function()
31209 this._resetLayout();
31211 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
31213 this.layoutItems( isInstant );
31215 this._isLayoutInited = true;
31217 this.fireEvent('layout', this);
31221 _resetLayout : function()
31223 if(this.isHorizontal){
31224 this.horizontalMeasureColumns();
31228 this.verticalMeasureColumns();
31232 verticalMeasureColumns : function()
31234 this.getContainerWidth();
31236 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
31237 // this.colWidth = Math.floor(this.containerWidth * 0.8);
31241 var boxWidth = this.boxWidth + this.padWidth;
31243 if(this.containerWidth < this.boxWidth){
31244 boxWidth = this.containerWidth
31247 var containerWidth = this.containerWidth;
31249 var cols = Math.floor(containerWidth / boxWidth);
31251 this.cols = Math.max( cols, 1 );
31253 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
31255 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
31257 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
31259 this.colWidth = boxWidth + avail - this.padWidth;
31261 this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
31262 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
31265 horizontalMeasureColumns : function()
31267 this.getContainerWidth();
31269 var boxWidth = this.boxWidth;
31271 if(this.containerWidth < boxWidth){
31272 boxWidth = this.containerWidth;
31275 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
31277 this.el.setHeight(boxWidth);
31281 getContainerWidth : function()
31283 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
31286 layoutItems : function( isInstant )
31288 Roo.log(this.bricks);
31290 var items = Roo.apply([], this.bricks);
31292 if(this.isHorizontal){
31293 this._horizontalLayoutItems( items , isInstant );
31297 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
31298 // this._verticalAlternativeLayoutItems( items , isInstant );
31302 this._verticalLayoutItems( items , isInstant );
31306 _verticalLayoutItems : function ( items , isInstant)
31308 if ( !items || !items.length ) {
31313 ['xs', 'xs', 'xs', 'tall'],
31314 ['xs', 'xs', 'tall'],
31315 ['xs', 'xs', 'sm'],
31316 ['xs', 'xs', 'xs'],
31322 ['sm', 'xs', 'xs'],
31326 ['tall', 'xs', 'xs', 'xs'],
31327 ['tall', 'xs', 'xs'],
31339 Roo.each(items, function(item, k){
31341 switch (item.size) {
31342 // these layouts take up a full box,
31353 boxes.push([item]);
31376 var filterPattern = function(box, length)
31384 var pattern = box.slice(0, length);
31388 Roo.each(pattern, function(i){
31389 format.push(i.size);
31392 Roo.each(standard, function(s){
31394 if(String(s) != String(format)){
31403 if(!match && length == 1){
31408 filterPattern(box, length - 1);
31412 queue.push(pattern);
31414 box = box.slice(length, box.length);
31416 filterPattern(box, 4);
31422 Roo.each(boxes, function(box, k){
31428 if(box.length == 1){
31433 filterPattern(box, 4);
31437 this._processVerticalLayoutQueue( queue, isInstant );
31441 // _verticalAlternativeLayoutItems : function( items , isInstant )
31443 // if ( !items || !items.length ) {
31447 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
31451 _horizontalLayoutItems : function ( items , isInstant)
31453 if ( !items || !items.length || items.length < 3) {
31459 var eItems = items.slice(0, 3);
31461 items = items.slice(3, items.length);
31464 ['xs', 'xs', 'xs', 'wide'],
31465 ['xs', 'xs', 'wide'],
31466 ['xs', 'xs', 'sm'],
31467 ['xs', 'xs', 'xs'],
31473 ['sm', 'xs', 'xs'],
31477 ['wide', 'xs', 'xs', 'xs'],
31478 ['wide', 'xs', 'xs'],
31491 Roo.each(items, function(item, k){
31493 switch (item.size) {
31504 boxes.push([item]);
31528 var filterPattern = function(box, length)
31536 var pattern = box.slice(0, length);
31540 Roo.each(pattern, function(i){
31541 format.push(i.size);
31544 Roo.each(standard, function(s){
31546 if(String(s) != String(format)){
31555 if(!match && length == 1){
31560 filterPattern(box, length - 1);
31564 queue.push(pattern);
31566 box = box.slice(length, box.length);
31568 filterPattern(box, 4);
31574 Roo.each(boxes, function(box, k){
31580 if(box.length == 1){
31585 filterPattern(box, 4);
31592 var pos = this.el.getBox(true);
31596 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31598 var hit_end = false;
31600 Roo.each(queue, function(box){
31604 Roo.each(box, function(b){
31606 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31616 Roo.each(box, function(b){
31618 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31621 mx = Math.max(mx, b.x);
31625 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
31629 Roo.each(box, function(b){
31631 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31645 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
31648 /** Sets position of item in DOM
31649 * @param {Element} item
31650 * @param {Number} x - horizontal position
31651 * @param {Number} y - vertical position
31652 * @param {Boolean} isInstant - disables transitions
31654 _processVerticalLayoutQueue : function( queue, isInstant )
31656 var pos = this.el.getBox(true);
31661 for (var i = 0; i < this.cols; i++){
31665 Roo.each(queue, function(box, k){
31667 var col = k % this.cols;
31669 Roo.each(box, function(b,kk){
31671 b.el.position('absolute');
31673 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31674 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31676 if(b.size == 'md-left' || b.size == 'md-right'){
31677 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31678 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31681 b.el.setWidth(width);
31682 b.el.setHeight(height);
31684 b.el.select('iframe',true).setSize(width,height);
31688 for (var i = 0; i < this.cols; i++){
31690 if(maxY[i] < maxY[col]){
31695 col = Math.min(col, i);
31699 x = pos.x + col * (this.colWidth + this.padWidth);
31703 var positions = [];
31705 switch (box.length){
31707 positions = this.getVerticalOneBoxColPositions(x, y, box);
31710 positions = this.getVerticalTwoBoxColPositions(x, y, box);
31713 positions = this.getVerticalThreeBoxColPositions(x, y, box);
31716 positions = this.getVerticalFourBoxColPositions(x, y, box);
31722 Roo.each(box, function(b,kk){
31724 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31726 var sz = b.el.getSize();
31728 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
31736 for (var i = 0; i < this.cols; i++){
31737 mY = Math.max(mY, maxY[i]);
31740 this.el.setHeight(mY - pos.y);
31744 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
31746 // var pos = this.el.getBox(true);
31749 // var maxX = pos.right;
31751 // var maxHeight = 0;
31753 // Roo.each(items, function(item, k){
31757 // item.el.position('absolute');
31759 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
31761 // item.el.setWidth(width);
31763 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
31765 // item.el.setHeight(height);
31768 // item.el.setXY([x, y], isInstant ? false : true);
31770 // item.el.setXY([maxX - width, y], isInstant ? false : true);
31773 // y = y + height + this.alternativePadWidth;
31775 // maxHeight = maxHeight + height + this.alternativePadWidth;
31779 // this.el.setHeight(maxHeight);
31783 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
31785 var pos = this.el.getBox(true);
31790 var maxX = pos.right;
31792 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
31794 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31796 Roo.each(queue, function(box, k){
31798 Roo.each(box, function(b, kk){
31800 b.el.position('absolute');
31802 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31803 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31805 if(b.size == 'md-left' || b.size == 'md-right'){
31806 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31807 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31810 b.el.setWidth(width);
31811 b.el.setHeight(height);
31819 var positions = [];
31821 switch (box.length){
31823 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
31826 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
31829 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
31832 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
31838 Roo.each(box, function(b,kk){
31840 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31842 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
31850 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
31852 Roo.each(eItems, function(b,k){
31854 b.size = (k == 0) ? 'sm' : 'xs';
31855 b.x = (k == 0) ? 2 : 1;
31856 b.y = (k == 0) ? 2 : 1;
31858 b.el.position('absolute');
31860 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31862 b.el.setWidth(width);
31864 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31866 b.el.setHeight(height);
31870 var positions = [];
31873 x : maxX - this.unitWidth * 2 - this.gutter,
31878 x : maxX - this.unitWidth,
31879 y : minY + (this.unitWidth + this.gutter) * 2
31883 x : maxX - this.unitWidth * 3 - this.gutter * 2,
31887 Roo.each(eItems, function(b,k){
31889 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
31895 getVerticalOneBoxColPositions : function(x, y, box)
31899 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
31901 if(box[0].size == 'md-left'){
31905 if(box[0].size == 'md-right'){
31910 x : x + (this.unitWidth + this.gutter) * rand,
31917 getVerticalTwoBoxColPositions : function(x, y, box)
31921 if(box[0].size == 'xs'){
31925 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
31929 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
31943 x : x + (this.unitWidth + this.gutter) * 2,
31944 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
31951 getVerticalThreeBoxColPositions : function(x, y, box)
31955 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31963 x : x + (this.unitWidth + this.gutter) * 1,
31968 x : x + (this.unitWidth + this.gutter) * 2,
31976 if(box[0].size == 'xs' && box[1].size == 'xs'){
31985 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
31989 x : x + (this.unitWidth + this.gutter) * 1,
32003 x : x + (this.unitWidth + this.gutter) * 2,
32008 x : x + (this.unitWidth + this.gutter) * 2,
32009 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
32016 getVerticalFourBoxColPositions : function(x, y, box)
32020 if(box[0].size == 'xs'){
32029 y : y + (this.unitHeight + this.gutter) * 1
32034 y : y + (this.unitHeight + this.gutter) * 2
32038 x : x + (this.unitWidth + this.gutter) * 1,
32052 x : x + (this.unitWidth + this.gutter) * 2,
32057 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
32058 y : y + (this.unitHeight + this.gutter) * 1
32062 x : x + (this.unitWidth + this.gutter) * 2,
32063 y : y + (this.unitWidth + this.gutter) * 2
32070 getHorizontalOneBoxColPositions : function(maxX, minY, box)
32074 if(box[0].size == 'md-left'){
32076 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
32083 if(box[0].size == 'md-right'){
32085 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
32086 y : minY + (this.unitWidth + this.gutter) * 1
32092 var rand = Math.floor(Math.random() * (4 - box[0].y));
32095 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32096 y : minY + (this.unitWidth + this.gutter) * rand
32103 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
32107 if(box[0].size == 'xs'){
32110 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32115 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32116 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
32124 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32129 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32130 y : minY + (this.unitWidth + this.gutter) * 2
32137 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
32141 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
32144 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32149 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32150 y : minY + (this.unitWidth + this.gutter) * 1
32154 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32155 y : minY + (this.unitWidth + this.gutter) * 2
32162 if(box[0].size == 'xs' && box[1].size == 'xs'){
32165 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32170 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32175 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32176 y : minY + (this.unitWidth + this.gutter) * 1
32184 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32189 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32190 y : minY + (this.unitWidth + this.gutter) * 2
32194 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32195 y : minY + (this.unitWidth + this.gutter) * 2
32202 getHorizontalFourBoxColPositions : function(maxX, minY, box)
32206 if(box[0].size == 'xs'){
32209 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32214 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32219 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),
32224 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
32225 y : minY + (this.unitWidth + this.gutter) * 1
32233 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32238 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32239 y : minY + (this.unitWidth + this.gutter) * 2
32243 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32244 y : minY + (this.unitWidth + this.gutter) * 2
32248 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),
32249 y : minY + (this.unitWidth + this.gutter) * 2
32257 * remove a Masonry Brick
32258 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
32260 removeBrick : function(brick_id)
32266 for (var i = 0; i<this.bricks.length; i++) {
32267 if (this.bricks[i].id == brick_id) {
32268 this.bricks.splice(i,1);
32269 this.el.dom.removeChild(Roo.get(brick_id).dom);
32276 * adds a Masonry Brick
32277 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32279 addBrick : function(cfg)
32281 var cn = new Roo.bootstrap.MasonryBrick(cfg);
32282 //this.register(cn);
32283 cn.parentId = this.id;
32284 cn.render(this.el);
32289 * register a Masonry Brick
32290 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32293 register : function(brick)
32295 this.bricks.push(brick);
32296 brick.masonryId = this.id;
32300 * clear all the Masonry Brick
32302 clearAll : function()
32305 //this.getChildContainer().dom.innerHTML = "";
32306 this.el.dom.innerHTML = '';
32309 getSelected : function()
32311 if (!this.selectedBrick) {
32315 return this.selectedBrick;
32319 Roo.apply(Roo.bootstrap.LayoutMasonry, {
32323 * register a Masonry Layout
32324 * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
32327 register : function(layout)
32329 this.groups[layout.id] = layout;
32332 * fetch a Masonry Layout based on the masonry layout ID
32333 * @param {string} the masonry layout to add
32334 * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
32337 get: function(layout_id) {
32338 if (typeof(this.groups[layout_id]) == 'undefined') {
32341 return this.groups[layout_id] ;
32353 * http://masonry.desandro.com
32355 * The idea is to render all the bricks based on vertical width...
32357 * The original code extends 'outlayer' - we might need to use that....
32363 * @class Roo.bootstrap.LayoutMasonryAuto
32364 * @extends Roo.bootstrap.Component
32365 * Bootstrap Layout Masonry class
32368 * Create a new Element
32369 * @param {Object} config The config object
32372 Roo.bootstrap.LayoutMasonryAuto = function(config){
32373 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
32376 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
32379 * @cfg {Boolean} isFitWidth - resize the width..
32381 isFitWidth : false, // options..
32383 * @cfg {Boolean} isOriginLeft = left align?
32385 isOriginLeft : true,
32387 * @cfg {Boolean} isOriginTop = top align?
32389 isOriginTop : false,
32391 * @cfg {Boolean} isLayoutInstant = no animation?
32393 isLayoutInstant : false, // needed?
32395 * @cfg {Boolean} isResizingContainer = not sure if this is used..
32397 isResizingContainer : true,
32399 * @cfg {Number} columnWidth width of the columns
32405 * @cfg {Number} maxCols maximum number of columns
32410 * @cfg {Number} padHeight padding below box..
32416 * @cfg {Boolean} isAutoInitial defalut true
32419 isAutoInitial : true,
32425 initialColumnWidth : 0,
32426 currentSize : null,
32428 colYs : null, // array.
32435 bricks: null, //CompositeElement
32436 cols : 0, // array?
32437 // element : null, // wrapped now this.el
32438 _isLayoutInited : null,
32441 getAutoCreate : function(){
32445 cls: 'blog-masonary-wrapper ' + this.cls,
32447 cls : 'mas-boxes masonary'
32454 getChildContainer: function( )
32456 if (this.boxesEl) {
32457 return this.boxesEl;
32460 this.boxesEl = this.el.select('.mas-boxes').first();
32462 return this.boxesEl;
32466 initEvents : function()
32470 if(this.isAutoInitial){
32471 Roo.log('hook children rendered');
32472 this.on('childrenrendered', function() {
32473 Roo.log('children rendered');
32480 initial : function()
32482 this.reloadItems();
32484 this.currentSize = this.el.getBox(true);
32486 /// was window resize... - let's see if this works..
32487 Roo.EventManager.onWindowResize(this.resize, this);
32489 if(!this.isAutoInitial){
32494 this.layout.defer(500,this);
32497 reloadItems: function()
32499 this.bricks = this.el.select('.masonry-brick', true);
32501 this.bricks.each(function(b) {
32502 //Roo.log(b.getSize());
32503 if (!b.attr('originalwidth')) {
32504 b.attr('originalwidth', b.getSize().width);
32509 Roo.log(this.bricks.elements.length);
32512 resize : function()
32515 var cs = this.el.getBox(true);
32517 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
32518 Roo.log("no change in with or X");
32521 this.currentSize = cs;
32525 layout : function()
32528 this._resetLayout();
32529 //this._manageStamps();
32531 // don't animate first layout
32532 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
32533 this.layoutItems( isInstant );
32535 // flag for initalized
32536 this._isLayoutInited = true;
32539 layoutItems : function( isInstant )
32541 //var items = this._getItemsForLayout( this.items );
32542 // original code supports filtering layout items.. we just ignore it..
32544 this._layoutItems( this.bricks , isInstant );
32546 this._postLayout();
32548 _layoutItems : function ( items , isInstant)
32550 //this.fireEvent( 'layout', this, items );
32553 if ( !items || !items.elements.length ) {
32554 // no items, emit event with empty array
32559 items.each(function(item) {
32560 Roo.log("layout item");
32562 // get x/y object from method
32563 var position = this._getItemLayoutPosition( item );
32565 position.item = item;
32566 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
32567 queue.push( position );
32570 this._processLayoutQueue( queue );
32572 /** Sets position of item in DOM
32573 * @param {Element} item
32574 * @param {Number} x - horizontal position
32575 * @param {Number} y - vertical position
32576 * @param {Boolean} isInstant - disables transitions
32578 _processLayoutQueue : function( queue )
32580 for ( var i=0, len = queue.length; i < len; i++ ) {
32581 var obj = queue[i];
32582 obj.item.position('absolute');
32583 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
32589 * Any logic you want to do after each layout,
32590 * i.e. size the container
32592 _postLayout : function()
32594 this.resizeContainer();
32597 resizeContainer : function()
32599 if ( !this.isResizingContainer ) {
32602 var size = this._getContainerSize();
32604 this.el.setSize(size.width,size.height);
32605 this.boxesEl.setSize(size.width,size.height);
32611 _resetLayout : function()
32613 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
32614 this.colWidth = this.el.getWidth();
32615 //this.gutter = this.el.getWidth();
32617 this.measureColumns();
32623 this.colYs.push( 0 );
32629 measureColumns : function()
32631 this.getContainerWidth();
32632 // if columnWidth is 0, default to outerWidth of first item
32633 if ( !this.columnWidth ) {
32634 var firstItem = this.bricks.first();
32635 Roo.log(firstItem);
32636 this.columnWidth = this.containerWidth;
32637 if (firstItem && firstItem.attr('originalwidth') ) {
32638 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
32640 // columnWidth fall back to item of first element
32641 Roo.log("set column width?");
32642 this.initialColumnWidth = this.columnWidth ;
32644 // if first elem has no width, default to size of container
32649 if (this.initialColumnWidth) {
32650 this.columnWidth = this.initialColumnWidth;
32655 // column width is fixed at the top - however if container width get's smaller we should
32658 // this bit calcs how man columns..
32660 var columnWidth = this.columnWidth += this.gutter;
32662 // calculate columns
32663 var containerWidth = this.containerWidth + this.gutter;
32665 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
32666 // fix rounding errors, typically with gutters
32667 var excess = columnWidth - containerWidth % columnWidth;
32670 // if overshoot is less than a pixel, round up, otherwise floor it
32671 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
32672 cols = Math[ mathMethod ]( cols );
32673 this.cols = Math.max( cols, 1 );
32674 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
32676 // padding positioning..
32677 var totalColWidth = this.cols * this.columnWidth;
32678 var padavail = this.containerWidth - totalColWidth;
32679 // so for 2 columns - we need 3 'pads'
32681 var padNeeded = (1+this.cols) * this.padWidth;
32683 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
32685 this.columnWidth += padExtra
32686 //this.padWidth = Math.floor(padavail / ( this.cols));
32688 // adjust colum width so that padding is fixed??
32690 // we have 3 columns ... total = width * 3
32691 // we have X left over... that should be used by
32693 //if (this.expandC) {
32701 getContainerWidth : function()
32703 /* // container is parent if fit width
32704 var container = this.isFitWidth ? this.element.parentNode : this.element;
32705 // check that this.size and size are there
32706 // IE8 triggers resize on body size change, so they might not be
32708 var size = getSize( container ); //FIXME
32709 this.containerWidth = size && size.innerWidth; //FIXME
32712 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
32716 _getItemLayoutPosition : function( item ) // what is item?
32718 // we resize the item to our columnWidth..
32720 item.setWidth(this.columnWidth);
32721 item.autoBoxAdjust = false;
32723 var sz = item.getSize();
32725 // how many columns does this brick span
32726 var remainder = this.containerWidth % this.columnWidth;
32728 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
32729 // round if off by 1 pixel, otherwise use ceil
32730 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
32731 colSpan = Math.min( colSpan, this.cols );
32733 // normally this should be '1' as we dont' currently allow multi width columns..
32735 var colGroup = this._getColGroup( colSpan );
32736 // get the minimum Y value from the columns
32737 var minimumY = Math.min.apply( Math, colGroup );
32738 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32740 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
32742 // position the brick
32744 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
32745 y: this.currentSize.y + minimumY + this.padHeight
32749 // apply setHeight to necessary columns
32750 var setHeight = minimumY + sz.height + this.padHeight;
32751 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32753 var setSpan = this.cols + 1 - colGroup.length;
32754 for ( var i = 0; i < setSpan; i++ ) {
32755 this.colYs[ shortColIndex + i ] = setHeight ;
32762 * @param {Number} colSpan - number of columns the element spans
32763 * @returns {Array} colGroup
32765 _getColGroup : function( colSpan )
32767 if ( colSpan < 2 ) {
32768 // if brick spans only one column, use all the column Ys
32773 // how many different places could this brick fit horizontally
32774 var groupCount = this.cols + 1 - colSpan;
32775 // for each group potential horizontal position
32776 for ( var i = 0; i < groupCount; i++ ) {
32777 // make an array of colY values for that one group
32778 var groupColYs = this.colYs.slice( i, i + colSpan );
32779 // and get the max value of the array
32780 colGroup[i] = Math.max.apply( Math, groupColYs );
32785 _manageStamp : function( stamp )
32787 var stampSize = stamp.getSize();
32788 var offset = stamp.getBox();
32789 // get the columns that this stamp affects
32790 var firstX = this.isOriginLeft ? offset.x : offset.right;
32791 var lastX = firstX + stampSize.width;
32792 var firstCol = Math.floor( firstX / this.columnWidth );
32793 firstCol = Math.max( 0, firstCol );
32795 var lastCol = Math.floor( lastX / this.columnWidth );
32796 // lastCol should not go over if multiple of columnWidth #425
32797 lastCol -= lastX % this.columnWidth ? 0 : 1;
32798 lastCol = Math.min( this.cols - 1, lastCol );
32800 // set colYs to bottom of the stamp
32801 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
32804 for ( var i = firstCol; i <= lastCol; i++ ) {
32805 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
32810 _getContainerSize : function()
32812 this.maxY = Math.max.apply( Math, this.colYs );
32817 if ( this.isFitWidth ) {
32818 size.width = this._getContainerFitWidth();
32824 _getContainerFitWidth : function()
32826 var unusedCols = 0;
32827 // count unused columns
32830 if ( this.colYs[i] !== 0 ) {
32835 // fit container to columns that have been used
32836 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
32839 needsResizeLayout : function()
32841 var previousWidth = this.containerWidth;
32842 this.getContainerWidth();
32843 return previousWidth !== this.containerWidth;
32858 * @class Roo.bootstrap.MasonryBrick
32859 * @extends Roo.bootstrap.Component
32860 * Bootstrap MasonryBrick class
32863 * Create a new MasonryBrick
32864 * @param {Object} config The config object
32867 Roo.bootstrap.MasonryBrick = function(config){
32869 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
32871 Roo.bootstrap.MasonryBrick.register(this);
32877 * When a MasonryBrick is clcik
32878 * @param {Roo.bootstrap.MasonryBrick} this
32879 * @param {Roo.EventObject} e
32885 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
32888 * @cfg {String} title
32892 * @cfg {String} html
32896 * @cfg {String} bgimage
32900 * @cfg {String} videourl
32904 * @cfg {String} cls
32908 * @cfg {String} href
32912 * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
32917 * @cfg {String} placetitle (center|bottom)
32922 * @cfg {Boolean} isFitContainer defalut true
32924 isFitContainer : true,
32927 * @cfg {Boolean} preventDefault defalut false
32929 preventDefault : false,
32932 * @cfg {Boolean} inverse defalut false
32934 maskInverse : false,
32936 getAutoCreate : function()
32938 if(!this.isFitContainer){
32939 return this.getSplitAutoCreate();
32942 var cls = 'masonry-brick masonry-brick-full';
32944 if(this.href.length){
32945 cls += ' masonry-brick-link';
32948 if(this.bgimage.length){
32949 cls += ' masonry-brick-image';
32952 if(this.maskInverse){
32953 cls += ' mask-inverse';
32956 if(!this.html.length && !this.maskInverse && !this.videourl.length){
32957 cls += ' enable-mask';
32961 cls += ' masonry-' + this.size + '-brick';
32964 if(this.placetitle.length){
32966 switch (this.placetitle) {
32968 cls += ' masonry-center-title';
32971 cls += ' masonry-bottom-title';
32978 if(!this.html.length && !this.bgimage.length){
32979 cls += ' masonry-center-title';
32982 if(!this.html.length && this.bgimage.length){
32983 cls += ' masonry-bottom-title';
32988 cls += ' ' + this.cls;
32992 tag: (this.href.length) ? 'a' : 'div',
32997 cls: 'masonry-brick-mask'
33001 cls: 'masonry-brick-paragraph',
33007 if(this.href.length){
33008 cfg.href = this.href;
33011 var cn = cfg.cn[1].cn;
33013 if(this.title.length){
33016 cls: 'masonry-brick-title',
33021 if(this.html.length){
33024 cls: 'masonry-brick-text',
33029 if (!this.title.length && !this.html.length) {
33030 cfg.cn[1].cls += ' hide';
33033 if(this.bgimage.length){
33036 cls: 'masonry-brick-image-view',
33041 if(this.videourl.length){
33042 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
33043 // youtube support only?
33046 cls: 'masonry-brick-image-view',
33049 allowfullscreen : true
33057 getSplitAutoCreate : function()
33059 var cls = 'masonry-brick masonry-brick-split';
33061 if(this.href.length){
33062 cls += ' masonry-brick-link';
33065 if(this.bgimage.length){
33066 cls += ' masonry-brick-image';
33070 cls += ' masonry-' + this.size + '-brick';
33073 switch (this.placetitle) {
33075 cls += ' masonry-center-title';
33078 cls += ' masonry-bottom-title';
33081 if(!this.bgimage.length){
33082 cls += ' masonry-center-title';
33085 if(this.bgimage.length){
33086 cls += ' masonry-bottom-title';
33092 cls += ' ' + this.cls;
33096 tag: (this.href.length) ? 'a' : 'div',
33101 cls: 'masonry-brick-split-head',
33105 cls: 'masonry-brick-paragraph',
33112 cls: 'masonry-brick-split-body',
33118 if(this.href.length){
33119 cfg.href = this.href;
33122 if(this.title.length){
33123 cfg.cn[0].cn[0].cn.push({
33125 cls: 'masonry-brick-title',
33130 if(this.html.length){
33131 cfg.cn[1].cn.push({
33133 cls: 'masonry-brick-text',
33138 if(this.bgimage.length){
33139 cfg.cn[0].cn.push({
33141 cls: 'masonry-brick-image-view',
33146 if(this.videourl.length){
33147 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
33148 // youtube support only?
33149 cfg.cn[0].cn.cn.push({
33151 cls: 'masonry-brick-image-view',
33154 allowfullscreen : true
33161 initEvents: function()
33163 switch (this.size) {
33196 this.el.on('touchstart', this.onTouchStart, this);
33197 this.el.on('touchmove', this.onTouchMove, this);
33198 this.el.on('touchend', this.onTouchEnd, this);
33199 this.el.on('contextmenu', this.onContextMenu, this);
33201 this.el.on('mouseenter' ,this.enter, this);
33202 this.el.on('mouseleave', this.leave, this);
33203 this.el.on('click', this.onClick, this);
33206 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
33207 this.parent().bricks.push(this);
33212 onClick: function(e, el)
33214 var time = this.endTimer - this.startTimer;
33215 // Roo.log(e.preventDefault());
33218 e.preventDefault();
33223 if(!this.preventDefault){
33227 e.preventDefault();
33229 if (this.activeClass != '') {
33230 this.selectBrick();
33233 this.fireEvent('click', this, e);
33236 enter: function(e, el)
33238 e.preventDefault();
33240 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
33244 if(this.bgimage.length && this.html.length){
33245 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
33249 leave: function(e, el)
33251 e.preventDefault();
33253 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
33257 if(this.bgimage.length && this.html.length){
33258 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
33262 onTouchStart: function(e, el)
33264 // e.preventDefault();
33266 this.touchmoved = false;
33268 if(!this.isFitContainer){
33272 if(!this.bgimage.length || !this.html.length){
33276 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
33278 this.timer = new Date().getTime();
33282 onTouchMove: function(e, el)
33284 this.touchmoved = true;
33287 onContextMenu : function(e,el)
33289 e.preventDefault();
33290 e.stopPropagation();
33294 onTouchEnd: function(e, el)
33296 // e.preventDefault();
33298 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
33305 if(!this.bgimage.length || !this.html.length){
33307 if(this.href.length){
33308 window.location.href = this.href;
33314 if(!this.isFitContainer){
33318 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
33320 window.location.href = this.href;
33323 //selection on single brick only
33324 selectBrick : function() {
33326 if (!this.parentId) {
33330 var m = Roo.bootstrap.LayoutMasonry.get(this.parentId);
33331 var index = m.selectedBrick.indexOf(this.id);
33334 m.selectedBrick.splice(index,1);
33335 this.el.removeClass(this.activeClass);
33339 for(var i = 0; i < m.selectedBrick.length; i++) {
33340 var b = Roo.bootstrap.MasonryBrick.get(m.selectedBrick[i]);
33341 b.el.removeClass(b.activeClass);
33344 m.selectedBrick = [];
33346 m.selectedBrick.push(this.id);
33347 this.el.addClass(this.activeClass);
33351 isSelected : function(){
33352 return this.el.hasClass(this.activeClass);
33357 Roo.apply(Roo.bootstrap.MasonryBrick, {
33360 groups : new Roo.util.MixedCollection(false, function(o) { return o.el.id; }),
33362 * register a Masonry Brick
33363 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
33366 register : function(brick)
33368 //this.groups[brick.id] = brick;
33369 this.groups.add(brick.id, brick);
33372 * fetch a masonry brick based on the masonry brick ID
33373 * @param {string} the masonry brick to add
33374 * @returns {Roo.bootstrap.MasonryBrick} the masonry brick
33377 get: function(brick_id)
33379 // if (typeof(this.groups[brick_id]) == 'undefined') {
33382 // return this.groups[brick_id] ;
33384 if(this.groups.key(brick_id)) {
33385 return this.groups.key(brick_id);
33403 * @class Roo.bootstrap.Brick
33404 * @extends Roo.bootstrap.Component
33405 * Bootstrap Brick class
33408 * Create a new Brick
33409 * @param {Object} config The config object
33412 Roo.bootstrap.Brick = function(config){
33413 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
33419 * When a Brick is click
33420 * @param {Roo.bootstrap.Brick} this
33421 * @param {Roo.EventObject} e
33427 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
33430 * @cfg {String} title
33434 * @cfg {String} html
33438 * @cfg {String} bgimage
33442 * @cfg {String} cls
33446 * @cfg {String} href
33450 * @cfg {String} video
33454 * @cfg {Boolean} square
33458 getAutoCreate : function()
33460 var cls = 'roo-brick';
33462 if(this.href.length){
33463 cls += ' roo-brick-link';
33466 if(this.bgimage.length){
33467 cls += ' roo-brick-image';
33470 if(!this.html.length && !this.bgimage.length){
33471 cls += ' roo-brick-center-title';
33474 if(!this.html.length && this.bgimage.length){
33475 cls += ' roo-brick-bottom-title';
33479 cls += ' ' + this.cls;
33483 tag: (this.href.length) ? 'a' : 'div',
33488 cls: 'roo-brick-paragraph',
33494 if(this.href.length){
33495 cfg.href = this.href;
33498 var cn = cfg.cn[0].cn;
33500 if(this.title.length){
33503 cls: 'roo-brick-title',
33508 if(this.html.length){
33511 cls: 'roo-brick-text',
33518 if(this.bgimage.length){
33521 cls: 'roo-brick-image-view',
33529 initEvents: function()
33531 if(this.title.length || this.html.length){
33532 this.el.on('mouseenter' ,this.enter, this);
33533 this.el.on('mouseleave', this.leave, this);
33536 Roo.EventManager.onWindowResize(this.resize, this);
33538 if(this.bgimage.length){
33539 this.imageEl = this.el.select('.roo-brick-image-view', true).first();
33540 this.imageEl.on('load', this.onImageLoad, this);
33547 onImageLoad : function()
33552 resize : function()
33554 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
33556 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
33558 if(this.bgimage.length){
33559 var image = this.el.select('.roo-brick-image-view', true).first();
33561 image.setWidth(paragraph.getWidth());
33564 image.setHeight(paragraph.getWidth());
33567 this.el.setHeight(image.getHeight());
33568 paragraph.setHeight(image.getHeight());
33574 enter: function(e, el)
33576 e.preventDefault();
33578 if(this.bgimage.length){
33579 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
33580 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
33584 leave: function(e, el)
33586 e.preventDefault();
33588 if(this.bgimage.length){
33589 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
33590 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
33605 * @class Roo.bootstrap.NumberField
33606 * @extends Roo.bootstrap.Input
33607 * Bootstrap NumberField class
33613 * Create a new NumberField
33614 * @param {Object} config The config object
33617 Roo.bootstrap.NumberField = function(config){
33618 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
33621 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
33624 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
33626 allowDecimals : true,
33628 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
33630 decimalSeparator : ".",
33632 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
33634 decimalPrecision : 2,
33636 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
33638 allowNegative : true,
33641 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
33645 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
33647 minValue : Number.NEGATIVE_INFINITY,
33649 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
33651 maxValue : Number.MAX_VALUE,
33653 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
33655 minText : "The minimum value for this field is {0}",
33657 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
33659 maxText : "The maximum value for this field is {0}",
33661 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
33662 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
33664 nanText : "{0} is not a valid number",
33666 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
33668 thousandsDelimiter : false,
33670 * @cfg {String} valueAlign alignment of value
33672 valueAlign : "left",
33674 getAutoCreate : function()
33676 var hiddenInput = {
33680 cls: 'hidden-number-input'
33684 hiddenInput.name = this.name;
33689 var cfg = Roo.bootstrap.NumberField.superclass.getAutoCreate.call(this);
33691 this.name = hiddenInput.name;
33693 if(cfg.cn.length > 0) {
33694 cfg.cn.push(hiddenInput);
33701 initEvents : function()
33703 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
33705 var allowed = "0123456789";
33707 if(this.allowDecimals){
33708 allowed += this.decimalSeparator;
33711 if(this.allowNegative){
33715 if(this.thousandsDelimiter) {
33719 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
33721 var keyPress = function(e){
33723 var k = e.getKey();
33725 var c = e.getCharCode();
33728 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
33729 allowed.indexOf(String.fromCharCode(c)) === -1
33735 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
33739 if(allowed.indexOf(String.fromCharCode(c)) === -1){
33744 this.el.on("keypress", keyPress, this);
33747 validateValue : function(value)
33750 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
33754 var num = this.parseValue(value);
33757 this.markInvalid(String.format(this.nanText, value));
33761 if(num < this.minValue){
33762 this.markInvalid(String.format(this.minText, this.minValue));
33766 if(num > this.maxValue){
33767 this.markInvalid(String.format(this.maxText, this.maxValue));
33774 getValue : function()
33776 var v = this.hiddenEl().getValue();
33778 return this.fixPrecision(this.parseValue(v));
33781 parseValue : function(value)
33783 if(this.thousandsDelimiter) {
33785 r = new RegExp(",", "g");
33786 value = value.replace(r, "");
33789 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
33790 return isNaN(value) ? '' : value;
33793 fixPrecision : function(value)
33795 if(this.thousandsDelimiter) {
33797 r = new RegExp(",", "g");
33798 value = value.replace(r, "");
33801 var nan = isNaN(value);
33803 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
33804 return nan ? '' : value;
33806 return parseFloat(value).toFixed(this.decimalPrecision);
33809 setValue : function(v)
33811 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
33817 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
33819 this.inputEl().dom.value = (v == '') ? '' :
33820 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
33822 if(!this.allowZero && v === '0') {
33823 this.hiddenEl().dom.value = '';
33824 this.inputEl().dom.value = '';
33831 decimalPrecisionFcn : function(v)
33833 return Math.floor(v);
33836 beforeBlur : function()
33838 var v = this.parseValue(this.getRawValue());
33840 if(v || v === 0 || v === ''){
33845 hiddenEl : function()
33847 return this.el.select('input.hidden-number-input',true).first();
33859 * @class Roo.bootstrap.DocumentSlider
33860 * @extends Roo.bootstrap.Component
33861 * Bootstrap DocumentSlider class
33864 * Create a new DocumentViewer
33865 * @param {Object} config The config object
33868 Roo.bootstrap.DocumentSlider = function(config){
33869 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
33876 * Fire after initEvent
33877 * @param {Roo.bootstrap.DocumentSlider} this
33882 * Fire after update
33883 * @param {Roo.bootstrap.DocumentSlider} this
33889 * @param {Roo.bootstrap.DocumentSlider} this
33895 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
33901 getAutoCreate : function()
33905 cls : 'roo-document-slider',
33909 cls : 'roo-document-slider-header',
33913 cls : 'roo-document-slider-header-title'
33919 cls : 'roo-document-slider-body',
33923 cls : 'roo-document-slider-prev',
33927 cls : 'fa fa-chevron-left'
33933 cls : 'roo-document-slider-thumb',
33937 cls : 'roo-document-slider-image'
33943 cls : 'roo-document-slider-next',
33947 cls : 'fa fa-chevron-right'
33959 initEvents : function()
33961 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
33962 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
33964 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
33965 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
33967 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
33968 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
33970 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
33971 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
33973 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
33974 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
33976 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
33977 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33979 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
33980 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33982 this.thumbEl.on('click', this.onClick, this);
33984 this.prevIndicator.on('click', this.prev, this);
33986 this.nextIndicator.on('click', this.next, this);
33990 initial : function()
33992 if(this.files.length){
33993 this.indicator = 1;
33997 this.fireEvent('initial', this);
34000 update : function()
34002 this.imageEl.attr('src', this.files[this.indicator - 1]);
34004 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
34006 this.prevIndicator.show();
34008 if(this.indicator == 1){
34009 this.prevIndicator.hide();
34012 this.nextIndicator.show();
34014 if(this.indicator == this.files.length){
34015 this.nextIndicator.hide();
34018 this.thumbEl.scrollTo('top');
34020 this.fireEvent('update', this);
34023 onClick : function(e)
34025 e.preventDefault();
34027 this.fireEvent('click', this);
34032 e.preventDefault();
34034 this.indicator = Math.max(1, this.indicator - 1);
34041 e.preventDefault();
34043 this.indicator = Math.min(this.files.length, this.indicator + 1);
34057 * @class Roo.bootstrap.RadioSet
34058 * @extends Roo.bootstrap.Input
34059 * Bootstrap RadioSet class
34060 * @cfg {String} indicatorpos (left|right) default left
34061 * @cfg {Boolean} inline (true|false) inline the element (default true)
34062 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
34064 * Create a new RadioSet
34065 * @param {Object} config The config object
34068 Roo.bootstrap.RadioSet = function(config){
34070 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
34074 Roo.bootstrap.RadioSet.register(this);
34079 * Fires when the element is checked or unchecked.
34080 * @param {Roo.bootstrap.RadioSet} this This radio
34081 * @param {Roo.bootstrap.Radio} item The checked item
34086 * Fires when the element is click.
34087 * @param {Roo.bootstrap.RadioSet} this This radio set
34088 * @param {Roo.bootstrap.Radio} item The checked item
34089 * @param {Roo.EventObject} e The event object
34096 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
34104 indicatorpos : 'left',
34106 getAutoCreate : function()
34110 cls : 'roo-radio-set-label',
34114 html : this.fieldLabel
34118 if (Roo.bootstrap.version == 3) {
34121 if(this.indicatorpos == 'left'){
34124 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
34125 tooltip : 'This field is required'
34130 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
34131 tooltip : 'This field is required'
34137 cls : 'roo-radio-set-items'
34140 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
34142 if (align === 'left' && this.fieldLabel.length) {
34145 cls : "roo-radio-set-right",
34151 if(this.labelWidth > 12){
34152 label.style = "width: " + this.labelWidth + 'px';
34155 if(this.labelWidth < 13 && this.labelmd == 0){
34156 this.labelmd = this.labelWidth;
34159 if(this.labellg > 0){
34160 label.cls += ' col-lg-' + this.labellg;
34161 items.cls += ' col-lg-' + (12 - this.labellg);
34164 if(this.labelmd > 0){
34165 label.cls += ' col-md-' + this.labelmd;
34166 items.cls += ' col-md-' + (12 - this.labelmd);
34169 if(this.labelsm > 0){
34170 label.cls += ' col-sm-' + this.labelsm;
34171 items.cls += ' col-sm-' + (12 - this.labelsm);
34174 if(this.labelxs > 0){
34175 label.cls += ' col-xs-' + this.labelxs;
34176 items.cls += ' col-xs-' + (12 - this.labelxs);
34182 cls : 'roo-radio-set',
34186 cls : 'roo-radio-set-input',
34189 value : this.value ? this.value : ''
34196 if(this.weight.length){
34197 cfg.cls += ' roo-radio-' + this.weight;
34201 cfg.cls += ' roo-radio-set-inline';
34205 ['xs','sm','md','lg'].map(function(size){
34206 if (settings[size]) {
34207 cfg.cls += ' col-' + size + '-' + settings[size];
34215 initEvents : function()
34217 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
34218 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
34220 if(!this.fieldLabel.length){
34221 this.labelEl.hide();
34224 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
34225 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
34227 this.indicator = this.indicatorEl();
34229 if(this.indicator){
34230 this.indicator.addClass('invisible');
34233 this.originalValue = this.getValue();
34237 inputEl: function ()
34239 return this.el.select('.roo-radio-set-input', true).first();
34242 getChildContainer : function()
34244 return this.itemsEl;
34247 register : function(item)
34249 this.radioes.push(item);
34253 validate : function()
34255 if(this.getVisibilityEl().hasClass('hidden')){
34261 Roo.each(this.radioes, function(i){
34270 if(this.allowBlank) {
34274 if(this.disabled || valid){
34279 this.markInvalid();
34284 markValid : function()
34286 if(this.labelEl.isVisible(true) && this.indicatorEl()){
34287 this.indicatorEl().removeClass('visible');
34288 this.indicatorEl().addClass('invisible');
34292 if (Roo.bootstrap.version == 3) {
34293 this.el.removeClass([this.invalidClass, this.validClass]);
34294 this.el.addClass(this.validClass);
34296 this.el.removeClass(['is-invalid','is-valid']);
34297 this.el.addClass(['is-valid']);
34299 this.fireEvent('valid', this);
34302 markInvalid : function(msg)
34304 if(this.allowBlank || this.disabled){
34308 if(this.labelEl.isVisible(true) && this.indicatorEl()){
34309 this.indicatorEl().removeClass('invisible');
34310 this.indicatorEl().addClass('visible');
34312 if (Roo.bootstrap.version == 3) {
34313 this.el.removeClass([this.invalidClass, this.validClass]);
34314 this.el.addClass(this.invalidClass);
34316 this.el.removeClass(['is-invalid','is-valid']);
34317 this.el.addClass(['is-invalid']);
34320 this.fireEvent('invalid', this, msg);
34324 setValue : function(v, suppressEvent)
34326 if(this.value === v){
34333 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
34336 Roo.each(this.radioes, function(i){
34338 i.el.removeClass('checked');
34341 Roo.each(this.radioes, function(i){
34343 if(i.value === v || i.value.toString() === v.toString()){
34345 i.el.addClass('checked');
34347 if(suppressEvent !== true){
34348 this.fireEvent('check', this, i);
34359 clearInvalid : function(){
34361 if(!this.el || this.preventMark){
34365 this.el.removeClass([this.invalidClass]);
34367 this.fireEvent('valid', this);
34372 Roo.apply(Roo.bootstrap.RadioSet, {
34376 register : function(set)
34378 this.groups[set.name] = set;
34381 get: function(name)
34383 if (typeof(this.groups[name]) == 'undefined') {
34387 return this.groups[name] ;
34393 * Ext JS Library 1.1.1
34394 * Copyright(c) 2006-2007, Ext JS, LLC.
34396 * Originally Released Under LGPL - original licence link has changed is not relivant.
34399 * <script type="text/javascript">
34404 * @class Roo.bootstrap.SplitBar
34405 * @extends Roo.util.Observable
34406 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
34410 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
34411 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
34412 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
34413 split.minSize = 100;
34414 split.maxSize = 600;
34415 split.animate = true;
34416 split.on('moved', splitterMoved);
34419 * Create a new SplitBar
34420 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
34421 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
34422 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34423 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
34424 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
34425 position of the SplitBar).
34427 Roo.bootstrap.SplitBar = function(cfg){
34432 // dragElement : elm
34433 // resizingElement: el,
34435 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
34436 // placement : Roo.bootstrap.SplitBar.LEFT ,
34437 // existingProxy ???
34440 this.el = Roo.get(cfg.dragElement, true);
34441 this.el.dom.unselectable = "on";
34443 this.resizingEl = Roo.get(cfg.resizingElement, true);
34447 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34448 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
34451 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
34454 * The minimum size of the resizing element. (Defaults to 0)
34460 * The maximum size of the resizing element. (Defaults to 2000)
34463 this.maxSize = 2000;
34466 * Whether to animate the transition to the new size
34469 this.animate = false;
34472 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
34475 this.useShim = false;
34480 if(!cfg.existingProxy){
34482 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
34484 this.proxy = Roo.get(cfg.existingProxy).dom;
34487 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
34490 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
34493 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
34496 this.dragSpecs = {};
34499 * @private The adapter to use to positon and resize elements
34501 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34502 this.adapter.init(this);
34504 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34506 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
34507 this.el.addClass("roo-splitbar-h");
34510 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
34511 this.el.addClass("roo-splitbar-v");
34517 * Fires when the splitter is moved (alias for {@link #event-moved})
34518 * @param {Roo.bootstrap.SplitBar} this
34519 * @param {Number} newSize the new width or height
34524 * Fires when the splitter is moved
34525 * @param {Roo.bootstrap.SplitBar} this
34526 * @param {Number} newSize the new width or height
34530 * @event beforeresize
34531 * Fires before the splitter is dragged
34532 * @param {Roo.bootstrap.SplitBar} this
34534 "beforeresize" : true,
34536 "beforeapply" : true
34539 Roo.util.Observable.call(this);
34542 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
34543 onStartProxyDrag : function(x, y){
34544 this.fireEvent("beforeresize", this);
34546 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
34548 o.enableDisplayMode("block");
34549 // all splitbars share the same overlay
34550 Roo.bootstrap.SplitBar.prototype.overlay = o;
34552 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
34553 this.overlay.show();
34554 Roo.get(this.proxy).setDisplayed("block");
34555 var size = this.adapter.getElementSize(this);
34556 this.activeMinSize = this.getMinimumSize();;
34557 this.activeMaxSize = this.getMaximumSize();;
34558 var c1 = size - this.activeMinSize;
34559 var c2 = Math.max(this.activeMaxSize - size, 0);
34560 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34561 this.dd.resetConstraints();
34562 this.dd.setXConstraint(
34563 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
34564 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
34566 this.dd.setYConstraint(0, 0);
34568 this.dd.resetConstraints();
34569 this.dd.setXConstraint(0, 0);
34570 this.dd.setYConstraint(
34571 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
34572 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
34575 this.dragSpecs.startSize = size;
34576 this.dragSpecs.startPoint = [x, y];
34577 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
34581 * @private Called after the drag operation by the DDProxy
34583 onEndProxyDrag : function(e){
34584 Roo.get(this.proxy).setDisplayed(false);
34585 var endPoint = Roo.lib.Event.getXY(e);
34587 this.overlay.hide();
34590 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34591 newSize = this.dragSpecs.startSize +
34592 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
34593 endPoint[0] - this.dragSpecs.startPoint[0] :
34594 this.dragSpecs.startPoint[0] - endPoint[0]
34597 newSize = this.dragSpecs.startSize +
34598 (this.placement == Roo.bootstrap.SplitBar.TOP ?
34599 endPoint[1] - this.dragSpecs.startPoint[1] :
34600 this.dragSpecs.startPoint[1] - endPoint[1]
34603 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
34604 if(newSize != this.dragSpecs.startSize){
34605 if(this.fireEvent('beforeapply', this, newSize) !== false){
34606 this.adapter.setElementSize(this, newSize);
34607 this.fireEvent("moved", this, newSize);
34608 this.fireEvent("resize", this, newSize);
34614 * Get the adapter this SplitBar uses
34615 * @return The adapter object
34617 getAdapter : function(){
34618 return this.adapter;
34622 * Set the adapter this SplitBar uses
34623 * @param {Object} adapter A SplitBar adapter object
34625 setAdapter : function(adapter){
34626 this.adapter = adapter;
34627 this.adapter.init(this);
34631 * Gets the minimum size for the resizing element
34632 * @return {Number} The minimum size
34634 getMinimumSize : function(){
34635 return this.minSize;
34639 * Sets the minimum size for the resizing element
34640 * @param {Number} minSize The minimum size
34642 setMinimumSize : function(minSize){
34643 this.minSize = minSize;
34647 * Gets the maximum size for the resizing element
34648 * @return {Number} The maximum size
34650 getMaximumSize : function(){
34651 return this.maxSize;
34655 * Sets the maximum size for the resizing element
34656 * @param {Number} maxSize The maximum size
34658 setMaximumSize : function(maxSize){
34659 this.maxSize = maxSize;
34663 * Sets the initialize size for the resizing element
34664 * @param {Number} size The initial size
34666 setCurrentSize : function(size){
34667 var oldAnimate = this.animate;
34668 this.animate = false;
34669 this.adapter.setElementSize(this, size);
34670 this.animate = oldAnimate;
34674 * Destroy this splitbar.
34675 * @param {Boolean} removeEl True to remove the element
34677 destroy : function(removeEl){
34679 this.shim.remove();
34682 this.proxy.parentNode.removeChild(this.proxy);
34690 * @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.
34692 Roo.bootstrap.SplitBar.createProxy = function(dir){
34693 var proxy = new Roo.Element(document.createElement("div"));
34694 proxy.unselectable();
34695 var cls = 'roo-splitbar-proxy';
34696 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
34697 document.body.appendChild(proxy.dom);
34702 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
34703 * Default Adapter. It assumes the splitter and resizing element are not positioned
34704 * elements and only gets/sets the width of the element. Generally used for table based layouts.
34706 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
34709 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
34710 // do nothing for now
34711 init : function(s){
34715 * Called before drag operations to get the current size of the resizing element.
34716 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34718 getElementSize : function(s){
34719 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34720 return s.resizingEl.getWidth();
34722 return s.resizingEl.getHeight();
34727 * Called after drag operations to set the size of the resizing element.
34728 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34729 * @param {Number} newSize The new size to set
34730 * @param {Function} onComplete A function to be invoked when resizing is complete
34732 setElementSize : function(s, newSize, onComplete){
34733 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34735 s.resizingEl.setWidth(newSize);
34737 onComplete(s, newSize);
34740 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
34745 s.resizingEl.setHeight(newSize);
34747 onComplete(s, newSize);
34750 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
34757 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
34758 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
34759 * Adapter that moves the splitter element to align with the resized sizing element.
34760 * Used with an absolute positioned SplitBar.
34761 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
34762 * document.body, make sure you assign an id to the body element.
34764 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
34765 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34766 this.container = Roo.get(container);
34769 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
34770 init : function(s){
34771 this.basic.init(s);
34774 getElementSize : function(s){
34775 return this.basic.getElementSize(s);
34778 setElementSize : function(s, newSize, onComplete){
34779 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
34782 moveSplitter : function(s){
34783 var yes = Roo.bootstrap.SplitBar;
34784 switch(s.placement){
34786 s.el.setX(s.resizingEl.getRight());
34789 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
34792 s.el.setY(s.resizingEl.getBottom());
34795 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
34802 * Orientation constant - Create a vertical SplitBar
34806 Roo.bootstrap.SplitBar.VERTICAL = 1;
34809 * Orientation constant - Create a horizontal SplitBar
34813 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
34816 * Placement constant - The resizing element is to the left of the splitter element
34820 Roo.bootstrap.SplitBar.LEFT = 1;
34823 * Placement constant - The resizing element is to the right of the splitter element
34827 Roo.bootstrap.SplitBar.RIGHT = 2;
34830 * Placement constant - The resizing element is positioned above the splitter element
34834 Roo.bootstrap.SplitBar.TOP = 3;
34837 * Placement constant - The resizing element is positioned under splitter element
34841 Roo.bootstrap.SplitBar.BOTTOM = 4;
34842 Roo.namespace("Roo.bootstrap.layout");/*
34844 * Ext JS Library 1.1.1
34845 * Copyright(c) 2006-2007, Ext JS, LLC.
34847 * Originally Released Under LGPL - original licence link has changed is not relivant.
34850 * <script type="text/javascript">
34854 * @class Roo.bootstrap.layout.Manager
34855 * @extends Roo.bootstrap.Component
34856 * Base class for layout managers.
34858 Roo.bootstrap.layout.Manager = function(config)
34860 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
34866 /** false to disable window resize monitoring @type Boolean */
34867 this.monitorWindowResize = true;
34872 * Fires when a layout is performed.
34873 * @param {Roo.LayoutManager} this
34877 * @event regionresized
34878 * Fires when the user resizes a region.
34879 * @param {Roo.LayoutRegion} region The resized region
34880 * @param {Number} newSize The new size (width for east/west, height for north/south)
34882 "regionresized" : true,
34884 * @event regioncollapsed
34885 * Fires when a region is collapsed.
34886 * @param {Roo.LayoutRegion} region The collapsed region
34888 "regioncollapsed" : true,
34890 * @event regionexpanded
34891 * Fires when a region is expanded.
34892 * @param {Roo.LayoutRegion} region The expanded region
34894 "regionexpanded" : true
34896 this.updating = false;
34899 this.el = Roo.get(config.el);
34905 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
34910 monitorWindowResize : true,
34916 onRender : function(ct, position)
34919 this.el = Roo.get(ct);
34922 //this.fireEvent('render',this);
34926 initEvents: function()
34930 // ie scrollbar fix
34931 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
34932 document.body.scroll = "no";
34933 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
34934 this.el.position('relative');
34936 this.id = this.el.id;
34937 this.el.addClass("roo-layout-container");
34938 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
34939 if(this.el.dom != document.body ) {
34940 this.el.on('resize', this.layout,this);
34941 this.el.on('show', this.layout,this);
34947 * Returns true if this layout is currently being updated
34948 * @return {Boolean}
34950 isUpdating : function(){
34951 return this.updating;
34955 * Suspend the LayoutManager from doing auto-layouts while
34956 * making multiple add or remove calls
34958 beginUpdate : function(){
34959 this.updating = true;
34963 * Restore auto-layouts and optionally disable the manager from performing a layout
34964 * @param {Boolean} noLayout true to disable a layout update
34966 endUpdate : function(noLayout){
34967 this.updating = false;
34973 layout: function(){
34977 onRegionResized : function(region, newSize){
34978 this.fireEvent("regionresized", region, newSize);
34982 onRegionCollapsed : function(region){
34983 this.fireEvent("regioncollapsed", region);
34986 onRegionExpanded : function(region){
34987 this.fireEvent("regionexpanded", region);
34991 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
34992 * performs box-model adjustments.
34993 * @return {Object} The size as an object {width: (the width), height: (the height)}
34995 getViewSize : function()
34998 if(this.el.dom != document.body){
34999 size = this.el.getSize();
35001 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
35003 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
35004 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
35009 * Returns the Element this layout is bound to.
35010 * @return {Roo.Element}
35012 getEl : function(){
35017 * Returns the specified region.
35018 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
35019 * @return {Roo.LayoutRegion}
35021 getRegion : function(target){
35022 return this.regions[target.toLowerCase()];
35025 onWindowResize : function(){
35026 if(this.monitorWindowResize){
35033 * Ext JS Library 1.1.1
35034 * Copyright(c) 2006-2007, Ext JS, LLC.
35036 * Originally Released Under LGPL - original licence link has changed is not relivant.
35039 * <script type="text/javascript">
35042 * @class Roo.bootstrap.layout.Border
35043 * @extends Roo.bootstrap.layout.Manager
35044 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
35045 * please see: examples/bootstrap/nested.html<br><br>
35047 <b>The container the layout is rendered into can be either the body element or any other element.
35048 If it is not the body element, the container needs to either be an absolute positioned element,
35049 or you will need to add "position:relative" to the css of the container. You will also need to specify
35050 the container size if it is not the body element.</b>
35053 * Create a new Border
35054 * @param {Object} config Configuration options
35056 Roo.bootstrap.layout.Border = function(config){
35057 config = config || {};
35058 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
35062 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
35063 if(config[region]){
35064 config[region].region = region;
35065 this.addRegion(config[region]);
35071 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
35073 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
35075 * Creates and adds a new region if it doesn't already exist.
35076 * @param {String} target The target region key (north, south, east, west or center).
35077 * @param {Object} config The regions config object
35078 * @return {BorderLayoutRegion} The new region
35080 addRegion : function(config)
35082 if(!this.regions[config.region]){
35083 var r = this.factory(config);
35084 this.bindRegion(r);
35086 return this.regions[config.region];
35090 bindRegion : function(r){
35091 this.regions[r.config.region] = r;
35093 r.on("visibilitychange", this.layout, this);
35094 r.on("paneladded", this.layout, this);
35095 r.on("panelremoved", this.layout, this);
35096 r.on("invalidated", this.layout, this);
35097 r.on("resized", this.onRegionResized, this);
35098 r.on("collapsed", this.onRegionCollapsed, this);
35099 r.on("expanded", this.onRegionExpanded, this);
35103 * Performs a layout update.
35105 layout : function()
35107 if(this.updating) {
35111 // render all the rebions if they have not been done alreayd?
35112 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
35113 if(this.regions[region] && !this.regions[region].bodyEl){
35114 this.regions[region].onRender(this.el)
35118 var size = this.getViewSize();
35119 var w = size.width;
35120 var h = size.height;
35125 //var x = 0, y = 0;
35127 var rs = this.regions;
35128 var north = rs["north"];
35129 var south = rs["south"];
35130 var west = rs["west"];
35131 var east = rs["east"];
35132 var center = rs["center"];
35133 //if(this.hideOnLayout){ // not supported anymore
35134 //c.el.setStyle("display", "none");
35136 if(north && north.isVisible()){
35137 var b = north.getBox();
35138 var m = north.getMargins();
35139 b.width = w - (m.left+m.right);
35142 centerY = b.height + b.y + m.bottom;
35143 centerH -= centerY;
35144 north.updateBox(this.safeBox(b));
35146 if(south && south.isVisible()){
35147 var b = south.getBox();
35148 var m = south.getMargins();
35149 b.width = w - (m.left+m.right);
35151 var totalHeight = (b.height + m.top + m.bottom);
35152 b.y = h - totalHeight + m.top;
35153 centerH -= totalHeight;
35154 south.updateBox(this.safeBox(b));
35156 if(west && west.isVisible()){
35157 var b = west.getBox();
35158 var m = west.getMargins();
35159 b.height = centerH - (m.top+m.bottom);
35161 b.y = centerY + m.top;
35162 var totalWidth = (b.width + m.left + m.right);
35163 centerX += totalWidth;
35164 centerW -= totalWidth;
35165 west.updateBox(this.safeBox(b));
35167 if(east && east.isVisible()){
35168 var b = east.getBox();
35169 var m = east.getMargins();
35170 b.height = centerH - (m.top+m.bottom);
35171 var totalWidth = (b.width + m.left + m.right);
35172 b.x = w - totalWidth + m.left;
35173 b.y = centerY + m.top;
35174 centerW -= totalWidth;
35175 east.updateBox(this.safeBox(b));
35178 var m = center.getMargins();
35180 x: centerX + m.left,
35181 y: centerY + m.top,
35182 width: centerW - (m.left+m.right),
35183 height: centerH - (m.top+m.bottom)
35185 //if(this.hideOnLayout){
35186 //center.el.setStyle("display", "block");
35188 center.updateBox(this.safeBox(centerBox));
35191 this.fireEvent("layout", this);
35195 safeBox : function(box){
35196 box.width = Math.max(0, box.width);
35197 box.height = Math.max(0, box.height);
35202 * Adds a ContentPanel (or subclass) to this layout.
35203 * @param {String} target The target region key (north, south, east, west or center).
35204 * @param {Roo.ContentPanel} panel The panel to add
35205 * @return {Roo.ContentPanel} The added panel
35207 add : function(target, panel){
35209 target = target.toLowerCase();
35210 return this.regions[target].add(panel);
35214 * Remove a ContentPanel (or subclass) to this layout.
35215 * @param {String} target The target region key (north, south, east, west or center).
35216 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
35217 * @return {Roo.ContentPanel} The removed panel
35219 remove : function(target, panel){
35220 target = target.toLowerCase();
35221 return this.regions[target].remove(panel);
35225 * Searches all regions for a panel with the specified id
35226 * @param {String} panelId
35227 * @return {Roo.ContentPanel} The panel or null if it wasn't found
35229 findPanel : function(panelId){
35230 var rs = this.regions;
35231 for(var target in rs){
35232 if(typeof rs[target] != "function"){
35233 var p = rs[target].getPanel(panelId);
35243 * Searches all regions for a panel with the specified id and activates (shows) it.
35244 * @param {String/ContentPanel} panelId The panels id or the panel itself
35245 * @return {Roo.ContentPanel} The shown panel or null
35247 showPanel : function(panelId) {
35248 var rs = this.regions;
35249 for(var target in rs){
35250 var r = rs[target];
35251 if(typeof r != "function"){
35252 if(r.hasPanel(panelId)){
35253 return r.showPanel(panelId);
35261 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
35262 * @param {Roo.state.Provider} provider (optional) An alternate state provider
35265 restoreState : function(provider){
35267 provider = Roo.state.Manager;
35269 var sm = new Roo.LayoutStateManager();
35270 sm.init(this, provider);
35276 * Adds a xtype elements to the layout.
35280 xtype : 'ContentPanel',
35287 xtype : 'NestedLayoutPanel',
35293 items : [ ... list of content panels or nested layout panels.. ]
35297 * @param {Object} cfg Xtype definition of item to add.
35299 addxtype : function(cfg)
35301 // basically accepts a pannel...
35302 // can accept a layout region..!?!?
35303 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
35306 // theory? children can only be panels??
35308 //if (!cfg.xtype.match(/Panel$/)) {
35313 if (typeof(cfg.region) == 'undefined') {
35314 Roo.log("Failed to add Panel, region was not set");
35318 var region = cfg.region;
35324 xitems = cfg.items;
35331 case 'Content': // ContentPanel (el, cfg)
35332 case 'Scroll': // ContentPanel (el, cfg)
35334 cfg.autoCreate = true;
35335 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35337 // var el = this.el.createChild();
35338 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
35341 this.add(region, ret);
35345 case 'TreePanel': // our new panel!
35346 cfg.el = this.el.createChild();
35347 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
35348 this.add(region, ret);
35353 // create a new Layout (which is a Border Layout...
35355 var clayout = cfg.layout;
35356 clayout.el = this.el.createChild();
35357 clayout.items = clayout.items || [];
35361 // replace this exitems with the clayout ones..
35362 xitems = clayout.items;
35364 // force background off if it's in center...
35365 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
35366 cfg.background = false;
35368 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
35371 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35372 //console.log('adding nested layout panel ' + cfg.toSource());
35373 this.add(region, ret);
35374 nb = {}; /// find first...
35379 // needs grid and region
35381 //var el = this.getRegion(region).el.createChild();
35383 *var el = this.el.createChild();
35384 // create the grid first...
35385 cfg.grid.container = el;
35386 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
35389 if (region == 'center' && this.active ) {
35390 cfg.background = false;
35393 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35395 this.add(region, ret);
35397 if (cfg.background) {
35398 // render grid on panel activation (if panel background)
35399 ret.on('activate', function(gp) {
35400 if (!gp.grid.rendered) {
35401 // gp.grid.render(el);
35405 // cfg.grid.render(el);
35411 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
35412 // it was the old xcomponent building that caused this before.
35413 // espeically if border is the top element in the tree.
35423 if (typeof(Roo[cfg.xtype]) != 'undefined') {
35425 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
35426 this.add(region, ret);
35430 throw "Can not add '" + cfg.xtype + "' to Border";
35436 this.beginUpdate();
35440 Roo.each(xitems, function(i) {
35441 region = nb && i.region ? i.region : false;
35443 var add = ret.addxtype(i);
35446 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
35447 if (!i.background) {
35448 abn[region] = nb[region] ;
35455 // make the last non-background panel active..
35456 //if (nb) { Roo.log(abn); }
35459 for(var r in abn) {
35460 region = this.getRegion(r);
35462 // tried using nb[r], but it does not work..
35464 region.showPanel(abn[r]);
35475 factory : function(cfg)
35478 var validRegions = Roo.bootstrap.layout.Border.regions;
35480 var target = cfg.region;
35483 var r = Roo.bootstrap.layout;
35487 return new r.North(cfg);
35489 return new r.South(cfg);
35491 return new r.East(cfg);
35493 return new r.West(cfg);
35495 return new r.Center(cfg);
35497 throw 'Layout region "'+target+'" not supported.';
35504 * Ext JS Library 1.1.1
35505 * Copyright(c) 2006-2007, Ext JS, LLC.
35507 * Originally Released Under LGPL - original licence link has changed is not relivant.
35510 * <script type="text/javascript">
35514 * @class Roo.bootstrap.layout.Basic
35515 * @extends Roo.util.Observable
35516 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
35517 * and does not have a titlebar, tabs or any other features. All it does is size and position
35518 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
35519 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35520 * @cfg {string} region the region that it inhabits..
35521 * @cfg {bool} skipConfig skip config?
35525 Roo.bootstrap.layout.Basic = function(config){
35527 this.mgr = config.mgr;
35529 this.position = config.region;
35531 var skipConfig = config.skipConfig;
35535 * @scope Roo.BasicLayoutRegion
35539 * @event beforeremove
35540 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
35541 * @param {Roo.LayoutRegion} this
35542 * @param {Roo.ContentPanel} panel The panel
35543 * @param {Object} e The cancel event object
35545 "beforeremove" : true,
35547 * @event invalidated
35548 * Fires when the layout for this region is changed.
35549 * @param {Roo.LayoutRegion} this
35551 "invalidated" : true,
35553 * @event visibilitychange
35554 * Fires when this region is shown or hidden
35555 * @param {Roo.LayoutRegion} this
35556 * @param {Boolean} visibility true or false
35558 "visibilitychange" : true,
35560 * @event paneladded
35561 * Fires when a panel is added.
35562 * @param {Roo.LayoutRegion} this
35563 * @param {Roo.ContentPanel} panel The panel
35565 "paneladded" : true,
35567 * @event panelremoved
35568 * Fires when a panel is removed.
35569 * @param {Roo.LayoutRegion} this
35570 * @param {Roo.ContentPanel} panel The panel
35572 "panelremoved" : true,
35574 * @event beforecollapse
35575 * Fires when this region before collapse.
35576 * @param {Roo.LayoutRegion} this
35578 "beforecollapse" : true,
35581 * Fires when this region is collapsed.
35582 * @param {Roo.LayoutRegion} this
35584 "collapsed" : true,
35587 * Fires when this region is expanded.
35588 * @param {Roo.LayoutRegion} this
35593 * Fires when this region is slid into view.
35594 * @param {Roo.LayoutRegion} this
35596 "slideshow" : true,
35599 * Fires when this region slides out of view.
35600 * @param {Roo.LayoutRegion} this
35602 "slidehide" : true,
35604 * @event panelactivated
35605 * Fires when a panel is activated.
35606 * @param {Roo.LayoutRegion} this
35607 * @param {Roo.ContentPanel} panel The activated panel
35609 "panelactivated" : true,
35612 * Fires when the user resizes this region.
35613 * @param {Roo.LayoutRegion} this
35614 * @param {Number} newSize The new size (width for east/west, height for north/south)
35618 /** A collection of panels in this region. @type Roo.util.MixedCollection */
35619 this.panels = new Roo.util.MixedCollection();
35620 this.panels.getKey = this.getPanelId.createDelegate(this);
35622 this.activePanel = null;
35623 // ensure listeners are added...
35625 if (config.listeners || config.events) {
35626 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
35627 listeners : config.listeners || {},
35628 events : config.events || {}
35632 if(skipConfig !== true){
35633 this.applyConfig(config);
35637 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
35639 getPanelId : function(p){
35643 applyConfig : function(config){
35644 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35645 this.config = config;
35650 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
35651 * the width, for horizontal (north, south) the height.
35652 * @param {Number} newSize The new width or height
35654 resizeTo : function(newSize){
35655 var el = this.el ? this.el :
35656 (this.activePanel ? this.activePanel.getEl() : null);
35658 switch(this.position){
35661 el.setWidth(newSize);
35662 this.fireEvent("resized", this, newSize);
35666 el.setHeight(newSize);
35667 this.fireEvent("resized", this, newSize);
35673 getBox : function(){
35674 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
35677 getMargins : function(){
35678 return this.margins;
35681 updateBox : function(box){
35683 var el = this.activePanel.getEl();
35684 el.dom.style.left = box.x + "px";
35685 el.dom.style.top = box.y + "px";
35686 this.activePanel.setSize(box.width, box.height);
35690 * Returns the container element for this region.
35691 * @return {Roo.Element}
35693 getEl : function(){
35694 return this.activePanel;
35698 * Returns true if this region is currently visible.
35699 * @return {Boolean}
35701 isVisible : function(){
35702 return this.activePanel ? true : false;
35705 setActivePanel : function(panel){
35706 panel = this.getPanel(panel);
35707 if(this.activePanel && this.activePanel != panel){
35708 this.activePanel.setActiveState(false);
35709 this.activePanel.getEl().setLeftTop(-10000,-10000);
35711 this.activePanel = panel;
35712 panel.setActiveState(true);
35714 panel.setSize(this.box.width, this.box.height);
35716 this.fireEvent("panelactivated", this, panel);
35717 this.fireEvent("invalidated");
35721 * Show the specified panel.
35722 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
35723 * @return {Roo.ContentPanel} The shown panel or null
35725 showPanel : function(panel){
35726 panel = this.getPanel(panel);
35728 this.setActivePanel(panel);
35734 * Get the active panel for this region.
35735 * @return {Roo.ContentPanel} The active panel or null
35737 getActivePanel : function(){
35738 return this.activePanel;
35742 * Add the passed ContentPanel(s)
35743 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35744 * @return {Roo.ContentPanel} The panel added (if only one was added)
35746 add : function(panel){
35747 if(arguments.length > 1){
35748 for(var i = 0, len = arguments.length; i < len; i++) {
35749 this.add(arguments[i]);
35753 if(this.hasPanel(panel)){
35754 this.showPanel(panel);
35757 var el = panel.getEl();
35758 if(el.dom.parentNode != this.mgr.el.dom){
35759 this.mgr.el.dom.appendChild(el.dom);
35761 if(panel.setRegion){
35762 panel.setRegion(this);
35764 this.panels.add(panel);
35765 el.setStyle("position", "absolute");
35766 if(!panel.background){
35767 this.setActivePanel(panel);
35768 if(this.config.initialSize && this.panels.getCount()==1){
35769 this.resizeTo(this.config.initialSize);
35772 this.fireEvent("paneladded", this, panel);
35777 * Returns true if the panel is in this region.
35778 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35779 * @return {Boolean}
35781 hasPanel : function(panel){
35782 if(typeof panel == "object"){ // must be panel obj
35783 panel = panel.getId();
35785 return this.getPanel(panel) ? true : false;
35789 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35790 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35791 * @param {Boolean} preservePanel Overrides the config preservePanel option
35792 * @return {Roo.ContentPanel} The panel that was removed
35794 remove : function(panel, preservePanel){
35795 panel = this.getPanel(panel);
35800 this.fireEvent("beforeremove", this, panel, e);
35801 if(e.cancel === true){
35804 var panelId = panel.getId();
35805 this.panels.removeKey(panelId);
35810 * Returns the panel specified or null if it's not in this region.
35811 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35812 * @return {Roo.ContentPanel}
35814 getPanel : function(id){
35815 if(typeof id == "object"){ // must be panel obj
35818 return this.panels.get(id);
35822 * Returns this regions position (north/south/east/west/center).
35825 getPosition: function(){
35826 return this.position;
35830 * Ext JS Library 1.1.1
35831 * Copyright(c) 2006-2007, Ext JS, LLC.
35833 * Originally Released Under LGPL - original licence link has changed is not relivant.
35836 * <script type="text/javascript">
35840 * @class Roo.bootstrap.layout.Region
35841 * @extends Roo.bootstrap.layout.Basic
35842 * This class represents a region in a layout manager.
35844 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
35845 * @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})
35846 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
35847 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
35848 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
35849 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
35850 * @cfg {String} title The title for the region (overrides panel titles)
35851 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
35852 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
35853 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
35854 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
35855 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
35856 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
35857 * the space available, similar to FireFox 1.5 tabs (defaults to false)
35858 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
35859 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
35860 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
35862 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
35863 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
35864 * @cfg {Boolean} disableTabTips True to disable tab tooltips
35865 * @cfg {Number} width For East/West panels
35866 * @cfg {Number} height For North/South panels
35867 * @cfg {Boolean} split To show the splitter
35868 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
35870 * @cfg {string} cls Extra CSS classes to add to region
35872 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35873 * @cfg {string} region the region that it inhabits..
35876 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
35877 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
35879 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
35880 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
35881 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
35883 Roo.bootstrap.layout.Region = function(config)
35885 this.applyConfig(config);
35887 var mgr = config.mgr;
35888 var pos = config.region;
35889 config.skipConfig = true;
35890 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
35893 this.onRender(mgr.el);
35896 this.visible = true;
35897 this.collapsed = false;
35898 this.unrendered_panels = [];
35901 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
35903 position: '', // set by wrapper (eg. north/south etc..)
35904 unrendered_panels : null, // unrendered panels.
35905 createBody : function(){
35906 /** This region's body element
35907 * @type Roo.Element */
35908 this.bodyEl = this.el.createChild({
35910 cls: "roo-layout-panel-body tab-content" // bootstrap added...
35914 onRender: function(ctr, pos)
35916 var dh = Roo.DomHelper;
35917 /** This region's container element
35918 * @type Roo.Element */
35919 this.el = dh.append(ctr.dom, {
35921 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
35923 /** This region's title element
35924 * @type Roo.Element */
35926 this.titleEl = dh.append(this.el.dom,
35929 unselectable: "on",
35930 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
35932 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
35933 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
35936 this.titleEl.enableDisplayMode();
35937 /** This region's title text element
35938 * @type HTMLElement */
35939 this.titleTextEl = this.titleEl.dom.firstChild;
35940 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
35942 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
35943 this.closeBtn.enableDisplayMode();
35944 this.closeBtn.on("click", this.closeClicked, this);
35945 this.closeBtn.hide();
35947 this.createBody(this.config);
35948 if(this.config.hideWhenEmpty){
35950 this.on("paneladded", this.validateVisibility, this);
35951 this.on("panelremoved", this.validateVisibility, this);
35953 if(this.autoScroll){
35954 this.bodyEl.setStyle("overflow", "auto");
35956 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
35958 //if(c.titlebar !== false){
35959 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
35960 this.titleEl.hide();
35962 this.titleEl.show();
35963 if(this.config.title){
35964 this.titleTextEl.innerHTML = this.config.title;
35968 if(this.config.collapsed){
35969 this.collapse(true);
35971 if(this.config.hidden){
35975 if (this.unrendered_panels && this.unrendered_panels.length) {
35976 for (var i =0;i< this.unrendered_panels.length; i++) {
35977 this.add(this.unrendered_panels[i]);
35979 this.unrendered_panels = null;
35985 applyConfig : function(c)
35988 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
35989 var dh = Roo.DomHelper;
35990 if(c.titlebar !== false){
35991 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
35992 this.collapseBtn.on("click", this.collapse, this);
35993 this.collapseBtn.enableDisplayMode();
35995 if(c.showPin === true || this.showPin){
35996 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
35997 this.stickBtn.enableDisplayMode();
35998 this.stickBtn.on("click", this.expand, this);
35999 this.stickBtn.hide();
36004 /** This region's collapsed element
36005 * @type Roo.Element */
36008 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
36009 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
36012 if(c.floatable !== false){
36013 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
36014 this.collapsedEl.on("click", this.collapseClick, this);
36017 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
36018 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
36019 id: "message", unselectable: "on", style:{"float":"left"}});
36020 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
36022 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
36023 this.expandBtn.on("click", this.expand, this);
36027 if(this.collapseBtn){
36028 this.collapseBtn.setVisible(c.collapsible == true);
36031 this.cmargins = c.cmargins || this.cmargins ||
36032 (this.position == "west" || this.position == "east" ?
36033 {top: 0, left: 2, right:2, bottom: 0} :
36034 {top: 2, left: 0, right:0, bottom: 2});
36036 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
36039 this.bottomTabs = c.tabPosition != "top";
36041 this.autoScroll = c.autoScroll || false;
36046 this.duration = c.duration || .30;
36047 this.slideDuration = c.slideDuration || .45;
36052 * Returns true if this region is currently visible.
36053 * @return {Boolean}
36055 isVisible : function(){
36056 return this.visible;
36060 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
36061 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
36063 //setCollapsedTitle : function(title){
36064 // title = title || " ";
36065 // if(this.collapsedTitleTextEl){
36066 // this.collapsedTitleTextEl.innerHTML = title;
36070 getBox : function(){
36072 // if(!this.collapsed){
36073 b = this.el.getBox(false, true);
36075 // b = this.collapsedEl.getBox(false, true);
36080 getMargins : function(){
36081 return this.margins;
36082 //return this.collapsed ? this.cmargins : this.margins;
36085 highlight : function(){
36086 this.el.addClass("x-layout-panel-dragover");
36089 unhighlight : function(){
36090 this.el.removeClass("x-layout-panel-dragover");
36093 updateBox : function(box)
36095 if (!this.bodyEl) {
36096 return; // not rendered yet..
36100 if(!this.collapsed){
36101 this.el.dom.style.left = box.x + "px";
36102 this.el.dom.style.top = box.y + "px";
36103 this.updateBody(box.width, box.height);
36105 this.collapsedEl.dom.style.left = box.x + "px";
36106 this.collapsedEl.dom.style.top = box.y + "px";
36107 this.collapsedEl.setSize(box.width, box.height);
36110 this.tabs.autoSizeTabs();
36114 updateBody : function(w, h)
36117 this.el.setWidth(w);
36118 w -= this.el.getBorderWidth("rl");
36119 if(this.config.adjustments){
36120 w += this.config.adjustments[0];
36123 if(h !== null && h > 0){
36124 this.el.setHeight(h);
36125 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
36126 h -= this.el.getBorderWidth("tb");
36127 if(this.config.adjustments){
36128 h += this.config.adjustments[1];
36130 this.bodyEl.setHeight(h);
36132 h = this.tabs.syncHeight(h);
36135 if(this.panelSize){
36136 w = w !== null ? w : this.panelSize.width;
36137 h = h !== null ? h : this.panelSize.height;
36139 if(this.activePanel){
36140 var el = this.activePanel.getEl();
36141 w = w !== null ? w : el.getWidth();
36142 h = h !== null ? h : el.getHeight();
36143 this.panelSize = {width: w, height: h};
36144 this.activePanel.setSize(w, h);
36146 if(Roo.isIE && this.tabs){
36147 this.tabs.el.repaint();
36152 * Returns the container element for this region.
36153 * @return {Roo.Element}
36155 getEl : function(){
36160 * Hides this region.
36163 //if(!this.collapsed){
36164 this.el.dom.style.left = "-2000px";
36167 // this.collapsedEl.dom.style.left = "-2000px";
36168 // this.collapsedEl.hide();
36170 this.visible = false;
36171 this.fireEvent("visibilitychange", this, false);
36175 * Shows this region if it was previously hidden.
36178 //if(!this.collapsed){
36181 // this.collapsedEl.show();
36183 this.visible = true;
36184 this.fireEvent("visibilitychange", this, true);
36187 closeClicked : function(){
36188 if(this.activePanel){
36189 this.remove(this.activePanel);
36193 collapseClick : function(e){
36195 e.stopPropagation();
36198 e.stopPropagation();
36204 * Collapses this region.
36205 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
36208 collapse : function(skipAnim, skipCheck = false){
36209 if(this.collapsed) {
36213 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
36215 this.collapsed = true;
36217 this.split.el.hide();
36219 if(this.config.animate && skipAnim !== true){
36220 this.fireEvent("invalidated", this);
36221 this.animateCollapse();
36223 this.el.setLocation(-20000,-20000);
36225 this.collapsedEl.show();
36226 this.fireEvent("collapsed", this);
36227 this.fireEvent("invalidated", this);
36233 animateCollapse : function(){
36238 * Expands this region if it was previously collapsed.
36239 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
36240 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
36243 expand : function(e, skipAnim){
36245 e.stopPropagation();
36247 if(!this.collapsed || this.el.hasActiveFx()) {
36251 this.afterSlideIn();
36254 this.collapsed = false;
36255 if(this.config.animate && skipAnim !== true){
36256 this.animateExpand();
36260 this.split.el.show();
36262 this.collapsedEl.setLocation(-2000,-2000);
36263 this.collapsedEl.hide();
36264 this.fireEvent("invalidated", this);
36265 this.fireEvent("expanded", this);
36269 animateExpand : function(){
36273 initTabs : function()
36275 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
36277 var ts = new Roo.bootstrap.panel.Tabs({
36278 el: this.bodyEl.dom,
36279 tabPosition: this.bottomTabs ? 'bottom' : 'top',
36280 disableTooltips: this.config.disableTabTips,
36281 toolbar : this.config.toolbar
36284 if(this.config.hideTabs){
36285 ts.stripWrap.setDisplayed(false);
36288 ts.resizeTabs = this.config.resizeTabs === true;
36289 ts.minTabWidth = this.config.minTabWidth || 40;
36290 ts.maxTabWidth = this.config.maxTabWidth || 250;
36291 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
36292 ts.monitorResize = false;
36293 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
36294 ts.bodyEl.addClass('roo-layout-tabs-body');
36295 this.panels.each(this.initPanelAsTab, this);
36298 initPanelAsTab : function(panel){
36299 var ti = this.tabs.addTab(
36303 this.config.closeOnTab && panel.isClosable(),
36306 if(panel.tabTip !== undefined){
36307 ti.setTooltip(panel.tabTip);
36309 ti.on("activate", function(){
36310 this.setActivePanel(panel);
36313 if(this.config.closeOnTab){
36314 ti.on("beforeclose", function(t, e){
36316 this.remove(panel);
36320 panel.tabItem = ti;
36325 updatePanelTitle : function(panel, title)
36327 if(this.activePanel == panel){
36328 this.updateTitle(title);
36331 var ti = this.tabs.getTab(panel.getEl().id);
36333 if(panel.tabTip !== undefined){
36334 ti.setTooltip(panel.tabTip);
36339 updateTitle : function(title){
36340 if(this.titleTextEl && !this.config.title){
36341 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
36345 setActivePanel : function(panel)
36347 panel = this.getPanel(panel);
36348 if(this.activePanel && this.activePanel != panel){
36349 if(this.activePanel.setActiveState(false) === false){
36353 this.activePanel = panel;
36354 panel.setActiveState(true);
36355 if(this.panelSize){
36356 panel.setSize(this.panelSize.width, this.panelSize.height);
36359 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
36361 this.updateTitle(panel.getTitle());
36363 this.fireEvent("invalidated", this);
36365 this.fireEvent("panelactivated", this, panel);
36369 * Shows the specified panel.
36370 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
36371 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
36373 showPanel : function(panel)
36375 panel = this.getPanel(panel);
36378 var tab = this.tabs.getTab(panel.getEl().id);
36379 if(tab.isHidden()){
36380 this.tabs.unhideTab(tab.id);
36384 this.setActivePanel(panel);
36391 * Get the active panel for this region.
36392 * @return {Roo.ContentPanel} The active panel or null
36394 getActivePanel : function(){
36395 return this.activePanel;
36398 validateVisibility : function(){
36399 if(this.panels.getCount() < 1){
36400 this.updateTitle(" ");
36401 this.closeBtn.hide();
36404 if(!this.isVisible()){
36411 * Adds the passed ContentPanel(s) to this region.
36412 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
36413 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
36415 add : function(panel)
36417 if(arguments.length > 1){
36418 for(var i = 0, len = arguments.length; i < len; i++) {
36419 this.add(arguments[i]);
36424 // if we have not been rendered yet, then we can not really do much of this..
36425 if (!this.bodyEl) {
36426 this.unrendered_panels.push(panel);
36433 if(this.hasPanel(panel)){
36434 this.showPanel(panel);
36437 panel.setRegion(this);
36438 this.panels.add(panel);
36439 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
36440 // sinle panel - no tab...?? would it not be better to render it with the tabs,
36441 // and hide them... ???
36442 this.bodyEl.dom.appendChild(panel.getEl().dom);
36443 if(panel.background !== true){
36444 this.setActivePanel(panel);
36446 this.fireEvent("paneladded", this, panel);
36453 this.initPanelAsTab(panel);
36457 if(panel.background !== true){
36458 this.tabs.activate(panel.getEl().id);
36460 this.fireEvent("paneladded", this, panel);
36465 * Hides the tab for the specified panel.
36466 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36468 hidePanel : function(panel){
36469 if(this.tabs && (panel = this.getPanel(panel))){
36470 this.tabs.hideTab(panel.getEl().id);
36475 * Unhides the tab for a previously hidden panel.
36476 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36478 unhidePanel : function(panel){
36479 if(this.tabs && (panel = this.getPanel(panel))){
36480 this.tabs.unhideTab(panel.getEl().id);
36484 clearPanels : function(){
36485 while(this.panels.getCount() > 0){
36486 this.remove(this.panels.first());
36491 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
36492 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36493 * @param {Boolean} preservePanel Overrides the config preservePanel option
36494 * @return {Roo.ContentPanel} The panel that was removed
36496 remove : function(panel, preservePanel)
36498 panel = this.getPanel(panel);
36503 this.fireEvent("beforeremove", this, panel, e);
36504 if(e.cancel === true){
36507 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
36508 var panelId = panel.getId();
36509 this.panels.removeKey(panelId);
36511 document.body.appendChild(panel.getEl().dom);
36514 this.tabs.removeTab(panel.getEl().id);
36515 }else if (!preservePanel){
36516 this.bodyEl.dom.removeChild(panel.getEl().dom);
36518 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
36519 var p = this.panels.first();
36520 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
36521 tempEl.appendChild(p.getEl().dom);
36522 this.bodyEl.update("");
36523 this.bodyEl.dom.appendChild(p.getEl().dom);
36525 this.updateTitle(p.getTitle());
36527 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
36528 this.setActivePanel(p);
36530 panel.setRegion(null);
36531 if(this.activePanel == panel){
36532 this.activePanel = null;
36534 if(this.config.autoDestroy !== false && preservePanel !== true){
36535 try{panel.destroy();}catch(e){}
36537 this.fireEvent("panelremoved", this, panel);
36542 * Returns the TabPanel component used by this region
36543 * @return {Roo.TabPanel}
36545 getTabs : function(){
36549 createTool : function(parentEl, className){
36550 var btn = Roo.DomHelper.append(parentEl, {
36552 cls: "x-layout-tools-button",
36555 cls: "roo-layout-tools-button-inner " + className,
36559 btn.addClassOnOver("roo-layout-tools-button-over");
36564 * Ext JS Library 1.1.1
36565 * Copyright(c) 2006-2007, Ext JS, LLC.
36567 * Originally Released Under LGPL - original licence link has changed is not relivant.
36570 * <script type="text/javascript">
36576 * @class Roo.SplitLayoutRegion
36577 * @extends Roo.LayoutRegion
36578 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
36580 Roo.bootstrap.layout.Split = function(config){
36581 this.cursor = config.cursor;
36582 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
36585 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
36587 splitTip : "Drag to resize.",
36588 collapsibleSplitTip : "Drag to resize. Double click to hide.",
36589 useSplitTips : false,
36591 applyConfig : function(config){
36592 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
36595 onRender : function(ctr,pos) {
36597 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
36598 if(!this.config.split){
36603 var splitEl = Roo.DomHelper.append(ctr.dom, {
36605 id: this.el.id + "-split",
36606 cls: "roo-layout-split roo-layout-split-"+this.position,
36609 /** The SplitBar for this region
36610 * @type Roo.SplitBar */
36611 // does not exist yet...
36612 Roo.log([this.position, this.orientation]);
36614 this.split = new Roo.bootstrap.SplitBar({
36615 dragElement : splitEl,
36616 resizingElement: this.el,
36617 orientation : this.orientation
36620 this.split.on("moved", this.onSplitMove, this);
36621 this.split.useShim = this.config.useShim === true;
36622 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
36623 if(this.useSplitTips){
36624 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
36626 //if(config.collapsible){
36627 // this.split.el.on("dblclick", this.collapse, this);
36630 if(typeof this.config.minSize != "undefined"){
36631 this.split.minSize = this.config.minSize;
36633 if(typeof this.config.maxSize != "undefined"){
36634 this.split.maxSize = this.config.maxSize;
36636 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
36637 this.hideSplitter();
36642 getHMaxSize : function(){
36643 var cmax = this.config.maxSize || 10000;
36644 var center = this.mgr.getRegion("center");
36645 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
36648 getVMaxSize : function(){
36649 var cmax = this.config.maxSize || 10000;
36650 var center = this.mgr.getRegion("center");
36651 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
36654 onSplitMove : function(split, newSize){
36655 this.fireEvent("resized", this, newSize);
36659 * Returns the {@link Roo.SplitBar} for this region.
36660 * @return {Roo.SplitBar}
36662 getSplitBar : function(){
36667 this.hideSplitter();
36668 Roo.bootstrap.layout.Split.superclass.hide.call(this);
36671 hideSplitter : function(){
36673 this.split.el.setLocation(-2000,-2000);
36674 this.split.el.hide();
36680 this.split.el.show();
36682 Roo.bootstrap.layout.Split.superclass.show.call(this);
36685 beforeSlide: function(){
36686 if(Roo.isGecko){// firefox overflow auto bug workaround
36687 this.bodyEl.clip();
36689 this.tabs.bodyEl.clip();
36691 if(this.activePanel){
36692 this.activePanel.getEl().clip();
36694 if(this.activePanel.beforeSlide){
36695 this.activePanel.beforeSlide();
36701 afterSlide : function(){
36702 if(Roo.isGecko){// firefox overflow auto bug workaround
36703 this.bodyEl.unclip();
36705 this.tabs.bodyEl.unclip();
36707 if(this.activePanel){
36708 this.activePanel.getEl().unclip();
36709 if(this.activePanel.afterSlide){
36710 this.activePanel.afterSlide();
36716 initAutoHide : function(){
36717 if(this.autoHide !== false){
36718 if(!this.autoHideHd){
36719 var st = new Roo.util.DelayedTask(this.slideIn, this);
36720 this.autoHideHd = {
36721 "mouseout": function(e){
36722 if(!e.within(this.el, true)){
36726 "mouseover" : function(e){
36732 this.el.on(this.autoHideHd);
36736 clearAutoHide : function(){
36737 if(this.autoHide !== false){
36738 this.el.un("mouseout", this.autoHideHd.mouseout);
36739 this.el.un("mouseover", this.autoHideHd.mouseover);
36743 clearMonitor : function(){
36744 Roo.get(document).un("click", this.slideInIf, this);
36747 // these names are backwards but not changed for compat
36748 slideOut : function(){
36749 if(this.isSlid || this.el.hasActiveFx()){
36752 this.isSlid = true;
36753 if(this.collapseBtn){
36754 this.collapseBtn.hide();
36756 this.closeBtnState = this.closeBtn.getStyle('display');
36757 this.closeBtn.hide();
36759 this.stickBtn.show();
36762 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
36763 this.beforeSlide();
36764 this.el.setStyle("z-index", 10001);
36765 this.el.slideIn(this.getSlideAnchor(), {
36766 callback: function(){
36768 this.initAutoHide();
36769 Roo.get(document).on("click", this.slideInIf, this);
36770 this.fireEvent("slideshow", this);
36777 afterSlideIn : function(){
36778 this.clearAutoHide();
36779 this.isSlid = false;
36780 this.clearMonitor();
36781 this.el.setStyle("z-index", "");
36782 if(this.collapseBtn){
36783 this.collapseBtn.show();
36785 this.closeBtn.setStyle('display', this.closeBtnState);
36787 this.stickBtn.hide();
36789 this.fireEvent("slidehide", this);
36792 slideIn : function(cb){
36793 if(!this.isSlid || this.el.hasActiveFx()){
36797 this.isSlid = false;
36798 this.beforeSlide();
36799 this.el.slideOut(this.getSlideAnchor(), {
36800 callback: function(){
36801 this.el.setLeftTop(-10000, -10000);
36803 this.afterSlideIn();
36811 slideInIf : function(e){
36812 if(!e.within(this.el)){
36817 animateCollapse : function(){
36818 this.beforeSlide();
36819 this.el.setStyle("z-index", 20000);
36820 var anchor = this.getSlideAnchor();
36821 this.el.slideOut(anchor, {
36822 callback : function(){
36823 this.el.setStyle("z-index", "");
36824 this.collapsedEl.slideIn(anchor, {duration:.3});
36826 this.el.setLocation(-10000,-10000);
36828 this.fireEvent("collapsed", this);
36835 animateExpand : function(){
36836 this.beforeSlide();
36837 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
36838 this.el.setStyle("z-index", 20000);
36839 this.collapsedEl.hide({
36842 this.el.slideIn(this.getSlideAnchor(), {
36843 callback : function(){
36844 this.el.setStyle("z-index", "");
36847 this.split.el.show();
36849 this.fireEvent("invalidated", this);
36850 this.fireEvent("expanded", this);
36878 getAnchor : function(){
36879 return this.anchors[this.position];
36882 getCollapseAnchor : function(){
36883 return this.canchors[this.position];
36886 getSlideAnchor : function(){
36887 return this.sanchors[this.position];
36890 getAlignAdj : function(){
36891 var cm = this.cmargins;
36892 switch(this.position){
36908 getExpandAdj : function(){
36909 var c = this.collapsedEl, cm = this.cmargins;
36910 switch(this.position){
36912 return [-(cm.right+c.getWidth()+cm.left), 0];
36915 return [cm.right+c.getWidth()+cm.left, 0];
36918 return [0, -(cm.top+cm.bottom+c.getHeight())];
36921 return [0, cm.top+cm.bottom+c.getHeight()];
36927 * Ext JS Library 1.1.1
36928 * Copyright(c) 2006-2007, Ext JS, LLC.
36930 * Originally Released Under LGPL - original licence link has changed is not relivant.
36933 * <script type="text/javascript">
36936 * These classes are private internal classes
36938 Roo.bootstrap.layout.Center = function(config){
36939 config.region = "center";
36940 Roo.bootstrap.layout.Region.call(this, config);
36941 this.visible = true;
36942 this.minWidth = config.minWidth || 20;
36943 this.minHeight = config.minHeight || 20;
36946 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
36948 // center panel can't be hidden
36952 // center panel can't be hidden
36955 getMinWidth: function(){
36956 return this.minWidth;
36959 getMinHeight: function(){
36960 return this.minHeight;
36973 Roo.bootstrap.layout.North = function(config)
36975 config.region = 'north';
36976 config.cursor = 'n-resize';
36978 Roo.bootstrap.layout.Split.call(this, config);
36982 this.split.placement = Roo.bootstrap.SplitBar.TOP;
36983 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36984 this.split.el.addClass("roo-layout-split-v");
36986 var size = config.initialSize || config.height;
36987 if(typeof size != "undefined"){
36988 this.el.setHeight(size);
36991 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
36993 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36997 getBox : function(){
36998 if(this.collapsed){
36999 return this.collapsedEl.getBox();
37001 var box = this.el.getBox();
37003 box.height += this.split.el.getHeight();
37008 updateBox : function(box){
37009 if(this.split && !this.collapsed){
37010 box.height -= this.split.el.getHeight();
37011 this.split.el.setLeft(box.x);
37012 this.split.el.setTop(box.y+box.height);
37013 this.split.el.setWidth(box.width);
37015 if(this.collapsed){
37016 this.updateBody(box.width, null);
37018 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37026 Roo.bootstrap.layout.South = function(config){
37027 config.region = 'south';
37028 config.cursor = 's-resize';
37029 Roo.bootstrap.layout.Split.call(this, config);
37031 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
37032 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
37033 this.split.el.addClass("roo-layout-split-v");
37035 var size = config.initialSize || config.height;
37036 if(typeof size != "undefined"){
37037 this.el.setHeight(size);
37041 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
37042 orientation: Roo.bootstrap.SplitBar.VERTICAL,
37043 getBox : function(){
37044 if(this.collapsed){
37045 return this.collapsedEl.getBox();
37047 var box = this.el.getBox();
37049 var sh = this.split.el.getHeight();
37056 updateBox : function(box){
37057 if(this.split && !this.collapsed){
37058 var sh = this.split.el.getHeight();
37061 this.split.el.setLeft(box.x);
37062 this.split.el.setTop(box.y-sh);
37063 this.split.el.setWidth(box.width);
37065 if(this.collapsed){
37066 this.updateBody(box.width, null);
37068 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37072 Roo.bootstrap.layout.East = function(config){
37073 config.region = "east";
37074 config.cursor = "e-resize";
37075 Roo.bootstrap.layout.Split.call(this, config);
37077 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
37078 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
37079 this.split.el.addClass("roo-layout-split-h");
37081 var size = config.initialSize || config.width;
37082 if(typeof size != "undefined"){
37083 this.el.setWidth(size);
37086 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
37087 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
37088 getBox : function(){
37089 if(this.collapsed){
37090 return this.collapsedEl.getBox();
37092 var box = this.el.getBox();
37094 var sw = this.split.el.getWidth();
37101 updateBox : function(box){
37102 if(this.split && !this.collapsed){
37103 var sw = this.split.el.getWidth();
37105 this.split.el.setLeft(box.x);
37106 this.split.el.setTop(box.y);
37107 this.split.el.setHeight(box.height);
37110 if(this.collapsed){
37111 this.updateBody(null, box.height);
37113 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37117 Roo.bootstrap.layout.West = function(config){
37118 config.region = "west";
37119 config.cursor = "w-resize";
37121 Roo.bootstrap.layout.Split.call(this, config);
37123 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
37124 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
37125 this.split.el.addClass("roo-layout-split-h");
37129 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
37130 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
37132 onRender: function(ctr, pos)
37134 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
37135 var size = this.config.initialSize || this.config.width;
37136 if(typeof size != "undefined"){
37137 this.el.setWidth(size);
37141 getBox : function(){
37142 if(this.collapsed){
37143 return this.collapsedEl.getBox();
37145 var box = this.el.getBox();
37147 box.width += this.split.el.getWidth();
37152 updateBox : function(box){
37153 if(this.split && !this.collapsed){
37154 var sw = this.split.el.getWidth();
37156 this.split.el.setLeft(box.x+box.width);
37157 this.split.el.setTop(box.y);
37158 this.split.el.setHeight(box.height);
37160 if(this.collapsed){
37161 this.updateBody(null, box.height);
37163 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37166 Roo.namespace("Roo.bootstrap.panel");/*
37168 * Ext JS Library 1.1.1
37169 * Copyright(c) 2006-2007, Ext JS, LLC.
37171 * Originally Released Under LGPL - original licence link has changed is not relivant.
37174 * <script type="text/javascript">
37177 * @class Roo.ContentPanel
37178 * @extends Roo.util.Observable
37179 * A basic ContentPanel element.
37180 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
37181 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
37182 * @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
37183 * @cfg {Boolean} closable True if the panel can be closed/removed
37184 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
37185 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
37186 * @cfg {Toolbar} toolbar A toolbar for this panel
37187 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
37188 * @cfg {String} title The title for this panel
37189 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
37190 * @cfg {String} url Calls {@link #setUrl} with this value
37191 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
37192 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
37193 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
37194 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
37195 * @cfg {Boolean} badges render the badges
37198 * Create a new ContentPanel.
37199 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
37200 * @param {String/Object} config A string to set only the title or a config object
37201 * @param {String} content (optional) Set the HTML content for this panel
37202 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
37204 Roo.bootstrap.panel.Content = function( config){
37206 this.tpl = config.tpl || false;
37208 var el = config.el;
37209 var content = config.content;
37211 if(config.autoCreate){ // xtype is available if this is called from factory
37214 this.el = Roo.get(el);
37215 if(!this.el && config && config.autoCreate){
37216 if(typeof config.autoCreate == "object"){
37217 if(!config.autoCreate.id){
37218 config.autoCreate.id = config.id||el;
37220 this.el = Roo.DomHelper.append(document.body,
37221 config.autoCreate, true);
37223 var elcfg = { tag: "div",
37224 cls: "roo-layout-inactive-content",
37228 elcfg.html = config.html;
37232 this.el = Roo.DomHelper.append(document.body, elcfg , true);
37235 this.closable = false;
37236 this.loaded = false;
37237 this.active = false;
37240 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
37242 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
37244 this.wrapEl = this.el; //this.el.wrap();
37246 if (config.toolbar.items) {
37247 ti = config.toolbar.items ;
37248 delete config.toolbar.items ;
37252 this.toolbar.render(this.wrapEl, 'before');
37253 for(var i =0;i < ti.length;i++) {
37254 // Roo.log(['add child', items[i]]);
37255 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37257 this.toolbar.items = nitems;
37258 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
37259 delete config.toolbar;
37263 // xtype created footer. - not sure if will work as we normally have to render first..
37264 if (this.footer && !this.footer.el && this.footer.xtype) {
37265 if (!this.wrapEl) {
37266 this.wrapEl = this.el.wrap();
37269 this.footer.container = this.wrapEl.createChild();
37271 this.footer = Roo.factory(this.footer, Roo);
37276 if(typeof config == "string"){
37277 this.title = config;
37279 Roo.apply(this, config);
37283 this.resizeEl = Roo.get(this.resizeEl, true);
37285 this.resizeEl = this.el;
37287 // handle view.xtype
37295 * Fires when this panel is activated.
37296 * @param {Roo.ContentPanel} this
37300 * @event deactivate
37301 * Fires when this panel is activated.
37302 * @param {Roo.ContentPanel} this
37304 "deactivate" : true,
37308 * Fires when this panel is resized if fitToFrame is true.
37309 * @param {Roo.ContentPanel} this
37310 * @param {Number} width The width after any component adjustments
37311 * @param {Number} height The height after any component adjustments
37317 * Fires when this tab is created
37318 * @param {Roo.ContentPanel} this
37329 if(this.autoScroll){
37330 this.resizeEl.setStyle("overflow", "auto");
37332 // fix randome scrolling
37333 //this.el.on('scroll', function() {
37334 // Roo.log('fix random scolling');
37335 // this.scrollTo('top',0);
37338 content = content || this.content;
37340 this.setContent(content);
37342 if(config && config.url){
37343 this.setUrl(this.url, this.params, this.loadOnce);
37348 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
37350 if (this.view && typeof(this.view.xtype) != 'undefined') {
37351 this.view.el = this.el.appendChild(document.createElement("div"));
37352 this.view = Roo.factory(this.view);
37353 this.view.render && this.view.render(false, '');
37357 this.fireEvent('render', this);
37360 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
37364 setRegion : function(region){
37365 this.region = region;
37366 this.setActiveClass(region && !this.background);
37370 setActiveClass: function(state)
37373 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
37374 this.el.setStyle('position','relative');
37376 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
37377 this.el.setStyle('position', 'absolute');
37382 * Returns the toolbar for this Panel if one was configured.
37383 * @return {Roo.Toolbar}
37385 getToolbar : function(){
37386 return this.toolbar;
37389 setActiveState : function(active)
37391 this.active = active;
37392 this.setActiveClass(active);
37394 if(this.fireEvent("deactivate", this) === false){
37399 this.fireEvent("activate", this);
37403 * Updates this panel's element
37404 * @param {String} content The new content
37405 * @param {Boolean} loadScripts (optional) true to look for and process scripts
37407 setContent : function(content, loadScripts){
37408 this.el.update(content, loadScripts);
37411 ignoreResize : function(w, h){
37412 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
37415 this.lastSize = {width: w, height: h};
37420 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
37421 * @return {Roo.UpdateManager} The UpdateManager
37423 getUpdateManager : function(){
37424 return this.el.getUpdateManager();
37427 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
37428 * @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:
37431 url: "your-url.php",
37432 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
37433 callback: yourFunction,
37434 scope: yourObject, //(optional scope)
37437 text: "Loading...",
37442 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
37443 * 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.
37444 * @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}
37445 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
37446 * @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.
37447 * @return {Roo.ContentPanel} this
37450 var um = this.el.getUpdateManager();
37451 um.update.apply(um, arguments);
37457 * 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.
37458 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
37459 * @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)
37460 * @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)
37461 * @return {Roo.UpdateManager} The UpdateManager
37463 setUrl : function(url, params, loadOnce){
37464 if(this.refreshDelegate){
37465 this.removeListener("activate", this.refreshDelegate);
37467 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
37468 this.on("activate", this.refreshDelegate);
37469 return this.el.getUpdateManager();
37472 _handleRefresh : function(url, params, loadOnce){
37473 if(!loadOnce || !this.loaded){
37474 var updater = this.el.getUpdateManager();
37475 updater.update(url, params, this._setLoaded.createDelegate(this));
37479 _setLoaded : function(){
37480 this.loaded = true;
37484 * Returns this panel's id
37487 getId : function(){
37492 * Returns this panel's element - used by regiosn to add.
37493 * @return {Roo.Element}
37495 getEl : function(){
37496 return this.wrapEl || this.el;
37501 adjustForComponents : function(width, height)
37503 //Roo.log('adjustForComponents ');
37504 if(this.resizeEl != this.el){
37505 width -= this.el.getFrameWidth('lr');
37506 height -= this.el.getFrameWidth('tb');
37509 var te = this.toolbar.getEl();
37510 te.setWidth(width);
37511 height -= te.getHeight();
37514 var te = this.footer.getEl();
37515 te.setWidth(width);
37516 height -= te.getHeight();
37520 if(this.adjustments){
37521 width += this.adjustments[0];
37522 height += this.adjustments[1];
37524 return {"width": width, "height": height};
37527 setSize : function(width, height){
37528 if(this.fitToFrame && !this.ignoreResize(width, height)){
37529 if(this.fitContainer && this.resizeEl != this.el){
37530 this.el.setSize(width, height);
37532 var size = this.adjustForComponents(width, height);
37533 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
37534 this.fireEvent('resize', this, size.width, size.height);
37539 * Returns this panel's title
37542 getTitle : function(){
37544 if (typeof(this.title) != 'object') {
37549 for (var k in this.title) {
37550 if (!this.title.hasOwnProperty(k)) {
37554 if (k.indexOf('-') >= 0) {
37555 var s = k.split('-');
37556 for (var i = 0; i<s.length; i++) {
37557 t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
37560 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
37567 * Set this panel's title
37568 * @param {String} title
37570 setTitle : function(title){
37571 this.title = title;
37573 this.region.updatePanelTitle(this, title);
37578 * Returns true is this panel was configured to be closable
37579 * @return {Boolean}
37581 isClosable : function(){
37582 return this.closable;
37585 beforeSlide : function(){
37587 this.resizeEl.clip();
37590 afterSlide : function(){
37592 this.resizeEl.unclip();
37596 * Force a content refresh from the URL specified in the {@link #setUrl} method.
37597 * Will fail silently if the {@link #setUrl} method has not been called.
37598 * This does not activate the panel, just updates its content.
37600 refresh : function(){
37601 if(this.refreshDelegate){
37602 this.loaded = false;
37603 this.refreshDelegate();
37608 * Destroys this panel
37610 destroy : function(){
37611 this.el.removeAllListeners();
37612 var tempEl = document.createElement("span");
37613 tempEl.appendChild(this.el.dom);
37614 tempEl.innerHTML = "";
37620 * form - if the content panel contains a form - this is a reference to it.
37621 * @type {Roo.form.Form}
37625 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
37626 * This contains a reference to it.
37632 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
37642 * @param {Object} cfg Xtype definition of item to add.
37646 getChildContainer: function () {
37647 return this.getEl();
37652 var ret = new Roo.factory(cfg);
37657 if (cfg.xtype.match(/^Form$/)) {
37660 //if (this.footer) {
37661 // el = this.footer.container.insertSibling(false, 'before');
37663 el = this.el.createChild();
37666 this.form = new Roo.form.Form(cfg);
37669 if ( this.form.allItems.length) {
37670 this.form.render(el.dom);
37674 // should only have one of theses..
37675 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
37676 // views.. should not be just added - used named prop 'view''
37678 cfg.el = this.el.appendChild(document.createElement("div"));
37681 var ret = new Roo.factory(cfg);
37683 ret.render && ret.render(false, ''); // render blank..
37693 * @class Roo.bootstrap.panel.Grid
37694 * @extends Roo.bootstrap.panel.Content
37696 * Create a new GridPanel.
37697 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
37698 * @param {Object} config A the config object
37704 Roo.bootstrap.panel.Grid = function(config)
37708 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
37709 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
37711 config.el = this.wrapper;
37712 //this.el = this.wrapper;
37714 if (config.container) {
37715 // ctor'ed from a Border/panel.grid
37718 this.wrapper.setStyle("overflow", "hidden");
37719 this.wrapper.addClass('roo-grid-container');
37724 if(config.toolbar){
37725 var tool_el = this.wrapper.createChild();
37726 this.toolbar = Roo.factory(config.toolbar);
37728 if (config.toolbar.items) {
37729 ti = config.toolbar.items ;
37730 delete config.toolbar.items ;
37734 this.toolbar.render(tool_el);
37735 for(var i =0;i < ti.length;i++) {
37736 // Roo.log(['add child', items[i]]);
37737 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37739 this.toolbar.items = nitems;
37741 delete config.toolbar;
37744 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
37745 config.grid.scrollBody = true;;
37746 config.grid.monitorWindowResize = false; // turn off autosizing
37747 config.grid.autoHeight = false;
37748 config.grid.autoWidth = false;
37750 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
37752 if (config.background) {
37753 // render grid on panel activation (if panel background)
37754 this.on('activate', function(gp) {
37755 if (!gp.grid.rendered) {
37756 gp.grid.render(this.wrapper);
37757 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37762 this.grid.render(this.wrapper);
37763 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37766 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
37767 // ??? needed ??? config.el = this.wrapper;
37772 // xtype created footer. - not sure if will work as we normally have to render first..
37773 if (this.footer && !this.footer.el && this.footer.xtype) {
37775 var ctr = this.grid.getView().getFooterPanel(true);
37776 this.footer.dataSource = this.grid.dataSource;
37777 this.footer = Roo.factory(this.footer, Roo);
37778 this.footer.render(ctr);
37788 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
37789 getId : function(){
37790 return this.grid.id;
37794 * Returns the grid for this panel
37795 * @return {Roo.bootstrap.Table}
37797 getGrid : function(){
37801 setSize : function(width, height){
37802 if(!this.ignoreResize(width, height)){
37803 var grid = this.grid;
37804 var size = this.adjustForComponents(width, height);
37805 var gridel = grid.getGridEl();
37806 gridel.setSize(size.width, size.height);
37808 var thd = grid.getGridEl().select('thead',true).first();
37809 var tbd = grid.getGridEl().select('tbody', true).first();
37811 tbd.setSize(width, height - thd.getHeight());
37820 beforeSlide : function(){
37821 this.grid.getView().scroller.clip();
37824 afterSlide : function(){
37825 this.grid.getView().scroller.unclip();
37828 destroy : function(){
37829 this.grid.destroy();
37831 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
37836 * @class Roo.bootstrap.panel.Nest
37837 * @extends Roo.bootstrap.panel.Content
37839 * Create a new Panel, that can contain a layout.Border.
37842 * @param {Roo.BorderLayout} layout The layout for this panel
37843 * @param {String/Object} config A string to set only the title or a config object
37845 Roo.bootstrap.panel.Nest = function(config)
37847 // construct with only one argument..
37848 /* FIXME - implement nicer consturctors
37849 if (layout.layout) {
37851 layout = config.layout;
37852 delete config.layout;
37854 if (layout.xtype && !layout.getEl) {
37855 // then layout needs constructing..
37856 layout = Roo.factory(layout, Roo);
37860 config.el = config.layout.getEl();
37862 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
37864 config.layout.monitorWindowResize = false; // turn off autosizing
37865 this.layout = config.layout;
37866 this.layout.getEl().addClass("roo-layout-nested-layout");
37873 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
37875 setSize : function(width, height){
37876 if(!this.ignoreResize(width, height)){
37877 var size = this.adjustForComponents(width, height);
37878 var el = this.layout.getEl();
37879 if (size.height < 1) {
37880 el.setWidth(size.width);
37882 el.setSize(size.width, size.height);
37884 var touch = el.dom.offsetWidth;
37885 this.layout.layout();
37886 // ie requires a double layout on the first pass
37887 if(Roo.isIE && !this.initialized){
37888 this.initialized = true;
37889 this.layout.layout();
37894 // activate all subpanels if not currently active..
37896 setActiveState : function(active){
37897 this.active = active;
37898 this.setActiveClass(active);
37901 this.fireEvent("deactivate", this);
37905 this.fireEvent("activate", this);
37906 // not sure if this should happen before or after..
37907 if (!this.layout) {
37908 return; // should not happen..
37911 for (var r in this.layout.regions) {
37912 reg = this.layout.getRegion(r);
37913 if (reg.getActivePanel()) {
37914 //reg.showPanel(reg.getActivePanel()); // force it to activate..
37915 reg.setActivePanel(reg.getActivePanel());
37918 if (!reg.panels.length) {
37921 reg.showPanel(reg.getPanel(0));
37930 * Returns the nested BorderLayout for this panel
37931 * @return {Roo.BorderLayout}
37933 getLayout : function(){
37934 return this.layout;
37938 * Adds a xtype elements to the layout of the nested panel
37942 xtype : 'ContentPanel',
37949 xtype : 'NestedLayoutPanel',
37955 items : [ ... list of content panels or nested layout panels.. ]
37959 * @param {Object} cfg Xtype definition of item to add.
37961 addxtype : function(cfg) {
37962 return this.layout.addxtype(cfg);
37967 * Ext JS Library 1.1.1
37968 * Copyright(c) 2006-2007, Ext JS, LLC.
37970 * Originally Released Under LGPL - original licence link has changed is not relivant.
37973 * <script type="text/javascript">
37976 * @class Roo.TabPanel
37977 * @extends Roo.util.Observable
37978 * A lightweight tab container.
37982 // basic tabs 1, built from existing content
37983 var tabs = new Roo.TabPanel("tabs1");
37984 tabs.addTab("script", "View Script");
37985 tabs.addTab("markup", "View Markup");
37986 tabs.activate("script");
37988 // more advanced tabs, built from javascript
37989 var jtabs = new Roo.TabPanel("jtabs");
37990 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
37992 // set up the UpdateManager
37993 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
37994 var updater = tab2.getUpdateManager();
37995 updater.setDefaultUrl("ajax1.htm");
37996 tab2.on('activate', updater.refresh, updater, true);
37998 // Use setUrl for Ajax loading
37999 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
38000 tab3.setUrl("ajax2.htm", null, true);
38003 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
38006 jtabs.activate("jtabs-1");
38009 * Create a new TabPanel.
38010 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
38011 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
38013 Roo.bootstrap.panel.Tabs = function(config){
38015 * The container element for this TabPanel.
38016 * @type Roo.Element
38018 this.el = Roo.get(config.el);
38021 if(typeof config == "boolean"){
38022 this.tabPosition = config ? "bottom" : "top";
38024 Roo.apply(this, config);
38028 if(this.tabPosition == "bottom"){
38029 this.bodyEl = Roo.get(this.createBody(this.el.dom));
38030 this.el.addClass("roo-tabs-bottom");
38032 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
38033 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
38034 this.stripEl.setVisibilityMode(Roo.Element.DISPLAY);
38035 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
38037 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
38039 if(this.tabPosition != "bottom"){
38040 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
38041 * @type Roo.Element
38043 this.bodyEl = Roo.get(this.createBody(this.el.dom));
38044 this.el.addClass("roo-tabs-top");
38048 this.bodyEl.setStyle("position", "relative");
38050 this.active = null;
38051 this.activateDelegate = this.activate.createDelegate(this);
38056 * Fires when the active tab changes
38057 * @param {Roo.TabPanel} this
38058 * @param {Roo.TabPanelItem} activePanel The new active tab
38062 * @event beforetabchange
38063 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
38064 * @param {Roo.TabPanel} this
38065 * @param {Object} e Set cancel to true on this object to cancel the tab change
38066 * @param {Roo.TabPanelItem} tab The tab being changed to
38068 "beforetabchange" : true
38071 Roo.EventManager.onWindowResize(this.onResize, this);
38072 this.cpad = this.el.getPadding("lr");
38073 this.hiddenCount = 0;
38076 // toolbar on the tabbar support...
38077 if (this.toolbar) {
38078 alert("no toolbar support yet");
38079 this.toolbar = false;
38081 var tcfg = this.toolbar;
38082 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
38083 this.toolbar = new Roo.Toolbar(tcfg);
38084 if (Roo.isSafari) {
38085 var tbl = tcfg.container.child('table', true);
38086 tbl.setAttribute('width', '100%');
38094 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
38097 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
38099 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
38101 tabPosition : "top",
38103 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
38105 currentTabWidth : 0,
38107 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
38111 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
38115 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
38117 preferredTabWidth : 175,
38119 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
38121 resizeTabs : false,
38123 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
38125 monitorResize : true,
38127 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
38132 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
38133 * @param {String} id The id of the div to use <b>or create</b>
38134 * @param {String} text The text for the tab
38135 * @param {String} content (optional) Content to put in the TabPanelItem body
38136 * @param {Boolean} closable (optional) True to create a close icon on the tab
38137 * @return {Roo.TabPanelItem} The created TabPanelItem
38139 addTab : function(id, text, content, closable, tpl)
38141 var item = new Roo.bootstrap.panel.TabItem({
38145 closable : closable,
38148 this.addTabItem(item);
38150 item.setContent(content);
38156 * Returns the {@link Roo.TabPanelItem} with the specified id/index
38157 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
38158 * @return {Roo.TabPanelItem}
38160 getTab : function(id){
38161 return this.items[id];
38165 * Hides the {@link Roo.TabPanelItem} with the specified id/index
38166 * @param {String/Number} id The id or index of the TabPanelItem to hide.
38168 hideTab : function(id){
38169 var t = this.items[id];
38172 this.hiddenCount++;
38173 this.autoSizeTabs();
38178 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
38179 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
38181 unhideTab : function(id){
38182 var t = this.items[id];
38184 t.setHidden(false);
38185 this.hiddenCount--;
38186 this.autoSizeTabs();
38191 * Adds an existing {@link Roo.TabPanelItem}.
38192 * @param {Roo.TabPanelItem} item The TabPanelItem to add
38194 addTabItem : function(item)
38196 this.items[item.id] = item;
38197 this.items.push(item);
38198 this.autoSizeTabs();
38199 // if(this.resizeTabs){
38200 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
38201 // this.autoSizeTabs();
38203 // item.autoSize();
38208 * Removes a {@link Roo.TabPanelItem}.
38209 * @param {String/Number} id The id or index of the TabPanelItem to remove.
38211 removeTab : function(id){
38212 var items = this.items;
38213 var tab = items[id];
38214 if(!tab) { return; }
38215 var index = items.indexOf(tab);
38216 if(this.active == tab && items.length > 1){
38217 var newTab = this.getNextAvailable(index);
38222 this.stripEl.dom.removeChild(tab.pnode.dom);
38223 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
38224 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
38226 items.splice(index, 1);
38227 delete this.items[tab.id];
38228 tab.fireEvent("close", tab);
38229 tab.purgeListeners();
38230 this.autoSizeTabs();
38233 getNextAvailable : function(start){
38234 var items = this.items;
38236 // look for a next tab that will slide over to
38237 // replace the one being removed
38238 while(index < items.length){
38239 var item = items[++index];
38240 if(item && !item.isHidden()){
38244 // if one isn't found select the previous tab (on the left)
38247 var item = items[--index];
38248 if(item && !item.isHidden()){
38256 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
38257 * @param {String/Number} id The id or index of the TabPanelItem to disable.
38259 disableTab : function(id){
38260 var tab = this.items[id];
38261 if(tab && this.active != tab){
38267 * Enables a {@link Roo.TabPanelItem} that is disabled.
38268 * @param {String/Number} id The id or index of the TabPanelItem to enable.
38270 enableTab : function(id){
38271 var tab = this.items[id];
38276 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
38277 * @param {String/Number} id The id or index of the TabPanelItem to activate.
38278 * @return {Roo.TabPanelItem} The TabPanelItem.
38280 activate : function(id)
38282 var tab = this.items[id];
38286 if(tab == this.active || tab.disabled){
38290 this.fireEvent("beforetabchange", this, e, tab);
38291 if(e.cancel !== true && !tab.disabled){
38293 this.active.hide();
38295 this.active = this.items[id];
38296 this.active.show();
38297 this.fireEvent("tabchange", this, this.active);
38303 * Gets the active {@link Roo.TabPanelItem}.
38304 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
38306 getActiveTab : function(){
38307 return this.active;
38311 * Updates the tab body element to fit the height of the container element
38312 * for overflow scrolling
38313 * @param {Number} targetHeight (optional) Override the starting height from the elements height
38315 syncHeight : function(targetHeight){
38316 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
38317 var bm = this.bodyEl.getMargins();
38318 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
38319 this.bodyEl.setHeight(newHeight);
38323 onResize : function(){
38324 if(this.monitorResize){
38325 this.autoSizeTabs();
38330 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
38332 beginUpdate : function(){
38333 this.updating = true;
38337 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
38339 endUpdate : function(){
38340 this.updating = false;
38341 this.autoSizeTabs();
38345 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
38347 autoSizeTabs : function()
38349 var count = this.items.length;
38350 var vcount = count - this.hiddenCount;
38353 this.stripEl.hide();
38355 this.stripEl.show();
38358 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
38363 var w = Math.max(this.el.getWidth() - this.cpad, 10);
38364 var availWidth = Math.floor(w / vcount);
38365 var b = this.stripBody;
38366 if(b.getWidth() > w){
38367 var tabs = this.items;
38368 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
38369 if(availWidth < this.minTabWidth){
38370 /*if(!this.sleft){ // incomplete scrolling code
38371 this.createScrollButtons();
38374 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
38377 if(this.currentTabWidth < this.preferredTabWidth){
38378 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
38384 * Returns the number of tabs in this TabPanel.
38387 getCount : function(){
38388 return this.items.length;
38392 * Resizes all the tabs to the passed width
38393 * @param {Number} The new width
38395 setTabWidth : function(width){
38396 this.currentTabWidth = width;
38397 for(var i = 0, len = this.items.length; i < len; i++) {
38398 if(!this.items[i].isHidden()) {
38399 this.items[i].setWidth(width);
38405 * Destroys this TabPanel
38406 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
38408 destroy : function(removeEl){
38409 Roo.EventManager.removeResizeListener(this.onResize, this);
38410 for(var i = 0, len = this.items.length; i < len; i++){
38411 this.items[i].purgeListeners();
38413 if(removeEl === true){
38414 this.el.update("");
38419 createStrip : function(container)
38421 var strip = document.createElement("nav");
38422 strip.className = Roo.bootstrap.version == 4 ?
38423 "navbar-light bg-light" :
38424 "navbar navbar-default"; //"x-tabs-wrap";
38425 container.appendChild(strip);
38429 createStripList : function(strip)
38431 // div wrapper for retard IE
38432 // returns the "tr" element.
38433 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
38434 //'<div class="x-tabs-strip-wrap">'+
38435 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
38436 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
38437 return strip.firstChild; //.firstChild.firstChild.firstChild;
38439 createBody : function(container)
38441 var body = document.createElement("div");
38442 Roo.id(body, "tab-body");
38443 //Roo.fly(body).addClass("x-tabs-body");
38444 Roo.fly(body).addClass("tab-content");
38445 container.appendChild(body);
38448 createItemBody :function(bodyEl, id){
38449 var body = Roo.getDom(id);
38451 body = document.createElement("div");
38454 //Roo.fly(body).addClass("x-tabs-item-body");
38455 Roo.fly(body).addClass("tab-pane");
38456 bodyEl.insertBefore(body, bodyEl.firstChild);
38460 createStripElements : function(stripEl, text, closable, tpl)
38462 var td = document.createElement("li"); // was td..
38463 td.className = 'nav-item';
38465 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
38468 stripEl.appendChild(td);
38470 td.className = "x-tabs-closable";
38471 if(!this.closeTpl){
38472 this.closeTpl = new Roo.Template(
38473 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38474 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
38475 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
38478 var el = this.closeTpl.overwrite(td, {"text": text});
38479 var close = el.getElementsByTagName("div")[0];
38480 var inner = el.getElementsByTagName("em")[0];
38481 return {"el": el, "close": close, "inner": inner};
38484 // not sure what this is..
38485 // if(!this.tabTpl){
38486 //this.tabTpl = new Roo.Template(
38487 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38488 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
38490 // this.tabTpl = new Roo.Template(
38491 // '<a href="#">' +
38492 // '<span unselectable="on"' +
38493 // (this.disableTooltips ? '' : ' title="{text}"') +
38494 // ' >{text}</span></a>'
38500 var template = tpl || this.tabTpl || false;
38503 template = new Roo.Template(
38504 Roo.bootstrap.version == 4 ?
38506 '<a class="nav-link" href="#" unselectable="on"' +
38507 (this.disableTooltips ? '' : ' title="{text}"') +
38510 '<a class="nav-link" href="#">' +
38511 '<span unselectable="on"' +
38512 (this.disableTooltips ? '' : ' title="{text}"') +
38513 ' >{text}</span></a>'
38518 switch (typeof(template)) {
38522 template = new Roo.Template(template);
38528 var el = template.overwrite(td, {"text": text});
38530 var inner = el.getElementsByTagName("span")[0];
38532 return {"el": el, "inner": inner};
38540 * @class Roo.TabPanelItem
38541 * @extends Roo.util.Observable
38542 * Represents an individual item (tab plus body) in a TabPanel.
38543 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
38544 * @param {String} id The id of this TabPanelItem
38545 * @param {String} text The text for the tab of this TabPanelItem
38546 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
38548 Roo.bootstrap.panel.TabItem = function(config){
38550 * The {@link Roo.TabPanel} this TabPanelItem belongs to
38551 * @type Roo.TabPanel
38553 this.tabPanel = config.panel;
38555 * The id for this TabPanelItem
38558 this.id = config.id;
38560 this.disabled = false;
38562 this.text = config.text;
38564 this.loaded = false;
38565 this.closable = config.closable;
38568 * The body element for this TabPanelItem.
38569 * @type Roo.Element
38571 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
38572 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
38573 this.bodyEl.setStyle("display", "block");
38574 this.bodyEl.setStyle("zoom", "1");
38575 //this.hideAction();
38577 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
38579 this.el = Roo.get(els.el);
38580 this.inner = Roo.get(els.inner, true);
38581 this.textEl = Roo.bootstrap.version == 4 ?
38582 this.el : Roo.get(this.el.dom.firstChild, true);
38584 this.pnode = this.linode = Roo.get(els.el.parentNode, true);
38585 this.status_node = Roo.bootstrap.version == 4 ? this.el : this.linode;
38588 // this.el.on("mousedown", this.onTabMouseDown, this);
38589 this.el.on("click", this.onTabClick, this);
38591 if(config.closable){
38592 var c = Roo.get(els.close, true);
38593 c.dom.title = this.closeText;
38594 c.addClassOnOver("close-over");
38595 c.on("click", this.closeClick, this);
38601 * Fires when this tab becomes the active tab.
38602 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38603 * @param {Roo.TabPanelItem} this
38607 * @event beforeclose
38608 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
38609 * @param {Roo.TabPanelItem} this
38610 * @param {Object} e Set cancel to true on this object to cancel the close.
38612 "beforeclose": true,
38615 * Fires when this tab is closed.
38616 * @param {Roo.TabPanelItem} this
38620 * @event deactivate
38621 * Fires when this tab is no longer the active tab.
38622 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38623 * @param {Roo.TabPanelItem} this
38625 "deactivate" : true
38627 this.hidden = false;
38629 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
38632 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
38634 purgeListeners : function(){
38635 Roo.util.Observable.prototype.purgeListeners.call(this);
38636 this.el.removeAllListeners();
38639 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
38642 this.status_node.addClass("active");
38645 this.tabPanel.stripWrap.repaint();
38647 this.fireEvent("activate", this.tabPanel, this);
38651 * Returns true if this tab is the active tab.
38652 * @return {Boolean}
38654 isActive : function(){
38655 return this.tabPanel.getActiveTab() == this;
38659 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
38662 this.status_node.removeClass("active");
38664 this.fireEvent("deactivate", this.tabPanel, this);
38667 hideAction : function(){
38668 this.bodyEl.hide();
38669 this.bodyEl.setStyle("position", "absolute");
38670 this.bodyEl.setLeft("-20000px");
38671 this.bodyEl.setTop("-20000px");
38674 showAction : function(){
38675 this.bodyEl.setStyle("position", "relative");
38676 this.bodyEl.setTop("");
38677 this.bodyEl.setLeft("");
38678 this.bodyEl.show();
38682 * Set the tooltip for the tab.
38683 * @param {String} tooltip The tab's tooltip
38685 setTooltip : function(text){
38686 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
38687 this.textEl.dom.qtip = text;
38688 this.textEl.dom.removeAttribute('title');
38690 this.textEl.dom.title = text;
38694 onTabClick : function(e){
38695 e.preventDefault();
38696 this.tabPanel.activate(this.id);
38699 onTabMouseDown : function(e){
38700 e.preventDefault();
38701 this.tabPanel.activate(this.id);
38704 getWidth : function(){
38705 return this.inner.getWidth();
38708 setWidth : function(width){
38709 var iwidth = width - this.linode.getPadding("lr");
38710 this.inner.setWidth(iwidth);
38711 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
38712 this.linode.setWidth(width);
38716 * Show or hide the tab
38717 * @param {Boolean} hidden True to hide or false to show.
38719 setHidden : function(hidden){
38720 this.hidden = hidden;
38721 this.linode.setStyle("display", hidden ? "none" : "");
38725 * Returns true if this tab is "hidden"
38726 * @return {Boolean}
38728 isHidden : function(){
38729 return this.hidden;
38733 * Returns the text for this tab
38736 getText : function(){
38740 autoSize : function(){
38741 //this.el.beginMeasure();
38742 this.textEl.setWidth(1);
38744 * #2804 [new] Tabs in Roojs
38745 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
38747 //this.setWidth(this.textEl.dom.scrollWidth+this.linode.getPadding("lr")+this.inner.getPadding("lr") + 2);
38748 //this.el.endMeasure();
38752 * Sets the text for the tab (Note: this also sets the tooltip text)
38753 * @param {String} text The tab's text and tooltip
38755 setText : function(text){
38757 this.textEl.update(text);
38758 this.setTooltip(text);
38759 //if(!this.tabPanel.resizeTabs){
38760 // this.autoSize();
38764 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
38766 activate : function(){
38767 this.tabPanel.activate(this.id);
38771 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
38773 disable : function(){
38774 if(this.tabPanel.active != this){
38775 this.disabled = true;
38776 this.status_node.addClass("disabled");
38781 * Enables this TabPanelItem if it was previously disabled.
38783 enable : function(){
38784 this.disabled = false;
38785 this.status_node.removeClass("disabled");
38789 * Sets the content for this TabPanelItem.
38790 * @param {String} content The content
38791 * @param {Boolean} loadScripts true to look for and load scripts
38793 setContent : function(content, loadScripts){
38794 this.bodyEl.update(content, loadScripts);
38798 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
38799 * @return {Roo.UpdateManager} The UpdateManager
38801 getUpdateManager : function(){
38802 return this.bodyEl.getUpdateManager();
38806 * Set a URL to be used to load the content for this TabPanelItem.
38807 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
38808 * @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)
38809 * @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)
38810 * @return {Roo.UpdateManager} The UpdateManager
38812 setUrl : function(url, params, loadOnce){
38813 if(this.refreshDelegate){
38814 this.un('activate', this.refreshDelegate);
38816 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
38817 this.on("activate", this.refreshDelegate);
38818 return this.bodyEl.getUpdateManager();
38822 _handleRefresh : function(url, params, loadOnce){
38823 if(!loadOnce || !this.loaded){
38824 var updater = this.bodyEl.getUpdateManager();
38825 updater.update(url, params, this._setLoaded.createDelegate(this));
38830 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
38831 * Will fail silently if the setUrl method has not been called.
38832 * This does not activate the panel, just updates its content.
38834 refresh : function(){
38835 if(this.refreshDelegate){
38836 this.loaded = false;
38837 this.refreshDelegate();
38842 _setLoaded : function(){
38843 this.loaded = true;
38847 closeClick : function(e){
38850 this.fireEvent("beforeclose", this, o);
38851 if(o.cancel !== true){
38852 this.tabPanel.removeTab(this.id);
38856 * The text displayed in the tooltip for the close icon.
38859 closeText : "Close this tab"
38862 * This script refer to:
38863 * Title: International Telephone Input
38864 * Author: Jack O'Connor
38865 * Code version: v12.1.12
38866 * Availability: https://github.com/jackocnr/intl-tel-input.git
38869 Roo.bootstrap.PhoneInputData = function() {
38872 "Afghanistan (افغانستان)",
38877 "Albania (Shqipëri)",
38882 "Algeria (الجزائر)",
38907 "Antigua and Barbuda",
38917 "Armenia (Հայաստան)",
38933 "Austria (Österreich)",
38938 "Azerbaijan (Azərbaycan)",
38948 "Bahrain (البحرين)",
38953 "Bangladesh (বাংলাদেশ)",
38963 "Belarus (Беларусь)",
38968 "Belgium (België)",
38998 "Bosnia and Herzegovina (Босна и Херцеговина)",
39013 "British Indian Ocean Territory",
39018 "British Virgin Islands",
39028 "Bulgaria (България)",
39038 "Burundi (Uburundi)",
39043 "Cambodia (កម្ពុជា)",
39048 "Cameroon (Cameroun)",
39057 ["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"]
39060 "Cape Verde (Kabu Verdi)",
39065 "Caribbean Netherlands",
39076 "Central African Republic (République centrafricaine)",
39096 "Christmas Island",
39102 "Cocos (Keeling) Islands",
39113 "Comoros (جزر القمر)",
39118 "Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)",
39123 "Congo (Republic) (Congo-Brazzaville)",
39143 "Croatia (Hrvatska)",
39164 "Czech Republic (Česká republika)",
39169 "Denmark (Danmark)",
39184 "Dominican Republic (República Dominicana)",
39188 ["809", "829", "849"]
39206 "Equatorial Guinea (Guinea Ecuatorial)",
39226 "Falkland Islands (Islas Malvinas)",
39231 "Faroe Islands (Føroyar)",
39252 "French Guiana (Guyane française)",
39257 "French Polynesia (Polynésie française)",
39272 "Georgia (საქართველო)",
39277 "Germany (Deutschland)",
39297 "Greenland (Kalaallit Nunaat)",
39334 "Guinea-Bissau (Guiné Bissau)",
39359 "Hungary (Magyarország)",
39364 "Iceland (Ísland)",
39384 "Iraq (العراق)",
39400 "Israel (ישראל)",
39427 "Jordan (الأردن)",
39432 "Kazakhstan (Казахстан)",
39453 "Kuwait (الكويت)",
39458 "Kyrgyzstan (Кыргызстан)",
39468 "Latvia (Latvija)",
39473 "Lebanon (لبنان)",
39488 "Libya (ليبيا)",
39498 "Lithuania (Lietuva)",
39513 "Macedonia (FYROM) (Македонија)",
39518 "Madagascar (Madagasikara)",
39548 "Marshall Islands",
39558 "Mauritania (موريتانيا)",
39563 "Mauritius (Moris)",
39584 "Moldova (Republica Moldova)",
39594 "Mongolia (Монгол)",
39599 "Montenegro (Crna Gora)",
39609 "Morocco (المغرب)",
39615 "Mozambique (Moçambique)",
39620 "Myanmar (Burma) (မြန်မာ)",
39625 "Namibia (Namibië)",
39640 "Netherlands (Nederland)",
39645 "New Caledonia (Nouvelle-Calédonie)",
39680 "North Korea (조선 민주주의 인민 공화국)",
39685 "Northern Mariana Islands",
39701 "Pakistan (پاکستان)",
39711 "Palestine (فلسطين)",
39721 "Papua New Guinea",
39763 "Réunion (La Réunion)",
39769 "Romania (România)",
39785 "Saint Barthélemy",
39796 "Saint Kitts and Nevis",
39806 "Saint Martin (Saint-Martin (partie française))",
39812 "Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)",
39817 "Saint Vincent and the Grenadines",
39832 "São Tomé and Príncipe (São Tomé e Príncipe)",
39837 "Saudi Arabia (المملكة العربية السعودية)",
39842 "Senegal (Sénégal)",
39872 "Slovakia (Slovensko)",
39877 "Slovenia (Slovenija)",
39887 "Somalia (Soomaaliya)",
39897 "South Korea (대한민국)",
39902 "South Sudan (جنوب السودان)",
39912 "Sri Lanka (ශ්රී ලංකාව)",
39917 "Sudan (السودان)",
39927 "Svalbard and Jan Mayen",
39938 "Sweden (Sverige)",
39943 "Switzerland (Schweiz)",
39948 "Syria (سوريا)",
39993 "Trinidad and Tobago",
39998 "Tunisia (تونس)",
40003 "Turkey (Türkiye)",
40013 "Turks and Caicos Islands",
40023 "U.S. Virgin Islands",
40033 "Ukraine (Україна)",
40038 "United Arab Emirates (الإمارات العربية المتحدة)",
40060 "Uzbekistan (Oʻzbekiston)",
40070 "Vatican City (Città del Vaticano)",
40081 "Vietnam (Việt Nam)",
40086 "Wallis and Futuna (Wallis-et-Futuna)",
40091 "Western Sahara (الصحراء الغربية)",
40097 "Yemen (اليمن)",
40121 * This script refer to:
40122 * Title: International Telephone Input
40123 * Author: Jack O'Connor
40124 * Code version: v12.1.12
40125 * Availability: https://github.com/jackocnr/intl-tel-input.git
40129 * @class Roo.bootstrap.PhoneInput
40130 * @extends Roo.bootstrap.TriggerField
40131 * An input with International dial-code selection
40133 * @cfg {String} defaultDialCode default '+852'
40134 * @cfg {Array} preferedCountries default []
40137 * Create a new PhoneInput.
40138 * @param {Object} config Configuration options
40141 Roo.bootstrap.PhoneInput = function(config) {
40142 Roo.bootstrap.PhoneInput.superclass.constructor.call(this, config);
40145 Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
40147 listWidth: undefined,
40149 selectedClass: 'active',
40151 invalidClass : "has-warning",
40153 validClass: 'has-success',
40155 allowed: '0123456789',
40160 * @cfg {String} defaultDialCode The default dial code when initializing the input
40162 defaultDialCode: '+852',
40165 * @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
40167 preferedCountries: false,
40169 getAutoCreate : function()
40171 var data = Roo.bootstrap.PhoneInputData();
40172 var align = this.labelAlign || this.parentLabelAlign();
40175 this.allCountries = [];
40176 this.dialCodeMapping = [];
40178 for (var i = 0; i < data.length; i++) {
40180 this.allCountries[i] = {
40184 priority: c[3] || 0,
40185 areaCodes: c[4] || null
40187 this.dialCodeMapping[c[2]] = {
40190 priority: c[3] || 0,
40191 areaCodes: c[4] || null
40203 // type: 'number', -- do not use number - we get the flaky up/down arrows.
40204 maxlength: this.max_length,
40205 cls : 'form-control tel-input',
40206 autocomplete: 'new-password'
40209 var hiddenInput = {
40212 cls: 'hidden-tel-input'
40216 hiddenInput.name = this.name;
40219 if (this.disabled) {
40220 input.disabled = true;
40223 var flag_container = {
40240 cls: this.hasFeedback ? 'has-feedback' : '',
40246 cls: 'dial-code-holder',
40253 cls: 'roo-select2-container input-group',
40260 if (this.fieldLabel.length) {
40263 tooltip: 'This field is required'
40269 cls: 'control-label',
40275 html: this.fieldLabel
40278 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40284 if(this.indicatorpos == 'right') {
40285 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40292 if(align == 'left') {
40300 if(this.labelWidth > 12){
40301 label.style = "width: " + this.labelWidth + 'px';
40303 if(this.labelWidth < 13 && this.labelmd == 0){
40304 this.labelmd = this.labelWidth;
40306 if(this.labellg > 0){
40307 label.cls += ' col-lg-' + this.labellg;
40308 input.cls += ' col-lg-' + (12 - this.labellg);
40310 if(this.labelmd > 0){
40311 label.cls += ' col-md-' + this.labelmd;
40312 container.cls += ' col-md-' + (12 - this.labelmd);
40314 if(this.labelsm > 0){
40315 label.cls += ' col-sm-' + this.labelsm;
40316 container.cls += ' col-sm-' + (12 - this.labelsm);
40318 if(this.labelxs > 0){
40319 label.cls += ' col-xs-' + this.labelxs;
40320 container.cls += ' col-xs-' + (12 - this.labelxs);
40330 var settings = this;
40332 ['xs','sm','md','lg'].map(function(size){
40333 if (settings[size]) {
40334 cfg.cls += ' col-' + size + '-' + settings[size];
40338 this.store = new Roo.data.Store({
40339 proxy : new Roo.data.MemoryProxy({}),
40340 reader : new Roo.data.JsonReader({
40351 'name' : 'dialCode',
40355 'name' : 'priority',
40359 'name' : 'areaCodes',
40366 if(!this.preferedCountries) {
40367 this.preferedCountries = [
40374 var p = this.preferedCountries.reverse();
40377 for (var i = 0; i < p.length; i++) {
40378 for (var j = 0; j < this.allCountries.length; j++) {
40379 if(this.allCountries[j].iso2 == p[i]) {
40380 var t = this.allCountries[j];
40381 this.allCountries.splice(j,1);
40382 this.allCountries.unshift(t);
40388 this.store.proxy.data = {
40390 data: this.allCountries
40396 initEvents : function()
40399 Roo.bootstrap.PhoneInput.superclass.initEvents.call(this);
40401 this.indicator = this.indicatorEl();
40402 this.flag = this.flagEl();
40403 this.dialCodeHolder = this.dialCodeHolderEl();
40405 this.trigger = this.el.select('div.flag-box',true).first();
40406 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
40411 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40412 _this.list.setWidth(lw);
40415 this.list.on('mouseover', this.onViewOver, this);
40416 this.list.on('mousemove', this.onViewMove, this);
40417 this.inputEl().on("keyup", this.onKeyUp, this);
40418 this.inputEl().on("keypress", this.onKeyPress, this);
40420 this.tpl = '<li><a href="#"><div class="flag {iso2}"></div>{name} <span class="dial-code">+{dialCode}</span></a></li>';
40422 this.view = new Roo.View(this.list, this.tpl, {
40423 singleSelect:true, store: this.store, selectedClass: this.selectedClass
40426 this.view.on('click', this.onViewClick, this);
40427 this.setValue(this.defaultDialCode);
40430 onTriggerClick : function(e)
40432 Roo.log('trigger click');
40437 if(this.isExpanded()){
40439 this.hasFocus = false;
40441 this.store.load({});
40442 this.hasFocus = true;
40447 isExpanded : function()
40449 return this.list.isVisible();
40452 collapse : function()
40454 if(!this.isExpanded()){
40458 Roo.get(document).un('mousedown', this.collapseIf, this);
40459 Roo.get(document).un('mousewheel', this.collapseIf, this);
40460 this.fireEvent('collapse', this);
40464 expand : function()
40468 if(this.isExpanded() || !this.hasFocus){
40472 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
40473 this.list.setWidth(lw);
40476 this.restrictHeight();
40478 Roo.get(document).on('mousedown', this.collapseIf, this);
40479 Roo.get(document).on('mousewheel', this.collapseIf, this);
40481 this.fireEvent('expand', this);
40484 restrictHeight : function()
40486 this.list.alignTo(this.inputEl(), this.listAlign);
40487 this.list.alignTo(this.inputEl(), this.listAlign);
40490 onViewOver : function(e, t)
40492 if(this.inKeyMode){
40495 var item = this.view.findItemFromChild(t);
40498 var index = this.view.indexOf(item);
40499 this.select(index, false);
40504 onViewClick : function(view, doFocus, el, e)
40506 var index = this.view.getSelectedIndexes()[0];
40508 var r = this.store.getAt(index);
40511 this.onSelect(r, index);
40513 if(doFocus !== false && !this.blockFocus){
40514 this.inputEl().focus();
40518 onViewMove : function(e, t)
40520 this.inKeyMode = false;
40523 select : function(index, scrollIntoView)
40525 this.selectedIndex = index;
40526 this.view.select(index);
40527 if(scrollIntoView !== false){
40528 var el = this.view.getNode(index);
40530 this.list.scrollChildIntoView(el, false);
40535 createList : function()
40537 this.list = Roo.get(document.body).createChild({
40539 cls: 'typeahead typeahead-long dropdown-menu tel-list',
40540 style: 'display:none'
40543 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
40546 collapseIf : function(e)
40548 var in_combo = e.within(this.el);
40549 var in_list = e.within(this.list);
40550 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
40552 if (in_combo || in_list || is_list) {
40558 onSelect : function(record, index)
40560 if(this.fireEvent('beforeselect', this, record, index) !== false){
40562 this.setFlagClass(record.data.iso2);
40563 this.setDialCode(record.data.dialCode);
40564 this.hasFocus = false;
40566 this.fireEvent('select', this, record, index);
40570 flagEl : function()
40572 var flag = this.el.select('div.flag',true).first();
40579 dialCodeHolderEl : function()
40581 var d = this.el.select('input.dial-code-holder',true).first();
40588 setDialCode : function(v)
40590 this.dialCodeHolder.dom.value = '+'+v;
40593 setFlagClass : function(n)
40595 this.flag.dom.className = 'flag '+n;
40598 getValue : function()
40600 var v = this.inputEl().getValue();
40601 if(this.dialCodeHolder) {
40602 v = this.dialCodeHolder.dom.value+this.inputEl().getValue();
40607 setValue : function(v)
40609 var d = this.getDialCode(v);
40611 //invalid dial code
40612 if(v.length == 0 || !d || d.length == 0) {
40614 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
40615 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
40621 this.setFlagClass(this.dialCodeMapping[d].iso2);
40622 this.setDialCode(d);
40623 this.inputEl().dom.value = v.replace('+'+d,'');
40624 this.hiddenEl().dom.value = this.getValue();
40629 getDialCode : function(v)
40633 if (v.length == 0) {
40634 return this.dialCodeHolder.dom.value;
40638 if (v.charAt(0) != "+") {
40641 var numericChars = "";
40642 for (var i = 1; i < v.length; i++) {
40643 var c = v.charAt(i);
40646 if (this.dialCodeMapping[numericChars]) {
40647 dialCode = v.substr(1, i);
40649 if (numericChars.length == 4) {
40659 this.setValue(this.defaultDialCode);
40663 hiddenEl : function()
40665 return this.el.select('input.hidden-tel-input',true).first();
40668 // after setting val
40669 onKeyUp : function(e){
40670 this.setValue(this.getValue());
40673 onKeyPress : function(e){
40674 if(this.allowed.indexOf(String.fromCharCode(e.getCharCode())) === -1){
40681 * @class Roo.bootstrap.MoneyField
40682 * @extends Roo.bootstrap.ComboBox
40683 * Bootstrap MoneyField class
40686 * Create a new MoneyField.
40687 * @param {Object} config Configuration options
40690 Roo.bootstrap.MoneyField = function(config) {
40692 Roo.bootstrap.MoneyField.superclass.constructor.call(this, config);
40696 Roo.extend(Roo.bootstrap.MoneyField, Roo.bootstrap.ComboBox, {
40699 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
40701 allowDecimals : true,
40703 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
40705 decimalSeparator : ".",
40707 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
40709 decimalPrecision : 0,
40711 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
40713 allowNegative : true,
40715 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
40719 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
40721 minValue : Number.NEGATIVE_INFINITY,
40723 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
40725 maxValue : Number.MAX_VALUE,
40727 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
40729 minText : "The minimum value for this field is {0}",
40731 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
40733 maxText : "The maximum value for this field is {0}",
40735 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
40736 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
40738 nanText : "{0} is not a valid number",
40740 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
40744 * @cfg {String} defaults currency of the MoneyField
40745 * value should be in lkey
40747 defaultCurrency : false,
40749 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
40751 thousandsDelimiter : false,
40753 * @cfg {Number} max_length Maximum input field length allowed (defaults to Number.MAX_VALUE)
40764 getAutoCreate : function()
40766 var align = this.labelAlign || this.parentLabelAlign();
40778 cls : 'form-control roo-money-amount-input',
40779 autocomplete: 'new-password'
40782 var hiddenInput = {
40786 cls: 'hidden-number-input'
40789 if(this.max_length) {
40790 input.maxlength = this.max_length;
40794 hiddenInput.name = this.name;
40797 if (this.disabled) {
40798 input.disabled = true;
40801 var clg = 12 - this.inputlg;
40802 var cmd = 12 - this.inputmd;
40803 var csm = 12 - this.inputsm;
40804 var cxs = 12 - this.inputxs;
40808 cls : 'row roo-money-field',
40812 cls : 'roo-money-currency column col-lg-' + clg + ' col-md-' + cmd + ' col-sm-' + csm + ' col-xs-' + cxs,
40816 cls: 'roo-select2-container input-group',
40820 cls : 'form-control roo-money-currency-input',
40821 autocomplete: 'new-password',
40823 name : this.currencyName
40827 cls : 'input-group-addon',
40841 cls : 'roo-money-amount column col-lg-' + this.inputlg + ' col-md-' + this.inputmd + ' col-sm-' + this.inputsm + ' col-xs-' + this.inputxs,
40845 cls: this.hasFeedback ? 'has-feedback' : '',
40856 if (this.fieldLabel.length) {
40859 tooltip: 'This field is required'
40865 cls: 'control-label',
40871 html: this.fieldLabel
40874 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40880 if(this.indicatorpos == 'right') {
40881 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40888 if(align == 'left') {
40896 if(this.labelWidth > 12){
40897 label.style = "width: " + this.labelWidth + 'px';
40899 if(this.labelWidth < 13 && this.labelmd == 0){
40900 this.labelmd = this.labelWidth;
40902 if(this.labellg > 0){
40903 label.cls += ' col-lg-' + this.labellg;
40904 input.cls += ' col-lg-' + (12 - this.labellg);
40906 if(this.labelmd > 0){
40907 label.cls += ' col-md-' + this.labelmd;
40908 container.cls += ' col-md-' + (12 - this.labelmd);
40910 if(this.labelsm > 0){
40911 label.cls += ' col-sm-' + this.labelsm;
40912 container.cls += ' col-sm-' + (12 - this.labelsm);
40914 if(this.labelxs > 0){
40915 label.cls += ' col-xs-' + this.labelxs;
40916 container.cls += ' col-xs-' + (12 - this.labelxs);
40927 var settings = this;
40929 ['xs','sm','md','lg'].map(function(size){
40930 if (settings[size]) {
40931 cfg.cls += ' col-' + size + '-' + settings[size];
40938 initEvents : function()
40940 this.indicator = this.indicatorEl();
40942 this.initCurrencyEvent();
40944 this.initNumberEvent();
40947 initCurrencyEvent : function()
40950 throw "can not find store for combo";
40953 this.store = Roo.factory(this.store, Roo.data);
40954 this.store.parent = this;
40958 this.triggerEl = this.el.select('.input-group-addon', true).first();
40960 this.triggerEl.on("click", this.onTriggerClick, this, { preventDefault : true });
40965 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40966 _this.list.setWidth(lw);
40969 this.list.on('mouseover', this.onViewOver, this);
40970 this.list.on('mousemove', this.onViewMove, this);
40971 this.list.on('scroll', this.onViewScroll, this);
40974 this.tpl = '<li><a href="#">{' + this.currencyField + '}</a></li>';
40977 this.view = new Roo.View(this.list, this.tpl, {
40978 singleSelect:true, store: this.store, selectedClass: this.selectedClass
40981 this.view.on('click', this.onViewClick, this);
40983 this.store.on('beforeload', this.onBeforeLoad, this);
40984 this.store.on('load', this.onLoad, this);
40985 this.store.on('loadexception', this.onLoadException, this);
40987 this.keyNav = new Roo.KeyNav(this.currencyEl(), {
40988 "up" : function(e){
40989 this.inKeyMode = true;
40993 "down" : function(e){
40994 if(!this.isExpanded()){
40995 this.onTriggerClick();
40997 this.inKeyMode = true;
41002 "enter" : function(e){
41005 if(this.fireEvent("specialkey", this, e)){
41006 this.onViewClick(false);
41012 "esc" : function(e){
41016 "tab" : function(e){
41019 if(this.fireEvent("specialkey", this, e)){
41020 this.onViewClick(false);
41028 doRelay : function(foo, bar, hname){
41029 if(hname == 'down' || this.scope.isExpanded()){
41030 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
41038 this.currencyEl().on("click", this.onTriggerClick, this, { preventDefault : true });
41042 initNumberEvent : function(e)
41044 this.inputEl().on("keydown" , this.fireKey, this);
41045 this.inputEl().on("focus", this.onFocus, this);
41046 this.inputEl().on("blur", this.onBlur, this);
41048 this.inputEl().relayEvent('keyup', this);
41050 if(this.indicator){
41051 this.indicator.addClass('invisible');
41054 this.originalValue = this.getValue();
41056 if(this.validationEvent == 'keyup'){
41057 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
41058 this.inputEl().on('keyup', this.filterValidation, this);
41060 else if(this.validationEvent !== false){
41061 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
41064 if(this.selectOnFocus){
41065 this.on("focus", this.preFocus, this);
41068 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
41069 this.inputEl().on("keypress", this.filterKeys, this);
41071 this.inputEl().relayEvent('keypress', this);
41074 var allowed = "0123456789";
41076 if(this.allowDecimals){
41077 allowed += this.decimalSeparator;
41080 if(this.allowNegative){
41084 if(this.thousandsDelimiter) {
41088 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
41090 var keyPress = function(e){
41092 var k = e.getKey();
41094 var c = e.getCharCode();
41097 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
41098 allowed.indexOf(String.fromCharCode(c)) === -1
41104 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
41108 if(allowed.indexOf(String.fromCharCode(c)) === -1){
41113 this.inputEl().on("keypress", keyPress, this);
41117 onTriggerClick : function(e)
41124 this.loadNext = false;
41126 if(this.isExpanded()){
41131 this.hasFocus = true;
41133 if(this.triggerAction == 'all') {
41134 this.doQuery(this.allQuery, true);
41138 this.doQuery(this.getRawValue());
41141 getCurrency : function()
41143 var v = this.currencyEl().getValue();
41148 restrictHeight : function()
41150 this.list.alignTo(this.currencyEl(), this.listAlign);
41151 this.list.alignTo(this.currencyEl(), this.listAlign);
41154 onViewClick : function(view, doFocus, el, e)
41156 var index = this.view.getSelectedIndexes()[0];
41158 var r = this.store.getAt(index);
41161 this.onSelect(r, index);
41165 onSelect : function(record, index){
41167 if(this.fireEvent('beforeselect', this, record, index) !== false){
41169 this.setFromCurrencyData(index > -1 ? record.data : false);
41173 this.fireEvent('select', this, record, index);
41177 setFromCurrencyData : function(o)
41181 this.lastCurrency = o;
41183 if (this.currencyField) {
41184 currency = !o || typeof(o[this.currencyField]) == 'undefined' ? '' : o[this.currencyField];
41186 Roo.log('no currencyField value set for '+ (this.name ? this.name : this.id));
41189 this.lastSelectionText = currency;
41191 //setting default currency
41192 if(o[this.currencyField] * 1 == 0 && this.defaultCurrency) {
41193 this.setCurrency(this.defaultCurrency);
41197 this.setCurrency(currency);
41200 setFromData : function(o)
41204 c[this.currencyField] = !o || typeof(o[this.currencyName]) == 'undefined' ? '' : o[this.currencyName];
41206 this.setFromCurrencyData(c);
41211 value = !o || typeof(o[this.name]) == 'undefined' ? '' : o[this.name];
41213 Roo.log('no value set for '+ (this.name ? this.name : this.id));
41216 this.setValue(value);
41220 setCurrency : function(v)
41222 this.currencyValue = v;
41225 this.currencyEl().dom.value = (v === null || v === undefined ? '' : v);
41230 setValue : function(v)
41232 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
41238 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
41240 this.inputEl().dom.value = (v == '') ? '' :
41241 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
41243 if(!this.allowZero && v === '0') {
41244 this.hiddenEl().dom.value = '';
41245 this.inputEl().dom.value = '';
41252 getRawValue : function()
41254 var v = this.inputEl().getValue();
41259 getValue : function()
41261 return this.fixPrecision(this.parseValue(this.getRawValue()));
41264 parseValue : function(value)
41266 if(this.thousandsDelimiter) {
41268 r = new RegExp(",", "g");
41269 value = value.replace(r, "");
41272 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
41273 return isNaN(value) ? '' : value;
41277 fixPrecision : function(value)
41279 if(this.thousandsDelimiter) {
41281 r = new RegExp(",", "g");
41282 value = value.replace(r, "");
41285 var nan = isNaN(value);
41287 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
41288 return nan ? '' : value;
41290 return parseFloat(value).toFixed(this.decimalPrecision);
41293 decimalPrecisionFcn : function(v)
41295 return Math.floor(v);
41298 validateValue : function(value)
41300 if(!Roo.bootstrap.MoneyField.superclass.validateValue.call(this, value)){
41304 var num = this.parseValue(value);
41307 this.markInvalid(String.format(this.nanText, value));
41311 if(num < this.minValue){
41312 this.markInvalid(String.format(this.minText, this.minValue));
41316 if(num > this.maxValue){
41317 this.markInvalid(String.format(this.maxText, this.maxValue));
41324 validate : function()
41326 if(this.disabled || this.allowBlank){
41331 var currency = this.getCurrency();
41333 if(this.validateValue(this.getRawValue()) && currency.length){
41338 this.markInvalid();
41342 getName: function()
41347 beforeBlur : function()
41353 var v = this.parseValue(this.getRawValue());
41360 onBlur : function()
41364 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
41365 //this.el.removeClass(this.focusClass);
41368 this.hasFocus = false;
41370 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
41374 var v = this.getValue();
41376 if(String(v) !== String(this.startValue)){
41377 this.fireEvent('change', this, v, this.startValue);
41380 this.fireEvent("blur", this);
41383 inputEl : function()
41385 return this.el.select('.roo-money-amount-input', true).first();
41388 currencyEl : function()
41390 return this.el.select('.roo-money-currency-input', true).first();
41393 hiddenEl : function()
41395 return this.el.select('input.hidden-number-input',true).first();