2 * set the version of bootstrap based on the stylesheet...
6 Roo.bootstrap.version = (
9 Roo.each(document.styleSheets[0], function(s) {
10 if (s.href.match(/css-bootstrap4/)) {
18 * base class for bootstrap elements.
22 Roo.bootstrap = Roo.bootstrap || {};
24 * @class Roo.bootstrap.Component
25 * @extends Roo.Component
26 * Bootstrap Component base class
27 * @cfg {String} cls css class
28 * @cfg {String} style any extra css
29 * @cfg {Object} xattr extra attributes to add to 'element' (used by builder to store stuff.)
30 * @cfg {Boolean} can_build_overlaid True if element can be rebuild from a HTML page
31 * @cfg {string} dataId cutomer id
32 * @cfg {string} name Specifies name attribute
33 * @cfg {string} tooltip Text for the tooltip
34 * @cfg {string} container_method method to fetch parents container element (used by NavHeaderbar - getHeaderChildContainer)
35 * @cfg {string|object} visibilityEl (el|parent) What element to use for visibility (@see getVisibilityEl())
38 * Do not use directly - it does not do anything..
39 * @param {Object} config The config object
44 Roo.bootstrap.Component = function(config){
45 Roo.bootstrap.Component.superclass.constructor.call(this, config);
49 * @event childrenrendered
50 * Fires when the children have been rendered..
51 * @param {Roo.bootstrap.Component} this
53 "childrenrendered" : true
62 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent, {
65 allowDomMove : false, // to stop relocations in parent onRender...
75 * Initialize Events for the element
77 initEvents : function() { },
83 can_build_overlaid : true,
85 container_method : false,
92 // returns the parent component..
93 return Roo.ComponentMgr.get(this.parentId)
99 onRender : function(ct, position)
101 // Roo.log("Call onRender: " + this.xtype);
103 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
106 if (this.el.attr('xtype')) {
107 this.el.attr('xtypex', this.el.attr('xtype'));
108 this.el.dom.removeAttribute('xtype');
118 var cfg = Roo.apply({}, this.getAutoCreate());
120 cfg.id = this.id || Roo.id();
122 // fill in the extra attributes
123 if (this.xattr && typeof(this.xattr) =='object') {
124 for (var i in this.xattr) {
125 cfg[i] = this.xattr[i];
130 cfg.dataId = this.dataId;
134 cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
137 if (this.style) { // fixme needs to support more complex style data.
138 cfg.style = this.style;
142 cfg.name = this.name;
145 this.el = ct.createChild(cfg, position);
148 this.tooltipEl().attr('tooltip', this.tooltip);
151 if(this.tabIndex !== undefined){
152 this.el.dom.setAttribute('tabIndex', this.tabIndex);
159 * Fetch the element to add children to
160 * @return {Roo.Element} defaults to this.el
162 getChildContainer : function()
167 * Fetch the element to display the tooltip on.
168 * @return {Roo.Element} defaults to this.el
170 tooltipEl : function()
175 addxtype : function(tree,cntr)
179 cn = Roo.factory(tree);
180 //Roo.log(['addxtype', cn]);
182 cn.parentType = this.xtype; //??
183 cn.parentId = this.id;
185 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
186 if (typeof(cn.container_method) == 'string') {
187 cntr = cn.container_method;
191 var has_flexy_each = (typeof(tree['flexy:foreach']) != 'undefined');
193 var has_flexy_if = (typeof(tree['flexy:if']) != 'undefined');
195 var build_from_html = Roo.XComponent.build_from_html;
197 var is_body = (tree.xtype == 'Body') ;
199 var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
201 var self_cntr_el = Roo.get(this[cntr](false));
203 // do not try and build conditional elements
204 if ((has_flexy_each || has_flexy_if || this.can_build_overlaid == false ) && build_from_html) {
208 if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
209 if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
210 return this.addxtypeChild(tree,cntr, is_body);
213 var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
216 return this.addxtypeChild(Roo.apply({}, tree),cntr);
219 Roo.log('skipping render');
225 if (!build_from_html) {
229 // this i think handles overlaying multiple children of the same type
230 // with the sam eelement.. - which might be buggy..
232 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
238 if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
242 ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
249 addxtypeChild : function (tree, cntr, is_body)
251 Roo.debug && Roo.log('addxtypeChild:' + cntr);
253 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
256 var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
257 (typeof(tree['flexy:foreach']) != 'undefined');
261 skip_children = false;
262 // render the element if it's not BODY.
265 // if parent was disabled, then do not try and create the children..
266 if(!this[cntr](true)){
271 cn = Roo.factory(tree);
273 cn.parentType = this.xtype; //??
274 cn.parentId = this.id;
276 var build_from_html = Roo.XComponent.build_from_html;
279 // does the container contain child eleemnts with 'xtype' attributes.
280 // that match this xtype..
281 // note - when we render we create these as well..
282 // so we should check to see if body has xtype set.
283 if (build_from_html && Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
285 var self_cntr_el = Roo.get(this[cntr](false));
286 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
288 //Roo.log(Roo.XComponent.build_from_html);
289 //Roo.log("got echild:");
292 // there is a scenario where some of the child elements are flexy:if (and all of the same type)
293 // and are not displayed -this causes this to use up the wrong element when matching.
294 // at present the only work around for this is to nest flexy:if elements in another element that is always rendered.
297 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
298 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
304 //echild.dom.removeAttribute('xtype');
306 Roo.debug && Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
307 Roo.debug && Roo.log(self_cntr_el);
308 Roo.debug && Roo.log(echild);
309 Roo.debug && Roo.log(cn);
315 // if object has flexy:if - then it may or may not be rendered.
316 if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) {
317 // skip a flexy if element.
318 Roo.debug && Roo.log('skipping render');
319 Roo.debug && Roo.log(tree);
321 Roo.debug && Roo.log('skipping all children');
322 skip_children = true;
327 // actually if flexy:foreach is found, we really want to create
328 // multiple copies here...
330 //Roo.log(this[cntr]());
331 // some elements do not have render methods.. like the layouts...
333 if(this[cntr](true) === false){
338 cn.render && cn.render(this[cntr](true));
341 // then add the element..
348 if (typeof (tree.menu) != 'undefined') {
349 tree.menu.parentType = cn.xtype;
350 tree.menu.triggerEl = cn.el;
351 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
355 if (!tree.items || !tree.items.length) {
357 //Roo.log(["no children", this]);
362 var items = tree.items;
365 //Roo.log(items.length);
367 if (!skip_children) {
368 for(var i =0;i < items.length;i++) {
369 // Roo.log(['add child', items[i]]);
370 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
376 //Roo.log("fire childrenrendered");
378 cn.fireEvent('childrenrendered', this);
384 * Set the element that will be used to show or hide
386 setVisibilityEl : function(el)
388 this.visibilityEl = el;
392 * Get the element that will be used to show or hide
394 getVisibilityEl : function()
396 if (typeof(this.visibilityEl) == 'object') {
397 return this.visibilityEl;
400 if (typeof(this.visibilityEl) == 'string') {
401 return this.visibilityEl == 'parent' ? this.parent().getEl() : this.getEl();
408 * Show a component - removes 'hidden' class
412 if(!this.getVisibilityEl()){
416 this.getVisibilityEl().removeClass('hidden');
418 this.fireEvent('show', this);
423 * Hide a component - adds 'hidden' class
427 if(!this.getVisibilityEl()){
431 this.getVisibilityEl().addClass('hidden');
433 this.fireEvent('hide', this);
446 * @class Roo.bootstrap.Body
447 * @extends Roo.bootstrap.Component
448 * Bootstrap Body class
452 * @param {Object} config The config object
455 Roo.bootstrap.Body = function(config){
457 config = config || {};
459 Roo.bootstrap.Body.superclass.constructor.call(this, config);
460 this.el = Roo.get(config.el ? config.el : document.body );
461 if (this.cls && this.cls.length) {
462 Roo.get(document.body).addClass(this.cls);
466 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
468 is_body : true,// just to make sure it's constructed?
473 onRender : function(ct, position)
475 /* Roo.log("Roo.bootstrap.Body - onRender");
476 if (this.cls && this.cls.length) {
477 Roo.get(document.body).addClass(this.cls);
496 * @class Roo.bootstrap.ButtonGroup
497 * @extends Roo.bootstrap.Component
498 * Bootstrap ButtonGroup class
499 * @cfg {String} size lg | sm | xs (default empty normal)
500 * @cfg {String} align vertical | justified (default none)
501 * @cfg {String} direction up | down (default down)
502 * @cfg {Boolean} toolbar false | true
503 * @cfg {Boolean} btn true | false
508 * @param {Object} config The config object
511 Roo.bootstrap.ButtonGroup = function(config){
512 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
515 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
523 getAutoCreate : function(){
529 cfg.html = this.html || cfg.html;
540 if (['vertical','justified'].indexOf(this.align)!==-1) {
541 cfg.cls = 'btn-group-' + this.align;
543 if (this.align == 'justified') {
544 console.log(this.items);
548 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
549 cfg.cls += ' btn-group-' + this.size;
552 if (this.direction == 'up') {
553 cfg.cls += ' dropup' ;
559 * Add a button to the group (similar to NavItem API.)
561 addItem : function(cfg)
563 var cn = new Roo.bootstrap.Button(cfg);
565 cn.parentId = this.id;
566 cn.onRender(this.el, null);
580 * @class Roo.bootstrap.Button
581 * @extends Roo.bootstrap.Component
582 * Bootstrap Button class
583 * @cfg {String} html The button content
584 * @cfg {String} weight (default | primary | secondary | success | info | warning | danger | link ) default
585 * @cfg {String} badge_weight (default | primary | secondary | success | info | warning | danger | link ) default (same as button)
586 * @cfg {Boolean} outline default false (except for weight=default which emulates old behaveiour with an outline)
587 * @cfg {String} size ( lg | sm | xs)
588 * @cfg {String} tag ( a | input | submit)
589 * @cfg {String} href empty or href
590 * @cfg {Boolean} disabled default false;
591 * @cfg {Boolean} isClose default false;
592 * @cfg {String} glyphicon depricated - use fs
593 * @cfg {String} badge text for badge
594 * @cfg {String} theme (default|glow)
595 * @cfg {Boolean} inverse dark themed version
596 * @cfg {Boolean} toggle is it a slidy toggle button
597 * @cfg {Boolean} pressed (true|false) default null - if the button ahs active state
598 * @cfg {String} ontext text for on slidy toggle state
599 * @cfg {String} offtext text for off slidy toggle state
600 * @cfg {Boolean} preventDefault default true (stop click event triggering the URL if it's a link.)
601 * @cfg {Boolean} removeClass remove the standard class..
602 * @cfg {String} target target for a href. (_self|_blank|_parent|_top| other)
605 * Create a new button
606 * @param {Object} config The config object
610 Roo.bootstrap.Button = function(config){
611 Roo.bootstrap.Button.superclass.constructor.call(this, config);
612 this.weightClass = ["btn-default btn-outline-secondary",
624 * When a butotn is pressed
625 * @param {Roo.bootstrap.Button} btn
626 * @param {Roo.EventObject} e
631 * After the button has been toggles
632 * @param {Roo.bootstrap.Button} btn
633 * @param {Roo.EventObject} e
634 * @param {boolean} pressed (also available as button.pressed)
640 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
661 preventDefault: true,
669 getAutoCreate : function(){
677 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
678 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
683 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
685 if (this.toggle == true) {
688 cls: 'slider-frame roo-button',
693 'data-off-text':'OFF',
694 cls: 'slider-button',
700 if (['default', 'secondary' , 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
701 cfg.cls += ' '+this.weight;
710 cfg["aria-hidden"] = true;
712 cfg.html = "×";
718 if (this.theme==='default') {
719 cfg.cls = 'btn roo-button';
721 //if (this.parentType != 'Navbar') {
722 this.weight = this.weight.length ? this.weight : 'default';
724 if (['default', 'primary', 'secondary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
726 var outline = this.outline || this.weight == 'default' ? 'outline-' : '';
727 var weight = this.weight == 'default' ? 'secondary' : this.weight;
728 cfg.cls += ' btn-' + outline + weight;
729 if (this.weight == 'default') {
731 cfg.cls += ' btn-' + this.weight;
734 } else if (this.theme==='glow') {
737 cfg.cls = 'btn-glow roo-button';
739 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
741 cfg.cls += ' ' + this.weight;
747 this.cls += ' inverse';
751 if (this.active || this.pressed === true) {
752 cfg.cls += ' active';
756 cfg.disabled = 'disabled';
760 Roo.log('changing to ul' );
762 this.glyphicon = 'caret';
763 if (Roo.bootstrap.version == 4) {
764 this.fa = 'caret-down';
769 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
771 //gsRoo.log(this.parentType);
772 if (this.parentType === 'Navbar' && !this.parent().bar) {
773 Roo.log('changing to li?');
782 href : this.href || '#'
785 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
786 cfg.cls += ' dropdown';
793 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
795 if (this.glyphicon) {
796 cfg.html = ' ' + cfg.html;
801 cls: 'glyphicon glyphicon-' + this.glyphicon
806 cfg.html = ' ' + cfg.html;
811 cls: 'fa fas fa-' + this.fa
821 // cfg.cls='btn roo-button';
825 var value = cfg.html;
830 cls: 'glyphicon glyphicon-' + this.glyphicon,
837 cls: 'fa fas fa-' + this.fa,
842 var bw = this.badge_weight.length ? this.badge_weight :
843 (this.weight.length ? this.weight : 'secondary');
844 bw = bw == 'default' ? 'secondary' : bw;
850 cls: 'badge badge-' + bw,
859 cfg.cls += ' dropdown';
860 cfg.html = typeof(cfg.html) != 'undefined' ?
861 cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
864 if (cfg.tag !== 'a' && this.href !== '') {
865 throw "Tag must be a to set href.";
866 } else if (this.href.length > 0) {
867 cfg.href = this.href;
870 if(this.removeClass){
875 cfg.target = this.target;
880 initEvents: function() {
881 // Roo.log('init events?');
882 // Roo.log(this.el.dom);
885 if (typeof (this.menu) != 'undefined') {
886 this.menu.parentType = this.xtype;
887 this.menu.triggerEl = this.el;
888 this.addxtype(Roo.apply({}, this.menu));
892 if (this.el.hasClass('roo-button')) {
893 this.el.on('click', this.onClick, this);
895 this.el.select('.roo-button').on('click', this.onClick, this);
898 if(this.removeClass){
899 this.el.on('click', this.onClick, this);
902 this.el.enableDisplayMode();
905 onClick : function(e)
911 Roo.log('button on click ');
912 if(this.preventDefault){
916 if (this.pressed === true || this.pressed === false) {
917 this.toggleActive(e);
921 this.fireEvent('click', this, e);
925 * Enables this button
929 this.disabled = false;
930 this.el.removeClass('disabled');
934 * Disable this button
938 this.disabled = true;
939 this.el.addClass('disabled');
942 * sets the active state on/off,
943 * @param {Boolean} state (optional) Force a particular state
945 setActive : function(v) {
947 this.el[v ? 'addClass' : 'removeClass']('active');
951 * toggles the current active state
953 toggleActive : function(e)
955 this.setActive(!this.pressed);
956 this.fireEvent('toggle', this, e, !this.pressed);
959 * get the current active state
960 * @return {boolean} true if it's active
962 isActive : function()
964 return this.el.hasClass('active');
967 * set the text of the first selected button
969 setText : function(str)
971 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
974 * get the text of the first selected button
978 return this.el.select('.roo-button-text',true).first().dom.innerHTML;
981 setWeight : function(str)
983 this.el.removeClass(this.weightClass);
985 var outline = this.outline ? 'outline-' : '';
986 if (str == 'default') {
987 this.el.addClass('btn-default btn-outline-secondary');
990 this.el.addClass('btn-' + outline + str);
1004 * @class Roo.bootstrap.Column
1005 * @extends Roo.bootstrap.Component
1006 * Bootstrap Column class
1007 * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
1008 * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
1009 * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
1010 * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
1011 * @cfg {Number} xsoff colspan offset out of 12 for mobile-sized screens or 0 for hidden
1012 * @cfg {Number} smoff colspan offset out of 12 for tablet-sized screens or 0 for hidden
1013 * @cfg {Number} mdoff colspan offset out of 12 for computer-sized screens or 0 for hidden
1014 * @cfg {Number} lgoff colspan offset out of 12 for large computer-sized screens or 0 for hidden
1017 * @cfg {Boolean} hidden (true|false) hide the element
1018 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
1019 * @cfg {String} fa (ban|check|...) font awesome icon
1020 * @cfg {Number} fasize (1|2|....) font awsome size
1022 * @cfg {String} icon (info-sign|check|...) glyphicon name
1024 * @cfg {String} html content of column.
1027 * Create a new Column
1028 * @param {Object} config The config object
1031 Roo.bootstrap.Column = function(config){
1032 Roo.bootstrap.Column.superclass.constructor.call(this, config);
1035 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
1053 getAutoCreate : function(){
1054 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
1062 ['xs','sm','md','lg'].map(function(size){
1063 //Roo.log( size + ':' + settings[size]);
1065 if (settings[size+'off'] !== false) {
1066 cfg.cls += ' col-' + size + '-offset-' + settings[size+'off'] ;
1069 if (settings[size] === false) {
1073 if (!settings[size]) { // 0 = hidden
1074 cfg.cls += ' hidden-' + size;
1077 cfg.cls += ' col-' + size + '-' + settings[size];
1082 cfg.cls += ' hidden';
1085 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1086 cfg.cls +=' alert alert-' + this.alert;
1090 if (this.html.length) {
1091 cfg.html = this.html;
1095 if (this.fasize > 1) {
1096 fasize = ' fa-' + this.fasize + 'x';
1098 cfg.html = '<i class="fa fa-'+this.fa + fasize + '"></i>' + (cfg.html || '');
1103 cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + (cfg.html || '');
1122 * @class Roo.bootstrap.Container
1123 * @extends Roo.bootstrap.Component
1124 * Bootstrap Container class
1125 * @cfg {Boolean} jumbotron is it a jumbotron element
1126 * @cfg {String} html content of element
1127 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
1128 * @cfg {String} panel (default|primary|success|info|warning|danger) render as panel - type - primary/success.....
1129 * @cfg {String} header content of header (for panel)
1130 * @cfg {String} footer content of footer (for panel)
1131 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
1132 * @cfg {String} tag (header|aside|section) type of HTML tag.
1133 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
1134 * @cfg {String} fa font awesome icon
1135 * @cfg {String} icon (info-sign|check|...) glyphicon name
1136 * @cfg {Boolean} hidden (true|false) hide the element
1137 * @cfg {Boolean} expandable (true|false) default false
1138 * @cfg {Boolean} expanded (true|false) default true
1139 * @cfg {String} rheader contet on the right of header
1140 * @cfg {Boolean} clickable (true|false) default false
1144 * Create a new Container
1145 * @param {Object} config The config object
1148 Roo.bootstrap.Container = function(config){
1149 Roo.bootstrap.Container.superclass.constructor.call(this, config);
1155 * After the panel has been expand
1157 * @param {Roo.bootstrap.Container} this
1162 * After the panel has been collapsed
1164 * @param {Roo.bootstrap.Container} this
1169 * When a element is chick
1170 * @param {Roo.bootstrap.Container} this
1171 * @param {Roo.EventObject} e
1177 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
1195 getChildContainer : function() {
1201 if (this.panel.length) {
1202 return this.el.select('.panel-body',true).first();
1209 getAutoCreate : function(){
1212 tag : this.tag || 'div',
1216 if (this.jumbotron) {
1217 cfg.cls = 'jumbotron';
1222 // - this is applied by the parent..
1224 // cfg.cls = this.cls + '';
1227 if (this.sticky.length) {
1229 var bd = Roo.get(document.body);
1230 if (!bd.hasClass('bootstrap-sticky')) {
1231 bd.addClass('bootstrap-sticky');
1232 Roo.select('html',true).setStyle('height', '100%');
1235 cfg.cls += 'bootstrap-sticky-' + this.sticky;
1239 if (this.well.length) {
1240 switch (this.well) {
1243 cfg.cls +=' well well-' +this.well;
1252 cfg.cls += ' hidden';
1256 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1257 cfg.cls +=' alert alert-' + this.alert;
1262 if (this.panel.length) {
1263 cfg.cls += ' panel panel-' + this.panel;
1265 if (this.header.length) {
1269 if(this.expandable){
1271 cfg.cls = cfg.cls + ' expandable';
1275 cls: (this.expanded ? 'fa fa-minus' : 'fa fa-plus')
1283 cls : 'panel-title',
1284 html : (this.expandable ? ' ' : '') + this.header
1288 cls: 'panel-header-right',
1294 cls : 'panel-heading',
1295 style : this.expandable ? 'cursor: pointer' : '',
1303 cls : 'panel-body' + (this.expanded ? '' : ' hide'),
1308 if (this.footer.length) {
1310 cls : 'panel-footer',
1319 body.html = this.html || cfg.html;
1320 // prefix with the icons..
1322 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1325 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1330 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1331 cfg.cls = 'container';
1337 initEvents: function()
1339 if(this.expandable){
1340 var headerEl = this.headerEl();
1343 headerEl.on('click', this.onToggleClick, this);
1348 this.el.on('click', this.onClick, this);
1353 onToggleClick : function()
1355 var headerEl = this.headerEl();
1371 if(this.fireEvent('expand', this)) {
1373 this.expanded = true;
1375 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).show();
1377 this.el.select('.panel-body',true).first().removeClass('hide');
1379 var toggleEl = this.toggleEl();
1385 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-minus']);
1390 collapse : function()
1392 if(this.fireEvent('collapse', this)) {
1394 this.expanded = false;
1396 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).hide();
1397 this.el.select('.panel-body',true).first().addClass('hide');
1399 var toggleEl = this.toggleEl();
1405 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-plus']);
1409 toggleEl : function()
1411 if(!this.el || !this.panel.length || !this.header.length || !this.expandable){
1415 return this.el.select('.panel-heading .fa',true).first();
1418 headerEl : function()
1420 if(!this.el || !this.panel.length || !this.header.length){
1424 return this.el.select('.panel-heading',true).first()
1429 if(!this.el || !this.panel.length){
1433 return this.el.select('.panel-body',true).first()
1436 titleEl : function()
1438 if(!this.el || !this.panel.length || !this.header.length){
1442 return this.el.select('.panel-title',true).first();
1445 setTitle : function(v)
1447 var titleEl = this.titleEl();
1453 titleEl.dom.innerHTML = v;
1456 getTitle : function()
1459 var titleEl = this.titleEl();
1465 return titleEl.dom.innerHTML;
1468 setRightTitle : function(v)
1470 var t = this.el.select('.panel-header-right',true).first();
1476 t.dom.innerHTML = v;
1479 onClick : function(e)
1483 this.fireEvent('click', this, e);
1496 * @class Roo.bootstrap.Img
1497 * @extends Roo.bootstrap.Component
1498 * Bootstrap Img class
1499 * @cfg {Boolean} imgResponsive false | true
1500 * @cfg {String} border rounded | circle | thumbnail
1501 * @cfg {String} src image source
1502 * @cfg {String} alt image alternative text
1503 * @cfg {String} href a tag href
1504 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1505 * @cfg {String} xsUrl xs image source
1506 * @cfg {String} smUrl sm image source
1507 * @cfg {String} mdUrl md image source
1508 * @cfg {String} lgUrl lg image source
1511 * Create a new Input
1512 * @param {Object} config The config object
1515 Roo.bootstrap.Img = function(config){
1516 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1522 * The img click event for the img.
1523 * @param {Roo.EventObject} e
1529 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1531 imgResponsive: true,
1541 getAutoCreate : function()
1543 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1544 return this.createSingleImg();
1549 cls: 'roo-image-responsive-group',
1554 Roo.each(['xs', 'sm', 'md', 'lg'], function(size){
1556 if(!_this[size + 'Url']){
1562 cls: (_this.imgResponsive) ? 'img-responsive' : '',
1563 html: _this.html || cfg.html,
1564 src: _this[size + 'Url']
1567 img.cls += ' roo-image-responsive-' + size;
1569 var s = ['xs', 'sm', 'md', 'lg'];
1571 s.splice(s.indexOf(size), 1);
1573 Roo.each(s, function(ss){
1574 img.cls += ' hidden-' + ss;
1577 if (['rounded','circle','thumbnail'].indexOf(_this.border)>-1) {
1578 cfg.cls += ' img-' + _this.border;
1582 cfg.alt = _this.alt;
1595 a.target = _this.target;
1599 cfg.cn.push((_this.href) ? a : img);
1606 createSingleImg : function()
1610 cls: (this.imgResponsive) ? 'img-responsive' : '',
1612 src : 'about:blank' // just incase src get's set to undefined?!?
1615 cfg.html = this.html || cfg.html;
1617 cfg.src = this.src || cfg.src;
1619 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1620 cfg.cls += ' img-' + this.border;
1637 a.target = this.target;
1642 return (this.href) ? a : cfg;
1645 initEvents: function()
1648 this.el.on('click', this.onClick, this);
1653 onClick : function(e)
1655 Roo.log('img onclick');
1656 this.fireEvent('click', this, e);
1659 * Sets the url of the image - used to update it
1660 * @param {String} url the url of the image
1663 setSrc : function(url)
1667 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1668 this.el.dom.src = url;
1672 this.el.select('img', true).first().dom.src = url;
1688 * @class Roo.bootstrap.Link
1689 * @extends Roo.bootstrap.Component
1690 * Bootstrap Link Class
1691 * @cfg {String} alt image alternative text
1692 * @cfg {String} href a tag href
1693 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1694 * @cfg {String} html the content of the link.
1695 * @cfg {String} anchor name for the anchor link
1696 * @cfg {String} fa - favicon
1698 * @cfg {Boolean} preventDefault (true | false) default false
1702 * Create a new Input
1703 * @param {Object} config The config object
1706 Roo.bootstrap.Link = function(config){
1707 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1713 * The img click event for the img.
1714 * @param {Roo.EventObject} e
1720 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1724 preventDefault: false,
1730 getAutoCreate : function()
1732 var html = this.html || '';
1734 if (this.fa !== false) {
1735 html = '<i class="fa fa-' + this.fa + '"></i>';
1740 // anchor's do not require html/href...
1741 if (this.anchor === false) {
1743 cfg.href = this.href || '#';
1745 cfg.name = this.anchor;
1746 if (this.html !== false || this.fa !== false) {
1749 if (this.href !== false) {
1750 cfg.href = this.href;
1754 if(this.alt !== false){
1759 if(this.target !== false) {
1760 cfg.target = this.target;
1766 initEvents: function() {
1768 if(!this.href || this.preventDefault){
1769 this.el.on('click', this.onClick, this);
1773 onClick : function(e)
1775 if(this.preventDefault){
1778 //Roo.log('img onclick');
1779 this.fireEvent('click', this, e);
1792 * @class Roo.bootstrap.Header
1793 * @extends Roo.bootstrap.Component
1794 * Bootstrap Header class
1795 * @cfg {String} html content of header
1796 * @cfg {Number} level (1|2|3|4|5|6) default 1
1799 * Create a new Header
1800 * @param {Object} config The config object
1804 Roo.bootstrap.Header = function(config){
1805 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1808 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1816 getAutoCreate : function(){
1821 tag: 'h' + (1 *this.level),
1822 html: this.html || ''
1834 * Ext JS Library 1.1.1
1835 * Copyright(c) 2006-2007, Ext JS, LLC.
1837 * Originally Released Under LGPL - original licence link has changed is not relivant.
1840 * <script type="text/javascript">
1844 * @class Roo.bootstrap.MenuMgr
1845 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1848 Roo.bootstrap.MenuMgr = function(){
1849 var menus, active, groups = {}, attached = false, lastShow = new Date();
1851 // private - called when first menu is created
1854 active = new Roo.util.MixedCollection();
1855 Roo.get(document).addKeyListener(27, function(){
1856 if(active.length > 0){
1864 if(active && active.length > 0){
1865 var c = active.clone();
1875 if(active.length < 1){
1876 Roo.get(document).un("mouseup", onMouseDown);
1884 var last = active.last();
1885 lastShow = new Date();
1888 Roo.get(document).on("mouseup", onMouseDown);
1893 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1894 m.parentMenu.activeChild = m;
1895 }else if(last && last.isVisible()){
1896 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1901 function onBeforeHide(m){
1903 m.activeChild.hide();
1905 if(m.autoHideTimer){
1906 clearTimeout(m.autoHideTimer);
1907 delete m.autoHideTimer;
1912 function onBeforeShow(m){
1913 var pm = m.parentMenu;
1914 if(!pm && !m.allowOtherMenus){
1916 }else if(pm && pm.activeChild && active != m){
1917 pm.activeChild.hide();
1921 // private this should really trigger on mouseup..
1922 function onMouseDown(e){
1923 Roo.log("on Mouse Up");
1925 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".dropdown-menu") && !e.getTarget('.user-menu')){
1926 Roo.log("MenuManager hideAll");
1935 function onBeforeCheck(mi, state){
1937 var g = groups[mi.group];
1938 for(var i = 0, l = g.length; i < l; i++){
1940 g[i].setChecked(false);
1949 * Hides all menus that are currently visible
1951 hideAll : function(){
1956 register : function(menu){
1960 menus[menu.id] = menu;
1961 menu.on("beforehide", onBeforeHide);
1962 menu.on("hide", onHide);
1963 menu.on("beforeshow", onBeforeShow);
1964 menu.on("show", onShow);
1966 if(g && menu.events["checkchange"]){
1970 groups[g].push(menu);
1971 menu.on("checkchange", onCheck);
1976 * Returns a {@link Roo.menu.Menu} object
1977 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1978 * be used to generate and return a new Menu instance.
1980 get : function(menu){
1981 if(typeof menu == "string"){ // menu id
1983 }else if(menu.events){ // menu instance
1986 /*else if(typeof menu.length == 'number'){ // array of menu items?
1987 return new Roo.bootstrap.Menu({items:menu});
1988 }else{ // otherwise, must be a config
1989 return new Roo.bootstrap.Menu(menu);
1996 unregister : function(menu){
1997 delete menus[menu.id];
1998 menu.un("beforehide", onBeforeHide);
1999 menu.un("hide", onHide);
2000 menu.un("beforeshow", onBeforeShow);
2001 menu.un("show", onShow);
2003 if(g && menu.events["checkchange"]){
2004 groups[g].remove(menu);
2005 menu.un("checkchange", onCheck);
2010 registerCheckable : function(menuItem){
2011 var g = menuItem.group;
2016 groups[g].push(menuItem);
2017 menuItem.on("beforecheckchange", onBeforeCheck);
2022 unregisterCheckable : function(menuItem){
2023 var g = menuItem.group;
2025 groups[g].remove(menuItem);
2026 menuItem.un("beforecheckchange", onBeforeCheck);
2038 * @class Roo.bootstrap.Menu
2039 * @extends Roo.bootstrap.Component
2040 * Bootstrap Menu class - container for MenuItems
2041 * @cfg {String} type (dropdown|treeview|submenu) type of menu
2042 * @cfg {bool} hidden if the menu should be hidden when rendered.
2043 * @cfg {bool} stopEvent (true|false) Stop event after trigger press (default true)
2044 * @cfg {bool} isLink (true|false) the menu has link disable auto expand and collaspe (default false)
2048 * @param {Object} config The config object
2052 Roo.bootstrap.Menu = function(config){
2053 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
2054 if (this.registerMenu && this.type != 'treeview') {
2055 Roo.bootstrap.MenuMgr.register(this);
2062 * Fires before this menu is displayed
2063 * @param {Roo.menu.Menu} this
2068 * Fires before this menu is hidden
2069 * @param {Roo.menu.Menu} this
2074 * Fires after this menu is displayed
2075 * @param {Roo.menu.Menu} this
2080 * Fires after this menu is hidden
2081 * @param {Roo.menu.Menu} this
2086 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
2087 * @param {Roo.menu.Menu} this
2088 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2089 * @param {Roo.EventObject} e
2094 * Fires when the mouse is hovering over this menu
2095 * @param {Roo.menu.Menu} this
2096 * @param {Roo.EventObject} e
2097 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2102 * Fires when the mouse exits this menu
2103 * @param {Roo.menu.Menu} this
2104 * @param {Roo.EventObject} e
2105 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2110 * Fires when a menu item contained in this menu is clicked
2111 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
2112 * @param {Roo.EventObject} e
2116 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
2119 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
2123 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
2126 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
2128 registerMenu : true,
2130 menuItems :false, // stores the menu items..
2140 getChildContainer : function() {
2144 getAutoCreate : function(){
2146 //if (['right'].indexOf(this.align)!==-1) {
2147 // cfg.cn[1].cls += ' pull-right'
2153 cls : 'dropdown-menu' ,
2154 style : 'z-index:1000'
2158 if (this.type === 'submenu') {
2159 cfg.cls = 'submenu active';
2161 if (this.type === 'treeview') {
2162 cfg.cls = 'treeview-menu';
2167 initEvents : function() {
2169 // Roo.log("ADD event");
2170 // Roo.log(this.triggerEl.dom);
2172 this.triggerEl.on('click', this.onTriggerClick, this);
2174 this.triggerEl.on(Roo.isTouch ? 'touchstart' : 'mouseup', this.onTriggerPress, this);
2177 if (this.triggerEl.hasClass('nav-item')) {
2178 // dropdown toggle on the 'a' in BS4?
2179 this.triggerEl.select('.nav-link',true).first().addClass('dropdown-toggle');
2181 this.triggerEl.addClass('dropdown-toggle');
2184 this.el.on('touchstart' , this.onTouch, this);
2186 this.el.on('click' , this.onClick, this);
2188 this.el.on("mouseover", this.onMouseOver, this);
2189 this.el.on("mouseout", this.onMouseOut, this);
2193 findTargetItem : function(e)
2195 var t = e.getTarget(".dropdown-menu-item", this.el, true);
2199 //Roo.log(t); Roo.log(t.id);
2201 //Roo.log(this.menuitems);
2202 return this.menuitems.get(t.id);
2204 //return this.items.get(t.menuItemId);
2210 onTouch : function(e)
2212 Roo.log("menu.onTouch");
2213 //e.stopEvent(); this make the user popdown broken
2217 onClick : function(e)
2219 Roo.log("menu.onClick");
2221 var t = this.findTargetItem(e);
2222 if(!t || t.isContainer){
2227 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
2228 if(t == this.activeItem && t.shouldDeactivate(e)){
2229 this.activeItem.deactivate();
2230 delete this.activeItem;
2234 this.setActiveItem(t, true);
2242 Roo.log('pass click event');
2246 this.fireEvent("click", this, t, e);
2250 if(!t.href.length || t.href == '#'){
2251 (function() { _this.hide(); }).defer(100);
2256 onMouseOver : function(e){
2257 var t = this.findTargetItem(e);
2260 // if(t.canActivate && !t.disabled){
2261 // this.setActiveItem(t, true);
2265 this.fireEvent("mouseover", this, e, t);
2267 isVisible : function(){
2268 return !this.hidden;
2270 onMouseOut : function(e){
2271 var t = this.findTargetItem(e);
2274 // if(t == this.activeItem && t.shouldDeactivate(e)){
2275 // this.activeItem.deactivate();
2276 // delete this.activeItem;
2279 this.fireEvent("mouseout", this, e, t);
2284 * Displays this menu relative to another element
2285 * @param {String/HTMLElement/Roo.Element} element The element to align to
2286 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
2287 * the element (defaults to this.defaultAlign)
2288 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2290 show : function(el, pos, parentMenu){
2291 this.parentMenu = parentMenu;
2295 this.fireEvent("beforeshow", this);
2296 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
2299 * Displays this menu at a specific xy position
2300 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
2301 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2303 showAt : function(xy, parentMenu, /* private: */_e){
2304 this.parentMenu = parentMenu;
2309 this.fireEvent("beforeshow", this);
2310 //xy = this.el.adjustForConstraints(xy);
2314 this.hideMenuItems();
2315 this.hidden = false;
2316 this.triggerEl.addClass('open');
2317 this.el.addClass('show');
2319 // reassign x when hitting right
2320 if(this.el.getWidth() + xy[0] >= Roo.lib.Dom.getViewWidth()){
2321 xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
2324 // reassign y when hitting bottom
2325 if(this.el.getHeight() + xy[1] >= Roo.lib.Dom.getViewHeight()){
2326 xy[1] = xy[1] - this.el.getHeight() - this.triggerEl.getHeight();
2329 // but the list may align on trigger left or trigger top... should it be a properity?
2331 if(this.el.getStyle('top') != 'auto' && this.el.getStyle('top').slice(-1) != "%"){
2336 this.fireEvent("show", this);
2342 this.doFocus.defer(50, this);
2346 doFocus : function(){
2348 this.focusEl.focus();
2353 * Hides this menu and optionally all parent menus
2354 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
2356 hide : function(deep)
2359 this.hideMenuItems();
2360 if(this.el && this.isVisible()){
2361 this.fireEvent("beforehide", this);
2362 if(this.activeItem){
2363 this.activeItem.deactivate();
2364 this.activeItem = null;
2366 this.triggerEl.removeClass('open');;
2367 this.el.removeClass('show');
2369 this.fireEvent("hide", this);
2371 if(deep === true && this.parentMenu){
2372 this.parentMenu.hide(true);
2376 onTriggerClick : function(e)
2378 Roo.log('trigger click');
2380 var target = e.getTarget();
2382 Roo.log(target.nodeName.toLowerCase());
2384 if(target.nodeName.toLowerCase() === 'i'){
2390 onTriggerPress : function(e)
2392 Roo.log('trigger press');
2393 //Roo.log(e.getTarget());
2394 // Roo.log(this.triggerEl.dom);
2396 // trigger only occurs on normal menu's -- if it's a treeview or dropdown... do not hide/show..
2397 var pel = Roo.get(e.getTarget());
2398 if (pel.findParent('.dropdown-menu') || pel.findParent('.treeview-menu') ) {
2399 Roo.log('is treeview or dropdown?');
2403 if(e.getTarget().nodeName.toLowerCase() !== 'i' && this.isLink){
2407 if (this.isVisible()) {
2412 this.show(this.triggerEl, false, false);
2415 if(this.stopEvent || e.getTarget().nodeName.toLowerCase() === 'i'){
2422 hideMenuItems : function()
2424 Roo.log("hide Menu Items");
2428 //$(backdrop).remove()
2429 this.el.select('.open',true).each(function(aa) {
2431 aa.removeClass('open');
2432 //var parent = getParent($(this))
2433 //var relatedTarget = { relatedTarget: this }
2435 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
2436 //if (e.isDefaultPrevented()) return
2437 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
2440 addxtypeChild : function (tree, cntr) {
2441 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
2443 this.menuitems.add(comp);
2455 this.getEl().dom.innerHTML = '';
2456 this.menuitems.clear();
2470 * @class Roo.bootstrap.MenuItem
2471 * @extends Roo.bootstrap.Component
2472 * Bootstrap MenuItem class
2473 * @cfg {String} html the menu label
2474 * @cfg {String} href the link
2475 * @cfg {Boolean} preventDefault do not trigger A href on clicks (default false).
2476 * @cfg {Boolean} isContainer is it a container - just returns a drop down item..
2477 * @cfg {Boolean} active used on sidebars to highlight active itesm
2478 * @cfg {String} fa favicon to show on left of menu item.
2479 * @cfg {Roo.bootsrap.Menu} menu the child menu.
2483 * Create a new MenuItem
2484 * @param {Object} config The config object
2488 Roo.bootstrap.MenuItem = function(config){
2489 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
2494 * The raw click event for the entire grid.
2495 * @param {Roo.bootstrap.MenuItem} this
2496 * @param {Roo.EventObject} e
2502 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
2506 preventDefault: false,
2507 isContainer : false,
2511 getAutoCreate : function(){
2513 if(this.isContainer){
2516 cls: 'dropdown-menu-item dropdown-item'
2530 if (this.fa !== false) {
2533 cls : 'fa fa-' + this.fa
2542 cls: 'dropdown-menu-item dropdown-item',
2545 if (this.parent().type == 'treeview') {
2546 cfg.cls = 'treeview-menu';
2549 cfg.cls += ' active';
2554 anc.href = this.href || cfg.cn[0].href ;
2555 ctag.html = this.html || cfg.cn[0].html ;
2559 initEvents: function()
2561 if (this.parent().type == 'treeview') {
2562 this.el.select('a').on('click', this.onClick, this);
2566 this.menu.parentType = this.xtype;
2567 this.menu.triggerEl = this.el;
2568 this.menu = this.addxtype(Roo.apply({}, this.menu));
2572 onClick : function(e)
2574 Roo.log('item on click ');
2576 if(this.preventDefault){
2579 //this.parent().hideMenuItems();
2581 this.fireEvent('click', this, e);
2600 * @class Roo.bootstrap.MenuSeparator
2601 * @extends Roo.bootstrap.Component
2602 * Bootstrap MenuSeparator class
2605 * Create a new MenuItem
2606 * @param {Object} config The config object
2610 Roo.bootstrap.MenuSeparator = function(config){
2611 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2614 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2616 getAutoCreate : function(){
2635 * @class Roo.bootstrap.Modal
2636 * @extends Roo.bootstrap.Component
2637 * Bootstrap Modal class
2638 * @cfg {String} title Title of dialog
2639 * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2640 * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method adn
2641 * @cfg {Boolean} specificTitle default false
2642 * @cfg {Array} buttons Array of buttons or standard button set..
2643 * @cfg {String} buttonPosition (left|right|center) default right
2644 * @cfg {Boolean} animate default true
2645 * @cfg {Boolean} allow_close default true
2646 * @cfg {Boolean} fitwindow default false
2647 * @cfg {String} size (sm|lg) default empty
2648 * @cfg {Number} max_width set the max width of modal
2652 * Create a new Modal Dialog
2653 * @param {Object} config The config object
2656 Roo.bootstrap.Modal = function(config){
2657 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2662 * The raw btnclick event for the button
2663 * @param {Roo.EventObject} e
2668 * Fire when dialog resize
2669 * @param {Roo.bootstrap.Modal} this
2670 * @param {Roo.EventObject} e
2674 this.buttons = this.buttons || [];
2677 this.tmpl = Roo.factory(this.tmpl);
2682 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2684 title : 'test dialog',
2694 specificTitle: false,
2696 buttonPosition: 'right',
2719 onRender : function(ct, position)
2721 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2724 var cfg = Roo.apply({}, this.getAutoCreate());
2727 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2729 //if (!cfg.name.length) {
2733 cfg.cls += ' ' + this.cls;
2736 cfg.style = this.style;
2738 this.el = Roo.get(document.body).createChild(cfg, position);
2740 //var type = this.el.dom.type;
2743 if(this.tabIndex !== undefined){
2744 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2747 this.dialogEl = this.el.select('.modal-dialog',true).first();
2748 this.bodyEl = this.el.select('.modal-body',true).first();
2749 this.closeEl = this.el.select('.modal-header .close', true).first();
2750 this.headerEl = this.el.select('.modal-header',true).first();
2751 this.titleEl = this.el.select('.modal-title',true).first();
2752 this.footerEl = this.el.select('.modal-footer',true).first();
2754 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2756 //this.el.addClass("x-dlg-modal");
2758 if (this.buttons.length) {
2759 Roo.each(this.buttons, function(bb) {
2760 var b = Roo.apply({}, bb);
2761 b.xns = b.xns || Roo.bootstrap;
2762 b.xtype = b.xtype || 'Button';
2763 if (typeof(b.listeners) == 'undefined') {
2764 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2767 var btn = Roo.factory(b);
2769 btn.render(this.el.select('.modal-footer div').first());
2773 // render the children.
2776 if(typeof(this.items) != 'undefined'){
2777 var items = this.items;
2780 for(var i =0;i < items.length;i++) {
2781 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2785 this.items = nitems;
2787 // where are these used - they used to be body/close/footer
2791 //this.el.addClass([this.fieldClass, this.cls]);
2795 getAutoCreate : function()
2799 html : this.html || ''
2804 cls : 'modal-title',
2808 if(this.specificTitle){
2814 if (this.allow_close && Roo.bootstrap.version == 3) {
2824 if (this.allow_close && Roo.bootstrap.version == 4) {
2834 if(this.size.length){
2835 size = 'modal-' + this.size;
2842 cls: "modal-dialog " + size,
2845 cls : "modal-content",
2848 cls : 'modal-header',
2853 cls : 'modal-footer',
2857 cls: 'btn-' + this.buttonPosition
2874 modal.cls += ' fade';
2880 getChildContainer : function() {
2885 getButtonContainer : function() {
2886 return this.el.select('.modal-footer div',true).first();
2889 initEvents : function()
2891 if (this.allow_close) {
2892 this.closeEl.on('click', this.hide, this);
2894 Roo.EventManager.onWindowResize(this.resize, this, true);
2901 this.maskEl.setSize(
2902 Roo.lib.Dom.getViewWidth(true),
2903 Roo.lib.Dom.getViewHeight(true)
2906 if (this.fitwindow) {
2908 this.width || Roo.lib.Dom.getViewportWidth(true) - 30,
2909 this.height || Roo.lib.Dom.getViewportHeight(true) - 60
2914 if(this.max_width !== 0) {
2916 var w = Math.min(this.max_width, Roo.lib.Dom.getViewportWidth(true) - 30);
2919 this.setSize(w, this.height);
2923 if(this.max_height) {
2924 this.setSize(w,Math.min(
2926 Roo.lib.Dom.getViewportHeight(true) - 60
2932 if(!this.fit_content) {
2933 this.setSize(w, Roo.lib.Dom.getViewportHeight(true) - 60);
2937 this.setSize(w, Math.min(
2939 this.headerEl.getHeight() +
2940 this.footerEl.getHeight() +
2941 this.getChildHeight(this.bodyEl.dom.childNodes),
2942 Roo.lib.Dom.getViewportHeight(true) - 60)
2948 setSize : function(w,h)
2959 if (!this.rendered) {
2963 //this.el.setStyle('display', 'block');
2964 this.el.removeClass('hideing');
2965 this.el.dom.style.display='block';
2967 Roo.get(document.body).addClass('modal-open');
2969 if(this.animate){ // element has 'fade' - so stuff happens after .3s ?- not sure why the delay?
2972 this.el.addClass('show');
2973 this.el.addClass('in');
2976 this.el.addClass('show');
2977 this.el.addClass('in');
2980 // not sure how we can show data in here..
2982 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
2985 Roo.get(document.body).addClass("x-body-masked");
2987 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2988 this.maskEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
2989 this.maskEl.dom.style.display = 'block';
2990 this.maskEl.addClass('show');
2995 this.fireEvent('show', this);
2997 // set zindex here - otherwise it appears to be ignored...
2998 this.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
3001 this.items.forEach( function(e) {
3002 e.layout ? e.layout() : false;
3010 if(this.fireEvent("beforehide", this) !== false){
3012 this.maskEl.removeClass('show');
3014 this.maskEl.dom.style.display = '';
3015 Roo.get(document.body).removeClass("x-body-masked");
3016 this.el.removeClass('in');
3017 this.el.select('.modal-dialog', true).first().setStyle('transform','');
3019 if(this.animate){ // why
3020 this.el.addClass('hideing');
3021 this.el.removeClass('show');
3023 if (!this.el.hasClass('hideing')) {
3024 return; // it's been shown again...
3027 this.el.dom.style.display='';
3029 Roo.get(document.body).removeClass('modal-open');
3030 this.el.removeClass('hideing');
3034 this.el.removeClass('show');
3035 this.el.dom.style.display='';
3036 Roo.get(document.body).removeClass('modal-open');
3039 this.fireEvent('hide', this);
3042 isVisible : function()
3045 return this.el.hasClass('show') && !this.el.hasClass('hideing');
3049 addButton : function(str, cb)
3053 var b = Roo.apply({}, { html : str } );
3054 b.xns = b.xns || Roo.bootstrap;
3055 b.xtype = b.xtype || 'Button';
3056 if (typeof(b.listeners) == 'undefined') {
3057 b.listeners = { click : cb.createDelegate(this) };
3060 var btn = Roo.factory(b);
3062 btn.render(this.el.select('.modal-footer div').first());
3068 setDefaultButton : function(btn)
3070 //this.el.select('.modal-footer').()
3074 resizeTo: function(w,h)
3078 this.dialogEl.setWidth(w);
3079 if (this.diff === false) {
3080 this.diff = this.dialogEl.getHeight() - this.bodyEl.getHeight();
3083 this.bodyEl.setHeight(h - this.diff);
3085 this.fireEvent('resize', this);
3088 setContentSize : function(w, h)
3092 onButtonClick: function(btn,e)
3095 this.fireEvent('btnclick', btn.name, e);
3098 * Set the title of the Dialog
3099 * @param {String} str new Title
3101 setTitle: function(str) {
3102 this.titleEl.dom.innerHTML = str;
3105 * Set the body of the Dialog
3106 * @param {String} str new Title
3108 setBody: function(str) {
3109 this.bodyEl.dom.innerHTML = str;
3112 * Set the body of the Dialog using the template
3113 * @param {Obj} data - apply this data to the template and replace the body contents.
3115 applyBody: function(obj)
3118 Roo.log("Error - using apply Body without a template");
3121 this.tmpl.overwrite(this.bodyEl, obj);
3124 getChildHeight : function(child_nodes)
3128 child_nodes.length == 0
3133 var child_height = 0;
3135 for(var i = 0; i < child_nodes.length; i++) {
3138 * for modal with tabs...
3139 if(child_nodes[i].classList.contains('roo-layout-panel')) {
3141 var layout_childs = child_nodes[i].childNodes;
3143 for(var j = 0; j < layout_childs.length; j++) {
3145 if(layout_childs[j].classList.contains('roo-layout-panel-body')) {
3147 var layout_body_childs = layout_childs[j].childNodes;
3149 for(var k = 0; k < layout_body_childs.length; k++) {
3151 if(layout_body_childs[k].classList.contains('navbar')) {
3152 child_height += layout_body_childs[k].offsetHeight;
3156 if(layout_body_childs[k].classList.contains('roo-layout-tabs-body')) {
3158 var layout_body_tab_childs = layout_body_childs[k].childNodes;
3160 for(var m = 0; m < layout_body_tab_childs.length; m++) {
3162 if(layout_body_tab_childs[m].classList.contains('roo-layout-active-content')) {
3163 child_height += this.getChildHeight(layout_body_tab_childs[m].childNodes);
3178 child_height += child_nodes[i].offsetHeight;
3179 // Roo.log(child_nodes[i].offsetHeight);
3182 return child_height;
3188 Roo.apply(Roo.bootstrap.Modal, {
3190 * Button config that displays a single OK button
3199 * Button config that displays Yes and No buttons
3215 * Button config that displays OK and Cancel buttons
3230 * Button config that displays Yes, No and Cancel buttons
3254 * messagebox - can be used as a replace
3258 * @class Roo.MessageBox
3259 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
3263 Roo.Msg.alert('Status', 'Changes saved successfully.');
3265 // Prompt for user data:
3266 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
3268 // process text value...
3272 // Show a dialog using config options:
3274 title:'Save Changes?',
3275 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
3276 buttons: Roo.Msg.YESNOCANCEL,
3283 Roo.bootstrap.MessageBox = function(){
3284 var dlg, opt, mask, waitTimer;
3285 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
3286 var buttons, activeTextEl, bwidth;
3290 var handleButton = function(button){
3292 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
3296 var handleHide = function(){
3298 dlg.el.removeClass(opt.cls);
3301 // Roo.TaskMgr.stop(waitTimer);
3302 // waitTimer = null;
3307 var updateButtons = function(b){
3310 buttons["ok"].hide();
3311 buttons["cancel"].hide();
3312 buttons["yes"].hide();
3313 buttons["no"].hide();
3314 //dlg.footer.dom.style.display = 'none';
3317 dlg.footerEl.dom.style.display = '';
3318 for(var k in buttons){
3319 if(typeof buttons[k] != "function"){
3322 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
3323 width += buttons[k].el.getWidth()+15;
3333 var handleEsc = function(d, k, e){
3334 if(opt && opt.closable !== false){
3344 * Returns a reference to the underlying {@link Roo.BasicDialog} element
3345 * @return {Roo.BasicDialog} The BasicDialog element
3347 getDialog : function(){
3349 dlg = new Roo.bootstrap.Modal( {
3352 //constraintoviewport:false,
3354 //collapsible : false,
3359 //buttonAlign:"center",
3360 closeClick : function(){
3361 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
3364 handleButton("cancel");
3369 dlg.on("hide", handleHide);
3371 //dlg.addKeyListener(27, handleEsc);
3373 this.buttons = buttons;
3374 var bt = this.buttonText;
3375 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
3376 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
3377 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
3378 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
3380 bodyEl = dlg.bodyEl.createChild({
3382 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
3383 '<textarea class="roo-mb-textarea"></textarea>' +
3384 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
3386 msgEl = bodyEl.dom.firstChild;
3387 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
3388 textboxEl.enableDisplayMode();
3389 textboxEl.addKeyListener([10,13], function(){
3390 if(dlg.isVisible() && opt && opt.buttons){
3393 }else if(opt.buttons.yes){
3394 handleButton("yes");
3398 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
3399 textareaEl.enableDisplayMode();
3400 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
3401 progressEl.enableDisplayMode();
3403 // This is supposed to be the progessElement.. but I think it's controlling the height of everything..
3404 var pf = progressEl.dom.firstChild;
3406 pp = Roo.get(pf.firstChild);
3407 pp.setHeight(pf.offsetHeight);
3415 * Updates the message box body text
3416 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
3417 * the XHTML-compliant non-breaking space character '&#160;')
3418 * @return {Roo.MessageBox} This message box
3420 updateText : function(text)
3422 if(!dlg.isVisible() && !opt.width){
3423 dlg.dialogEl.setStyle({ 'max-width' : this.maxWidth});
3424 // dlg.resizeTo(this.maxWidth, 100); // forcing the height breaks long alerts()
3426 msgEl.innerHTML = text || ' ';
3428 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
3429 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
3431 Math.min(opt.width || cw , this.maxWidth),
3432 Math.max(opt.minWidth || this.minWidth, bwidth)
3435 activeTextEl.setWidth(w);
3437 if(dlg.isVisible()){
3438 dlg.fixedcenter = false;
3440 // to big, make it scroll. = But as usual stupid IE does not support
3443 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
3444 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
3445 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
3447 bodyEl.dom.style.height = '';
3448 bodyEl.dom.style.overflowY = '';
3451 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
3453 bodyEl.dom.style.overflowX = '';
3456 dlg.setContentSize(w, bodyEl.getHeight());
3457 if(dlg.isVisible()){
3458 dlg.fixedcenter = true;
3464 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
3465 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
3466 * @param {Number} value Any number between 0 and 1 (e.g., .5)
3467 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
3468 * @return {Roo.MessageBox} This message box
3470 updateProgress : function(value, text){
3472 this.updateText(text);
3475 if (pp) { // weird bug on my firefox - for some reason this is not defined
3476 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
3477 pp.setHeight(Math.floor(progressEl.dom.firstChild.offsetHeight));
3483 * Returns true if the message box is currently displayed
3484 * @return {Boolean} True if the message box is visible, else false
3486 isVisible : function(){
3487 return dlg && dlg.isVisible();
3491 * Hides the message box if it is displayed
3494 if(this.isVisible()){
3500 * Displays a new message box, or reinitializes an existing message box, based on the config options
3501 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
3502 * The following config object properties are supported:
3504 Property Type Description
3505 ---------- --------------- ------------------------------------------------------------------------------------
3506 animEl String/Element An id or Element from which the message box should animate as it opens and
3507 closes (defaults to undefined)
3508 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
3509 cancel:'Bar'}), or false to not show any buttons (defaults to false)
3510 closable Boolean False to hide the top-right close button (defaults to true). Note that
3511 progress and wait dialogs will ignore this property and always hide the
3512 close button as they can only be closed programmatically.
3513 cls String A custom CSS class to apply to the message box element
3514 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
3515 displayed (defaults to 75)
3516 fn Function A callback function to execute after closing the dialog. The arguments to the
3517 function will be btn (the name of the button that was clicked, if applicable,
3518 e.g. "ok"), and text (the value of the active text field, if applicable).
3519 Progress and wait dialogs will ignore this option since they do not respond to
3520 user actions and can only be closed programmatically, so any required function
3521 should be called by the same code after it closes the dialog.
3522 icon String A CSS class that provides a background image to be used as an icon for
3523 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
3524 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
3525 minWidth Number The minimum width in pixels of the message box (defaults to 100)
3526 modal Boolean False to allow user interaction with the page while the message box is
3527 displayed (defaults to true)
3528 msg String A string that will replace the existing message box body text (defaults
3529 to the XHTML-compliant non-breaking space character ' ')
3530 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
3531 progress Boolean True to display a progress bar (defaults to false)
3532 progressText String The text to display inside the progress bar if progress = true (defaults to '')
3533 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
3534 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
3535 title String The title text
3536 value String The string value to set into the active textbox element if displayed
3537 wait Boolean True to display a progress bar (defaults to false)
3538 width Number The width of the dialog in pixels
3545 msg: 'Please enter your address:',
3547 buttons: Roo.MessageBox.OKCANCEL,
3550 animEl: 'addAddressBtn'
3553 * @param {Object} config Configuration options
3554 * @return {Roo.MessageBox} This message box
3556 show : function(options)
3559 // this causes nightmares if you show one dialog after another
3560 // especially on callbacks..
3562 if(this.isVisible()){
3565 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
3566 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
3567 Roo.log("New Dialog Message:" + options.msg )
3568 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
3569 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
3572 var d = this.getDialog();
3574 d.setTitle(opt.title || " ");
3575 d.closeEl.setDisplayed(opt.closable !== false);
3576 activeTextEl = textboxEl;
3577 opt.prompt = opt.prompt || (opt.multiline ? true : false);
3582 textareaEl.setHeight(typeof opt.multiline == "number" ?
3583 opt.multiline : this.defaultTextHeight);
3584 activeTextEl = textareaEl;
3593 progressEl.setDisplayed(opt.progress === true);
3594 this.updateProgress(0);
3595 activeTextEl.dom.value = opt.value || "";
3597 dlg.setDefaultButton(activeTextEl);
3599 var bs = opt.buttons;
3603 }else if(bs && bs.yes){
3604 db = buttons["yes"];
3606 dlg.setDefaultButton(db);
3608 bwidth = updateButtons(opt.buttons);
3609 this.updateText(opt.msg);
3611 d.el.addClass(opt.cls);
3613 d.proxyDrag = opt.proxyDrag === true;
3614 d.modal = opt.modal !== false;
3615 d.mask = opt.modal !== false ? mask : false;
3617 // force it to the end of the z-index stack so it gets a cursor in FF
3618 document.body.appendChild(dlg.el.dom);
3619 d.animateTarget = null;
3620 d.show(options.animEl);
3626 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
3627 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
3628 * and closing the message box when the process is complete.
3629 * @param {String} title The title bar text
3630 * @param {String} msg The message box body text
3631 * @return {Roo.MessageBox} This message box
3633 progress : function(title, msg){
3640 minWidth: this.minProgressWidth,
3647 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
3648 * If a callback function is passed it will be called after the user clicks the button, and the
3649 * id of the button that was clicked will be passed as the only parameter to the callback
3650 * (could also be the top-right close button).
3651 * @param {String} title The title bar text
3652 * @param {String} msg The message box body text
3653 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3654 * @param {Object} scope (optional) The scope of the callback function
3655 * @return {Roo.MessageBox} This message box
3657 alert : function(title, msg, fn, scope)
3672 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
3673 * interaction while waiting for a long-running process to complete that does not have defined intervals.
3674 * You are responsible for closing the message box when the process is complete.
3675 * @param {String} msg The message box body text
3676 * @param {String} title (optional) The title bar text
3677 * @return {Roo.MessageBox} This message box
3679 wait : function(msg, title){
3690 waitTimer = Roo.TaskMgr.start({
3692 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
3700 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
3701 * If a callback function is passed it will be called after the user clicks either button, and the id of the
3702 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
3703 * @param {String} title The title bar text
3704 * @param {String} msg The message box body text
3705 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3706 * @param {Object} scope (optional) The scope of the callback function
3707 * @return {Roo.MessageBox} This message box
3709 confirm : function(title, msg, fn, scope){
3713 buttons: this.YESNO,
3722 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
3723 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
3724 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
3725 * (could also be the top-right close button) and the text that was entered will be passed as the two
3726 * parameters to the callback.
3727 * @param {String} title The title bar text
3728 * @param {String} msg The message box body text
3729 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3730 * @param {Object} scope (optional) The scope of the callback function
3731 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
3732 * property, or the height in pixels to create the textbox (defaults to false / single-line)
3733 * @return {Roo.MessageBox} This message box
3735 prompt : function(title, msg, fn, scope, multiline){
3739 buttons: this.OKCANCEL,
3744 multiline: multiline,
3751 * Button config that displays a single OK button
3756 * Button config that displays Yes and No buttons
3759 YESNO : {yes:true, no:true},
3761 * Button config that displays OK and Cancel buttons
3764 OKCANCEL : {ok:true, cancel:true},
3766 * Button config that displays Yes, No and Cancel buttons
3769 YESNOCANCEL : {yes:true, no:true, cancel:true},
3772 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3775 defaultTextHeight : 75,
3777 * The maximum width in pixels of the message box (defaults to 600)
3782 * The minimum width in pixels of the message box (defaults to 100)
3787 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3788 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3791 minProgressWidth : 250,
3793 * An object containing the default button text strings that can be overriden for localized language support.
3794 * Supported properties are: ok, cancel, yes and no.
3795 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3808 * Shorthand for {@link Roo.MessageBox}
3810 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3811 Roo.Msg = Roo.Msg || Roo.MessageBox;
3820 * @class Roo.bootstrap.Navbar
3821 * @extends Roo.bootstrap.Component
3822 * Bootstrap Navbar class
3825 * Create a new Navbar
3826 * @param {Object} config The config object
3830 Roo.bootstrap.Navbar = function(config){
3831 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3835 * @event beforetoggle
3836 * Fire before toggle the menu
3837 * @param {Roo.EventObject} e
3839 "beforetoggle" : true
3843 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3852 getAutoCreate : function(){
3855 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3859 initEvents :function ()
3861 //Roo.log(this.el.select('.navbar-toggle',true));
3862 this.el.select('.navbar-toggle',true).on('click', function() {
3863 if(this.fireEvent('beforetoggle', this) !== false){
3864 this.el.select('.navbar-collapse',true).toggleClass('in');
3874 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3876 var size = this.el.getSize();
3877 this.maskEl.setSize(size.width, size.height);
3878 this.maskEl.enableDisplayMode("block");
3887 getChildContainer : function()
3889 if (this.el.select('.collapse').getCount()) {
3890 return this.el.select('.collapse',true).first();
3923 * @class Roo.bootstrap.NavSimplebar
3924 * @extends Roo.bootstrap.Navbar
3925 * Bootstrap Sidebar class
3927 * @cfg {Boolean} inverse is inverted color
3929 * @cfg {String} type (nav | pills | tabs)
3930 * @cfg {Boolean} arrangement stacked | justified
3931 * @cfg {String} align (left | right) alignment
3933 * @cfg {Boolean} main (true|false) main nav bar? default false
3934 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3936 * @cfg {String} tag (header|footer|nav|div) default is nav
3938 * @cfg {String} weight (light|primary|secondary|success|danger|warning|info|dark|white) default is light.
3942 * Create a new Sidebar
3943 * @param {Object} config The config object
3947 Roo.bootstrap.NavSimplebar = function(config){
3948 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3951 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
3967 getAutoCreate : function(){
3971 tag : this.tag || 'div',
3972 cls : 'navbar navbar-expand-lg'
3974 if (['light','white'].indexOf(this.weight) > -1) {
3975 cfg.cls += ['light','white'].indexOf(this.weight) > -1 ? ' navbar-light' : ' navbar-dark';
3977 cfg.cls += ' bg-' + this.weight;
3989 this.type = this.type || 'nav';
3990 if (['tabs','pills'].indexOf(this.type)!==-1) {
3991 cfg.cn[0].cls += ' nav-' + this.type
3995 if (this.type!=='nav') {
3996 Roo.log('nav type must be nav/tabs/pills')
3998 cfg.cn[0].cls += ' navbar-nav'
4004 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
4005 cfg.cn[0].cls += ' nav-' + this.arrangement;
4009 if (this.align === 'right') {
4010 cfg.cn[0].cls += ' navbar-right';
4014 cfg.cls += ' navbar-inverse';
4038 * navbar-expand-md fixed-top
4042 * @class Roo.bootstrap.NavHeaderbar
4043 * @extends Roo.bootstrap.NavSimplebar
4044 * Bootstrap Sidebar class
4046 * @cfg {String} brand what is brand
4047 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
4048 * @cfg {String} brand_href href of the brand
4049 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
4050 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
4051 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
4052 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
4055 * Create a new Sidebar
4056 * @param {Object} config The config object
4060 Roo.bootstrap.NavHeaderbar = function(config){
4061 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
4065 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
4072 desktopCenter : false,
4075 getAutoCreate : function(){
4078 tag: this.nav || 'nav',
4079 cls: 'navbar navbar-expand-md',
4085 if (this.desktopCenter) {
4086 cn.push({cls : 'container', cn : []});
4093 cls: 'navbar-header',
4098 cls: 'navbar-toggle navbar-toggler',
4099 'data-toggle': 'collapse',
4104 html: 'Toggle navigation'
4108 cls: 'icon-bar navbar-toggler-icon'
4126 cls: 'collapse navbar-collapse',
4130 cfg.cls += this.inverse ? ' navbar-inverse navbar-dark bg-dark' : ' navbar-default';
4132 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
4133 cfg.cls += ' navbar-' + this.position + ' ' + this.position ;
4135 // tag can override this..
4137 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
4140 if (this.brand !== '') {
4142 cn.unshift({ // changed from push ?? BS4 needs it at the start? - does this break or exsiting?
4144 href: this.brand_href ? this.brand_href : '#',
4145 cls: 'navbar-brand',
4153 cfg.cls += ' main-nav';
4161 getHeaderChildContainer : function()
4163 if (this.srButton && this.el.select('.navbar-header').getCount()) {
4164 return this.el.select('.navbar-header',true).first();
4167 return this.getChildContainer();
4171 initEvents : function()
4173 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
4175 if (this.autohide) {
4180 Roo.get(document).on('scroll',function(e) {
4181 var ns = Roo.get(document).getScroll().top;
4182 var os = prevScroll;
4186 ft.removeClass('slideDown');
4187 ft.addClass('slideUp');
4190 ft.removeClass('slideUp');
4191 ft.addClass('slideDown');
4212 * @class Roo.bootstrap.NavSidebar
4213 * @extends Roo.bootstrap.Navbar
4214 * Bootstrap Sidebar class
4217 * Create a new Sidebar
4218 * @param {Object} config The config object
4222 Roo.bootstrap.NavSidebar = function(config){
4223 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
4226 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
4228 sidebar : true, // used by Navbar Item and NavbarGroup at present...
4230 getAutoCreate : function(){
4235 cls: 'sidebar sidebar-nav'
4257 * @class Roo.bootstrap.NavGroup
4258 * @extends Roo.bootstrap.Component
4259 * Bootstrap NavGroup class
4260 * @cfg {String} align (left|right)
4261 * @cfg {Boolean} inverse
4262 * @cfg {String} type (nav|pills|tab) default nav
4263 * @cfg {String} navId - reference Id for navbar.
4267 * Create a new nav group
4268 * @param {Object} config The config object
4271 Roo.bootstrap.NavGroup = function(config){
4272 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
4275 Roo.bootstrap.NavGroup.register(this);
4279 * Fires when the active item changes
4280 * @param {Roo.bootstrap.NavGroup} this
4281 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
4282 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
4289 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
4300 getAutoCreate : function()
4302 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
4309 if (['tabs','pills'].indexOf(this.type)!==-1) {
4310 cfg.cls += ' nav-' + this.type
4312 if (this.type!=='nav') {
4313 Roo.log('nav type must be nav/tabs/pills')
4315 cfg.cls += ' navbar-nav'
4318 if (this.parent() && this.parent().sidebar) {
4321 cls: 'dashboard-menu sidebar-menu'
4327 if (this.form === true) {
4333 if (this.align === 'right') {
4334 cfg.cls += ' navbar-right ml-md-auto';
4336 cfg.cls += ' navbar-left';
4340 if (this.align === 'right') {
4341 cfg.cls += ' navbar-right ml-md-auto';
4343 cfg.cls += ' mr-auto';
4347 cfg.cls += ' navbar-inverse';
4355 * sets the active Navigation item
4356 * @param {Roo.bootstrap.NavItem} the new current navitem
4358 setActiveItem : function(item)
4361 Roo.each(this.navItems, function(v){
4366 v.setActive(false, true);
4373 item.setActive(true, true);
4374 this.fireEvent('changed', this, item, prev);
4379 * gets the active Navigation item
4380 * @return {Roo.bootstrap.NavItem} the current navitem
4382 getActive : function()
4386 Roo.each(this.navItems, function(v){
4397 indexOfNav : function()
4401 Roo.each(this.navItems, function(v,i){
4412 * adds a Navigation item
4413 * @param {Roo.bootstrap.NavItem} the navitem to add
4415 addItem : function(cfg)
4417 var cn = new Roo.bootstrap.NavItem(cfg);
4419 cn.parentId = this.id;
4420 cn.onRender(this.el, null);
4424 * register a Navigation item
4425 * @param {Roo.bootstrap.NavItem} the navitem to add
4427 register : function(item)
4429 this.navItems.push( item);
4430 item.navId = this.navId;
4435 * clear all the Navigation item
4438 clearAll : function()
4441 this.el.dom.innerHTML = '';
4444 getNavItem: function(tabId)
4447 Roo.each(this.navItems, function(e) {
4448 if (e.tabId == tabId) {
4458 setActiveNext : function()
4460 var i = this.indexOfNav(this.getActive());
4461 if (i > this.navItems.length) {
4464 this.setActiveItem(this.navItems[i+1]);
4466 setActivePrev : function()
4468 var i = this.indexOfNav(this.getActive());
4472 this.setActiveItem(this.navItems[i-1]);
4474 clearWasActive : function(except) {
4475 Roo.each(this.navItems, function(e) {
4476 if (e.tabId != except.tabId && e.was_active) {
4477 e.was_active = false;
4484 getWasActive : function ()
4487 Roo.each(this.navItems, function(e) {
4502 Roo.apply(Roo.bootstrap.NavGroup, {
4506 * register a Navigation Group
4507 * @param {Roo.bootstrap.NavGroup} the navgroup to add
4509 register : function(navgrp)
4511 this.groups[navgrp.navId] = navgrp;
4515 * fetch a Navigation Group based on the navigation ID
4516 * @param {string} the navgroup to add
4517 * @returns {Roo.bootstrap.NavGroup} the navgroup
4519 get: function(navId) {
4520 if (typeof(this.groups[navId]) == 'undefined') {
4522 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
4524 return this.groups[navId] ;
4539 * @class Roo.bootstrap.NavItem
4540 * @extends Roo.bootstrap.Component
4541 * Bootstrap Navbar.NavItem class
4542 * @cfg {String} href link to
4543 * @cfg {String} html content of button
4544 * @cfg {String} badge text inside badge
4545 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
4546 * @cfg {String} glyphicon DEPRICATED - use fa
4547 * @cfg {String} icon DEPRICATED - use fa
4548 * @cfg {String} fa - Fontawsome icon name (can add stuff to it like fa-2x)
4549 * @cfg {Boolean} active Is item active
4550 * @cfg {Boolean} disabled Is item disabled
4552 * @cfg {Boolean} preventDefault (true | false) default false
4553 * @cfg {String} tabId the tab that this item activates.
4554 * @cfg {String} tagtype (a|span) render as a href or span?
4555 * @cfg {Boolean} animateRef (true|false) link to element default false
4558 * Create a new Navbar Item
4559 * @param {Object} config The config object
4561 Roo.bootstrap.NavItem = function(config){
4562 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
4567 * The raw click event for the entire grid.
4568 * @param {Roo.EventObject} e
4573 * Fires when the active item active state changes
4574 * @param {Roo.bootstrap.NavItem} this
4575 * @param {boolean} state the new state
4581 * Fires when scroll to element
4582 * @param {Roo.bootstrap.NavItem} this
4583 * @param {Object} options
4584 * @param {Roo.EventObject} e
4592 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
4601 preventDefault : false,
4608 getAutoCreate : function(){
4617 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
4619 if (this.disabled) {
4620 cfg.cls += ' disabled';
4623 if (this.href || this.html || this.glyphicon || this.icon || this.fa) {
4627 href : this.href || "#",
4628 html: this.html || ''
4631 if (this.tagtype == 'a') {
4632 cfg.cn[0].cls = 'nav-link';
4635 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
4638 cfg.cn[0].html = '<i class="fa fas fa-'+this.fa+'"></i> <span>' + cfg.cn[0].html + '</span>'
4640 if(this.glyphicon) {
4641 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
4646 cfg.cn[0].html += " <span class='caret'></span>";
4650 if (this.badge !== '') {
4652 cfg.cn[0].html += ' <span class="badge badge-secondary">' + this.badge + '</span>';
4660 initEvents: function()
4662 if (typeof (this.menu) != 'undefined') {
4663 this.menu.parentType = this.xtype;
4664 this.menu.triggerEl = this.el;
4665 this.menu = this.addxtype(Roo.apply({}, this.menu));
4668 this.el.select('a',true).on('click', this.onClick, this);
4670 if(this.tagtype == 'span'){
4671 this.el.select('span',true).on('click', this.onClick, this);
4674 // at this point parent should be available..
4675 this.parent().register(this);
4678 onClick : function(e)
4680 if (e.getTarget('.dropdown-menu-item')) {
4681 // did you click on a menu itemm.... - then don't trigger onclick..
4686 this.preventDefault ||
4689 Roo.log("NavItem - prevent Default?");
4693 if (this.disabled) {
4697 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4698 if (tg && tg.transition) {
4699 Roo.log("waiting for the transitionend");
4705 //Roo.log("fire event clicked");
4706 if(this.fireEvent('click', this, e) === false){
4710 if(this.tagtype == 'span'){
4714 //Roo.log(this.href);
4715 var ael = this.el.select('a',true).first();
4718 if(ael && this.animateRef && this.href.indexOf('#') > -1){
4719 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4720 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4721 return; // ignore... - it's a 'hash' to another page.
4723 Roo.log("NavItem - prevent Default?");
4725 this.scrollToElement(e);
4729 var p = this.parent();
4731 if (['tabs','pills'].indexOf(p.type)!==-1) {
4732 if (typeof(p.setActiveItem) !== 'undefined') {
4733 p.setActiveItem(this);
4737 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4738 if (p.parentType == 'NavHeaderbar' && !this.menu) {
4739 // remove the collapsed menu expand...
4740 p.parent().el.select('.navbar-collapse',true).removeClass('in');
4744 isActive: function () {
4747 setActive : function(state, fire, is_was_active)
4749 if (this.active && !state && this.navId) {
4750 this.was_active = true;
4751 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4753 nv.clearWasActive(this);
4757 this.active = state;
4760 this.el.removeClass('active');
4761 } else if (!this.el.hasClass('active')) {
4762 this.el.addClass('active');
4765 this.fireEvent('changed', this, state);
4768 // show a panel if it's registered and related..
4770 if (!this.navId || !this.tabId || !state || is_was_active) {
4774 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4778 var pan = tg.getPanelByName(this.tabId);
4782 // if we can not flip to new panel - go back to old nav highlight..
4783 if (false == tg.showPanel(pan)) {
4784 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4786 var onav = nv.getWasActive();
4788 onav.setActive(true, false, true);
4797 // this should not be here...
4798 setDisabled : function(state)
4800 this.disabled = state;
4802 this.el.removeClass('disabled');
4803 } else if (!this.el.hasClass('disabled')) {
4804 this.el.addClass('disabled');
4810 * Fetch the element to display the tooltip on.
4811 * @return {Roo.Element} defaults to this.el
4813 tooltipEl : function()
4815 return this.el.select('' + this.tagtype + '', true).first();
4818 scrollToElement : function(e)
4820 var c = document.body;
4823 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
4825 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
4826 c = document.documentElement;
4829 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4835 var o = target.calcOffsetsTo(c);
4842 this.fireEvent('scrollto', this, options, e);
4844 Roo.get(c).scrollTo('top', options.value, true);
4857 * <span> icon </span>
4858 * <span> text </span>
4859 * <span>badge </span>
4863 * @class Roo.bootstrap.NavSidebarItem
4864 * @extends Roo.bootstrap.NavItem
4865 * Bootstrap Navbar.NavSidebarItem class
4866 * {String} badgeWeight (default|primary|success|info|warning|danger)the extra classes for the badge
4867 * {Boolean} open is the menu open
4868 * {Boolean} buttonView use button as the tigger el rather that a (default false)
4869 * {String} buttonWeight (default|primary|success|info|warning|danger)the extra classes for the button
4870 * {String} buttonSize (sm|md|lg)the extra classes for the button
4871 * {Boolean} showArrow show arrow next to the text (default true)
4873 * Create a new Navbar Button
4874 * @param {Object} config The config object
4876 Roo.bootstrap.NavSidebarItem = function(config){
4877 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4882 * The raw click event for the entire grid.
4883 * @param {Roo.EventObject} e
4888 * Fires when the active item active state changes
4889 * @param {Roo.bootstrap.NavSidebarItem} this
4890 * @param {boolean} state the new state
4898 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
4900 badgeWeight : 'default',
4906 buttonWeight : 'default',
4912 getAutoCreate : function(){
4917 href : this.href || '#',
4923 if(this.buttonView){
4926 href : this.href || '#',
4927 cls: 'btn btn-' + this.buttonWeight + ' btn-' + this.buttonSize + 'roo-button-dropdown-toggle',
4940 cfg.cls += ' active';
4943 if (this.disabled) {
4944 cfg.cls += ' disabled';
4947 cfg.cls += ' open x-open';
4950 if (this.glyphicon || this.icon) {
4951 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
4952 a.cn.push({ tag : 'i', cls : c }) ;
4955 if(!this.buttonView){
4958 html : this.html || ''
4965 if (this.badge !== '') {
4966 a.cn.push({ tag: 'span', cls : 'badge pull-right badge-' + this.badgeWeight, html: this.badge });
4972 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4975 a.cls += ' dropdown-toggle treeview' ;
4981 initEvents : function()
4983 if (typeof (this.menu) != 'undefined') {
4984 this.menu.parentType = this.xtype;
4985 this.menu.triggerEl = this.el;
4986 this.menu = this.addxtype(Roo.apply({}, this.menu));
4989 this.el.on('click', this.onClick, this);
4991 if(this.badge !== ''){
4992 this.badgeEl = this.el.select('.badge', true).first().setVisibilityMode(Roo.Element.DISPLAY);
4997 onClick : function(e)
5004 if(this.preventDefault){
5008 this.fireEvent('click', this);
5011 disable : function()
5013 this.setDisabled(true);
5018 this.setDisabled(false);
5021 setDisabled : function(state)
5023 if(this.disabled == state){
5027 this.disabled = state;
5030 this.el.addClass('disabled');
5034 this.el.removeClass('disabled');
5039 setActive : function(state)
5041 if(this.active == state){
5045 this.active = state;
5048 this.el.addClass('active');
5052 this.el.removeClass('active');
5057 isActive: function ()
5062 setBadge : function(str)
5068 this.badgeEl.dom.innerHTML = str;
5085 * @class Roo.bootstrap.Row
5086 * @extends Roo.bootstrap.Component
5087 * Bootstrap Row class (contains columns...)
5091 * @param {Object} config The config object
5094 Roo.bootstrap.Row = function(config){
5095 Roo.bootstrap.Row.superclass.constructor.call(this, config);
5098 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
5100 getAutoCreate : function(){
5119 * @class Roo.bootstrap.Element
5120 * @extends Roo.bootstrap.Component
5121 * Bootstrap Element class
5122 * @cfg {String} html contents of the element
5123 * @cfg {String} tag tag of the element
5124 * @cfg {String} cls class of the element
5125 * @cfg {Boolean} preventDefault (true|false) default false
5126 * @cfg {Boolean} clickable (true|false) default false
5129 * Create a new Element
5130 * @param {Object} config The config object
5133 Roo.bootstrap.Element = function(config){
5134 Roo.bootstrap.Element.superclass.constructor.call(this, config);
5140 * When a element is chick
5141 * @param {Roo.bootstrap.Element} this
5142 * @param {Roo.EventObject} e
5148 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
5153 preventDefault: false,
5156 getAutoCreate : function(){
5160 // cls: this.cls, double assign in parent class Component.js :: onRender
5167 initEvents: function()
5169 Roo.bootstrap.Element.superclass.initEvents.call(this);
5172 this.el.on('click', this.onClick, this);
5177 onClick : function(e)
5179 if(this.preventDefault){
5183 this.fireEvent('click', this, e);
5186 getValue : function()
5188 return this.el.dom.innerHTML;
5191 setValue : function(value)
5193 this.el.dom.innerHTML = value;
5208 * @class Roo.bootstrap.Pagination
5209 * @extends Roo.bootstrap.Component
5210 * Bootstrap Pagination class
5211 * @cfg {String} size xs | sm | md | lg
5212 * @cfg {Boolean} inverse false | true
5215 * Create a new Pagination
5216 * @param {Object} config The config object
5219 Roo.bootstrap.Pagination = function(config){
5220 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
5223 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
5229 getAutoCreate : function(){
5235 cfg.cls += ' inverse';
5241 cfg.cls += " " + this.cls;
5259 * @class Roo.bootstrap.PaginationItem
5260 * @extends Roo.bootstrap.Component
5261 * Bootstrap PaginationItem class
5262 * @cfg {String} html text
5263 * @cfg {String} href the link
5264 * @cfg {Boolean} preventDefault (true | false) default true
5265 * @cfg {Boolean} active (true | false) default false
5266 * @cfg {Boolean} disabled default false
5270 * Create a new PaginationItem
5271 * @param {Object} config The config object
5275 Roo.bootstrap.PaginationItem = function(config){
5276 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
5281 * The raw click event for the entire grid.
5282 * @param {Roo.EventObject} e
5288 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
5292 preventDefault: true,
5297 getAutoCreate : function(){
5303 href : this.href ? this.href : '#',
5304 html : this.html ? this.html : ''
5314 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
5318 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
5324 initEvents: function() {
5326 this.el.on('click', this.onClick, this);
5329 onClick : function(e)
5331 Roo.log('PaginationItem on click ');
5332 if(this.preventDefault){
5340 this.fireEvent('click', this, e);
5356 * @class Roo.bootstrap.Slider
5357 * @extends Roo.bootstrap.Component
5358 * Bootstrap Slider class
5361 * Create a new Slider
5362 * @param {Object} config The config object
5365 Roo.bootstrap.Slider = function(config){
5366 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
5369 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
5371 getAutoCreate : function(){
5375 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
5379 cls: 'ui-slider-handle ui-state-default ui-corner-all'
5391 * Ext JS Library 1.1.1
5392 * Copyright(c) 2006-2007, Ext JS, LLC.
5394 * Originally Released Under LGPL - original licence link has changed is not relivant.
5397 * <script type="text/javascript">
5402 * @class Roo.grid.ColumnModel
5403 * @extends Roo.util.Observable
5404 * This is the default implementation of a ColumnModel used by the Grid. It defines
5405 * the columns in the grid.
5408 var colModel = new Roo.grid.ColumnModel([
5409 {header: "Ticker", width: 60, sortable: true, locked: true},
5410 {header: "Company Name", width: 150, sortable: true},
5411 {header: "Market Cap.", width: 100, sortable: true},
5412 {header: "$ Sales", width: 100, sortable: true, renderer: money},
5413 {header: "Employees", width: 100, sortable: true, resizable: false}
5418 * The config options listed for this class are options which may appear in each
5419 * individual column definition.
5420 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
5422 * @param {Object} config An Array of column config objects. See this class's
5423 * config objects for details.
5425 Roo.grid.ColumnModel = function(config){
5427 * The config passed into the constructor
5429 this.config = config;
5432 // if no id, create one
5433 // if the column does not have a dataIndex mapping,
5434 // map it to the order it is in the config
5435 for(var i = 0, len = config.length; i < len; i++){
5437 if(typeof c.dataIndex == "undefined"){
5440 if(typeof c.renderer == "string"){
5441 c.renderer = Roo.util.Format[c.renderer];
5443 if(typeof c.id == "undefined"){
5446 if(c.editor && c.editor.xtype){
5447 c.editor = Roo.factory(c.editor, Roo.grid);
5449 if(c.editor && c.editor.isFormField){
5450 c.editor = new Roo.grid.GridEditor(c.editor);
5452 this.lookup[c.id] = c;
5456 * The width of columns which have no width specified (defaults to 100)
5459 this.defaultWidth = 100;
5462 * Default sortable of columns which have no sortable specified (defaults to false)
5465 this.defaultSortable = false;
5469 * @event widthchange
5470 * Fires when the width of a column changes.
5471 * @param {ColumnModel} this
5472 * @param {Number} columnIndex The column index
5473 * @param {Number} newWidth The new width
5475 "widthchange": true,
5477 * @event headerchange
5478 * Fires when the text of a header changes.
5479 * @param {ColumnModel} this
5480 * @param {Number} columnIndex The column index
5481 * @param {Number} newText The new header text
5483 "headerchange": true,
5485 * @event hiddenchange
5486 * Fires when a column is hidden or "unhidden".
5487 * @param {ColumnModel} this
5488 * @param {Number} columnIndex The column index
5489 * @param {Boolean} hidden true if hidden, false otherwise
5491 "hiddenchange": true,
5493 * @event columnmoved
5494 * Fires when a column is moved.
5495 * @param {ColumnModel} this
5496 * @param {Number} oldIndex
5497 * @param {Number} newIndex
5499 "columnmoved" : true,
5501 * @event columlockchange
5502 * Fires when a column's locked state is changed
5503 * @param {ColumnModel} this
5504 * @param {Number} colIndex
5505 * @param {Boolean} locked true if locked
5507 "columnlockchange" : true
5509 Roo.grid.ColumnModel.superclass.constructor.call(this);
5511 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
5513 * @cfg {String} header The header text to display in the Grid view.
5516 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
5517 * {@link Roo.data.Record} definition from which to draw the column's value. If not
5518 * specified, the column's index is used as an index into the Record's data Array.
5521 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
5522 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
5525 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
5526 * Defaults to the value of the {@link #defaultSortable} property.
5527 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
5530 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
5533 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
5536 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
5539 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
5542 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
5543 * given the cell's data value. See {@link #setRenderer}. If not specified, the
5544 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
5545 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
5548 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
5551 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
5554 * @cfg {String} valign (Optional) Set the CSS vertical-align property of the column (eg. middle, top, bottom etc). Defaults to undefined.
5557 * @cfg {String} cursor (Optional)
5560 * @cfg {String} tooltip (Optional)
5563 * @cfg {Number} xs (Optional)
5566 * @cfg {Number} sm (Optional)
5569 * @cfg {Number} md (Optional)
5572 * @cfg {Number} lg (Optional)
5575 * Returns the id of the column at the specified index.
5576 * @param {Number} index The column index
5577 * @return {String} the id
5579 getColumnId : function(index){
5580 return this.config[index].id;
5584 * Returns the column for a specified id.
5585 * @param {String} id The column id
5586 * @return {Object} the column
5588 getColumnById : function(id){
5589 return this.lookup[id];
5594 * Returns the column for a specified dataIndex.
5595 * @param {String} dataIndex The column dataIndex
5596 * @return {Object|Boolean} the column or false if not found
5598 getColumnByDataIndex: function(dataIndex){
5599 var index = this.findColumnIndex(dataIndex);
5600 return index > -1 ? this.config[index] : false;
5604 * Returns the index for a specified column id.
5605 * @param {String} id The column id
5606 * @return {Number} the index, or -1 if not found
5608 getIndexById : function(id){
5609 for(var i = 0, len = this.config.length; i < len; i++){
5610 if(this.config[i].id == id){
5618 * Returns the index for a specified column dataIndex.
5619 * @param {String} dataIndex The column dataIndex
5620 * @return {Number} the index, or -1 if not found
5623 findColumnIndex : function(dataIndex){
5624 for(var i = 0, len = this.config.length; i < len; i++){
5625 if(this.config[i].dataIndex == dataIndex){
5633 moveColumn : function(oldIndex, newIndex){
5634 var c = this.config[oldIndex];
5635 this.config.splice(oldIndex, 1);
5636 this.config.splice(newIndex, 0, c);
5637 this.dataMap = null;
5638 this.fireEvent("columnmoved", this, oldIndex, newIndex);
5641 isLocked : function(colIndex){
5642 return this.config[colIndex].locked === true;
5645 setLocked : function(colIndex, value, suppressEvent){
5646 if(this.isLocked(colIndex) == value){
5649 this.config[colIndex].locked = value;
5651 this.fireEvent("columnlockchange", this, colIndex, value);
5655 getTotalLockedWidth : function(){
5657 for(var i = 0; i < this.config.length; i++){
5658 if(this.isLocked(i) && !this.isHidden(i)){
5659 this.totalWidth += this.getColumnWidth(i);
5665 getLockedCount : function(){
5666 for(var i = 0, len = this.config.length; i < len; i++){
5667 if(!this.isLocked(i)){
5672 return this.config.length;
5676 * Returns the number of columns.
5679 getColumnCount : function(visibleOnly){
5680 if(visibleOnly === true){
5682 for(var i = 0, len = this.config.length; i < len; i++){
5683 if(!this.isHidden(i)){
5689 return this.config.length;
5693 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
5694 * @param {Function} fn
5695 * @param {Object} scope (optional)
5696 * @return {Array} result
5698 getColumnsBy : function(fn, scope){
5700 for(var i = 0, len = this.config.length; i < len; i++){
5701 var c = this.config[i];
5702 if(fn.call(scope||this, c, i) === true){
5710 * Returns true if the specified column is sortable.
5711 * @param {Number} col The column index
5714 isSortable : function(col){
5715 if(typeof this.config[col].sortable == "undefined"){
5716 return this.defaultSortable;
5718 return this.config[col].sortable;
5722 * Returns the rendering (formatting) function defined for the column.
5723 * @param {Number} col The column index.
5724 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
5726 getRenderer : function(col){
5727 if(!this.config[col].renderer){
5728 return Roo.grid.ColumnModel.defaultRenderer;
5730 return this.config[col].renderer;
5734 * Sets the rendering (formatting) function for a column.
5735 * @param {Number} col The column index
5736 * @param {Function} fn The function to use to process the cell's raw data
5737 * to return HTML markup for the grid view. The render function is called with
5738 * the following parameters:<ul>
5739 * <li>Data value.</li>
5740 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
5741 * <li>css A CSS style string to apply to the table cell.</li>
5742 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
5743 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
5744 * <li>Row index</li>
5745 * <li>Column index</li>
5746 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
5748 setRenderer : function(col, fn){
5749 this.config[col].renderer = fn;
5753 * Returns the width for the specified column.
5754 * @param {Number} col The column index
5757 getColumnWidth : function(col){
5758 return this.config[col].width * 1 || this.defaultWidth;
5762 * Sets the width for a column.
5763 * @param {Number} col The column index
5764 * @param {Number} width The new width
5766 setColumnWidth : function(col, width, suppressEvent){
5767 this.config[col].width = width;
5768 this.totalWidth = null;
5770 this.fireEvent("widthchange", this, col, width);
5775 * Returns the total width of all columns.
5776 * @param {Boolean} includeHidden True to include hidden column widths
5779 getTotalWidth : function(includeHidden){
5780 if(!this.totalWidth){
5781 this.totalWidth = 0;
5782 for(var i = 0, len = this.config.length; i < len; i++){
5783 if(includeHidden || !this.isHidden(i)){
5784 this.totalWidth += this.getColumnWidth(i);
5788 return this.totalWidth;
5792 * Returns the header for the specified column.
5793 * @param {Number} col The column index
5796 getColumnHeader : function(col){
5797 return this.config[col].header;
5801 * Sets the header for a column.
5802 * @param {Number} col The column index
5803 * @param {String} header The new header
5805 setColumnHeader : function(col, header){
5806 this.config[col].header = header;
5807 this.fireEvent("headerchange", this, col, header);
5811 * Returns the tooltip for the specified column.
5812 * @param {Number} col The column index
5815 getColumnTooltip : function(col){
5816 return this.config[col].tooltip;
5819 * Sets the tooltip for a column.
5820 * @param {Number} col The column index
5821 * @param {String} tooltip The new tooltip
5823 setColumnTooltip : function(col, tooltip){
5824 this.config[col].tooltip = tooltip;
5828 * Returns the dataIndex for the specified column.
5829 * @param {Number} col The column index
5832 getDataIndex : function(col){
5833 return this.config[col].dataIndex;
5837 * Sets the dataIndex for a column.
5838 * @param {Number} col The column index
5839 * @param {Number} dataIndex The new dataIndex
5841 setDataIndex : function(col, dataIndex){
5842 this.config[col].dataIndex = dataIndex;
5848 * Returns true if the cell is editable.
5849 * @param {Number} colIndex The column index
5850 * @param {Number} rowIndex The row index - this is nto actually used..?
5853 isCellEditable : function(colIndex, rowIndex){
5854 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
5858 * Returns the editor defined for the cell/column.
5859 * return false or null to disable editing.
5860 * @param {Number} colIndex The column index
5861 * @param {Number} rowIndex The row index
5864 getCellEditor : function(colIndex, rowIndex){
5865 return this.config[colIndex].editor;
5869 * Sets if a column is editable.
5870 * @param {Number} col The column index
5871 * @param {Boolean} editable True if the column is editable
5873 setEditable : function(col, editable){
5874 this.config[col].editable = editable;
5879 * Returns true if the column is hidden.
5880 * @param {Number} colIndex The column index
5883 isHidden : function(colIndex){
5884 return this.config[colIndex].hidden;
5889 * Returns true if the column width cannot be changed
5891 isFixed : function(colIndex){
5892 return this.config[colIndex].fixed;
5896 * Returns true if the column can be resized
5899 isResizable : function(colIndex){
5900 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
5903 * Sets if a column is hidden.
5904 * @param {Number} colIndex The column index
5905 * @param {Boolean} hidden True if the column is hidden
5907 setHidden : function(colIndex, hidden){
5908 this.config[colIndex].hidden = hidden;
5909 this.totalWidth = null;
5910 this.fireEvent("hiddenchange", this, colIndex, hidden);
5914 * Sets the editor for a column.
5915 * @param {Number} col The column index
5916 * @param {Object} editor The editor object
5918 setEditor : function(col, editor){
5919 this.config[col].editor = editor;
5923 Roo.grid.ColumnModel.defaultRenderer = function(value)
5925 if(typeof value == "object") {
5928 if(typeof value == "string" && value.length < 1){
5932 return String.format("{0}", value);
5935 // Alias for backwards compatibility
5936 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
5939 * Ext JS Library 1.1.1
5940 * Copyright(c) 2006-2007, Ext JS, LLC.
5942 * Originally Released Under LGPL - original licence link has changed is not relivant.
5945 * <script type="text/javascript">
5949 * @class Roo.LoadMask
5950 * A simple utility class for generically masking elements while loading data. If the element being masked has
5951 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
5952 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
5953 * element's UpdateManager load indicator and will be destroyed after the initial load.
5955 * Create a new LoadMask
5956 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
5957 * @param {Object} config The config object
5959 Roo.LoadMask = function(el, config){
5960 this.el = Roo.get(el);
5961 Roo.apply(this, config);
5963 this.store.on('beforeload', this.onBeforeLoad, this);
5964 this.store.on('load', this.onLoad, this);
5965 this.store.on('loadexception', this.onLoadException, this);
5966 this.removeMask = false;
5968 var um = this.el.getUpdateManager();
5969 um.showLoadIndicator = false; // disable the default indicator
5970 um.on('beforeupdate', this.onBeforeLoad, this);
5971 um.on('update', this.onLoad, this);
5972 um.on('failure', this.onLoad, this);
5973 this.removeMask = true;
5977 Roo.LoadMask.prototype = {
5979 * @cfg {Boolean} removeMask
5980 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
5981 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
5985 * The text to display in a centered loading message box (defaults to 'Loading...')
5989 * @cfg {String} msgCls
5990 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
5992 msgCls : 'x-mask-loading',
5995 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
6001 * Disables the mask to prevent it from being displayed
6003 disable : function(){
6004 this.disabled = true;
6008 * Enables the mask so that it can be displayed
6010 enable : function(){
6011 this.disabled = false;
6014 onLoadException : function()
6018 if (typeof(arguments[3]) != 'undefined') {
6019 Roo.MessageBox.alert("Error loading",arguments[3]);
6023 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
6024 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
6031 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
6036 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
6040 onBeforeLoad : function(){
6042 (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
6047 destroy : function(){
6049 this.store.un('beforeload', this.onBeforeLoad, this);
6050 this.store.un('load', this.onLoad, this);
6051 this.store.un('loadexception', this.onLoadException, this);
6053 var um = this.el.getUpdateManager();
6054 um.un('beforeupdate', this.onBeforeLoad, this);
6055 um.un('update', this.onLoad, this);
6056 um.un('failure', this.onLoad, this);
6067 * @class Roo.bootstrap.Table
6068 * @extends Roo.bootstrap.Component
6069 * Bootstrap Table class
6070 * @cfg {String} cls table class
6071 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
6072 * @cfg {String} bgcolor Specifies the background color for a table
6073 * @cfg {Number} border Specifies whether the table cells should have borders or not
6074 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
6075 * @cfg {Number} cellspacing Specifies the space between cells
6076 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
6077 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
6078 * @cfg {String} sortable Specifies that the table should be sortable
6079 * @cfg {String} summary Specifies a summary of the content of a table
6080 * @cfg {Number} width Specifies the width of a table
6081 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
6083 * @cfg {boolean} striped Should the rows be alternative striped
6084 * @cfg {boolean} bordered Add borders to the table
6085 * @cfg {boolean} hover Add hover highlighting
6086 * @cfg {boolean} condensed Format condensed
6087 * @cfg {boolean} responsive Format condensed
6088 * @cfg {Boolean} loadMask (true|false) default false
6089 * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
6090 * @cfg {Boolean} headerShow (true|false) generate thead, default true
6091 * @cfg {Boolean} rowSelection (true|false) default false
6092 * @cfg {Boolean} cellSelection (true|false) default false
6093 * @cfg {Boolean} scrollBody (true|false) default false - body scrolled / fixed header
6094 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
6095 * @cfg {Boolean} lazyLoad auto load data while scrolling to the end (default false)
6096 * @cfg {Boolean} auto_hide_footer auto hide footer if only one page (default false)
6100 * Create a new Table
6101 * @param {Object} config The config object
6104 Roo.bootstrap.Table = function(config){
6105 Roo.bootstrap.Table.superclass.constructor.call(this, config);
6110 this.rowSelection = (typeof(config.rowSelection) != 'undefined') ? config.rowSelection : this.rowSelection;
6111 this.cellSelection = (typeof(config.cellSelection) != 'undefined') ? config.cellSelection : this.cellSelection;
6112 this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
6113 this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
6115 this.sm = this.sm || {xtype: 'RowSelectionModel'};
6117 this.sm.grid = this;
6118 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
6119 this.sm = this.selModel;
6120 this.sm.xmodule = this.xmodule || false;
6123 if (this.cm && typeof(this.cm.config) == 'undefined') {
6124 this.colModel = new Roo.grid.ColumnModel(this.cm);
6125 this.cm = this.colModel;
6126 this.cm.xmodule = this.xmodule || false;
6129 this.store= Roo.factory(this.store, Roo.data);
6130 this.ds = this.store;
6131 this.ds.xmodule = this.xmodule || false;
6134 if (this.footer && this.store) {
6135 this.footer.dataSource = this.ds;
6136 this.footer = Roo.factory(this.footer);
6143 * Fires when a cell is clicked
6144 * @param {Roo.bootstrap.Table} this
6145 * @param {Roo.Element} el
6146 * @param {Number} rowIndex
6147 * @param {Number} columnIndex
6148 * @param {Roo.EventObject} e
6152 * @event celldblclick
6153 * Fires when a cell is double clicked
6154 * @param {Roo.bootstrap.Table} this
6155 * @param {Roo.Element} el
6156 * @param {Number} rowIndex
6157 * @param {Number} columnIndex
6158 * @param {Roo.EventObject} e
6160 "celldblclick" : true,
6163 * Fires when a row is clicked
6164 * @param {Roo.bootstrap.Table} this
6165 * @param {Roo.Element} el
6166 * @param {Number} rowIndex
6167 * @param {Roo.EventObject} e
6171 * @event rowdblclick
6172 * Fires when a row is double clicked
6173 * @param {Roo.bootstrap.Table} this
6174 * @param {Roo.Element} el
6175 * @param {Number} rowIndex
6176 * @param {Roo.EventObject} e
6178 "rowdblclick" : true,
6181 * Fires when a mouseover occur
6182 * @param {Roo.bootstrap.Table} this
6183 * @param {Roo.Element} el
6184 * @param {Number} rowIndex
6185 * @param {Number} columnIndex
6186 * @param {Roo.EventObject} e
6191 * Fires when a mouseout occur
6192 * @param {Roo.bootstrap.Table} this
6193 * @param {Roo.Element} el
6194 * @param {Number} rowIndex
6195 * @param {Number} columnIndex
6196 * @param {Roo.EventObject} e
6201 * Fires when a row is rendered, so you can change add a style to it.
6202 * @param {Roo.bootstrap.Table} this
6203 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
6207 * @event rowsrendered
6208 * Fires when all the rows have been rendered
6209 * @param {Roo.bootstrap.Table} this
6211 'rowsrendered' : true,
6213 * @event contextmenu
6214 * The raw contextmenu event for the entire grid.
6215 * @param {Roo.EventObject} e
6217 "contextmenu" : true,
6219 * @event rowcontextmenu
6220 * Fires when a row is right clicked
6221 * @param {Roo.bootstrap.Table} this
6222 * @param {Number} rowIndex
6223 * @param {Roo.EventObject} e
6225 "rowcontextmenu" : true,
6227 * @event cellcontextmenu
6228 * Fires when a cell is right clicked
6229 * @param {Roo.bootstrap.Table} this
6230 * @param {Number} rowIndex
6231 * @param {Number} cellIndex
6232 * @param {Roo.EventObject} e
6234 "cellcontextmenu" : true,
6236 * @event headercontextmenu
6237 * Fires when a header is right clicked
6238 * @param {Roo.bootstrap.Table} this
6239 * @param {Number} columnIndex
6240 * @param {Roo.EventObject} e
6242 "headercontextmenu" : true
6246 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
6272 rowSelection : false,
6273 cellSelection : false,
6276 // Roo.Element - the tbody
6278 // Roo.Element - thead element
6281 container: false, // used by gridpanel...
6287 auto_hide_footer : false,
6289 getAutoCreate : function()
6291 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
6298 if (this.scrollBody) {
6299 cfg.cls += ' table-body-fixed';
6302 cfg.cls += ' table-striped';
6306 cfg.cls += ' table-hover';
6308 if (this.bordered) {
6309 cfg.cls += ' table-bordered';
6311 if (this.condensed) {
6312 cfg.cls += ' table-condensed';
6314 if (this.responsive) {
6315 cfg.cls += ' table-responsive';
6319 cfg.cls+= ' ' +this.cls;
6322 // this lot should be simplifed...
6335 ].forEach(function(k) {
6343 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
6346 if(this.store || this.cm){
6347 if(this.headerShow){
6348 cfg.cn.push(this.renderHeader());
6351 cfg.cn.push(this.renderBody());
6353 if(this.footerShow){
6354 cfg.cn.push(this.renderFooter());
6356 // where does this come from?
6357 //cfg.cls+= ' TableGrid';
6360 return { cn : [ cfg ] };
6363 initEvents : function()
6365 if(!this.store || !this.cm){
6368 if (this.selModel) {
6369 this.selModel.initEvents();
6373 //Roo.log('initEvents with ds!!!!');
6375 this.mainBody = this.el.select('tbody', true).first();
6376 this.mainHead = this.el.select('thead', true).first();
6377 this.mainFoot = this.el.select('tfoot', true).first();
6383 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6384 e.on('click', _this.sort, _this);
6387 this.mainBody.on("click", this.onClick, this);
6388 this.mainBody.on("dblclick", this.onDblClick, this);
6390 // why is this done????? = it breaks dialogs??
6391 //this.parent().el.setStyle('position', 'relative');
6395 this.footer.parentId = this.id;
6396 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
6399 this.el.select('tfoot tr td').first().addClass('hide');
6404 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
6407 this.store.on('load', this.onLoad, this);
6408 this.store.on('beforeload', this.onBeforeLoad, this);
6409 this.store.on('update', this.onUpdate, this);
6410 this.store.on('add', this.onAdd, this);
6411 this.store.on("clear", this.clear, this);
6413 this.el.on("contextmenu", this.onContextMenu, this);
6415 this.mainBody.on('scroll', this.onBodyScroll, this);
6417 this.cm.on("headerchange", this.onHeaderChange, this);
6419 this.cm.on("hiddenchange", this.onHiddenChange, this, arguments);
6423 onContextMenu : function(e, t)
6425 this.processEvent("contextmenu", e);
6428 processEvent : function(name, e)
6430 if (name != 'touchstart' ) {
6431 this.fireEvent(name, e);
6434 var t = e.getTarget();
6436 var cell = Roo.get(t);
6442 if(cell.findParent('tfoot', false, true)){
6446 if(cell.findParent('thead', false, true)){
6448 if(e.getTarget().nodeName.toLowerCase() != 'th'){
6449 cell = Roo.get(t).findParent('th', false, true);
6451 Roo.log("failed to find th in thead?");
6452 Roo.log(e.getTarget());
6457 var cellIndex = cell.dom.cellIndex;
6459 var ename = name == 'touchstart' ? 'click' : name;
6460 this.fireEvent("header" + ename, this, cellIndex, e);
6465 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6466 cell = Roo.get(t).findParent('td', false, true);
6468 Roo.log("failed to find th in tbody?");
6469 Roo.log(e.getTarget());
6474 var row = cell.findParent('tr', false, true);
6475 var cellIndex = cell.dom.cellIndex;
6476 var rowIndex = row.dom.rowIndex - 1;
6480 this.fireEvent("row" + name, this, rowIndex, e);
6484 this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
6490 onMouseover : function(e, el)
6492 var cell = Roo.get(el);
6498 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6499 cell = cell.findParent('td', false, true);
6502 var row = cell.findParent('tr', false, true);
6503 var cellIndex = cell.dom.cellIndex;
6504 var rowIndex = row.dom.rowIndex - 1; // start from 0
6506 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
6510 onMouseout : function(e, el)
6512 var cell = Roo.get(el);
6518 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6519 cell = cell.findParent('td', false, true);
6522 var row = cell.findParent('tr', false, true);
6523 var cellIndex = cell.dom.cellIndex;
6524 var rowIndex = row.dom.rowIndex - 1; // start from 0
6526 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
6530 onClick : function(e, el)
6532 var cell = Roo.get(el);
6534 if(!cell || (!this.cellSelection && !this.rowSelection)){
6538 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6539 cell = cell.findParent('td', false, true);
6542 if(!cell || typeof(cell) == 'undefined'){
6546 var row = cell.findParent('tr', false, true);
6548 if(!row || typeof(row) == 'undefined'){
6552 var cellIndex = cell.dom.cellIndex;
6553 var rowIndex = this.getRowIndex(row);
6555 // why??? - should these not be based on SelectionModel?
6556 if(this.cellSelection){
6557 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
6560 if(this.rowSelection){
6561 this.fireEvent('rowclick', this, row, rowIndex, e);
6567 onDblClick : function(e,el)
6569 var cell = Roo.get(el);
6571 if(!cell || (!this.cellSelection && !this.rowSelection)){
6575 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6576 cell = cell.findParent('td', false, true);
6579 if(!cell || typeof(cell) == 'undefined'){
6583 var row = cell.findParent('tr', false, true);
6585 if(!row || typeof(row) == 'undefined'){
6589 var cellIndex = cell.dom.cellIndex;
6590 var rowIndex = this.getRowIndex(row);
6592 if(this.cellSelection){
6593 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
6596 if(this.rowSelection){
6597 this.fireEvent('rowdblclick', this, row, rowIndex, e);
6601 sort : function(e,el)
6603 var col = Roo.get(el);
6605 if(!col.hasClass('sortable')){
6609 var sort = col.attr('sort');
6612 if(col.select('i', true).first().hasClass('glyphicon-arrow-up')){
6616 this.store.sortInfo = {field : sort, direction : dir};
6619 Roo.log("calling footer first");
6620 this.footer.onClick('first');
6623 this.store.load({ params : { start : 0 } });
6627 renderHeader : function()
6635 this.totalWidth = 0;
6637 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6639 var config = cm.config[i];
6643 cls : 'x-hcol-' + i,
6645 html: cm.getColumnHeader(i)
6650 if(typeof(config.sortable) != 'undefined' && config.sortable){
6652 c.html = '<i class="glyphicon"></i>' + c.html;
6655 if(typeof(config.lgHeader) != 'undefined'){
6656 hh += '<span class="hidden-xs hidden-sm hidden-md">' + config.lgHeader + '</span>';
6659 if(typeof(config.mdHeader) != 'undefined'){
6660 hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
6663 if(typeof(config.smHeader) != 'undefined'){
6664 hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
6667 if(typeof(config.xsHeader) != 'undefined'){
6668 hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
6675 if(typeof(config.tooltip) != 'undefined'){
6676 c.tooltip = config.tooltip;
6679 if(typeof(config.colspan) != 'undefined'){
6680 c.colspan = config.colspan;
6683 if(typeof(config.hidden) != 'undefined' && config.hidden){
6684 c.style += ' display:none;';
6687 if(typeof(config.dataIndex) != 'undefined'){
6688 c.sort = config.dataIndex;
6693 if(typeof(config.align) != 'undefined' && config.align.length){
6694 c.style += ' text-align:' + config.align + ';';
6697 if(typeof(config.width) != 'undefined'){
6698 c.style += ' width:' + config.width + 'px;';
6699 this.totalWidth += config.width;
6701 this.totalWidth += 100; // assume minimum of 100 per column?
6704 if(typeof(config.cls) != 'undefined'){
6705 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
6708 ['xs','sm','md','lg'].map(function(size){
6710 if(typeof(config[size]) == 'undefined'){
6714 if (!config[size]) { // 0 = hidden
6715 c.cls += ' hidden-' + size;
6719 c.cls += ' col-' + size + '-' + config[size];
6729 renderBody : function()
6739 colspan : this.cm.getColumnCount()
6749 renderFooter : function()
6759 colspan : this.cm.getColumnCount()
6773 // Roo.log('ds onload');
6778 var ds = this.store;
6780 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6781 e.select('i', true).removeClass(['glyphicon-arrow-up', 'glyphicon-arrow-down']);
6782 if (_this.store.sortInfo) {
6784 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
6785 e.select('i', true).addClass(['glyphicon-arrow-up']);
6788 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
6789 e.select('i', true).addClass(['glyphicon-arrow-down']);
6794 var tbody = this.mainBody;
6796 if(ds.getCount() > 0){
6797 ds.data.each(function(d,rowIndex){
6798 var row = this.renderRow(cm, ds, rowIndex);
6800 tbody.createChild(row);
6804 if(row.cellObjects.length){
6805 Roo.each(row.cellObjects, function(r){
6806 _this.renderCellObject(r);
6813 var tfoot = this.el.select('tfoot', true).first();
6815 if(this.footerShow && this.auto_hide_footer && this.mainFoot){
6817 this.mainFoot.setVisibilityMode(Roo.Element.DISPLAY).hide();
6819 var total = this.ds.getTotalCount();
6821 if(this.footer.pageSize < total){
6822 this.mainFoot.show();
6826 Roo.each(this.el.select('tbody td', true).elements, function(e){
6827 e.on('mouseover', _this.onMouseover, _this);
6830 Roo.each(this.el.select('tbody td', true).elements, function(e){
6831 e.on('mouseout', _this.onMouseout, _this);
6833 this.fireEvent('rowsrendered', this);
6839 onUpdate : function(ds,record)
6841 this.refreshRow(record);
6845 onRemove : function(ds, record, index, isUpdate){
6846 if(isUpdate !== true){
6847 this.fireEvent("beforerowremoved", this, index, record);
6849 var bt = this.mainBody.dom;
6851 var rows = this.el.select('tbody > tr', true).elements;
6853 if(typeof(rows[index]) != 'undefined'){
6854 bt.removeChild(rows[index].dom);
6857 // if(bt.rows[index]){
6858 // bt.removeChild(bt.rows[index]);
6861 if(isUpdate !== true){
6862 //this.stripeRows(index);
6863 //this.syncRowHeights(index, index);
6865 this.fireEvent("rowremoved", this, index, record);
6869 onAdd : function(ds, records, rowIndex)
6871 //Roo.log('on Add called');
6872 // - note this does not handle multiple adding very well..
6873 var bt = this.mainBody.dom;
6874 for (var i =0 ; i < records.length;i++) {
6875 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
6876 //Roo.log(records[i]);
6877 //Roo.log(this.store.getAt(rowIndex+i));
6878 this.insertRow(this.store, rowIndex + i, false);
6885 refreshRow : function(record){
6886 var ds = this.store, index;
6887 if(typeof record == 'number'){
6889 record = ds.getAt(index);
6891 index = ds.indexOf(record);
6893 this.insertRow(ds, index, true);
6895 this.onRemove(ds, record, index+1, true);
6897 //this.syncRowHeights(index, index);
6899 this.fireEvent("rowupdated", this, index, record);
6902 insertRow : function(dm, rowIndex, isUpdate){
6905 this.fireEvent("beforerowsinserted", this, rowIndex);
6907 //var s = this.getScrollState();
6908 var row = this.renderRow(this.cm, this.store, rowIndex);
6909 // insert before rowIndex..
6910 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
6914 if(row.cellObjects.length){
6915 Roo.each(row.cellObjects, function(r){
6916 _this.renderCellObject(r);
6921 this.fireEvent("rowsinserted", this, rowIndex);
6922 //this.syncRowHeights(firstRow, lastRow);
6923 //this.stripeRows(firstRow);
6930 getRowDom : function(rowIndex)
6932 var rows = this.el.select('tbody > tr', true).elements;
6934 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
6937 // returns the object tree for a tr..
6940 renderRow : function(cm, ds, rowIndex)
6942 var d = ds.getAt(rowIndex);
6946 cls : 'x-row-' + rowIndex,
6950 var cellObjects = [];
6952 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6953 var config = cm.config[i];
6955 var renderer = cm.getRenderer(i);
6959 if(typeof(renderer) !== 'undefined'){
6960 value = renderer(d.data[cm.getDataIndex(i)], false, d);
6962 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
6963 // and are rendered into the cells after the row is rendered - using the id for the element.
6965 if(typeof(value) === 'object'){
6975 rowIndex : rowIndex,
6980 this.fireEvent('rowclass', this, rowcfg);
6984 cls : rowcfg.rowClass + ' x-col-' + i,
6986 html: (typeof(value) === 'object') ? '' : value
6993 if(typeof(config.colspan) != 'undefined'){
6994 td.colspan = config.colspan;
6997 if(typeof(config.hidden) != 'undefined' && config.hidden){
6998 td.style += ' display:none;';
7001 if(typeof(config.align) != 'undefined' && config.align.length){
7002 td.style += ' text-align:' + config.align + ';';
7004 if(typeof(config.valign) != 'undefined' && config.valign.length){
7005 td.style += ' vertical-align:' + config.valign + ';';
7008 if(typeof(config.width) != 'undefined'){
7009 td.style += ' width:' + config.width + 'px;';
7012 if(typeof(config.cursor) != 'undefined'){
7013 td.style += ' cursor:' + config.cursor + ';';
7016 if(typeof(config.cls) != 'undefined'){
7017 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
7020 ['xs','sm','md','lg'].map(function(size){
7022 if(typeof(config[size]) == 'undefined'){
7026 if (!config[size]) { // 0 = hidden
7027 td.cls += ' hidden-' + size;
7031 td.cls += ' col-' + size + '-' + config[size];
7039 row.cellObjects = cellObjects;
7047 onBeforeLoad : function()
7056 this.el.select('tbody', true).first().dom.innerHTML = '';
7059 * Show or hide a row.
7060 * @param {Number} rowIndex to show or hide
7061 * @param {Boolean} state hide
7063 setRowVisibility : function(rowIndex, state)
7065 var bt = this.mainBody.dom;
7067 var rows = this.el.select('tbody > tr', true).elements;
7069 if(typeof(rows[rowIndex]) == 'undefined'){
7072 rows[rowIndex].dom.style.display = state ? '' : 'none';
7076 getSelectionModel : function(){
7078 this.selModel = new Roo.bootstrap.Table.RowSelectionModel({grid: this});
7080 return this.selModel;
7083 * Render the Roo.bootstrap object from renderder
7085 renderCellObject : function(r)
7089 r.cfg.parentId = (typeof(r.container) == 'string') ? r.container : r.container.id;
7091 var t = r.cfg.render(r.container);
7094 Roo.each(r.cfg.cn, function(c){
7096 container: t.getChildContainer(),
7099 _this.renderCellObject(child);
7104 getRowIndex : function(row)
7108 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
7119 * Returns the grid's underlying element = used by panel.Grid
7120 * @return {Element} The element
7122 getGridEl : function(){
7126 * Forces a resize - used by panel.Grid
7127 * @return {Element} The element
7129 autoSize : function()
7131 //var ctr = Roo.get(this.container.dom.parentElement);
7132 var ctr = Roo.get(this.el.dom);
7134 var thd = this.getGridEl().select('thead',true).first();
7135 var tbd = this.getGridEl().select('tbody', true).first();
7136 var tfd = this.getGridEl().select('tfoot', true).first();
7138 var cw = ctr.getWidth();
7142 tbd.setSize(ctr.getWidth(),
7143 ctr.getHeight() - ((thd ? thd.getHeight() : 0) + (tfd ? tfd.getHeight() : 0))
7145 var barsize = (tbd.dom.offsetWidth - tbd.dom.clientWidth);
7148 cw = Math.max(cw, this.totalWidth);
7149 this.getGridEl().select('tr',true).setWidth(cw);
7150 // resize 'expandable coloumn?
7152 return; // we doe not have a view in this design..
7155 onBodyScroll: function()
7157 //Roo.log("body scrolled');" + this.mainBody.dom.scrollLeft);
7159 this.mainHead.setStyle({
7160 'position' : 'relative',
7161 'left': (-1* this.mainBody.dom.scrollLeft) + 'px'
7167 var scrollHeight = this.mainBody.dom.scrollHeight;
7169 var scrollTop = Math.ceil(this.mainBody.getScroll().top);
7171 var height = this.mainBody.getHeight();
7173 if(scrollHeight - height == scrollTop) {
7175 var total = this.ds.getTotalCount();
7177 if(this.footer.cursor + this.footer.pageSize < total){
7179 this.footer.ds.load({
7181 start : this.footer.cursor + this.footer.pageSize,
7182 limit : this.footer.pageSize
7192 onHeaderChange : function()
7194 var header = this.renderHeader();
7195 var table = this.el.select('table', true).first();
7197 this.mainHead.remove();
7198 this.mainHead = table.createChild(header, this.mainBody, false);
7201 onHiddenChange : function(colModel, colIndex, hidden)
7203 var thSelector = '#' + this.id + ' .x-hcol-' + colIndex;
7204 var tdSelector = '#' + this.id + ' .x-col-' + colIndex;
7206 this.CSS.updateRule(thSelector, "display", "");
7207 this.CSS.updateRule(tdSelector, "display", "");
7210 this.CSS.updateRule(thSelector, "display", "none");
7211 this.CSS.updateRule(tdSelector, "display", "none");
7214 this.onHeaderChange();
7218 setColumnWidth: function(col_index, width)
7220 // width = "md-2 xs-2..."
7221 if(!this.colModel.config[col_index]) {
7225 var w = width.split(" ");
7227 var rows = this.el.dom.getElementsByClassName("x-col-"+col_index);
7229 var h_row = this.el.dom.getElementsByClassName("x-hcol-"+col_index);
7232 for(var j = 0; j < w.length; j++) {
7238 var size_cls = w[j].split("-");
7240 if(!Number.isInteger(size_cls[1] * 1)) {
7244 if(!this.colModel.config[col_index][size_cls[0]]) {
7248 if(!h_row[0].classList.contains("col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]])) {
7252 h_row[0].classList.replace(
7253 "col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]],
7254 "col-"+size_cls[0]+"-"+size_cls[1]
7257 for(var i = 0; i < rows.length; i++) {
7259 var size_cls = w[j].split("-");
7261 if(!Number.isInteger(size_cls[1] * 1)) {
7265 if(!this.colModel.config[col_index][size_cls[0]]) {
7269 if(!rows[i].classList.contains("col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]])) {
7273 rows[i].classList.replace(
7274 "col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]],
7275 "col-"+size_cls[0]+"-"+size_cls[1]
7279 this.colModel.config[col_index][size_cls[0]] = size_cls[1];
7294 * @class Roo.bootstrap.TableCell
7295 * @extends Roo.bootstrap.Component
7296 * Bootstrap TableCell class
7297 * @cfg {String} html cell contain text
7298 * @cfg {String} cls cell class
7299 * @cfg {String} tag cell tag (td|th) default td
7300 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
7301 * @cfg {String} align Aligns the content in a cell
7302 * @cfg {String} axis Categorizes cells
7303 * @cfg {String} bgcolor Specifies the background color of a cell
7304 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7305 * @cfg {Number} colspan Specifies the number of columns a cell should span
7306 * @cfg {String} headers Specifies one or more header cells a cell is related to
7307 * @cfg {Number} height Sets the height of a cell
7308 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
7309 * @cfg {Number} rowspan Sets the number of rows a cell should span
7310 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
7311 * @cfg {String} valign Vertical aligns the content in a cell
7312 * @cfg {Number} width Specifies the width of a cell
7315 * Create a new TableCell
7316 * @param {Object} config The config object
7319 Roo.bootstrap.TableCell = function(config){
7320 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
7323 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
7343 getAutoCreate : function(){
7344 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
7364 cfg.align=this.align
7370 cfg.bgcolor=this.bgcolor
7373 cfg.charoff=this.charoff
7376 cfg.colspan=this.colspan
7379 cfg.headers=this.headers
7382 cfg.height=this.height
7385 cfg.nowrap=this.nowrap
7388 cfg.rowspan=this.rowspan
7391 cfg.scope=this.scope
7394 cfg.valign=this.valign
7397 cfg.width=this.width
7416 * @class Roo.bootstrap.TableRow
7417 * @extends Roo.bootstrap.Component
7418 * Bootstrap TableRow class
7419 * @cfg {String} cls row class
7420 * @cfg {String} align Aligns the content in a table row
7421 * @cfg {String} bgcolor Specifies a background color for a table row
7422 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7423 * @cfg {String} valign Vertical aligns the content in a table row
7426 * Create a new TableRow
7427 * @param {Object} config The config object
7430 Roo.bootstrap.TableRow = function(config){
7431 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
7434 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
7442 getAutoCreate : function(){
7443 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
7453 cfg.align = this.align;
7456 cfg.bgcolor = this.bgcolor;
7459 cfg.charoff = this.charoff;
7462 cfg.valign = this.valign;
7480 * @class Roo.bootstrap.TableBody
7481 * @extends Roo.bootstrap.Component
7482 * Bootstrap TableBody class
7483 * @cfg {String} cls element class
7484 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
7485 * @cfg {String} align Aligns the content inside the element
7486 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
7487 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
7490 * Create a new TableBody
7491 * @param {Object} config The config object
7494 Roo.bootstrap.TableBody = function(config){
7495 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
7498 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
7506 getAutoCreate : function(){
7507 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
7521 cfg.align = this.align;
7524 cfg.charoff = this.charoff;
7527 cfg.valign = this.valign;
7534 // initEvents : function()
7541 // this.store = Roo.factory(this.store, Roo.data);
7542 // this.store.on('load', this.onLoad, this);
7544 // this.store.load();
7548 // onLoad: function ()
7550 // this.fireEvent('load', this);
7560 * Ext JS Library 1.1.1
7561 * Copyright(c) 2006-2007, Ext JS, LLC.
7563 * Originally Released Under LGPL - original licence link has changed is not relivant.
7566 * <script type="text/javascript">
7569 // as we use this in bootstrap.
7570 Roo.namespace('Roo.form');
7572 * @class Roo.form.Action
7573 * Internal Class used to handle form actions
7575 * @param {Roo.form.BasicForm} el The form element or its id
7576 * @param {Object} config Configuration options
7581 // define the action interface
7582 Roo.form.Action = function(form, options){
7584 this.options = options || {};
7587 * Client Validation Failed
7590 Roo.form.Action.CLIENT_INVALID = 'client';
7592 * Server Validation Failed
7595 Roo.form.Action.SERVER_INVALID = 'server';
7597 * Connect to Server Failed
7600 Roo.form.Action.CONNECT_FAILURE = 'connect';
7602 * Reading Data from Server Failed
7605 Roo.form.Action.LOAD_FAILURE = 'load';
7607 Roo.form.Action.prototype = {
7609 failureType : undefined,
7610 response : undefined,
7614 run : function(options){
7619 success : function(response){
7624 handleResponse : function(response){
7628 // default connection failure
7629 failure : function(response){
7631 this.response = response;
7632 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7633 this.form.afterAction(this, false);
7636 processResponse : function(response){
7637 this.response = response;
7638 if(!response.responseText){
7641 this.result = this.handleResponse(response);
7645 // utility functions used internally
7646 getUrl : function(appendParams){
7647 var url = this.options.url || this.form.url || this.form.el.dom.action;
7649 var p = this.getParams();
7651 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
7657 getMethod : function(){
7658 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
7661 getParams : function(){
7662 var bp = this.form.baseParams;
7663 var p = this.options.params;
7665 if(typeof p == "object"){
7666 p = Roo.urlEncode(Roo.applyIf(p, bp));
7667 }else if(typeof p == 'string' && bp){
7668 p += '&' + Roo.urlEncode(bp);
7671 p = Roo.urlEncode(bp);
7676 createCallback : function(){
7678 success: this.success,
7679 failure: this.failure,
7681 timeout: (this.form.timeout*1000),
7682 upload: this.form.fileUpload ? this.success : undefined
7687 Roo.form.Action.Submit = function(form, options){
7688 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
7691 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
7694 haveProgress : false,
7695 uploadComplete : false,
7697 // uploadProgress indicator.
7698 uploadProgress : function()
7700 if (!this.form.progressUrl) {
7704 if (!this.haveProgress) {
7705 Roo.MessageBox.progress("Uploading", "Uploading");
7707 if (this.uploadComplete) {
7708 Roo.MessageBox.hide();
7712 this.haveProgress = true;
7714 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
7716 var c = new Roo.data.Connection();
7718 url : this.form.progressUrl,
7723 success : function(req){
7724 //console.log(data);
7728 rdata = Roo.decode(req.responseText)
7730 Roo.log("Invalid data from server..");
7734 if (!rdata || !rdata.success) {
7736 Roo.MessageBox.alert(Roo.encode(rdata));
7739 var data = rdata.data;
7741 if (this.uploadComplete) {
7742 Roo.MessageBox.hide();
7747 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
7748 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
7751 this.uploadProgress.defer(2000,this);
7754 failure: function(data) {
7755 Roo.log('progress url failed ');
7766 // run get Values on the form, so it syncs any secondary forms.
7767 this.form.getValues();
7769 var o = this.options;
7770 var method = this.getMethod();
7771 var isPost = method == 'POST';
7772 if(o.clientValidation === false || this.form.isValid()){
7774 if (this.form.progressUrl) {
7775 this.form.findField('UPLOAD_IDENTIFIER').setValue(
7776 (new Date() * 1) + '' + Math.random());
7781 Roo.Ajax.request(Roo.apply(this.createCallback(), {
7782 form:this.form.el.dom,
7783 url:this.getUrl(!isPost),
7785 params:isPost ? this.getParams() : null,
7786 isUpload: this.form.fileUpload
7789 this.uploadProgress();
7791 }else if (o.clientValidation !== false){ // client validation failed
7792 this.failureType = Roo.form.Action.CLIENT_INVALID;
7793 this.form.afterAction(this, false);
7797 success : function(response)
7799 this.uploadComplete= true;
7800 if (this.haveProgress) {
7801 Roo.MessageBox.hide();
7805 var result = this.processResponse(response);
7806 if(result === true || result.success){
7807 this.form.afterAction(this, true);
7811 this.form.markInvalid(result.errors);
7812 this.failureType = Roo.form.Action.SERVER_INVALID;
7814 this.form.afterAction(this, false);
7816 failure : function(response)
7818 this.uploadComplete= true;
7819 if (this.haveProgress) {
7820 Roo.MessageBox.hide();
7823 this.response = response;
7824 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7825 this.form.afterAction(this, false);
7828 handleResponse : function(response){
7829 if(this.form.errorReader){
7830 var rs = this.form.errorReader.read(response);
7833 for(var i = 0, len = rs.records.length; i < len; i++) {
7834 var r = rs.records[i];
7838 if(errors.length < 1){
7842 success : rs.success,
7848 ret = Roo.decode(response.responseText);
7852 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
7862 Roo.form.Action.Load = function(form, options){
7863 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
7864 this.reader = this.form.reader;
7867 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
7872 Roo.Ajax.request(Roo.apply(
7873 this.createCallback(), {
7874 method:this.getMethod(),
7875 url:this.getUrl(false),
7876 params:this.getParams()
7880 success : function(response){
7882 var result = this.processResponse(response);
7883 if(result === true || !result.success || !result.data){
7884 this.failureType = Roo.form.Action.LOAD_FAILURE;
7885 this.form.afterAction(this, false);
7888 this.form.clearInvalid();
7889 this.form.setValues(result.data);
7890 this.form.afterAction(this, true);
7893 handleResponse : function(response){
7894 if(this.form.reader){
7895 var rs = this.form.reader.read(response);
7896 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
7898 success : rs.success,
7902 return Roo.decode(response.responseText);
7906 Roo.form.Action.ACTION_TYPES = {
7907 'load' : Roo.form.Action.Load,
7908 'submit' : Roo.form.Action.Submit
7917 * @class Roo.bootstrap.Form
7918 * @extends Roo.bootstrap.Component
7919 * Bootstrap Form class
7920 * @cfg {String} method GET | POST (default POST)
7921 * @cfg {String} labelAlign top | left (default top)
7922 * @cfg {String} align left | right - for navbars
7923 * @cfg {Boolean} loadMask load mask when submit (default true)
7928 * @param {Object} config The config object
7932 Roo.bootstrap.Form = function(config){
7934 Roo.bootstrap.Form.superclass.constructor.call(this, config);
7936 Roo.bootstrap.Form.popover.apply();
7940 * @event clientvalidation
7941 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
7942 * @param {Form} this
7943 * @param {Boolean} valid true if the form has passed client-side validation
7945 clientvalidation: true,
7947 * @event beforeaction
7948 * Fires before any action is performed. Return false to cancel the action.
7949 * @param {Form} this
7950 * @param {Action} action The action to be performed
7954 * @event actionfailed
7955 * Fires when an action fails.
7956 * @param {Form} this
7957 * @param {Action} action The action that failed
7959 actionfailed : true,
7961 * @event actioncomplete
7962 * Fires when an action is completed.
7963 * @param {Form} this
7964 * @param {Action} action The action that completed
7966 actioncomplete : true
7970 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
7973 * @cfg {String} method
7974 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
7979 * The URL to use for form actions if one isn't supplied in the action options.
7982 * @cfg {Boolean} fileUpload
7983 * Set to true if this form is a file upload.
7987 * @cfg {Object} baseParams
7988 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
7992 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
7996 * @cfg {Sting} align (left|right) for navbar forms
8001 activeAction : null,
8004 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
8005 * element by passing it or its id or mask the form itself by passing in true.
8008 waitMsgTarget : false,
8013 * @cfg {Boolean} errorMask (true|false) default false
8018 * @cfg {Number} maskOffset Default 100
8023 * @cfg {Boolean} maskBody
8027 getAutoCreate : function(){
8031 method : this.method || 'POST',
8032 id : this.id || Roo.id(),
8035 if (this.parent().xtype.match(/^Nav/)) {
8036 cfg.cls = 'navbar-form form-inline navbar-' + this.align;
8040 if (this.labelAlign == 'left' ) {
8041 cfg.cls += ' form-horizontal';
8047 initEvents : function()
8049 this.el.on('submit', this.onSubmit, this);
8050 // this was added as random key presses on the form where triggering form submit.
8051 this.el.on('keypress', function(e) {
8052 if (e.getCharCode() != 13) {
8055 // we might need to allow it for textareas.. and some other items.
8056 // check e.getTarget().
8058 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
8062 Roo.log("keypress blocked");
8070 onSubmit : function(e){
8075 * Returns true if client-side validation on the form is successful.
8078 isValid : function(){
8079 var items = this.getItems();
8083 items.each(function(f){
8089 Roo.log('invalid field: ' + f.name);
8093 if(!target && f.el.isVisible(true)){
8099 if(this.errorMask && !valid){
8100 Roo.bootstrap.Form.popover.mask(this, target);
8107 * Returns true if any fields in this form have changed since their original load.
8110 isDirty : function(){
8112 var items = this.getItems();
8113 items.each(function(f){
8123 * Performs a predefined action (submit or load) or custom actions you define on this form.
8124 * @param {String} actionName The name of the action type
8125 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
8126 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
8127 * accept other config options):
8129 Property Type Description
8130 ---------------- --------------- ----------------------------------------------------------------------------------
8131 url String The url for the action (defaults to the form's url)
8132 method String The form method to use (defaults to the form's method, or POST if not defined)
8133 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
8134 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
8135 validate the form on the client (defaults to false)
8137 * @return {BasicForm} this
8139 doAction : function(action, options){
8140 if(typeof action == 'string'){
8141 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
8143 if(this.fireEvent('beforeaction', this, action) !== false){
8144 this.beforeAction(action);
8145 action.run.defer(100, action);
8151 beforeAction : function(action){
8152 var o = action.options;
8157 Roo.get(document.body).mask(o.waitMsg || "Sending", 'x-mask-loading')
8159 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
8162 // not really supported yet.. ??
8164 //if(this.waitMsgTarget === true){
8165 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
8166 //}else if(this.waitMsgTarget){
8167 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
8168 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
8170 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
8176 afterAction : function(action, success){
8177 this.activeAction = null;
8178 var o = action.options;
8183 Roo.get(document.body).unmask();
8189 //if(this.waitMsgTarget === true){
8190 // this.el.unmask();
8191 //}else if(this.waitMsgTarget){
8192 // this.waitMsgTarget.unmask();
8194 // Roo.MessageBox.updateProgress(1);
8195 // Roo.MessageBox.hide();
8202 Roo.callback(o.success, o.scope, [this, action]);
8203 this.fireEvent('actioncomplete', this, action);
8207 // failure condition..
8208 // we have a scenario where updates need confirming.
8209 // eg. if a locking scenario exists..
8210 // we look for { errors : { needs_confirm : true }} in the response.
8212 (typeof(action.result) != 'undefined') &&
8213 (typeof(action.result.errors) != 'undefined') &&
8214 (typeof(action.result.errors.needs_confirm) != 'undefined')
8217 Roo.log("not supported yet");
8220 Roo.MessageBox.confirm(
8221 "Change requires confirmation",
8222 action.result.errorMsg,
8227 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
8237 Roo.callback(o.failure, o.scope, [this, action]);
8238 // show an error message if no failed handler is set..
8239 if (!this.hasListener('actionfailed')) {
8240 Roo.log("need to add dialog support");
8242 Roo.MessageBox.alert("Error",
8243 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
8244 action.result.errorMsg :
8245 "Saving Failed, please check your entries or try again"
8250 this.fireEvent('actionfailed', this, action);
8255 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
8256 * @param {String} id The value to search for
8259 findField : function(id){
8260 var items = this.getItems();
8261 var field = items.get(id);
8263 items.each(function(f){
8264 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
8271 return field || null;
8274 * Mark fields in this form invalid in bulk.
8275 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
8276 * @return {BasicForm} this
8278 markInvalid : function(errors){
8279 if(errors instanceof Array){
8280 for(var i = 0, len = errors.length; i < len; i++){
8281 var fieldError = errors[i];
8282 var f = this.findField(fieldError.id);
8284 f.markInvalid(fieldError.msg);
8290 if(typeof errors[id] != 'function' && (field = this.findField(id))){
8291 field.markInvalid(errors[id]);
8295 //Roo.each(this.childForms || [], function (f) {
8296 // f.markInvalid(errors);
8303 * Set values for fields in this form in bulk.
8304 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
8305 * @return {BasicForm} this
8307 setValues : function(values){
8308 if(values instanceof Array){ // array of objects
8309 for(var i = 0, len = values.length; i < len; i++){
8311 var f = this.findField(v.id);
8313 f.setValue(v.value);
8314 if(this.trackResetOnLoad){
8315 f.originalValue = f.getValue();
8319 }else{ // object hash
8322 if(typeof values[id] != 'function' && (field = this.findField(id))){
8324 if (field.setFromData &&
8326 field.displayField &&
8327 // combos' with local stores can
8328 // be queried via setValue()
8329 // to set their value..
8330 (field.store && !field.store.isLocal)
8334 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
8335 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
8336 field.setFromData(sd);
8338 } else if(field.setFromData && (field.store && !field.store.isLocal)) {
8340 field.setFromData(values);
8343 field.setValue(values[id]);
8347 if(this.trackResetOnLoad){
8348 field.originalValue = field.getValue();
8354 //Roo.each(this.childForms || [], function (f) {
8355 // f.setValues(values);
8362 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
8363 * they are returned as an array.
8364 * @param {Boolean} asString
8367 getValues : function(asString){
8368 //if (this.childForms) {
8369 // copy values from the child forms
8370 // Roo.each(this.childForms, function (f) {
8371 // this.setValues(f.getValues());
8377 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
8378 if(asString === true){
8381 return Roo.urlDecode(fs);
8385 * Returns the fields in this form as an object with key/value pairs.
8386 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
8389 getFieldValues : function(with_hidden)
8391 var items = this.getItems();
8393 items.each(function(f){
8399 var v = f.getValue();
8401 if (f.inputType =='radio') {
8402 if (typeof(ret[f.getName()]) == 'undefined') {
8403 ret[f.getName()] = ''; // empty..
8406 if (!f.el.dom.checked) {
8414 if(f.xtype == 'MoneyField'){
8415 ret[f.currencyName] = f.getCurrency();
8418 // not sure if this supported any more..
8419 if ((typeof(v) == 'object') && f.getRawValue) {
8420 v = f.getRawValue() ; // dates..
8422 // combo boxes where name != hiddenName...
8423 if (f.name !== false && f.name != '' && f.name != f.getName()) {
8424 ret[f.name] = f.getRawValue();
8426 ret[f.getName()] = v;
8433 * Clears all invalid messages in this form.
8434 * @return {BasicForm} this
8436 clearInvalid : function(){
8437 var items = this.getItems();
8439 items.each(function(f){
8448 * @return {BasicForm} this
8451 var items = this.getItems();
8452 items.each(function(f){
8456 Roo.each(this.childForms || [], function (f) {
8464 getItems : function()
8466 var r=new Roo.util.MixedCollection(false, function(o){
8467 return o.id || (o.id = Roo.id());
8469 var iter = function(el) {
8476 Roo.each(el.items,function(e) {
8485 hideFields : function(items)
8487 Roo.each(items, function(i){
8489 var f = this.findField(i);
8500 showFields : function(items)
8502 Roo.each(items, function(i){
8504 var f = this.findField(i);
8517 Roo.apply(Roo.bootstrap.Form, {
8544 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
8545 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
8546 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
8547 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
8550 this.maskEl.top.enableDisplayMode("block");
8551 this.maskEl.left.enableDisplayMode("block");
8552 this.maskEl.bottom.enableDisplayMode("block");
8553 this.maskEl.right.enableDisplayMode("block");
8555 this.toolTip = new Roo.bootstrap.Tooltip({
8556 cls : 'roo-form-error-popover',
8558 'left' : ['r-l', [-2,0], 'right'],
8559 'right' : ['l-r', [2,0], 'left'],
8560 'bottom' : ['tl-bl', [0,2], 'top'],
8561 'top' : [ 'bl-tl', [0,-2], 'bottom']
8565 this.toolTip.render(Roo.get(document.body));
8567 this.toolTip.el.enableDisplayMode("block");
8569 Roo.get(document.body).on('click', function(){
8573 Roo.get(document.body).on('touchstart', function(){
8577 this.isApplied = true
8580 mask : function(form, target)
8584 this.target = target;
8586 if(!this.form.errorMask || !target.el){
8590 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.modal', 100, true) || Roo.get(document.body);
8592 Roo.log(scrollable);
8594 var ot = this.target.el.calcOffsetsTo(scrollable);
8596 var scrollTo = ot[1] - this.form.maskOffset;
8598 scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
8600 scrollable.scrollTo('top', scrollTo);
8602 var box = this.target.el.getBox();
8604 var zIndex = Roo.bootstrap.Modal.zIndex++;
8607 this.maskEl.top.setStyle('position', 'absolute');
8608 this.maskEl.top.setStyle('z-index', zIndex);
8609 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
8610 this.maskEl.top.setLeft(0);
8611 this.maskEl.top.setTop(0);
8612 this.maskEl.top.show();
8614 this.maskEl.left.setStyle('position', 'absolute');
8615 this.maskEl.left.setStyle('z-index', zIndex);
8616 this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
8617 this.maskEl.left.setLeft(0);
8618 this.maskEl.left.setTop(box.y - this.padding);
8619 this.maskEl.left.show();
8621 this.maskEl.bottom.setStyle('position', 'absolute');
8622 this.maskEl.bottom.setStyle('z-index', zIndex);
8623 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
8624 this.maskEl.bottom.setLeft(0);
8625 this.maskEl.bottom.setTop(box.bottom + this.padding);
8626 this.maskEl.bottom.show();
8628 this.maskEl.right.setStyle('position', 'absolute');
8629 this.maskEl.right.setStyle('z-index', zIndex);
8630 this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
8631 this.maskEl.right.setLeft(box.right + this.padding);
8632 this.maskEl.right.setTop(box.y - this.padding);
8633 this.maskEl.right.show();
8635 this.toolTip.bindEl = this.target.el;
8637 this.toolTip.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
8639 var tip = this.target.blankText;
8641 if(this.target.getValue() !== '' ) {
8643 if (this.target.invalidText.length) {
8644 tip = this.target.invalidText;
8645 } else if (this.target.regexText.length){
8646 tip = this.target.regexText;
8650 this.toolTip.show(tip);
8652 this.intervalID = window.setInterval(function() {
8653 Roo.bootstrap.Form.popover.unmask();
8656 window.onwheel = function(){ return false;};
8658 (function(){ this.isMasked = true; }).defer(500, this);
8664 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
8668 this.maskEl.top.setStyle('position', 'absolute');
8669 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
8670 this.maskEl.top.hide();
8672 this.maskEl.left.setStyle('position', 'absolute');
8673 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
8674 this.maskEl.left.hide();
8676 this.maskEl.bottom.setStyle('position', 'absolute');
8677 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
8678 this.maskEl.bottom.hide();
8680 this.maskEl.right.setStyle('position', 'absolute');
8681 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
8682 this.maskEl.right.hide();
8684 this.toolTip.hide();
8686 this.toolTip.el.hide();
8688 window.onwheel = function(){ return true;};
8690 if(this.intervalID){
8691 window.clearInterval(this.intervalID);
8692 this.intervalID = false;
8695 this.isMasked = false;
8705 * Ext JS Library 1.1.1
8706 * Copyright(c) 2006-2007, Ext JS, LLC.
8708 * Originally Released Under LGPL - original licence link has changed is not relivant.
8711 * <script type="text/javascript">
8714 * @class Roo.form.VTypes
8715 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
8718 Roo.form.VTypes = function(){
8719 // closure these in so they are only created once.
8720 var alpha = /^[a-zA-Z_]+$/;
8721 var alphanum = /^[a-zA-Z0-9_]+$/;
8722 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
8723 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
8725 // All these messages and functions are configurable
8728 * The function used to validate email addresses
8729 * @param {String} value The email address
8731 'email' : function(v){
8732 return email.test(v);
8735 * The error text to display when the email validation function returns false
8738 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
8740 * The keystroke filter mask to be applied on email input
8743 'emailMask' : /[a-z0-9_\.\-@]/i,
8746 * The function used to validate URLs
8747 * @param {String} value The URL
8749 'url' : function(v){
8753 * The error text to display when the url validation function returns false
8756 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
8759 * The function used to validate alpha values
8760 * @param {String} value The value
8762 'alpha' : function(v){
8763 return alpha.test(v);
8766 * The error text to display when the alpha validation function returns false
8769 'alphaText' : 'This field should only contain letters and _',
8771 * The keystroke filter mask to be applied on alpha input
8774 'alphaMask' : /[a-z_]/i,
8777 * The function used to validate alphanumeric values
8778 * @param {String} value The value
8780 'alphanum' : function(v){
8781 return alphanum.test(v);
8784 * The error text to display when the alphanumeric validation function returns false
8787 'alphanumText' : 'This field should only contain letters, numbers and _',
8789 * The keystroke filter mask to be applied on alphanumeric input
8792 'alphanumMask' : /[a-z0-9_]/i
8802 * @class Roo.bootstrap.Input
8803 * @extends Roo.bootstrap.Component
8804 * Bootstrap Input class
8805 * @cfg {Boolean} disabled is it disabled
8806 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
8807 * @cfg {String} name name of the input
8808 * @cfg {string} fieldLabel - the label associated
8809 * @cfg {string} placeholder - placeholder to put in text.
8810 * @cfg {string} before - input group add on before
8811 * @cfg {string} after - input group add on after
8812 * @cfg {string} size - (lg|sm) or leave empty..
8813 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
8814 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
8815 * @cfg {Number} md colspan out of 12 for computer-sized screens
8816 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
8817 * @cfg {string} value default value of the input
8818 * @cfg {Number} labelWidth set the width of label
8819 * @cfg {Number} labellg set the width of label (1-12)
8820 * @cfg {Number} labelmd set the width of label (1-12)
8821 * @cfg {Number} labelsm set the width of label (1-12)
8822 * @cfg {Number} labelxs set the width of label (1-12)
8823 * @cfg {String} labelAlign (top|left)
8824 * @cfg {Boolean} readOnly Specifies that the field should be read-only
8825 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
8826 * @cfg {String} indicatorpos (left|right) default left
8827 * @cfg {String} capture (user|camera) use for file input only. (default empty)
8828 * @cfg {String} accept (image|video|audio) use for file input only. (default empty)
8830 * @cfg {String} align (left|center|right) Default left
8831 * @cfg {Boolean} forceFeedback (true|false) Default false
8834 * Create a new Input
8835 * @param {Object} config The config object
8838 Roo.bootstrap.Input = function(config){
8840 Roo.bootstrap.Input.superclass.constructor.call(this, config);
8845 * Fires when this field receives input focus.
8846 * @param {Roo.form.Field} this
8851 * Fires when this field loses input focus.
8852 * @param {Roo.form.Field} this
8857 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
8858 * {@link Roo.EventObject#getKey} to determine which key was pressed.
8859 * @param {Roo.form.Field} this
8860 * @param {Roo.EventObject} e The event object
8865 * Fires just before the field blurs if the field value has changed.
8866 * @param {Roo.form.Field} this
8867 * @param {Mixed} newValue The new value
8868 * @param {Mixed} oldValue The original value
8873 * Fires after the field has been marked as invalid.
8874 * @param {Roo.form.Field} this
8875 * @param {String} msg The validation message
8880 * Fires after the field has been validated with no errors.
8881 * @param {Roo.form.Field} this
8886 * Fires after the key up
8887 * @param {Roo.form.Field} this
8888 * @param {Roo.EventObject} e The event Object
8894 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
8896 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
8897 automatic validation (defaults to "keyup").
8899 validationEvent : "keyup",
8901 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
8903 validateOnBlur : true,
8905 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
8907 validationDelay : 250,
8909 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
8911 focusClass : "x-form-focus", // not needed???
8915 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
8917 invalidClass : "has-warning",
8920 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
8922 validClass : "has-success",
8925 * @cfg {Boolean} hasFeedback (true|false) default true
8930 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8932 invalidFeedbackClass : "glyphicon-warning-sign",
8935 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8937 validFeedbackClass : "glyphicon-ok",
8940 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
8942 selectOnFocus : false,
8945 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
8949 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
8954 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
8956 disableKeyFilter : false,
8959 * @cfg {Boolean} disabled True to disable the field (defaults to false).
8963 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
8967 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
8969 blankText : "Please complete this mandatory field",
8972 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
8976 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
8978 maxLength : Number.MAX_VALUE,
8980 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
8982 minLengthText : "The minimum length for this field is {0}",
8984 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
8986 maxLengthText : "The maximum length for this field is {0}",
8990 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
8991 * If available, this function will be called only after the basic validators all return true, and will be passed the
8992 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
8996 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
8997 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
8998 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
9002 * @cfg {String} regexText -- Depricated - use Invalid Text
9007 * @cfg {String} invalidText The error text to display if {@link #validator} test fails during validation (defaults to "")
9013 autocomplete: false,
9032 formatedValue : false,
9033 forceFeedback : false,
9035 indicatorpos : 'left',
9045 parentLabelAlign : function()
9048 while (parent.parent()) {
9049 parent = parent.parent();
9050 if (typeof(parent.labelAlign) !='undefined') {
9051 return parent.labelAlign;
9058 getAutoCreate : function()
9060 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9066 if(this.inputType != 'hidden'){
9067 cfg.cls = 'form-group' //input-group
9073 type : this.inputType,
9075 cls : 'form-control',
9076 placeholder : this.placeholder || '',
9077 autocomplete : this.autocomplete || 'new-password'
9080 if(this.capture.length){
9081 input.capture = this.capture;
9084 if(this.accept.length){
9085 input.accept = this.accept + "/*";
9089 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
9092 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9093 input.maxLength = this.maxLength;
9096 if (this.disabled) {
9097 input.disabled=true;
9100 if (this.readOnly) {
9101 input.readonly=true;
9105 input.name = this.name;
9109 input.cls += ' input-' + this.size;
9113 ['xs','sm','md','lg'].map(function(size){
9114 if (settings[size]) {
9115 cfg.cls += ' col-' + size + '-' + settings[size];
9119 var inputblock = input;
9123 cls: 'glyphicon form-control-feedback'
9126 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9129 cls : 'has-feedback',
9137 if (this.before || this.after) {
9140 cls : 'input-group',
9144 if (this.before && typeof(this.before) == 'string') {
9146 inputblock.cn.push({
9148 cls : 'roo-input-before input-group-addon input-group-prepend input-group-text',
9152 if (this.before && typeof(this.before) == 'object') {
9153 this.before = Roo.factory(this.before);
9155 inputblock.cn.push({
9157 cls : 'roo-input-before input-group-prepend input-group-text input-group-' +
9158 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
9162 inputblock.cn.push(input);
9164 if (this.after && typeof(this.after) == 'string') {
9165 inputblock.cn.push({
9167 cls : 'roo-input-after input-group-append input-group-text input-group-addon',
9171 if (this.after && typeof(this.after) == 'object') {
9172 this.after = Roo.factory(this.after);
9174 inputblock.cn.push({
9176 cls : 'roo-input-after input-group-append input-group-text input-group-' +
9177 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
9181 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9182 inputblock.cls += ' has-feedback';
9183 inputblock.cn.push(feedback);
9188 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
9189 tooltip : 'This field is required'
9191 if (Roo.bootstrap.version == 4) {
9194 style : 'display-none'
9197 if (align ==='left' && this.fieldLabel.length) {
9199 cfg.cls += ' roo-form-group-label-left row';
9206 cls : 'control-label col-form-label',
9207 html : this.fieldLabel
9218 var labelCfg = cfg.cn[1];
9219 var contentCfg = cfg.cn[2];
9221 if(this.indicatorpos == 'right'){
9226 cls : 'control-label col-form-label',
9230 html : this.fieldLabel
9244 labelCfg = cfg.cn[0];
9245 contentCfg = cfg.cn[1];
9249 if(this.labelWidth > 12){
9250 labelCfg.style = "width: " + this.labelWidth + 'px';
9253 if(this.labelWidth < 13 && this.labelmd == 0){
9254 this.labelmd = this.labelWidth;
9257 if(this.labellg > 0){
9258 labelCfg.cls += ' col-lg-' + this.labellg;
9259 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
9262 if(this.labelmd > 0){
9263 labelCfg.cls += ' col-md-' + this.labelmd;
9264 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
9267 if(this.labelsm > 0){
9268 labelCfg.cls += ' col-sm-' + this.labelsm;
9269 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
9272 if(this.labelxs > 0){
9273 labelCfg.cls += ' col-xs-' + this.labelxs;
9274 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
9278 } else if ( this.fieldLabel.length) {
9283 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
9284 tooltip : 'This field is required'
9288 //cls : 'input-group-addon',
9289 html : this.fieldLabel
9297 if(this.indicatorpos == 'right'){
9302 //cls : 'input-group-addon',
9303 html : this.fieldLabel
9308 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9309 tooltip : 'This field is required'
9329 if (this.parentType === 'Navbar' && this.parent().bar) {
9330 cfg.cls += ' navbar-form';
9333 if (this.parentType === 'NavGroup') {
9334 cfg.cls += ' navbar-form';
9342 * return the real input element.
9344 inputEl: function ()
9346 return this.el.select('input.form-control',true).first();
9349 tooltipEl : function()
9351 return this.inputEl();
9354 indicatorEl : function()
9356 if (Roo.bootstrap.version == 4) {
9357 return false; // not enabled in v4 yet.
9360 var indicator = this.el.select('i.roo-required-indicator',true).first();
9370 setDisabled : function(v)
9372 var i = this.inputEl().dom;
9374 i.removeAttribute('disabled');
9378 i.setAttribute('disabled','true');
9380 initEvents : function()
9383 this.inputEl().on("keydown" , this.fireKey, this);
9384 this.inputEl().on("focus", this.onFocus, this);
9385 this.inputEl().on("blur", this.onBlur, this);
9387 this.inputEl().relayEvent('keyup', this);
9389 this.indicator = this.indicatorEl();
9392 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible'); // changed from invisible??? -
9395 // reference to original value for reset
9396 this.originalValue = this.getValue();
9397 //Roo.form.TextField.superclass.initEvents.call(this);
9398 if(this.validationEvent == 'keyup'){
9399 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
9400 this.inputEl().on('keyup', this.filterValidation, this);
9402 else if(this.validationEvent !== false){
9403 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
9406 if(this.selectOnFocus){
9407 this.on("focus", this.preFocus, this);
9410 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
9411 this.inputEl().on("keypress", this.filterKeys, this);
9413 this.inputEl().relayEvent('keypress', this);
9416 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
9417 this.el.on("click", this.autoSize, this);
9420 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
9421 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
9424 if (typeof(this.before) == 'object') {
9425 this.before.render(this.el.select('.roo-input-before',true).first());
9427 if (typeof(this.after) == 'object') {
9428 this.after.render(this.el.select('.roo-input-after',true).first());
9431 this.inputEl().on('change', this.onChange, this);
9434 filterValidation : function(e){
9435 if(!e.isNavKeyPress()){
9436 this.validationTask.delay(this.validationDelay);
9440 * Validates the field value
9441 * @return {Boolean} True if the value is valid, else false
9443 validate : function(){
9444 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
9445 if(this.disabled || this.validateValue(this.getRawValue())){
9456 * Validates a value according to the field's validation rules and marks the field as invalid
9457 * if the validation fails
9458 * @param {Mixed} value The value to validate
9459 * @return {Boolean} True if the value is valid, else false
9461 validateValue : function(value)
9463 if(this.getVisibilityEl().hasClass('hidden')){
9467 if(value.length < 1) { // if it's blank
9468 if(this.allowBlank){
9474 if(value.length < this.minLength){
9477 if(value.length > this.maxLength){
9481 var vt = Roo.form.VTypes;
9482 if(!vt[this.vtype](value, this)){
9486 if(typeof this.validator == "function"){
9487 var msg = this.validator(value);
9491 if (typeof(msg) == 'string') {
9492 this.invalidText = msg;
9496 if(this.regex && !this.regex.test(value)){
9504 fireKey : function(e){
9505 //Roo.log('field ' + e.getKey());
9506 if(e.isNavKeyPress()){
9507 this.fireEvent("specialkey", this, e);
9510 focus : function (selectText){
9512 this.inputEl().focus();
9513 if(selectText === true){
9514 this.inputEl().dom.select();
9520 onFocus : function(){
9521 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9522 // this.el.addClass(this.focusClass);
9525 this.hasFocus = true;
9526 this.startValue = this.getValue();
9527 this.fireEvent("focus", this);
9531 beforeBlur : Roo.emptyFn,
9535 onBlur : function(){
9537 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9538 //this.el.removeClass(this.focusClass);
9540 this.hasFocus = false;
9541 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
9544 var v = this.getValue();
9545 if(String(v) !== String(this.startValue)){
9546 this.fireEvent('change', this, v, this.startValue);
9548 this.fireEvent("blur", this);
9551 onChange : function(e)
9553 var v = this.getValue();
9554 if(String(v) !== String(this.startValue)){
9555 this.fireEvent('change', this, v, this.startValue);
9561 * Resets the current field value to the originally loaded value and clears any validation messages
9564 this.setValue(this.originalValue);
9568 * Returns the name of the field
9569 * @return {Mixed} name The name field
9571 getName: function(){
9575 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
9576 * @return {Mixed} value The field value
9578 getValue : function(){
9580 var v = this.inputEl().getValue();
9585 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
9586 * @return {Mixed} value The field value
9588 getRawValue : function(){
9589 var v = this.inputEl().getValue();
9595 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
9596 * @param {Mixed} value The value to set
9598 setRawValue : function(v){
9599 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9602 selectText : function(start, end){
9603 var v = this.getRawValue();
9605 start = start === undefined ? 0 : start;
9606 end = end === undefined ? v.length : end;
9607 var d = this.inputEl().dom;
9608 if(d.setSelectionRange){
9609 d.setSelectionRange(start, end);
9610 }else if(d.createTextRange){
9611 var range = d.createTextRange();
9612 range.moveStart("character", start);
9613 range.moveEnd("character", v.length-end);
9620 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
9621 * @param {Mixed} value The value to set
9623 setValue : function(v){
9626 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9632 processValue : function(value){
9633 if(this.stripCharsRe){
9634 var newValue = value.replace(this.stripCharsRe, '');
9635 if(newValue !== value){
9636 this.setRawValue(newValue);
9643 preFocus : function(){
9645 if(this.selectOnFocus){
9646 this.inputEl().dom.select();
9649 filterKeys : function(e){
9651 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
9654 var c = e.getCharCode(), cc = String.fromCharCode(c);
9655 if(Roo.isIE && (e.isSpecialKey() || !cc)){
9658 if(!this.maskRe.test(cc)){
9663 * Clear any invalid styles/messages for this field
9665 clearInvalid : function(){
9667 if(!this.el || this.preventMark){ // not rendered
9672 this.el.removeClass(this.invalidClass);
9674 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9676 var feedback = this.el.select('.form-control-feedback', true).first();
9679 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9685 this.indicator.removeClass('visible');
9686 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9689 this.fireEvent('valid', this);
9693 * Mark this field as valid
9695 markValid : function()
9697 if(!this.el || this.preventMark){ // not rendered...
9701 this.el.removeClass([this.invalidClass, this.validClass]);
9703 var feedback = this.el.select('.form-control-feedback', true).first();
9706 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9710 this.indicator.removeClass('visible');
9711 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9718 if(this.allowBlank && !this.getRawValue().length){
9722 this.el.addClass(this.validClass);
9724 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9726 var feedback = this.el.select('.form-control-feedback', true).first();
9729 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9730 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9735 this.fireEvent('valid', this);
9739 * Mark this field as invalid
9740 * @param {String} msg The validation message
9742 markInvalid : function(msg)
9744 if(!this.el || this.preventMark){ // not rendered
9748 this.el.removeClass([this.invalidClass, this.validClass]);
9750 var feedback = this.el.select('.form-control-feedback', true).first();
9753 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9760 if(this.allowBlank && !this.getRawValue().length){
9765 this.indicator.removeClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9766 this.indicator.addClass('visible');
9769 this.el.addClass(this.invalidClass);
9771 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9773 var feedback = this.el.select('.form-control-feedback', true).first();
9776 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9778 if(this.getValue().length || this.forceFeedback){
9779 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9786 this.fireEvent('invalid', this, msg);
9789 SafariOnKeyDown : function(event)
9791 // this is a workaround for a password hang bug on chrome/ webkit.
9792 if (this.inputEl().dom.type != 'password') {
9796 var isSelectAll = false;
9798 if(this.inputEl().dom.selectionEnd > 0){
9799 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
9801 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
9802 event.preventDefault();
9807 if(isSelectAll && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
9809 event.preventDefault();
9810 // this is very hacky as keydown always get's upper case.
9812 var cc = String.fromCharCode(event.getCharCode());
9813 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
9817 adjustWidth : function(tag, w){
9818 tag = tag.toLowerCase();
9819 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
9820 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
9824 if(tag == 'textarea'){
9827 }else if(Roo.isOpera){
9831 if(tag == 'textarea'){
9839 setFieldLabel : function(v)
9845 if(this.indicatorEl()){
9846 var ar = this.el.select('label > span',true);
9848 if (ar.elements.length) {
9849 this.el.select('label > span',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9850 this.fieldLabel = v;
9854 var br = this.el.select('label',true);
9856 if(br.elements.length) {
9857 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9858 this.fieldLabel = v;
9862 Roo.log('Cannot Found any of label > span || label in input');
9866 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9867 this.fieldLabel = v;
9882 * @class Roo.bootstrap.TextArea
9883 * @extends Roo.bootstrap.Input
9884 * Bootstrap TextArea class
9885 * @cfg {Number} cols Specifies the visible width of a text area
9886 * @cfg {Number} rows Specifies the visible number of lines in a text area
9887 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
9888 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
9889 * @cfg {string} html text
9892 * Create a new TextArea
9893 * @param {Object} config The config object
9896 Roo.bootstrap.TextArea = function(config){
9897 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
9901 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
9911 getAutoCreate : function(){
9913 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9919 if(this.inputType != 'hidden'){
9920 cfg.cls = 'form-group' //input-group
9928 value : this.value || '',
9929 html: this.html || '',
9930 cls : 'form-control',
9931 placeholder : this.placeholder || ''
9935 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9936 input.maxLength = this.maxLength;
9940 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
9944 input.cols = this.cols;
9947 if (this.readOnly) {
9948 input.readonly = true;
9952 input.name = this.name;
9956 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
9960 ['xs','sm','md','lg'].map(function(size){
9961 if (settings[size]) {
9962 cfg.cls += ' col-' + size + '-' + settings[size];
9966 var inputblock = input;
9968 if(this.hasFeedback && !this.allowBlank){
9972 cls: 'glyphicon form-control-feedback'
9976 cls : 'has-feedback',
9985 if (this.before || this.after) {
9988 cls : 'input-group',
9992 inputblock.cn.push({
9994 cls : 'input-group-addon',
9999 inputblock.cn.push(input);
10001 if(this.hasFeedback && !this.allowBlank){
10002 inputblock.cls += ' has-feedback';
10003 inputblock.cn.push(feedback);
10007 inputblock.cn.push({
10009 cls : 'input-group-addon',
10016 if (align ==='left' && this.fieldLabel.length) {
10021 cls : 'control-label',
10022 html : this.fieldLabel
10033 if(this.labelWidth > 12){
10034 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
10037 if(this.labelWidth < 13 && this.labelmd == 0){
10038 this.labelmd = this.labelWidth;
10041 if(this.labellg > 0){
10042 cfg.cn[0].cls += ' col-lg-' + this.labellg;
10043 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
10046 if(this.labelmd > 0){
10047 cfg.cn[0].cls += ' col-md-' + this.labelmd;
10048 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
10051 if(this.labelsm > 0){
10052 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
10053 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
10056 if(this.labelxs > 0){
10057 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
10058 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
10061 } else if ( this.fieldLabel.length) {
10066 //cls : 'input-group-addon',
10067 html : this.fieldLabel
10085 if (this.disabled) {
10086 input.disabled=true;
10093 * return the real textarea element.
10095 inputEl: function ()
10097 return this.el.select('textarea.form-control',true).first();
10101 * Clear any invalid styles/messages for this field
10103 clearInvalid : function()
10106 if(!this.el || this.preventMark){ // not rendered
10110 var label = this.el.select('label', true).first();
10111 var icon = this.el.select('i.fa-star', true).first();
10117 this.el.removeClass(this.invalidClass);
10119 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10121 var feedback = this.el.select('.form-control-feedback', true).first();
10124 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
10129 this.fireEvent('valid', this);
10133 * Mark this field as valid
10135 markValid : function()
10137 if(!this.el || this.preventMark){ // not rendered
10141 this.el.removeClass([this.invalidClass, this.validClass]);
10143 var feedback = this.el.select('.form-control-feedback', true).first();
10146 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10149 if(this.disabled || this.allowBlank){
10153 var label = this.el.select('label', true).first();
10154 var icon = this.el.select('i.fa-star', true).first();
10160 this.el.addClass(this.validClass);
10162 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
10164 var feedback = this.el.select('.form-control-feedback', true).first();
10167 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10168 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
10173 this.fireEvent('valid', this);
10177 * Mark this field as invalid
10178 * @param {String} msg The validation message
10180 markInvalid : function(msg)
10182 if(!this.el || this.preventMark){ // not rendered
10186 this.el.removeClass([this.invalidClass, this.validClass]);
10188 var feedback = this.el.select('.form-control-feedback', true).first();
10191 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10194 if(this.disabled || this.allowBlank){
10198 var label = this.el.select('label', true).first();
10199 var icon = this.el.select('i.fa-star', true).first();
10201 if(!this.getValue().length && label && !icon){
10202 this.el.createChild({
10204 cls : 'text-danger fa fa-lg fa-star',
10205 tooltip : 'This field is required',
10206 style : 'margin-right:5px;'
10210 this.el.addClass(this.invalidClass);
10212 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10214 var feedback = this.el.select('.form-control-feedback', true).first();
10217 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10219 if(this.getValue().length || this.forceFeedback){
10220 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
10227 this.fireEvent('invalid', this, msg);
10235 * trigger field - base class for combo..
10240 * @class Roo.bootstrap.TriggerField
10241 * @extends Roo.bootstrap.Input
10242 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
10243 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
10244 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
10245 * for which you can provide a custom implementation. For example:
10247 var trigger = new Roo.bootstrap.TriggerField();
10248 trigger.onTriggerClick = myTriggerFn;
10249 trigger.applyTo('my-field');
10252 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
10253 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
10254 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
10255 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
10256 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
10259 * Create a new TriggerField.
10260 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
10261 * to the base TextField)
10263 Roo.bootstrap.TriggerField = function(config){
10264 this.mimicing = false;
10265 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
10268 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
10270 * @cfg {String} triggerClass A CSS class to apply to the trigger
10273 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
10278 * @cfg {Boolean} removable (true|false) special filter default false
10282 /** @cfg {Boolean} grow @hide */
10283 /** @cfg {Number} growMin @hide */
10284 /** @cfg {Number} growMax @hide */
10290 autoSize: Roo.emptyFn,
10294 deferHeight : true,
10297 actionMode : 'wrap',
10302 getAutoCreate : function(){
10304 var align = this.labelAlign || this.parentLabelAlign();
10309 cls: 'form-group' //input-group
10316 type : this.inputType,
10317 cls : 'form-control',
10318 autocomplete: 'new-password',
10319 placeholder : this.placeholder || ''
10323 input.name = this.name;
10326 input.cls += ' input-' + this.size;
10329 if (this.disabled) {
10330 input.disabled=true;
10333 var inputblock = input;
10335 if(this.hasFeedback && !this.allowBlank){
10339 cls: 'glyphicon form-control-feedback'
10342 if(this.removable && !this.editable && !this.tickable){
10344 cls : 'has-feedback',
10350 cls : 'roo-combo-removable-btn close'
10357 cls : 'has-feedback',
10366 if(this.removable && !this.editable && !this.tickable){
10368 cls : 'roo-removable',
10374 cls : 'roo-combo-removable-btn close'
10381 if (this.before || this.after) {
10384 cls : 'input-group',
10388 inputblock.cn.push({
10390 cls : 'input-group-addon input-group-prepend input-group-text',
10395 inputblock.cn.push(input);
10397 if(this.hasFeedback && !this.allowBlank){
10398 inputblock.cls += ' has-feedback';
10399 inputblock.cn.push(feedback);
10403 inputblock.cn.push({
10405 cls : 'input-group-addon input-group-append input-group-text',
10414 var ibwrap = inputblock;
10419 cls: 'roo-select2-choices',
10423 cls: 'roo-select2-search-field',
10435 cls: 'roo-select2-container input-group',
10440 cls: 'form-hidden-field'
10446 if(!this.multiple && this.showToggleBtn){
10452 if (this.caret != false) {
10455 cls: 'fa fa-' + this.caret
10462 cls : 'input-group-addon input-group-append input-group-text btn dropdown-toggle',
10467 cls: 'combobox-clear',
10481 combobox.cls += ' roo-select2-container-multi';
10485 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
10486 tooltip : 'This field is required'
10488 if (Roo.bootstrap.version == 4) {
10491 style : 'display:none'
10496 if (align ==='left' && this.fieldLabel.length) {
10498 cfg.cls += ' roo-form-group-label-left row';
10505 cls : 'control-label',
10506 html : this.fieldLabel
10518 var labelCfg = cfg.cn[1];
10519 var contentCfg = cfg.cn[2];
10521 if(this.indicatorpos == 'right'){
10526 cls : 'control-label',
10530 html : this.fieldLabel
10544 labelCfg = cfg.cn[0];
10545 contentCfg = cfg.cn[1];
10548 if(this.labelWidth > 12){
10549 labelCfg.style = "width: " + this.labelWidth + 'px';
10552 if(this.labelWidth < 13 && this.labelmd == 0){
10553 this.labelmd = this.labelWidth;
10556 if(this.labellg > 0){
10557 labelCfg.cls += ' col-lg-' + this.labellg;
10558 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
10561 if(this.labelmd > 0){
10562 labelCfg.cls += ' col-md-' + this.labelmd;
10563 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
10566 if(this.labelsm > 0){
10567 labelCfg.cls += ' col-sm-' + this.labelsm;
10568 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
10571 if(this.labelxs > 0){
10572 labelCfg.cls += ' col-xs-' + this.labelxs;
10573 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
10576 } else if ( this.fieldLabel.length) {
10577 // Roo.log(" label");
10582 //cls : 'input-group-addon',
10583 html : this.fieldLabel
10591 if(this.indicatorpos == 'right'){
10599 html : this.fieldLabel
10613 // Roo.log(" no label && no align");
10620 ['xs','sm','md','lg'].map(function(size){
10621 if (settings[size]) {
10622 cfg.cls += ' col-' + size + '-' + settings[size];
10633 onResize : function(w, h){
10634 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
10635 // if(typeof w == 'number'){
10636 // var x = w - this.trigger.getWidth();
10637 // this.inputEl().setWidth(this.adjustWidth('input', x));
10638 // this.trigger.setStyle('left', x+'px');
10643 adjustSize : Roo.BoxComponent.prototype.adjustSize,
10646 getResizeEl : function(){
10647 return this.inputEl();
10651 getPositionEl : function(){
10652 return this.inputEl();
10656 alignErrorIcon : function(){
10657 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
10661 initEvents : function(){
10665 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
10666 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
10667 if(!this.multiple && this.showToggleBtn){
10668 this.trigger = this.el.select('span.dropdown-toggle',true).first();
10669 if(this.hideTrigger){
10670 this.trigger.setDisplayed(false);
10672 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10676 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
10679 if(this.removable && !this.editable && !this.tickable){
10680 var close = this.closeTriggerEl();
10683 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
10684 close.on('click', this.removeBtnClick, this, close);
10688 //this.trigger.addClassOnOver('x-form-trigger-over');
10689 //this.trigger.addClassOnClick('x-form-trigger-click');
10692 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
10696 closeTriggerEl : function()
10698 var close = this.el.select('.roo-combo-removable-btn', true).first();
10699 return close ? close : false;
10702 removeBtnClick : function(e, h, el)
10704 e.preventDefault();
10706 if(this.fireEvent("remove", this) !== false){
10708 this.fireEvent("afterremove", this)
10712 createList : function()
10714 this.list = Roo.get(document.body).createChild({
10715 tag: Roo.bootstrap.version == 4 ? 'div' : 'ul',
10716 cls: 'typeahead typeahead-long dropdown-menu',
10717 style: 'display:none'
10720 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
10725 initTrigger : function(){
10730 onDestroy : function(){
10732 this.trigger.removeAllListeners();
10733 // this.trigger.remove();
10736 // this.wrap.remove();
10738 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
10742 onFocus : function(){
10743 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
10745 if(!this.mimicing){
10746 this.wrap.addClass('x-trigger-wrap-focus');
10747 this.mimicing = true;
10748 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
10749 if(this.monitorTab){
10750 this.el.on("keydown", this.checkTab, this);
10757 checkTab : function(e){
10758 if(e.getKey() == e.TAB){
10759 this.triggerBlur();
10764 onBlur : function(){
10769 mimicBlur : function(e, t){
10771 if(!this.wrap.contains(t) && this.validateBlur()){
10772 this.triggerBlur();
10778 triggerBlur : function(){
10779 this.mimicing = false;
10780 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
10781 if(this.monitorTab){
10782 this.el.un("keydown", this.checkTab, this);
10784 //this.wrap.removeClass('x-trigger-wrap-focus');
10785 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
10789 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
10790 validateBlur : function(e, t){
10795 onDisable : function(){
10796 this.inputEl().dom.disabled = true;
10797 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
10799 // this.wrap.addClass('x-item-disabled');
10804 onEnable : function(){
10805 this.inputEl().dom.disabled = false;
10806 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
10808 // this.el.removeClass('x-item-disabled');
10813 onShow : function(){
10814 var ae = this.getActionEl();
10817 ae.dom.style.display = '';
10818 ae.dom.style.visibility = 'visible';
10824 onHide : function(){
10825 var ae = this.getActionEl();
10826 ae.dom.style.display = 'none';
10830 * The function that should handle the trigger's click event. This method does nothing by default until overridden
10831 * by an implementing function.
10833 * @param {EventObject} e
10835 onTriggerClick : Roo.emptyFn
10839 * Ext JS Library 1.1.1
10840 * Copyright(c) 2006-2007, Ext JS, LLC.
10842 * Originally Released Under LGPL - original licence link has changed is not relivant.
10845 * <script type="text/javascript">
10850 * @class Roo.data.SortTypes
10852 * Defines the default sorting (casting?) comparison functions used when sorting data.
10854 Roo.data.SortTypes = {
10856 * Default sort that does nothing
10857 * @param {Mixed} s The value being converted
10858 * @return {Mixed} The comparison value
10860 none : function(s){
10865 * The regular expression used to strip tags
10869 stripTagsRE : /<\/?[^>]+>/gi,
10872 * Strips all HTML tags to sort on text only
10873 * @param {Mixed} s The value being converted
10874 * @return {String} The comparison value
10876 asText : function(s){
10877 return String(s).replace(this.stripTagsRE, "");
10881 * Strips all HTML tags to sort on text only - Case insensitive
10882 * @param {Mixed} s The value being converted
10883 * @return {String} The comparison value
10885 asUCText : function(s){
10886 return String(s).toUpperCase().replace(this.stripTagsRE, "");
10890 * Case insensitive string
10891 * @param {Mixed} s The value being converted
10892 * @return {String} The comparison value
10894 asUCString : function(s) {
10895 return String(s).toUpperCase();
10900 * @param {Mixed} s The value being converted
10901 * @return {Number} The comparison value
10903 asDate : function(s) {
10907 if(s instanceof Date){
10908 return s.getTime();
10910 return Date.parse(String(s));
10915 * @param {Mixed} s The value being converted
10916 * @return {Float} The comparison value
10918 asFloat : function(s) {
10919 var val = parseFloat(String(s).replace(/,/g, ""));
10928 * @param {Mixed} s The value being converted
10929 * @return {Number} The comparison value
10931 asInt : function(s) {
10932 var val = parseInt(String(s).replace(/,/g, ""));
10940 * Ext JS Library 1.1.1
10941 * Copyright(c) 2006-2007, Ext JS, LLC.
10943 * Originally Released Under LGPL - original licence link has changed is not relivant.
10946 * <script type="text/javascript">
10950 * @class Roo.data.Record
10951 * Instances of this class encapsulate both record <em>definition</em> information, and record
10952 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
10953 * to access Records cached in an {@link Roo.data.Store} object.<br>
10955 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
10956 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
10959 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
10961 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
10962 * {@link #create}. The parameters are the same.
10963 * @param {Array} data An associative Array of data values keyed by the field name.
10964 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
10965 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
10966 * not specified an integer id is generated.
10968 Roo.data.Record = function(data, id){
10969 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
10974 * Generate a constructor for a specific record layout.
10975 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
10976 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
10977 * Each field definition object may contain the following properties: <ul>
10978 * <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,
10979 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
10980 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
10981 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
10982 * is being used, then this is a string containing the javascript expression to reference the data relative to
10983 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
10984 * to the data item relative to the record element. If the mapping expression is the same as the field name,
10985 * this may be omitted.</p></li>
10986 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
10987 * <ul><li>auto (Default, implies no conversion)</li>
10992 * <li>date</li></ul></p></li>
10993 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
10994 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
10995 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
10996 * by the Reader into an object that will be stored in the Record. It is passed the
10997 * following parameters:<ul>
10998 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
11000 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
11002 * <br>usage:<br><pre><code>
11003 var TopicRecord = Roo.data.Record.create(
11004 {name: 'title', mapping: 'topic_title'},
11005 {name: 'author', mapping: 'username'},
11006 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
11007 {name: 'lastPost', mapping: 'post_time', type: 'date'},
11008 {name: 'lastPoster', mapping: 'user2'},
11009 {name: 'excerpt', mapping: 'post_text'}
11012 var myNewRecord = new TopicRecord({
11013 title: 'Do my job please',
11016 lastPost: new Date(),
11017 lastPoster: 'Animal',
11018 excerpt: 'No way dude!'
11020 myStore.add(myNewRecord);
11025 Roo.data.Record.create = function(o){
11026 var f = function(){
11027 f.superclass.constructor.apply(this, arguments);
11029 Roo.extend(f, Roo.data.Record);
11030 var p = f.prototype;
11031 p.fields = new Roo.util.MixedCollection(false, function(field){
11034 for(var i = 0, len = o.length; i < len; i++){
11035 p.fields.add(new Roo.data.Field(o[i]));
11037 f.getField = function(name){
11038 return p.fields.get(name);
11043 Roo.data.Record.AUTO_ID = 1000;
11044 Roo.data.Record.EDIT = 'edit';
11045 Roo.data.Record.REJECT = 'reject';
11046 Roo.data.Record.COMMIT = 'commit';
11048 Roo.data.Record.prototype = {
11050 * Readonly flag - true if this record has been modified.
11059 join : function(store){
11060 this.store = store;
11064 * Set the named field to the specified value.
11065 * @param {String} name The name of the field to set.
11066 * @param {Object} value The value to set the field to.
11068 set : function(name, value){
11069 if(this.data[name] == value){
11073 if(!this.modified){
11074 this.modified = {};
11076 if(typeof this.modified[name] == 'undefined'){
11077 this.modified[name] = this.data[name];
11079 this.data[name] = value;
11080 if(!this.editing && this.store){
11081 this.store.afterEdit(this);
11086 * Get the value of the named field.
11087 * @param {String} name The name of the field to get the value of.
11088 * @return {Object} The value of the field.
11090 get : function(name){
11091 return this.data[name];
11095 beginEdit : function(){
11096 this.editing = true;
11097 this.modified = {};
11101 cancelEdit : function(){
11102 this.editing = false;
11103 delete this.modified;
11107 endEdit : function(){
11108 this.editing = false;
11109 if(this.dirty && this.store){
11110 this.store.afterEdit(this);
11115 * Usually called by the {@link Roo.data.Store} which owns the Record.
11116 * Rejects all changes made to the Record since either creation, or the last commit operation.
11117 * Modified fields are reverted to their original values.
11119 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
11120 * of reject operations.
11122 reject : function(){
11123 var m = this.modified;
11125 if(typeof m[n] != "function"){
11126 this.data[n] = m[n];
11129 this.dirty = false;
11130 delete this.modified;
11131 this.editing = false;
11133 this.store.afterReject(this);
11138 * Usually called by the {@link Roo.data.Store} which owns the Record.
11139 * Commits all changes made to the Record since either creation, or the last commit operation.
11141 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
11142 * of commit operations.
11144 commit : function(){
11145 this.dirty = false;
11146 delete this.modified;
11147 this.editing = false;
11149 this.store.afterCommit(this);
11154 hasError : function(){
11155 return this.error != null;
11159 clearError : function(){
11164 * Creates a copy of this record.
11165 * @param {String} id (optional) A new record id if you don't want to use this record's id
11168 copy : function(newId) {
11169 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
11173 * Ext JS Library 1.1.1
11174 * Copyright(c) 2006-2007, Ext JS, LLC.
11176 * Originally Released Under LGPL - original licence link has changed is not relivant.
11179 * <script type="text/javascript">
11185 * @class Roo.data.Store
11186 * @extends Roo.util.Observable
11187 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
11188 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
11190 * 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
11191 * has no knowledge of the format of the data returned by the Proxy.<br>
11193 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
11194 * instances from the data object. These records are cached and made available through accessor functions.
11196 * Creates a new Store.
11197 * @param {Object} config A config object containing the objects needed for the Store to access data,
11198 * and read the data into Records.
11200 Roo.data.Store = function(config){
11201 this.data = new Roo.util.MixedCollection(false);
11202 this.data.getKey = function(o){
11205 this.baseParams = {};
11207 this.paramNames = {
11212 "multisort" : "_multisort"
11215 if(config && config.data){
11216 this.inlineData = config.data;
11217 delete config.data;
11220 Roo.apply(this, config);
11222 if(this.reader){ // reader passed
11223 this.reader = Roo.factory(this.reader, Roo.data);
11224 this.reader.xmodule = this.xmodule || false;
11225 if(!this.recordType){
11226 this.recordType = this.reader.recordType;
11228 if(this.reader.onMetaChange){
11229 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
11233 if(this.recordType){
11234 this.fields = this.recordType.prototype.fields;
11236 this.modified = [];
11240 * @event datachanged
11241 * Fires when the data cache has changed, and a widget which is using this Store
11242 * as a Record cache should refresh its view.
11243 * @param {Store} this
11245 datachanged : true,
11247 * @event metachange
11248 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
11249 * @param {Store} this
11250 * @param {Object} meta The JSON metadata
11255 * Fires when Records have been added to the Store
11256 * @param {Store} this
11257 * @param {Roo.data.Record[]} records The array of Records added
11258 * @param {Number} index The index at which the record(s) were added
11263 * Fires when a Record has been removed from the Store
11264 * @param {Store} this
11265 * @param {Roo.data.Record} record The Record that was removed
11266 * @param {Number} index The index at which the record was removed
11271 * Fires when a Record has been updated
11272 * @param {Store} this
11273 * @param {Roo.data.Record} record The Record that was updated
11274 * @param {String} operation The update operation being performed. Value may be one of:
11276 Roo.data.Record.EDIT
11277 Roo.data.Record.REJECT
11278 Roo.data.Record.COMMIT
11284 * Fires when the data cache has been cleared.
11285 * @param {Store} this
11289 * @event beforeload
11290 * Fires before a request is made for a new data object. If the beforeload handler returns false
11291 * the load action will be canceled.
11292 * @param {Store} this
11293 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11297 * @event beforeloadadd
11298 * Fires after a new set of Records has been loaded.
11299 * @param {Store} this
11300 * @param {Roo.data.Record[]} records The Records that were loaded
11301 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11303 beforeloadadd : true,
11306 * Fires after a new set of Records has been loaded, before they are added to the store.
11307 * @param {Store} this
11308 * @param {Roo.data.Record[]} records The Records that were loaded
11309 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11310 * @params {Object} return from reader
11314 * @event loadexception
11315 * Fires if an exception occurs in the Proxy during loading.
11316 * Called with the signature of the Proxy's "loadexception" event.
11317 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
11320 * @param {Object} return from JsonData.reader() - success, totalRecords, records
11321 * @param {Object} load options
11322 * @param {Object} jsonData from your request (normally this contains the Exception)
11324 loadexception : true
11328 this.proxy = Roo.factory(this.proxy, Roo.data);
11329 this.proxy.xmodule = this.xmodule || false;
11330 this.relayEvents(this.proxy, ["loadexception"]);
11332 this.sortToggle = {};
11333 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
11335 Roo.data.Store.superclass.constructor.call(this);
11337 if(this.inlineData){
11338 this.loadData(this.inlineData);
11339 delete this.inlineData;
11343 Roo.extend(Roo.data.Store, Roo.util.Observable, {
11345 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
11346 * without a remote query - used by combo/forms at present.
11350 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
11353 * @cfg {Array} data Inline data to be loaded when the store is initialized.
11356 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
11357 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
11360 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
11361 * on any HTTP request
11364 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
11367 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
11371 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
11372 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
11374 remoteSort : false,
11377 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
11378 * loaded or when a record is removed. (defaults to false).
11380 pruneModifiedRecords : false,
11383 lastOptions : null,
11386 * Add Records to the Store and fires the add event.
11387 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11389 add : function(records){
11390 records = [].concat(records);
11391 for(var i = 0, len = records.length; i < len; i++){
11392 records[i].join(this);
11394 var index = this.data.length;
11395 this.data.addAll(records);
11396 this.fireEvent("add", this, records, index);
11400 * Remove a Record from the Store and fires the remove event.
11401 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
11403 remove : function(record){
11404 var index = this.data.indexOf(record);
11405 this.data.removeAt(index);
11407 if(this.pruneModifiedRecords){
11408 this.modified.remove(record);
11410 this.fireEvent("remove", this, record, index);
11414 * Remove all Records from the Store and fires the clear event.
11416 removeAll : function(){
11418 if(this.pruneModifiedRecords){
11419 this.modified = [];
11421 this.fireEvent("clear", this);
11425 * Inserts Records to the Store at the given index and fires the add event.
11426 * @param {Number} index The start index at which to insert the passed Records.
11427 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11429 insert : function(index, records){
11430 records = [].concat(records);
11431 for(var i = 0, len = records.length; i < len; i++){
11432 this.data.insert(index, records[i]);
11433 records[i].join(this);
11435 this.fireEvent("add", this, records, index);
11439 * Get the index within the cache of the passed Record.
11440 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
11441 * @return {Number} The index of the passed Record. Returns -1 if not found.
11443 indexOf : function(record){
11444 return this.data.indexOf(record);
11448 * Get the index within the cache of the Record with the passed id.
11449 * @param {String} id The id of the Record to find.
11450 * @return {Number} The index of the Record. Returns -1 if not found.
11452 indexOfId : function(id){
11453 return this.data.indexOfKey(id);
11457 * Get the Record with the specified id.
11458 * @param {String} id The id of the Record to find.
11459 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
11461 getById : function(id){
11462 return this.data.key(id);
11466 * Get the Record at the specified index.
11467 * @param {Number} index The index of the Record to find.
11468 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
11470 getAt : function(index){
11471 return this.data.itemAt(index);
11475 * Returns a range of Records between specified indices.
11476 * @param {Number} startIndex (optional) The starting index (defaults to 0)
11477 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
11478 * @return {Roo.data.Record[]} An array of Records
11480 getRange : function(start, end){
11481 return this.data.getRange(start, end);
11485 storeOptions : function(o){
11486 o = Roo.apply({}, o);
11489 this.lastOptions = o;
11493 * Loads the Record cache from the configured Proxy using the configured Reader.
11495 * If using remote paging, then the first load call must specify the <em>start</em>
11496 * and <em>limit</em> properties in the options.params property to establish the initial
11497 * position within the dataset, and the number of Records to cache on each read from the Proxy.
11499 * <strong>It is important to note that for remote data sources, loading is asynchronous,
11500 * and this call will return before the new data has been loaded. Perform any post-processing
11501 * in a callback function, or in a "load" event handler.</strong>
11503 * @param {Object} options An object containing properties which control loading options:<ul>
11504 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
11505 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
11506 * passed the following arguments:<ul>
11507 * <li>r : Roo.data.Record[]</li>
11508 * <li>options: Options object from the load call</li>
11509 * <li>success: Boolean success indicator</li></ul></li>
11510 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
11511 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
11514 load : function(options){
11515 options = options || {};
11516 if(this.fireEvent("beforeload", this, options) !== false){
11517 this.storeOptions(options);
11518 var p = Roo.apply(options.params || {}, this.baseParams);
11519 // if meta was not loaded from remote source.. try requesting it.
11520 if (!this.reader.metaFromRemote) {
11521 p._requestMeta = 1;
11523 if(this.sortInfo && this.remoteSort){
11524 var pn = this.paramNames;
11525 p[pn["sort"]] = this.sortInfo.field;
11526 p[pn["dir"]] = this.sortInfo.direction;
11528 if (this.multiSort) {
11529 var pn = this.paramNames;
11530 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
11533 this.proxy.load(p, this.reader, this.loadRecords, this, options);
11538 * Reloads the Record cache from the configured Proxy using the configured Reader and
11539 * the options from the last load operation performed.
11540 * @param {Object} options (optional) An object containing properties which may override the options
11541 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
11542 * the most recently used options are reused).
11544 reload : function(options){
11545 this.load(Roo.applyIf(options||{}, this.lastOptions));
11549 // Called as a callback by the Reader during a load operation.
11550 loadRecords : function(o, options, success){
11551 if(!o || success === false){
11552 if(success !== false){
11553 this.fireEvent("load", this, [], options, o);
11555 if(options.callback){
11556 options.callback.call(options.scope || this, [], options, false);
11560 // if data returned failure - throw an exception.
11561 if (o.success === false) {
11562 // show a message if no listener is registered.
11563 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
11564 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
11566 // loadmask wil be hooked into this..
11567 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
11570 var r = o.records, t = o.totalRecords || r.length;
11572 this.fireEvent("beforeloadadd", this, r, options, o);
11574 if(!options || options.add !== true){
11575 if(this.pruneModifiedRecords){
11576 this.modified = [];
11578 for(var i = 0, len = r.length; i < len; i++){
11582 this.data = this.snapshot;
11583 delete this.snapshot;
11586 this.data.addAll(r);
11587 this.totalLength = t;
11589 this.fireEvent("datachanged", this);
11591 this.totalLength = Math.max(t, this.data.length+r.length);
11595 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
11597 var e = new Roo.data.Record({});
11599 e.set(this.parent.displayField, this.parent.emptyTitle);
11600 e.set(this.parent.valueField, '');
11605 this.fireEvent("load", this, r, options, o);
11606 if(options.callback){
11607 options.callback.call(options.scope || this, r, options, true);
11613 * Loads data from a passed data block. A Reader which understands the format of the data
11614 * must have been configured in the constructor.
11615 * @param {Object} data The data block from which to read the Records. The format of the data expected
11616 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
11617 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
11619 loadData : function(o, append){
11620 var r = this.reader.readRecords(o);
11621 this.loadRecords(r, {add: append}, true);
11625 * Gets the number of cached records.
11627 * <em>If using paging, this may not be the total size of the dataset. If the data object
11628 * used by the Reader contains the dataset size, then the getTotalCount() function returns
11629 * the data set size</em>
11631 getCount : function(){
11632 return this.data.length || 0;
11636 * Gets the total number of records in the dataset as returned by the server.
11638 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
11639 * the dataset size</em>
11641 getTotalCount : function(){
11642 return this.totalLength || 0;
11646 * Returns the sort state of the Store as an object with two properties:
11648 field {String} The name of the field by which the Records are sorted
11649 direction {String} The sort order, "ASC" or "DESC"
11652 getSortState : function(){
11653 return this.sortInfo;
11657 applySort : function(){
11658 if(this.sortInfo && !this.remoteSort){
11659 var s = this.sortInfo, f = s.field;
11660 var st = this.fields.get(f).sortType;
11661 var fn = function(r1, r2){
11662 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
11663 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
11665 this.data.sort(s.direction, fn);
11666 if(this.snapshot && this.snapshot != this.data){
11667 this.snapshot.sort(s.direction, fn);
11673 * Sets the default sort column and order to be used by the next load operation.
11674 * @param {String} fieldName The name of the field to sort by.
11675 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11677 setDefaultSort : function(field, dir){
11678 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
11682 * Sort the Records.
11683 * If remote sorting is used, the sort is performed on the server, and the cache is
11684 * reloaded. If local sorting is used, the cache is sorted internally.
11685 * @param {String} fieldName The name of the field to sort by.
11686 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11688 sort : function(fieldName, dir){
11689 var f = this.fields.get(fieldName);
11691 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
11693 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
11694 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
11699 this.sortToggle[f.name] = dir;
11700 this.sortInfo = {field: f.name, direction: dir};
11701 if(!this.remoteSort){
11703 this.fireEvent("datachanged", this);
11705 this.load(this.lastOptions);
11710 * Calls the specified function for each of the Records in the cache.
11711 * @param {Function} fn The function to call. The Record is passed as the first parameter.
11712 * Returning <em>false</em> aborts and exits the iteration.
11713 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
11715 each : function(fn, scope){
11716 this.data.each(fn, scope);
11720 * Gets all records modified since the last commit. Modified records are persisted across load operations
11721 * (e.g., during paging).
11722 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
11724 getModifiedRecords : function(){
11725 return this.modified;
11729 createFilterFn : function(property, value, anyMatch){
11730 if(!value.exec){ // not a regex
11731 value = String(value);
11732 if(value.length == 0){
11735 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
11737 return function(r){
11738 return value.test(r.data[property]);
11743 * Sums the value of <i>property</i> for each record between start and end and returns the result.
11744 * @param {String} property A field on your records
11745 * @param {Number} start The record index to start at (defaults to 0)
11746 * @param {Number} end The last record index to include (defaults to length - 1)
11747 * @return {Number} The sum
11749 sum : function(property, start, end){
11750 var rs = this.data.items, v = 0;
11751 start = start || 0;
11752 end = (end || end === 0) ? end : rs.length-1;
11754 for(var i = start; i <= end; i++){
11755 v += (rs[i].data[property] || 0);
11761 * Filter the records by a specified property.
11762 * @param {String} field A field on your records
11763 * @param {String/RegExp} value Either a string that the field
11764 * should start with or a RegExp to test against the field
11765 * @param {Boolean} anyMatch True to match any part not just the beginning
11767 filter : function(property, value, anyMatch){
11768 var fn = this.createFilterFn(property, value, anyMatch);
11769 return fn ? this.filterBy(fn) : this.clearFilter();
11773 * Filter by a function. The specified function will be called with each
11774 * record in this data source. If the function returns true the record is included,
11775 * otherwise it is filtered.
11776 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11777 * @param {Object} scope (optional) The scope of the function (defaults to this)
11779 filterBy : function(fn, scope){
11780 this.snapshot = this.snapshot || this.data;
11781 this.data = this.queryBy(fn, scope||this);
11782 this.fireEvent("datachanged", this);
11786 * Query the records by a specified property.
11787 * @param {String} field A field on your records
11788 * @param {String/RegExp} value Either a string that the field
11789 * should start with or a RegExp to test against the field
11790 * @param {Boolean} anyMatch True to match any part not just the beginning
11791 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11793 query : function(property, value, anyMatch){
11794 var fn = this.createFilterFn(property, value, anyMatch);
11795 return fn ? this.queryBy(fn) : this.data.clone();
11799 * Query by a function. The specified function will be called with each
11800 * record in this data source. If the function returns true the record is included
11802 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11803 * @param {Object} scope (optional) The scope of the function (defaults to this)
11804 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11806 queryBy : function(fn, scope){
11807 var data = this.snapshot || this.data;
11808 return data.filterBy(fn, scope||this);
11812 * Collects unique values for a particular dataIndex from this store.
11813 * @param {String} dataIndex The property to collect
11814 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
11815 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
11816 * @return {Array} An array of the unique values
11818 collect : function(dataIndex, allowNull, bypassFilter){
11819 var d = (bypassFilter === true && this.snapshot) ?
11820 this.snapshot.items : this.data.items;
11821 var v, sv, r = [], l = {};
11822 for(var i = 0, len = d.length; i < len; i++){
11823 v = d[i].data[dataIndex];
11825 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
11834 * Revert to a view of the Record cache with no filtering applied.
11835 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
11837 clearFilter : function(suppressEvent){
11838 if(this.snapshot && this.snapshot != this.data){
11839 this.data = this.snapshot;
11840 delete this.snapshot;
11841 if(suppressEvent !== true){
11842 this.fireEvent("datachanged", this);
11848 afterEdit : function(record){
11849 if(this.modified.indexOf(record) == -1){
11850 this.modified.push(record);
11852 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
11856 afterReject : function(record){
11857 this.modified.remove(record);
11858 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
11862 afterCommit : function(record){
11863 this.modified.remove(record);
11864 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
11868 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
11869 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
11871 commitChanges : function(){
11872 var m = this.modified.slice(0);
11873 this.modified = [];
11874 for(var i = 0, len = m.length; i < len; i++){
11880 * Cancel outstanding changes on all changed records.
11882 rejectChanges : function(){
11883 var m = this.modified.slice(0);
11884 this.modified = [];
11885 for(var i = 0, len = m.length; i < len; i++){
11890 onMetaChange : function(meta, rtype, o){
11891 this.recordType = rtype;
11892 this.fields = rtype.prototype.fields;
11893 delete this.snapshot;
11894 this.sortInfo = meta.sortInfo || this.sortInfo;
11895 this.modified = [];
11896 this.fireEvent('metachange', this, this.reader.meta);
11899 moveIndex : function(data, type)
11901 var index = this.indexOf(data);
11903 var newIndex = index + type;
11907 this.insert(newIndex, data);
11912 * Ext JS Library 1.1.1
11913 * Copyright(c) 2006-2007, Ext JS, LLC.
11915 * Originally Released Under LGPL - original licence link has changed is not relivant.
11918 * <script type="text/javascript">
11922 * @class Roo.data.SimpleStore
11923 * @extends Roo.data.Store
11924 * Small helper class to make creating Stores from Array data easier.
11925 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
11926 * @cfg {Array} fields An array of field definition objects, or field name strings.
11927 * @cfg {Array} data The multi-dimensional array of data
11929 * @param {Object} config
11931 Roo.data.SimpleStore = function(config){
11932 Roo.data.SimpleStore.superclass.constructor.call(this, {
11934 reader: new Roo.data.ArrayReader({
11937 Roo.data.Record.create(config.fields)
11939 proxy : new Roo.data.MemoryProxy(config.data)
11943 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
11945 * Ext JS Library 1.1.1
11946 * Copyright(c) 2006-2007, Ext JS, LLC.
11948 * Originally Released Under LGPL - original licence link has changed is not relivant.
11951 * <script type="text/javascript">
11956 * @extends Roo.data.Store
11957 * @class Roo.data.JsonStore
11958 * Small helper class to make creating Stores for JSON data easier. <br/>
11960 var store = new Roo.data.JsonStore({
11961 url: 'get-images.php',
11963 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
11966 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
11967 * JsonReader and HttpProxy (unless inline data is provided).</b>
11968 * @cfg {Array} fields An array of field definition objects, or field name strings.
11970 * @param {Object} config
11972 Roo.data.JsonStore = function(c){
11973 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
11974 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
11975 reader: new Roo.data.JsonReader(c, c.fields)
11978 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
11980 * Ext JS Library 1.1.1
11981 * Copyright(c) 2006-2007, Ext JS, LLC.
11983 * Originally Released Under LGPL - original licence link has changed is not relivant.
11986 * <script type="text/javascript">
11990 Roo.data.Field = function(config){
11991 if(typeof config == "string"){
11992 config = {name: config};
11994 Roo.apply(this, config);
11997 this.type = "auto";
12000 var st = Roo.data.SortTypes;
12001 // named sortTypes are supported, here we look them up
12002 if(typeof this.sortType == "string"){
12003 this.sortType = st[this.sortType];
12006 // set default sortType for strings and dates
12007 if(!this.sortType){
12010 this.sortType = st.asUCString;
12013 this.sortType = st.asDate;
12016 this.sortType = st.none;
12021 var stripRe = /[\$,%]/g;
12023 // prebuilt conversion function for this field, instead of
12024 // switching every time we're reading a value
12026 var cv, dateFormat = this.dateFormat;
12031 cv = function(v){ return v; };
12034 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
12038 return v !== undefined && v !== null && v !== '' ?
12039 parseInt(String(v).replace(stripRe, ""), 10) : '';
12044 return v !== undefined && v !== null && v !== '' ?
12045 parseFloat(String(v).replace(stripRe, ""), 10) : '';
12050 cv = function(v){ return v === true || v === "true" || v == 1; };
12057 if(v instanceof Date){
12061 if(dateFormat == "timestamp"){
12062 return new Date(v*1000);
12064 return Date.parseDate(v, dateFormat);
12066 var parsed = Date.parse(v);
12067 return parsed ? new Date(parsed) : null;
12076 Roo.data.Field.prototype = {
12084 * Ext JS Library 1.1.1
12085 * Copyright(c) 2006-2007, Ext JS, LLC.
12087 * Originally Released Under LGPL - original licence link has changed is not relivant.
12090 * <script type="text/javascript">
12093 // Base class for reading structured data from a data source. This class is intended to be
12094 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
12097 * @class Roo.data.DataReader
12098 * Base class for reading structured data from a data source. This class is intended to be
12099 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
12102 Roo.data.DataReader = function(meta, recordType){
12106 this.recordType = recordType instanceof Array ?
12107 Roo.data.Record.create(recordType) : recordType;
12110 Roo.data.DataReader.prototype = {
12112 * Create an empty record
12113 * @param {Object} data (optional) - overlay some values
12114 * @return {Roo.data.Record} record created.
12116 newRow : function(d) {
12118 this.recordType.prototype.fields.each(function(c) {
12120 case 'int' : da[c.name] = 0; break;
12121 case 'date' : da[c.name] = new Date(); break;
12122 case 'float' : da[c.name] = 0.0; break;
12123 case 'boolean' : da[c.name] = false; break;
12124 default : da[c.name] = ""; break;
12128 return new this.recordType(Roo.apply(da, d));
12133 * Ext JS Library 1.1.1
12134 * Copyright(c) 2006-2007, Ext JS, LLC.
12136 * Originally Released Under LGPL - original licence link has changed is not relivant.
12139 * <script type="text/javascript">
12143 * @class Roo.data.DataProxy
12144 * @extends Roo.data.Observable
12145 * This class is an abstract base class for implementations which provide retrieval of
12146 * unformatted data objects.<br>
12148 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
12149 * (of the appropriate type which knows how to parse the data object) to provide a block of
12150 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
12152 * Custom implementations must implement the load method as described in
12153 * {@link Roo.data.HttpProxy#load}.
12155 Roo.data.DataProxy = function(){
12158 * @event beforeload
12159 * Fires before a network request is made to retrieve a data object.
12160 * @param {Object} This DataProxy object.
12161 * @param {Object} params The params parameter to the load function.
12166 * Fires before the load method's callback is called.
12167 * @param {Object} This DataProxy object.
12168 * @param {Object} o The data object.
12169 * @param {Object} arg The callback argument object passed to the load function.
12173 * @event loadexception
12174 * Fires if an Exception occurs during data retrieval.
12175 * @param {Object} This DataProxy object.
12176 * @param {Object} o The data object.
12177 * @param {Object} arg The callback argument object passed to the load function.
12178 * @param {Object} e The Exception.
12180 loadexception : true
12182 Roo.data.DataProxy.superclass.constructor.call(this);
12185 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
12188 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
12192 * Ext JS Library 1.1.1
12193 * Copyright(c) 2006-2007, Ext JS, LLC.
12195 * Originally Released Under LGPL - original licence link has changed is not relivant.
12198 * <script type="text/javascript">
12201 * @class Roo.data.MemoryProxy
12202 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
12203 * to the Reader when its load method is called.
12205 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
12207 Roo.data.MemoryProxy = function(data){
12211 Roo.data.MemoryProxy.superclass.constructor.call(this);
12215 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
12218 * Load data from the requested source (in this case an in-memory
12219 * data object passed to the constructor), read the data object into
12220 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12221 * process that block using the passed callback.
12222 * @param {Object} params This parameter is not used by the MemoryProxy class.
12223 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12224 * object into a block of Roo.data.Records.
12225 * @param {Function} callback The function into which to pass the block of Roo.data.records.
12226 * The function must be passed <ul>
12227 * <li>The Record block object</li>
12228 * <li>The "arg" argument from the load function</li>
12229 * <li>A boolean success indicator</li>
12231 * @param {Object} scope The scope in which to call the callback
12232 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12234 load : function(params, reader, callback, scope, arg){
12235 params = params || {};
12238 result = reader.readRecords(this.data);
12240 this.fireEvent("loadexception", this, arg, null, e);
12241 callback.call(scope, null, arg, false);
12244 callback.call(scope, result, arg, true);
12248 update : function(params, records){
12253 * Ext JS Library 1.1.1
12254 * Copyright(c) 2006-2007, Ext JS, LLC.
12256 * Originally Released Under LGPL - original licence link has changed is not relivant.
12259 * <script type="text/javascript">
12262 * @class Roo.data.HttpProxy
12263 * @extends Roo.data.DataProxy
12264 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
12265 * configured to reference a certain URL.<br><br>
12267 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
12268 * from which the running page was served.<br><br>
12270 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
12272 * Be aware that to enable the browser to parse an XML document, the server must set
12273 * the Content-Type header in the HTTP response to "text/xml".
12275 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
12276 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
12277 * will be used to make the request.
12279 Roo.data.HttpProxy = function(conn){
12280 Roo.data.HttpProxy.superclass.constructor.call(this);
12281 // is conn a conn config or a real conn?
12283 this.useAjax = !conn || !conn.events;
12287 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
12288 // thse are take from connection...
12291 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
12294 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
12295 * extra parameters to each request made by this object. (defaults to undefined)
12298 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
12299 * to each request made by this object. (defaults to undefined)
12302 * @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)
12305 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
12308 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
12314 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
12318 * Return the {@link Roo.data.Connection} object being used by this Proxy.
12319 * @return {Connection} The Connection object. This object may be used to subscribe to events on
12320 * a finer-grained basis than the DataProxy events.
12322 getConnection : function(){
12323 return this.useAjax ? Roo.Ajax : this.conn;
12327 * Load data from the configured {@link Roo.data.Connection}, read the data object into
12328 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
12329 * process that block using the passed callback.
12330 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12331 * for the request to the remote server.
12332 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12333 * object into a block of Roo.data.Records.
12334 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12335 * The function must be passed <ul>
12336 * <li>The Record block object</li>
12337 * <li>The "arg" argument from the load function</li>
12338 * <li>A boolean success indicator</li>
12340 * @param {Object} scope The scope in which to call the callback
12341 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12343 load : function(params, reader, callback, scope, arg){
12344 if(this.fireEvent("beforeload", this, params) !== false){
12346 params : params || {},
12348 callback : callback,
12353 callback : this.loadResponse,
12357 Roo.applyIf(o, this.conn);
12358 if(this.activeRequest){
12359 Roo.Ajax.abort(this.activeRequest);
12361 this.activeRequest = Roo.Ajax.request(o);
12363 this.conn.request(o);
12366 callback.call(scope||this, null, arg, false);
12371 loadResponse : function(o, success, response){
12372 delete this.activeRequest;
12374 this.fireEvent("loadexception", this, o, response);
12375 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12380 result = o.reader.read(response);
12382 this.fireEvent("loadexception", this, o, response, e);
12383 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12387 this.fireEvent("load", this, o, o.request.arg);
12388 o.request.callback.call(o.request.scope, result, o.request.arg, true);
12392 update : function(dataSet){
12397 updateResponse : function(dataSet){
12402 * Ext JS Library 1.1.1
12403 * Copyright(c) 2006-2007, Ext JS, LLC.
12405 * Originally Released Under LGPL - original licence link has changed is not relivant.
12408 * <script type="text/javascript">
12412 * @class Roo.data.ScriptTagProxy
12413 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
12414 * other than the originating domain of the running page.<br><br>
12416 * <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
12417 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
12419 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
12420 * source code that is used as the source inside a <script> tag.<br><br>
12422 * In order for the browser to process the returned data, the server must wrap the data object
12423 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
12424 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
12425 * depending on whether the callback name was passed:
12428 boolean scriptTag = false;
12429 String cb = request.getParameter("callback");
12432 response.setContentType("text/javascript");
12434 response.setContentType("application/x-json");
12436 Writer out = response.getWriter();
12438 out.write(cb + "(");
12440 out.print(dataBlock.toJsonString());
12447 * @param {Object} config A configuration object.
12449 Roo.data.ScriptTagProxy = function(config){
12450 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
12451 Roo.apply(this, config);
12452 this.head = document.getElementsByTagName("head")[0];
12455 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
12457 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
12459 * @cfg {String} url The URL from which to request the data object.
12462 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
12466 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
12467 * the server the name of the callback function set up by the load call to process the returned data object.
12468 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
12469 * javascript output which calls this named function passing the data object as its only parameter.
12471 callbackParam : "callback",
12473 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
12474 * name to the request.
12479 * Load data from the configured URL, read the data object into
12480 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12481 * process that block using the passed callback.
12482 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12483 * for the request to the remote server.
12484 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12485 * object into a block of Roo.data.Records.
12486 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12487 * The function must be passed <ul>
12488 * <li>The Record block object</li>
12489 * <li>The "arg" argument from the load function</li>
12490 * <li>A boolean success indicator</li>
12492 * @param {Object} scope The scope in which to call the callback
12493 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12495 load : function(params, reader, callback, scope, arg){
12496 if(this.fireEvent("beforeload", this, params) !== false){
12498 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
12500 var url = this.url;
12501 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
12503 url += "&_dc=" + (new Date().getTime());
12505 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
12508 cb : "stcCallback"+transId,
12509 scriptId : "stcScript"+transId,
12513 callback : callback,
12519 window[trans.cb] = function(o){
12520 conn.handleResponse(o, trans);
12523 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
12525 if(this.autoAbort !== false){
12529 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
12531 var script = document.createElement("script");
12532 script.setAttribute("src", url);
12533 script.setAttribute("type", "text/javascript");
12534 script.setAttribute("id", trans.scriptId);
12535 this.head.appendChild(script);
12537 this.trans = trans;
12539 callback.call(scope||this, null, arg, false);
12544 isLoading : function(){
12545 return this.trans ? true : false;
12549 * Abort the current server request.
12551 abort : function(){
12552 if(this.isLoading()){
12553 this.destroyTrans(this.trans);
12558 destroyTrans : function(trans, isLoaded){
12559 this.head.removeChild(document.getElementById(trans.scriptId));
12560 clearTimeout(trans.timeoutId);
12562 window[trans.cb] = undefined;
12564 delete window[trans.cb];
12567 // if hasn't been loaded, wait for load to remove it to prevent script error
12568 window[trans.cb] = function(){
12569 window[trans.cb] = undefined;
12571 delete window[trans.cb];
12578 handleResponse : function(o, trans){
12579 this.trans = false;
12580 this.destroyTrans(trans, true);
12583 result = trans.reader.readRecords(o);
12585 this.fireEvent("loadexception", this, o, trans.arg, e);
12586 trans.callback.call(trans.scope||window, null, trans.arg, false);
12589 this.fireEvent("load", this, o, trans.arg);
12590 trans.callback.call(trans.scope||window, result, trans.arg, true);
12594 handleFailure : function(trans){
12595 this.trans = false;
12596 this.destroyTrans(trans, false);
12597 this.fireEvent("loadexception", this, null, trans.arg);
12598 trans.callback.call(trans.scope||window, null, trans.arg, false);
12602 * Ext JS Library 1.1.1
12603 * Copyright(c) 2006-2007, Ext JS, LLC.
12605 * Originally Released Under LGPL - original licence link has changed is not relivant.
12608 * <script type="text/javascript">
12612 * @class Roo.data.JsonReader
12613 * @extends Roo.data.DataReader
12614 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
12615 * based on mappings in a provided Roo.data.Record constructor.
12617 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
12618 * in the reply previously.
12623 var RecordDef = Roo.data.Record.create([
12624 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
12625 {name: 'occupation'} // This field will use "occupation" as the mapping.
12627 var myReader = new Roo.data.JsonReader({
12628 totalProperty: "results", // The property which contains the total dataset size (optional)
12629 root: "rows", // The property which contains an Array of row objects
12630 id: "id" // The property within each row object that provides an ID for the record (optional)
12634 * This would consume a JSON file like this:
12636 { 'results': 2, 'rows': [
12637 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
12638 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
12641 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
12642 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
12643 * paged from the remote server.
12644 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
12645 * @cfg {String} root name of the property which contains the Array of row objects.
12646 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
12647 * @cfg {Array} fields Array of field definition objects
12649 * Create a new JsonReader
12650 * @param {Object} meta Metadata configuration options
12651 * @param {Object} recordType Either an Array of field definition objects,
12652 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
12654 Roo.data.JsonReader = function(meta, recordType){
12657 // set some defaults:
12658 Roo.applyIf(meta, {
12659 totalProperty: 'total',
12660 successProperty : 'success',
12665 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
12667 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
12670 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
12671 * Used by Store query builder to append _requestMeta to params.
12674 metaFromRemote : false,
12676 * This method is only used by a DataProxy which has retrieved data from a remote server.
12677 * @param {Object} response The XHR object which contains the JSON data in its responseText.
12678 * @return {Object} data A data block which is used by an Roo.data.Store object as
12679 * a cache of Roo.data.Records.
12681 read : function(response){
12682 var json = response.responseText;
12684 var o = /* eval:var:o */ eval("("+json+")");
12686 throw {message: "JsonReader.read: Json object not found"};
12692 this.metaFromRemote = true;
12693 this.meta = o.metaData;
12694 this.recordType = Roo.data.Record.create(o.metaData.fields);
12695 this.onMetaChange(this.meta, this.recordType, o);
12697 return this.readRecords(o);
12700 // private function a store will implement
12701 onMetaChange : function(meta, recordType, o){
12708 simpleAccess: function(obj, subsc) {
12715 getJsonAccessor: function(){
12717 return function(expr) {
12719 return(re.test(expr))
12720 ? new Function("obj", "return obj." + expr)
12725 return Roo.emptyFn;
12730 * Create a data block containing Roo.data.Records from an XML document.
12731 * @param {Object} o An object which contains an Array of row objects in the property specified
12732 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
12733 * which contains the total size of the dataset.
12734 * @return {Object} data A data block which is used by an Roo.data.Store object as
12735 * a cache of Roo.data.Records.
12737 readRecords : function(o){
12739 * After any data loads, the raw JSON data is available for further custom processing.
12743 var s = this.meta, Record = this.recordType,
12744 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
12746 // Generate extraction functions for the totalProperty, the root, the id, and for each field
12748 if(s.totalProperty) {
12749 this.getTotal = this.getJsonAccessor(s.totalProperty);
12751 if(s.successProperty) {
12752 this.getSuccess = this.getJsonAccessor(s.successProperty);
12754 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
12756 var g = this.getJsonAccessor(s.id);
12757 this.getId = function(rec) {
12759 return (r === undefined || r === "") ? null : r;
12762 this.getId = function(){return null;};
12765 for(var jj = 0; jj < fl; jj++){
12767 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
12768 this.ef[jj] = this.getJsonAccessor(map);
12772 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
12773 if(s.totalProperty){
12774 var vt = parseInt(this.getTotal(o), 10);
12779 if(s.successProperty){
12780 var vs = this.getSuccess(o);
12781 if(vs === false || vs === 'false'){
12786 for(var i = 0; i < c; i++){
12789 var id = this.getId(n);
12790 for(var j = 0; j < fl; j++){
12792 var v = this.ef[j](n);
12794 Roo.log('missing convert for ' + f.name);
12798 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
12800 var record = new Record(values, id);
12802 records[i] = record;
12808 totalRecords : totalRecords
12813 * Ext JS Library 1.1.1
12814 * Copyright(c) 2006-2007, Ext JS, LLC.
12816 * Originally Released Under LGPL - original licence link has changed is not relivant.
12819 * <script type="text/javascript">
12823 * @class Roo.data.ArrayReader
12824 * @extends Roo.data.DataReader
12825 * Data reader class to create an Array of Roo.data.Record objects from an Array.
12826 * Each element of that Array represents a row of data fields. The
12827 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
12828 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
12832 var RecordDef = Roo.data.Record.create([
12833 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
12834 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
12836 var myReader = new Roo.data.ArrayReader({
12837 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
12841 * This would consume an Array like this:
12843 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
12845 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
12847 * Create a new JsonReader
12848 * @param {Object} meta Metadata configuration options.
12849 * @param {Object} recordType Either an Array of field definition objects
12850 * as specified to {@link Roo.data.Record#create},
12851 * or an {@link Roo.data.Record} object
12852 * created using {@link Roo.data.Record#create}.
12854 Roo.data.ArrayReader = function(meta, recordType){
12855 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
12858 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
12860 * Create a data block containing Roo.data.Records from an XML document.
12861 * @param {Object} o An Array of row objects which represents the dataset.
12862 * @return {Object} data A data block which is used by an Roo.data.Store object as
12863 * a cache of Roo.data.Records.
12865 readRecords : function(o){
12866 var sid = this.meta ? this.meta.id : null;
12867 var recordType = this.recordType, fields = recordType.prototype.fields;
12870 for(var i = 0; i < root.length; i++){
12873 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
12874 for(var j = 0, jlen = fields.length; j < jlen; j++){
12875 var f = fields.items[j];
12876 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
12877 var v = n[k] !== undefined ? n[k] : f.defaultValue;
12879 values[f.name] = v;
12881 var record = new recordType(values, id);
12883 records[records.length] = record;
12887 totalRecords : records.length
12896 * @class Roo.bootstrap.ComboBox
12897 * @extends Roo.bootstrap.TriggerField
12898 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
12899 * @cfg {Boolean} append (true|false) default false
12900 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
12901 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
12902 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
12903 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
12904 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
12905 * @cfg {Boolean} animate default true
12906 * @cfg {Boolean} emptyResultText only for touch device
12907 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
12908 * @cfg {String} emptyTitle default ''
12910 * Create a new ComboBox.
12911 * @param {Object} config Configuration options
12913 Roo.bootstrap.ComboBox = function(config){
12914 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
12918 * Fires when the dropdown list is expanded
12919 * @param {Roo.bootstrap.ComboBox} combo This combo box
12924 * Fires when the dropdown list is collapsed
12925 * @param {Roo.bootstrap.ComboBox} combo This combo box
12929 * @event beforeselect
12930 * Fires before a list item is selected. Return false to cancel the selection.
12931 * @param {Roo.bootstrap.ComboBox} combo This combo box
12932 * @param {Roo.data.Record} record The data record returned from the underlying store
12933 * @param {Number} index The index of the selected item in the dropdown list
12935 'beforeselect' : true,
12938 * Fires when a list item is selected
12939 * @param {Roo.bootstrap.ComboBox} combo This combo box
12940 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
12941 * @param {Number} index The index of the selected item in the dropdown list
12945 * @event beforequery
12946 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
12947 * The event object passed has these properties:
12948 * @param {Roo.bootstrap.ComboBox} combo This combo box
12949 * @param {String} query The query
12950 * @param {Boolean} forceAll true to force "all" query
12951 * @param {Boolean} cancel true to cancel the query
12952 * @param {Object} e The query event object
12954 'beforequery': true,
12957 * Fires when the 'add' icon is pressed (add a listener to enable add button)
12958 * @param {Roo.bootstrap.ComboBox} combo This combo box
12963 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
12964 * @param {Roo.bootstrap.ComboBox} combo This combo box
12965 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
12970 * Fires when the remove value from the combobox array
12971 * @param {Roo.bootstrap.ComboBox} combo This combo box
12975 * @event afterremove
12976 * Fires when the remove value from the combobox array
12977 * @param {Roo.bootstrap.ComboBox} combo This combo box
12979 'afterremove' : true,
12981 * @event specialfilter
12982 * Fires when specialfilter
12983 * @param {Roo.bootstrap.ComboBox} combo This combo box
12985 'specialfilter' : true,
12988 * Fires when tick the element
12989 * @param {Roo.bootstrap.ComboBox} combo This combo box
12993 * @event touchviewdisplay
12994 * Fires when touch view require special display (default is using displayField)
12995 * @param {Roo.bootstrap.ComboBox} combo This combo box
12996 * @param {Object} cfg set html .
12998 'touchviewdisplay' : true
13003 this.tickItems = [];
13005 this.selectedIndex = -1;
13006 if(this.mode == 'local'){
13007 if(config.queryDelay === undefined){
13008 this.queryDelay = 10;
13010 if(config.minChars === undefined){
13016 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
13019 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
13020 * rendering into an Roo.Editor, defaults to false)
13023 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
13024 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
13027 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
13030 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
13031 * the dropdown list (defaults to undefined, with no header element)
13035 * @cfg {String/Roo.Template} tpl The template to use to render the output
13039 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
13041 listWidth: undefined,
13043 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
13044 * mode = 'remote' or 'text' if mode = 'local')
13046 displayField: undefined,
13049 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
13050 * mode = 'remote' or 'value' if mode = 'local').
13051 * Note: use of a valueField requires the user make a selection
13052 * in order for a value to be mapped.
13054 valueField: undefined,
13056 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
13061 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
13062 * field's data value (defaults to the underlying DOM element's name)
13064 hiddenName: undefined,
13066 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
13070 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
13072 selectedClass: 'active',
13075 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
13079 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
13080 * anchor positions (defaults to 'tl-bl')
13082 listAlign: 'tl-bl?',
13084 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
13088 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
13089 * query specified by the allQuery config option (defaults to 'query')
13091 triggerAction: 'query',
13093 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
13094 * (defaults to 4, does not apply if editable = false)
13098 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
13099 * delay (typeAheadDelay) if it matches a known value (defaults to false)
13103 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
13104 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
13108 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
13109 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
13113 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
13114 * when editable = true (defaults to false)
13116 selectOnFocus:false,
13118 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
13120 queryParam: 'query',
13122 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
13123 * when mode = 'remote' (defaults to 'Loading...')
13125 loadingText: 'Loading...',
13127 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
13131 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
13135 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
13136 * traditional select (defaults to true)
13140 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
13144 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
13148 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
13149 * listWidth has a higher value)
13153 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
13154 * allow the user to set arbitrary text into the field (defaults to false)
13156 forceSelection:false,
13158 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
13159 * if typeAhead = true (defaults to 250)
13161 typeAheadDelay : 250,
13163 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
13164 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
13166 valueNotFoundText : undefined,
13168 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
13170 blockFocus : false,
13173 * @cfg {Boolean} disableClear Disable showing of clear button.
13175 disableClear : false,
13177 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
13179 alwaysQuery : false,
13182 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
13187 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
13189 invalidClass : "has-warning",
13192 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
13194 validClass : "has-success",
13197 * @cfg {Boolean} specialFilter (true|false) special filter default false
13199 specialFilter : false,
13202 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
13204 mobileTouchView : true,
13207 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
13209 useNativeIOS : false,
13212 * @cfg {Boolean} mobile_restrict_height (true|false) restrict height for touch view
13214 mobile_restrict_height : false,
13216 ios_options : false,
13228 btnPosition : 'right',
13229 triggerList : true,
13230 showToggleBtn : true,
13232 emptyResultText: 'Empty',
13233 triggerText : 'Select',
13236 // element that contains real text value.. (when hidden is used..)
13238 getAutoCreate : function()
13243 * Render classic select for iso
13246 if(Roo.isIOS && this.useNativeIOS){
13247 cfg = this.getAutoCreateNativeIOS();
13255 if(Roo.isTouch && this.mobileTouchView){
13256 cfg = this.getAutoCreateTouchView();
13263 if(!this.tickable){
13264 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
13269 * ComboBox with tickable selections
13272 var align = this.labelAlign || this.parentLabelAlign();
13275 cls : 'form-group roo-combobox-tickable' //input-group
13278 var btn_text_select = '';
13279 var btn_text_done = '';
13280 var btn_text_cancel = '';
13282 if (this.btn_text_show) {
13283 btn_text_select = 'Select';
13284 btn_text_done = 'Done';
13285 btn_text_cancel = 'Cancel';
13290 cls : 'tickable-buttons',
13295 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
13296 //html : this.triggerText
13297 html: btn_text_select
13303 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
13305 html: btn_text_done
13311 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
13313 html: btn_text_cancel
13319 buttons.cn.unshift({
13321 cls: 'roo-select2-search-field-input'
13327 Roo.each(buttons.cn, function(c){
13329 c.cls += ' btn-' + _this.size;
13332 if (_this.disabled) {
13343 cls: 'form-hidden-field'
13347 cls: 'roo-select2-choices',
13351 cls: 'roo-select2-search-field',
13362 cls: 'roo-select2-container input-group roo-select2-container-multi',
13368 // cls: 'typeahead typeahead-long dropdown-menu',
13369 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
13374 if(this.hasFeedback && !this.allowBlank){
13378 cls: 'glyphicon form-control-feedback'
13381 combobox.cn.push(feedback);
13386 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
13387 tooltip : 'This field is required'
13389 if (Roo.bootstrap.version == 4) {
13392 style : 'display:none'
13395 if (align ==='left' && this.fieldLabel.length) {
13397 cfg.cls += ' roo-form-group-label-left row';
13404 cls : 'control-label col-form-label',
13405 html : this.fieldLabel
13417 var labelCfg = cfg.cn[1];
13418 var contentCfg = cfg.cn[2];
13421 if(this.indicatorpos == 'right'){
13427 cls : 'control-label col-form-label',
13431 html : this.fieldLabel
13447 labelCfg = cfg.cn[0];
13448 contentCfg = cfg.cn[1];
13452 if(this.labelWidth > 12){
13453 labelCfg.style = "width: " + this.labelWidth + 'px';
13456 if(this.labelWidth < 13 && this.labelmd == 0){
13457 this.labelmd = this.labelWidth;
13460 if(this.labellg > 0){
13461 labelCfg.cls += ' col-lg-' + this.labellg;
13462 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
13465 if(this.labelmd > 0){
13466 labelCfg.cls += ' col-md-' + this.labelmd;
13467 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
13470 if(this.labelsm > 0){
13471 labelCfg.cls += ' col-sm-' + this.labelsm;
13472 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
13475 if(this.labelxs > 0){
13476 labelCfg.cls += ' col-xs-' + this.labelxs;
13477 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
13481 } else if ( this.fieldLabel.length) {
13482 // Roo.log(" label");
13487 //cls : 'input-group-addon',
13488 html : this.fieldLabel
13493 if(this.indicatorpos == 'right'){
13497 //cls : 'input-group-addon',
13498 html : this.fieldLabel
13508 // Roo.log(" no label && no align");
13515 ['xs','sm','md','lg'].map(function(size){
13516 if (settings[size]) {
13517 cfg.cls += ' col-' + size + '-' + settings[size];
13525 _initEventsCalled : false,
13528 initEvents: function()
13530 if (this._initEventsCalled) { // as we call render... prevent looping...
13533 this._initEventsCalled = true;
13536 throw "can not find store for combo";
13539 this.indicator = this.indicatorEl();
13541 this.store = Roo.factory(this.store, Roo.data);
13542 this.store.parent = this;
13544 // if we are building from html. then this element is so complex, that we can not really
13545 // use the rendered HTML.
13546 // so we have to trash and replace the previous code.
13547 if (Roo.XComponent.build_from_html) {
13548 // remove this element....
13549 var e = this.el.dom, k=0;
13550 while (e ) { e = e.previousSibling; ++k;}
13555 this.rendered = false;
13557 this.render(this.parent().getChildContainer(true), k);
13560 if(Roo.isIOS && this.useNativeIOS){
13561 this.initIOSView();
13569 if(Roo.isTouch && this.mobileTouchView){
13570 this.initTouchView();
13575 this.initTickableEvents();
13579 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
13581 if(this.hiddenName){
13583 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13585 this.hiddenField.dom.value =
13586 this.hiddenValue !== undefined ? this.hiddenValue :
13587 this.value !== undefined ? this.value : '';
13589 // prevent input submission
13590 this.el.dom.removeAttribute('name');
13591 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13596 // this.el.dom.setAttribute('autocomplete', 'off');
13599 var cls = 'x-combo-list';
13601 //this.list = new Roo.Layer({
13602 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
13608 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13609 _this.list.setWidth(lw);
13612 this.list.on('mouseover', this.onViewOver, this);
13613 this.list.on('mousemove', this.onViewMove, this);
13614 this.list.on('scroll', this.onViewScroll, this);
13617 this.list.swallowEvent('mousewheel');
13618 this.assetHeight = 0;
13621 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
13622 this.assetHeight += this.header.getHeight();
13625 this.innerList = this.list.createChild({cls:cls+'-inner'});
13626 this.innerList.on('mouseover', this.onViewOver, this);
13627 this.innerList.on('mousemove', this.onViewMove, this);
13628 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13630 if(this.allowBlank && !this.pageSize && !this.disableClear){
13631 this.footer = this.list.createChild({cls:cls+'-ft'});
13632 this.pageTb = new Roo.Toolbar(this.footer);
13636 this.footer = this.list.createChild({cls:cls+'-ft'});
13637 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
13638 {pageSize: this.pageSize});
13642 if (this.pageTb && this.allowBlank && !this.disableClear) {
13644 this.pageTb.add(new Roo.Toolbar.Fill(), {
13645 cls: 'x-btn-icon x-btn-clear',
13647 handler: function()
13650 _this.clearValue();
13651 _this.onSelect(false, -1);
13656 this.assetHeight += this.footer.getHeight();
13661 this.tpl = Roo.bootstrap.version == 4 ?
13662 '<a class="dropdown-item" href="#">{' + this.displayField + '}</a>' : // 4 does not need <li> and it get's really confisued.
13663 '<li><a class="dropdown-item" href="#">{' + this.displayField + '}</a></li>';
13666 this.view = new Roo.View(this.list, this.tpl, {
13667 singleSelect:true, store: this.store, selectedClass: this.selectedClass
13669 //this.view.wrapEl.setDisplayed(false);
13670 this.view.on('click', this.onViewClick, this);
13673 this.store.on('beforeload', this.onBeforeLoad, this);
13674 this.store.on('load', this.onLoad, this);
13675 this.store.on('loadexception', this.onLoadException, this);
13677 if(this.resizable){
13678 this.resizer = new Roo.Resizable(this.list, {
13679 pinned:true, handles:'se'
13681 this.resizer.on('resize', function(r, w, h){
13682 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
13683 this.listWidth = w;
13684 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
13685 this.restrictHeight();
13687 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
13690 if(!this.editable){
13691 this.editable = true;
13692 this.setEditable(false);
13697 if (typeof(this.events.add.listeners) != 'undefined') {
13699 this.addicon = this.wrap.createChild(
13700 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
13702 this.addicon.on('click', function(e) {
13703 this.fireEvent('add', this);
13706 if (typeof(this.events.edit.listeners) != 'undefined') {
13708 this.editicon = this.wrap.createChild(
13709 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
13710 if (this.addicon) {
13711 this.editicon.setStyle('margin-left', '40px');
13713 this.editicon.on('click', function(e) {
13715 // we fire even if inothing is selected..
13716 this.fireEvent('edit', this, this.lastData );
13722 this.keyNav = new Roo.KeyNav(this.inputEl(), {
13723 "up" : function(e){
13724 this.inKeyMode = true;
13728 "down" : function(e){
13729 if(!this.isExpanded()){
13730 this.onTriggerClick();
13732 this.inKeyMode = true;
13737 "enter" : function(e){
13738 // this.onViewClick();
13742 if(this.fireEvent("specialkey", this, e)){
13743 this.onViewClick(false);
13749 "esc" : function(e){
13753 "tab" : function(e){
13756 if(this.fireEvent("specialkey", this, e)){
13757 this.onViewClick(false);
13765 doRelay : function(foo, bar, hname){
13766 if(hname == 'down' || this.scope.isExpanded()){
13767 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13776 this.queryDelay = Math.max(this.queryDelay || 10,
13777 this.mode == 'local' ? 10 : 250);
13780 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13782 if(this.typeAhead){
13783 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13785 if(this.editable !== false){
13786 this.inputEl().on("keyup", this.onKeyUp, this);
13788 if(this.forceSelection){
13789 this.inputEl().on('blur', this.doForce, this);
13793 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13794 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13798 initTickableEvents: function()
13802 if(this.hiddenName){
13804 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13806 this.hiddenField.dom.value =
13807 this.hiddenValue !== undefined ? this.hiddenValue :
13808 this.value !== undefined ? this.value : '';
13810 // prevent input submission
13811 this.el.dom.removeAttribute('name');
13812 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13817 // this.list = this.el.select('ul.dropdown-menu',true).first();
13819 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13820 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13821 if(this.triggerList){
13822 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
13825 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
13826 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
13828 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
13829 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
13831 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
13832 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
13834 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
13835 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
13836 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
13839 this.cancelBtn.hide();
13844 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13845 _this.list.setWidth(lw);
13848 this.list.on('mouseover', this.onViewOver, this);
13849 this.list.on('mousemove', this.onViewMove, this);
13851 this.list.on('scroll', this.onViewScroll, this);
13854 this.tpl = '<li class="roo-select2-result"><div class="checkbox"><input id="{roo-id}"' +
13855 'type="checkbox" {roo-data-checked}><label for="{roo-id}"><b>{' + this.displayField + '}</b></label></div></li>';
13858 this.view = new Roo.View(this.list, this.tpl, {
13863 selectedClass: this.selectedClass
13866 //this.view.wrapEl.setDisplayed(false);
13867 this.view.on('click', this.onViewClick, this);
13871 this.store.on('beforeload', this.onBeforeLoad, this);
13872 this.store.on('load', this.onLoad, this);
13873 this.store.on('loadexception', this.onLoadException, this);
13876 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
13877 "up" : function(e){
13878 this.inKeyMode = true;
13882 "down" : function(e){
13883 this.inKeyMode = true;
13887 "enter" : function(e){
13888 if(this.fireEvent("specialkey", this, e)){
13889 this.onViewClick(false);
13895 "esc" : function(e){
13896 this.onTickableFooterButtonClick(e, false, false);
13899 "tab" : function(e){
13900 this.fireEvent("specialkey", this, e);
13902 this.onTickableFooterButtonClick(e, false, false);
13909 doRelay : function(e, fn, key){
13910 if(this.scope.isExpanded()){
13911 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13920 this.queryDelay = Math.max(this.queryDelay || 10,
13921 this.mode == 'local' ? 10 : 250);
13924 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13926 if(this.typeAhead){
13927 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13930 if(this.editable !== false){
13931 this.tickableInputEl().on("keyup", this.onKeyUp, this);
13934 this.indicator = this.indicatorEl();
13936 if(this.indicator){
13937 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
13938 this.indicator.hide();
13943 onDestroy : function(){
13945 this.view.setStore(null);
13946 this.view.el.removeAllListeners();
13947 this.view.el.remove();
13948 this.view.purgeListeners();
13951 this.list.dom.innerHTML = '';
13955 this.store.un('beforeload', this.onBeforeLoad, this);
13956 this.store.un('load', this.onLoad, this);
13957 this.store.un('loadexception', this.onLoadException, this);
13959 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
13963 fireKey : function(e){
13964 if(e.isNavKeyPress() && !this.list.isVisible()){
13965 this.fireEvent("specialkey", this, e);
13970 onResize: function(w, h){
13971 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
13973 // if(typeof w != 'number'){
13974 // // we do not handle it!?!?
13977 // var tw = this.trigger.getWidth();
13978 // // tw += this.addicon ? this.addicon.getWidth() : 0;
13979 // // tw += this.editicon ? this.editicon.getWidth() : 0;
13981 // this.inputEl().setWidth( this.adjustWidth('input', x));
13983 // //this.trigger.setStyle('left', x+'px');
13985 // if(this.list && this.listWidth === undefined){
13986 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
13987 // this.list.setWidth(lw);
13988 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13996 * Allow or prevent the user from directly editing the field text. If false is passed,
13997 * the user will only be able to select from the items defined in the dropdown list. This method
13998 * is the runtime equivalent of setting the 'editable' config option at config time.
13999 * @param {Boolean} value True to allow the user to directly edit the field text
14001 setEditable : function(value){
14002 if(value == this.editable){
14005 this.editable = value;
14007 this.inputEl().dom.setAttribute('readOnly', true);
14008 this.inputEl().on('mousedown', this.onTriggerClick, this);
14009 this.inputEl().addClass('x-combo-noedit');
14011 this.inputEl().dom.setAttribute('readOnly', false);
14012 this.inputEl().un('mousedown', this.onTriggerClick, this);
14013 this.inputEl().removeClass('x-combo-noedit');
14019 onBeforeLoad : function(combo,opts){
14020 if(!this.hasFocus){
14024 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
14026 this.restrictHeight();
14027 this.selectedIndex = -1;
14031 onLoad : function(){
14033 this.hasQuery = false;
14035 if(!this.hasFocus){
14039 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
14040 this.loading.hide();
14043 if(this.store.getCount() > 0){
14046 this.restrictHeight();
14047 if(this.lastQuery == this.allQuery){
14048 if(this.editable && !this.tickable){
14049 this.inputEl().dom.select();
14053 !this.selectByValue(this.value, true) &&
14056 !this.store.lastOptions ||
14057 typeof(this.store.lastOptions.add) == 'undefined' ||
14058 this.store.lastOptions.add != true
14061 this.select(0, true);
14064 if(this.autoFocus){
14067 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
14068 this.taTask.delay(this.typeAheadDelay);
14072 this.onEmptyResults();
14078 onLoadException : function()
14080 this.hasQuery = false;
14082 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
14083 this.loading.hide();
14086 if(this.tickable && this.editable){
14091 // only causes errors at present
14092 //Roo.log(this.store.reader.jsonData);
14093 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
14095 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
14101 onTypeAhead : function(){
14102 if(this.store.getCount() > 0){
14103 var r = this.store.getAt(0);
14104 var newValue = r.data[this.displayField];
14105 var len = newValue.length;
14106 var selStart = this.getRawValue().length;
14108 if(selStart != len){
14109 this.setRawValue(newValue);
14110 this.selectText(selStart, newValue.length);
14116 onSelect : function(record, index){
14118 if(this.fireEvent('beforeselect', this, record, index) !== false){
14120 this.setFromData(index > -1 ? record.data : false);
14123 this.fireEvent('select', this, record, index);
14128 * Returns the currently selected field value or empty string if no value is set.
14129 * @return {String} value The selected value
14131 getValue : function()
14133 if(Roo.isIOS && this.useNativeIOS){
14134 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
14138 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
14141 if(this.valueField){
14142 return typeof this.value != 'undefined' ? this.value : '';
14144 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
14148 getRawValue : function()
14150 if(Roo.isIOS && this.useNativeIOS){
14151 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
14154 var v = this.inputEl().getValue();
14160 * Clears any text/value currently set in the field
14162 clearValue : function(){
14164 if(this.hiddenField){
14165 this.hiddenField.dom.value = '';
14168 this.setRawValue('');
14169 this.lastSelectionText = '';
14170 this.lastData = false;
14172 var close = this.closeTriggerEl();
14183 * Sets the specified value into the field. If the value finds a match, the corresponding record text
14184 * will be displayed in the field. If the value does not match the data value of an existing item,
14185 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
14186 * Otherwise the field will be blank (although the value will still be set).
14187 * @param {String} value The value to match
14189 setValue : function(v)
14191 if(Roo.isIOS && this.useNativeIOS){
14192 this.setIOSValue(v);
14202 if(this.valueField){
14203 var r = this.findRecord(this.valueField, v);
14205 text = r.data[this.displayField];
14206 }else if(this.valueNotFoundText !== undefined){
14207 text = this.valueNotFoundText;
14210 this.lastSelectionText = text;
14211 if(this.hiddenField){
14212 this.hiddenField.dom.value = v;
14214 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
14217 var close = this.closeTriggerEl();
14220 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
14226 * @property {Object} the last set data for the element
14231 * Sets the value of the field based on a object which is related to the record format for the store.
14232 * @param {Object} value the value to set as. or false on reset?
14234 setFromData : function(o){
14241 var dv = ''; // display value
14242 var vv = ''; // value value..
14244 if (this.displayField) {
14245 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14247 // this is an error condition!!!
14248 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14251 if(this.valueField){
14252 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
14255 var close = this.closeTriggerEl();
14258 if(dv.length || vv * 1 > 0){
14260 this.blockFocus=true;
14266 if(this.hiddenField){
14267 this.hiddenField.dom.value = vv;
14269 this.lastSelectionText = dv;
14270 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14274 // no hidden field.. - we store the value in 'value', but still display
14275 // display field!!!!
14276 this.lastSelectionText = dv;
14277 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14284 reset : function(){
14285 // overridden so that last data is reset..
14292 this.setValue(this.originalValue);
14293 //this.clearInvalid();
14294 this.lastData = false;
14296 this.view.clearSelections();
14302 findRecord : function(prop, value){
14304 if(this.store.getCount() > 0){
14305 this.store.each(function(r){
14306 if(r.data[prop] == value){
14316 getName: function()
14318 // returns hidden if it's set..
14319 if (!this.rendered) {return ''};
14320 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
14324 onViewMove : function(e, t){
14325 this.inKeyMode = false;
14329 onViewOver : function(e, t){
14330 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
14333 var item = this.view.findItemFromChild(t);
14336 var index = this.view.indexOf(item);
14337 this.select(index, false);
14342 onViewClick : function(view, doFocus, el, e)
14344 var index = this.view.getSelectedIndexes()[0];
14346 var r = this.store.getAt(index);
14350 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
14357 Roo.each(this.tickItems, function(v,k){
14359 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
14361 _this.tickItems.splice(k, 1);
14363 if(typeof(e) == 'undefined' && view == false){
14364 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
14376 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
14377 this.tickItems.push(r.data);
14380 if(typeof(e) == 'undefined' && view == false){
14381 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
14388 this.onSelect(r, index);
14390 if(doFocus !== false && !this.blockFocus){
14391 this.inputEl().focus();
14396 restrictHeight : function(){
14397 //this.innerList.dom.style.height = '';
14398 //var inner = this.innerList.dom;
14399 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
14400 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
14401 //this.list.beginUpdate();
14402 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
14403 this.list.alignTo(this.inputEl(), this.listAlign);
14404 this.list.alignTo(this.inputEl(), this.listAlign);
14405 //this.list.endUpdate();
14409 onEmptyResults : function(){
14411 if(this.tickable && this.editable){
14412 this.hasFocus = false;
14413 this.restrictHeight();
14421 * Returns true if the dropdown list is expanded, else false.
14423 isExpanded : function(){
14424 return this.list.isVisible();
14428 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
14429 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14430 * @param {String} value The data value of the item to select
14431 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14432 * selected item if it is not currently in view (defaults to true)
14433 * @return {Boolean} True if the value matched an item in the list, else false
14435 selectByValue : function(v, scrollIntoView){
14436 if(v !== undefined && v !== null){
14437 var r = this.findRecord(this.valueField || this.displayField, v);
14439 this.select(this.store.indexOf(r), scrollIntoView);
14447 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
14448 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14449 * @param {Number} index The zero-based index of the list item to select
14450 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14451 * selected item if it is not currently in view (defaults to true)
14453 select : function(index, scrollIntoView){
14454 this.selectedIndex = index;
14455 this.view.select(index);
14456 if(scrollIntoView !== false){
14457 var el = this.view.getNode(index);
14459 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
14462 this.list.scrollChildIntoView(el, false);
14468 selectNext : function(){
14469 var ct = this.store.getCount();
14471 if(this.selectedIndex == -1){
14473 }else if(this.selectedIndex < ct-1){
14474 this.select(this.selectedIndex+1);
14480 selectPrev : function(){
14481 var ct = this.store.getCount();
14483 if(this.selectedIndex == -1){
14485 }else if(this.selectedIndex != 0){
14486 this.select(this.selectedIndex-1);
14492 onKeyUp : function(e){
14493 if(this.editable !== false && !e.isSpecialKey()){
14494 this.lastKey = e.getKey();
14495 this.dqTask.delay(this.queryDelay);
14500 validateBlur : function(){
14501 return !this.list || !this.list.isVisible();
14505 initQuery : function(){
14507 var v = this.getRawValue();
14509 if(this.tickable && this.editable){
14510 v = this.tickableInputEl().getValue();
14517 doForce : function(){
14518 if(this.inputEl().dom.value.length > 0){
14519 this.inputEl().dom.value =
14520 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
14526 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
14527 * query allowing the query action to be canceled if needed.
14528 * @param {String} query The SQL query to execute
14529 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
14530 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
14531 * saved in the current store (defaults to false)
14533 doQuery : function(q, forceAll){
14535 if(q === undefined || q === null){
14540 forceAll: forceAll,
14544 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
14549 forceAll = qe.forceAll;
14550 if(forceAll === true || (q.length >= this.minChars)){
14552 this.hasQuery = true;
14554 if(this.lastQuery != q || this.alwaysQuery){
14555 this.lastQuery = q;
14556 if(this.mode == 'local'){
14557 this.selectedIndex = -1;
14559 this.store.clearFilter();
14562 if(this.specialFilter){
14563 this.fireEvent('specialfilter', this);
14568 this.store.filter(this.displayField, q);
14571 this.store.fireEvent("datachanged", this.store);
14578 this.store.baseParams[this.queryParam] = q;
14580 var options = {params : this.getParams(q)};
14583 options.add = true;
14584 options.params.start = this.page * this.pageSize;
14587 this.store.load(options);
14590 * this code will make the page width larger, at the beginning, the list not align correctly,
14591 * we should expand the list on onLoad
14592 * so command out it
14597 this.selectedIndex = -1;
14602 this.loadNext = false;
14606 getParams : function(q){
14608 //p[this.queryParam] = q;
14612 p.limit = this.pageSize;
14618 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
14620 collapse : function(){
14621 if(!this.isExpanded()){
14627 this.hasFocus = false;
14631 this.cancelBtn.hide();
14632 this.trigger.show();
14635 this.tickableInputEl().dom.value = '';
14636 this.tickableInputEl().blur();
14641 Roo.get(document).un('mousedown', this.collapseIf, this);
14642 Roo.get(document).un('mousewheel', this.collapseIf, this);
14643 if (!this.editable) {
14644 Roo.get(document).un('keydown', this.listKeyPress, this);
14646 this.fireEvent('collapse', this);
14652 collapseIf : function(e){
14653 var in_combo = e.within(this.el);
14654 var in_list = e.within(this.list);
14655 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
14657 if (in_combo || in_list || is_list) {
14658 //e.stopPropagation();
14663 this.onTickableFooterButtonClick(e, false, false);
14671 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
14673 expand : function(){
14675 if(this.isExpanded() || !this.hasFocus){
14679 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
14680 this.list.setWidth(lw);
14686 this.restrictHeight();
14690 this.tickItems = Roo.apply([], this.item);
14693 this.cancelBtn.show();
14694 this.trigger.hide();
14697 this.tickableInputEl().focus();
14702 Roo.get(document).on('mousedown', this.collapseIf, this);
14703 Roo.get(document).on('mousewheel', this.collapseIf, this);
14704 if (!this.editable) {
14705 Roo.get(document).on('keydown', this.listKeyPress, this);
14708 this.fireEvent('expand', this);
14712 // Implements the default empty TriggerField.onTriggerClick function
14713 onTriggerClick : function(e)
14715 Roo.log('trigger click');
14717 if(this.disabled || !this.triggerList){
14722 this.loadNext = false;
14724 if(this.isExpanded()){
14726 if (!this.blockFocus) {
14727 this.inputEl().focus();
14731 this.hasFocus = true;
14732 if(this.triggerAction == 'all') {
14733 this.doQuery(this.allQuery, true);
14735 this.doQuery(this.getRawValue());
14737 if (!this.blockFocus) {
14738 this.inputEl().focus();
14743 onTickableTriggerClick : function(e)
14750 this.loadNext = false;
14751 this.hasFocus = true;
14753 if(this.triggerAction == 'all') {
14754 this.doQuery(this.allQuery, true);
14756 this.doQuery(this.getRawValue());
14760 onSearchFieldClick : function(e)
14762 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
14763 this.onTickableFooterButtonClick(e, false, false);
14767 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
14772 this.loadNext = false;
14773 this.hasFocus = true;
14775 if(this.triggerAction == 'all') {
14776 this.doQuery(this.allQuery, true);
14778 this.doQuery(this.getRawValue());
14782 listKeyPress : function(e)
14784 //Roo.log('listkeypress');
14785 // scroll to first matching element based on key pres..
14786 if (e.isSpecialKey()) {
14789 var k = String.fromCharCode(e.getKey()).toUpperCase();
14792 var csel = this.view.getSelectedNodes();
14793 var cselitem = false;
14795 var ix = this.view.indexOf(csel[0]);
14796 cselitem = this.store.getAt(ix);
14797 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
14803 this.store.each(function(v) {
14805 // start at existing selection.
14806 if (cselitem.id == v.id) {
14812 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
14813 match = this.store.indexOf(v);
14819 if (match === false) {
14820 return true; // no more action?
14823 this.view.select(match);
14824 var sn = Roo.get(this.view.getSelectedNodes()[0]);
14825 sn.scrollIntoView(sn.dom.parentNode, false);
14828 onViewScroll : function(e, t){
14830 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){
14834 this.hasQuery = true;
14836 this.loading = this.list.select('.loading', true).first();
14838 if(this.loading === null){
14839 this.list.createChild({
14841 cls: 'loading roo-select2-more-results roo-select2-active',
14842 html: 'Loading more results...'
14845 this.loading = this.list.select('.loading', true).first();
14847 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
14849 this.loading.hide();
14852 this.loading.show();
14857 this.loadNext = true;
14859 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
14864 addItem : function(o)
14866 var dv = ''; // display value
14868 if (this.displayField) {
14869 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14871 // this is an error condition!!!
14872 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14879 var choice = this.choices.createChild({
14881 cls: 'roo-select2-search-choice',
14890 cls: 'roo-select2-search-choice-close fa fa-times',
14895 }, this.searchField);
14897 var close = choice.select('a.roo-select2-search-choice-close', true).first();
14899 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
14907 this.inputEl().dom.value = '';
14912 onRemoveItem : function(e, _self, o)
14914 e.preventDefault();
14916 this.lastItem = Roo.apply([], this.item);
14918 var index = this.item.indexOf(o.data) * 1;
14921 Roo.log('not this item?!');
14925 this.item.splice(index, 1);
14930 this.fireEvent('remove', this, e);
14936 syncValue : function()
14938 if(!this.item.length){
14945 Roo.each(this.item, function(i){
14946 if(_this.valueField){
14947 value.push(i[_this.valueField]);
14954 this.value = value.join(',');
14956 if(this.hiddenField){
14957 this.hiddenField.dom.value = this.value;
14960 this.store.fireEvent("datachanged", this.store);
14965 clearItem : function()
14967 if(!this.multiple){
14973 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
14981 if(this.tickable && !Roo.isTouch){
14982 this.view.refresh();
14986 inputEl: function ()
14988 if(Roo.isIOS && this.useNativeIOS){
14989 return this.el.select('select.roo-ios-select', true).first();
14992 if(Roo.isTouch && this.mobileTouchView){
14993 return this.el.select('input.form-control',true).first();
14997 return this.searchField;
15000 return this.el.select('input.form-control',true).first();
15003 onTickableFooterButtonClick : function(e, btn, el)
15005 e.preventDefault();
15007 this.lastItem = Roo.apply([], this.item);
15009 if(btn && btn.name == 'cancel'){
15010 this.tickItems = Roo.apply([], this.item);
15019 Roo.each(this.tickItems, function(o){
15027 validate : function()
15029 if(this.getVisibilityEl().hasClass('hidden')){
15033 var v = this.getRawValue();
15036 v = this.getValue();
15039 if(this.disabled || this.allowBlank || v.length){
15044 this.markInvalid();
15048 tickableInputEl : function()
15050 if(!this.tickable || !this.editable){
15051 return this.inputEl();
15054 return this.inputEl().select('.roo-select2-search-field-input', true).first();
15058 getAutoCreateTouchView : function()
15063 cls: 'form-group' //input-group
15069 type : this.inputType,
15070 cls : 'form-control x-combo-noedit',
15071 autocomplete: 'new-password',
15072 placeholder : this.placeholder || '',
15077 input.name = this.name;
15081 input.cls += ' input-' + this.size;
15084 if (this.disabled) {
15085 input.disabled = true;
15096 inputblock.cls += ' input-group';
15098 inputblock.cn.unshift({
15100 cls : 'input-group-addon input-group-prepend input-group-text',
15105 if(this.removable && !this.multiple){
15106 inputblock.cls += ' roo-removable';
15108 inputblock.cn.push({
15111 cls : 'roo-combo-removable-btn close'
15115 if(this.hasFeedback && !this.allowBlank){
15117 inputblock.cls += ' has-feedback';
15119 inputblock.cn.push({
15121 cls: 'glyphicon form-control-feedback'
15128 inputblock.cls += (this.before) ? '' : ' input-group';
15130 inputblock.cn.push({
15132 cls : 'input-group-addon input-group-append input-group-text',
15138 var ibwrap = inputblock;
15143 cls: 'roo-select2-choices',
15147 cls: 'roo-select2-search-field',
15160 cls: 'roo-select2-container input-group roo-touchview-combobox ',
15165 cls: 'form-hidden-field'
15171 if(!this.multiple && this.showToggleBtn){
15178 if (this.caret != false) {
15181 cls: 'fa fa-' + this.caret
15188 cls : 'input-group-addon input-group-append input-group-text btn dropdown-toggle',
15193 cls: 'combobox-clear',
15207 combobox.cls += ' roo-select2-container-multi';
15210 var align = this.labelAlign || this.parentLabelAlign();
15212 if (align ==='left' && this.fieldLabel.length) {
15217 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15218 tooltip : 'This field is required'
15222 cls : 'control-label col-form-label',
15223 html : this.fieldLabel
15234 var labelCfg = cfg.cn[1];
15235 var contentCfg = cfg.cn[2];
15238 if(this.indicatorpos == 'right'){
15243 cls : 'control-label col-form-label',
15247 html : this.fieldLabel
15251 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15252 tooltip : 'This field is required'
15265 labelCfg = cfg.cn[0];
15266 contentCfg = cfg.cn[1];
15271 if(this.labelWidth > 12){
15272 labelCfg.style = "width: " + this.labelWidth + 'px';
15275 if(this.labelWidth < 13 && this.labelmd == 0){
15276 this.labelmd = this.labelWidth;
15279 if(this.labellg > 0){
15280 labelCfg.cls += ' col-lg-' + this.labellg;
15281 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
15284 if(this.labelmd > 0){
15285 labelCfg.cls += ' col-md-' + this.labelmd;
15286 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
15289 if(this.labelsm > 0){
15290 labelCfg.cls += ' col-sm-' + this.labelsm;
15291 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
15294 if(this.labelxs > 0){
15295 labelCfg.cls += ' col-xs-' + this.labelxs;
15296 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
15300 } else if ( this.fieldLabel.length) {
15304 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15305 tooltip : 'This field is required'
15309 cls : 'control-label',
15310 html : this.fieldLabel
15321 if(this.indicatorpos == 'right'){
15325 cls : 'control-label',
15326 html : this.fieldLabel,
15330 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15331 tooltip : 'This field is required'
15348 var settings = this;
15350 ['xs','sm','md','lg'].map(function(size){
15351 if (settings[size]) {
15352 cfg.cls += ' col-' + size + '-' + settings[size];
15359 initTouchView : function()
15361 this.renderTouchView();
15363 this.touchViewEl.on('scroll', function(){
15364 this.el.dom.scrollTop = 0;
15367 this.originalValue = this.getValue();
15369 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
15371 this.inputEl().on("click", this.showTouchView, this);
15372 if (this.triggerEl) {
15373 this.triggerEl.on("click", this.showTouchView, this);
15377 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
15378 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
15380 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
15382 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
15383 this.store.on('load', this.onTouchViewLoad, this);
15384 this.store.on('loadexception', this.onTouchViewLoadException, this);
15386 if(this.hiddenName){
15388 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
15390 this.hiddenField.dom.value =
15391 this.hiddenValue !== undefined ? this.hiddenValue :
15392 this.value !== undefined ? this.value : '';
15394 this.el.dom.removeAttribute('name');
15395 this.hiddenField.dom.setAttribute('name', this.hiddenName);
15399 this.choices = this.el.select('ul.roo-select2-choices', true).first();
15400 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
15403 if(this.removable && !this.multiple){
15404 var close = this.closeTriggerEl();
15406 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
15407 close.on('click', this.removeBtnClick, this, close);
15411 * fix the bug in Safari iOS8
15413 this.inputEl().on("focus", function(e){
15414 document.activeElement.blur();
15417 this._touchViewMask = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
15424 renderTouchView : function()
15426 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
15427 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15429 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
15430 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15432 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
15433 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15434 this.touchViewBodyEl.setStyle('overflow', 'auto');
15436 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
15437 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15439 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
15440 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15444 showTouchView : function()
15450 this.touchViewHeaderEl.hide();
15452 if(this.modalTitle.length){
15453 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
15454 this.touchViewHeaderEl.show();
15457 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
15458 this.touchViewEl.show();
15460 this.touchViewEl.select('.modal-dialog', true).first().setStyle({ margin : '0px', width : '100%'});
15462 //this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
15463 // Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15465 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15467 if(this.modalTitle.length){
15468 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15471 this.touchViewBodyEl.setHeight(bodyHeight);
15475 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
15477 this.touchViewEl.addClass('in');
15480 if(this._touchViewMask){
15481 Roo.get(document.body).addClass("x-body-masked");
15482 this._touchViewMask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15483 this._touchViewMask.setStyle('z-index', 10000);
15484 this._touchViewMask.addClass('show');
15487 this.doTouchViewQuery();
15491 hideTouchView : function()
15493 this.touchViewEl.removeClass('in');
15497 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
15499 this.touchViewEl.setStyle('display', 'none');
15502 if(this._touchViewMask){
15503 this._touchViewMask.removeClass('show');
15504 Roo.get(document.body).removeClass("x-body-masked");
15508 setTouchViewValue : function()
15515 Roo.each(this.tickItems, function(o){
15520 this.hideTouchView();
15523 doTouchViewQuery : function()
15532 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
15536 if(!this.alwaysQuery || this.mode == 'local'){
15537 this.onTouchViewLoad();
15544 onTouchViewBeforeLoad : function(combo,opts)
15550 onTouchViewLoad : function()
15552 if(this.store.getCount() < 1){
15553 this.onTouchViewEmptyResults();
15557 this.clearTouchView();
15559 var rawValue = this.getRawValue();
15561 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
15563 this.tickItems = [];
15565 this.store.data.each(function(d, rowIndex){
15566 var row = this.touchViewListGroup.createChild(template);
15568 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
15569 row.addClass(d.data.cls);
15572 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15575 html : d.data[this.displayField]
15578 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
15579 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
15582 row.removeClass('selected');
15583 if(!this.multiple && this.valueField &&
15584 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
15587 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15588 row.addClass('selected');
15591 if(this.multiple && this.valueField &&
15592 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
15596 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15597 this.tickItems.push(d.data);
15600 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
15604 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
15606 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15608 if(this.modalTitle.length){
15609 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15612 var listHeight = this.touchViewListGroup.getHeight() + this.touchViewBodyEl.getPadding('tb') * 2;
15614 if(this.mobile_restrict_height && listHeight < bodyHeight){
15615 this.touchViewBodyEl.setHeight(listHeight);
15620 if(firstChecked && listHeight > bodyHeight){
15621 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
15626 onTouchViewLoadException : function()
15628 this.hideTouchView();
15631 onTouchViewEmptyResults : function()
15633 this.clearTouchView();
15635 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
15637 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
15641 clearTouchView : function()
15643 this.touchViewListGroup.dom.innerHTML = '';
15646 onTouchViewClick : function(e, el, o)
15648 e.preventDefault();
15651 var rowIndex = o.rowIndex;
15653 var r = this.store.getAt(rowIndex);
15655 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
15657 if(!this.multiple){
15658 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
15659 c.dom.removeAttribute('checked');
15662 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15664 this.setFromData(r.data);
15666 var close = this.closeTriggerEl();
15672 this.hideTouchView();
15674 this.fireEvent('select', this, r, rowIndex);
15679 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
15680 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
15681 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
15685 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15686 this.addItem(r.data);
15687 this.tickItems.push(r.data);
15691 getAutoCreateNativeIOS : function()
15694 cls: 'form-group' //input-group,
15699 cls : 'roo-ios-select'
15703 combobox.name = this.name;
15706 if (this.disabled) {
15707 combobox.disabled = true;
15710 var settings = this;
15712 ['xs','sm','md','lg'].map(function(size){
15713 if (settings[size]) {
15714 cfg.cls += ' col-' + size + '-' + settings[size];
15724 initIOSView : function()
15726 this.store.on('load', this.onIOSViewLoad, this);
15731 onIOSViewLoad : function()
15733 if(this.store.getCount() < 1){
15737 this.clearIOSView();
15739 if(this.allowBlank) {
15741 var default_text = '-- SELECT --';
15743 if(this.placeholder.length){
15744 default_text = this.placeholder;
15747 if(this.emptyTitle.length){
15748 default_text += ' - ' + this.emptyTitle + ' -';
15751 var opt = this.inputEl().createChild({
15754 html : default_text
15758 o[this.valueField] = 0;
15759 o[this.displayField] = default_text;
15761 this.ios_options.push({
15768 this.store.data.each(function(d, rowIndex){
15772 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15773 html = d.data[this.displayField];
15778 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
15779 value = d.data[this.valueField];
15788 if(this.value == d.data[this.valueField]){
15789 option['selected'] = true;
15792 var opt = this.inputEl().createChild(option);
15794 this.ios_options.push({
15801 this.inputEl().on('change', function(){
15802 this.fireEvent('select', this);
15807 clearIOSView: function()
15809 this.inputEl().dom.innerHTML = '';
15811 this.ios_options = [];
15814 setIOSValue: function(v)
15818 if(!this.ios_options){
15822 Roo.each(this.ios_options, function(opts){
15824 opts.el.dom.removeAttribute('selected');
15826 if(opts.data[this.valueField] != v){
15830 opts.el.dom.setAttribute('selected', true);
15836 * @cfg {Boolean} grow
15840 * @cfg {Number} growMin
15844 * @cfg {Number} growMax
15853 Roo.apply(Roo.bootstrap.ComboBox, {
15857 cls: 'modal-header',
15879 cls: 'list-group-item',
15883 cls: 'roo-combobox-list-group-item-value'
15887 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
15901 listItemCheckbox : {
15903 cls: 'list-group-item',
15907 cls: 'roo-combobox-list-group-item-value'
15911 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
15927 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
15932 cls: 'modal-footer',
15940 cls: 'col-xs-6 text-left',
15943 cls: 'btn btn-danger roo-touch-view-cancel',
15949 cls: 'col-xs-6 text-right',
15952 cls: 'btn btn-success roo-touch-view-ok',
15963 Roo.apply(Roo.bootstrap.ComboBox, {
15965 touchViewTemplate : {
15967 cls: 'modal fade roo-combobox-touch-view',
15971 cls: 'modal-dialog',
15972 style : 'position:fixed', // we have to fix position....
15976 cls: 'modal-content',
15978 Roo.bootstrap.ComboBox.header,
15979 Roo.bootstrap.ComboBox.body,
15980 Roo.bootstrap.ComboBox.footer
15989 * Ext JS Library 1.1.1
15990 * Copyright(c) 2006-2007, Ext JS, LLC.
15992 * Originally Released Under LGPL - original licence link has changed is not relivant.
15995 * <script type="text/javascript">
16000 * @extends Roo.util.Observable
16001 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
16002 * This class also supports single and multi selection modes. <br>
16003 * Create a data model bound view:
16005 var store = new Roo.data.Store(...);
16007 var view = new Roo.View({
16009 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
16011 singleSelect: true,
16012 selectedClass: "ydataview-selected",
16016 // listen for node click?
16017 view.on("click", function(vw, index, node, e){
16018 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
16022 dataModel.load("foobar.xml");
16024 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
16026 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
16027 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
16029 * Note: old style constructor is still suported (container, template, config)
16032 * Create a new View
16033 * @param {Object} config The config object
16036 Roo.View = function(config, depreciated_tpl, depreciated_config){
16038 this.parent = false;
16040 if (typeof(depreciated_tpl) == 'undefined') {
16041 // new way.. - universal constructor.
16042 Roo.apply(this, config);
16043 this.el = Roo.get(this.el);
16046 this.el = Roo.get(config);
16047 this.tpl = depreciated_tpl;
16048 Roo.apply(this, depreciated_config);
16050 this.wrapEl = this.el.wrap().wrap();
16051 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
16054 if(typeof(this.tpl) == "string"){
16055 this.tpl = new Roo.Template(this.tpl);
16057 // support xtype ctors..
16058 this.tpl = new Roo.factory(this.tpl, Roo);
16062 this.tpl.compile();
16067 * @event beforeclick
16068 * Fires before a click is processed. Returns false to cancel the default action.
16069 * @param {Roo.View} this
16070 * @param {Number} index The index of the target node
16071 * @param {HTMLElement} node The target node
16072 * @param {Roo.EventObject} e The raw event object
16074 "beforeclick" : true,
16077 * Fires when a template node is clicked.
16078 * @param {Roo.View} this
16079 * @param {Number} index The index of the target node
16080 * @param {HTMLElement} node The target node
16081 * @param {Roo.EventObject} e The raw event object
16086 * Fires when a template node is double clicked.
16087 * @param {Roo.View} this
16088 * @param {Number} index The index of the target node
16089 * @param {HTMLElement} node The target node
16090 * @param {Roo.EventObject} e The raw event object
16094 * @event contextmenu
16095 * Fires when a template node is right clicked.
16096 * @param {Roo.View} this
16097 * @param {Number} index The index of the target node
16098 * @param {HTMLElement} node The target node
16099 * @param {Roo.EventObject} e The raw event object
16101 "contextmenu" : true,
16103 * @event selectionchange
16104 * Fires when the selected nodes change.
16105 * @param {Roo.View} this
16106 * @param {Array} selections Array of the selected nodes
16108 "selectionchange" : true,
16111 * @event beforeselect
16112 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
16113 * @param {Roo.View} this
16114 * @param {HTMLElement} node The node to be selected
16115 * @param {Array} selections Array of currently selected nodes
16117 "beforeselect" : true,
16119 * @event preparedata
16120 * Fires on every row to render, to allow you to change the data.
16121 * @param {Roo.View} this
16122 * @param {Object} data to be rendered (change this)
16124 "preparedata" : true
16132 "click": this.onClick,
16133 "dblclick": this.onDblClick,
16134 "contextmenu": this.onContextMenu,
16138 this.selections = [];
16140 this.cmp = new Roo.CompositeElementLite([]);
16142 this.store = Roo.factory(this.store, Roo.data);
16143 this.setStore(this.store, true);
16146 if ( this.footer && this.footer.xtype) {
16148 var fctr = this.wrapEl.appendChild(document.createElement("div"));
16150 this.footer.dataSource = this.store;
16151 this.footer.container = fctr;
16152 this.footer = Roo.factory(this.footer, Roo);
16153 fctr.insertFirst(this.el);
16155 // this is a bit insane - as the paging toolbar seems to detach the el..
16156 // dom.parentNode.parentNode.parentNode
16157 // they get detached?
16161 Roo.View.superclass.constructor.call(this);
16166 Roo.extend(Roo.View, Roo.util.Observable, {
16169 * @cfg {Roo.data.Store} store Data store to load data from.
16174 * @cfg {String|Roo.Element} el The container element.
16179 * @cfg {String|Roo.Template} tpl The template used by this View
16183 * @cfg {String} dataName the named area of the template to use as the data area
16184 * Works with domtemplates roo-name="name"
16188 * @cfg {String} selectedClass The css class to add to selected nodes
16190 selectedClass : "x-view-selected",
16192 * @cfg {String} emptyText The empty text to show when nothing is loaded.
16197 * @cfg {String} text to display on mask (default Loading)
16201 * @cfg {Boolean} multiSelect Allow multiple selection
16203 multiSelect : false,
16205 * @cfg {Boolean} singleSelect Allow single selection
16207 singleSelect: false,
16210 * @cfg {Boolean} toggleSelect - selecting
16212 toggleSelect : false,
16215 * @cfg {Boolean} tickable - selecting
16220 * Returns the element this view is bound to.
16221 * @return {Roo.Element}
16223 getEl : function(){
16224 return this.wrapEl;
16230 * Refreshes the view. - called by datachanged on the store. - do not call directly.
16232 refresh : function(){
16233 //Roo.log('refresh');
16236 // if we are using something like 'domtemplate', then
16237 // the what gets used is:
16238 // t.applySubtemplate(NAME, data, wrapping data..)
16239 // the outer template then get' applied with
16240 // the store 'extra data'
16241 // and the body get's added to the
16242 // roo-name="data" node?
16243 // <span class='roo-tpl-{name}'></span> ?????
16247 this.clearSelections();
16248 this.el.update("");
16250 var records = this.store.getRange();
16251 if(records.length < 1) {
16253 // is this valid?? = should it render a template??
16255 this.el.update(this.emptyText);
16259 if (this.dataName) {
16260 this.el.update(t.apply(this.store.meta)); //????
16261 el = this.el.child('.roo-tpl-' + this.dataName);
16264 for(var i = 0, len = records.length; i < len; i++){
16265 var data = this.prepareData(records[i].data, i, records[i]);
16266 this.fireEvent("preparedata", this, data, i, records[i]);
16268 var d = Roo.apply({}, data);
16271 Roo.apply(d, {'roo-id' : Roo.id()});
16275 Roo.each(this.parent.item, function(item){
16276 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
16279 Roo.apply(d, {'roo-data-checked' : 'checked'});
16283 html[html.length] = Roo.util.Format.trim(
16285 t.applySubtemplate(this.dataName, d, this.store.meta) :
16292 el.update(html.join(""));
16293 this.nodes = el.dom.childNodes;
16294 this.updateIndexes(0);
16299 * Function to override to reformat the data that is sent to
16300 * the template for each node.
16301 * DEPRICATED - use the preparedata event handler.
16302 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
16303 * a JSON object for an UpdateManager bound view).
16305 prepareData : function(data, index, record)
16307 this.fireEvent("preparedata", this, data, index, record);
16311 onUpdate : function(ds, record){
16312 // Roo.log('on update');
16313 this.clearSelections();
16314 var index = this.store.indexOf(record);
16315 var n = this.nodes[index];
16316 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
16317 n.parentNode.removeChild(n);
16318 this.updateIndexes(index, index);
16324 onAdd : function(ds, records, index)
16326 //Roo.log(['on Add', ds, records, index] );
16327 this.clearSelections();
16328 if(this.nodes.length == 0){
16332 var n = this.nodes[index];
16333 for(var i = 0, len = records.length; i < len; i++){
16334 var d = this.prepareData(records[i].data, i, records[i]);
16336 this.tpl.insertBefore(n, d);
16339 this.tpl.append(this.el, d);
16342 this.updateIndexes(index);
16345 onRemove : function(ds, record, index){
16346 // Roo.log('onRemove');
16347 this.clearSelections();
16348 var el = this.dataName ?
16349 this.el.child('.roo-tpl-' + this.dataName) :
16352 el.dom.removeChild(this.nodes[index]);
16353 this.updateIndexes(index);
16357 * Refresh an individual node.
16358 * @param {Number} index
16360 refreshNode : function(index){
16361 this.onUpdate(this.store, this.store.getAt(index));
16364 updateIndexes : function(startIndex, endIndex){
16365 var ns = this.nodes;
16366 startIndex = startIndex || 0;
16367 endIndex = endIndex || ns.length - 1;
16368 for(var i = startIndex; i <= endIndex; i++){
16369 ns[i].nodeIndex = i;
16374 * Changes the data store this view uses and refresh the view.
16375 * @param {Store} store
16377 setStore : function(store, initial){
16378 if(!initial && this.store){
16379 this.store.un("datachanged", this.refresh);
16380 this.store.un("add", this.onAdd);
16381 this.store.un("remove", this.onRemove);
16382 this.store.un("update", this.onUpdate);
16383 this.store.un("clear", this.refresh);
16384 this.store.un("beforeload", this.onBeforeLoad);
16385 this.store.un("load", this.onLoad);
16386 this.store.un("loadexception", this.onLoad);
16390 store.on("datachanged", this.refresh, this);
16391 store.on("add", this.onAdd, this);
16392 store.on("remove", this.onRemove, this);
16393 store.on("update", this.onUpdate, this);
16394 store.on("clear", this.refresh, this);
16395 store.on("beforeload", this.onBeforeLoad, this);
16396 store.on("load", this.onLoad, this);
16397 store.on("loadexception", this.onLoad, this);
16405 * onbeforeLoad - masks the loading area.
16408 onBeforeLoad : function(store,opts)
16410 //Roo.log('onBeforeLoad');
16412 this.el.update("");
16414 this.el.mask(this.mask ? this.mask : "Loading" );
16416 onLoad : function ()
16423 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
16424 * @param {HTMLElement} node
16425 * @return {HTMLElement} The template node
16427 findItemFromChild : function(node){
16428 var el = this.dataName ?
16429 this.el.child('.roo-tpl-' + this.dataName,true) :
16432 if(!node || node.parentNode == el){
16435 var p = node.parentNode;
16436 while(p && p != el){
16437 if(p.parentNode == el){
16446 onClick : function(e){
16447 var item = this.findItemFromChild(e.getTarget());
16449 var index = this.indexOf(item);
16450 if(this.onItemClick(item, index, e) !== false){
16451 this.fireEvent("click", this, index, item, e);
16454 this.clearSelections();
16459 onContextMenu : function(e){
16460 var item = this.findItemFromChild(e.getTarget());
16462 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
16467 onDblClick : function(e){
16468 var item = this.findItemFromChild(e.getTarget());
16470 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
16474 onItemClick : function(item, index, e)
16476 if(this.fireEvent("beforeclick", this, index, item, e) === false){
16479 if (this.toggleSelect) {
16480 var m = this.isSelected(item) ? 'unselect' : 'select';
16483 _t[m](item, true, false);
16486 if(this.multiSelect || this.singleSelect){
16487 if(this.multiSelect && e.shiftKey && this.lastSelection){
16488 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
16490 this.select(item, this.multiSelect && e.ctrlKey);
16491 this.lastSelection = item;
16494 if(!this.tickable){
16495 e.preventDefault();
16503 * Get the number of selected nodes.
16506 getSelectionCount : function(){
16507 return this.selections.length;
16511 * Get the currently selected nodes.
16512 * @return {Array} An array of HTMLElements
16514 getSelectedNodes : function(){
16515 return this.selections;
16519 * Get the indexes of the selected nodes.
16522 getSelectedIndexes : function(){
16523 var indexes = [], s = this.selections;
16524 for(var i = 0, len = s.length; i < len; i++){
16525 indexes.push(s[i].nodeIndex);
16531 * Clear all selections
16532 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
16534 clearSelections : function(suppressEvent){
16535 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
16536 this.cmp.elements = this.selections;
16537 this.cmp.removeClass(this.selectedClass);
16538 this.selections = [];
16539 if(!suppressEvent){
16540 this.fireEvent("selectionchange", this, this.selections);
16546 * Returns true if the passed node is selected
16547 * @param {HTMLElement/Number} node The node or node index
16548 * @return {Boolean}
16550 isSelected : function(node){
16551 var s = this.selections;
16555 node = this.getNode(node);
16556 return s.indexOf(node) !== -1;
16561 * @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
16562 * @param {Boolean} keepExisting (optional) true to keep existing selections
16563 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16565 select : function(nodeInfo, keepExisting, suppressEvent){
16566 if(nodeInfo instanceof Array){
16568 this.clearSelections(true);
16570 for(var i = 0, len = nodeInfo.length; i < len; i++){
16571 this.select(nodeInfo[i], true, true);
16575 var node = this.getNode(nodeInfo);
16576 if(!node || this.isSelected(node)){
16577 return; // already selected.
16580 this.clearSelections(true);
16583 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
16584 Roo.fly(node).addClass(this.selectedClass);
16585 this.selections.push(node);
16586 if(!suppressEvent){
16587 this.fireEvent("selectionchange", this, this.selections);
16595 * @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
16596 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
16597 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16599 unselect : function(nodeInfo, keepExisting, suppressEvent)
16601 if(nodeInfo instanceof Array){
16602 Roo.each(this.selections, function(s) {
16603 this.unselect(s, nodeInfo);
16607 var node = this.getNode(nodeInfo);
16608 if(!node || !this.isSelected(node)){
16609 //Roo.log("not selected");
16610 return; // not selected.
16614 Roo.each(this.selections, function(s) {
16616 Roo.fly(node).removeClass(this.selectedClass);
16623 this.selections= ns;
16624 this.fireEvent("selectionchange", this, this.selections);
16628 * Gets a template node.
16629 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16630 * @return {HTMLElement} The node or null if it wasn't found
16632 getNode : function(nodeInfo){
16633 if(typeof nodeInfo == "string"){
16634 return document.getElementById(nodeInfo);
16635 }else if(typeof nodeInfo == "number"){
16636 return this.nodes[nodeInfo];
16642 * Gets a range template nodes.
16643 * @param {Number} startIndex
16644 * @param {Number} endIndex
16645 * @return {Array} An array of nodes
16647 getNodes : function(start, end){
16648 var ns = this.nodes;
16649 start = start || 0;
16650 end = typeof end == "undefined" ? ns.length - 1 : end;
16653 for(var i = start; i <= end; i++){
16657 for(var i = start; i >= end; i--){
16665 * Finds the index of the passed node
16666 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16667 * @return {Number} The index of the node or -1
16669 indexOf : function(node){
16670 node = this.getNode(node);
16671 if(typeof node.nodeIndex == "number"){
16672 return node.nodeIndex;
16674 var ns = this.nodes;
16675 for(var i = 0, len = ns.length; i < len; i++){
16686 * based on jquery fullcalendar
16690 Roo.bootstrap = Roo.bootstrap || {};
16692 * @class Roo.bootstrap.Calendar
16693 * @extends Roo.bootstrap.Component
16694 * Bootstrap Calendar class
16695 * @cfg {Boolean} loadMask (true|false) default false
16696 * @cfg {Object} header generate the user specific header of the calendar, default false
16699 * Create a new Container
16700 * @param {Object} config The config object
16705 Roo.bootstrap.Calendar = function(config){
16706 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
16710 * Fires when a date is selected
16711 * @param {DatePicker} this
16712 * @param {Date} date The selected date
16716 * @event monthchange
16717 * Fires when the displayed month changes
16718 * @param {DatePicker} this
16719 * @param {Date} date The selected month
16721 'monthchange': true,
16723 * @event evententer
16724 * Fires when mouse over an event
16725 * @param {Calendar} this
16726 * @param {event} Event
16728 'evententer': true,
16730 * @event eventleave
16731 * Fires when the mouse leaves an
16732 * @param {Calendar} this
16735 'eventleave': true,
16737 * @event eventclick
16738 * Fires when the mouse click an
16739 * @param {Calendar} this
16748 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
16751 * @cfg {Number} startDay
16752 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16760 getAutoCreate : function(){
16763 var fc_button = function(name, corner, style, content ) {
16764 return Roo.apply({},{
16766 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
16768 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
16771 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
16782 style : 'width:100%',
16789 cls : 'fc-header-left',
16791 fc_button('prev', 'left', 'arrow', '‹' ),
16792 fc_button('next', 'right', 'arrow', '›' ),
16793 { tag: 'span', cls: 'fc-header-space' },
16794 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
16802 cls : 'fc-header-center',
16806 cls: 'fc-header-title',
16809 html : 'month / year'
16817 cls : 'fc-header-right',
16819 /* fc_button('month', 'left', '', 'month' ),
16820 fc_button('week', '', '', 'week' ),
16821 fc_button('day', 'right', '', 'day' )
16833 header = this.header;
16836 var cal_heads = function() {
16838 // fixme - handle this.
16840 for (var i =0; i < Date.dayNames.length; i++) {
16841 var d = Date.dayNames[i];
16844 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
16845 html : d.substring(0,3)
16849 ret[0].cls += ' fc-first';
16850 ret[6].cls += ' fc-last';
16853 var cal_cell = function(n) {
16856 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
16861 cls: 'fc-day-number',
16865 cls: 'fc-day-content',
16869 style: 'position: relative;' // height: 17px;
16881 var cal_rows = function() {
16884 for (var r = 0; r < 6; r++) {
16891 for (var i =0; i < Date.dayNames.length; i++) {
16892 var d = Date.dayNames[i];
16893 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
16896 row.cn[0].cls+=' fc-first';
16897 row.cn[0].cn[0].style = 'min-height:90px';
16898 row.cn[6].cls+=' fc-last';
16902 ret[0].cls += ' fc-first';
16903 ret[4].cls += ' fc-prev-last';
16904 ret[5].cls += ' fc-last';
16911 cls: 'fc-border-separate',
16912 style : 'width:100%',
16920 cls : 'fc-first fc-last',
16938 cls : 'fc-content',
16939 style : "position: relative;",
16942 cls : 'fc-view fc-view-month fc-grid',
16943 style : 'position: relative',
16944 unselectable : 'on',
16947 cls : 'fc-event-container',
16948 style : 'position:absolute;z-index:8;top:0;left:0;'
16966 initEvents : function()
16969 throw "can not find store for calendar";
16975 style: "text-align:center",
16979 style: "background-color:white;width:50%;margin:250 auto",
16983 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
16994 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
16996 var size = this.el.select('.fc-content', true).first().getSize();
16997 this.maskEl.setSize(size.width, size.height);
16998 this.maskEl.enableDisplayMode("block");
16999 if(!this.loadMask){
17000 this.maskEl.hide();
17003 this.store = Roo.factory(this.store, Roo.data);
17004 this.store.on('load', this.onLoad, this);
17005 this.store.on('beforeload', this.onBeforeLoad, this);
17009 this.cells = this.el.select('.fc-day',true);
17010 //Roo.log(this.cells);
17011 this.textNodes = this.el.query('.fc-day-number');
17012 this.cells.addClassOnOver('fc-state-hover');
17014 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
17015 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
17016 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
17017 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
17019 this.on('monthchange', this.onMonthChange, this);
17021 this.update(new Date().clearTime());
17024 resize : function() {
17025 var sz = this.el.getSize();
17027 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
17028 this.el.select('.fc-day-content div',true).setHeight(34);
17033 showPrevMonth : function(e){
17034 this.update(this.activeDate.add("mo", -1));
17036 showToday : function(e){
17037 this.update(new Date().clearTime());
17040 showNextMonth : function(e){
17041 this.update(this.activeDate.add("mo", 1));
17045 showPrevYear : function(){
17046 this.update(this.activeDate.add("y", -1));
17050 showNextYear : function(){
17051 this.update(this.activeDate.add("y", 1));
17056 update : function(date)
17058 var vd = this.activeDate;
17059 this.activeDate = date;
17060 // if(vd && this.el){
17061 // var t = date.getTime();
17062 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
17063 // Roo.log('using add remove');
17065 // this.fireEvent('monthchange', this, date);
17067 // this.cells.removeClass("fc-state-highlight");
17068 // this.cells.each(function(c){
17069 // if(c.dateValue == t){
17070 // c.addClass("fc-state-highlight");
17071 // setTimeout(function(){
17072 // try{c.dom.firstChild.focus();}catch(e){}
17082 var days = date.getDaysInMonth();
17084 var firstOfMonth = date.getFirstDateOfMonth();
17085 var startingPos = firstOfMonth.getDay()-this.startDay;
17087 if(startingPos < this.startDay){
17091 var pm = date.add(Date.MONTH, -1);
17092 var prevStart = pm.getDaysInMonth()-startingPos;
17094 this.cells = this.el.select('.fc-day',true);
17095 this.textNodes = this.el.query('.fc-day-number');
17096 this.cells.addClassOnOver('fc-state-hover');
17098 var cells = this.cells.elements;
17099 var textEls = this.textNodes;
17101 Roo.each(cells, function(cell){
17102 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
17105 days += startingPos;
17107 // convert everything to numbers so it's fast
17108 var day = 86400000;
17109 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
17112 //Roo.log(prevStart);
17114 var today = new Date().clearTime().getTime();
17115 var sel = date.clearTime().getTime();
17116 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
17117 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
17118 var ddMatch = this.disabledDatesRE;
17119 var ddText = this.disabledDatesText;
17120 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
17121 var ddaysText = this.disabledDaysText;
17122 var format = this.format;
17124 var setCellClass = function(cal, cell){
17128 //Roo.log('set Cell Class');
17130 var t = d.getTime();
17134 cell.dateValue = t;
17136 cell.className += " fc-today";
17137 cell.className += " fc-state-highlight";
17138 cell.title = cal.todayText;
17141 // disable highlight in other month..
17142 //cell.className += " fc-state-highlight";
17147 cell.className = " fc-state-disabled";
17148 cell.title = cal.minText;
17152 cell.className = " fc-state-disabled";
17153 cell.title = cal.maxText;
17157 if(ddays.indexOf(d.getDay()) != -1){
17158 cell.title = ddaysText;
17159 cell.className = " fc-state-disabled";
17162 if(ddMatch && format){
17163 var fvalue = d.dateFormat(format);
17164 if(ddMatch.test(fvalue)){
17165 cell.title = ddText.replace("%0", fvalue);
17166 cell.className = " fc-state-disabled";
17170 if (!cell.initialClassName) {
17171 cell.initialClassName = cell.dom.className;
17174 cell.dom.className = cell.initialClassName + ' ' + cell.className;
17179 for(; i < startingPos; i++) {
17180 textEls[i].innerHTML = (++prevStart);
17181 d.setDate(d.getDate()+1);
17183 cells[i].className = "fc-past fc-other-month";
17184 setCellClass(this, cells[i]);
17189 for(; i < days; i++){
17190 intDay = i - startingPos + 1;
17191 textEls[i].innerHTML = (intDay);
17192 d.setDate(d.getDate()+1);
17194 cells[i].className = ''; // "x-date-active";
17195 setCellClass(this, cells[i]);
17199 for(; i < 42; i++) {
17200 textEls[i].innerHTML = (++extraDays);
17201 d.setDate(d.getDate()+1);
17203 cells[i].className = "fc-future fc-other-month";
17204 setCellClass(this, cells[i]);
17207 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
17209 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
17211 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
17212 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
17214 if(totalRows != 6){
17215 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
17216 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
17219 this.fireEvent('monthchange', this, date);
17223 if(!this.internalRender){
17224 var main = this.el.dom.firstChild;
17225 var w = main.offsetWidth;
17226 this.el.setWidth(w + this.el.getBorderWidth("lr"));
17227 Roo.fly(main).setWidth(w);
17228 this.internalRender = true;
17229 // opera does not respect the auto grow header center column
17230 // then, after it gets a width opera refuses to recalculate
17231 // without a second pass
17232 if(Roo.isOpera && !this.secondPass){
17233 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
17234 this.secondPass = true;
17235 this.update.defer(10, this, [date]);
17242 findCell : function(dt) {
17243 dt = dt.clearTime().getTime();
17245 this.cells.each(function(c){
17246 //Roo.log("check " +c.dateValue + '?=' + dt);
17247 if(c.dateValue == dt){
17257 findCells : function(ev) {
17258 var s = ev.start.clone().clearTime().getTime();
17260 var e= ev.end.clone().clearTime().getTime();
17263 this.cells.each(function(c){
17264 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
17266 if(c.dateValue > e){
17269 if(c.dateValue < s){
17278 // findBestRow: function(cells)
17282 // for (var i =0 ; i < cells.length;i++) {
17283 // ret = Math.max(cells[i].rows || 0,ret);
17290 addItem : function(ev)
17292 // look for vertical location slot in
17293 var cells = this.findCells(ev);
17295 // ev.row = this.findBestRow(cells);
17297 // work out the location.
17301 for(var i =0; i < cells.length; i++) {
17303 cells[i].row = cells[0].row;
17306 cells[i].row = cells[i].row + 1;
17316 if (crow.start.getY() == cells[i].getY()) {
17318 crow.end = cells[i];
17335 cells[0].events.push(ev);
17337 this.calevents.push(ev);
17340 clearEvents: function() {
17342 if(!this.calevents){
17346 Roo.each(this.cells.elements, function(c){
17352 Roo.each(this.calevents, function(e) {
17353 Roo.each(e.els, function(el) {
17354 el.un('mouseenter' ,this.onEventEnter, this);
17355 el.un('mouseleave' ,this.onEventLeave, this);
17360 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
17366 renderEvents: function()
17370 this.cells.each(function(c) {
17379 if(c.row != c.events.length){
17380 r = 4 - (4 - (c.row - c.events.length));
17383 c.events = ev.slice(0, r);
17384 c.more = ev.slice(r);
17386 if(c.more.length && c.more.length == 1){
17387 c.events.push(c.more.pop());
17390 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
17394 this.cells.each(function(c) {
17396 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
17399 for (var e = 0; e < c.events.length; e++){
17400 var ev = c.events[e];
17401 var rows = ev.rows;
17403 for(var i = 0; i < rows.length; i++) {
17405 // how many rows should it span..
17408 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
17409 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
17411 unselectable : "on",
17414 cls: 'fc-event-inner',
17418 // cls: 'fc-event-time',
17419 // html : cells.length > 1 ? '' : ev.time
17423 cls: 'fc-event-title',
17424 html : String.format('{0}', ev.title)
17431 cls: 'ui-resizable-handle ui-resizable-e',
17432 html : '  '
17439 cfg.cls += ' fc-event-start';
17441 if ((i+1) == rows.length) {
17442 cfg.cls += ' fc-event-end';
17445 var ctr = _this.el.select('.fc-event-container',true).first();
17446 var cg = ctr.createChild(cfg);
17448 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
17449 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
17451 var r = (c.more.length) ? 1 : 0;
17452 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
17453 cg.setWidth(ebox.right - sbox.x -2);
17455 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
17456 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
17457 cg.on('click', _this.onEventClick, _this, ev);
17468 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
17469 style : 'position: absolute',
17470 unselectable : "on",
17473 cls: 'fc-event-inner',
17477 cls: 'fc-event-title',
17485 cls: 'ui-resizable-handle ui-resizable-e',
17486 html : '  '
17492 var ctr = _this.el.select('.fc-event-container',true).first();
17493 var cg = ctr.createChild(cfg);
17495 var sbox = c.select('.fc-day-content',true).first().getBox();
17496 var ebox = c.select('.fc-day-content',true).first().getBox();
17498 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
17499 cg.setWidth(ebox.right - sbox.x -2);
17501 cg.on('click', _this.onMoreEventClick, _this, c.more);
17511 onEventEnter: function (e, el,event,d) {
17512 this.fireEvent('evententer', this, el, event);
17515 onEventLeave: function (e, el,event,d) {
17516 this.fireEvent('eventleave', this, el, event);
17519 onEventClick: function (e, el,event,d) {
17520 this.fireEvent('eventclick', this, el, event);
17523 onMonthChange: function () {
17527 onMoreEventClick: function(e, el, more)
17531 this.calpopover.placement = 'right';
17532 this.calpopover.setTitle('More');
17534 this.calpopover.setContent('');
17536 var ctr = this.calpopover.el.select('.popover-content', true).first();
17538 Roo.each(more, function(m){
17540 cls : 'fc-event-hori fc-event-draggable',
17543 var cg = ctr.createChild(cfg);
17545 cg.on('click', _this.onEventClick, _this, m);
17548 this.calpopover.show(el);
17553 onLoad: function ()
17555 this.calevents = [];
17558 if(this.store.getCount() > 0){
17559 this.store.data.each(function(d){
17562 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
17563 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
17564 time : d.data.start_time,
17565 title : d.data.title,
17566 description : d.data.description,
17567 venue : d.data.venue
17572 this.renderEvents();
17574 if(this.calevents.length && this.loadMask){
17575 this.maskEl.hide();
17579 onBeforeLoad: function()
17581 this.clearEvents();
17583 this.maskEl.show();
17597 * @class Roo.bootstrap.Popover
17598 * @extends Roo.bootstrap.Component
17599 * Bootstrap Popover class
17600 * @cfg {String} html contents of the popover (or false to use children..)
17601 * @cfg {String} title of popover (or false to hide)
17602 * @cfg {String} placement how it is placed
17603 * @cfg {String} trigger click || hover (or false to trigger manually)
17604 * @cfg {String} over what (parent or false to trigger manually.)
17605 * @cfg {Number} delay - delay before showing
17608 * Create a new Popover
17609 * @param {Object} config The config object
17612 Roo.bootstrap.Popover = function(config){
17613 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
17619 * After the popover show
17621 * @param {Roo.bootstrap.Popover} this
17626 * After the popover hide
17628 * @param {Roo.bootstrap.Popover} this
17634 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
17636 title: 'Fill in a title',
17639 placement : 'right',
17640 trigger : 'hover', // hover
17646 can_build_overlaid : false,
17648 getChildContainer : function()
17650 return this.el.select('.popover-content',true).first();
17653 getAutoCreate : function(){
17656 cls : 'popover roo-dynamic',
17657 style: 'display:block',
17663 cls : 'popover-inner',
17667 cls: 'popover-title popover-header',
17671 cls : 'popover-content popover-body',
17682 setTitle: function(str)
17685 this.el.select('.popover-title',true).first().dom.innerHTML = str;
17687 setContent: function(str)
17690 this.el.select('.popover-content',true).first().dom.innerHTML = str;
17692 // as it get's added to the bottom of the page.
17693 onRender : function(ct, position)
17695 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17697 var cfg = Roo.apply({}, this.getAutoCreate());
17701 cfg.cls += ' ' + this.cls;
17704 cfg.style = this.style;
17706 //Roo.log("adding to ");
17707 this.el = Roo.get(document.body).createChild(cfg, position);
17708 // Roo.log(this.el);
17713 initEvents : function()
17715 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
17716 this.el.enableDisplayMode('block');
17718 if (this.over === false) {
17721 if (this.triggers === false) {
17724 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17725 var triggers = this.trigger ? this.trigger.split(' ') : [];
17726 Roo.each(triggers, function(trigger) {
17728 if (trigger == 'click') {
17729 on_el.on('click', this.toggle, this);
17730 } else if (trigger != 'manual') {
17731 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
17732 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
17734 on_el.on(eventIn ,this.enter, this);
17735 on_el.on(eventOut, this.leave, this);
17746 toggle : function () {
17747 this.hoverState == 'in' ? this.leave() : this.enter();
17750 enter : function () {
17752 clearTimeout(this.timeout);
17754 this.hoverState = 'in';
17756 if (!this.delay || !this.delay.show) {
17761 this.timeout = setTimeout(function () {
17762 if (_t.hoverState == 'in') {
17765 }, this.delay.show)
17768 leave : function() {
17769 clearTimeout(this.timeout);
17771 this.hoverState = 'out';
17773 if (!this.delay || !this.delay.hide) {
17778 this.timeout = setTimeout(function () {
17779 if (_t.hoverState == 'out') {
17782 }, this.delay.hide)
17785 show : function (on_el)
17788 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17792 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
17793 if (this.html !== false) {
17794 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
17796 this.el.removeClass([
17797 'fade','top','bottom', 'left', 'right','in',
17798 'bs-popover-top','bs-popover-bottom', 'bs-popover-left', 'bs-popover-right'
17800 if (!this.title.length) {
17801 this.el.select('.popover-title',true).hide();
17804 var placement = typeof this.placement == 'function' ?
17805 this.placement.call(this, this.el, on_el) :
17808 var autoToken = /\s?auto?\s?/i;
17809 var autoPlace = autoToken.test(placement);
17811 placement = placement.replace(autoToken, '') || 'top';
17815 //this.el.setXY([0,0]);
17817 this.el.dom.style.display='block';
17818 this.el.addClass(placement);
17820 //this.el.appendTo(on_el);
17822 var p = this.getPosition();
17823 var box = this.el.getBox();
17828 var align = Roo.bootstrap.Popover.alignment[placement];
17831 this.el.alignTo(on_el, align[0],align[1]);
17832 //var arrow = this.el.select('.arrow',true).first();
17833 //arrow.set(align[2],
17835 this.el.addClass('in');
17838 if (this.el.hasClass('fade')) {
17842 this.hoverState = 'in';
17844 this.fireEvent('show', this);
17849 this.el.setXY([0,0]);
17850 this.el.removeClass('in');
17852 this.hoverState = null;
17854 this.fireEvent('hide', this);
17859 Roo.bootstrap.Popover.alignment = {
17860 'left' : ['r-l', [-10,0], 'right bs-popover-right'],
17861 'right' : ['l-r', [10,0], 'left bs-popover-left'],
17862 'bottom' : ['t-b', [0,10], 'top bs-popover-top'],
17863 'top' : [ 'b-t', [0,-10], 'bottom bs-popover-bottom']
17874 * @class Roo.bootstrap.Progress
17875 * @extends Roo.bootstrap.Component
17876 * Bootstrap Progress class
17877 * @cfg {Boolean} striped striped of the progress bar
17878 * @cfg {Boolean} active animated of the progress bar
17882 * Create a new Progress
17883 * @param {Object} config The config object
17886 Roo.bootstrap.Progress = function(config){
17887 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
17890 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
17895 getAutoCreate : function(){
17903 cfg.cls += ' progress-striped';
17907 cfg.cls += ' active';
17926 * @class Roo.bootstrap.ProgressBar
17927 * @extends Roo.bootstrap.Component
17928 * Bootstrap ProgressBar class
17929 * @cfg {Number} aria_valuenow aria-value now
17930 * @cfg {Number} aria_valuemin aria-value min
17931 * @cfg {Number} aria_valuemax aria-value max
17932 * @cfg {String} label label for the progress bar
17933 * @cfg {String} panel (success | info | warning | danger )
17934 * @cfg {String} role role of the progress bar
17935 * @cfg {String} sr_only text
17939 * Create a new ProgressBar
17940 * @param {Object} config The config object
17943 Roo.bootstrap.ProgressBar = function(config){
17944 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
17947 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
17951 aria_valuemax : 100,
17957 getAutoCreate : function()
17962 cls: 'progress-bar',
17963 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
17975 cfg.role = this.role;
17978 if(this.aria_valuenow){
17979 cfg['aria-valuenow'] = this.aria_valuenow;
17982 if(this.aria_valuemin){
17983 cfg['aria-valuemin'] = this.aria_valuemin;
17986 if(this.aria_valuemax){
17987 cfg['aria-valuemax'] = this.aria_valuemax;
17990 if(this.label && !this.sr_only){
17991 cfg.html = this.label;
17995 cfg.cls += ' progress-bar-' + this.panel;
18001 update : function(aria_valuenow)
18003 this.aria_valuenow = aria_valuenow;
18005 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
18020 * @class Roo.bootstrap.TabGroup
18021 * @extends Roo.bootstrap.Column
18022 * Bootstrap Column class
18023 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
18024 * @cfg {Boolean} carousel true to make the group behave like a carousel
18025 * @cfg {Boolean} bullets show bullets for the panels
18026 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
18027 * @cfg {Number} timer auto slide timer .. default 0 millisecond
18028 * @cfg {Boolean} showarrow (true|false) show arrow default true
18031 * Create a new TabGroup
18032 * @param {Object} config The config object
18035 Roo.bootstrap.TabGroup = function(config){
18036 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
18038 this.navId = Roo.id();
18041 Roo.bootstrap.TabGroup.register(this);
18045 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
18048 transition : false,
18053 slideOnTouch : false,
18056 getAutoCreate : function()
18058 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
18060 cfg.cls += ' tab-content';
18062 if (this.carousel) {
18063 cfg.cls += ' carousel slide';
18066 cls : 'carousel-inner',
18070 if(this.bullets && !Roo.isTouch){
18073 cls : 'carousel-bullets',
18077 if(this.bullets_cls){
18078 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
18085 cfg.cn[0].cn.push(bullets);
18088 if(this.showarrow){
18089 cfg.cn[0].cn.push({
18091 class : 'carousel-arrow',
18095 class : 'carousel-prev',
18099 class : 'fa fa-chevron-left'
18105 class : 'carousel-next',
18109 class : 'fa fa-chevron-right'
18122 initEvents: function()
18124 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
18125 // this.el.on("touchstart", this.onTouchStart, this);
18128 if(this.autoslide){
18131 this.slideFn = window.setInterval(function() {
18132 _this.showPanelNext();
18136 if(this.showarrow){
18137 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
18138 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
18144 // onTouchStart : function(e, el, o)
18146 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
18150 // this.showPanelNext();
18154 getChildContainer : function()
18156 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
18160 * register a Navigation item
18161 * @param {Roo.bootstrap.NavItem} the navitem to add
18163 register : function(item)
18165 this.tabs.push( item);
18166 item.navId = this.navId; // not really needed..
18171 getActivePanel : function()
18174 Roo.each(this.tabs, function(t) {
18184 getPanelByName : function(n)
18187 Roo.each(this.tabs, function(t) {
18188 if (t.tabId == n) {
18196 indexOfPanel : function(p)
18199 Roo.each(this.tabs, function(t,i) {
18200 if (t.tabId == p.tabId) {
18209 * show a specific panel
18210 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
18211 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
18213 showPanel : function (pan)
18215 if(this.transition || typeof(pan) == 'undefined'){
18216 Roo.log("waiting for the transitionend");
18220 if (typeof(pan) == 'number') {
18221 pan = this.tabs[pan];
18224 if (typeof(pan) == 'string') {
18225 pan = this.getPanelByName(pan);
18228 var cur = this.getActivePanel();
18231 Roo.log('pan or acitve pan is undefined');
18235 if (pan.tabId == this.getActivePanel().tabId) {
18239 if (false === cur.fireEvent('beforedeactivate')) {
18243 if(this.bullets > 0 && !Roo.isTouch){
18244 this.setActiveBullet(this.indexOfPanel(pan));
18247 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
18249 this.transition = true;
18250 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
18251 var lr = dir == 'next' ? 'left' : 'right';
18252 pan.el.addClass(dir); // or prev
18253 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
18254 cur.el.addClass(lr); // or right
18255 pan.el.addClass(lr);
18258 cur.el.on('transitionend', function() {
18259 Roo.log("trans end?");
18261 pan.el.removeClass([lr,dir]);
18262 pan.setActive(true);
18264 cur.el.removeClass([lr]);
18265 cur.setActive(false);
18267 _this.transition = false;
18269 }, this, { single: true } );
18274 cur.setActive(false);
18275 pan.setActive(true);
18280 showPanelNext : function()
18282 var i = this.indexOfPanel(this.getActivePanel());
18284 if (i >= this.tabs.length - 1 && !this.autoslide) {
18288 if (i >= this.tabs.length - 1 && this.autoslide) {
18292 this.showPanel(this.tabs[i+1]);
18295 showPanelPrev : function()
18297 var i = this.indexOfPanel(this.getActivePanel());
18299 if (i < 1 && !this.autoslide) {
18303 if (i < 1 && this.autoslide) {
18304 i = this.tabs.length;
18307 this.showPanel(this.tabs[i-1]);
18311 addBullet: function()
18313 if(!this.bullets || Roo.isTouch){
18316 var ctr = this.el.select('.carousel-bullets',true).first();
18317 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
18318 var bullet = ctr.createChild({
18319 cls : 'bullet bullet-' + i
18320 },ctr.dom.lastChild);
18325 bullet.on('click', (function(e, el, o, ii, t){
18327 e.preventDefault();
18329 this.showPanel(ii);
18331 if(this.autoslide && this.slideFn){
18332 clearInterval(this.slideFn);
18333 this.slideFn = window.setInterval(function() {
18334 _this.showPanelNext();
18338 }).createDelegate(this, [i, bullet], true));
18343 setActiveBullet : function(i)
18349 Roo.each(this.el.select('.bullet', true).elements, function(el){
18350 el.removeClass('selected');
18353 var bullet = this.el.select('.bullet-' + i, true).first();
18359 bullet.addClass('selected');
18370 Roo.apply(Roo.bootstrap.TabGroup, {
18374 * register a Navigation Group
18375 * @param {Roo.bootstrap.NavGroup} the navgroup to add
18377 register : function(navgrp)
18379 this.groups[navgrp.navId] = navgrp;
18383 * fetch a Navigation Group based on the navigation ID
18384 * if one does not exist , it will get created.
18385 * @param {string} the navgroup to add
18386 * @returns {Roo.bootstrap.NavGroup} the navgroup
18388 get: function(navId) {
18389 if (typeof(this.groups[navId]) == 'undefined') {
18390 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
18392 return this.groups[navId] ;
18407 * @class Roo.bootstrap.TabPanel
18408 * @extends Roo.bootstrap.Component
18409 * Bootstrap TabPanel class
18410 * @cfg {Boolean} active panel active
18411 * @cfg {String} html panel content
18412 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
18413 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
18414 * @cfg {String} href click to link..
18418 * Create a new TabPanel
18419 * @param {Object} config The config object
18422 Roo.bootstrap.TabPanel = function(config){
18423 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
18427 * Fires when the active status changes
18428 * @param {Roo.bootstrap.TabPanel} this
18429 * @param {Boolean} state the new state
18434 * @event beforedeactivate
18435 * Fires before a tab is de-activated - can be used to do validation on a form.
18436 * @param {Roo.bootstrap.TabPanel} this
18437 * @return {Boolean} false if there is an error
18440 'beforedeactivate': true
18443 this.tabId = this.tabId || Roo.id();
18447 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
18455 getAutoCreate : function(){
18458 // item is needed for carousel - not sure if it has any effect otherwise
18459 cls: 'tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
18460 html: this.html || ''
18464 cfg.cls += ' active';
18468 cfg.tabId = this.tabId;
18475 initEvents: function()
18477 var p = this.parent();
18479 this.navId = this.navId || p.navId;
18481 if (typeof(this.navId) != 'undefined') {
18482 // not really needed.. but just in case.. parent should be a NavGroup.
18483 var tg = Roo.bootstrap.TabGroup.get(this.navId);
18487 var i = tg.tabs.length - 1;
18489 if(this.active && tg.bullets > 0 && i < tg.bullets){
18490 tg.setActiveBullet(i);
18494 this.el.on('click', this.onClick, this);
18497 this.el.on("touchstart", this.onTouchStart, this);
18498 this.el.on("touchmove", this.onTouchMove, this);
18499 this.el.on("touchend", this.onTouchEnd, this);
18504 onRender : function(ct, position)
18506 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
18509 setActive : function(state)
18511 Roo.log("panel - set active " + this.tabId + "=" + state);
18513 this.active = state;
18515 this.el.removeClass('active');
18517 } else if (!this.el.hasClass('active')) {
18518 this.el.addClass('active');
18521 this.fireEvent('changed', this, state);
18524 onClick : function(e)
18526 e.preventDefault();
18528 if(!this.href.length){
18532 window.location.href = this.href;
18541 onTouchStart : function(e)
18543 this.swiping = false;
18545 this.startX = e.browserEvent.touches[0].clientX;
18546 this.startY = e.browserEvent.touches[0].clientY;
18549 onTouchMove : function(e)
18551 this.swiping = true;
18553 this.endX = e.browserEvent.touches[0].clientX;
18554 this.endY = e.browserEvent.touches[0].clientY;
18557 onTouchEnd : function(e)
18564 var tabGroup = this.parent();
18566 if(this.endX > this.startX){ // swiping right
18567 tabGroup.showPanelPrev();
18571 if(this.startX > this.endX){ // swiping left
18572 tabGroup.showPanelNext();
18591 * @class Roo.bootstrap.DateField
18592 * @extends Roo.bootstrap.Input
18593 * Bootstrap DateField class
18594 * @cfg {Number} weekStart default 0
18595 * @cfg {String} viewMode default empty, (months|years)
18596 * @cfg {String} minViewMode default empty, (months|years)
18597 * @cfg {Number} startDate default -Infinity
18598 * @cfg {Number} endDate default Infinity
18599 * @cfg {Boolean} todayHighlight default false
18600 * @cfg {Boolean} todayBtn default false
18601 * @cfg {Boolean} calendarWeeks default false
18602 * @cfg {Object} daysOfWeekDisabled default empty
18603 * @cfg {Boolean} singleMode default false (true | false)
18605 * @cfg {Boolean} keyboardNavigation default true
18606 * @cfg {String} language default en
18609 * Create a new DateField
18610 * @param {Object} config The config object
18613 Roo.bootstrap.DateField = function(config){
18614 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
18618 * Fires when this field show.
18619 * @param {Roo.bootstrap.DateField} this
18620 * @param {Mixed} date The date value
18625 * Fires when this field hide.
18626 * @param {Roo.bootstrap.DateField} this
18627 * @param {Mixed} date The date value
18632 * Fires when select a date.
18633 * @param {Roo.bootstrap.DateField} this
18634 * @param {Mixed} date The date value
18638 * @event beforeselect
18639 * Fires when before select a date.
18640 * @param {Roo.bootstrap.DateField} this
18641 * @param {Mixed} date The date value
18643 beforeselect : true
18647 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
18650 * @cfg {String} format
18651 * The default date format string which can be overriden for localization support. The format must be
18652 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
18656 * @cfg {String} altFormats
18657 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
18658 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
18660 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
18668 todayHighlight : false,
18674 keyboardNavigation: true,
18676 calendarWeeks: false,
18678 startDate: -Infinity,
18682 daysOfWeekDisabled: [],
18686 singleMode : false,
18688 UTCDate: function()
18690 return new Date(Date.UTC.apply(Date, arguments));
18693 UTCToday: function()
18695 var today = new Date();
18696 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
18699 getDate: function() {
18700 var d = this.getUTCDate();
18701 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
18704 getUTCDate: function() {
18708 setDate: function(d) {
18709 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
18712 setUTCDate: function(d) {
18714 this.setValue(this.formatDate(this.date));
18717 onRender: function(ct, position)
18720 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
18722 this.language = this.language || 'en';
18723 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
18724 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
18726 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
18727 this.format = this.format || 'm/d/y';
18728 this.isInline = false;
18729 this.isInput = true;
18730 this.component = this.el.select('.add-on', true).first() || false;
18731 this.component = (this.component && this.component.length === 0) ? false : this.component;
18732 this.hasInput = this.component && this.inputEl().length;
18734 if (typeof(this.minViewMode === 'string')) {
18735 switch (this.minViewMode) {
18737 this.minViewMode = 1;
18740 this.minViewMode = 2;
18743 this.minViewMode = 0;
18748 if (typeof(this.viewMode === 'string')) {
18749 switch (this.viewMode) {
18762 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
18764 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
18766 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18768 this.picker().on('mousedown', this.onMousedown, this);
18769 this.picker().on('click', this.onClick, this);
18771 this.picker().addClass('datepicker-dropdown');
18773 this.startViewMode = this.viewMode;
18775 if(this.singleMode){
18776 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
18777 v.setVisibilityMode(Roo.Element.DISPLAY);
18781 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
18782 v.setStyle('width', '189px');
18786 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
18787 if(!this.calendarWeeks){
18792 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18793 v.attr('colspan', function(i, val){
18794 return parseInt(val) + 1;
18799 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
18801 this.setStartDate(this.startDate);
18802 this.setEndDate(this.endDate);
18804 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
18811 if(this.isInline) {
18816 picker : function()
18818 return this.pickerEl;
18819 // return this.el.select('.datepicker', true).first();
18822 fillDow: function()
18824 var dowCnt = this.weekStart;
18833 if(this.calendarWeeks){
18841 while (dowCnt < this.weekStart + 7) {
18845 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
18849 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
18852 fillMonths: function()
18855 var months = this.picker().select('>.datepicker-months td', true).first();
18857 months.dom.innerHTML = '';
18863 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
18866 months.createChild(month);
18873 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;
18875 if (this.date < this.startDate) {
18876 this.viewDate = new Date(this.startDate);
18877 } else if (this.date > this.endDate) {
18878 this.viewDate = new Date(this.endDate);
18880 this.viewDate = new Date(this.date);
18888 var d = new Date(this.viewDate),
18889 year = d.getUTCFullYear(),
18890 month = d.getUTCMonth(),
18891 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
18892 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
18893 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
18894 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
18895 currentDate = this.date && this.date.valueOf(),
18896 today = this.UTCToday();
18898 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
18900 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18902 // this.picker.select('>tfoot th.today').
18903 // .text(dates[this.language].today)
18904 // .toggle(this.todayBtn !== false);
18906 this.updateNavArrows();
18909 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
18911 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
18913 prevMonth.setUTCDate(day);
18915 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
18917 var nextMonth = new Date(prevMonth);
18919 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
18921 nextMonth = nextMonth.valueOf();
18923 var fillMonths = false;
18925 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
18927 while(prevMonth.valueOf() <= nextMonth) {
18930 if (prevMonth.getUTCDay() === this.weekStart) {
18932 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
18940 if(this.calendarWeeks){
18941 // ISO 8601: First week contains first thursday.
18942 // ISO also states week starts on Monday, but we can be more abstract here.
18944 // Start of current week: based on weekstart/current date
18945 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
18946 // Thursday of this week
18947 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
18948 // First Thursday of year, year from thursday
18949 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
18950 // Calendar week: ms between thursdays, div ms per day, div 7 days
18951 calWeek = (th - yth) / 864e5 / 7 + 1;
18953 fillMonths.cn.push({
18961 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
18963 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
18966 if (this.todayHighlight &&
18967 prevMonth.getUTCFullYear() == today.getFullYear() &&
18968 prevMonth.getUTCMonth() == today.getMonth() &&
18969 prevMonth.getUTCDate() == today.getDate()) {
18970 clsName += ' today';
18973 if (currentDate && prevMonth.valueOf() === currentDate) {
18974 clsName += ' active';
18977 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
18978 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
18979 clsName += ' disabled';
18982 fillMonths.cn.push({
18984 cls: 'day ' + clsName,
18985 html: prevMonth.getDate()
18988 prevMonth.setDate(prevMonth.getDate()+1);
18991 var currentYear = this.date && this.date.getUTCFullYear();
18992 var currentMonth = this.date && this.date.getUTCMonth();
18994 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
18996 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
18997 v.removeClass('active');
18999 if(currentYear === year && k === currentMonth){
19000 v.addClass('active');
19003 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
19004 v.addClass('disabled');
19010 year = parseInt(year/10, 10) * 10;
19012 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
19014 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
19017 for (var i = -1; i < 11; i++) {
19018 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
19020 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
19028 showMode: function(dir)
19031 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
19034 Roo.each(this.picker().select('>div',true).elements, function(v){
19035 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19038 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
19043 if(this.isInline) {
19047 this.picker().removeClass(['bottom', 'top']);
19049 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
19051 * place to the top of element!
19055 this.picker().addClass('top');
19056 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
19061 this.picker().addClass('bottom');
19063 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
19066 parseDate : function(value)
19068 if(!value || value instanceof Date){
19071 var v = Date.parseDate(value, this.format);
19072 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
19073 v = Date.parseDate(value, 'Y-m-d');
19075 if(!v && this.altFormats){
19076 if(!this.altFormatsArray){
19077 this.altFormatsArray = this.altFormats.split("|");
19079 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
19080 v = Date.parseDate(value, this.altFormatsArray[i]);
19086 formatDate : function(date, fmt)
19088 return (!date || !(date instanceof Date)) ?
19089 date : date.dateFormat(fmt || this.format);
19092 onFocus : function()
19094 Roo.bootstrap.DateField.superclass.onFocus.call(this);
19098 onBlur : function()
19100 Roo.bootstrap.DateField.superclass.onBlur.call(this);
19102 var d = this.inputEl().getValue();
19109 showPopup : function()
19111 this.picker().show();
19115 this.fireEvent('showpopup', this, this.date);
19118 hidePopup : function()
19120 if(this.isInline) {
19123 this.picker().hide();
19124 this.viewMode = this.startViewMode;
19127 this.fireEvent('hidepopup', this, this.date);
19131 onMousedown: function(e)
19133 e.stopPropagation();
19134 e.preventDefault();
19139 Roo.bootstrap.DateField.superclass.keyup.call(this);
19143 setValue: function(v)
19145 if(this.fireEvent('beforeselect', this, v) !== false){
19146 var d = new Date(this.parseDate(v) ).clearTime();
19148 if(isNaN(d.getTime())){
19149 this.date = this.viewDate = '';
19150 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
19154 v = this.formatDate(d);
19156 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
19158 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
19162 this.fireEvent('select', this, this.date);
19166 getValue: function()
19168 return this.formatDate(this.date);
19171 fireKey: function(e)
19173 if (!this.picker().isVisible()){
19174 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19180 var dateChanged = false,
19182 newDate, newViewDate;
19187 e.preventDefault();
19191 if (!this.keyboardNavigation) {
19194 dir = e.keyCode == 37 ? -1 : 1;
19197 newDate = this.moveYear(this.date, dir);
19198 newViewDate = this.moveYear(this.viewDate, dir);
19199 } else if (e.shiftKey){
19200 newDate = this.moveMonth(this.date, dir);
19201 newViewDate = this.moveMonth(this.viewDate, dir);
19203 newDate = new Date(this.date);
19204 newDate.setUTCDate(this.date.getUTCDate() + dir);
19205 newViewDate = new Date(this.viewDate);
19206 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
19208 if (this.dateWithinRange(newDate)){
19209 this.date = newDate;
19210 this.viewDate = newViewDate;
19211 this.setValue(this.formatDate(this.date));
19213 e.preventDefault();
19214 dateChanged = true;
19219 if (!this.keyboardNavigation) {
19222 dir = e.keyCode == 38 ? -1 : 1;
19224 newDate = this.moveYear(this.date, dir);
19225 newViewDate = this.moveYear(this.viewDate, dir);
19226 } else if (e.shiftKey){
19227 newDate = this.moveMonth(this.date, dir);
19228 newViewDate = this.moveMonth(this.viewDate, dir);
19230 newDate = new Date(this.date);
19231 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
19232 newViewDate = new Date(this.viewDate);
19233 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
19235 if (this.dateWithinRange(newDate)){
19236 this.date = newDate;
19237 this.viewDate = newViewDate;
19238 this.setValue(this.formatDate(this.date));
19240 e.preventDefault();
19241 dateChanged = true;
19245 this.setValue(this.formatDate(this.date));
19247 e.preventDefault();
19250 this.setValue(this.formatDate(this.date));
19264 onClick: function(e)
19266 e.stopPropagation();
19267 e.preventDefault();
19269 var target = e.getTarget();
19271 if(target.nodeName.toLowerCase() === 'i'){
19272 target = Roo.get(target).dom.parentNode;
19275 var nodeName = target.nodeName;
19276 var className = target.className;
19277 var html = target.innerHTML;
19278 //Roo.log(nodeName);
19280 switch(nodeName.toLowerCase()) {
19282 switch(className) {
19288 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
19289 switch(this.viewMode){
19291 this.viewDate = this.moveMonth(this.viewDate, dir);
19295 this.viewDate = this.moveYear(this.viewDate, dir);
19301 var date = new Date();
19302 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
19304 this.setValue(this.formatDate(this.date));
19311 if (className.indexOf('disabled') < 0) {
19312 this.viewDate.setUTCDate(1);
19313 if (className.indexOf('month') > -1) {
19314 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
19316 var year = parseInt(html, 10) || 0;
19317 this.viewDate.setUTCFullYear(year);
19321 if(this.singleMode){
19322 this.setValue(this.formatDate(this.viewDate));
19333 //Roo.log(className);
19334 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
19335 var day = parseInt(html, 10) || 1;
19336 var year = this.viewDate.getUTCFullYear(),
19337 month = this.viewDate.getUTCMonth();
19339 if (className.indexOf('old') > -1) {
19346 } else if (className.indexOf('new') > -1) {
19354 //Roo.log([year,month,day]);
19355 this.date = this.UTCDate(year, month, day,0,0,0,0);
19356 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
19358 //Roo.log(this.formatDate(this.date));
19359 this.setValue(this.formatDate(this.date));
19366 setStartDate: function(startDate)
19368 this.startDate = startDate || -Infinity;
19369 if (this.startDate !== -Infinity) {
19370 this.startDate = this.parseDate(this.startDate);
19373 this.updateNavArrows();
19376 setEndDate: function(endDate)
19378 this.endDate = endDate || Infinity;
19379 if (this.endDate !== Infinity) {
19380 this.endDate = this.parseDate(this.endDate);
19383 this.updateNavArrows();
19386 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
19388 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
19389 if (typeof(this.daysOfWeekDisabled) !== 'object') {
19390 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
19392 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
19393 return parseInt(d, 10);
19396 this.updateNavArrows();
19399 updateNavArrows: function()
19401 if(this.singleMode){
19405 var d = new Date(this.viewDate),
19406 year = d.getUTCFullYear(),
19407 month = d.getUTCMonth();
19409 Roo.each(this.picker().select('.prev', true).elements, function(v){
19411 switch (this.viewMode) {
19414 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
19420 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
19427 Roo.each(this.picker().select('.next', true).elements, function(v){
19429 switch (this.viewMode) {
19432 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
19438 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
19446 moveMonth: function(date, dir)
19451 var new_date = new Date(date.valueOf()),
19452 day = new_date.getUTCDate(),
19453 month = new_date.getUTCMonth(),
19454 mag = Math.abs(dir),
19456 dir = dir > 0 ? 1 : -1;
19459 // If going back one month, make sure month is not current month
19460 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
19462 return new_date.getUTCMonth() == month;
19464 // If going forward one month, make sure month is as expected
19465 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
19467 return new_date.getUTCMonth() != new_month;
19469 new_month = month + dir;
19470 new_date.setUTCMonth(new_month);
19471 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
19472 if (new_month < 0 || new_month > 11) {
19473 new_month = (new_month + 12) % 12;
19476 // For magnitudes >1, move one month at a time...
19477 for (var i=0; i<mag; i++) {
19478 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
19479 new_date = this.moveMonth(new_date, dir);
19481 // ...then reset the day, keeping it in the new month
19482 new_month = new_date.getUTCMonth();
19483 new_date.setUTCDate(day);
19485 return new_month != new_date.getUTCMonth();
19488 // Common date-resetting loop -- if date is beyond end of month, make it
19491 new_date.setUTCDate(--day);
19492 new_date.setUTCMonth(new_month);
19497 moveYear: function(date, dir)
19499 return this.moveMonth(date, dir*12);
19502 dateWithinRange: function(date)
19504 return date >= this.startDate && date <= this.endDate;
19510 this.picker().remove();
19513 validateValue : function(value)
19515 if(this.getVisibilityEl().hasClass('hidden')){
19519 if(value.length < 1) {
19520 if(this.allowBlank){
19526 if(value.length < this.minLength){
19529 if(value.length > this.maxLength){
19533 var vt = Roo.form.VTypes;
19534 if(!vt[this.vtype](value, this)){
19538 if(typeof this.validator == "function"){
19539 var msg = this.validator(value);
19545 if(this.regex && !this.regex.test(value)){
19549 if(typeof(this.parseDate(value)) == 'undefined'){
19553 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
19557 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
19567 this.date = this.viewDate = '';
19569 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
19574 Roo.apply(Roo.bootstrap.DateField, {
19585 html: '<i class="fa fa-arrow-left"/>'
19595 html: '<i class="fa fa-arrow-right"/>'
19637 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
19638 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
19639 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
19640 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19641 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
19654 navFnc: 'FullYear',
19659 navFnc: 'FullYear',
19664 Roo.apply(Roo.bootstrap.DateField, {
19668 cls: 'datepicker dropdown-menu roo-dynamic',
19672 cls: 'datepicker-days',
19676 cls: 'table-condensed',
19678 Roo.bootstrap.DateField.head,
19682 Roo.bootstrap.DateField.footer
19689 cls: 'datepicker-months',
19693 cls: 'table-condensed',
19695 Roo.bootstrap.DateField.head,
19696 Roo.bootstrap.DateField.content,
19697 Roo.bootstrap.DateField.footer
19704 cls: 'datepicker-years',
19708 cls: 'table-condensed',
19710 Roo.bootstrap.DateField.head,
19711 Roo.bootstrap.DateField.content,
19712 Roo.bootstrap.DateField.footer
19731 * @class Roo.bootstrap.TimeField
19732 * @extends Roo.bootstrap.Input
19733 * Bootstrap DateField class
19737 * Create a new TimeField
19738 * @param {Object} config The config object
19741 Roo.bootstrap.TimeField = function(config){
19742 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
19746 * Fires when this field show.
19747 * @param {Roo.bootstrap.DateField} thisthis
19748 * @param {Mixed} date The date value
19753 * Fires when this field hide.
19754 * @param {Roo.bootstrap.DateField} this
19755 * @param {Mixed} date The date value
19760 * Fires when select a date.
19761 * @param {Roo.bootstrap.DateField} this
19762 * @param {Mixed} date The date value
19768 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
19771 * @cfg {String} format
19772 * The default time format string which can be overriden for localization support. The format must be
19773 * valid according to {@link Date#parseDate} (defaults to 'H:i').
19777 onRender: function(ct, position)
19780 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
19782 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
19784 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19786 this.pop = this.picker().select('>.datepicker-time',true).first();
19787 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19789 this.picker().on('mousedown', this.onMousedown, this);
19790 this.picker().on('click', this.onClick, this);
19792 this.picker().addClass('datepicker-dropdown');
19797 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
19798 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
19799 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
19800 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
19801 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
19802 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
19806 fireKey: function(e){
19807 if (!this.picker().isVisible()){
19808 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19814 e.preventDefault();
19822 this.onTogglePeriod();
19825 this.onIncrementMinutes();
19828 this.onDecrementMinutes();
19837 onClick: function(e) {
19838 e.stopPropagation();
19839 e.preventDefault();
19842 picker : function()
19844 return this.el.select('.datepicker', true).first();
19847 fillTime: function()
19849 var time = this.pop.select('tbody', true).first();
19851 time.dom.innerHTML = '';
19866 cls: 'hours-up glyphicon glyphicon-chevron-up'
19886 cls: 'minutes-up glyphicon glyphicon-chevron-up'
19907 cls: 'timepicker-hour',
19922 cls: 'timepicker-minute',
19937 cls: 'btn btn-primary period',
19959 cls: 'hours-down glyphicon glyphicon-chevron-down'
19979 cls: 'minutes-down glyphicon glyphicon-chevron-down'
19997 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
20004 var hours = this.time.getHours();
20005 var minutes = this.time.getMinutes();
20018 hours = hours - 12;
20022 hours = '0' + hours;
20026 minutes = '0' + minutes;
20029 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
20030 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
20031 this.pop.select('button', true).first().dom.innerHTML = period;
20037 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
20039 var cls = ['bottom'];
20041 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
20048 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
20053 this.picker().addClass(cls.join('-'));
20057 Roo.each(cls, function(c){
20059 _this.picker().setTop(_this.inputEl().getHeight());
20063 _this.picker().setTop(0 - _this.picker().getHeight());
20068 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
20072 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
20079 onFocus : function()
20081 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
20085 onBlur : function()
20087 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
20093 this.picker().show();
20098 this.fireEvent('show', this, this.date);
20103 this.picker().hide();
20106 this.fireEvent('hide', this, this.date);
20109 setTime : function()
20112 this.setValue(this.time.format(this.format));
20114 this.fireEvent('select', this, this.date);
20119 onMousedown: function(e){
20120 e.stopPropagation();
20121 e.preventDefault();
20124 onIncrementHours: function()
20126 Roo.log('onIncrementHours');
20127 this.time = this.time.add(Date.HOUR, 1);
20132 onDecrementHours: function()
20134 Roo.log('onDecrementHours');
20135 this.time = this.time.add(Date.HOUR, -1);
20139 onIncrementMinutes: function()
20141 Roo.log('onIncrementMinutes');
20142 this.time = this.time.add(Date.MINUTE, 1);
20146 onDecrementMinutes: function()
20148 Roo.log('onDecrementMinutes');
20149 this.time = this.time.add(Date.MINUTE, -1);
20153 onTogglePeriod: function()
20155 Roo.log('onTogglePeriod');
20156 this.time = this.time.add(Date.HOUR, 12);
20163 Roo.apply(Roo.bootstrap.TimeField, {
20193 cls: 'btn btn-info ok',
20205 Roo.apply(Roo.bootstrap.TimeField, {
20209 cls: 'datepicker dropdown-menu',
20213 cls: 'datepicker-time',
20217 cls: 'table-condensed',
20219 Roo.bootstrap.TimeField.content,
20220 Roo.bootstrap.TimeField.footer
20239 * @class Roo.bootstrap.MonthField
20240 * @extends Roo.bootstrap.Input
20241 * Bootstrap MonthField class
20243 * @cfg {String} language default en
20246 * Create a new MonthField
20247 * @param {Object} config The config object
20250 Roo.bootstrap.MonthField = function(config){
20251 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
20256 * Fires when this field show.
20257 * @param {Roo.bootstrap.MonthField} this
20258 * @param {Mixed} date The date value
20263 * Fires when this field hide.
20264 * @param {Roo.bootstrap.MonthField} this
20265 * @param {Mixed} date The date value
20270 * Fires when select a date.
20271 * @param {Roo.bootstrap.MonthField} this
20272 * @param {String} oldvalue The old value
20273 * @param {String} newvalue The new value
20279 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
20281 onRender: function(ct, position)
20284 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
20286 this.language = this.language || 'en';
20287 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
20288 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
20290 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
20291 this.isInline = false;
20292 this.isInput = true;
20293 this.component = this.el.select('.add-on', true).first() || false;
20294 this.component = (this.component && this.component.length === 0) ? false : this.component;
20295 this.hasInput = this.component && this.inputEL().length;
20297 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
20299 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
20301 this.picker().on('mousedown', this.onMousedown, this);
20302 this.picker().on('click', this.onClick, this);
20304 this.picker().addClass('datepicker-dropdown');
20306 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
20307 v.setStyle('width', '189px');
20314 if(this.isInline) {
20320 setValue: function(v, suppressEvent)
20322 var o = this.getValue();
20324 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
20328 if(suppressEvent !== true){
20329 this.fireEvent('select', this, o, v);
20334 getValue: function()
20339 onClick: function(e)
20341 e.stopPropagation();
20342 e.preventDefault();
20344 var target = e.getTarget();
20346 if(target.nodeName.toLowerCase() === 'i'){
20347 target = Roo.get(target).dom.parentNode;
20350 var nodeName = target.nodeName;
20351 var className = target.className;
20352 var html = target.innerHTML;
20354 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
20358 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
20360 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20366 picker : function()
20368 return this.pickerEl;
20371 fillMonths: function()
20374 var months = this.picker().select('>.datepicker-months td', true).first();
20376 months.dom.innerHTML = '';
20382 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
20385 months.createChild(month);
20394 if(typeof(this.vIndex) == 'undefined' && this.value.length){
20395 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
20398 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
20399 e.removeClass('active');
20401 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
20402 e.addClass('active');
20409 if(this.isInline) {
20413 this.picker().removeClass(['bottom', 'top']);
20415 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
20417 * place to the top of element!
20421 this.picker().addClass('top');
20422 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
20427 this.picker().addClass('bottom');
20429 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
20432 onFocus : function()
20434 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
20438 onBlur : function()
20440 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
20442 var d = this.inputEl().getValue();
20451 this.picker().show();
20452 this.picker().select('>.datepicker-months', true).first().show();
20456 this.fireEvent('show', this, this.date);
20461 if(this.isInline) {
20464 this.picker().hide();
20465 this.fireEvent('hide', this, this.date);
20469 onMousedown: function(e)
20471 e.stopPropagation();
20472 e.preventDefault();
20477 Roo.bootstrap.MonthField.superclass.keyup.call(this);
20481 fireKey: function(e)
20483 if (!this.picker().isVisible()){
20484 if (e.keyCode == 27) {// allow escape to hide and re-show picker
20495 e.preventDefault();
20499 dir = e.keyCode == 37 ? -1 : 1;
20501 this.vIndex = this.vIndex + dir;
20503 if(this.vIndex < 0){
20507 if(this.vIndex > 11){
20511 if(isNaN(this.vIndex)){
20515 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20521 dir = e.keyCode == 38 ? -1 : 1;
20523 this.vIndex = this.vIndex + dir * 4;
20525 if(this.vIndex < 0){
20529 if(this.vIndex > 11){
20533 if(isNaN(this.vIndex)){
20537 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20542 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20543 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20547 e.preventDefault();
20550 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20551 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20567 this.picker().remove();
20572 Roo.apply(Roo.bootstrap.MonthField, {
20591 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
20592 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
20597 Roo.apply(Roo.bootstrap.MonthField, {
20601 cls: 'datepicker dropdown-menu roo-dynamic',
20605 cls: 'datepicker-months',
20609 cls: 'table-condensed',
20611 Roo.bootstrap.DateField.content
20631 * @class Roo.bootstrap.CheckBox
20632 * @extends Roo.bootstrap.Input
20633 * Bootstrap CheckBox class
20635 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
20636 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
20637 * @cfg {String} boxLabel The text that appears beside the checkbox
20638 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
20639 * @cfg {Boolean} checked initnal the element
20640 * @cfg {Boolean} inline inline the element (default false)
20641 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
20642 * @cfg {String} tooltip label tooltip
20645 * Create a new CheckBox
20646 * @param {Object} config The config object
20649 Roo.bootstrap.CheckBox = function(config){
20650 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
20655 * Fires when the element is checked or unchecked.
20656 * @param {Roo.bootstrap.CheckBox} this This input
20657 * @param {Boolean} checked The new checked value
20662 * Fires when the element is click.
20663 * @param {Roo.bootstrap.CheckBox} this This input
20670 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
20672 inputType: 'checkbox',
20681 getAutoCreate : function()
20683 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20689 cfg.cls = 'form-group ' + this.inputType; //input-group
20692 cfg.cls += ' ' + this.inputType + '-inline';
20698 type : this.inputType,
20699 value : this.inputValue,
20700 cls : 'roo-' + this.inputType, //'form-box',
20701 placeholder : this.placeholder || ''
20705 if(this.inputType != 'radio'){
20709 cls : 'roo-hidden-value',
20710 value : this.checked ? this.inputValue : this.valueOff
20715 if (this.weight) { // Validity check?
20716 cfg.cls += " " + this.inputType + "-" + this.weight;
20719 if (this.disabled) {
20720 input.disabled=true;
20724 input.checked = this.checked;
20729 input.name = this.name;
20731 if(this.inputType != 'radio'){
20732 hidden.name = this.name;
20733 input.name = '_hidden_' + this.name;
20738 input.cls += ' input-' + this.size;
20743 ['xs','sm','md','lg'].map(function(size){
20744 if (settings[size]) {
20745 cfg.cls += ' col-' + size + '-' + settings[size];
20749 var inputblock = input;
20751 if (this.before || this.after) {
20754 cls : 'input-group',
20759 inputblock.cn.push({
20761 cls : 'input-group-addon',
20766 inputblock.cn.push(input);
20768 if(this.inputType != 'radio'){
20769 inputblock.cn.push(hidden);
20773 inputblock.cn.push({
20775 cls : 'input-group-addon',
20782 if (align ==='left' && this.fieldLabel.length) {
20783 // Roo.log("left and has label");
20788 cls : 'control-label',
20789 html : this.fieldLabel
20799 if(this.labelWidth > 12){
20800 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
20803 if(this.labelWidth < 13 && this.labelmd == 0){
20804 this.labelmd = this.labelWidth;
20807 if(this.labellg > 0){
20808 cfg.cn[0].cls += ' col-lg-' + this.labellg;
20809 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
20812 if(this.labelmd > 0){
20813 cfg.cn[0].cls += ' col-md-' + this.labelmd;
20814 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
20817 if(this.labelsm > 0){
20818 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
20819 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
20822 if(this.labelxs > 0){
20823 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
20824 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
20827 } else if ( this.fieldLabel.length) {
20828 // Roo.log(" label");
20832 tag: this.boxLabel ? 'span' : 'label',
20834 cls: 'control-label box-input-label',
20835 //cls : 'input-group-addon',
20836 html : this.fieldLabel
20845 // Roo.log(" no label && no align");
20846 cfg.cn = [ inputblock ] ;
20852 var boxLabelCfg = {
20854 //'for': id, // box label is handled by onclick - so no for...
20856 html: this.boxLabel
20860 boxLabelCfg.tooltip = this.tooltip;
20863 cfg.cn.push(boxLabelCfg);
20866 if(this.inputType != 'radio'){
20867 cfg.cn.push(hidden);
20875 * return the real input element.
20877 inputEl: function ()
20879 return this.el.select('input.roo-' + this.inputType,true).first();
20881 hiddenEl: function ()
20883 return this.el.select('input.roo-hidden-value',true).first();
20886 labelEl: function()
20888 return this.el.select('label.control-label',true).first();
20890 /* depricated... */
20894 return this.labelEl();
20897 boxLabelEl: function()
20899 return this.el.select('label.box-label',true).first();
20902 initEvents : function()
20904 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
20906 this.inputEl().on('click', this.onClick, this);
20908 if (this.boxLabel) {
20909 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
20912 this.startValue = this.getValue();
20915 Roo.bootstrap.CheckBox.register(this);
20919 onClick : function(e)
20921 if(this.fireEvent('click', this, e) !== false){
20922 this.setChecked(!this.checked);
20927 setChecked : function(state,suppressEvent)
20929 this.startValue = this.getValue();
20931 if(this.inputType == 'radio'){
20933 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20934 e.dom.checked = false;
20937 this.inputEl().dom.checked = true;
20939 this.inputEl().dom.value = this.inputValue;
20941 if(suppressEvent !== true){
20942 this.fireEvent('check', this, true);
20950 this.checked = state;
20952 this.inputEl().dom.checked = state;
20955 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
20957 if(suppressEvent !== true){
20958 this.fireEvent('check', this, state);
20964 getValue : function()
20966 if(this.inputType == 'radio'){
20967 return this.getGroupValue();
20970 return this.hiddenEl().dom.value;
20974 getGroupValue : function()
20976 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
20980 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
20983 setValue : function(v,suppressEvent)
20985 if(this.inputType == 'radio'){
20986 this.setGroupValue(v, suppressEvent);
20990 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
20995 setGroupValue : function(v, suppressEvent)
20997 this.startValue = this.getValue();
20999 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21000 e.dom.checked = false;
21002 if(e.dom.value == v){
21003 e.dom.checked = true;
21007 if(suppressEvent !== true){
21008 this.fireEvent('check', this, true);
21016 validate : function()
21018 if(this.getVisibilityEl().hasClass('hidden')){
21024 (this.inputType == 'radio' && this.validateRadio()) ||
21025 (this.inputType == 'checkbox' && this.validateCheckbox())
21031 this.markInvalid();
21035 validateRadio : function()
21037 if(this.getVisibilityEl().hasClass('hidden')){
21041 if(this.allowBlank){
21047 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21048 if(!e.dom.checked){
21060 validateCheckbox : function()
21063 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
21064 //return (this.getValue() == this.inputValue) ? true : false;
21067 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21075 for(var i in group){
21076 if(group[i].el.isVisible(true)){
21084 for(var i in group){
21089 r = (group[i].getValue() == group[i].inputValue) ? true : false;
21096 * Mark this field as valid
21098 markValid : function()
21102 this.fireEvent('valid', this);
21104 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21107 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
21114 if(this.inputType == 'radio'){
21115 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21116 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
21117 e.findParent('.form-group', false, true).addClass(_this.validClass);
21124 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21125 this.el.findParent('.form-group', false, true).addClass(this.validClass);
21129 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21135 for(var i in group){
21136 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21137 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
21142 * Mark this field as invalid
21143 * @param {String} msg The validation message
21145 markInvalid : function(msg)
21147 if(this.allowBlank){
21153 this.fireEvent('invalid', this, msg);
21155 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21158 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
21162 label.markInvalid();
21165 if(this.inputType == 'radio'){
21166 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21167 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
21168 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
21175 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21176 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
21180 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21186 for(var i in group){
21187 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21188 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
21193 clearInvalid : function()
21195 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
21197 // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21199 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21201 if (label && label.iconEl) {
21202 label.iconEl.removeClass(label.validClass);
21203 label.iconEl.removeClass(label.invalidClass);
21207 disable : function()
21209 if(this.inputType != 'radio'){
21210 Roo.bootstrap.CheckBox.superclass.disable.call(this);
21217 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21218 _this.getActionEl().addClass(this.disabledClass);
21219 e.dom.disabled = true;
21223 this.disabled = true;
21224 this.fireEvent("disable", this);
21228 enable : function()
21230 if(this.inputType != 'radio'){
21231 Roo.bootstrap.CheckBox.superclass.enable.call(this);
21238 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21239 _this.getActionEl().removeClass(this.disabledClass);
21240 e.dom.disabled = false;
21244 this.disabled = false;
21245 this.fireEvent("enable", this);
21249 setBoxLabel : function(v)
21254 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21260 Roo.apply(Roo.bootstrap.CheckBox, {
21265 * register a CheckBox Group
21266 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
21268 register : function(checkbox)
21270 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
21271 this.groups[checkbox.groupId] = {};
21274 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
21278 this.groups[checkbox.groupId][checkbox.name] = checkbox;
21282 * fetch a CheckBox Group based on the group ID
21283 * @param {string} the group ID
21284 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
21286 get: function(groupId) {
21287 if (typeof(this.groups[groupId]) == 'undefined') {
21291 return this.groups[groupId] ;
21304 * @class Roo.bootstrap.Radio
21305 * @extends Roo.bootstrap.Component
21306 * Bootstrap Radio class
21307 * @cfg {String} boxLabel - the label associated
21308 * @cfg {String} value - the value of radio
21311 * Create a new Radio
21312 * @param {Object} config The config object
21314 Roo.bootstrap.Radio = function(config){
21315 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
21319 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
21325 getAutoCreate : function()
21329 cls : 'form-group radio',
21334 html : this.boxLabel
21342 initEvents : function()
21344 this.parent().register(this);
21346 this.el.on('click', this.onClick, this);
21350 onClick : function(e)
21352 if(this.parent().fireEvent('click', this.parent(), this, e) !== false){
21353 this.setChecked(true);
21357 setChecked : function(state, suppressEvent)
21359 this.parent().setValue(this.value, suppressEvent);
21363 setBoxLabel : function(v)
21368 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21383 * @class Roo.bootstrap.SecurePass
21384 * @extends Roo.bootstrap.Input
21385 * Bootstrap SecurePass class
21389 * Create a new SecurePass
21390 * @param {Object} config The config object
21393 Roo.bootstrap.SecurePass = function (config) {
21394 // these go here, so the translation tool can replace them..
21396 PwdEmpty: "Please type a password, and then retype it to confirm.",
21397 PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21398 PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21399 PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21400 IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21401 FNInPwd: "Your password can't contain your first name. Please type a different password.",
21402 LNInPwd: "Your password can't contain your last name. Please type a different password.",
21403 TooWeak: "Your password is Too Weak."
21405 this.meterLabel = "Password strength:";
21406 this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
21407 this.meterClass = [
21408 "roo-password-meter-tooweak",
21409 "roo-password-meter-weak",
21410 "roo-password-meter-medium",
21411 "roo-password-meter-strong",
21412 "roo-password-meter-grey"
21417 Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
21420 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
21422 * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
21424 * PwdEmpty: "Please type a password, and then retype it to confirm.",
21425 * PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21426 * PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21427 * PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21428 * IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21429 * FNInPwd: "Your password can't contain your first name. Please type a different password.",
21430 * LNInPwd: "Your password can't contain your last name. Please type a different password."
21440 * @cfg {String/Object} Label for the strength meter (defaults to
21441 * 'Password strength:')
21446 * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
21447 * ['Weak', 'Medium', 'Strong'])
21450 pwdStrengths: false,
21463 initEvents: function ()
21465 Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
21467 if (this.el.is('input[type=password]') && Roo.isSafari) {
21468 this.el.on('keydown', this.SafariOnKeyDown, this);
21471 this.el.on('keyup', this.checkStrength, this, {buffer: 50});
21474 onRender: function (ct, position)
21476 Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
21477 this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
21478 this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
21480 this.trigger.createChild({
21485 cls: 'roo-password-meter-grey col-xs-12',
21488 //width: this.meterWidth + 'px'
21492 cls: 'roo-password-meter-text'
21498 if (this.hideTrigger) {
21499 this.trigger.setDisplayed(false);
21501 this.setSize(this.width || '', this.height || '');
21504 onDestroy: function ()
21506 if (this.trigger) {
21507 this.trigger.removeAllListeners();
21508 this.trigger.remove();
21511 this.wrap.remove();
21513 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
21516 checkStrength: function ()
21518 var pwd = this.inputEl().getValue();
21519 if (pwd == this._lastPwd) {
21524 if (this.ClientSideStrongPassword(pwd)) {
21526 } else if (this.ClientSideMediumPassword(pwd)) {
21528 } else if (this.ClientSideWeakPassword(pwd)) {
21534 Roo.log('strength1: ' + strength);
21536 //var pm = this.trigger.child('div/div/div').dom;
21537 var pm = this.trigger.child('div/div');
21538 pm.removeClass(this.meterClass);
21539 pm.addClass(this.meterClass[strength]);
21542 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21544 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21546 this._lastPwd = pwd;
21550 Roo.bootstrap.SecurePass.superclass.reset.call(this);
21552 this._lastPwd = '';
21554 var pm = this.trigger.child('div/div');
21555 pm.removeClass(this.meterClass);
21556 pm.addClass('roo-password-meter-grey');
21559 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21562 this.inputEl().dom.type='password';
21565 validateValue: function (value)
21568 if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
21571 if (value.length == 0) {
21572 if (this.allowBlank) {
21573 this.clearInvalid();
21577 this.markInvalid(this.errors.PwdEmpty);
21578 this.errorMsg = this.errors.PwdEmpty;
21586 if ('[\x21-\x7e]*'.match(value)) {
21587 this.markInvalid(this.errors.PwdBadChar);
21588 this.errorMsg = this.errors.PwdBadChar;
21591 if (value.length < 6) {
21592 this.markInvalid(this.errors.PwdShort);
21593 this.errorMsg = this.errors.PwdShort;
21596 if (value.length > 16) {
21597 this.markInvalid(this.errors.PwdLong);
21598 this.errorMsg = this.errors.PwdLong;
21602 if (this.ClientSideStrongPassword(value)) {
21604 } else if (this.ClientSideMediumPassword(value)) {
21606 } else if (this.ClientSideWeakPassword(value)) {
21613 if (strength < 2) {
21614 //this.markInvalid(this.errors.TooWeak);
21615 this.errorMsg = this.errors.TooWeak;
21620 console.log('strength2: ' + strength);
21622 //var pm = this.trigger.child('div/div/div').dom;
21624 var pm = this.trigger.child('div/div');
21625 pm.removeClass(this.meterClass);
21626 pm.addClass(this.meterClass[strength]);
21628 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21630 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21632 this.errorMsg = '';
21636 CharacterSetChecks: function (type)
21639 this.fResult = false;
21642 isctype: function (character, type)
21645 case this.kCapitalLetter:
21646 if (character >= 'A' && character <= 'Z') {
21651 case this.kSmallLetter:
21652 if (character >= 'a' && character <= 'z') {
21658 if (character >= '0' && character <= '9') {
21663 case this.kPunctuation:
21664 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
21675 IsLongEnough: function (pwd, size)
21677 return !(pwd == null || isNaN(size) || pwd.length < size);
21680 SpansEnoughCharacterSets: function (word, nb)
21682 if (!this.IsLongEnough(word, nb))
21687 var characterSetChecks = new Array(
21688 new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
21689 new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
21692 for (var index = 0; index < word.length; ++index) {
21693 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21694 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
21695 characterSetChecks[nCharSet].fResult = true;
21702 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21703 if (characterSetChecks[nCharSet].fResult) {
21708 if (nCharSets < nb) {
21714 ClientSideStrongPassword: function (pwd)
21716 return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
21719 ClientSideMediumPassword: function (pwd)
21721 return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
21724 ClientSideWeakPassword: function (pwd)
21726 return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
21729 })//<script type="text/javascript">
21732 * Based Ext JS Library 1.1.1
21733 * Copyright(c) 2006-2007, Ext JS, LLC.
21739 * @class Roo.HtmlEditorCore
21740 * @extends Roo.Component
21741 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
21743 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
21746 Roo.HtmlEditorCore = function(config){
21749 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
21754 * @event initialize
21755 * Fires when the editor is fully initialized (including the iframe)
21756 * @param {Roo.HtmlEditorCore} this
21761 * Fires when the editor is first receives the focus. Any insertion must wait
21762 * until after this event.
21763 * @param {Roo.HtmlEditorCore} this
21767 * @event beforesync
21768 * Fires before the textarea is updated with content from the editor iframe. Return false
21769 * to cancel the sync.
21770 * @param {Roo.HtmlEditorCore} this
21771 * @param {String} html
21775 * @event beforepush
21776 * Fires before the iframe editor is updated with content from the textarea. Return false
21777 * to cancel the push.
21778 * @param {Roo.HtmlEditorCore} this
21779 * @param {String} html
21784 * Fires when the textarea is updated with content from the editor iframe.
21785 * @param {Roo.HtmlEditorCore} this
21786 * @param {String} html
21791 * Fires when the iframe editor is updated with content from the textarea.
21792 * @param {Roo.HtmlEditorCore} this
21793 * @param {String} html
21798 * @event editorevent
21799 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
21800 * @param {Roo.HtmlEditorCore} this
21806 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
21808 // defaults : white / black...
21809 this.applyBlacklists();
21816 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
21820 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
21826 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
21831 * @cfg {Number} height (in pixels)
21835 * @cfg {Number} width (in pixels)
21840 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
21843 stylesheets: false,
21848 // private properties
21849 validationEvent : false,
21851 initialized : false,
21853 sourceEditMode : false,
21854 onFocus : Roo.emptyFn,
21856 hideMode:'offsets',
21860 // blacklist + whitelisted elements..
21867 * Protected method that will not generally be called directly. It
21868 * is called when the editor initializes the iframe with HTML contents. Override this method if you
21869 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
21871 getDocMarkup : function(){
21875 // inherit styels from page...??
21876 if (this.stylesheets === false) {
21878 Roo.get(document.head).select('style').each(function(node) {
21879 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21882 Roo.get(document.head).select('link').each(function(node) {
21883 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21886 } else if (!this.stylesheets.length) {
21888 st = '<style type="text/css">' +
21889 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21892 st = '<style type="text/css">' +
21897 st += '<style type="text/css">' +
21898 'IMG { cursor: pointer } ' +
21901 var cls = 'roo-htmleditor-body';
21903 if(this.bodyCls.length){
21904 cls += ' ' + this.bodyCls;
21907 return '<html><head>' + st +
21908 //<style type="text/css">' +
21909 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21911 ' </head><body class="' + cls + '"></body></html>';
21915 onRender : function(ct, position)
21918 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
21919 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
21922 this.el.dom.style.border = '0 none';
21923 this.el.dom.setAttribute('tabIndex', -1);
21924 this.el.addClass('x-hidden hide');
21928 if(Roo.isIE){ // fix IE 1px bogus margin
21929 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
21933 this.frameId = Roo.id();
21937 var iframe = this.owner.wrap.createChild({
21939 cls: 'form-control', // bootstrap..
21941 name: this.frameId,
21942 frameBorder : 'no',
21943 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
21948 this.iframe = iframe.dom;
21950 this.assignDocWin();
21952 this.doc.designMode = 'on';
21955 this.doc.write(this.getDocMarkup());
21959 var task = { // must defer to wait for browser to be ready
21961 //console.log("run task?" + this.doc.readyState);
21962 this.assignDocWin();
21963 if(this.doc.body || this.doc.readyState == 'complete'){
21965 this.doc.designMode="on";
21969 Roo.TaskMgr.stop(task);
21970 this.initEditor.defer(10, this);
21977 Roo.TaskMgr.start(task);
21982 onResize : function(w, h)
21984 Roo.log('resize: ' +w + ',' + h );
21985 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
21989 if(typeof w == 'number'){
21991 this.iframe.style.width = w + 'px';
21993 if(typeof h == 'number'){
21995 this.iframe.style.height = h + 'px';
21997 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
22004 * Toggles the editor between standard and source edit mode.
22005 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
22007 toggleSourceEdit : function(sourceEditMode){
22009 this.sourceEditMode = sourceEditMode === true;
22011 if(this.sourceEditMode){
22013 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
22016 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
22017 //this.iframe.className = '';
22020 //this.setSize(this.owner.wrap.getSize());
22021 //this.fireEvent('editmodechange', this, this.sourceEditMode);
22028 * Protected method that will not generally be called directly. If you need/want
22029 * custom HTML cleanup, this is the method you should override.
22030 * @param {String} html The HTML to be cleaned
22031 * return {String} The cleaned HTML
22033 cleanHtml : function(html){
22034 html = String(html);
22035 if(html.length > 5){
22036 if(Roo.isSafari){ // strip safari nonsense
22037 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
22040 if(html == ' '){
22047 * HTML Editor -> Textarea
22048 * Protected method that will not generally be called directly. Syncs the contents
22049 * of the editor iframe with the textarea.
22051 syncValue : function(){
22052 if(this.initialized){
22053 var bd = (this.doc.body || this.doc.documentElement);
22054 //this.cleanUpPaste(); -- this is done else where and causes havoc..
22055 var html = bd.innerHTML;
22057 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
22058 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
22060 html = '<div style="'+m[0]+'">' + html + '</div>';
22063 html = this.cleanHtml(html);
22064 // fix up the special chars.. normaly like back quotes in word...
22065 // however we do not want to do this with chinese..
22066 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
22067 var cc = b.charCodeAt();
22069 (cc >= 0x4E00 && cc < 0xA000 ) ||
22070 (cc >= 0x3400 && cc < 0x4E00 ) ||
22071 (cc >= 0xf900 && cc < 0xfb00 )
22077 if(this.owner.fireEvent('beforesync', this, html) !== false){
22078 this.el.dom.value = html;
22079 this.owner.fireEvent('sync', this, html);
22085 * Protected method that will not generally be called directly. Pushes the value of the textarea
22086 * into the iframe editor.
22088 pushValue : function(){
22089 if(this.initialized){
22090 var v = this.el.dom.value.trim();
22092 // if(v.length < 1){
22096 if(this.owner.fireEvent('beforepush', this, v) !== false){
22097 var d = (this.doc.body || this.doc.documentElement);
22099 this.cleanUpPaste();
22100 this.el.dom.value = d.innerHTML;
22101 this.owner.fireEvent('push', this, v);
22107 deferFocus : function(){
22108 this.focus.defer(10, this);
22112 focus : function(){
22113 if(this.win && !this.sourceEditMode){
22120 assignDocWin: function()
22122 var iframe = this.iframe;
22125 this.doc = iframe.contentWindow.document;
22126 this.win = iframe.contentWindow;
22128 // if (!Roo.get(this.frameId)) {
22131 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
22132 // this.win = Roo.get(this.frameId).dom.contentWindow;
22134 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
22138 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
22139 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
22144 initEditor : function(){
22145 //console.log("INIT EDITOR");
22146 this.assignDocWin();
22150 this.doc.designMode="on";
22152 this.doc.write(this.getDocMarkup());
22155 var dbody = (this.doc.body || this.doc.documentElement);
22156 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
22157 // this copies styles from the containing element into thsi one..
22158 // not sure why we need all of this..
22159 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
22161 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
22162 //ss['background-attachment'] = 'fixed'; // w3c
22163 dbody.bgProperties = 'fixed'; // ie
22164 //Roo.DomHelper.applyStyles(dbody, ss);
22165 Roo.EventManager.on(this.doc, {
22166 //'mousedown': this.onEditorEvent,
22167 'mouseup': this.onEditorEvent,
22168 'dblclick': this.onEditorEvent,
22169 'click': this.onEditorEvent,
22170 'keyup': this.onEditorEvent,
22175 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
22177 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
22178 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
22180 this.initialized = true;
22182 this.owner.fireEvent('initialize', this);
22187 onDestroy : function(){
22193 //for (var i =0; i < this.toolbars.length;i++) {
22194 // // fixme - ask toolbars for heights?
22195 // this.toolbars[i].onDestroy();
22198 //this.wrap.dom.innerHTML = '';
22199 //this.wrap.remove();
22204 onFirstFocus : function(){
22206 this.assignDocWin();
22209 this.activated = true;
22212 if(Roo.isGecko){ // prevent silly gecko errors
22214 var s = this.win.getSelection();
22215 if(!s.focusNode || s.focusNode.nodeType != 3){
22216 var r = s.getRangeAt(0);
22217 r.selectNodeContents((this.doc.body || this.doc.documentElement));
22222 this.execCmd('useCSS', true);
22223 this.execCmd('styleWithCSS', false);
22226 this.owner.fireEvent('activate', this);
22230 adjustFont: function(btn){
22231 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
22232 //if(Roo.isSafari){ // safari
22235 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
22236 if(Roo.isSafari){ // safari
22237 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
22238 v = (v < 10) ? 10 : v;
22239 v = (v > 48) ? 48 : v;
22240 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
22245 v = Math.max(1, v+adjust);
22247 this.execCmd('FontSize', v );
22250 onEditorEvent : function(e)
22252 this.owner.fireEvent('editorevent', this, e);
22253 // this.updateToolbar();
22254 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
22257 insertTag : function(tg)
22259 // could be a bit smarter... -> wrap the current selected tRoo..
22260 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
22262 range = this.createRange(this.getSelection());
22263 var wrappingNode = this.doc.createElement(tg.toLowerCase());
22264 wrappingNode.appendChild(range.extractContents());
22265 range.insertNode(wrappingNode);
22272 this.execCmd("formatblock", tg);
22276 insertText : function(txt)
22280 var range = this.createRange();
22281 range.deleteContents();
22282 //alert(Sender.getAttribute('label'));
22284 range.insertNode(this.doc.createTextNode(txt));
22290 * Executes a Midas editor command on the editor document and performs necessary focus and
22291 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
22292 * @param {String} cmd The Midas command
22293 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22295 relayCmd : function(cmd, value){
22297 this.execCmd(cmd, value);
22298 this.owner.fireEvent('editorevent', this);
22299 //this.updateToolbar();
22300 this.owner.deferFocus();
22304 * Executes a Midas editor command directly on the editor document.
22305 * For visual commands, you should use {@link #relayCmd} instead.
22306 * <b>This should only be called after the editor is initialized.</b>
22307 * @param {String} cmd The Midas command
22308 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22310 execCmd : function(cmd, value){
22311 this.doc.execCommand(cmd, false, value === undefined ? null : value);
22318 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
22320 * @param {String} text | dom node..
22322 insertAtCursor : function(text)
22325 if(!this.activated){
22331 var r = this.doc.selection.createRange();
22342 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
22346 // from jquery ui (MIT licenced)
22348 var win = this.win;
22350 if (win.getSelection && win.getSelection().getRangeAt) {
22351 range = win.getSelection().getRangeAt(0);
22352 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
22353 range.insertNode(node);
22354 } else if (win.document.selection && win.document.selection.createRange) {
22355 // no firefox support
22356 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22357 win.document.selection.createRange().pasteHTML(txt);
22359 // no firefox support
22360 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22361 this.execCmd('InsertHTML', txt);
22370 mozKeyPress : function(e){
22372 var c = e.getCharCode(), cmd;
22375 c = String.fromCharCode(c).toLowerCase();
22389 this.cleanUpPaste.defer(100, this);
22397 e.preventDefault();
22405 fixKeys : function(){ // load time branching for fastest keydown performance
22407 return function(e){
22408 var k = e.getKey(), r;
22411 r = this.doc.selection.createRange();
22414 r.pasteHTML('    ');
22421 r = this.doc.selection.createRange();
22423 var target = r.parentElement();
22424 if(!target || target.tagName.toLowerCase() != 'li'){
22426 r.pasteHTML('<br />');
22432 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22433 this.cleanUpPaste.defer(100, this);
22439 }else if(Roo.isOpera){
22440 return function(e){
22441 var k = e.getKey();
22445 this.execCmd('InsertHTML','    ');
22448 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22449 this.cleanUpPaste.defer(100, this);
22454 }else if(Roo.isSafari){
22455 return function(e){
22456 var k = e.getKey();
22460 this.execCmd('InsertText','\t');
22464 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22465 this.cleanUpPaste.defer(100, this);
22473 getAllAncestors: function()
22475 var p = this.getSelectedNode();
22478 a.push(p); // push blank onto stack..
22479 p = this.getParentElement();
22483 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
22487 a.push(this.doc.body);
22491 lastSelNode : false,
22494 getSelection : function()
22496 this.assignDocWin();
22497 return Roo.isIE ? this.doc.selection : this.win.getSelection();
22500 getSelectedNode: function()
22502 // this may only work on Gecko!!!
22504 // should we cache this!!!!
22509 var range = this.createRange(this.getSelection()).cloneRange();
22512 var parent = range.parentElement();
22514 var testRange = range.duplicate();
22515 testRange.moveToElementText(parent);
22516 if (testRange.inRange(range)) {
22519 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
22522 parent = parent.parentElement;
22527 // is ancestor a text element.
22528 var ac = range.commonAncestorContainer;
22529 if (ac.nodeType == 3) {
22530 ac = ac.parentNode;
22533 var ar = ac.childNodes;
22536 var other_nodes = [];
22537 var has_other_nodes = false;
22538 for (var i=0;i<ar.length;i++) {
22539 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
22542 // fullly contained node.
22544 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
22549 // probably selected..
22550 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
22551 other_nodes.push(ar[i]);
22555 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
22560 has_other_nodes = true;
22562 if (!nodes.length && other_nodes.length) {
22563 nodes= other_nodes;
22565 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
22571 createRange: function(sel)
22573 // this has strange effects when using with
22574 // top toolbar - not sure if it's a great idea.
22575 //this.editor.contentWindow.focus();
22576 if (typeof sel != "undefined") {
22578 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
22580 return this.doc.createRange();
22583 return this.doc.createRange();
22586 getParentElement: function()
22589 this.assignDocWin();
22590 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
22592 var range = this.createRange(sel);
22595 var p = range.commonAncestorContainer;
22596 while (p.nodeType == 3) { // text node
22607 * Range intersection.. the hard stuff...
22611 * [ -- selected range --- ]
22615 * if end is before start or hits it. fail.
22616 * if start is after end or hits it fail.
22618 * if either hits (but other is outside. - then it's not
22624 // @see http://www.thismuchiknow.co.uk/?p=64.
22625 rangeIntersectsNode : function(range, node)
22627 var nodeRange = node.ownerDocument.createRange();
22629 nodeRange.selectNode(node);
22631 nodeRange.selectNodeContents(node);
22634 var rangeStartRange = range.cloneRange();
22635 rangeStartRange.collapse(true);
22637 var rangeEndRange = range.cloneRange();
22638 rangeEndRange.collapse(false);
22640 var nodeStartRange = nodeRange.cloneRange();
22641 nodeStartRange.collapse(true);
22643 var nodeEndRange = nodeRange.cloneRange();
22644 nodeEndRange.collapse(false);
22646 return rangeStartRange.compareBoundaryPoints(
22647 Range.START_TO_START, nodeEndRange) == -1 &&
22648 rangeEndRange.compareBoundaryPoints(
22649 Range.START_TO_START, nodeStartRange) == 1;
22653 rangeCompareNode : function(range, node)
22655 var nodeRange = node.ownerDocument.createRange();
22657 nodeRange.selectNode(node);
22659 nodeRange.selectNodeContents(node);
22663 range.collapse(true);
22665 nodeRange.collapse(true);
22667 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
22668 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
22670 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
22672 var nodeIsBefore = ss == 1;
22673 var nodeIsAfter = ee == -1;
22675 if (nodeIsBefore && nodeIsAfter) {
22678 if (!nodeIsBefore && nodeIsAfter) {
22679 return 1; //right trailed.
22682 if (nodeIsBefore && !nodeIsAfter) {
22683 return 2; // left trailed.
22689 // private? - in a new class?
22690 cleanUpPaste : function()
22692 // cleans up the whole document..
22693 Roo.log('cleanuppaste');
22695 this.cleanUpChildren(this.doc.body);
22696 var clean = this.cleanWordChars(this.doc.body.innerHTML);
22697 if (clean != this.doc.body.innerHTML) {
22698 this.doc.body.innerHTML = clean;
22703 cleanWordChars : function(input) {// change the chars to hex code
22704 var he = Roo.HtmlEditorCore;
22706 var output = input;
22707 Roo.each(he.swapCodes, function(sw) {
22708 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
22710 output = output.replace(swapper, sw[1]);
22717 cleanUpChildren : function (n)
22719 if (!n.childNodes.length) {
22722 for (var i = n.childNodes.length-1; i > -1 ; i--) {
22723 this.cleanUpChild(n.childNodes[i]);
22730 cleanUpChild : function (node)
22733 //console.log(node);
22734 if (node.nodeName == "#text") {
22735 // clean up silly Windows -- stuff?
22738 if (node.nodeName == "#comment") {
22739 node.parentNode.removeChild(node);
22740 // clean up silly Windows -- stuff?
22743 var lcname = node.tagName.toLowerCase();
22744 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
22745 // whitelist of tags..
22747 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
22749 node.parentNode.removeChild(node);
22754 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
22756 // remove <a name=....> as rendering on yahoo mailer is borked with this.
22757 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
22759 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
22760 // remove_keep_children = true;
22763 if (remove_keep_children) {
22764 this.cleanUpChildren(node);
22765 // inserts everything just before this node...
22766 while (node.childNodes.length) {
22767 var cn = node.childNodes[0];
22768 node.removeChild(cn);
22769 node.parentNode.insertBefore(cn, node);
22771 node.parentNode.removeChild(node);
22775 if (!node.attributes || !node.attributes.length) {
22776 this.cleanUpChildren(node);
22780 function cleanAttr(n,v)
22783 if (v.match(/^\./) || v.match(/^\//)) {
22786 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/) || v.match(/^ftp:/)) {
22789 if (v.match(/^#/)) {
22792 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
22793 node.removeAttribute(n);
22797 var cwhite = this.cwhite;
22798 var cblack = this.cblack;
22800 function cleanStyle(n,v)
22802 if (v.match(/expression/)) { //XSS?? should we even bother..
22803 node.removeAttribute(n);
22807 var parts = v.split(/;/);
22810 Roo.each(parts, function(p) {
22811 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
22815 var l = p.split(':').shift().replace(/\s+/g,'');
22816 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
22818 if ( cwhite.length && cblack.indexOf(l) > -1) {
22819 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22820 //node.removeAttribute(n);
22824 // only allow 'c whitelisted system attributes'
22825 if ( cwhite.length && cwhite.indexOf(l) < 0) {
22826 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22827 //node.removeAttribute(n);
22837 if (clean.length) {
22838 node.setAttribute(n, clean.join(';'));
22840 node.removeAttribute(n);
22846 for (var i = node.attributes.length-1; i > -1 ; i--) {
22847 var a = node.attributes[i];
22850 if (a.name.toLowerCase().substr(0,2)=='on') {
22851 node.removeAttribute(a.name);
22854 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
22855 node.removeAttribute(a.name);
22858 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
22859 cleanAttr(a.name,a.value); // fixme..
22862 if (a.name == 'style') {
22863 cleanStyle(a.name,a.value);
22866 /// clean up MS crap..
22867 // tecnically this should be a list of valid class'es..
22870 if (a.name == 'class') {
22871 if (a.value.match(/^Mso/)) {
22872 node.className = '';
22875 if (a.value.match(/^body$/)) {
22876 node.className = '';
22887 this.cleanUpChildren(node);
22893 * Clean up MS wordisms...
22895 cleanWord : function(node)
22900 this.cleanWord(this.doc.body);
22903 if (node.nodeName == "#text") {
22904 // clean up silly Windows -- stuff?
22907 if (node.nodeName == "#comment") {
22908 node.parentNode.removeChild(node);
22909 // clean up silly Windows -- stuff?
22913 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
22914 node.parentNode.removeChild(node);
22918 // remove - but keep children..
22919 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
22920 while (node.childNodes.length) {
22921 var cn = node.childNodes[0];
22922 node.removeChild(cn);
22923 node.parentNode.insertBefore(cn, node);
22925 node.parentNode.removeChild(node);
22926 this.iterateChildren(node, this.cleanWord);
22930 if (node.className.length) {
22932 var cn = node.className.split(/\W+/);
22934 Roo.each(cn, function(cls) {
22935 if (cls.match(/Mso[a-zA-Z]+/)) {
22940 node.className = cna.length ? cna.join(' ') : '';
22942 node.removeAttribute("class");
22946 if (node.hasAttribute("lang")) {
22947 node.removeAttribute("lang");
22950 if (node.hasAttribute("style")) {
22952 var styles = node.getAttribute("style").split(";");
22954 Roo.each(styles, function(s) {
22955 if (!s.match(/:/)) {
22958 var kv = s.split(":");
22959 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
22962 // what ever is left... we allow.
22965 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22966 if (!nstyle.length) {
22967 node.removeAttribute('style');
22970 this.iterateChildren(node, this.cleanWord);
22976 * iterateChildren of a Node, calling fn each time, using this as the scole..
22977 * @param {DomNode} node node to iterate children of.
22978 * @param {Function} fn method of this class to call on each item.
22980 iterateChildren : function(node, fn)
22982 if (!node.childNodes.length) {
22985 for (var i = node.childNodes.length-1; i > -1 ; i--) {
22986 fn.call(this, node.childNodes[i])
22992 * cleanTableWidths.
22994 * Quite often pasting from word etc.. results in tables with column and widths.
22995 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
22998 cleanTableWidths : function(node)
23003 this.cleanTableWidths(this.doc.body);
23008 if (node.nodeName == "#text" || node.nodeName == "#comment") {
23011 Roo.log(node.tagName);
23012 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
23013 this.iterateChildren(node, this.cleanTableWidths);
23016 if (node.hasAttribute('width')) {
23017 node.removeAttribute('width');
23021 if (node.hasAttribute("style")) {
23024 var styles = node.getAttribute("style").split(";");
23026 Roo.each(styles, function(s) {
23027 if (!s.match(/:/)) {
23030 var kv = s.split(":");
23031 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
23034 // what ever is left... we allow.
23037 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
23038 if (!nstyle.length) {
23039 node.removeAttribute('style');
23043 this.iterateChildren(node, this.cleanTableWidths);
23051 domToHTML : function(currentElement, depth, nopadtext) {
23053 depth = depth || 0;
23054 nopadtext = nopadtext || false;
23056 if (!currentElement) {
23057 return this.domToHTML(this.doc.body);
23060 //Roo.log(currentElement);
23062 var allText = false;
23063 var nodeName = currentElement.nodeName;
23064 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
23066 if (nodeName == '#text') {
23068 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
23073 if (nodeName != 'BODY') {
23076 // Prints the node tagName, such as <A>, <IMG>, etc
23079 for(i = 0; i < currentElement.attributes.length;i++) {
23081 var aname = currentElement.attributes.item(i).name;
23082 if (!currentElement.attributes.item(i).value.length) {
23085 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
23088 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
23097 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
23100 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
23105 // Traverse the tree
23107 var currentElementChild = currentElement.childNodes.item(i);
23108 var allText = true;
23109 var innerHTML = '';
23111 while (currentElementChild) {
23112 // Formatting code (indent the tree so it looks nice on the screen)
23113 var nopad = nopadtext;
23114 if (lastnode == 'SPAN') {
23118 if (currentElementChild.nodeName == '#text') {
23119 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
23120 toadd = nopadtext ? toadd : toadd.trim();
23121 if (!nopad && toadd.length > 80) {
23122 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
23124 innerHTML += toadd;
23127 currentElementChild = currentElement.childNodes.item(i);
23133 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
23135 // Recursively traverse the tree structure of the child node
23136 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
23137 lastnode = currentElementChild.nodeName;
23139 currentElementChild=currentElement.childNodes.item(i);
23145 // The remaining code is mostly for formatting the tree
23146 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
23151 ret+= "</"+tagName+">";
23157 applyBlacklists : function()
23159 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
23160 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
23164 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
23165 if (b.indexOf(tag) > -1) {
23168 this.white.push(tag);
23172 Roo.each(w, function(tag) {
23173 if (b.indexOf(tag) > -1) {
23176 if (this.white.indexOf(tag) > -1) {
23179 this.white.push(tag);
23184 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
23185 if (w.indexOf(tag) > -1) {
23188 this.black.push(tag);
23192 Roo.each(b, function(tag) {
23193 if (w.indexOf(tag) > -1) {
23196 if (this.black.indexOf(tag) > -1) {
23199 this.black.push(tag);
23204 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
23205 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
23209 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
23210 if (b.indexOf(tag) > -1) {
23213 this.cwhite.push(tag);
23217 Roo.each(w, function(tag) {
23218 if (b.indexOf(tag) > -1) {
23221 if (this.cwhite.indexOf(tag) > -1) {
23224 this.cwhite.push(tag);
23229 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
23230 if (w.indexOf(tag) > -1) {
23233 this.cblack.push(tag);
23237 Roo.each(b, function(tag) {
23238 if (w.indexOf(tag) > -1) {
23241 if (this.cblack.indexOf(tag) > -1) {
23244 this.cblack.push(tag);
23249 setStylesheets : function(stylesheets)
23251 if(typeof(stylesheets) == 'string'){
23252 Roo.get(this.iframe.contentDocument.head).createChild({
23254 rel : 'stylesheet',
23263 Roo.each(stylesheets, function(s) {
23268 Roo.get(_this.iframe.contentDocument.head).createChild({
23270 rel : 'stylesheet',
23279 removeStylesheets : function()
23283 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
23288 setStyle : function(style)
23290 Roo.get(this.iframe.contentDocument.head).createChild({
23299 // hide stuff that is not compatible
23313 * @event specialkey
23317 * @cfg {String} fieldClass @hide
23320 * @cfg {String} focusClass @hide
23323 * @cfg {String} autoCreate @hide
23326 * @cfg {String} inputType @hide
23329 * @cfg {String} invalidClass @hide
23332 * @cfg {String} invalidText @hide
23335 * @cfg {String} msgFx @hide
23338 * @cfg {String} validateOnBlur @hide
23342 Roo.HtmlEditorCore.white = [
23343 'area', 'br', 'img', 'input', 'hr', 'wbr',
23345 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
23346 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
23347 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
23348 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
23349 'table', 'ul', 'xmp',
23351 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
23354 'dir', 'menu', 'ol', 'ul', 'dl',
23360 Roo.HtmlEditorCore.black = [
23361 // 'embed', 'object', // enable - backend responsiblity to clean thiese
23363 'base', 'basefont', 'bgsound', 'blink', 'body',
23364 'frame', 'frameset', 'head', 'html', 'ilayer',
23365 'iframe', 'layer', 'link', 'meta', 'object',
23366 'script', 'style' ,'title', 'xml' // clean later..
23368 Roo.HtmlEditorCore.clean = [
23369 'script', 'style', 'title', 'xml'
23371 Roo.HtmlEditorCore.remove = [
23376 Roo.HtmlEditorCore.ablack = [
23380 Roo.HtmlEditorCore.aclean = [
23381 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
23385 Roo.HtmlEditorCore.pwhite= [
23386 'http', 'https', 'mailto'
23389 // white listed style attributes.
23390 Roo.HtmlEditorCore.cwhite= [
23391 // 'text-align', /// default is to allow most things..
23397 // black listed style attributes.
23398 Roo.HtmlEditorCore.cblack= [
23399 // 'font-size' -- this can be set by the project
23403 Roo.HtmlEditorCore.swapCodes =[
23422 * @class Roo.bootstrap.HtmlEditor
23423 * @extends Roo.bootstrap.TextArea
23424 * Bootstrap HtmlEditor class
23427 * Create a new HtmlEditor
23428 * @param {Object} config The config object
23431 Roo.bootstrap.HtmlEditor = function(config){
23432 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
23433 if (!this.toolbars) {
23434 this.toolbars = [];
23437 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
23440 * @event initialize
23441 * Fires when the editor is fully initialized (including the iframe)
23442 * @param {HtmlEditor} this
23447 * Fires when the editor is first receives the focus. Any insertion must wait
23448 * until after this event.
23449 * @param {HtmlEditor} this
23453 * @event beforesync
23454 * Fires before the textarea is updated with content from the editor iframe. Return false
23455 * to cancel the sync.
23456 * @param {HtmlEditor} this
23457 * @param {String} html
23461 * @event beforepush
23462 * Fires before the iframe editor is updated with content from the textarea. Return false
23463 * to cancel the push.
23464 * @param {HtmlEditor} this
23465 * @param {String} html
23470 * Fires when the textarea is updated with content from the editor iframe.
23471 * @param {HtmlEditor} this
23472 * @param {String} html
23477 * Fires when the iframe editor is updated with content from the textarea.
23478 * @param {HtmlEditor} this
23479 * @param {String} html
23483 * @event editmodechange
23484 * Fires when the editor switches edit modes
23485 * @param {HtmlEditor} this
23486 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
23488 editmodechange: true,
23490 * @event editorevent
23491 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
23492 * @param {HtmlEditor} this
23496 * @event firstfocus
23497 * Fires when on first focus - needed by toolbars..
23498 * @param {HtmlEditor} this
23503 * Auto save the htmlEditor value as a file into Events
23504 * @param {HtmlEditor} this
23508 * @event savedpreview
23509 * preview the saved version of htmlEditor
23510 * @param {HtmlEditor} this
23517 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
23521 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
23526 * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
23531 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
23536 * @cfg {Number} height (in pixels)
23540 * @cfg {Number} width (in pixels)
23545 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
23548 stylesheets: false,
23553 // private properties
23554 validationEvent : false,
23556 initialized : false,
23559 onFocus : Roo.emptyFn,
23561 hideMode:'offsets',
23563 tbContainer : false,
23567 toolbarContainer :function() {
23568 return this.wrap.select('.x-html-editor-tb',true).first();
23572 * Protected method that will not generally be called directly. It
23573 * is called when the editor creates its toolbar. Override this method if you need to
23574 * add custom toolbar buttons.
23575 * @param {HtmlEditor} editor
23577 createToolbar : function(){
23578 Roo.log('renewing');
23579 Roo.log("create toolbars");
23581 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
23582 this.toolbars[0].render(this.toolbarContainer());
23586 // if (!editor.toolbars || !editor.toolbars.length) {
23587 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
23590 // for (var i =0 ; i < editor.toolbars.length;i++) {
23591 // editor.toolbars[i] = Roo.factory(
23592 // typeof(editor.toolbars[i]) == 'string' ?
23593 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
23594 // Roo.bootstrap.HtmlEditor);
23595 // editor.toolbars[i].init(editor);
23601 onRender : function(ct, position)
23603 // Roo.log("Call onRender: " + this.xtype);
23605 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
23607 this.wrap = this.inputEl().wrap({
23608 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
23611 this.editorcore.onRender(ct, position);
23613 if (this.resizable) {
23614 this.resizeEl = new Roo.Resizable(this.wrap, {
23618 minHeight : this.height,
23619 height: this.height,
23620 handles : this.resizable,
23623 resize : function(r, w, h) {
23624 _t.onResize(w,h); // -something
23630 this.createToolbar(this);
23633 if(!this.width && this.resizable){
23634 this.setSize(this.wrap.getSize());
23636 if (this.resizeEl) {
23637 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
23638 // should trigger onReize..
23644 onResize : function(w, h)
23646 Roo.log('resize: ' +w + ',' + h );
23647 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
23651 if(this.inputEl() ){
23652 if(typeof w == 'number'){
23653 var aw = w - this.wrap.getFrameWidth('lr');
23654 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
23657 if(typeof h == 'number'){
23658 var tbh = -11; // fixme it needs to tool bar size!
23659 for (var i =0; i < this.toolbars.length;i++) {
23660 // fixme - ask toolbars for heights?
23661 tbh += this.toolbars[i].el.getHeight();
23662 //if (this.toolbars[i].footer) {
23663 // tbh += this.toolbars[i].footer.el.getHeight();
23671 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
23672 ah -= 5; // knock a few pixes off for look..
23673 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
23677 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
23678 this.editorcore.onResize(ew,eh);
23683 * Toggles the editor between standard and source edit mode.
23684 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
23686 toggleSourceEdit : function(sourceEditMode)
23688 this.editorcore.toggleSourceEdit(sourceEditMode);
23690 if(this.editorcore.sourceEditMode){
23691 Roo.log('editor - showing textarea');
23694 // Roo.log(this.syncValue());
23696 this.inputEl().removeClass(['hide', 'x-hidden']);
23697 this.inputEl().dom.removeAttribute('tabIndex');
23698 this.inputEl().focus();
23700 Roo.log('editor - hiding textarea');
23702 // Roo.log(this.pushValue());
23705 this.inputEl().addClass(['hide', 'x-hidden']);
23706 this.inputEl().dom.setAttribute('tabIndex', -1);
23707 //this.deferFocus();
23710 if(this.resizable){
23711 this.setSize(this.wrap.getSize());
23714 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
23717 // private (for BoxComponent)
23718 adjustSize : Roo.BoxComponent.prototype.adjustSize,
23720 // private (for BoxComponent)
23721 getResizeEl : function(){
23725 // private (for BoxComponent)
23726 getPositionEl : function(){
23731 initEvents : function(){
23732 this.originalValue = this.getValue();
23736 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23739 // markInvalid : Roo.emptyFn,
23741 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23744 // clearInvalid : Roo.emptyFn,
23746 setValue : function(v){
23747 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
23748 this.editorcore.pushValue();
23753 deferFocus : function(){
23754 this.focus.defer(10, this);
23758 focus : function(){
23759 this.editorcore.focus();
23765 onDestroy : function(){
23771 for (var i =0; i < this.toolbars.length;i++) {
23772 // fixme - ask toolbars for heights?
23773 this.toolbars[i].onDestroy();
23776 this.wrap.dom.innerHTML = '';
23777 this.wrap.remove();
23782 onFirstFocus : function(){
23783 //Roo.log("onFirstFocus");
23784 this.editorcore.onFirstFocus();
23785 for (var i =0; i < this.toolbars.length;i++) {
23786 this.toolbars[i].onFirstFocus();
23792 syncValue : function()
23794 this.editorcore.syncValue();
23797 pushValue : function()
23799 this.editorcore.pushValue();
23803 // hide stuff that is not compatible
23817 * @event specialkey
23821 * @cfg {String} fieldClass @hide
23824 * @cfg {String} focusClass @hide
23827 * @cfg {String} autoCreate @hide
23830 * @cfg {String} inputType @hide
23833 * @cfg {String} invalidClass @hide
23836 * @cfg {String} invalidText @hide
23839 * @cfg {String} msgFx @hide
23842 * @cfg {String} validateOnBlur @hide
23851 Roo.namespace('Roo.bootstrap.htmleditor');
23853 * @class Roo.bootstrap.HtmlEditorToolbar1
23858 new Roo.bootstrap.HtmlEditor({
23861 new Roo.bootstrap.HtmlEditorToolbar1({
23862 disable : { fonts: 1 , format: 1, ..., ... , ...],
23868 * @cfg {Object} disable List of elements to disable..
23869 * @cfg {Array} btns List of additional buttons.
23873 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
23876 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
23879 Roo.apply(this, config);
23881 // default disabled, based on 'good practice'..
23882 this.disable = this.disable || {};
23883 Roo.applyIf(this.disable, {
23886 specialElements : true
23888 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
23890 this.editor = config.editor;
23891 this.editorcore = config.editor.editorcore;
23893 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
23895 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
23896 // dont call parent... till later.
23898 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
23903 editorcore : false,
23908 "h1","h2","h3","h4","h5","h6",
23910 "abbr", "acronym", "address", "cite", "samp", "var",
23914 onRender : function(ct, position)
23916 // Roo.log("Call onRender: " + this.xtype);
23918 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
23920 this.el.dom.style.marginBottom = '0';
23922 var editorcore = this.editorcore;
23923 var editor= this.editor;
23926 var btn = function(id,cmd , toggle, handler, html){
23928 var event = toggle ? 'toggle' : 'click';
23933 xns: Roo.bootstrap,
23936 enableToggle:toggle !== false,
23938 pressed : toggle ? false : null,
23941 a.listeners[toggle ? 'toggle' : 'click'] = function() {
23942 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
23948 // var cb_box = function...
23953 xns: Roo.bootstrap,
23954 glyphicon : 'font',
23958 xns: Roo.bootstrap,
23962 Roo.each(this.formats, function(f) {
23963 style.menu.items.push({
23965 xns: Roo.bootstrap,
23966 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
23971 editorcore.insertTag(this.tagname);
23978 children.push(style);
23980 btn('bold',false,true);
23981 btn('italic',false,true);
23982 btn('align-left', 'justifyleft',true);
23983 btn('align-center', 'justifycenter',true);
23984 btn('align-right' , 'justifyright',true);
23985 btn('link', false, false, function(btn) {
23986 //Roo.log("create link?");
23987 var url = prompt(this.createLinkText, this.defaultLinkValue);
23988 if(url && url != 'http:/'+'/'){
23989 this.editorcore.relayCmd('createlink', url);
23992 btn('list','insertunorderedlist',true);
23993 btn('pencil', false,true, function(btn){
23995 this.toggleSourceEdit(btn.pressed);
23998 if (this.editor.btns.length > 0) {
23999 for (var i = 0; i<this.editor.btns.length; i++) {
24000 children.push(this.editor.btns[i]);
24008 xns: Roo.bootstrap,
24013 xns: Roo.bootstrap,
24018 cog.menu.items.push({
24020 xns: Roo.bootstrap,
24021 html : Clean styles,
24026 editorcore.insertTag(this.tagname);
24035 this.xtype = 'NavSimplebar';
24037 for(var i=0;i< children.length;i++) {
24039 this.buttons.add(this.addxtypeChild(children[i]));
24043 editor.on('editorevent', this.updateToolbar, this);
24045 onBtnClick : function(id)
24047 this.editorcore.relayCmd(id);
24048 this.editorcore.focus();
24052 * Protected method that will not generally be called directly. It triggers
24053 * a toolbar update by reading the markup state of the current selection in the editor.
24055 updateToolbar: function(){
24057 if(!this.editorcore.activated){
24058 this.editor.onFirstFocus(); // is this neeed?
24062 var btns = this.buttons;
24063 var doc = this.editorcore.doc;
24064 btns.get('bold').setActive(doc.queryCommandState('bold'));
24065 btns.get('italic').setActive(doc.queryCommandState('italic'));
24066 //btns.get('underline').setActive(doc.queryCommandState('underline'));
24068 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
24069 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
24070 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
24072 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
24073 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
24076 var ans = this.editorcore.getAllAncestors();
24077 if (this.formatCombo) {
24080 var store = this.formatCombo.store;
24081 this.formatCombo.setValue("");
24082 for (var i =0; i < ans.length;i++) {
24083 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
24085 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
24093 // hides menus... - so this cant be on a menu...
24094 Roo.bootstrap.MenuMgr.hideAll();
24096 Roo.bootstrap.MenuMgr.hideAll();
24097 //this.editorsyncValue();
24099 onFirstFocus: function() {
24100 this.buttons.each(function(item){
24104 toggleSourceEdit : function(sourceEditMode){
24107 if(sourceEditMode){
24108 Roo.log("disabling buttons");
24109 this.buttons.each( function(item){
24110 if(item.cmd != 'pencil'){
24116 Roo.log("enabling buttons");
24117 if(this.editorcore.initialized){
24118 this.buttons.each( function(item){
24124 Roo.log("calling toggole on editor");
24125 // tell the editor that it's been pressed..
24126 this.editor.toggleSourceEdit(sourceEditMode);
24136 * @class Roo.bootstrap.Table.AbstractSelectionModel
24137 * @extends Roo.util.Observable
24138 * Abstract base class for grid SelectionModels. It provides the interface that should be
24139 * implemented by descendant classes. This class should not be directly instantiated.
24142 Roo.bootstrap.Table.AbstractSelectionModel = function(){
24143 this.locked = false;
24144 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
24148 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
24149 /** @ignore Called by the grid automatically. Do not call directly. */
24150 init : function(grid){
24156 * Locks the selections.
24159 this.locked = true;
24163 * Unlocks the selections.
24165 unlock : function(){
24166 this.locked = false;
24170 * Returns true if the selections are locked.
24171 * @return {Boolean}
24173 isLocked : function(){
24174 return this.locked;
24178 * @extends Roo.bootstrap.Table.AbstractSelectionModel
24179 * @class Roo.bootstrap.Table.RowSelectionModel
24180 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
24181 * It supports multiple selections and keyboard selection/navigation.
24183 * @param {Object} config
24186 Roo.bootstrap.Table.RowSelectionModel = function(config){
24187 Roo.apply(this, config);
24188 this.selections = new Roo.util.MixedCollection(false, function(o){
24193 this.lastActive = false;
24197 * @event selectionchange
24198 * Fires when the selection changes
24199 * @param {SelectionModel} this
24201 "selectionchange" : true,
24203 * @event afterselectionchange
24204 * Fires after the selection changes (eg. by key press or clicking)
24205 * @param {SelectionModel} this
24207 "afterselectionchange" : true,
24209 * @event beforerowselect
24210 * Fires when a row is selected being selected, return false to cancel.
24211 * @param {SelectionModel} this
24212 * @param {Number} rowIndex The selected index
24213 * @param {Boolean} keepExisting False if other selections will be cleared
24215 "beforerowselect" : true,
24218 * Fires when a row is selected.
24219 * @param {SelectionModel} this
24220 * @param {Number} rowIndex The selected index
24221 * @param {Roo.data.Record} r The record
24223 "rowselect" : true,
24225 * @event rowdeselect
24226 * Fires when a row is deselected.
24227 * @param {SelectionModel} this
24228 * @param {Number} rowIndex The selected index
24230 "rowdeselect" : true
24232 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
24233 this.locked = false;
24236 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
24238 * @cfg {Boolean} singleSelect
24239 * True to allow selection of only one row at a time (defaults to false)
24241 singleSelect : false,
24244 initEvents : function()
24247 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
24248 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
24249 //}else{ // allow click to work like normal
24250 // this.grid.on("rowclick", this.handleDragableRowClick, this);
24252 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
24253 this.grid.on("rowclick", this.handleMouseDown, this);
24255 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
24256 "up" : function(e){
24258 this.selectPrevious(e.shiftKey);
24259 }else if(this.last !== false && this.lastActive !== false){
24260 var last = this.last;
24261 this.selectRange(this.last, this.lastActive-1);
24262 this.grid.getView().focusRow(this.lastActive);
24263 if(last !== false){
24267 this.selectFirstRow();
24269 this.fireEvent("afterselectionchange", this);
24271 "down" : function(e){
24273 this.selectNext(e.shiftKey);
24274 }else if(this.last !== false && this.lastActive !== false){
24275 var last = this.last;
24276 this.selectRange(this.last, this.lastActive+1);
24277 this.grid.getView().focusRow(this.lastActive);
24278 if(last !== false){
24282 this.selectFirstRow();
24284 this.fireEvent("afterselectionchange", this);
24288 this.grid.store.on('load', function(){
24289 this.selections.clear();
24292 var view = this.grid.view;
24293 view.on("refresh", this.onRefresh, this);
24294 view.on("rowupdated", this.onRowUpdated, this);
24295 view.on("rowremoved", this.onRemove, this);
24300 onRefresh : function()
24302 var ds = this.grid.store, i, v = this.grid.view;
24303 var s = this.selections;
24304 s.each(function(r){
24305 if((i = ds.indexOfId(r.id)) != -1){
24314 onRemove : function(v, index, r){
24315 this.selections.remove(r);
24319 onRowUpdated : function(v, index, r){
24320 if(this.isSelected(r)){
24321 v.onRowSelect(index);
24327 * @param {Array} records The records to select
24328 * @param {Boolean} keepExisting (optional) True to keep existing selections
24330 selectRecords : function(records, keepExisting)
24333 this.clearSelections();
24335 var ds = this.grid.store;
24336 for(var i = 0, len = records.length; i < len; i++){
24337 this.selectRow(ds.indexOf(records[i]), true);
24342 * Gets the number of selected rows.
24345 getCount : function(){
24346 return this.selections.length;
24350 * Selects the first row in the grid.
24352 selectFirstRow : function(){
24357 * Select the last row.
24358 * @param {Boolean} keepExisting (optional) True to keep existing selections
24360 selectLastRow : function(keepExisting){
24361 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
24362 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
24366 * Selects the row immediately following the last selected row.
24367 * @param {Boolean} keepExisting (optional) True to keep existing selections
24369 selectNext : function(keepExisting)
24371 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
24372 this.selectRow(this.last+1, keepExisting);
24373 this.grid.getView().focusRow(this.last);
24378 * Selects the row that precedes the last selected row.
24379 * @param {Boolean} keepExisting (optional) True to keep existing selections
24381 selectPrevious : function(keepExisting){
24383 this.selectRow(this.last-1, keepExisting);
24384 this.grid.getView().focusRow(this.last);
24389 * Returns the selected records
24390 * @return {Array} Array of selected records
24392 getSelections : function(){
24393 return [].concat(this.selections.items);
24397 * Returns the first selected record.
24400 getSelected : function(){
24401 return this.selections.itemAt(0);
24406 * Clears all selections.
24408 clearSelections : function(fast)
24414 var ds = this.grid.store;
24415 var s = this.selections;
24416 s.each(function(r){
24417 this.deselectRow(ds.indexOfId(r.id));
24421 this.selections.clear();
24428 * Selects all rows.
24430 selectAll : function(){
24434 this.selections.clear();
24435 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
24436 this.selectRow(i, true);
24441 * Returns True if there is a selection.
24442 * @return {Boolean}
24444 hasSelection : function(){
24445 return this.selections.length > 0;
24449 * Returns True if the specified row is selected.
24450 * @param {Number/Record} record The record or index of the record to check
24451 * @return {Boolean}
24453 isSelected : function(index){
24454 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
24455 return (r && this.selections.key(r.id) ? true : false);
24459 * Returns True if the specified record id is selected.
24460 * @param {String} id The id of record to check
24461 * @return {Boolean}
24463 isIdSelected : function(id){
24464 return (this.selections.key(id) ? true : false);
24469 handleMouseDBClick : function(e, t){
24473 handleMouseDown : function(e, t)
24475 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
24476 if(this.isLocked() || rowIndex < 0 ){
24479 if(e.shiftKey && this.last !== false){
24480 var last = this.last;
24481 this.selectRange(last, rowIndex, e.ctrlKey);
24482 this.last = last; // reset the last
24486 var isSelected = this.isSelected(rowIndex);
24487 //Roo.log("select row:" + rowIndex);
24489 this.deselectRow(rowIndex);
24491 this.selectRow(rowIndex, true);
24495 if(e.button !== 0 && isSelected){
24496 alert('rowIndex 2: ' + rowIndex);
24497 view.focusRow(rowIndex);
24498 }else if(e.ctrlKey && isSelected){
24499 this.deselectRow(rowIndex);
24500 }else if(!isSelected){
24501 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
24502 view.focusRow(rowIndex);
24506 this.fireEvent("afterselectionchange", this);
24509 handleDragableRowClick : function(grid, rowIndex, e)
24511 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
24512 this.selectRow(rowIndex, false);
24513 grid.view.focusRow(rowIndex);
24514 this.fireEvent("afterselectionchange", this);
24519 * Selects multiple rows.
24520 * @param {Array} rows Array of the indexes of the row to select
24521 * @param {Boolean} keepExisting (optional) True to keep existing selections
24523 selectRows : function(rows, keepExisting){
24525 this.clearSelections();
24527 for(var i = 0, len = rows.length; i < len; i++){
24528 this.selectRow(rows[i], true);
24533 * Selects a range of rows. All rows in between startRow and endRow are also selected.
24534 * @param {Number} startRow The index of the first row in the range
24535 * @param {Number} endRow The index of the last row in the range
24536 * @param {Boolean} keepExisting (optional) True to retain existing selections
24538 selectRange : function(startRow, endRow, keepExisting){
24543 this.clearSelections();
24545 if(startRow <= endRow){
24546 for(var i = startRow; i <= endRow; i++){
24547 this.selectRow(i, true);
24550 for(var i = startRow; i >= endRow; i--){
24551 this.selectRow(i, true);
24557 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
24558 * @param {Number} startRow The index of the first row in the range
24559 * @param {Number} endRow The index of the last row in the range
24561 deselectRange : function(startRow, endRow, preventViewNotify){
24565 for(var i = startRow; i <= endRow; i++){
24566 this.deselectRow(i, preventViewNotify);
24572 * @param {Number} row The index of the row to select
24573 * @param {Boolean} keepExisting (optional) True to keep existing selections
24575 selectRow : function(index, keepExisting, preventViewNotify)
24577 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
24580 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
24581 if(!keepExisting || this.singleSelect){
24582 this.clearSelections();
24585 var r = this.grid.store.getAt(index);
24586 //console.log('selectRow - record id :' + r.id);
24588 this.selections.add(r);
24589 this.last = this.lastActive = index;
24590 if(!preventViewNotify){
24591 var proxy = new Roo.Element(
24592 this.grid.getRowDom(index)
24594 proxy.addClass('bg-info info');
24596 this.fireEvent("rowselect", this, index, r);
24597 this.fireEvent("selectionchange", this);
24603 * @param {Number} row The index of the row to deselect
24605 deselectRow : function(index, preventViewNotify)
24610 if(this.last == index){
24613 if(this.lastActive == index){
24614 this.lastActive = false;
24617 var r = this.grid.store.getAt(index);
24622 this.selections.remove(r);
24623 //.console.log('deselectRow - record id :' + r.id);
24624 if(!preventViewNotify){
24626 var proxy = new Roo.Element(
24627 this.grid.getRowDom(index)
24629 proxy.removeClass('bg-info info');
24631 this.fireEvent("rowdeselect", this, index);
24632 this.fireEvent("selectionchange", this);
24636 restoreLast : function(){
24638 this.last = this._last;
24643 acceptsNav : function(row, col, cm){
24644 return !cm.isHidden(col) && cm.isCellEditable(col, row);
24648 onEditorKey : function(field, e){
24649 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
24654 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
24656 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
24658 }else if(k == e.ENTER && !e.ctrlKey){
24662 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
24664 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
24666 }else if(k == e.ESC){
24670 g.startEditing(newCell[0], newCell[1]);
24676 * Ext JS Library 1.1.1
24677 * Copyright(c) 2006-2007, Ext JS, LLC.
24679 * Originally Released Under LGPL - original licence link has changed is not relivant.
24682 * <script type="text/javascript">
24686 * @class Roo.bootstrap.PagingToolbar
24687 * @extends Roo.bootstrap.NavSimplebar
24688 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
24690 * Create a new PagingToolbar
24691 * @param {Object} config The config object
24692 * @param {Roo.data.Store} store
24694 Roo.bootstrap.PagingToolbar = function(config)
24696 // old args format still supported... - xtype is prefered..
24697 // created from xtype...
24699 this.ds = config.dataSource;
24701 if (config.store && !this.ds) {
24702 this.store= Roo.factory(config.store, Roo.data);
24703 this.ds = this.store;
24704 this.ds.xmodule = this.xmodule || false;
24707 this.toolbarItems = [];
24708 if (config.items) {
24709 this.toolbarItems = config.items;
24712 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
24717 this.bind(this.ds);
24720 if (Roo.bootstrap.version == 4) {
24721 this.navgroup = new Roo.bootstrap.ButtonGroup({ cls: 'pagination' });
24723 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
24728 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
24730 * @cfg {Roo.data.Store} dataSource
24731 * The underlying data store providing the paged data
24734 * @cfg {String/HTMLElement/Element} container
24735 * container The id or element that will contain the toolbar
24738 * @cfg {Boolean} displayInfo
24739 * True to display the displayMsg (defaults to false)
24742 * @cfg {Number} pageSize
24743 * The number of records to display per page (defaults to 20)
24747 * @cfg {String} displayMsg
24748 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
24750 displayMsg : 'Displaying {0} - {1} of {2}',
24752 * @cfg {String} emptyMsg
24753 * The message to display when no records are found (defaults to "No data to display")
24755 emptyMsg : 'No data to display',
24757 * Customizable piece of the default paging text (defaults to "Page")
24760 beforePageText : "Page",
24762 * Customizable piece of the default paging text (defaults to "of %0")
24765 afterPageText : "of {0}",
24767 * Customizable piece of the default paging text (defaults to "First Page")
24770 firstText : "First Page",
24772 * Customizable piece of the default paging text (defaults to "Previous Page")
24775 prevText : "Previous Page",
24777 * Customizable piece of the default paging text (defaults to "Next Page")
24780 nextText : "Next Page",
24782 * Customizable piece of the default paging text (defaults to "Last Page")
24785 lastText : "Last Page",
24787 * Customizable piece of the default paging text (defaults to "Refresh")
24790 refreshText : "Refresh",
24794 onRender : function(ct, position)
24796 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
24797 this.navgroup.parentId = this.id;
24798 this.navgroup.onRender(this.el, null);
24799 // add the buttons to the navgroup
24801 if(this.displayInfo){
24802 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
24803 this.displayEl = this.el.select('.x-paging-info', true).first();
24804 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
24805 // this.displayEl = navel.el.select('span',true).first();
24811 Roo.each(_this.buttons, function(e){ // this might need to use render????
24812 Roo.factory(e).render(_this.el);
24816 Roo.each(_this.toolbarItems, function(e) {
24817 _this.navgroup.addItem(e);
24821 this.first = this.navgroup.addItem({
24822 tooltip: this.firstText,
24823 cls: "prev btn-outline-secondary",
24824 html : ' <i class="fa fa-step-backward"></i>',
24826 preventDefault: true,
24827 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
24830 this.prev = this.navgroup.addItem({
24831 tooltip: this.prevText,
24832 cls: "prev btn-outline-secondary",
24833 html : ' <i class="fa fa-backward"></i>',
24835 preventDefault: true,
24836 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
24838 //this.addSeparator();
24841 var field = this.navgroup.addItem( {
24843 cls : 'x-paging-position btn-outline-secondary',
24845 html : this.beforePageText +
24846 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
24847 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
24850 this.field = field.el.select('input', true).first();
24851 this.field.on("keydown", this.onPagingKeydown, this);
24852 this.field.on("focus", function(){this.dom.select();});
24855 this.afterTextEl = field.el.select('.x-paging-after',true).first();
24856 //this.field.setHeight(18);
24857 //this.addSeparator();
24858 this.next = this.navgroup.addItem({
24859 tooltip: this.nextText,
24860 cls: "next btn-outline-secondary",
24861 html : ' <i class="fa fa-forward"></i>',
24863 preventDefault: true,
24864 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
24866 this.last = this.navgroup.addItem({
24867 tooltip: this.lastText,
24868 html : ' <i class="fa fa-step-forward"></i>',
24869 cls: "next btn-outline-secondary",
24871 preventDefault: true,
24872 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
24874 //this.addSeparator();
24875 this.loading = this.navgroup.addItem({
24876 tooltip: this.refreshText,
24877 cls: "btn-outline-secondary",
24878 html : ' <i class="fa fa-refresh"></i>',
24879 preventDefault: true,
24880 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
24886 updateInfo : function(){
24887 if(this.displayEl){
24888 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
24889 var msg = count == 0 ?
24893 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
24895 this.displayEl.update(msg);
24900 onLoad : function(ds, r, o)
24902 this.cursor = o.params.start ? o.params.start : 0;
24904 var d = this.getPageData(),
24909 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
24910 this.field.dom.value = ap;
24911 this.first.setDisabled(ap == 1);
24912 this.prev.setDisabled(ap == 1);
24913 this.next.setDisabled(ap == ps);
24914 this.last.setDisabled(ap == ps);
24915 this.loading.enable();
24920 getPageData : function(){
24921 var total = this.ds.getTotalCount();
24924 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
24925 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
24930 onLoadError : function(){
24931 this.loading.enable();
24935 onPagingKeydown : function(e){
24936 var k = e.getKey();
24937 var d = this.getPageData();
24939 var v = this.field.dom.value, pageNum;
24940 if(!v || isNaN(pageNum = parseInt(v, 10))){
24941 this.field.dom.value = d.activePage;
24944 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
24945 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24948 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))
24950 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
24951 this.field.dom.value = pageNum;
24952 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
24955 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
24957 var v = this.field.dom.value, pageNum;
24958 var increment = (e.shiftKey) ? 10 : 1;
24959 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
24962 if(!v || isNaN(pageNum = parseInt(v, 10))) {
24963 this.field.dom.value = d.activePage;
24966 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
24968 this.field.dom.value = parseInt(v, 10) + increment;
24969 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
24970 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24977 beforeLoad : function(){
24979 this.loading.disable();
24984 onClick : function(which){
24993 ds.load({params:{start: 0, limit: this.pageSize}});
24996 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
24999 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
25002 var total = ds.getTotalCount();
25003 var extra = total % this.pageSize;
25004 var lastStart = extra ? (total - extra) : total-this.pageSize;
25005 ds.load({params:{start: lastStart, limit: this.pageSize}});
25008 ds.load({params:{start: this.cursor, limit: this.pageSize}});
25014 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
25015 * @param {Roo.data.Store} store The data store to unbind
25017 unbind : function(ds){
25018 ds.un("beforeload", this.beforeLoad, this);
25019 ds.un("load", this.onLoad, this);
25020 ds.un("loadexception", this.onLoadError, this);
25021 ds.un("remove", this.updateInfo, this);
25022 ds.un("add", this.updateInfo, this);
25023 this.ds = undefined;
25027 * Binds the paging toolbar to the specified {@link Roo.data.Store}
25028 * @param {Roo.data.Store} store The data store to bind
25030 bind : function(ds){
25031 ds.on("beforeload", this.beforeLoad, this);
25032 ds.on("load", this.onLoad, this);
25033 ds.on("loadexception", this.onLoadError, this);
25034 ds.on("remove", this.updateInfo, this);
25035 ds.on("add", this.updateInfo, this);
25046 * @class Roo.bootstrap.MessageBar
25047 * @extends Roo.bootstrap.Component
25048 * Bootstrap MessageBar class
25049 * @cfg {String} html contents of the MessageBar
25050 * @cfg {String} weight (info | success | warning | danger) default info
25051 * @cfg {String} beforeClass insert the bar before the given class
25052 * @cfg {Boolean} closable (true | false) default false
25053 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
25056 * Create a new Element
25057 * @param {Object} config The config object
25060 Roo.bootstrap.MessageBar = function(config){
25061 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
25064 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
25070 beforeClass: 'bootstrap-sticky-wrap',
25072 getAutoCreate : function(){
25076 cls: 'alert alert-dismissable alert-' + this.weight,
25081 html: this.html || ''
25087 cfg.cls += ' alert-messages-fixed';
25101 onRender : function(ct, position)
25103 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
25106 var cfg = Roo.apply({}, this.getAutoCreate());
25110 cfg.cls += ' ' + this.cls;
25113 cfg.style = this.style;
25115 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
25117 this.el.setVisibilityMode(Roo.Element.DISPLAY);
25120 this.el.select('>button.close').on('click', this.hide, this);
25126 if (!this.rendered) {
25132 this.fireEvent('show', this);
25138 if (!this.rendered) {
25144 this.fireEvent('hide', this);
25147 update : function()
25149 // var e = this.el.dom.firstChild;
25151 // if(this.closable){
25152 // e = e.nextSibling;
25155 // e.data = this.html || '';
25157 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
25173 * @class Roo.bootstrap.Graph
25174 * @extends Roo.bootstrap.Component
25175 * Bootstrap Graph class
25179 @cfg {String} graphtype bar | vbar | pie
25180 @cfg {number} g_x coodinator | centre x (pie)
25181 @cfg {number} g_y coodinator | centre y (pie)
25182 @cfg {number} g_r radius (pie)
25183 @cfg {number} g_height height of the chart (respected by all elements in the set)
25184 @cfg {number} g_width width of the chart (respected by all elements in the set)
25185 @cfg {Object} title The title of the chart
25188 -opts (object) options for the chart
25190 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
25191 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
25193 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.
25194 o stacked (boolean) whether or not to tread values as in a stacked bar chart
25196 o stretch (boolean)
25198 -opts (object) options for the pie
25201 o startAngle (number)
25202 o endAngle (number)
25206 * Create a new Input
25207 * @param {Object} config The config object
25210 Roo.bootstrap.Graph = function(config){
25211 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
25217 * The img click event for the img.
25218 * @param {Roo.EventObject} e
25224 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
25235 //g_colors: this.colors,
25242 getAutoCreate : function(){
25253 onRender : function(ct,position){
25256 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
25258 if (typeof(Raphael) == 'undefined') {
25259 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
25263 this.raphael = Raphael(this.el.dom);
25265 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25266 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25267 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25268 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
25270 r.text(160, 10, "Single Series Chart").attr(txtattr);
25271 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
25272 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
25273 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
25275 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
25276 r.barchart(330, 10, 300, 220, data1);
25277 r.barchart(10, 250, 300, 220, data2, {stacked: true});
25278 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
25281 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25282 // r.barchart(30, 30, 560, 250, xdata, {
25283 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
25284 // axis : "0 0 1 1",
25285 // axisxlabels : xdata
25286 // //yvalues : cols,
25289 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25291 // this.load(null,xdata,{
25292 // axis : "0 0 1 1",
25293 // axisxlabels : xdata
25298 load : function(graphtype,xdata,opts)
25300 this.raphael.clear();
25302 graphtype = this.graphtype;
25307 var r = this.raphael,
25308 fin = function () {
25309 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
25311 fout = function () {
25312 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
25314 pfin = function() {
25315 this.sector.stop();
25316 this.sector.scale(1.1, 1.1, this.cx, this.cy);
25319 this.label[0].stop();
25320 this.label[0].attr({ r: 7.5 });
25321 this.label[1].attr({ "font-weight": 800 });
25324 pfout = function() {
25325 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
25328 this.label[0].animate({ r: 5 }, 500, "bounce");
25329 this.label[1].attr({ "font-weight": 400 });
25335 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25338 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25341 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
25342 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
25344 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
25351 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
25356 setTitle: function(o)
25361 initEvents: function() {
25364 this.el.on('click', this.onClick, this);
25368 onClick : function(e)
25370 Roo.log('img onclick');
25371 this.fireEvent('click', this, e);
25383 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25386 * @class Roo.bootstrap.dash.NumberBox
25387 * @extends Roo.bootstrap.Component
25388 * Bootstrap NumberBox class
25389 * @cfg {String} headline Box headline
25390 * @cfg {String} content Box content
25391 * @cfg {String} icon Box icon
25392 * @cfg {String} footer Footer text
25393 * @cfg {String} fhref Footer href
25396 * Create a new NumberBox
25397 * @param {Object} config The config object
25401 Roo.bootstrap.dash.NumberBox = function(config){
25402 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
25406 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
25415 getAutoCreate : function(){
25419 cls : 'small-box ',
25427 cls : 'roo-headline',
25428 html : this.headline
25432 cls : 'roo-content',
25433 html : this.content
25447 cls : 'ion ' + this.icon
25456 cls : 'small-box-footer',
25457 href : this.fhref || '#',
25461 cfg.cn.push(footer);
25468 onRender : function(ct,position){
25469 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
25476 setHeadline: function (value)
25478 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
25481 setFooter: function (value, href)
25483 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
25486 this.el.select('a.small-box-footer',true).first().attr('href', href);
25491 setContent: function (value)
25493 this.el.select('.roo-content',true).first().dom.innerHTML = value;
25496 initEvents: function()
25510 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25513 * @class Roo.bootstrap.dash.TabBox
25514 * @extends Roo.bootstrap.Component
25515 * Bootstrap TabBox class
25516 * @cfg {String} title Title of the TabBox
25517 * @cfg {String} icon Icon of the TabBox
25518 * @cfg {Boolean} showtabs (true|false) show the tabs default true
25519 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
25522 * Create a new TabBox
25523 * @param {Object} config The config object
25527 Roo.bootstrap.dash.TabBox = function(config){
25528 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
25533 * When a pane is added
25534 * @param {Roo.bootstrap.dash.TabPane} pane
25538 * @event activatepane
25539 * When a pane is activated
25540 * @param {Roo.bootstrap.dash.TabPane} pane
25542 "activatepane" : true
25550 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
25555 tabScrollable : false,
25557 getChildContainer : function()
25559 return this.el.select('.tab-content', true).first();
25562 getAutoCreate : function(){
25566 cls: 'pull-left header',
25574 cls: 'fa ' + this.icon
25580 cls: 'nav nav-tabs pull-right',
25586 if(this.tabScrollable){
25593 cls: 'nav nav-tabs pull-right',
25604 cls: 'nav-tabs-custom',
25609 cls: 'tab-content no-padding',
25617 initEvents : function()
25619 //Roo.log('add add pane handler');
25620 this.on('addpane', this.onAddPane, this);
25623 * Updates the box title
25624 * @param {String} html to set the title to.
25626 setTitle : function(value)
25628 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
25630 onAddPane : function(pane)
25632 this.panes.push(pane);
25633 //Roo.log('addpane');
25635 // tabs are rendere left to right..
25636 if(!this.showtabs){
25640 var ctr = this.el.select('.nav-tabs', true).first();
25643 var existing = ctr.select('.nav-tab',true);
25644 var qty = existing.getCount();;
25647 var tab = ctr.createChild({
25649 cls : 'nav-tab' + (qty ? '' : ' active'),
25657 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
25660 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
25662 pane.el.addClass('active');
25667 onTabClick : function(ev,un,ob,pane)
25669 //Roo.log('tab - prev default');
25670 ev.preventDefault();
25673 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
25674 pane.tab.addClass('active');
25675 //Roo.log(pane.title);
25676 this.getChildContainer().select('.tab-pane',true).removeClass('active');
25677 // technically we should have a deactivate event.. but maybe add later.
25678 // and it should not de-activate the selected tab...
25679 this.fireEvent('activatepane', pane);
25680 pane.el.addClass('active');
25681 pane.fireEvent('activate');
25686 getActivePane : function()
25689 Roo.each(this.panes, function(p) {
25690 if(p.el.hasClass('active')){
25711 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25713 * @class Roo.bootstrap.TabPane
25714 * @extends Roo.bootstrap.Component
25715 * Bootstrap TabPane class
25716 * @cfg {Boolean} active (false | true) Default false
25717 * @cfg {String} title title of panel
25721 * Create a new TabPane
25722 * @param {Object} config The config object
25725 Roo.bootstrap.dash.TabPane = function(config){
25726 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
25732 * When a pane is activated
25733 * @param {Roo.bootstrap.dash.TabPane} pane
25740 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
25745 // the tabBox that this is attached to.
25748 getAutoCreate : function()
25756 cfg.cls += ' active';
25761 initEvents : function()
25763 //Roo.log('trigger add pane handler');
25764 this.parent().fireEvent('addpane', this)
25768 * Updates the tab title
25769 * @param {String} html to set the title to.
25771 setTitle: function(str)
25777 this.tab.select('a', true).first().dom.innerHTML = str;
25794 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25797 * @class Roo.bootstrap.menu.Menu
25798 * @extends Roo.bootstrap.Component
25799 * Bootstrap Menu class - container for Menu
25800 * @cfg {String} html Text of the menu
25801 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
25802 * @cfg {String} icon Font awesome icon
25803 * @cfg {String} pos Menu align to (top | bottom) default bottom
25807 * Create a new Menu
25808 * @param {Object} config The config object
25812 Roo.bootstrap.menu.Menu = function(config){
25813 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
25817 * @event beforeshow
25818 * Fires before this menu is displayed
25819 * @param {Roo.bootstrap.menu.Menu} this
25823 * @event beforehide
25824 * Fires before this menu is hidden
25825 * @param {Roo.bootstrap.menu.Menu} this
25830 * Fires after this menu is displayed
25831 * @param {Roo.bootstrap.menu.Menu} this
25836 * Fires after this menu is hidden
25837 * @param {Roo.bootstrap.menu.Menu} this
25842 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
25843 * @param {Roo.bootstrap.menu.Menu} this
25844 * @param {Roo.EventObject} e
25851 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
25855 weight : 'default',
25860 getChildContainer : function() {
25861 if(this.isSubMenu){
25865 return this.el.select('ul.dropdown-menu', true).first();
25868 getAutoCreate : function()
25873 cls : 'roo-menu-text',
25881 cls : 'fa ' + this.icon
25892 cls : 'dropdown-button btn btn-' + this.weight,
25897 cls : 'dropdown-toggle btn btn-' + this.weight,
25907 cls : 'dropdown-menu'
25913 if(this.pos == 'top'){
25914 cfg.cls += ' dropup';
25917 if(this.isSubMenu){
25920 cls : 'dropdown-menu'
25927 onRender : function(ct, position)
25929 this.isSubMenu = ct.hasClass('dropdown-submenu');
25931 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
25934 initEvents : function()
25936 if(this.isSubMenu){
25940 this.hidden = true;
25942 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
25943 this.triggerEl.on('click', this.onTriggerPress, this);
25945 this.buttonEl = this.el.select('button.dropdown-button', true).first();
25946 this.buttonEl.on('click', this.onClick, this);
25952 if(this.isSubMenu){
25956 return this.el.select('ul.dropdown-menu', true).first();
25959 onClick : function(e)
25961 this.fireEvent("click", this, e);
25964 onTriggerPress : function(e)
25966 if (this.isVisible()) {
25973 isVisible : function(){
25974 return !this.hidden;
25979 this.fireEvent("beforeshow", this);
25981 this.hidden = false;
25982 this.el.addClass('open');
25984 Roo.get(document).on("mouseup", this.onMouseUp, this);
25986 this.fireEvent("show", this);
25993 this.fireEvent("beforehide", this);
25995 this.hidden = true;
25996 this.el.removeClass('open');
25998 Roo.get(document).un("mouseup", this.onMouseUp);
26000 this.fireEvent("hide", this);
26003 onMouseUp : function()
26017 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
26020 * @class Roo.bootstrap.menu.Item
26021 * @extends Roo.bootstrap.Component
26022 * Bootstrap MenuItem class
26023 * @cfg {Boolean} submenu (true | false) default false
26024 * @cfg {String} html text of the item
26025 * @cfg {String} href the link
26026 * @cfg {Boolean} disable (true | false) default false
26027 * @cfg {Boolean} preventDefault (true | false) default true
26028 * @cfg {String} icon Font awesome icon
26029 * @cfg {String} pos Submenu align to (left | right) default right
26033 * Create a new Item
26034 * @param {Object} config The config object
26038 Roo.bootstrap.menu.Item = function(config){
26039 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
26043 * Fires when the mouse is hovering over this menu
26044 * @param {Roo.bootstrap.menu.Item} this
26045 * @param {Roo.EventObject} e
26050 * Fires when the mouse exits this menu
26051 * @param {Roo.bootstrap.menu.Item} this
26052 * @param {Roo.EventObject} e
26058 * The raw click event for the entire grid.
26059 * @param {Roo.EventObject} e
26065 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
26070 preventDefault: true,
26075 getAutoCreate : function()
26080 cls : 'roo-menu-item-text',
26088 cls : 'fa ' + this.icon
26097 href : this.href || '#',
26104 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
26108 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
26110 if(this.pos == 'left'){
26111 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
26118 initEvents : function()
26120 this.el.on('mouseover', this.onMouseOver, this);
26121 this.el.on('mouseout', this.onMouseOut, this);
26123 this.el.select('a', true).first().on('click', this.onClick, this);
26127 onClick : function(e)
26129 if(this.preventDefault){
26130 e.preventDefault();
26133 this.fireEvent("click", this, e);
26136 onMouseOver : function(e)
26138 if(this.submenu && this.pos == 'left'){
26139 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
26142 this.fireEvent("mouseover", this, e);
26145 onMouseOut : function(e)
26147 this.fireEvent("mouseout", this, e);
26159 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
26162 * @class Roo.bootstrap.menu.Separator
26163 * @extends Roo.bootstrap.Component
26164 * Bootstrap Separator class
26167 * Create a new Separator
26168 * @param {Object} config The config object
26172 Roo.bootstrap.menu.Separator = function(config){
26173 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
26176 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
26178 getAutoCreate : function(){
26199 * @class Roo.bootstrap.Tooltip
26200 * Bootstrap Tooltip class
26201 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
26202 * to determine which dom element triggers the tooltip.
26204 * It needs to add support for additional attributes like tooltip-position
26207 * Create a new Toolti
26208 * @param {Object} config The config object
26211 Roo.bootstrap.Tooltip = function(config){
26212 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
26214 this.alignment = Roo.bootstrap.Tooltip.alignment;
26216 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
26217 this.alignment = config.alignment;
26222 Roo.apply(Roo.bootstrap.Tooltip, {
26224 * @function init initialize tooltip monitoring.
26228 currentTip : false,
26229 currentRegion : false,
26235 Roo.get(document).on('mouseover', this.enter ,this);
26236 Roo.get(document).on('mouseout', this.leave, this);
26239 this.currentTip = new Roo.bootstrap.Tooltip();
26242 enter : function(ev)
26244 var dom = ev.getTarget();
26246 //Roo.log(['enter',dom]);
26247 var el = Roo.fly(dom);
26248 if (this.currentEl) {
26250 //Roo.log(this.currentEl);
26251 //Roo.log(this.currentEl.contains(dom));
26252 if (this.currentEl == el) {
26255 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
26261 if (this.currentTip.el) {
26262 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
26266 if(!el || el.dom == document){
26272 // you can not look for children, as if el is the body.. then everythign is the child..
26273 if (!el.attr('tooltip')) { //
26274 if (!el.select("[tooltip]").elements.length) {
26277 // is the mouse over this child...?
26278 bindEl = el.select("[tooltip]").first();
26279 var xy = ev.getXY();
26280 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
26281 //Roo.log("not in region.");
26284 //Roo.log("child element over..");
26287 this.currentEl = bindEl;
26288 this.currentTip.bind(bindEl);
26289 this.currentRegion = Roo.lib.Region.getRegion(dom);
26290 this.currentTip.enter();
26293 leave : function(ev)
26295 var dom = ev.getTarget();
26296 //Roo.log(['leave',dom]);
26297 if (!this.currentEl) {
26302 if (dom != this.currentEl.dom) {
26305 var xy = ev.getXY();
26306 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
26309 // only activate leave if mouse cursor is outside... bounding box..
26314 if (this.currentTip) {
26315 this.currentTip.leave();
26317 //Roo.log('clear currentEl');
26318 this.currentEl = false;
26323 'left' : ['r-l', [-2,0], 'right'],
26324 'right' : ['l-r', [2,0], 'left'],
26325 'bottom' : ['t-b', [0,2], 'top'],
26326 'top' : [ 'b-t', [0,-2], 'bottom']
26332 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
26337 delay : null, // can be { show : 300 , hide: 500}
26341 hoverState : null, //???
26343 placement : 'bottom',
26347 getAutoCreate : function(){
26354 cls : 'tooltip-arrow'
26357 cls : 'tooltip-inner'
26364 bind : function(el)
26370 enter : function () {
26372 if (this.timeout != null) {
26373 clearTimeout(this.timeout);
26376 this.hoverState = 'in';
26377 //Roo.log("enter - show");
26378 if (!this.delay || !this.delay.show) {
26383 this.timeout = setTimeout(function () {
26384 if (_t.hoverState == 'in') {
26387 }, this.delay.show);
26391 clearTimeout(this.timeout);
26393 this.hoverState = 'out';
26394 if (!this.delay || !this.delay.hide) {
26400 this.timeout = setTimeout(function () {
26401 //Roo.log("leave - timeout");
26403 if (_t.hoverState == 'out') {
26405 Roo.bootstrap.Tooltip.currentEl = false;
26410 show : function (msg)
26413 this.render(document.body);
26416 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
26418 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
26420 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
26422 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
26424 var placement = typeof this.placement == 'function' ?
26425 this.placement.call(this, this.el, on_el) :
26428 var autoToken = /\s?auto?\s?/i;
26429 var autoPlace = autoToken.test(placement);
26431 placement = placement.replace(autoToken, '') || 'top';
26435 //this.el.setXY([0,0]);
26437 //this.el.dom.style.display='block';
26439 //this.el.appendTo(on_el);
26441 var p = this.getPosition();
26442 var box = this.el.getBox();
26448 var align = this.alignment[placement];
26450 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
26452 if(placement == 'top' || placement == 'bottom'){
26454 placement = 'right';
26457 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
26458 placement = 'left';
26461 var scroll = Roo.select('body', true).first().getScroll();
26463 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
26467 align = this.alignment[placement];
26470 this.el.alignTo(this.bindEl, align[0],align[1]);
26471 //var arrow = this.el.select('.arrow',true).first();
26472 //arrow.set(align[2],
26474 this.el.addClass(placement);
26476 this.el.addClass('in fade');
26478 this.hoverState = null;
26480 if (this.el.hasClass('fade')) {
26491 //this.el.setXY([0,0]);
26492 this.el.removeClass('in');
26508 * @class Roo.bootstrap.LocationPicker
26509 * @extends Roo.bootstrap.Component
26510 * Bootstrap LocationPicker class
26511 * @cfg {Number} latitude Position when init default 0
26512 * @cfg {Number} longitude Position when init default 0
26513 * @cfg {Number} zoom default 15
26514 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
26515 * @cfg {Boolean} mapTypeControl default false
26516 * @cfg {Boolean} disableDoubleClickZoom default false
26517 * @cfg {Boolean} scrollwheel default true
26518 * @cfg {Boolean} streetViewControl default false
26519 * @cfg {Number} radius default 0
26520 * @cfg {String} locationName
26521 * @cfg {Boolean} draggable default true
26522 * @cfg {Boolean} enableAutocomplete default false
26523 * @cfg {Boolean} enableReverseGeocode default true
26524 * @cfg {String} markerTitle
26527 * Create a new LocationPicker
26528 * @param {Object} config The config object
26532 Roo.bootstrap.LocationPicker = function(config){
26534 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
26539 * Fires when the picker initialized.
26540 * @param {Roo.bootstrap.LocationPicker} this
26541 * @param {Google Location} location
26545 * @event positionchanged
26546 * Fires when the picker position changed.
26547 * @param {Roo.bootstrap.LocationPicker} this
26548 * @param {Google Location} location
26550 positionchanged : true,
26553 * Fires when the map resize.
26554 * @param {Roo.bootstrap.LocationPicker} this
26559 * Fires when the map show.
26560 * @param {Roo.bootstrap.LocationPicker} this
26565 * Fires when the map hide.
26566 * @param {Roo.bootstrap.LocationPicker} this
26571 * Fires when click the map.
26572 * @param {Roo.bootstrap.LocationPicker} this
26573 * @param {Map event} e
26577 * @event mapRightClick
26578 * Fires when right click the map.
26579 * @param {Roo.bootstrap.LocationPicker} this
26580 * @param {Map event} e
26582 mapRightClick : true,
26584 * @event markerClick
26585 * Fires when click the marker.
26586 * @param {Roo.bootstrap.LocationPicker} this
26587 * @param {Map event} e
26589 markerClick : true,
26591 * @event markerRightClick
26592 * Fires when right click the marker.
26593 * @param {Roo.bootstrap.LocationPicker} this
26594 * @param {Map event} e
26596 markerRightClick : true,
26598 * @event OverlayViewDraw
26599 * Fires when OverlayView Draw
26600 * @param {Roo.bootstrap.LocationPicker} this
26602 OverlayViewDraw : true,
26604 * @event OverlayViewOnAdd
26605 * Fires when OverlayView Draw
26606 * @param {Roo.bootstrap.LocationPicker} this
26608 OverlayViewOnAdd : true,
26610 * @event OverlayViewOnRemove
26611 * Fires when OverlayView Draw
26612 * @param {Roo.bootstrap.LocationPicker} this
26614 OverlayViewOnRemove : true,
26616 * @event OverlayViewShow
26617 * Fires when OverlayView Draw
26618 * @param {Roo.bootstrap.LocationPicker} this
26619 * @param {Pixel} cpx
26621 OverlayViewShow : true,
26623 * @event OverlayViewHide
26624 * Fires when OverlayView Draw
26625 * @param {Roo.bootstrap.LocationPicker} this
26627 OverlayViewHide : true,
26629 * @event loadexception
26630 * Fires when load google lib failed.
26631 * @param {Roo.bootstrap.LocationPicker} this
26633 loadexception : true
26638 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
26640 gMapContext: false,
26646 mapTypeControl: false,
26647 disableDoubleClickZoom: false,
26649 streetViewControl: false,
26653 enableAutocomplete: false,
26654 enableReverseGeocode: true,
26657 getAutoCreate: function()
26662 cls: 'roo-location-picker'
26668 initEvents: function(ct, position)
26670 if(!this.el.getWidth() || this.isApplied()){
26674 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26679 initial: function()
26681 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
26682 this.fireEvent('loadexception', this);
26686 if(!this.mapTypeId){
26687 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
26690 this.gMapContext = this.GMapContext();
26692 this.initOverlayView();
26694 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
26698 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
26699 _this.setPosition(_this.gMapContext.marker.position);
26702 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
26703 _this.fireEvent('mapClick', this, event);
26707 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
26708 _this.fireEvent('mapRightClick', this, event);
26712 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
26713 _this.fireEvent('markerClick', this, event);
26717 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
26718 _this.fireEvent('markerRightClick', this, event);
26722 this.setPosition(this.gMapContext.location);
26724 this.fireEvent('initial', this, this.gMapContext.location);
26727 initOverlayView: function()
26731 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
26735 _this.fireEvent('OverlayViewDraw', _this);
26740 _this.fireEvent('OverlayViewOnAdd', _this);
26743 onRemove: function()
26745 _this.fireEvent('OverlayViewOnRemove', _this);
26748 show: function(cpx)
26750 _this.fireEvent('OverlayViewShow', _this, cpx);
26755 _this.fireEvent('OverlayViewHide', _this);
26761 fromLatLngToContainerPixel: function(event)
26763 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
26766 isApplied: function()
26768 return this.getGmapContext() == false ? false : true;
26771 getGmapContext: function()
26773 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
26776 GMapContext: function()
26778 var position = new google.maps.LatLng(this.latitude, this.longitude);
26780 var _map = new google.maps.Map(this.el.dom, {
26783 mapTypeId: this.mapTypeId,
26784 mapTypeControl: this.mapTypeControl,
26785 disableDoubleClickZoom: this.disableDoubleClickZoom,
26786 scrollwheel: this.scrollwheel,
26787 streetViewControl: this.streetViewControl,
26788 locationName: this.locationName,
26789 draggable: this.draggable,
26790 enableAutocomplete: this.enableAutocomplete,
26791 enableReverseGeocode: this.enableReverseGeocode
26794 var _marker = new google.maps.Marker({
26795 position: position,
26797 title: this.markerTitle,
26798 draggable: this.draggable
26805 location: position,
26806 radius: this.radius,
26807 locationName: this.locationName,
26808 addressComponents: {
26809 formatted_address: null,
26810 addressLine1: null,
26811 addressLine2: null,
26813 streetNumber: null,
26817 stateOrProvince: null
26820 domContainer: this.el.dom,
26821 geodecoder: new google.maps.Geocoder()
26825 drawCircle: function(center, radius, options)
26827 if (this.gMapContext.circle != null) {
26828 this.gMapContext.circle.setMap(null);
26832 options = Roo.apply({}, options, {
26833 strokeColor: "#0000FF",
26834 strokeOpacity: .35,
26836 fillColor: "#0000FF",
26840 options.map = this.gMapContext.map;
26841 options.radius = radius;
26842 options.center = center;
26843 this.gMapContext.circle = new google.maps.Circle(options);
26844 return this.gMapContext.circle;
26850 setPosition: function(location)
26852 this.gMapContext.location = location;
26853 this.gMapContext.marker.setPosition(location);
26854 this.gMapContext.map.panTo(location);
26855 this.drawCircle(location, this.gMapContext.radius, {});
26859 if (this.gMapContext.settings.enableReverseGeocode) {
26860 this.gMapContext.geodecoder.geocode({
26861 latLng: this.gMapContext.location
26862 }, function(results, status) {
26864 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
26865 _this.gMapContext.locationName = results[0].formatted_address;
26866 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
26868 _this.fireEvent('positionchanged', this, location);
26875 this.fireEvent('positionchanged', this, location);
26880 google.maps.event.trigger(this.gMapContext.map, "resize");
26882 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
26884 this.fireEvent('resize', this);
26887 setPositionByLatLng: function(latitude, longitude)
26889 this.setPosition(new google.maps.LatLng(latitude, longitude));
26892 getCurrentPosition: function()
26895 latitude: this.gMapContext.location.lat(),
26896 longitude: this.gMapContext.location.lng()
26900 getAddressName: function()
26902 return this.gMapContext.locationName;
26905 getAddressComponents: function()
26907 return this.gMapContext.addressComponents;
26910 address_component_from_google_geocode: function(address_components)
26914 for (var i = 0; i < address_components.length; i++) {
26915 var component = address_components[i];
26916 if (component.types.indexOf("postal_code") >= 0) {
26917 result.postalCode = component.short_name;
26918 } else if (component.types.indexOf("street_number") >= 0) {
26919 result.streetNumber = component.short_name;
26920 } else if (component.types.indexOf("route") >= 0) {
26921 result.streetName = component.short_name;
26922 } else if (component.types.indexOf("neighborhood") >= 0) {
26923 result.city = component.short_name;
26924 } else if (component.types.indexOf("locality") >= 0) {
26925 result.city = component.short_name;
26926 } else if (component.types.indexOf("sublocality") >= 0) {
26927 result.district = component.short_name;
26928 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
26929 result.stateOrProvince = component.short_name;
26930 } else if (component.types.indexOf("country") >= 0) {
26931 result.country = component.short_name;
26935 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
26936 result.addressLine2 = "";
26940 setZoomLevel: function(zoom)
26942 this.gMapContext.map.setZoom(zoom);
26955 this.fireEvent('show', this);
26966 this.fireEvent('hide', this);
26971 Roo.apply(Roo.bootstrap.LocationPicker, {
26973 OverlayView : function(map, options)
26975 options = options || {};
26989 * @class Roo.bootstrap.Alert
26990 * @extends Roo.bootstrap.Component
26991 * Bootstrap Alert class
26992 * @cfg {String} title The title of alert
26993 * @cfg {String} html The content of alert
26994 * @cfg {String} weight ( success | info | warning | danger )
26995 * @cfg {String} faicon font-awesomeicon
26998 * Create a new alert
26999 * @param {Object} config The config object
27003 Roo.bootstrap.Alert = function(config){
27004 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
27008 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
27015 getAutoCreate : function()
27024 cls : 'roo-alert-icon'
27029 cls : 'roo-alert-title',
27034 cls : 'roo-alert-text',
27041 cfg.cn[0].cls += ' fa ' + this.faicon;
27045 cfg.cls += ' alert-' + this.weight;
27051 initEvents: function()
27053 this.el.setVisibilityMode(Roo.Element.DISPLAY);
27056 setTitle : function(str)
27058 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
27061 setText : function(str)
27063 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
27066 setWeight : function(weight)
27069 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
27072 this.weight = weight;
27074 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
27077 setIcon : function(icon)
27080 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
27083 this.faicon = icon;
27085 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
27106 * @class Roo.bootstrap.UploadCropbox
27107 * @extends Roo.bootstrap.Component
27108 * Bootstrap UploadCropbox class
27109 * @cfg {String} emptyText show when image has been loaded
27110 * @cfg {String} rotateNotify show when image too small to rotate
27111 * @cfg {Number} errorTimeout default 3000
27112 * @cfg {Number} minWidth default 300
27113 * @cfg {Number} minHeight default 300
27114 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
27115 * @cfg {Boolean} isDocument (true|false) default false
27116 * @cfg {String} url action url
27117 * @cfg {String} paramName default 'imageUpload'
27118 * @cfg {String} method default POST
27119 * @cfg {Boolean} loadMask (true|false) default true
27120 * @cfg {Boolean} loadingText default 'Loading...'
27123 * Create a new UploadCropbox
27124 * @param {Object} config The config object
27127 Roo.bootstrap.UploadCropbox = function(config){
27128 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
27132 * @event beforeselectfile
27133 * Fire before select file
27134 * @param {Roo.bootstrap.UploadCropbox} this
27136 "beforeselectfile" : true,
27139 * Fire after initEvent
27140 * @param {Roo.bootstrap.UploadCropbox} this
27145 * Fire after initEvent
27146 * @param {Roo.bootstrap.UploadCropbox} this
27147 * @param {String} data
27152 * Fire when preparing the file data
27153 * @param {Roo.bootstrap.UploadCropbox} this
27154 * @param {Object} file
27159 * Fire when get exception
27160 * @param {Roo.bootstrap.UploadCropbox} this
27161 * @param {XMLHttpRequest} xhr
27163 "exception" : true,
27165 * @event beforeloadcanvas
27166 * Fire before load the canvas
27167 * @param {Roo.bootstrap.UploadCropbox} this
27168 * @param {String} src
27170 "beforeloadcanvas" : true,
27173 * Fire when trash image
27174 * @param {Roo.bootstrap.UploadCropbox} this
27179 * Fire when download the image
27180 * @param {Roo.bootstrap.UploadCropbox} this
27184 * @event footerbuttonclick
27185 * Fire when footerbuttonclick
27186 * @param {Roo.bootstrap.UploadCropbox} this
27187 * @param {String} type
27189 "footerbuttonclick" : true,
27193 * @param {Roo.bootstrap.UploadCropbox} this
27198 * Fire when rotate the image
27199 * @param {Roo.bootstrap.UploadCropbox} this
27200 * @param {String} pos
27205 * Fire when inspect the file
27206 * @param {Roo.bootstrap.UploadCropbox} this
27207 * @param {Object} file
27212 * Fire when xhr upload the file
27213 * @param {Roo.bootstrap.UploadCropbox} this
27214 * @param {Object} data
27219 * Fire when arrange the file data
27220 * @param {Roo.bootstrap.UploadCropbox} this
27221 * @param {Object} formData
27226 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
27229 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
27231 emptyText : 'Click to upload image',
27232 rotateNotify : 'Image is too small to rotate',
27233 errorTimeout : 3000,
27247 cropType : 'image/jpeg',
27249 canvasLoaded : false,
27250 isDocument : false,
27252 paramName : 'imageUpload',
27254 loadingText : 'Loading...',
27257 getAutoCreate : function()
27261 cls : 'roo-upload-cropbox',
27265 cls : 'roo-upload-cropbox-selector',
27270 cls : 'roo-upload-cropbox-body',
27271 style : 'cursor:pointer',
27275 cls : 'roo-upload-cropbox-preview'
27279 cls : 'roo-upload-cropbox-thumb'
27283 cls : 'roo-upload-cropbox-empty-notify',
27284 html : this.emptyText
27288 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
27289 html : this.rotateNotify
27295 cls : 'roo-upload-cropbox-footer',
27298 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
27308 onRender : function(ct, position)
27310 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
27312 if (this.buttons.length) {
27314 Roo.each(this.buttons, function(bb) {
27316 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
27318 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
27324 this.maskEl = this.el;
27328 initEvents : function()
27330 this.urlAPI = (window.createObjectURL && window) ||
27331 (window.URL && URL.revokeObjectURL && URL) ||
27332 (window.webkitURL && webkitURL);
27334 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
27335 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27337 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
27338 this.selectorEl.hide();
27340 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
27341 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27343 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
27344 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27345 this.thumbEl.hide();
27347 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
27348 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27350 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
27351 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27352 this.errorEl.hide();
27354 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
27355 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27356 this.footerEl.hide();
27358 this.setThumbBoxSize();
27364 this.fireEvent('initial', this);
27371 window.addEventListener("resize", function() { _this.resize(); } );
27373 this.bodyEl.on('click', this.beforeSelectFile, this);
27376 this.bodyEl.on('touchstart', this.onTouchStart, this);
27377 this.bodyEl.on('touchmove', this.onTouchMove, this);
27378 this.bodyEl.on('touchend', this.onTouchEnd, this);
27382 this.bodyEl.on('mousedown', this.onMouseDown, this);
27383 this.bodyEl.on('mousemove', this.onMouseMove, this);
27384 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
27385 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
27386 Roo.get(document).on('mouseup', this.onMouseUp, this);
27389 this.selectorEl.on('change', this.onFileSelected, this);
27395 this.baseScale = 1;
27397 this.baseRotate = 1;
27398 this.dragable = false;
27399 this.pinching = false;
27402 this.cropData = false;
27403 this.notifyEl.dom.innerHTML = this.emptyText;
27405 this.selectorEl.dom.value = '';
27409 resize : function()
27411 if(this.fireEvent('resize', this) != false){
27412 this.setThumbBoxPosition();
27413 this.setCanvasPosition();
27417 onFooterButtonClick : function(e, el, o, type)
27420 case 'rotate-left' :
27421 this.onRotateLeft(e);
27423 case 'rotate-right' :
27424 this.onRotateRight(e);
27427 this.beforeSelectFile(e);
27442 this.fireEvent('footerbuttonclick', this, type);
27445 beforeSelectFile : function(e)
27447 e.preventDefault();
27449 if(this.fireEvent('beforeselectfile', this) != false){
27450 this.selectorEl.dom.click();
27454 onFileSelected : function(e)
27456 e.preventDefault();
27458 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
27462 var file = this.selectorEl.dom.files[0];
27464 if(this.fireEvent('inspect', this, file) != false){
27465 this.prepare(file);
27470 trash : function(e)
27472 this.fireEvent('trash', this);
27475 download : function(e)
27477 this.fireEvent('download', this);
27480 loadCanvas : function(src)
27482 if(this.fireEvent('beforeloadcanvas', this, src) != false){
27486 this.imageEl = document.createElement('img');
27490 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
27492 this.imageEl.src = src;
27496 onLoadCanvas : function()
27498 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
27499 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
27501 this.bodyEl.un('click', this.beforeSelectFile, this);
27503 this.notifyEl.hide();
27504 this.thumbEl.show();
27505 this.footerEl.show();
27507 this.baseRotateLevel();
27509 if(this.isDocument){
27510 this.setThumbBoxSize();
27513 this.setThumbBoxPosition();
27515 this.baseScaleLevel();
27521 this.canvasLoaded = true;
27524 this.maskEl.unmask();
27529 setCanvasPosition : function()
27531 if(!this.canvasEl){
27535 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
27536 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
27538 this.previewEl.setLeft(pw);
27539 this.previewEl.setTop(ph);
27543 onMouseDown : function(e)
27547 this.dragable = true;
27548 this.pinching = false;
27550 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
27551 this.dragable = false;
27555 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27556 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27560 onMouseMove : function(e)
27564 if(!this.canvasLoaded){
27568 if (!this.dragable){
27572 var minX = Math.ceil(this.thumbEl.getLeft(true));
27573 var minY = Math.ceil(this.thumbEl.getTop(true));
27575 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
27576 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
27578 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27579 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27581 x = x - this.mouseX;
27582 y = y - this.mouseY;
27584 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
27585 var bgY = Math.ceil(y + this.previewEl.getTop(true));
27587 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
27588 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
27590 this.previewEl.setLeft(bgX);
27591 this.previewEl.setTop(bgY);
27593 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27594 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27597 onMouseUp : function(e)
27601 this.dragable = false;
27604 onMouseWheel : function(e)
27608 this.startScale = this.scale;
27610 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
27612 if(!this.zoomable()){
27613 this.scale = this.startScale;
27622 zoomable : function()
27624 var minScale = this.thumbEl.getWidth() / this.minWidth;
27626 if(this.minWidth < this.minHeight){
27627 minScale = this.thumbEl.getHeight() / this.minHeight;
27630 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
27631 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
27635 (this.rotate == 0 || this.rotate == 180) &&
27637 width > this.imageEl.OriginWidth ||
27638 height > this.imageEl.OriginHeight ||
27639 (width < this.minWidth && height < this.minHeight)
27647 (this.rotate == 90 || this.rotate == 270) &&
27649 width > this.imageEl.OriginWidth ||
27650 height > this.imageEl.OriginHeight ||
27651 (width < this.minHeight && height < this.minWidth)
27658 !this.isDocument &&
27659 (this.rotate == 0 || this.rotate == 180) &&
27661 width < this.minWidth ||
27662 width > this.imageEl.OriginWidth ||
27663 height < this.minHeight ||
27664 height > this.imageEl.OriginHeight
27671 !this.isDocument &&
27672 (this.rotate == 90 || this.rotate == 270) &&
27674 width < this.minHeight ||
27675 width > this.imageEl.OriginWidth ||
27676 height < this.minWidth ||
27677 height > this.imageEl.OriginHeight
27687 onRotateLeft : function(e)
27689 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27691 var minScale = this.thumbEl.getWidth() / this.minWidth;
27693 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27694 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27696 this.startScale = this.scale;
27698 while (this.getScaleLevel() < minScale){
27700 this.scale = this.scale + 1;
27702 if(!this.zoomable()){
27707 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27708 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27713 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27720 this.scale = this.startScale;
27722 this.onRotateFail();
27727 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27729 if(this.isDocument){
27730 this.setThumbBoxSize();
27731 this.setThumbBoxPosition();
27732 this.setCanvasPosition();
27737 this.fireEvent('rotate', this, 'left');
27741 onRotateRight : function(e)
27743 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27745 var minScale = this.thumbEl.getWidth() / this.minWidth;
27747 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27748 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27750 this.startScale = this.scale;
27752 while (this.getScaleLevel() < minScale){
27754 this.scale = this.scale + 1;
27756 if(!this.zoomable()){
27761 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27762 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27767 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27774 this.scale = this.startScale;
27776 this.onRotateFail();
27781 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27783 if(this.isDocument){
27784 this.setThumbBoxSize();
27785 this.setThumbBoxPosition();
27786 this.setCanvasPosition();
27791 this.fireEvent('rotate', this, 'right');
27794 onRotateFail : function()
27796 this.errorEl.show(true);
27800 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
27805 this.previewEl.dom.innerHTML = '';
27807 var canvasEl = document.createElement("canvas");
27809 var contextEl = canvasEl.getContext("2d");
27811 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27812 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27813 var center = this.imageEl.OriginWidth / 2;
27815 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
27816 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27817 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27818 center = this.imageEl.OriginHeight / 2;
27821 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
27823 contextEl.translate(center, center);
27824 contextEl.rotate(this.rotate * Math.PI / 180);
27826 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27828 this.canvasEl = document.createElement("canvas");
27830 this.contextEl = this.canvasEl.getContext("2d");
27832 switch (this.rotate) {
27835 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27836 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27838 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27843 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27844 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27846 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27847 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);
27851 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27856 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27857 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27859 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27860 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);
27864 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);
27869 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27870 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27872 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27873 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27877 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);
27884 this.previewEl.appendChild(this.canvasEl);
27886 this.setCanvasPosition();
27891 if(!this.canvasLoaded){
27895 var imageCanvas = document.createElement("canvas");
27897 var imageContext = imageCanvas.getContext("2d");
27899 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27900 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27902 var center = imageCanvas.width / 2;
27904 imageContext.translate(center, center);
27906 imageContext.rotate(this.rotate * Math.PI / 180);
27908 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27910 var canvas = document.createElement("canvas");
27912 var context = canvas.getContext("2d");
27914 canvas.width = this.minWidth;
27915 canvas.height = this.minHeight;
27917 switch (this.rotate) {
27920 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27921 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27923 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27924 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27926 var targetWidth = this.minWidth - 2 * x;
27927 var targetHeight = this.minHeight - 2 * y;
27931 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27932 scale = targetWidth / width;
27935 if(x > 0 && y == 0){
27936 scale = targetHeight / height;
27939 if(x > 0 && y > 0){
27940 scale = targetWidth / width;
27942 if(width < height){
27943 scale = targetHeight / height;
27947 context.scale(scale, scale);
27949 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27950 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27952 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27953 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27955 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27960 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27961 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27963 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27964 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27966 var targetWidth = this.minWidth - 2 * x;
27967 var targetHeight = this.minHeight - 2 * y;
27971 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27972 scale = targetWidth / width;
27975 if(x > 0 && y == 0){
27976 scale = targetHeight / height;
27979 if(x > 0 && y > 0){
27980 scale = targetWidth / width;
27982 if(width < height){
27983 scale = targetHeight / height;
27987 context.scale(scale, scale);
27989 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27990 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27992 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27993 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27995 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27997 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28002 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
28003 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
28005 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28006 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28008 var targetWidth = this.minWidth - 2 * x;
28009 var targetHeight = this.minHeight - 2 * y;
28013 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28014 scale = targetWidth / width;
28017 if(x > 0 && y == 0){
28018 scale = targetHeight / height;
28021 if(x > 0 && y > 0){
28022 scale = targetWidth / width;
28024 if(width < height){
28025 scale = targetHeight / height;
28029 context.scale(scale, scale);
28031 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28032 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28034 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28035 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28037 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
28038 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
28040 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28045 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
28046 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
28048 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28049 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28051 var targetWidth = this.minWidth - 2 * x;
28052 var targetHeight = this.minHeight - 2 * y;
28056 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28057 scale = targetWidth / width;
28060 if(x > 0 && y == 0){
28061 scale = targetHeight / height;
28064 if(x > 0 && y > 0){
28065 scale = targetWidth / width;
28067 if(width < height){
28068 scale = targetHeight / height;
28072 context.scale(scale, scale);
28074 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28075 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28077 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28078 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28080 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
28082 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28089 this.cropData = canvas.toDataURL(this.cropType);
28091 if(this.fireEvent('crop', this, this.cropData) !== false){
28092 this.process(this.file, this.cropData);
28099 setThumbBoxSize : function()
28103 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
28104 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
28105 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
28107 this.minWidth = width;
28108 this.minHeight = height;
28110 if(this.rotate == 90 || this.rotate == 270){
28111 this.minWidth = height;
28112 this.minHeight = width;
28117 width = Math.ceil(this.minWidth * height / this.minHeight);
28119 if(this.minWidth > this.minHeight){
28121 height = Math.ceil(this.minHeight * width / this.minWidth);
28124 this.thumbEl.setStyle({
28125 width : width + 'px',
28126 height : height + 'px'
28133 setThumbBoxPosition : function()
28135 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
28136 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
28138 this.thumbEl.setLeft(x);
28139 this.thumbEl.setTop(y);
28143 baseRotateLevel : function()
28145 this.baseRotate = 1;
28148 typeof(this.exif) != 'undefined' &&
28149 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
28150 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
28152 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
28155 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
28159 baseScaleLevel : function()
28163 if(this.isDocument){
28165 if(this.baseRotate == 6 || this.baseRotate == 8){
28167 height = this.thumbEl.getHeight();
28168 this.baseScale = height / this.imageEl.OriginWidth;
28170 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
28171 width = this.thumbEl.getWidth();
28172 this.baseScale = width / this.imageEl.OriginHeight;
28178 height = this.thumbEl.getHeight();
28179 this.baseScale = height / this.imageEl.OriginHeight;
28181 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
28182 width = this.thumbEl.getWidth();
28183 this.baseScale = width / this.imageEl.OriginWidth;
28189 if(this.baseRotate == 6 || this.baseRotate == 8){
28191 width = this.thumbEl.getHeight();
28192 this.baseScale = width / this.imageEl.OriginHeight;
28194 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
28195 height = this.thumbEl.getWidth();
28196 this.baseScale = height / this.imageEl.OriginHeight;
28199 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28200 height = this.thumbEl.getWidth();
28201 this.baseScale = height / this.imageEl.OriginHeight;
28203 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
28204 width = this.thumbEl.getHeight();
28205 this.baseScale = width / this.imageEl.OriginWidth;
28212 width = this.thumbEl.getWidth();
28213 this.baseScale = width / this.imageEl.OriginWidth;
28215 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
28216 height = this.thumbEl.getHeight();
28217 this.baseScale = height / this.imageEl.OriginHeight;
28220 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28222 height = this.thumbEl.getHeight();
28223 this.baseScale = height / this.imageEl.OriginHeight;
28225 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
28226 width = this.thumbEl.getWidth();
28227 this.baseScale = width / this.imageEl.OriginWidth;
28235 getScaleLevel : function()
28237 return this.baseScale * Math.pow(1.1, this.scale);
28240 onTouchStart : function(e)
28242 if(!this.canvasLoaded){
28243 this.beforeSelectFile(e);
28247 var touches = e.browserEvent.touches;
28253 if(touches.length == 1){
28254 this.onMouseDown(e);
28258 if(touches.length != 2){
28264 for(var i = 0, finger; finger = touches[i]; i++){
28265 coords.push(finger.pageX, finger.pageY);
28268 var x = Math.pow(coords[0] - coords[2], 2);
28269 var y = Math.pow(coords[1] - coords[3], 2);
28271 this.startDistance = Math.sqrt(x + y);
28273 this.startScale = this.scale;
28275 this.pinching = true;
28276 this.dragable = false;
28280 onTouchMove : function(e)
28282 if(!this.pinching && !this.dragable){
28286 var touches = e.browserEvent.touches;
28293 this.onMouseMove(e);
28299 for(var i = 0, finger; finger = touches[i]; i++){
28300 coords.push(finger.pageX, finger.pageY);
28303 var x = Math.pow(coords[0] - coords[2], 2);
28304 var y = Math.pow(coords[1] - coords[3], 2);
28306 this.endDistance = Math.sqrt(x + y);
28308 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
28310 if(!this.zoomable()){
28311 this.scale = this.startScale;
28319 onTouchEnd : function(e)
28321 this.pinching = false;
28322 this.dragable = false;
28326 process : function(file, crop)
28329 this.maskEl.mask(this.loadingText);
28332 this.xhr = new XMLHttpRequest();
28334 file.xhr = this.xhr;
28336 this.xhr.open(this.method, this.url, true);
28339 "Accept": "application/json",
28340 "Cache-Control": "no-cache",
28341 "X-Requested-With": "XMLHttpRequest"
28344 for (var headerName in headers) {
28345 var headerValue = headers[headerName];
28347 this.xhr.setRequestHeader(headerName, headerValue);
28353 this.xhr.onload = function()
28355 _this.xhrOnLoad(_this.xhr);
28358 this.xhr.onerror = function()
28360 _this.xhrOnError(_this.xhr);
28363 var formData = new FormData();
28365 formData.append('returnHTML', 'NO');
28368 formData.append('crop', crop);
28371 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
28372 formData.append(this.paramName, file, file.name);
28375 if(typeof(file.filename) != 'undefined'){
28376 formData.append('filename', file.filename);
28379 if(typeof(file.mimetype) != 'undefined'){
28380 formData.append('mimetype', file.mimetype);
28383 if(this.fireEvent('arrange', this, formData) != false){
28384 this.xhr.send(formData);
28388 xhrOnLoad : function(xhr)
28391 this.maskEl.unmask();
28394 if (xhr.readyState !== 4) {
28395 this.fireEvent('exception', this, xhr);
28399 var response = Roo.decode(xhr.responseText);
28401 if(!response.success){
28402 this.fireEvent('exception', this, xhr);
28406 var response = Roo.decode(xhr.responseText);
28408 this.fireEvent('upload', this, response);
28412 xhrOnError : function()
28415 this.maskEl.unmask();
28418 Roo.log('xhr on error');
28420 var response = Roo.decode(xhr.responseText);
28426 prepare : function(file)
28429 this.maskEl.mask(this.loadingText);
28435 if(typeof(file) === 'string'){
28436 this.loadCanvas(file);
28440 if(!file || !this.urlAPI){
28445 this.cropType = file.type;
28449 if(this.fireEvent('prepare', this, this.file) != false){
28451 var reader = new FileReader();
28453 reader.onload = function (e) {
28454 if (e.target.error) {
28455 Roo.log(e.target.error);
28459 var buffer = e.target.result,
28460 dataView = new DataView(buffer),
28462 maxOffset = dataView.byteLength - 4,
28466 if (dataView.getUint16(0) === 0xffd8) {
28467 while (offset < maxOffset) {
28468 markerBytes = dataView.getUint16(offset);
28470 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
28471 markerLength = dataView.getUint16(offset + 2) + 2;
28472 if (offset + markerLength > dataView.byteLength) {
28473 Roo.log('Invalid meta data: Invalid segment size.');
28477 if(markerBytes == 0xffe1){
28478 _this.parseExifData(
28485 offset += markerLength;
28495 var url = _this.urlAPI.createObjectURL(_this.file);
28497 _this.loadCanvas(url);
28502 reader.readAsArrayBuffer(this.file);
28508 parseExifData : function(dataView, offset, length)
28510 var tiffOffset = offset + 10,
28514 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28515 // No Exif data, might be XMP data instead
28519 // Check for the ASCII code for "Exif" (0x45786966):
28520 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28521 // No Exif data, might be XMP data instead
28524 if (tiffOffset + 8 > dataView.byteLength) {
28525 Roo.log('Invalid Exif data: Invalid segment size.');
28528 // Check for the two null bytes:
28529 if (dataView.getUint16(offset + 8) !== 0x0000) {
28530 Roo.log('Invalid Exif data: Missing byte alignment offset.');
28533 // Check the byte alignment:
28534 switch (dataView.getUint16(tiffOffset)) {
28536 littleEndian = true;
28539 littleEndian = false;
28542 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
28545 // Check for the TIFF tag marker (0x002A):
28546 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
28547 Roo.log('Invalid Exif data: Missing TIFF marker.');
28550 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
28551 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
28553 this.parseExifTags(
28556 tiffOffset + dirOffset,
28561 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
28566 if (dirOffset + 6 > dataView.byteLength) {
28567 Roo.log('Invalid Exif data: Invalid directory offset.');
28570 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
28571 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
28572 if (dirEndOffset + 4 > dataView.byteLength) {
28573 Roo.log('Invalid Exif data: Invalid directory size.');
28576 for (i = 0; i < tagsNumber; i += 1) {
28580 dirOffset + 2 + 12 * i, // tag offset
28584 // Return the offset to the next directory:
28585 return dataView.getUint32(dirEndOffset, littleEndian);
28588 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
28590 var tag = dataView.getUint16(offset, littleEndian);
28592 this.exif[tag] = this.getExifValue(
28596 dataView.getUint16(offset + 2, littleEndian), // tag type
28597 dataView.getUint32(offset + 4, littleEndian), // tag length
28602 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
28604 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
28613 Roo.log('Invalid Exif data: Invalid tag type.');
28617 tagSize = tagType.size * length;
28618 // Determine if the value is contained in the dataOffset bytes,
28619 // or if the value at the dataOffset is a pointer to the actual data:
28620 dataOffset = tagSize > 4 ?
28621 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
28622 if (dataOffset + tagSize > dataView.byteLength) {
28623 Roo.log('Invalid Exif data: Invalid data offset.');
28626 if (length === 1) {
28627 return tagType.getValue(dataView, dataOffset, littleEndian);
28630 for (i = 0; i < length; i += 1) {
28631 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
28634 if (tagType.ascii) {
28636 // Concatenate the chars:
28637 for (i = 0; i < values.length; i += 1) {
28639 // Ignore the terminating NULL byte(s):
28640 if (c === '\u0000') {
28652 Roo.apply(Roo.bootstrap.UploadCropbox, {
28654 'Orientation': 0x0112
28658 1: 0, //'top-left',
28660 3: 180, //'bottom-right',
28661 // 4: 'bottom-left',
28663 6: 90, //'right-top',
28664 // 7: 'right-bottom',
28665 8: 270 //'left-bottom'
28669 // byte, 8-bit unsigned int:
28671 getValue: function (dataView, dataOffset) {
28672 return dataView.getUint8(dataOffset);
28676 // ascii, 8-bit byte:
28678 getValue: function (dataView, dataOffset) {
28679 return String.fromCharCode(dataView.getUint8(dataOffset));
28684 // short, 16 bit int:
28686 getValue: function (dataView, dataOffset, littleEndian) {
28687 return dataView.getUint16(dataOffset, littleEndian);
28691 // long, 32 bit int:
28693 getValue: function (dataView, dataOffset, littleEndian) {
28694 return dataView.getUint32(dataOffset, littleEndian);
28698 // rational = two long values, first is numerator, second is denominator:
28700 getValue: function (dataView, dataOffset, littleEndian) {
28701 return dataView.getUint32(dataOffset, littleEndian) /
28702 dataView.getUint32(dataOffset + 4, littleEndian);
28706 // slong, 32 bit signed int:
28708 getValue: function (dataView, dataOffset, littleEndian) {
28709 return dataView.getInt32(dataOffset, littleEndian);
28713 // srational, two slongs, first is numerator, second is denominator:
28715 getValue: function (dataView, dataOffset, littleEndian) {
28716 return dataView.getInt32(dataOffset, littleEndian) /
28717 dataView.getInt32(dataOffset + 4, littleEndian);
28727 cls : 'btn-group roo-upload-cropbox-rotate-left',
28728 action : 'rotate-left',
28732 cls : 'btn btn-default',
28733 html : '<i class="fa fa-undo"></i>'
28739 cls : 'btn-group roo-upload-cropbox-picture',
28740 action : 'picture',
28744 cls : 'btn btn-default',
28745 html : '<i class="fa fa-picture-o"></i>'
28751 cls : 'btn-group roo-upload-cropbox-rotate-right',
28752 action : 'rotate-right',
28756 cls : 'btn btn-default',
28757 html : '<i class="fa fa-repeat"></i>'
28765 cls : 'btn-group roo-upload-cropbox-rotate-left',
28766 action : 'rotate-left',
28770 cls : 'btn btn-default',
28771 html : '<i class="fa fa-undo"></i>'
28777 cls : 'btn-group roo-upload-cropbox-download',
28778 action : 'download',
28782 cls : 'btn btn-default',
28783 html : '<i class="fa fa-download"></i>'
28789 cls : 'btn-group roo-upload-cropbox-crop',
28794 cls : 'btn btn-default',
28795 html : '<i class="fa fa-crop"></i>'
28801 cls : 'btn-group roo-upload-cropbox-trash',
28806 cls : 'btn btn-default',
28807 html : '<i class="fa fa-trash"></i>'
28813 cls : 'btn-group roo-upload-cropbox-rotate-right',
28814 action : 'rotate-right',
28818 cls : 'btn btn-default',
28819 html : '<i class="fa fa-repeat"></i>'
28827 cls : 'btn-group roo-upload-cropbox-rotate-left',
28828 action : 'rotate-left',
28832 cls : 'btn btn-default',
28833 html : '<i class="fa fa-undo"></i>'
28839 cls : 'btn-group roo-upload-cropbox-rotate-right',
28840 action : 'rotate-right',
28844 cls : 'btn btn-default',
28845 html : '<i class="fa fa-repeat"></i>'
28858 * @class Roo.bootstrap.DocumentManager
28859 * @extends Roo.bootstrap.Component
28860 * Bootstrap DocumentManager class
28861 * @cfg {String} paramName default 'imageUpload'
28862 * @cfg {String} toolTipName default 'filename'
28863 * @cfg {String} method default POST
28864 * @cfg {String} url action url
28865 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
28866 * @cfg {Boolean} multiple multiple upload default true
28867 * @cfg {Number} thumbSize default 300
28868 * @cfg {String} fieldLabel
28869 * @cfg {Number} labelWidth default 4
28870 * @cfg {String} labelAlign (left|top) default left
28871 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
28872 * @cfg {Number} labellg set the width of label (1-12)
28873 * @cfg {Number} labelmd set the width of label (1-12)
28874 * @cfg {Number} labelsm set the width of label (1-12)
28875 * @cfg {Number} labelxs set the width of label (1-12)
28878 * Create a new DocumentManager
28879 * @param {Object} config The config object
28882 Roo.bootstrap.DocumentManager = function(config){
28883 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
28886 this.delegates = [];
28891 * Fire when initial the DocumentManager
28892 * @param {Roo.bootstrap.DocumentManager} this
28897 * inspect selected file
28898 * @param {Roo.bootstrap.DocumentManager} this
28899 * @param {File} file
28904 * Fire when xhr load exception
28905 * @param {Roo.bootstrap.DocumentManager} this
28906 * @param {XMLHttpRequest} xhr
28908 "exception" : true,
28910 * @event afterupload
28911 * Fire when xhr load exception
28912 * @param {Roo.bootstrap.DocumentManager} this
28913 * @param {XMLHttpRequest} xhr
28915 "afterupload" : true,
28918 * prepare the form data
28919 * @param {Roo.bootstrap.DocumentManager} this
28920 * @param {Object} formData
28925 * Fire when remove the file
28926 * @param {Roo.bootstrap.DocumentManager} this
28927 * @param {Object} file
28932 * Fire after refresh the file
28933 * @param {Roo.bootstrap.DocumentManager} this
28938 * Fire after click the image
28939 * @param {Roo.bootstrap.DocumentManager} this
28940 * @param {Object} file
28945 * Fire when upload a image and editable set to true
28946 * @param {Roo.bootstrap.DocumentManager} this
28947 * @param {Object} file
28951 * @event beforeselectfile
28952 * Fire before select file
28953 * @param {Roo.bootstrap.DocumentManager} this
28955 "beforeselectfile" : true,
28958 * Fire before process file
28959 * @param {Roo.bootstrap.DocumentManager} this
28960 * @param {Object} file
28964 * @event previewrendered
28965 * Fire when preview rendered
28966 * @param {Roo.bootstrap.DocumentManager} this
28967 * @param {Object} file
28969 "previewrendered" : true,
28972 "previewResize" : true
28977 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
28986 paramName : 'imageUpload',
28987 toolTipName : 'filename',
28990 labelAlign : 'left',
29000 getAutoCreate : function()
29002 var managerWidget = {
29004 cls : 'roo-document-manager',
29008 cls : 'roo-document-manager-selector',
29013 cls : 'roo-document-manager-uploader',
29017 cls : 'roo-document-manager-upload-btn',
29018 html : '<i class="fa fa-plus"></i>'
29029 cls : 'column col-md-12',
29034 if(this.fieldLabel.length){
29039 cls : 'column col-md-12',
29040 html : this.fieldLabel
29044 cls : 'column col-md-12',
29049 if(this.labelAlign == 'left'){
29054 html : this.fieldLabel
29063 if(this.labelWidth > 12){
29064 content[0].style = "width: " + this.labelWidth + 'px';
29067 if(this.labelWidth < 13 && this.labelmd == 0){
29068 this.labelmd = this.labelWidth;
29071 if(this.labellg > 0){
29072 content[0].cls += ' col-lg-' + this.labellg;
29073 content[1].cls += ' col-lg-' + (12 - this.labellg);
29076 if(this.labelmd > 0){
29077 content[0].cls += ' col-md-' + this.labelmd;
29078 content[1].cls += ' col-md-' + (12 - this.labelmd);
29081 if(this.labelsm > 0){
29082 content[0].cls += ' col-sm-' + this.labelsm;
29083 content[1].cls += ' col-sm-' + (12 - this.labelsm);
29086 if(this.labelxs > 0){
29087 content[0].cls += ' col-xs-' + this.labelxs;
29088 content[1].cls += ' col-xs-' + (12 - this.labelxs);
29096 cls : 'row clearfix',
29104 initEvents : function()
29106 this.managerEl = this.el.select('.roo-document-manager', true).first();
29107 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29109 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
29110 this.selectorEl.hide();
29113 this.selectorEl.attr('multiple', 'multiple');
29116 this.selectorEl.on('change', this.onFileSelected, this);
29118 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
29119 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29121 this.uploader.on('click', this.onUploaderClick, this);
29123 this.renderProgressDialog();
29127 window.addEventListener("resize", function() { _this.refresh(); } );
29129 this.fireEvent('initial', this);
29132 renderProgressDialog : function()
29136 this.progressDialog = new Roo.bootstrap.Modal({
29137 cls : 'roo-document-manager-progress-dialog',
29138 allow_close : false,
29148 btnclick : function() {
29149 _this.uploadCancel();
29155 this.progressDialog.render(Roo.get(document.body));
29157 this.progress = new Roo.bootstrap.Progress({
29158 cls : 'roo-document-manager-progress',
29163 this.progress.render(this.progressDialog.getChildContainer());
29165 this.progressBar = new Roo.bootstrap.ProgressBar({
29166 cls : 'roo-document-manager-progress-bar',
29169 aria_valuemax : 12,
29173 this.progressBar.render(this.progress.getChildContainer());
29176 onUploaderClick : function(e)
29178 e.preventDefault();
29180 if(this.fireEvent('beforeselectfile', this) != false){
29181 this.selectorEl.dom.click();
29186 onFileSelected : function(e)
29188 e.preventDefault();
29190 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
29194 Roo.each(this.selectorEl.dom.files, function(file){
29195 if(this.fireEvent('inspect', this, file) != false){
29196 this.files.push(file);
29206 this.selectorEl.dom.value = '';
29208 if(!this.files || !this.files.length){
29212 if(this.boxes > 0 && this.files.length > this.boxes){
29213 this.files = this.files.slice(0, this.boxes);
29216 this.uploader.show();
29218 if(this.boxes > 0 && this.files.length > this.boxes - 1){
29219 this.uploader.hide();
29228 Roo.each(this.files, function(file){
29230 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29231 var f = this.renderPreview(file);
29236 if(file.type.indexOf('image') != -1){
29237 this.delegates.push(
29239 _this.process(file);
29240 }).createDelegate(this)
29248 _this.process(file);
29249 }).createDelegate(this)
29254 this.files = files;
29256 this.delegates = this.delegates.concat(docs);
29258 if(!this.delegates.length){
29263 this.progressBar.aria_valuemax = this.delegates.length;
29270 arrange : function()
29272 if(!this.delegates.length){
29273 this.progressDialog.hide();
29278 var delegate = this.delegates.shift();
29280 this.progressDialog.show();
29282 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
29284 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
29289 refresh : function()
29291 this.uploader.show();
29293 if(this.boxes > 0 && this.files.length > this.boxes - 1){
29294 this.uploader.hide();
29297 Roo.isTouch ? this.closable(false) : this.closable(true);
29299 this.fireEvent('refresh', this);
29302 onRemove : function(e, el, o)
29304 e.preventDefault();
29306 this.fireEvent('remove', this, o);
29310 remove : function(o)
29314 Roo.each(this.files, function(file){
29315 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
29324 this.files = files;
29331 Roo.each(this.files, function(file){
29336 file.target.remove();
29345 onClick : function(e, el, o)
29347 e.preventDefault();
29349 this.fireEvent('click', this, o);
29353 closable : function(closable)
29355 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
29357 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29369 xhrOnLoad : function(xhr)
29371 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29375 if (xhr.readyState !== 4) {
29377 this.fireEvent('exception', this, xhr);
29381 var response = Roo.decode(xhr.responseText);
29383 if(!response.success){
29385 this.fireEvent('exception', this, xhr);
29389 var file = this.renderPreview(response.data);
29391 this.files.push(file);
29395 this.fireEvent('afterupload', this, xhr);
29399 xhrOnError : function(xhr)
29401 Roo.log('xhr on error');
29403 var response = Roo.decode(xhr.responseText);
29410 process : function(file)
29412 if(this.fireEvent('process', this, file) !== false){
29413 if(this.editable && file.type.indexOf('image') != -1){
29414 this.fireEvent('edit', this, file);
29418 this.uploadStart(file, false);
29425 uploadStart : function(file, crop)
29427 this.xhr = new XMLHttpRequest();
29429 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29434 file.xhr = this.xhr;
29436 this.managerEl.createChild({
29438 cls : 'roo-document-manager-loading',
29442 tooltip : file.name,
29443 cls : 'roo-document-manager-thumb',
29444 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29450 this.xhr.open(this.method, this.url, true);
29453 "Accept": "application/json",
29454 "Cache-Control": "no-cache",
29455 "X-Requested-With": "XMLHttpRequest"
29458 for (var headerName in headers) {
29459 var headerValue = headers[headerName];
29461 this.xhr.setRequestHeader(headerName, headerValue);
29467 this.xhr.onload = function()
29469 _this.xhrOnLoad(_this.xhr);
29472 this.xhr.onerror = function()
29474 _this.xhrOnError(_this.xhr);
29477 var formData = new FormData();
29479 formData.append('returnHTML', 'NO');
29482 formData.append('crop', crop);
29485 formData.append(this.paramName, file, file.name);
29492 if(this.fireEvent('prepare', this, formData, options) != false){
29494 if(options.manually){
29498 this.xhr.send(formData);
29502 this.uploadCancel();
29505 uploadCancel : function()
29511 this.delegates = [];
29513 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29520 renderPreview : function(file)
29522 if(typeof(file.target) != 'undefined' && file.target){
29526 var img_src = encodeURI(baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename);
29528 var previewEl = this.managerEl.createChild({
29530 cls : 'roo-document-manager-preview',
29534 tooltip : file[this.toolTipName],
29535 cls : 'roo-document-manager-thumb',
29536 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + img_src + '">'
29541 html : '<i class="fa fa-times-circle"></i>'
29546 var close = previewEl.select('button.close', true).first();
29548 close.on('click', this.onRemove, this, file);
29550 file.target = previewEl;
29552 var image = previewEl.select('img', true).first();
29556 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
29558 image.on('click', this.onClick, this, file);
29560 this.fireEvent('previewrendered', this, file);
29566 onPreviewLoad : function(file, image)
29568 if(typeof(file.target) == 'undefined' || !file.target){
29572 var width = image.dom.naturalWidth || image.dom.width;
29573 var height = image.dom.naturalHeight || image.dom.height;
29575 if(!this.previewResize) {
29579 if(width > height){
29580 file.target.addClass('wide');
29584 file.target.addClass('tall');
29589 uploadFromSource : function(file, crop)
29591 this.xhr = new XMLHttpRequest();
29593 this.managerEl.createChild({
29595 cls : 'roo-document-manager-loading',
29599 tooltip : file.name,
29600 cls : 'roo-document-manager-thumb',
29601 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29607 this.xhr.open(this.method, this.url, true);
29610 "Accept": "application/json",
29611 "Cache-Control": "no-cache",
29612 "X-Requested-With": "XMLHttpRequest"
29615 for (var headerName in headers) {
29616 var headerValue = headers[headerName];
29618 this.xhr.setRequestHeader(headerName, headerValue);
29624 this.xhr.onload = function()
29626 _this.xhrOnLoad(_this.xhr);
29629 this.xhr.onerror = function()
29631 _this.xhrOnError(_this.xhr);
29634 var formData = new FormData();
29636 formData.append('returnHTML', 'NO');
29638 formData.append('crop', crop);
29640 if(typeof(file.filename) != 'undefined'){
29641 formData.append('filename', file.filename);
29644 if(typeof(file.mimetype) != 'undefined'){
29645 formData.append('mimetype', file.mimetype);
29650 if(this.fireEvent('prepare', this, formData) != false){
29651 this.xhr.send(formData);
29661 * @class Roo.bootstrap.DocumentViewer
29662 * @extends Roo.bootstrap.Component
29663 * Bootstrap DocumentViewer class
29664 * @cfg {Boolean} showDownload (true|false) show download button (default true)
29665 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
29668 * Create a new DocumentViewer
29669 * @param {Object} config The config object
29672 Roo.bootstrap.DocumentViewer = function(config){
29673 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
29678 * Fire after initEvent
29679 * @param {Roo.bootstrap.DocumentViewer} this
29685 * @param {Roo.bootstrap.DocumentViewer} this
29690 * Fire after download button
29691 * @param {Roo.bootstrap.DocumentViewer} this
29696 * Fire after trash button
29697 * @param {Roo.bootstrap.DocumentViewer} this
29704 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
29706 showDownload : true,
29710 getAutoCreate : function()
29714 cls : 'roo-document-viewer',
29718 cls : 'roo-document-viewer-body',
29722 cls : 'roo-document-viewer-thumb',
29726 cls : 'roo-document-viewer-image'
29734 cls : 'roo-document-viewer-footer',
29737 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
29741 cls : 'btn-group roo-document-viewer-download',
29745 cls : 'btn btn-default',
29746 html : '<i class="fa fa-download"></i>'
29752 cls : 'btn-group roo-document-viewer-trash',
29756 cls : 'btn btn-default',
29757 html : '<i class="fa fa-trash"></i>'
29770 initEvents : function()
29772 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
29773 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
29775 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
29776 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
29778 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
29779 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
29781 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
29782 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
29784 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
29785 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
29787 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
29788 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
29790 this.bodyEl.on('click', this.onClick, this);
29791 this.downloadBtn.on('click', this.onDownload, this);
29792 this.trashBtn.on('click', this.onTrash, this);
29794 this.downloadBtn.hide();
29795 this.trashBtn.hide();
29797 if(this.showDownload){
29798 this.downloadBtn.show();
29801 if(this.showTrash){
29802 this.trashBtn.show();
29805 if(!this.showDownload && !this.showTrash) {
29806 this.footerEl.hide();
29811 initial : function()
29813 this.fireEvent('initial', this);
29817 onClick : function(e)
29819 e.preventDefault();
29821 this.fireEvent('click', this);
29824 onDownload : function(e)
29826 e.preventDefault();
29828 this.fireEvent('download', this);
29831 onTrash : function(e)
29833 e.preventDefault();
29835 this.fireEvent('trash', this);
29847 * @class Roo.bootstrap.NavProgressBar
29848 * @extends Roo.bootstrap.Component
29849 * Bootstrap NavProgressBar class
29852 * Create a new nav progress bar
29853 * @param {Object} config The config object
29856 Roo.bootstrap.NavProgressBar = function(config){
29857 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
29859 this.bullets = this.bullets || [];
29861 // Roo.bootstrap.NavProgressBar.register(this);
29865 * Fires when the active item changes
29866 * @param {Roo.bootstrap.NavProgressBar} this
29867 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
29868 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
29875 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
29880 getAutoCreate : function()
29882 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
29886 cls : 'roo-navigation-bar-group',
29890 cls : 'roo-navigation-top-bar'
29894 cls : 'roo-navigation-bullets-bar',
29898 cls : 'roo-navigation-bar'
29905 cls : 'roo-navigation-bottom-bar'
29915 initEvents: function()
29920 onRender : function(ct, position)
29922 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
29924 if(this.bullets.length){
29925 Roo.each(this.bullets, function(b){
29934 addItem : function(cfg)
29936 var item = new Roo.bootstrap.NavProgressItem(cfg);
29938 item.parentId = this.id;
29939 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
29942 var top = new Roo.bootstrap.Element({
29944 cls : 'roo-navigation-bar-text'
29947 var bottom = new Roo.bootstrap.Element({
29949 cls : 'roo-navigation-bar-text'
29952 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
29953 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
29955 var topText = new Roo.bootstrap.Element({
29957 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
29960 var bottomText = new Roo.bootstrap.Element({
29962 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
29965 topText.onRender(top.el, null);
29966 bottomText.onRender(bottom.el, null);
29969 item.bottomEl = bottom;
29972 this.barItems.push(item);
29977 getActive : function()
29979 var active = false;
29981 Roo.each(this.barItems, function(v){
29983 if (!v.isActive()) {
29995 setActiveItem : function(item)
29999 Roo.each(this.barItems, function(v){
30000 if (v.rid == item.rid) {
30004 if (v.isActive()) {
30005 v.setActive(false);
30010 item.setActive(true);
30012 this.fireEvent('changed', this, item, prev);
30015 getBarItem: function(rid)
30019 Roo.each(this.barItems, function(e) {
30020 if (e.rid != rid) {
30031 indexOfItem : function(item)
30035 Roo.each(this.barItems, function(v, i){
30037 if (v.rid != item.rid) {
30048 setActiveNext : function()
30050 var i = this.indexOfItem(this.getActive());
30052 if (i > this.barItems.length) {
30056 this.setActiveItem(this.barItems[i+1]);
30059 setActivePrev : function()
30061 var i = this.indexOfItem(this.getActive());
30067 this.setActiveItem(this.barItems[i-1]);
30070 format : function()
30072 if(!this.barItems.length){
30076 var width = 100 / this.barItems.length;
30078 Roo.each(this.barItems, function(i){
30079 i.el.setStyle('width', width + '%');
30080 i.topEl.el.setStyle('width', width + '%');
30081 i.bottomEl.el.setStyle('width', width + '%');
30090 * Nav Progress Item
30095 * @class Roo.bootstrap.NavProgressItem
30096 * @extends Roo.bootstrap.Component
30097 * Bootstrap NavProgressItem class
30098 * @cfg {String} rid the reference id
30099 * @cfg {Boolean} active (true|false) Is item active default false
30100 * @cfg {Boolean} disabled (true|false) Is item active default false
30101 * @cfg {String} html
30102 * @cfg {String} position (top|bottom) text position default bottom
30103 * @cfg {String} icon show icon instead of number
30106 * Create a new NavProgressItem
30107 * @param {Object} config The config object
30109 Roo.bootstrap.NavProgressItem = function(config){
30110 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
30115 * The raw click event for the entire grid.
30116 * @param {Roo.bootstrap.NavProgressItem} this
30117 * @param {Roo.EventObject} e
30124 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
30130 position : 'bottom',
30133 getAutoCreate : function()
30135 var iconCls = 'roo-navigation-bar-item-icon';
30137 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
30141 cls: 'roo-navigation-bar-item',
30151 cfg.cls += ' active';
30154 cfg.cls += ' disabled';
30160 disable : function()
30162 this.setDisabled(true);
30165 enable : function()
30167 this.setDisabled(false);
30170 initEvents: function()
30172 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
30174 this.iconEl.on('click', this.onClick, this);
30177 onClick : function(e)
30179 e.preventDefault();
30185 if(this.fireEvent('click', this, e) === false){
30189 this.parent().setActiveItem(this);
30192 isActive: function ()
30194 return this.active;
30197 setActive : function(state)
30199 if(this.active == state){
30203 this.active = state;
30206 this.el.addClass('active');
30210 this.el.removeClass('active');
30215 setDisabled : function(state)
30217 if(this.disabled == state){
30221 this.disabled = state;
30224 this.el.addClass('disabled');
30228 this.el.removeClass('disabled');
30231 tooltipEl : function()
30233 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
30246 * @class Roo.bootstrap.FieldLabel
30247 * @extends Roo.bootstrap.Component
30248 * Bootstrap FieldLabel class
30249 * @cfg {String} html contents of the element
30250 * @cfg {String} tag tag of the element default label
30251 * @cfg {String} cls class of the element
30252 * @cfg {String} target label target
30253 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
30254 * @cfg {String} invalidClass default "text-warning"
30255 * @cfg {String} validClass default "text-success"
30256 * @cfg {String} iconTooltip default "This field is required"
30257 * @cfg {String} indicatorpos (left|right) default left
30260 * Create a new FieldLabel
30261 * @param {Object} config The config object
30264 Roo.bootstrap.FieldLabel = function(config){
30265 Roo.bootstrap.Element.superclass.constructor.call(this, config);
30270 * Fires after the field has been marked as invalid.
30271 * @param {Roo.form.FieldLabel} this
30272 * @param {String} msg The validation message
30277 * Fires after the field has been validated with no errors.
30278 * @param {Roo.form.FieldLabel} this
30284 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
30291 invalidClass : 'has-warning',
30292 validClass : 'has-success',
30293 iconTooltip : 'This field is required',
30294 indicatorpos : 'left',
30296 getAutoCreate : function(){
30299 if (!this.allowBlank) {
30305 cls : 'roo-bootstrap-field-label ' + this.cls,
30310 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star ' + cls,
30311 tooltip : this.iconTooltip
30320 if(this.indicatorpos == 'right'){
30323 cls : 'roo-bootstrap-field-label ' + this.cls,
30332 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star '+ cls,
30333 tooltip : this.iconTooltip
30342 initEvents: function()
30344 Roo.bootstrap.Element.superclass.initEvents.call(this);
30346 this.indicator = this.indicatorEl();
30348 if(this.indicator){
30349 this.indicator.removeClass('visible');
30350 this.indicator.addClass('invisible');
30353 Roo.bootstrap.FieldLabel.register(this);
30356 indicatorEl : function()
30358 var indicator = this.el.select('i.roo-required-indicator',true).first();
30369 * Mark this field as valid
30371 markValid : function()
30373 if(this.indicator){
30374 this.indicator.removeClass('visible');
30375 this.indicator.addClass('invisible');
30378 this.el.removeClass(this.invalidClass);
30380 this.el.addClass(this.validClass);
30382 this.fireEvent('valid', this);
30386 * Mark this field as invalid
30387 * @param {String} msg The validation message
30389 markInvalid : function(msg)
30391 if(this.indicator){
30392 this.indicator.removeClass('invisible');
30393 this.indicator.addClass('visible');
30396 this.el.removeClass(this.validClass);
30398 this.el.addClass(this.invalidClass);
30400 this.fireEvent('invalid', this, msg);
30406 Roo.apply(Roo.bootstrap.FieldLabel, {
30411 * register a FieldLabel Group
30412 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
30414 register : function(label)
30416 if(this.groups.hasOwnProperty(label.target)){
30420 this.groups[label.target] = label;
30424 * fetch a FieldLabel Group based on the target
30425 * @param {string} target
30426 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
30428 get: function(target) {
30429 if (typeof(this.groups[target]) == 'undefined') {
30433 return this.groups[target] ;
30442 * page DateSplitField.
30448 * @class Roo.bootstrap.DateSplitField
30449 * @extends Roo.bootstrap.Component
30450 * Bootstrap DateSplitField class
30451 * @cfg {string} fieldLabel - the label associated
30452 * @cfg {Number} labelWidth set the width of label (0-12)
30453 * @cfg {String} labelAlign (top|left)
30454 * @cfg {Boolean} dayAllowBlank (true|false) default false
30455 * @cfg {Boolean} monthAllowBlank (true|false) default false
30456 * @cfg {Boolean} yearAllowBlank (true|false) default false
30457 * @cfg {string} dayPlaceholder
30458 * @cfg {string} monthPlaceholder
30459 * @cfg {string} yearPlaceholder
30460 * @cfg {string} dayFormat default 'd'
30461 * @cfg {string} monthFormat default 'm'
30462 * @cfg {string} yearFormat default 'Y'
30463 * @cfg {Number} labellg set the width of label (1-12)
30464 * @cfg {Number} labelmd set the width of label (1-12)
30465 * @cfg {Number} labelsm set the width of label (1-12)
30466 * @cfg {Number} labelxs set the width of label (1-12)
30470 * Create a new DateSplitField
30471 * @param {Object} config The config object
30474 Roo.bootstrap.DateSplitField = function(config){
30475 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
30481 * getting the data of years
30482 * @param {Roo.bootstrap.DateSplitField} this
30483 * @param {Object} years
30488 * getting the data of days
30489 * @param {Roo.bootstrap.DateSplitField} this
30490 * @param {Object} days
30495 * Fires after the field has been marked as invalid.
30496 * @param {Roo.form.Field} this
30497 * @param {String} msg The validation message
30502 * Fires after the field has been validated with no errors.
30503 * @param {Roo.form.Field} this
30509 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
30512 labelAlign : 'top',
30514 dayAllowBlank : false,
30515 monthAllowBlank : false,
30516 yearAllowBlank : false,
30517 dayPlaceholder : '',
30518 monthPlaceholder : '',
30519 yearPlaceholder : '',
30523 isFormField : true,
30529 getAutoCreate : function()
30533 cls : 'row roo-date-split-field-group',
30538 cls : 'form-hidden-field roo-date-split-field-group-value',
30544 var labelCls = 'col-md-12';
30545 var contentCls = 'col-md-4';
30547 if(this.fieldLabel){
30551 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
30555 html : this.fieldLabel
30560 if(this.labelAlign == 'left'){
30562 if(this.labelWidth > 12){
30563 label.style = "width: " + this.labelWidth + 'px';
30566 if(this.labelWidth < 13 && this.labelmd == 0){
30567 this.labelmd = this.labelWidth;
30570 if(this.labellg > 0){
30571 labelCls = ' col-lg-' + this.labellg;
30572 contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
30575 if(this.labelmd > 0){
30576 labelCls = ' col-md-' + this.labelmd;
30577 contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
30580 if(this.labelsm > 0){
30581 labelCls = ' col-sm-' + this.labelsm;
30582 contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
30585 if(this.labelxs > 0){
30586 labelCls = ' col-xs-' + this.labelxs;
30587 contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
30591 label.cls += ' ' + labelCls;
30593 cfg.cn.push(label);
30596 Roo.each(['day', 'month', 'year'], function(t){
30599 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
30606 inputEl: function ()
30608 return this.el.select('.roo-date-split-field-group-value', true).first();
30611 onRender : function(ct, position)
30615 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30617 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
30619 this.dayField = new Roo.bootstrap.ComboBox({
30620 allowBlank : this.dayAllowBlank,
30621 alwaysQuery : true,
30622 displayField : 'value',
30625 forceSelection : true,
30627 placeholder : this.dayPlaceholder,
30628 selectOnFocus : true,
30629 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30630 triggerAction : 'all',
30632 valueField : 'value',
30633 store : new Roo.data.SimpleStore({
30634 data : (function() {
30636 _this.fireEvent('days', _this, days);
30639 fields : [ 'value' ]
30642 select : function (_self, record, index)
30644 _this.setValue(_this.getValue());
30649 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
30651 this.monthField = new Roo.bootstrap.MonthField({
30652 after : '<i class=\"fa fa-calendar\"></i>',
30653 allowBlank : this.monthAllowBlank,
30654 placeholder : this.monthPlaceholder,
30657 render : function (_self)
30659 this.el.select('span.input-group-addon', true).first().on('click', function(e){
30660 e.preventDefault();
30664 select : function (_self, oldvalue, newvalue)
30666 _this.setValue(_this.getValue());
30671 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
30673 this.yearField = new Roo.bootstrap.ComboBox({
30674 allowBlank : this.yearAllowBlank,
30675 alwaysQuery : true,
30676 displayField : 'value',
30679 forceSelection : true,
30681 placeholder : this.yearPlaceholder,
30682 selectOnFocus : true,
30683 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30684 triggerAction : 'all',
30686 valueField : 'value',
30687 store : new Roo.data.SimpleStore({
30688 data : (function() {
30690 _this.fireEvent('years', _this, years);
30693 fields : [ 'value' ]
30696 select : function (_self, record, index)
30698 _this.setValue(_this.getValue());
30703 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
30706 setValue : function(v, format)
30708 this.inputEl.dom.value = v;
30710 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
30712 var d = Date.parseDate(v, f);
30719 this.setDay(d.format(this.dayFormat));
30720 this.setMonth(d.format(this.monthFormat));
30721 this.setYear(d.format(this.yearFormat));
30728 setDay : function(v)
30730 this.dayField.setValue(v);
30731 this.inputEl.dom.value = this.getValue();
30736 setMonth : function(v)
30738 this.monthField.setValue(v, true);
30739 this.inputEl.dom.value = this.getValue();
30744 setYear : function(v)
30746 this.yearField.setValue(v);
30747 this.inputEl.dom.value = this.getValue();
30752 getDay : function()
30754 return this.dayField.getValue();
30757 getMonth : function()
30759 return this.monthField.getValue();
30762 getYear : function()
30764 return this.yearField.getValue();
30767 getValue : function()
30769 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
30771 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
30781 this.inputEl.dom.value = '';
30786 validate : function()
30788 var d = this.dayField.validate();
30789 var m = this.monthField.validate();
30790 var y = this.yearField.validate();
30795 (!this.dayAllowBlank && !d) ||
30796 (!this.monthAllowBlank && !m) ||
30797 (!this.yearAllowBlank && !y)
30802 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
30811 this.markInvalid();
30816 markValid : function()
30819 var label = this.el.select('label', true).first();
30820 var icon = this.el.select('i.fa-star', true).first();
30826 this.fireEvent('valid', this);
30830 * Mark this field as invalid
30831 * @param {String} msg The validation message
30833 markInvalid : function(msg)
30836 var label = this.el.select('label', true).first();
30837 var icon = this.el.select('i.fa-star', true).first();
30839 if(label && !icon){
30840 this.el.select('.roo-date-split-field-label', true).createChild({
30842 cls : 'text-danger fa fa-lg fa-star',
30843 tooltip : 'This field is required',
30844 style : 'margin-right:5px;'
30848 this.fireEvent('invalid', this, msg);
30851 clearInvalid : function()
30853 var label = this.el.select('label', true).first();
30854 var icon = this.el.select('i.fa-star', true).first();
30860 this.fireEvent('valid', this);
30863 getName: function()
30873 * http://masonry.desandro.com
30875 * The idea is to render all the bricks based on vertical width...
30877 * The original code extends 'outlayer' - we might need to use that....
30883 * @class Roo.bootstrap.LayoutMasonry
30884 * @extends Roo.bootstrap.Component
30885 * Bootstrap Layout Masonry class
30888 * Create a new Element
30889 * @param {Object} config The config object
30892 Roo.bootstrap.LayoutMasonry = function(config){
30894 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
30898 Roo.bootstrap.LayoutMasonry.register(this);
30904 * Fire after layout the items
30905 * @param {Roo.bootstrap.LayoutMasonry} this
30906 * @param {Roo.EventObject} e
30913 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
30916 * @cfg {Boolean} isLayoutInstant = no animation?
30918 isLayoutInstant : false, // needed?
30921 * @cfg {Number} boxWidth width of the columns
30926 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
30931 * @cfg {Number} padWidth padding below box..
30936 * @cfg {Number} gutter gutter width..
30941 * @cfg {Number} maxCols maximum number of columns
30947 * @cfg {Boolean} isAutoInitial defalut true
30949 isAutoInitial : true,
30954 * @cfg {Boolean} isHorizontal defalut false
30956 isHorizontal : false,
30958 currentSize : null,
30964 bricks: null, //CompositeElement
30968 _isLayoutInited : false,
30970 // isAlternative : false, // only use for vertical layout...
30973 * @cfg {Number} alternativePadWidth padding below box..
30975 alternativePadWidth : 50,
30977 selectedBrick : [],
30979 getAutoCreate : function(){
30981 var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
30985 cls: 'blog-masonary-wrapper ' + this.cls,
30987 cls : 'mas-boxes masonary'
30994 getChildContainer: function( )
30996 if (this.boxesEl) {
30997 return this.boxesEl;
31000 this.boxesEl = this.el.select('.mas-boxes').first();
31002 return this.boxesEl;
31006 initEvents : function()
31010 if(this.isAutoInitial){
31011 Roo.log('hook children rendered');
31012 this.on('childrenrendered', function() {
31013 Roo.log('children rendered');
31019 initial : function()
31021 this.selectedBrick = [];
31023 this.currentSize = this.el.getBox(true);
31025 Roo.EventManager.onWindowResize(this.resize, this);
31027 if(!this.isAutoInitial){
31035 //this.layout.defer(500,this);
31039 resize : function()
31041 var cs = this.el.getBox(true);
31044 this.currentSize.width == cs.width &&
31045 this.currentSize.x == cs.x &&
31046 this.currentSize.height == cs.height &&
31047 this.currentSize.y == cs.y
31049 Roo.log("no change in with or X or Y");
31053 this.currentSize = cs;
31059 layout : function()
31061 this._resetLayout();
31063 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
31065 this.layoutItems( isInstant );
31067 this._isLayoutInited = true;
31069 this.fireEvent('layout', this);
31073 _resetLayout : function()
31075 if(this.isHorizontal){
31076 this.horizontalMeasureColumns();
31080 this.verticalMeasureColumns();
31084 verticalMeasureColumns : function()
31086 this.getContainerWidth();
31088 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
31089 // this.colWidth = Math.floor(this.containerWidth * 0.8);
31093 var boxWidth = this.boxWidth + this.padWidth;
31095 if(this.containerWidth < this.boxWidth){
31096 boxWidth = this.containerWidth
31099 var containerWidth = this.containerWidth;
31101 var cols = Math.floor(containerWidth / boxWidth);
31103 this.cols = Math.max( cols, 1 );
31105 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
31107 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
31109 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
31111 this.colWidth = boxWidth + avail - this.padWidth;
31113 this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
31114 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
31117 horizontalMeasureColumns : function()
31119 this.getContainerWidth();
31121 var boxWidth = this.boxWidth;
31123 if(this.containerWidth < boxWidth){
31124 boxWidth = this.containerWidth;
31127 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
31129 this.el.setHeight(boxWidth);
31133 getContainerWidth : function()
31135 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
31138 layoutItems : function( isInstant )
31140 Roo.log(this.bricks);
31142 var items = Roo.apply([], this.bricks);
31144 if(this.isHorizontal){
31145 this._horizontalLayoutItems( items , isInstant );
31149 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
31150 // this._verticalAlternativeLayoutItems( items , isInstant );
31154 this._verticalLayoutItems( items , isInstant );
31158 _verticalLayoutItems : function ( items , isInstant)
31160 if ( !items || !items.length ) {
31165 ['xs', 'xs', 'xs', 'tall'],
31166 ['xs', 'xs', 'tall'],
31167 ['xs', 'xs', 'sm'],
31168 ['xs', 'xs', 'xs'],
31174 ['sm', 'xs', 'xs'],
31178 ['tall', 'xs', 'xs', 'xs'],
31179 ['tall', 'xs', 'xs'],
31191 Roo.each(items, function(item, k){
31193 switch (item.size) {
31194 // these layouts take up a full box,
31205 boxes.push([item]);
31228 var filterPattern = function(box, length)
31236 var pattern = box.slice(0, length);
31240 Roo.each(pattern, function(i){
31241 format.push(i.size);
31244 Roo.each(standard, function(s){
31246 if(String(s) != String(format)){
31255 if(!match && length == 1){
31260 filterPattern(box, length - 1);
31264 queue.push(pattern);
31266 box = box.slice(length, box.length);
31268 filterPattern(box, 4);
31274 Roo.each(boxes, function(box, k){
31280 if(box.length == 1){
31285 filterPattern(box, 4);
31289 this._processVerticalLayoutQueue( queue, isInstant );
31293 // _verticalAlternativeLayoutItems : function( items , isInstant )
31295 // if ( !items || !items.length ) {
31299 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
31303 _horizontalLayoutItems : function ( items , isInstant)
31305 if ( !items || !items.length || items.length < 3) {
31311 var eItems = items.slice(0, 3);
31313 items = items.slice(3, items.length);
31316 ['xs', 'xs', 'xs', 'wide'],
31317 ['xs', 'xs', 'wide'],
31318 ['xs', 'xs', 'sm'],
31319 ['xs', 'xs', 'xs'],
31325 ['sm', 'xs', 'xs'],
31329 ['wide', 'xs', 'xs', 'xs'],
31330 ['wide', 'xs', 'xs'],
31343 Roo.each(items, function(item, k){
31345 switch (item.size) {
31356 boxes.push([item]);
31380 var filterPattern = function(box, length)
31388 var pattern = box.slice(0, length);
31392 Roo.each(pattern, function(i){
31393 format.push(i.size);
31396 Roo.each(standard, function(s){
31398 if(String(s) != String(format)){
31407 if(!match && length == 1){
31412 filterPattern(box, length - 1);
31416 queue.push(pattern);
31418 box = box.slice(length, box.length);
31420 filterPattern(box, 4);
31426 Roo.each(boxes, function(box, k){
31432 if(box.length == 1){
31437 filterPattern(box, 4);
31444 var pos = this.el.getBox(true);
31448 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31450 var hit_end = false;
31452 Roo.each(queue, function(box){
31456 Roo.each(box, function(b){
31458 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31468 Roo.each(box, function(b){
31470 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31473 mx = Math.max(mx, b.x);
31477 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
31481 Roo.each(box, function(b){
31483 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31497 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
31500 /** Sets position of item in DOM
31501 * @param {Element} item
31502 * @param {Number} x - horizontal position
31503 * @param {Number} y - vertical position
31504 * @param {Boolean} isInstant - disables transitions
31506 _processVerticalLayoutQueue : function( queue, isInstant )
31508 var pos = this.el.getBox(true);
31513 for (var i = 0; i < this.cols; i++){
31517 Roo.each(queue, function(box, k){
31519 var col = k % this.cols;
31521 Roo.each(box, function(b,kk){
31523 b.el.position('absolute');
31525 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31526 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31528 if(b.size == 'md-left' || b.size == 'md-right'){
31529 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31530 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31533 b.el.setWidth(width);
31534 b.el.setHeight(height);
31536 b.el.select('iframe',true).setSize(width,height);
31540 for (var i = 0; i < this.cols; i++){
31542 if(maxY[i] < maxY[col]){
31547 col = Math.min(col, i);
31551 x = pos.x + col * (this.colWidth + this.padWidth);
31555 var positions = [];
31557 switch (box.length){
31559 positions = this.getVerticalOneBoxColPositions(x, y, box);
31562 positions = this.getVerticalTwoBoxColPositions(x, y, box);
31565 positions = this.getVerticalThreeBoxColPositions(x, y, box);
31568 positions = this.getVerticalFourBoxColPositions(x, y, box);
31574 Roo.each(box, function(b,kk){
31576 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31578 var sz = b.el.getSize();
31580 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
31588 for (var i = 0; i < this.cols; i++){
31589 mY = Math.max(mY, maxY[i]);
31592 this.el.setHeight(mY - pos.y);
31596 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
31598 // var pos = this.el.getBox(true);
31601 // var maxX = pos.right;
31603 // var maxHeight = 0;
31605 // Roo.each(items, function(item, k){
31609 // item.el.position('absolute');
31611 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
31613 // item.el.setWidth(width);
31615 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
31617 // item.el.setHeight(height);
31620 // item.el.setXY([x, y], isInstant ? false : true);
31622 // item.el.setXY([maxX - width, y], isInstant ? false : true);
31625 // y = y + height + this.alternativePadWidth;
31627 // maxHeight = maxHeight + height + this.alternativePadWidth;
31631 // this.el.setHeight(maxHeight);
31635 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
31637 var pos = this.el.getBox(true);
31642 var maxX = pos.right;
31644 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
31646 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31648 Roo.each(queue, function(box, k){
31650 Roo.each(box, function(b, kk){
31652 b.el.position('absolute');
31654 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31655 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31657 if(b.size == 'md-left' || b.size == 'md-right'){
31658 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31659 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31662 b.el.setWidth(width);
31663 b.el.setHeight(height);
31671 var positions = [];
31673 switch (box.length){
31675 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
31678 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
31681 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
31684 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
31690 Roo.each(box, function(b,kk){
31692 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31694 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
31702 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
31704 Roo.each(eItems, function(b,k){
31706 b.size = (k == 0) ? 'sm' : 'xs';
31707 b.x = (k == 0) ? 2 : 1;
31708 b.y = (k == 0) ? 2 : 1;
31710 b.el.position('absolute');
31712 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31714 b.el.setWidth(width);
31716 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31718 b.el.setHeight(height);
31722 var positions = [];
31725 x : maxX - this.unitWidth * 2 - this.gutter,
31730 x : maxX - this.unitWidth,
31731 y : minY + (this.unitWidth + this.gutter) * 2
31735 x : maxX - this.unitWidth * 3 - this.gutter * 2,
31739 Roo.each(eItems, function(b,k){
31741 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
31747 getVerticalOneBoxColPositions : function(x, y, box)
31751 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
31753 if(box[0].size == 'md-left'){
31757 if(box[0].size == 'md-right'){
31762 x : x + (this.unitWidth + this.gutter) * rand,
31769 getVerticalTwoBoxColPositions : function(x, y, box)
31773 if(box[0].size == 'xs'){
31777 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
31781 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
31795 x : x + (this.unitWidth + this.gutter) * 2,
31796 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
31803 getVerticalThreeBoxColPositions : function(x, y, box)
31807 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31815 x : x + (this.unitWidth + this.gutter) * 1,
31820 x : x + (this.unitWidth + this.gutter) * 2,
31828 if(box[0].size == 'xs' && box[1].size == 'xs'){
31837 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
31841 x : x + (this.unitWidth + this.gutter) * 1,
31855 x : x + (this.unitWidth + this.gutter) * 2,
31860 x : x + (this.unitWidth + this.gutter) * 2,
31861 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
31868 getVerticalFourBoxColPositions : function(x, y, box)
31872 if(box[0].size == 'xs'){
31881 y : y + (this.unitHeight + this.gutter) * 1
31886 y : y + (this.unitHeight + this.gutter) * 2
31890 x : x + (this.unitWidth + this.gutter) * 1,
31904 x : x + (this.unitWidth + this.gutter) * 2,
31909 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
31910 y : y + (this.unitHeight + this.gutter) * 1
31914 x : x + (this.unitWidth + this.gutter) * 2,
31915 y : y + (this.unitWidth + this.gutter) * 2
31922 getHorizontalOneBoxColPositions : function(maxX, minY, box)
31926 if(box[0].size == 'md-left'){
31928 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31935 if(box[0].size == 'md-right'){
31937 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31938 y : minY + (this.unitWidth + this.gutter) * 1
31944 var rand = Math.floor(Math.random() * (4 - box[0].y));
31947 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31948 y : minY + (this.unitWidth + this.gutter) * rand
31955 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
31959 if(box[0].size == 'xs'){
31962 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31967 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31968 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
31976 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31981 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31982 y : minY + (this.unitWidth + this.gutter) * 2
31989 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
31993 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31996 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32001 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32002 y : minY + (this.unitWidth + this.gutter) * 1
32006 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32007 y : minY + (this.unitWidth + this.gutter) * 2
32014 if(box[0].size == 'xs' && box[1].size == 'xs'){
32017 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32022 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32027 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32028 y : minY + (this.unitWidth + this.gutter) * 1
32036 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32041 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32042 y : minY + (this.unitWidth + this.gutter) * 2
32046 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32047 y : minY + (this.unitWidth + this.gutter) * 2
32054 getHorizontalFourBoxColPositions : function(maxX, minY, box)
32058 if(box[0].size == 'xs'){
32061 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32066 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32071 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),
32076 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
32077 y : minY + (this.unitWidth + this.gutter) * 1
32085 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32090 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32091 y : minY + (this.unitWidth + this.gutter) * 2
32095 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32096 y : minY + (this.unitWidth + this.gutter) * 2
32100 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),
32101 y : minY + (this.unitWidth + this.gutter) * 2
32109 * remove a Masonry Brick
32110 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
32112 removeBrick : function(brick_id)
32118 for (var i = 0; i<this.bricks.length; i++) {
32119 if (this.bricks[i].id == brick_id) {
32120 this.bricks.splice(i,1);
32121 this.el.dom.removeChild(Roo.get(brick_id).dom);
32128 * adds a Masonry Brick
32129 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32131 addBrick : function(cfg)
32133 var cn = new Roo.bootstrap.MasonryBrick(cfg);
32134 //this.register(cn);
32135 cn.parentId = this.id;
32136 cn.render(this.el);
32141 * register a Masonry Brick
32142 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32145 register : function(brick)
32147 this.bricks.push(brick);
32148 brick.masonryId = this.id;
32152 * clear all the Masonry Brick
32154 clearAll : function()
32157 //this.getChildContainer().dom.innerHTML = "";
32158 this.el.dom.innerHTML = '';
32161 getSelected : function()
32163 if (!this.selectedBrick) {
32167 return this.selectedBrick;
32171 Roo.apply(Roo.bootstrap.LayoutMasonry, {
32175 * register a Masonry Layout
32176 * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
32179 register : function(layout)
32181 this.groups[layout.id] = layout;
32184 * fetch a Masonry Layout based on the masonry layout ID
32185 * @param {string} the masonry layout to add
32186 * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
32189 get: function(layout_id) {
32190 if (typeof(this.groups[layout_id]) == 'undefined') {
32193 return this.groups[layout_id] ;
32205 * http://masonry.desandro.com
32207 * The idea is to render all the bricks based on vertical width...
32209 * The original code extends 'outlayer' - we might need to use that....
32215 * @class Roo.bootstrap.LayoutMasonryAuto
32216 * @extends Roo.bootstrap.Component
32217 * Bootstrap Layout Masonry class
32220 * Create a new Element
32221 * @param {Object} config The config object
32224 Roo.bootstrap.LayoutMasonryAuto = function(config){
32225 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
32228 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
32231 * @cfg {Boolean} isFitWidth - resize the width..
32233 isFitWidth : false, // options..
32235 * @cfg {Boolean} isOriginLeft = left align?
32237 isOriginLeft : true,
32239 * @cfg {Boolean} isOriginTop = top align?
32241 isOriginTop : false,
32243 * @cfg {Boolean} isLayoutInstant = no animation?
32245 isLayoutInstant : false, // needed?
32247 * @cfg {Boolean} isResizingContainer = not sure if this is used..
32249 isResizingContainer : true,
32251 * @cfg {Number} columnWidth width of the columns
32257 * @cfg {Number} maxCols maximum number of columns
32262 * @cfg {Number} padHeight padding below box..
32268 * @cfg {Boolean} isAutoInitial defalut true
32271 isAutoInitial : true,
32277 initialColumnWidth : 0,
32278 currentSize : null,
32280 colYs : null, // array.
32287 bricks: null, //CompositeElement
32288 cols : 0, // array?
32289 // element : null, // wrapped now this.el
32290 _isLayoutInited : null,
32293 getAutoCreate : function(){
32297 cls: 'blog-masonary-wrapper ' + this.cls,
32299 cls : 'mas-boxes masonary'
32306 getChildContainer: function( )
32308 if (this.boxesEl) {
32309 return this.boxesEl;
32312 this.boxesEl = this.el.select('.mas-boxes').first();
32314 return this.boxesEl;
32318 initEvents : function()
32322 if(this.isAutoInitial){
32323 Roo.log('hook children rendered');
32324 this.on('childrenrendered', function() {
32325 Roo.log('children rendered');
32332 initial : function()
32334 this.reloadItems();
32336 this.currentSize = this.el.getBox(true);
32338 /// was window resize... - let's see if this works..
32339 Roo.EventManager.onWindowResize(this.resize, this);
32341 if(!this.isAutoInitial){
32346 this.layout.defer(500,this);
32349 reloadItems: function()
32351 this.bricks = this.el.select('.masonry-brick', true);
32353 this.bricks.each(function(b) {
32354 //Roo.log(b.getSize());
32355 if (!b.attr('originalwidth')) {
32356 b.attr('originalwidth', b.getSize().width);
32361 Roo.log(this.bricks.elements.length);
32364 resize : function()
32367 var cs = this.el.getBox(true);
32369 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
32370 Roo.log("no change in with or X");
32373 this.currentSize = cs;
32377 layout : function()
32380 this._resetLayout();
32381 //this._manageStamps();
32383 // don't animate first layout
32384 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
32385 this.layoutItems( isInstant );
32387 // flag for initalized
32388 this._isLayoutInited = true;
32391 layoutItems : function( isInstant )
32393 //var items = this._getItemsForLayout( this.items );
32394 // original code supports filtering layout items.. we just ignore it..
32396 this._layoutItems( this.bricks , isInstant );
32398 this._postLayout();
32400 _layoutItems : function ( items , isInstant)
32402 //this.fireEvent( 'layout', this, items );
32405 if ( !items || !items.elements.length ) {
32406 // no items, emit event with empty array
32411 items.each(function(item) {
32412 Roo.log("layout item");
32414 // get x/y object from method
32415 var position = this._getItemLayoutPosition( item );
32417 position.item = item;
32418 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
32419 queue.push( position );
32422 this._processLayoutQueue( queue );
32424 /** Sets position of item in DOM
32425 * @param {Element} item
32426 * @param {Number} x - horizontal position
32427 * @param {Number} y - vertical position
32428 * @param {Boolean} isInstant - disables transitions
32430 _processLayoutQueue : function( queue )
32432 for ( var i=0, len = queue.length; i < len; i++ ) {
32433 var obj = queue[i];
32434 obj.item.position('absolute');
32435 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
32441 * Any logic you want to do after each layout,
32442 * i.e. size the container
32444 _postLayout : function()
32446 this.resizeContainer();
32449 resizeContainer : function()
32451 if ( !this.isResizingContainer ) {
32454 var size = this._getContainerSize();
32456 this.el.setSize(size.width,size.height);
32457 this.boxesEl.setSize(size.width,size.height);
32463 _resetLayout : function()
32465 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
32466 this.colWidth = this.el.getWidth();
32467 //this.gutter = this.el.getWidth();
32469 this.measureColumns();
32475 this.colYs.push( 0 );
32481 measureColumns : function()
32483 this.getContainerWidth();
32484 // if columnWidth is 0, default to outerWidth of first item
32485 if ( !this.columnWidth ) {
32486 var firstItem = this.bricks.first();
32487 Roo.log(firstItem);
32488 this.columnWidth = this.containerWidth;
32489 if (firstItem && firstItem.attr('originalwidth') ) {
32490 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
32492 // columnWidth fall back to item of first element
32493 Roo.log("set column width?");
32494 this.initialColumnWidth = this.columnWidth ;
32496 // if first elem has no width, default to size of container
32501 if (this.initialColumnWidth) {
32502 this.columnWidth = this.initialColumnWidth;
32507 // column width is fixed at the top - however if container width get's smaller we should
32510 // this bit calcs how man columns..
32512 var columnWidth = this.columnWidth += this.gutter;
32514 // calculate columns
32515 var containerWidth = this.containerWidth + this.gutter;
32517 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
32518 // fix rounding errors, typically with gutters
32519 var excess = columnWidth - containerWidth % columnWidth;
32522 // if overshoot is less than a pixel, round up, otherwise floor it
32523 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
32524 cols = Math[ mathMethod ]( cols );
32525 this.cols = Math.max( cols, 1 );
32526 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
32528 // padding positioning..
32529 var totalColWidth = this.cols * this.columnWidth;
32530 var padavail = this.containerWidth - totalColWidth;
32531 // so for 2 columns - we need 3 'pads'
32533 var padNeeded = (1+this.cols) * this.padWidth;
32535 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
32537 this.columnWidth += padExtra
32538 //this.padWidth = Math.floor(padavail / ( this.cols));
32540 // adjust colum width so that padding is fixed??
32542 // we have 3 columns ... total = width * 3
32543 // we have X left over... that should be used by
32545 //if (this.expandC) {
32553 getContainerWidth : function()
32555 /* // container is parent if fit width
32556 var container = this.isFitWidth ? this.element.parentNode : this.element;
32557 // check that this.size and size are there
32558 // IE8 triggers resize on body size change, so they might not be
32560 var size = getSize( container ); //FIXME
32561 this.containerWidth = size && size.innerWidth; //FIXME
32564 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
32568 _getItemLayoutPosition : function( item ) // what is item?
32570 // we resize the item to our columnWidth..
32572 item.setWidth(this.columnWidth);
32573 item.autoBoxAdjust = false;
32575 var sz = item.getSize();
32577 // how many columns does this brick span
32578 var remainder = this.containerWidth % this.columnWidth;
32580 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
32581 // round if off by 1 pixel, otherwise use ceil
32582 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
32583 colSpan = Math.min( colSpan, this.cols );
32585 // normally this should be '1' as we dont' currently allow multi width columns..
32587 var colGroup = this._getColGroup( colSpan );
32588 // get the minimum Y value from the columns
32589 var minimumY = Math.min.apply( Math, colGroup );
32590 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32592 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
32594 // position the brick
32596 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
32597 y: this.currentSize.y + minimumY + this.padHeight
32601 // apply setHeight to necessary columns
32602 var setHeight = minimumY + sz.height + this.padHeight;
32603 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32605 var setSpan = this.cols + 1 - colGroup.length;
32606 for ( var i = 0; i < setSpan; i++ ) {
32607 this.colYs[ shortColIndex + i ] = setHeight ;
32614 * @param {Number} colSpan - number of columns the element spans
32615 * @returns {Array} colGroup
32617 _getColGroup : function( colSpan )
32619 if ( colSpan < 2 ) {
32620 // if brick spans only one column, use all the column Ys
32625 // how many different places could this brick fit horizontally
32626 var groupCount = this.cols + 1 - colSpan;
32627 // for each group potential horizontal position
32628 for ( var i = 0; i < groupCount; i++ ) {
32629 // make an array of colY values for that one group
32630 var groupColYs = this.colYs.slice( i, i + colSpan );
32631 // and get the max value of the array
32632 colGroup[i] = Math.max.apply( Math, groupColYs );
32637 _manageStamp : function( stamp )
32639 var stampSize = stamp.getSize();
32640 var offset = stamp.getBox();
32641 // get the columns that this stamp affects
32642 var firstX = this.isOriginLeft ? offset.x : offset.right;
32643 var lastX = firstX + stampSize.width;
32644 var firstCol = Math.floor( firstX / this.columnWidth );
32645 firstCol = Math.max( 0, firstCol );
32647 var lastCol = Math.floor( lastX / this.columnWidth );
32648 // lastCol should not go over if multiple of columnWidth #425
32649 lastCol -= lastX % this.columnWidth ? 0 : 1;
32650 lastCol = Math.min( this.cols - 1, lastCol );
32652 // set colYs to bottom of the stamp
32653 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
32656 for ( var i = firstCol; i <= lastCol; i++ ) {
32657 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
32662 _getContainerSize : function()
32664 this.maxY = Math.max.apply( Math, this.colYs );
32669 if ( this.isFitWidth ) {
32670 size.width = this._getContainerFitWidth();
32676 _getContainerFitWidth : function()
32678 var unusedCols = 0;
32679 // count unused columns
32682 if ( this.colYs[i] !== 0 ) {
32687 // fit container to columns that have been used
32688 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
32691 needsResizeLayout : function()
32693 var previousWidth = this.containerWidth;
32694 this.getContainerWidth();
32695 return previousWidth !== this.containerWidth;
32710 * @class Roo.bootstrap.MasonryBrick
32711 * @extends Roo.bootstrap.Component
32712 * Bootstrap MasonryBrick class
32715 * Create a new MasonryBrick
32716 * @param {Object} config The config object
32719 Roo.bootstrap.MasonryBrick = function(config){
32721 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
32723 Roo.bootstrap.MasonryBrick.register(this);
32729 * When a MasonryBrick is clcik
32730 * @param {Roo.bootstrap.MasonryBrick} this
32731 * @param {Roo.EventObject} e
32737 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
32740 * @cfg {String} title
32744 * @cfg {String} html
32748 * @cfg {String} bgimage
32752 * @cfg {String} videourl
32756 * @cfg {String} cls
32760 * @cfg {String} href
32764 * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
32769 * @cfg {String} placetitle (center|bottom)
32774 * @cfg {Boolean} isFitContainer defalut true
32776 isFitContainer : true,
32779 * @cfg {Boolean} preventDefault defalut false
32781 preventDefault : false,
32784 * @cfg {Boolean} inverse defalut false
32786 maskInverse : false,
32788 getAutoCreate : function()
32790 if(!this.isFitContainer){
32791 return this.getSplitAutoCreate();
32794 var cls = 'masonry-brick masonry-brick-full';
32796 if(this.href.length){
32797 cls += ' masonry-brick-link';
32800 if(this.bgimage.length){
32801 cls += ' masonry-brick-image';
32804 if(this.maskInverse){
32805 cls += ' mask-inverse';
32808 if(!this.html.length && !this.maskInverse && !this.videourl.length){
32809 cls += ' enable-mask';
32813 cls += ' masonry-' + this.size + '-brick';
32816 if(this.placetitle.length){
32818 switch (this.placetitle) {
32820 cls += ' masonry-center-title';
32823 cls += ' masonry-bottom-title';
32830 if(!this.html.length && !this.bgimage.length){
32831 cls += ' masonry-center-title';
32834 if(!this.html.length && this.bgimage.length){
32835 cls += ' masonry-bottom-title';
32840 cls += ' ' + this.cls;
32844 tag: (this.href.length) ? 'a' : 'div',
32849 cls: 'masonry-brick-mask'
32853 cls: 'masonry-brick-paragraph',
32859 if(this.href.length){
32860 cfg.href = this.href;
32863 var cn = cfg.cn[1].cn;
32865 if(this.title.length){
32868 cls: 'masonry-brick-title',
32873 if(this.html.length){
32876 cls: 'masonry-brick-text',
32881 if (!this.title.length && !this.html.length) {
32882 cfg.cn[1].cls += ' hide';
32885 if(this.bgimage.length){
32888 cls: 'masonry-brick-image-view',
32893 if(this.videourl.length){
32894 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32895 // youtube support only?
32898 cls: 'masonry-brick-image-view',
32901 allowfullscreen : true
32909 getSplitAutoCreate : function()
32911 var cls = 'masonry-brick masonry-brick-split';
32913 if(this.href.length){
32914 cls += ' masonry-brick-link';
32917 if(this.bgimage.length){
32918 cls += ' masonry-brick-image';
32922 cls += ' masonry-' + this.size + '-brick';
32925 switch (this.placetitle) {
32927 cls += ' masonry-center-title';
32930 cls += ' masonry-bottom-title';
32933 if(!this.bgimage.length){
32934 cls += ' masonry-center-title';
32937 if(this.bgimage.length){
32938 cls += ' masonry-bottom-title';
32944 cls += ' ' + this.cls;
32948 tag: (this.href.length) ? 'a' : 'div',
32953 cls: 'masonry-brick-split-head',
32957 cls: 'masonry-brick-paragraph',
32964 cls: 'masonry-brick-split-body',
32970 if(this.href.length){
32971 cfg.href = this.href;
32974 if(this.title.length){
32975 cfg.cn[0].cn[0].cn.push({
32977 cls: 'masonry-brick-title',
32982 if(this.html.length){
32983 cfg.cn[1].cn.push({
32985 cls: 'masonry-brick-text',
32990 if(this.bgimage.length){
32991 cfg.cn[0].cn.push({
32993 cls: 'masonry-brick-image-view',
32998 if(this.videourl.length){
32999 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
33000 // youtube support only?
33001 cfg.cn[0].cn.cn.push({
33003 cls: 'masonry-brick-image-view',
33006 allowfullscreen : true
33013 initEvents: function()
33015 switch (this.size) {
33048 this.el.on('touchstart', this.onTouchStart, this);
33049 this.el.on('touchmove', this.onTouchMove, this);
33050 this.el.on('touchend', this.onTouchEnd, this);
33051 this.el.on('contextmenu', this.onContextMenu, this);
33053 this.el.on('mouseenter' ,this.enter, this);
33054 this.el.on('mouseleave', this.leave, this);
33055 this.el.on('click', this.onClick, this);
33058 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
33059 this.parent().bricks.push(this);
33064 onClick: function(e, el)
33066 var time = this.endTimer - this.startTimer;
33067 // Roo.log(e.preventDefault());
33070 e.preventDefault();
33075 if(!this.preventDefault){
33079 e.preventDefault();
33081 if (this.activeClass != '') {
33082 this.selectBrick();
33085 this.fireEvent('click', this, e);
33088 enter: function(e, el)
33090 e.preventDefault();
33092 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
33096 if(this.bgimage.length && this.html.length){
33097 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
33101 leave: function(e, el)
33103 e.preventDefault();
33105 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
33109 if(this.bgimage.length && this.html.length){
33110 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
33114 onTouchStart: function(e, el)
33116 // e.preventDefault();
33118 this.touchmoved = false;
33120 if(!this.isFitContainer){
33124 if(!this.bgimage.length || !this.html.length){
33128 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
33130 this.timer = new Date().getTime();
33134 onTouchMove: function(e, el)
33136 this.touchmoved = true;
33139 onContextMenu : function(e,el)
33141 e.preventDefault();
33142 e.stopPropagation();
33146 onTouchEnd: function(e, el)
33148 // e.preventDefault();
33150 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
33157 if(!this.bgimage.length || !this.html.length){
33159 if(this.href.length){
33160 window.location.href = this.href;
33166 if(!this.isFitContainer){
33170 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
33172 window.location.href = this.href;
33175 //selection on single brick only
33176 selectBrick : function() {
33178 if (!this.parentId) {
33182 var m = Roo.bootstrap.LayoutMasonry.get(this.parentId);
33183 var index = m.selectedBrick.indexOf(this.id);
33186 m.selectedBrick.splice(index,1);
33187 this.el.removeClass(this.activeClass);
33191 for(var i = 0; i < m.selectedBrick.length; i++) {
33192 var b = Roo.bootstrap.MasonryBrick.get(m.selectedBrick[i]);
33193 b.el.removeClass(b.activeClass);
33196 m.selectedBrick = [];
33198 m.selectedBrick.push(this.id);
33199 this.el.addClass(this.activeClass);
33203 isSelected : function(){
33204 return this.el.hasClass(this.activeClass);
33209 Roo.apply(Roo.bootstrap.MasonryBrick, {
33212 groups : new Roo.util.MixedCollection(false, function(o) { return o.el.id; }),
33214 * register a Masonry Brick
33215 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
33218 register : function(brick)
33220 //this.groups[brick.id] = brick;
33221 this.groups.add(brick.id, brick);
33224 * fetch a masonry brick based on the masonry brick ID
33225 * @param {string} the masonry brick to add
33226 * @returns {Roo.bootstrap.MasonryBrick} the masonry brick
33229 get: function(brick_id)
33231 // if (typeof(this.groups[brick_id]) == 'undefined') {
33234 // return this.groups[brick_id] ;
33236 if(this.groups.key(brick_id)) {
33237 return this.groups.key(brick_id);
33255 * @class Roo.bootstrap.Brick
33256 * @extends Roo.bootstrap.Component
33257 * Bootstrap Brick class
33260 * Create a new Brick
33261 * @param {Object} config The config object
33264 Roo.bootstrap.Brick = function(config){
33265 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
33271 * When a Brick is click
33272 * @param {Roo.bootstrap.Brick} this
33273 * @param {Roo.EventObject} e
33279 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
33282 * @cfg {String} title
33286 * @cfg {String} html
33290 * @cfg {String} bgimage
33294 * @cfg {String} cls
33298 * @cfg {String} href
33302 * @cfg {String} video
33306 * @cfg {Boolean} square
33310 getAutoCreate : function()
33312 var cls = 'roo-brick';
33314 if(this.href.length){
33315 cls += ' roo-brick-link';
33318 if(this.bgimage.length){
33319 cls += ' roo-brick-image';
33322 if(!this.html.length && !this.bgimage.length){
33323 cls += ' roo-brick-center-title';
33326 if(!this.html.length && this.bgimage.length){
33327 cls += ' roo-brick-bottom-title';
33331 cls += ' ' + this.cls;
33335 tag: (this.href.length) ? 'a' : 'div',
33340 cls: 'roo-brick-paragraph',
33346 if(this.href.length){
33347 cfg.href = this.href;
33350 var cn = cfg.cn[0].cn;
33352 if(this.title.length){
33355 cls: 'roo-brick-title',
33360 if(this.html.length){
33363 cls: 'roo-brick-text',
33370 if(this.bgimage.length){
33373 cls: 'roo-brick-image-view',
33381 initEvents: function()
33383 if(this.title.length || this.html.length){
33384 this.el.on('mouseenter' ,this.enter, this);
33385 this.el.on('mouseleave', this.leave, this);
33388 Roo.EventManager.onWindowResize(this.resize, this);
33390 if(this.bgimage.length){
33391 this.imageEl = this.el.select('.roo-brick-image-view', true).first();
33392 this.imageEl.on('load', this.onImageLoad, this);
33399 onImageLoad : function()
33404 resize : function()
33406 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
33408 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
33410 if(this.bgimage.length){
33411 var image = this.el.select('.roo-brick-image-view', true).first();
33413 image.setWidth(paragraph.getWidth());
33416 image.setHeight(paragraph.getWidth());
33419 this.el.setHeight(image.getHeight());
33420 paragraph.setHeight(image.getHeight());
33426 enter: function(e, el)
33428 e.preventDefault();
33430 if(this.bgimage.length){
33431 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
33432 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
33436 leave: function(e, el)
33438 e.preventDefault();
33440 if(this.bgimage.length){
33441 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
33442 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
33457 * @class Roo.bootstrap.NumberField
33458 * @extends Roo.bootstrap.Input
33459 * Bootstrap NumberField class
33465 * Create a new NumberField
33466 * @param {Object} config The config object
33469 Roo.bootstrap.NumberField = function(config){
33470 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
33473 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
33476 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
33478 allowDecimals : true,
33480 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
33482 decimalSeparator : ".",
33484 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
33486 decimalPrecision : 2,
33488 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
33490 allowNegative : true,
33493 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
33497 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
33499 minValue : Number.NEGATIVE_INFINITY,
33501 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
33503 maxValue : Number.MAX_VALUE,
33505 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
33507 minText : "The minimum value for this field is {0}",
33509 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
33511 maxText : "The maximum value for this field is {0}",
33513 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
33514 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
33516 nanText : "{0} is not a valid number",
33518 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
33520 thousandsDelimiter : false,
33522 * @cfg {String} valueAlign alignment of value
33524 valueAlign : "left",
33526 getAutoCreate : function()
33528 var hiddenInput = {
33532 cls: 'hidden-number-input'
33536 hiddenInput.name = this.name;
33541 var cfg = Roo.bootstrap.NumberField.superclass.getAutoCreate.call(this);
33543 this.name = hiddenInput.name;
33545 if(cfg.cn.length > 0) {
33546 cfg.cn.push(hiddenInput);
33553 initEvents : function()
33555 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
33557 var allowed = "0123456789";
33559 if(this.allowDecimals){
33560 allowed += this.decimalSeparator;
33563 if(this.allowNegative){
33567 if(this.thousandsDelimiter) {
33571 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
33573 var keyPress = function(e){
33575 var k = e.getKey();
33577 var c = e.getCharCode();
33580 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
33581 allowed.indexOf(String.fromCharCode(c)) === -1
33587 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
33591 if(allowed.indexOf(String.fromCharCode(c)) === -1){
33596 this.el.on("keypress", keyPress, this);
33599 validateValue : function(value)
33602 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
33606 var num = this.parseValue(value);
33609 this.markInvalid(String.format(this.nanText, value));
33613 if(num < this.minValue){
33614 this.markInvalid(String.format(this.minText, this.minValue));
33618 if(num > this.maxValue){
33619 this.markInvalid(String.format(this.maxText, this.maxValue));
33626 getValue : function()
33628 var v = this.hiddenEl().getValue();
33630 return this.fixPrecision(this.parseValue(v));
33633 parseValue : function(value)
33635 if(this.thousandsDelimiter) {
33637 r = new RegExp(",", "g");
33638 value = value.replace(r, "");
33641 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
33642 return isNaN(value) ? '' : value;
33645 fixPrecision : function(value)
33647 if(this.thousandsDelimiter) {
33649 r = new RegExp(",", "g");
33650 value = value.replace(r, "");
33653 var nan = isNaN(value);
33655 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
33656 return nan ? '' : value;
33658 return parseFloat(value).toFixed(this.decimalPrecision);
33661 setValue : function(v)
33663 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
33669 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
33671 this.inputEl().dom.value = (v == '') ? '' :
33672 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
33674 if(!this.allowZero && v === '0') {
33675 this.hiddenEl().dom.value = '';
33676 this.inputEl().dom.value = '';
33683 decimalPrecisionFcn : function(v)
33685 return Math.floor(v);
33688 beforeBlur : function()
33690 var v = this.parseValue(this.getRawValue());
33692 if(v || v === 0 || v === ''){
33697 hiddenEl : function()
33699 return this.el.select('input.hidden-number-input',true).first();
33711 * @class Roo.bootstrap.DocumentSlider
33712 * @extends Roo.bootstrap.Component
33713 * Bootstrap DocumentSlider class
33716 * Create a new DocumentViewer
33717 * @param {Object} config The config object
33720 Roo.bootstrap.DocumentSlider = function(config){
33721 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
33728 * Fire after initEvent
33729 * @param {Roo.bootstrap.DocumentSlider} this
33734 * Fire after update
33735 * @param {Roo.bootstrap.DocumentSlider} this
33741 * @param {Roo.bootstrap.DocumentSlider} this
33747 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
33753 getAutoCreate : function()
33757 cls : 'roo-document-slider',
33761 cls : 'roo-document-slider-header',
33765 cls : 'roo-document-slider-header-title'
33771 cls : 'roo-document-slider-body',
33775 cls : 'roo-document-slider-prev',
33779 cls : 'fa fa-chevron-left'
33785 cls : 'roo-document-slider-thumb',
33789 cls : 'roo-document-slider-image'
33795 cls : 'roo-document-slider-next',
33799 cls : 'fa fa-chevron-right'
33811 initEvents : function()
33813 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
33814 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
33816 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
33817 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
33819 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
33820 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
33822 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
33823 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
33825 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
33826 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
33828 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
33829 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33831 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
33832 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33834 this.thumbEl.on('click', this.onClick, this);
33836 this.prevIndicator.on('click', this.prev, this);
33838 this.nextIndicator.on('click', this.next, this);
33842 initial : function()
33844 if(this.files.length){
33845 this.indicator = 1;
33849 this.fireEvent('initial', this);
33852 update : function()
33854 this.imageEl.attr('src', this.files[this.indicator - 1]);
33856 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
33858 this.prevIndicator.show();
33860 if(this.indicator == 1){
33861 this.prevIndicator.hide();
33864 this.nextIndicator.show();
33866 if(this.indicator == this.files.length){
33867 this.nextIndicator.hide();
33870 this.thumbEl.scrollTo('top');
33872 this.fireEvent('update', this);
33875 onClick : function(e)
33877 e.preventDefault();
33879 this.fireEvent('click', this);
33884 e.preventDefault();
33886 this.indicator = Math.max(1, this.indicator - 1);
33893 e.preventDefault();
33895 this.indicator = Math.min(this.files.length, this.indicator + 1);
33909 * @class Roo.bootstrap.RadioSet
33910 * @extends Roo.bootstrap.Input
33911 * Bootstrap RadioSet class
33912 * @cfg {String} indicatorpos (left|right) default left
33913 * @cfg {Boolean} inline (true|false) inline the element (default true)
33914 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
33916 * Create a new RadioSet
33917 * @param {Object} config The config object
33920 Roo.bootstrap.RadioSet = function(config){
33922 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
33926 Roo.bootstrap.RadioSet.register(this);
33931 * Fires when the element is checked or unchecked.
33932 * @param {Roo.bootstrap.RadioSet} this This radio
33933 * @param {Roo.bootstrap.Radio} item The checked item
33938 * Fires when the element is click.
33939 * @param {Roo.bootstrap.RadioSet} this This radio set
33940 * @param {Roo.bootstrap.Radio} item The checked item
33941 * @param {Roo.EventObject} e The event object
33948 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
33956 indicatorpos : 'left',
33958 getAutoCreate : function()
33962 cls : 'roo-radio-set-label',
33966 html : this.fieldLabel
33971 if(this.indicatorpos == 'left'){
33974 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
33975 tooltip : 'This field is required'
33980 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
33981 tooltip : 'This field is required'
33987 cls : 'roo-radio-set-items'
33990 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
33992 if (align === 'left' && this.fieldLabel.length) {
33995 cls : "roo-radio-set-right",
34001 if(this.labelWidth > 12){
34002 label.style = "width: " + this.labelWidth + 'px';
34005 if(this.labelWidth < 13 && this.labelmd == 0){
34006 this.labelmd = this.labelWidth;
34009 if(this.labellg > 0){
34010 label.cls += ' col-lg-' + this.labellg;
34011 items.cls += ' col-lg-' + (12 - this.labellg);
34014 if(this.labelmd > 0){
34015 label.cls += ' col-md-' + this.labelmd;
34016 items.cls += ' col-md-' + (12 - this.labelmd);
34019 if(this.labelsm > 0){
34020 label.cls += ' col-sm-' + this.labelsm;
34021 items.cls += ' col-sm-' + (12 - this.labelsm);
34024 if(this.labelxs > 0){
34025 label.cls += ' col-xs-' + this.labelxs;
34026 items.cls += ' col-xs-' + (12 - this.labelxs);
34032 cls : 'roo-radio-set',
34036 cls : 'roo-radio-set-input',
34039 value : this.value ? this.value : ''
34046 if(this.weight.length){
34047 cfg.cls += ' roo-radio-' + this.weight;
34051 cfg.cls += ' roo-radio-set-inline';
34055 ['xs','sm','md','lg'].map(function(size){
34056 if (settings[size]) {
34057 cfg.cls += ' col-' + size + '-' + settings[size];
34065 initEvents : function()
34067 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
34068 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
34070 if(!this.fieldLabel.length){
34071 this.labelEl.hide();
34074 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
34075 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
34077 this.indicator = this.indicatorEl();
34079 if(this.indicator){
34080 this.indicator.addClass('invisible');
34083 this.originalValue = this.getValue();
34087 inputEl: function ()
34089 return this.el.select('.roo-radio-set-input', true).first();
34092 getChildContainer : function()
34094 return this.itemsEl;
34097 register : function(item)
34099 this.radioes.push(item);
34103 validate : function()
34105 if(this.getVisibilityEl().hasClass('hidden')){
34111 Roo.each(this.radioes, function(i){
34120 if(this.allowBlank) {
34124 if(this.disabled || valid){
34129 this.markInvalid();
34134 markValid : function()
34136 if(this.labelEl.isVisible(true)){
34137 this.indicatorEl().removeClass('visible');
34138 this.indicatorEl().addClass('invisible');
34141 this.el.removeClass([this.invalidClass, this.validClass]);
34142 this.el.addClass(this.validClass);
34144 this.fireEvent('valid', this);
34147 markInvalid : function(msg)
34149 if(this.allowBlank || this.disabled){
34153 if(this.labelEl.isVisible(true)){
34154 this.indicatorEl().removeClass('invisible');
34155 this.indicatorEl().addClass('visible');
34158 this.el.removeClass([this.invalidClass, this.validClass]);
34159 this.el.addClass(this.invalidClass);
34161 this.fireEvent('invalid', this, msg);
34165 setValue : function(v, suppressEvent)
34167 if(this.value === v){
34174 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
34177 Roo.each(this.radioes, function(i){
34179 i.el.removeClass('checked');
34182 Roo.each(this.radioes, function(i){
34184 if(i.value === v || i.value.toString() === v.toString()){
34186 i.el.addClass('checked');
34188 if(suppressEvent !== true){
34189 this.fireEvent('check', this, i);
34200 clearInvalid : function(){
34202 if(!this.el || this.preventMark){
34206 this.el.removeClass([this.invalidClass]);
34208 this.fireEvent('valid', this);
34213 Roo.apply(Roo.bootstrap.RadioSet, {
34217 register : function(set)
34219 this.groups[set.name] = set;
34222 get: function(name)
34224 if (typeof(this.groups[name]) == 'undefined') {
34228 return this.groups[name] ;
34234 * Ext JS Library 1.1.1
34235 * Copyright(c) 2006-2007, Ext JS, LLC.
34237 * Originally Released Under LGPL - original licence link has changed is not relivant.
34240 * <script type="text/javascript">
34245 * @class Roo.bootstrap.SplitBar
34246 * @extends Roo.util.Observable
34247 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
34251 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
34252 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
34253 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
34254 split.minSize = 100;
34255 split.maxSize = 600;
34256 split.animate = true;
34257 split.on('moved', splitterMoved);
34260 * Create a new SplitBar
34261 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
34262 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
34263 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34264 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
34265 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
34266 position of the SplitBar).
34268 Roo.bootstrap.SplitBar = function(cfg){
34273 // dragElement : elm
34274 // resizingElement: el,
34276 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
34277 // placement : Roo.bootstrap.SplitBar.LEFT ,
34278 // existingProxy ???
34281 this.el = Roo.get(cfg.dragElement, true);
34282 this.el.dom.unselectable = "on";
34284 this.resizingEl = Roo.get(cfg.resizingElement, true);
34288 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34289 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
34292 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
34295 * The minimum size of the resizing element. (Defaults to 0)
34301 * The maximum size of the resizing element. (Defaults to 2000)
34304 this.maxSize = 2000;
34307 * Whether to animate the transition to the new size
34310 this.animate = false;
34313 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
34316 this.useShim = false;
34321 if(!cfg.existingProxy){
34323 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
34325 this.proxy = Roo.get(cfg.existingProxy).dom;
34328 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
34331 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
34334 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
34337 this.dragSpecs = {};
34340 * @private The adapter to use to positon and resize elements
34342 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34343 this.adapter.init(this);
34345 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34347 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
34348 this.el.addClass("roo-splitbar-h");
34351 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
34352 this.el.addClass("roo-splitbar-v");
34358 * Fires when the splitter is moved (alias for {@link #event-moved})
34359 * @param {Roo.bootstrap.SplitBar} this
34360 * @param {Number} newSize the new width or height
34365 * Fires when the splitter is moved
34366 * @param {Roo.bootstrap.SplitBar} this
34367 * @param {Number} newSize the new width or height
34371 * @event beforeresize
34372 * Fires before the splitter is dragged
34373 * @param {Roo.bootstrap.SplitBar} this
34375 "beforeresize" : true,
34377 "beforeapply" : true
34380 Roo.util.Observable.call(this);
34383 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
34384 onStartProxyDrag : function(x, y){
34385 this.fireEvent("beforeresize", this);
34387 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
34389 o.enableDisplayMode("block");
34390 // all splitbars share the same overlay
34391 Roo.bootstrap.SplitBar.prototype.overlay = o;
34393 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
34394 this.overlay.show();
34395 Roo.get(this.proxy).setDisplayed("block");
34396 var size = this.adapter.getElementSize(this);
34397 this.activeMinSize = this.getMinimumSize();;
34398 this.activeMaxSize = this.getMaximumSize();;
34399 var c1 = size - this.activeMinSize;
34400 var c2 = Math.max(this.activeMaxSize - size, 0);
34401 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34402 this.dd.resetConstraints();
34403 this.dd.setXConstraint(
34404 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
34405 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
34407 this.dd.setYConstraint(0, 0);
34409 this.dd.resetConstraints();
34410 this.dd.setXConstraint(0, 0);
34411 this.dd.setYConstraint(
34412 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
34413 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
34416 this.dragSpecs.startSize = size;
34417 this.dragSpecs.startPoint = [x, y];
34418 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
34422 * @private Called after the drag operation by the DDProxy
34424 onEndProxyDrag : function(e){
34425 Roo.get(this.proxy).setDisplayed(false);
34426 var endPoint = Roo.lib.Event.getXY(e);
34428 this.overlay.hide();
34431 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34432 newSize = this.dragSpecs.startSize +
34433 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
34434 endPoint[0] - this.dragSpecs.startPoint[0] :
34435 this.dragSpecs.startPoint[0] - endPoint[0]
34438 newSize = this.dragSpecs.startSize +
34439 (this.placement == Roo.bootstrap.SplitBar.TOP ?
34440 endPoint[1] - this.dragSpecs.startPoint[1] :
34441 this.dragSpecs.startPoint[1] - endPoint[1]
34444 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
34445 if(newSize != this.dragSpecs.startSize){
34446 if(this.fireEvent('beforeapply', this, newSize) !== false){
34447 this.adapter.setElementSize(this, newSize);
34448 this.fireEvent("moved", this, newSize);
34449 this.fireEvent("resize", this, newSize);
34455 * Get the adapter this SplitBar uses
34456 * @return The adapter object
34458 getAdapter : function(){
34459 return this.adapter;
34463 * Set the adapter this SplitBar uses
34464 * @param {Object} adapter A SplitBar adapter object
34466 setAdapter : function(adapter){
34467 this.adapter = adapter;
34468 this.adapter.init(this);
34472 * Gets the minimum size for the resizing element
34473 * @return {Number} The minimum size
34475 getMinimumSize : function(){
34476 return this.minSize;
34480 * Sets the minimum size for the resizing element
34481 * @param {Number} minSize The minimum size
34483 setMinimumSize : function(minSize){
34484 this.minSize = minSize;
34488 * Gets the maximum size for the resizing element
34489 * @return {Number} The maximum size
34491 getMaximumSize : function(){
34492 return this.maxSize;
34496 * Sets the maximum size for the resizing element
34497 * @param {Number} maxSize The maximum size
34499 setMaximumSize : function(maxSize){
34500 this.maxSize = maxSize;
34504 * Sets the initialize size for the resizing element
34505 * @param {Number} size The initial size
34507 setCurrentSize : function(size){
34508 var oldAnimate = this.animate;
34509 this.animate = false;
34510 this.adapter.setElementSize(this, size);
34511 this.animate = oldAnimate;
34515 * Destroy this splitbar.
34516 * @param {Boolean} removeEl True to remove the element
34518 destroy : function(removeEl){
34520 this.shim.remove();
34523 this.proxy.parentNode.removeChild(this.proxy);
34531 * @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.
34533 Roo.bootstrap.SplitBar.createProxy = function(dir){
34534 var proxy = new Roo.Element(document.createElement("div"));
34535 proxy.unselectable();
34536 var cls = 'roo-splitbar-proxy';
34537 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
34538 document.body.appendChild(proxy.dom);
34543 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
34544 * Default Adapter. It assumes the splitter and resizing element are not positioned
34545 * elements and only gets/sets the width of the element. Generally used for table based layouts.
34547 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
34550 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
34551 // do nothing for now
34552 init : function(s){
34556 * Called before drag operations to get the current size of the resizing element.
34557 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34559 getElementSize : function(s){
34560 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34561 return s.resizingEl.getWidth();
34563 return s.resizingEl.getHeight();
34568 * Called after drag operations to set the size of the resizing element.
34569 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34570 * @param {Number} newSize The new size to set
34571 * @param {Function} onComplete A function to be invoked when resizing is complete
34573 setElementSize : function(s, newSize, onComplete){
34574 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34576 s.resizingEl.setWidth(newSize);
34578 onComplete(s, newSize);
34581 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
34586 s.resizingEl.setHeight(newSize);
34588 onComplete(s, newSize);
34591 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
34598 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
34599 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
34600 * Adapter that moves the splitter element to align with the resized sizing element.
34601 * Used with an absolute positioned SplitBar.
34602 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
34603 * document.body, make sure you assign an id to the body element.
34605 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
34606 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34607 this.container = Roo.get(container);
34610 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
34611 init : function(s){
34612 this.basic.init(s);
34615 getElementSize : function(s){
34616 return this.basic.getElementSize(s);
34619 setElementSize : function(s, newSize, onComplete){
34620 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
34623 moveSplitter : function(s){
34624 var yes = Roo.bootstrap.SplitBar;
34625 switch(s.placement){
34627 s.el.setX(s.resizingEl.getRight());
34630 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
34633 s.el.setY(s.resizingEl.getBottom());
34636 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
34643 * Orientation constant - Create a vertical SplitBar
34647 Roo.bootstrap.SplitBar.VERTICAL = 1;
34650 * Orientation constant - Create a horizontal SplitBar
34654 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
34657 * Placement constant - The resizing element is to the left of the splitter element
34661 Roo.bootstrap.SplitBar.LEFT = 1;
34664 * Placement constant - The resizing element is to the right of the splitter element
34668 Roo.bootstrap.SplitBar.RIGHT = 2;
34671 * Placement constant - The resizing element is positioned above the splitter element
34675 Roo.bootstrap.SplitBar.TOP = 3;
34678 * Placement constant - The resizing element is positioned under splitter element
34682 Roo.bootstrap.SplitBar.BOTTOM = 4;
34683 Roo.namespace("Roo.bootstrap.layout");/*
34685 * Ext JS Library 1.1.1
34686 * Copyright(c) 2006-2007, Ext JS, LLC.
34688 * Originally Released Under LGPL - original licence link has changed is not relivant.
34691 * <script type="text/javascript">
34695 * @class Roo.bootstrap.layout.Manager
34696 * @extends Roo.bootstrap.Component
34697 * Base class for layout managers.
34699 Roo.bootstrap.layout.Manager = function(config)
34701 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
34707 /** false to disable window resize monitoring @type Boolean */
34708 this.monitorWindowResize = true;
34713 * Fires when a layout is performed.
34714 * @param {Roo.LayoutManager} this
34718 * @event regionresized
34719 * Fires when the user resizes a region.
34720 * @param {Roo.LayoutRegion} region The resized region
34721 * @param {Number} newSize The new size (width for east/west, height for north/south)
34723 "regionresized" : true,
34725 * @event regioncollapsed
34726 * Fires when a region is collapsed.
34727 * @param {Roo.LayoutRegion} region The collapsed region
34729 "regioncollapsed" : true,
34731 * @event regionexpanded
34732 * Fires when a region is expanded.
34733 * @param {Roo.LayoutRegion} region The expanded region
34735 "regionexpanded" : true
34737 this.updating = false;
34740 this.el = Roo.get(config.el);
34746 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
34751 monitorWindowResize : true,
34757 onRender : function(ct, position)
34760 this.el = Roo.get(ct);
34763 //this.fireEvent('render',this);
34767 initEvents: function()
34771 // ie scrollbar fix
34772 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
34773 document.body.scroll = "no";
34774 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
34775 this.el.position('relative');
34777 this.id = this.el.id;
34778 this.el.addClass("roo-layout-container");
34779 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
34780 if(this.el.dom != document.body ) {
34781 this.el.on('resize', this.layout,this);
34782 this.el.on('show', this.layout,this);
34788 * Returns true if this layout is currently being updated
34789 * @return {Boolean}
34791 isUpdating : function(){
34792 return this.updating;
34796 * Suspend the LayoutManager from doing auto-layouts while
34797 * making multiple add or remove calls
34799 beginUpdate : function(){
34800 this.updating = true;
34804 * Restore auto-layouts and optionally disable the manager from performing a layout
34805 * @param {Boolean} noLayout true to disable a layout update
34807 endUpdate : function(noLayout){
34808 this.updating = false;
34814 layout: function(){
34818 onRegionResized : function(region, newSize){
34819 this.fireEvent("regionresized", region, newSize);
34823 onRegionCollapsed : function(region){
34824 this.fireEvent("regioncollapsed", region);
34827 onRegionExpanded : function(region){
34828 this.fireEvent("regionexpanded", region);
34832 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
34833 * performs box-model adjustments.
34834 * @return {Object} The size as an object {width: (the width), height: (the height)}
34836 getViewSize : function()
34839 if(this.el.dom != document.body){
34840 size = this.el.getSize();
34842 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
34844 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
34845 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
34850 * Returns the Element this layout is bound to.
34851 * @return {Roo.Element}
34853 getEl : function(){
34858 * Returns the specified region.
34859 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
34860 * @return {Roo.LayoutRegion}
34862 getRegion : function(target){
34863 return this.regions[target.toLowerCase()];
34866 onWindowResize : function(){
34867 if(this.monitorWindowResize){
34874 * Ext JS Library 1.1.1
34875 * Copyright(c) 2006-2007, Ext JS, LLC.
34877 * Originally Released Under LGPL - original licence link has changed is not relivant.
34880 * <script type="text/javascript">
34883 * @class Roo.bootstrap.layout.Border
34884 * @extends Roo.bootstrap.layout.Manager
34885 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
34886 * please see: examples/bootstrap/nested.html<br><br>
34888 <b>The container the layout is rendered into can be either the body element or any other element.
34889 If it is not the body element, the container needs to either be an absolute positioned element,
34890 or you will need to add "position:relative" to the css of the container. You will also need to specify
34891 the container size if it is not the body element.</b>
34894 * Create a new Border
34895 * @param {Object} config Configuration options
34897 Roo.bootstrap.layout.Border = function(config){
34898 config = config || {};
34899 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
34903 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34904 if(config[region]){
34905 config[region].region = region;
34906 this.addRegion(config[region]);
34912 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
34914 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
34916 * Creates and adds a new region if it doesn't already exist.
34917 * @param {String} target The target region key (north, south, east, west or center).
34918 * @param {Object} config The regions config object
34919 * @return {BorderLayoutRegion} The new region
34921 addRegion : function(config)
34923 if(!this.regions[config.region]){
34924 var r = this.factory(config);
34925 this.bindRegion(r);
34927 return this.regions[config.region];
34931 bindRegion : function(r){
34932 this.regions[r.config.region] = r;
34934 r.on("visibilitychange", this.layout, this);
34935 r.on("paneladded", this.layout, this);
34936 r.on("panelremoved", this.layout, this);
34937 r.on("invalidated", this.layout, this);
34938 r.on("resized", this.onRegionResized, this);
34939 r.on("collapsed", this.onRegionCollapsed, this);
34940 r.on("expanded", this.onRegionExpanded, this);
34944 * Performs a layout update.
34946 layout : function()
34948 if(this.updating) {
34952 // render all the rebions if they have not been done alreayd?
34953 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34954 if(this.regions[region] && !this.regions[region].bodyEl){
34955 this.regions[region].onRender(this.el)
34959 var size = this.getViewSize();
34960 var w = size.width;
34961 var h = size.height;
34966 //var x = 0, y = 0;
34968 var rs = this.regions;
34969 var north = rs["north"];
34970 var south = rs["south"];
34971 var west = rs["west"];
34972 var east = rs["east"];
34973 var center = rs["center"];
34974 //if(this.hideOnLayout){ // not supported anymore
34975 //c.el.setStyle("display", "none");
34977 if(north && north.isVisible()){
34978 var b = north.getBox();
34979 var m = north.getMargins();
34980 b.width = w - (m.left+m.right);
34983 centerY = b.height + b.y + m.bottom;
34984 centerH -= centerY;
34985 north.updateBox(this.safeBox(b));
34987 if(south && south.isVisible()){
34988 var b = south.getBox();
34989 var m = south.getMargins();
34990 b.width = w - (m.left+m.right);
34992 var totalHeight = (b.height + m.top + m.bottom);
34993 b.y = h - totalHeight + m.top;
34994 centerH -= totalHeight;
34995 south.updateBox(this.safeBox(b));
34997 if(west && west.isVisible()){
34998 var b = west.getBox();
34999 var m = west.getMargins();
35000 b.height = centerH - (m.top+m.bottom);
35002 b.y = centerY + m.top;
35003 var totalWidth = (b.width + m.left + m.right);
35004 centerX += totalWidth;
35005 centerW -= totalWidth;
35006 west.updateBox(this.safeBox(b));
35008 if(east && east.isVisible()){
35009 var b = east.getBox();
35010 var m = east.getMargins();
35011 b.height = centerH - (m.top+m.bottom);
35012 var totalWidth = (b.width + m.left + m.right);
35013 b.x = w - totalWidth + m.left;
35014 b.y = centerY + m.top;
35015 centerW -= totalWidth;
35016 east.updateBox(this.safeBox(b));
35019 var m = center.getMargins();
35021 x: centerX + m.left,
35022 y: centerY + m.top,
35023 width: centerW - (m.left+m.right),
35024 height: centerH - (m.top+m.bottom)
35026 //if(this.hideOnLayout){
35027 //center.el.setStyle("display", "block");
35029 center.updateBox(this.safeBox(centerBox));
35032 this.fireEvent("layout", this);
35036 safeBox : function(box){
35037 box.width = Math.max(0, box.width);
35038 box.height = Math.max(0, box.height);
35043 * Adds a ContentPanel (or subclass) to this layout.
35044 * @param {String} target The target region key (north, south, east, west or center).
35045 * @param {Roo.ContentPanel} panel The panel to add
35046 * @return {Roo.ContentPanel} The added panel
35048 add : function(target, panel){
35050 target = target.toLowerCase();
35051 return this.regions[target].add(panel);
35055 * Remove a ContentPanel (or subclass) to this layout.
35056 * @param {String} target The target region key (north, south, east, west or center).
35057 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
35058 * @return {Roo.ContentPanel} The removed panel
35060 remove : function(target, panel){
35061 target = target.toLowerCase();
35062 return this.regions[target].remove(panel);
35066 * Searches all regions for a panel with the specified id
35067 * @param {String} panelId
35068 * @return {Roo.ContentPanel} The panel or null if it wasn't found
35070 findPanel : function(panelId){
35071 var rs = this.regions;
35072 for(var target in rs){
35073 if(typeof rs[target] != "function"){
35074 var p = rs[target].getPanel(panelId);
35084 * Searches all regions for a panel with the specified id and activates (shows) it.
35085 * @param {String/ContentPanel} panelId The panels id or the panel itself
35086 * @return {Roo.ContentPanel} The shown panel or null
35088 showPanel : function(panelId) {
35089 var rs = this.regions;
35090 for(var target in rs){
35091 var r = rs[target];
35092 if(typeof r != "function"){
35093 if(r.hasPanel(panelId)){
35094 return r.showPanel(panelId);
35102 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
35103 * @param {Roo.state.Provider} provider (optional) An alternate state provider
35106 restoreState : function(provider){
35108 provider = Roo.state.Manager;
35110 var sm = new Roo.LayoutStateManager();
35111 sm.init(this, provider);
35117 * Adds a xtype elements to the layout.
35121 xtype : 'ContentPanel',
35128 xtype : 'NestedLayoutPanel',
35134 items : [ ... list of content panels or nested layout panels.. ]
35138 * @param {Object} cfg Xtype definition of item to add.
35140 addxtype : function(cfg)
35142 // basically accepts a pannel...
35143 // can accept a layout region..!?!?
35144 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
35147 // theory? children can only be panels??
35149 //if (!cfg.xtype.match(/Panel$/)) {
35154 if (typeof(cfg.region) == 'undefined') {
35155 Roo.log("Failed to add Panel, region was not set");
35159 var region = cfg.region;
35165 xitems = cfg.items;
35172 case 'Content': // ContentPanel (el, cfg)
35173 case 'Scroll': // ContentPanel (el, cfg)
35175 cfg.autoCreate = true;
35176 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35178 // var el = this.el.createChild();
35179 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
35182 this.add(region, ret);
35186 case 'TreePanel': // our new panel!
35187 cfg.el = this.el.createChild();
35188 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
35189 this.add(region, ret);
35194 // create a new Layout (which is a Border Layout...
35196 var clayout = cfg.layout;
35197 clayout.el = this.el.createChild();
35198 clayout.items = clayout.items || [];
35202 // replace this exitems with the clayout ones..
35203 xitems = clayout.items;
35205 // force background off if it's in center...
35206 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
35207 cfg.background = false;
35209 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
35212 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35213 //console.log('adding nested layout panel ' + cfg.toSource());
35214 this.add(region, ret);
35215 nb = {}; /// find first...
35220 // needs grid and region
35222 //var el = this.getRegion(region).el.createChild();
35224 *var el = this.el.createChild();
35225 // create the grid first...
35226 cfg.grid.container = el;
35227 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
35230 if (region == 'center' && this.active ) {
35231 cfg.background = false;
35234 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35236 this.add(region, ret);
35238 if (cfg.background) {
35239 // render grid on panel activation (if panel background)
35240 ret.on('activate', function(gp) {
35241 if (!gp.grid.rendered) {
35242 // gp.grid.render(el);
35246 // cfg.grid.render(el);
35252 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
35253 // it was the old xcomponent building that caused this before.
35254 // espeically if border is the top element in the tree.
35264 if (typeof(Roo[cfg.xtype]) != 'undefined') {
35266 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
35267 this.add(region, ret);
35271 throw "Can not add '" + cfg.xtype + "' to Border";
35277 this.beginUpdate();
35281 Roo.each(xitems, function(i) {
35282 region = nb && i.region ? i.region : false;
35284 var add = ret.addxtype(i);
35287 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
35288 if (!i.background) {
35289 abn[region] = nb[region] ;
35296 // make the last non-background panel active..
35297 //if (nb) { Roo.log(abn); }
35300 for(var r in abn) {
35301 region = this.getRegion(r);
35303 // tried using nb[r], but it does not work..
35305 region.showPanel(abn[r]);
35316 factory : function(cfg)
35319 var validRegions = Roo.bootstrap.layout.Border.regions;
35321 var target = cfg.region;
35324 var r = Roo.bootstrap.layout;
35328 return new r.North(cfg);
35330 return new r.South(cfg);
35332 return new r.East(cfg);
35334 return new r.West(cfg);
35336 return new r.Center(cfg);
35338 throw 'Layout region "'+target+'" not supported.';
35345 * Ext JS Library 1.1.1
35346 * Copyright(c) 2006-2007, Ext JS, LLC.
35348 * Originally Released Under LGPL - original licence link has changed is not relivant.
35351 * <script type="text/javascript">
35355 * @class Roo.bootstrap.layout.Basic
35356 * @extends Roo.util.Observable
35357 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
35358 * and does not have a titlebar, tabs or any other features. All it does is size and position
35359 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
35360 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35361 * @cfg {string} region the region that it inhabits..
35362 * @cfg {bool} skipConfig skip config?
35366 Roo.bootstrap.layout.Basic = function(config){
35368 this.mgr = config.mgr;
35370 this.position = config.region;
35372 var skipConfig = config.skipConfig;
35376 * @scope Roo.BasicLayoutRegion
35380 * @event beforeremove
35381 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
35382 * @param {Roo.LayoutRegion} this
35383 * @param {Roo.ContentPanel} panel The panel
35384 * @param {Object} e The cancel event object
35386 "beforeremove" : true,
35388 * @event invalidated
35389 * Fires when the layout for this region is changed.
35390 * @param {Roo.LayoutRegion} this
35392 "invalidated" : true,
35394 * @event visibilitychange
35395 * Fires when this region is shown or hidden
35396 * @param {Roo.LayoutRegion} this
35397 * @param {Boolean} visibility true or false
35399 "visibilitychange" : true,
35401 * @event paneladded
35402 * Fires when a panel is added.
35403 * @param {Roo.LayoutRegion} this
35404 * @param {Roo.ContentPanel} panel The panel
35406 "paneladded" : true,
35408 * @event panelremoved
35409 * Fires when a panel is removed.
35410 * @param {Roo.LayoutRegion} this
35411 * @param {Roo.ContentPanel} panel The panel
35413 "panelremoved" : true,
35415 * @event beforecollapse
35416 * Fires when this region before collapse.
35417 * @param {Roo.LayoutRegion} this
35419 "beforecollapse" : true,
35422 * Fires when this region is collapsed.
35423 * @param {Roo.LayoutRegion} this
35425 "collapsed" : true,
35428 * Fires when this region is expanded.
35429 * @param {Roo.LayoutRegion} this
35434 * Fires when this region is slid into view.
35435 * @param {Roo.LayoutRegion} this
35437 "slideshow" : true,
35440 * Fires when this region slides out of view.
35441 * @param {Roo.LayoutRegion} this
35443 "slidehide" : true,
35445 * @event panelactivated
35446 * Fires when a panel is activated.
35447 * @param {Roo.LayoutRegion} this
35448 * @param {Roo.ContentPanel} panel The activated panel
35450 "panelactivated" : true,
35453 * Fires when the user resizes this region.
35454 * @param {Roo.LayoutRegion} this
35455 * @param {Number} newSize The new size (width for east/west, height for north/south)
35459 /** A collection of panels in this region. @type Roo.util.MixedCollection */
35460 this.panels = new Roo.util.MixedCollection();
35461 this.panels.getKey = this.getPanelId.createDelegate(this);
35463 this.activePanel = null;
35464 // ensure listeners are added...
35466 if (config.listeners || config.events) {
35467 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
35468 listeners : config.listeners || {},
35469 events : config.events || {}
35473 if(skipConfig !== true){
35474 this.applyConfig(config);
35478 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
35480 getPanelId : function(p){
35484 applyConfig : function(config){
35485 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35486 this.config = config;
35491 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
35492 * the width, for horizontal (north, south) the height.
35493 * @param {Number} newSize The new width or height
35495 resizeTo : function(newSize){
35496 var el = this.el ? this.el :
35497 (this.activePanel ? this.activePanel.getEl() : null);
35499 switch(this.position){
35502 el.setWidth(newSize);
35503 this.fireEvent("resized", this, newSize);
35507 el.setHeight(newSize);
35508 this.fireEvent("resized", this, newSize);
35514 getBox : function(){
35515 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
35518 getMargins : function(){
35519 return this.margins;
35522 updateBox : function(box){
35524 var el = this.activePanel.getEl();
35525 el.dom.style.left = box.x + "px";
35526 el.dom.style.top = box.y + "px";
35527 this.activePanel.setSize(box.width, box.height);
35531 * Returns the container element for this region.
35532 * @return {Roo.Element}
35534 getEl : function(){
35535 return this.activePanel;
35539 * Returns true if this region is currently visible.
35540 * @return {Boolean}
35542 isVisible : function(){
35543 return this.activePanel ? true : false;
35546 setActivePanel : function(panel){
35547 panel = this.getPanel(panel);
35548 if(this.activePanel && this.activePanel != panel){
35549 this.activePanel.setActiveState(false);
35550 this.activePanel.getEl().setLeftTop(-10000,-10000);
35552 this.activePanel = panel;
35553 panel.setActiveState(true);
35555 panel.setSize(this.box.width, this.box.height);
35557 this.fireEvent("panelactivated", this, panel);
35558 this.fireEvent("invalidated");
35562 * Show the specified panel.
35563 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
35564 * @return {Roo.ContentPanel} The shown panel or null
35566 showPanel : function(panel){
35567 panel = this.getPanel(panel);
35569 this.setActivePanel(panel);
35575 * Get the active panel for this region.
35576 * @return {Roo.ContentPanel} The active panel or null
35578 getActivePanel : function(){
35579 return this.activePanel;
35583 * Add the passed ContentPanel(s)
35584 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35585 * @return {Roo.ContentPanel} The panel added (if only one was added)
35587 add : function(panel){
35588 if(arguments.length > 1){
35589 for(var i = 0, len = arguments.length; i < len; i++) {
35590 this.add(arguments[i]);
35594 if(this.hasPanel(panel)){
35595 this.showPanel(panel);
35598 var el = panel.getEl();
35599 if(el.dom.parentNode != this.mgr.el.dom){
35600 this.mgr.el.dom.appendChild(el.dom);
35602 if(panel.setRegion){
35603 panel.setRegion(this);
35605 this.panels.add(panel);
35606 el.setStyle("position", "absolute");
35607 if(!panel.background){
35608 this.setActivePanel(panel);
35609 if(this.config.initialSize && this.panels.getCount()==1){
35610 this.resizeTo(this.config.initialSize);
35613 this.fireEvent("paneladded", this, panel);
35618 * Returns true if the panel is in this region.
35619 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35620 * @return {Boolean}
35622 hasPanel : function(panel){
35623 if(typeof panel == "object"){ // must be panel obj
35624 panel = panel.getId();
35626 return this.getPanel(panel) ? true : false;
35630 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35631 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35632 * @param {Boolean} preservePanel Overrides the config preservePanel option
35633 * @return {Roo.ContentPanel} The panel that was removed
35635 remove : function(panel, preservePanel){
35636 panel = this.getPanel(panel);
35641 this.fireEvent("beforeremove", this, panel, e);
35642 if(e.cancel === true){
35645 var panelId = panel.getId();
35646 this.panels.removeKey(panelId);
35651 * Returns the panel specified or null if it's not in this region.
35652 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35653 * @return {Roo.ContentPanel}
35655 getPanel : function(id){
35656 if(typeof id == "object"){ // must be panel obj
35659 return this.panels.get(id);
35663 * Returns this regions position (north/south/east/west/center).
35666 getPosition: function(){
35667 return this.position;
35671 * Ext JS Library 1.1.1
35672 * Copyright(c) 2006-2007, Ext JS, LLC.
35674 * Originally Released Under LGPL - original licence link has changed is not relivant.
35677 * <script type="text/javascript">
35681 * @class Roo.bootstrap.layout.Region
35682 * @extends Roo.bootstrap.layout.Basic
35683 * This class represents a region in a layout manager.
35685 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
35686 * @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})
35687 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
35688 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
35689 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
35690 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
35691 * @cfg {String} title The title for the region (overrides panel titles)
35692 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
35693 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
35694 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
35695 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
35696 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
35697 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
35698 * the space available, similar to FireFox 1.5 tabs (defaults to false)
35699 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
35700 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
35701 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
35703 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
35704 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
35705 * @cfg {Boolean} disableTabTips True to disable tab tooltips
35706 * @cfg {Number} width For East/West panels
35707 * @cfg {Number} height For North/South panels
35708 * @cfg {Boolean} split To show the splitter
35709 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
35711 * @cfg {string} cls Extra CSS classes to add to region
35713 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35714 * @cfg {string} region the region that it inhabits..
35717 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
35718 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
35720 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
35721 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
35722 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
35724 Roo.bootstrap.layout.Region = function(config)
35726 this.applyConfig(config);
35728 var mgr = config.mgr;
35729 var pos = config.region;
35730 config.skipConfig = true;
35731 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
35734 this.onRender(mgr.el);
35737 this.visible = true;
35738 this.collapsed = false;
35739 this.unrendered_panels = [];
35742 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
35744 position: '', // set by wrapper (eg. north/south etc..)
35745 unrendered_panels : null, // unrendered panels.
35746 createBody : function(){
35747 /** This region's body element
35748 * @type Roo.Element */
35749 this.bodyEl = this.el.createChild({
35751 cls: "roo-layout-panel-body tab-content" // bootstrap added...
35755 onRender: function(ctr, pos)
35757 var dh = Roo.DomHelper;
35758 /** This region's container element
35759 * @type Roo.Element */
35760 this.el = dh.append(ctr.dom, {
35762 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
35764 /** This region's title element
35765 * @type Roo.Element */
35767 this.titleEl = dh.append(this.el.dom,
35770 unselectable: "on",
35771 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
35773 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
35774 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
35777 this.titleEl.enableDisplayMode();
35778 /** This region's title text element
35779 * @type HTMLElement */
35780 this.titleTextEl = this.titleEl.dom.firstChild;
35781 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
35783 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
35784 this.closeBtn.enableDisplayMode();
35785 this.closeBtn.on("click", this.closeClicked, this);
35786 this.closeBtn.hide();
35788 this.createBody(this.config);
35789 if(this.config.hideWhenEmpty){
35791 this.on("paneladded", this.validateVisibility, this);
35792 this.on("panelremoved", this.validateVisibility, this);
35794 if(this.autoScroll){
35795 this.bodyEl.setStyle("overflow", "auto");
35797 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
35799 //if(c.titlebar !== false){
35800 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
35801 this.titleEl.hide();
35803 this.titleEl.show();
35804 if(this.config.title){
35805 this.titleTextEl.innerHTML = this.config.title;
35809 if(this.config.collapsed){
35810 this.collapse(true);
35812 if(this.config.hidden){
35816 if (this.unrendered_panels && this.unrendered_panels.length) {
35817 for (var i =0;i< this.unrendered_panels.length; i++) {
35818 this.add(this.unrendered_panels[i]);
35820 this.unrendered_panels = null;
35826 applyConfig : function(c)
35829 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
35830 var dh = Roo.DomHelper;
35831 if(c.titlebar !== false){
35832 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
35833 this.collapseBtn.on("click", this.collapse, this);
35834 this.collapseBtn.enableDisplayMode();
35836 if(c.showPin === true || this.showPin){
35837 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
35838 this.stickBtn.enableDisplayMode();
35839 this.stickBtn.on("click", this.expand, this);
35840 this.stickBtn.hide();
35845 /** This region's collapsed element
35846 * @type Roo.Element */
35849 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
35850 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
35853 if(c.floatable !== false){
35854 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
35855 this.collapsedEl.on("click", this.collapseClick, this);
35858 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
35859 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
35860 id: "message", unselectable: "on", style:{"float":"left"}});
35861 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
35863 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
35864 this.expandBtn.on("click", this.expand, this);
35868 if(this.collapseBtn){
35869 this.collapseBtn.setVisible(c.collapsible == true);
35872 this.cmargins = c.cmargins || this.cmargins ||
35873 (this.position == "west" || this.position == "east" ?
35874 {top: 0, left: 2, right:2, bottom: 0} :
35875 {top: 2, left: 0, right:0, bottom: 2});
35877 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35880 this.bottomTabs = c.tabPosition != "top";
35882 this.autoScroll = c.autoScroll || false;
35887 this.duration = c.duration || .30;
35888 this.slideDuration = c.slideDuration || .45;
35893 * Returns true if this region is currently visible.
35894 * @return {Boolean}
35896 isVisible : function(){
35897 return this.visible;
35901 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
35902 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
35904 //setCollapsedTitle : function(title){
35905 // title = title || " ";
35906 // if(this.collapsedTitleTextEl){
35907 // this.collapsedTitleTextEl.innerHTML = title;
35911 getBox : function(){
35913 // if(!this.collapsed){
35914 b = this.el.getBox(false, true);
35916 // b = this.collapsedEl.getBox(false, true);
35921 getMargins : function(){
35922 return this.margins;
35923 //return this.collapsed ? this.cmargins : this.margins;
35926 highlight : function(){
35927 this.el.addClass("x-layout-panel-dragover");
35930 unhighlight : function(){
35931 this.el.removeClass("x-layout-panel-dragover");
35934 updateBox : function(box)
35936 if (!this.bodyEl) {
35937 return; // not rendered yet..
35941 if(!this.collapsed){
35942 this.el.dom.style.left = box.x + "px";
35943 this.el.dom.style.top = box.y + "px";
35944 this.updateBody(box.width, box.height);
35946 this.collapsedEl.dom.style.left = box.x + "px";
35947 this.collapsedEl.dom.style.top = box.y + "px";
35948 this.collapsedEl.setSize(box.width, box.height);
35951 this.tabs.autoSizeTabs();
35955 updateBody : function(w, h)
35958 this.el.setWidth(w);
35959 w -= this.el.getBorderWidth("rl");
35960 if(this.config.adjustments){
35961 w += this.config.adjustments[0];
35964 if(h !== null && h > 0){
35965 this.el.setHeight(h);
35966 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
35967 h -= this.el.getBorderWidth("tb");
35968 if(this.config.adjustments){
35969 h += this.config.adjustments[1];
35971 this.bodyEl.setHeight(h);
35973 h = this.tabs.syncHeight(h);
35976 if(this.panelSize){
35977 w = w !== null ? w : this.panelSize.width;
35978 h = h !== null ? h : this.panelSize.height;
35980 if(this.activePanel){
35981 var el = this.activePanel.getEl();
35982 w = w !== null ? w : el.getWidth();
35983 h = h !== null ? h : el.getHeight();
35984 this.panelSize = {width: w, height: h};
35985 this.activePanel.setSize(w, h);
35987 if(Roo.isIE && this.tabs){
35988 this.tabs.el.repaint();
35993 * Returns the container element for this region.
35994 * @return {Roo.Element}
35996 getEl : function(){
36001 * Hides this region.
36004 //if(!this.collapsed){
36005 this.el.dom.style.left = "-2000px";
36008 // this.collapsedEl.dom.style.left = "-2000px";
36009 // this.collapsedEl.hide();
36011 this.visible = false;
36012 this.fireEvent("visibilitychange", this, false);
36016 * Shows this region if it was previously hidden.
36019 //if(!this.collapsed){
36022 // this.collapsedEl.show();
36024 this.visible = true;
36025 this.fireEvent("visibilitychange", this, true);
36028 closeClicked : function(){
36029 if(this.activePanel){
36030 this.remove(this.activePanel);
36034 collapseClick : function(e){
36036 e.stopPropagation();
36039 e.stopPropagation();
36045 * Collapses this region.
36046 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
36049 collapse : function(skipAnim, skipCheck = false){
36050 if(this.collapsed) {
36054 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
36056 this.collapsed = true;
36058 this.split.el.hide();
36060 if(this.config.animate && skipAnim !== true){
36061 this.fireEvent("invalidated", this);
36062 this.animateCollapse();
36064 this.el.setLocation(-20000,-20000);
36066 this.collapsedEl.show();
36067 this.fireEvent("collapsed", this);
36068 this.fireEvent("invalidated", this);
36074 animateCollapse : function(){
36079 * Expands this region if it was previously collapsed.
36080 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
36081 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
36084 expand : function(e, skipAnim){
36086 e.stopPropagation();
36088 if(!this.collapsed || this.el.hasActiveFx()) {
36092 this.afterSlideIn();
36095 this.collapsed = false;
36096 if(this.config.animate && skipAnim !== true){
36097 this.animateExpand();
36101 this.split.el.show();
36103 this.collapsedEl.setLocation(-2000,-2000);
36104 this.collapsedEl.hide();
36105 this.fireEvent("invalidated", this);
36106 this.fireEvent("expanded", this);
36110 animateExpand : function(){
36114 initTabs : function()
36116 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
36118 var ts = new Roo.bootstrap.panel.Tabs({
36119 el: this.bodyEl.dom,
36120 tabPosition: this.bottomTabs ? 'bottom' : 'top',
36121 disableTooltips: this.config.disableTabTips,
36122 toolbar : this.config.toolbar
36125 if(this.config.hideTabs){
36126 ts.stripWrap.setDisplayed(false);
36129 ts.resizeTabs = this.config.resizeTabs === true;
36130 ts.minTabWidth = this.config.minTabWidth || 40;
36131 ts.maxTabWidth = this.config.maxTabWidth || 250;
36132 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
36133 ts.monitorResize = false;
36134 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
36135 ts.bodyEl.addClass('roo-layout-tabs-body');
36136 this.panels.each(this.initPanelAsTab, this);
36139 initPanelAsTab : function(panel){
36140 var ti = this.tabs.addTab(
36144 this.config.closeOnTab && panel.isClosable(),
36147 if(panel.tabTip !== undefined){
36148 ti.setTooltip(panel.tabTip);
36150 ti.on("activate", function(){
36151 this.setActivePanel(panel);
36154 if(this.config.closeOnTab){
36155 ti.on("beforeclose", function(t, e){
36157 this.remove(panel);
36161 panel.tabItem = ti;
36166 updatePanelTitle : function(panel, title)
36168 if(this.activePanel == panel){
36169 this.updateTitle(title);
36172 var ti = this.tabs.getTab(panel.getEl().id);
36174 if(panel.tabTip !== undefined){
36175 ti.setTooltip(panel.tabTip);
36180 updateTitle : function(title){
36181 if(this.titleTextEl && !this.config.title){
36182 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
36186 setActivePanel : function(panel)
36188 panel = this.getPanel(panel);
36189 if(this.activePanel && this.activePanel != panel){
36190 if(this.activePanel.setActiveState(false) === false){
36194 this.activePanel = panel;
36195 panel.setActiveState(true);
36196 if(this.panelSize){
36197 panel.setSize(this.panelSize.width, this.panelSize.height);
36200 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
36202 this.updateTitle(panel.getTitle());
36204 this.fireEvent("invalidated", this);
36206 this.fireEvent("panelactivated", this, panel);
36210 * Shows the specified panel.
36211 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
36212 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
36214 showPanel : function(panel)
36216 panel = this.getPanel(panel);
36219 var tab = this.tabs.getTab(panel.getEl().id);
36220 if(tab.isHidden()){
36221 this.tabs.unhideTab(tab.id);
36225 this.setActivePanel(panel);
36232 * Get the active panel for this region.
36233 * @return {Roo.ContentPanel} The active panel or null
36235 getActivePanel : function(){
36236 return this.activePanel;
36239 validateVisibility : function(){
36240 if(this.panels.getCount() < 1){
36241 this.updateTitle(" ");
36242 this.closeBtn.hide();
36245 if(!this.isVisible()){
36252 * Adds the passed ContentPanel(s) to this region.
36253 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
36254 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
36256 add : function(panel)
36258 if(arguments.length > 1){
36259 for(var i = 0, len = arguments.length; i < len; i++) {
36260 this.add(arguments[i]);
36265 // if we have not been rendered yet, then we can not really do much of this..
36266 if (!this.bodyEl) {
36267 this.unrendered_panels.push(panel);
36274 if(this.hasPanel(panel)){
36275 this.showPanel(panel);
36278 panel.setRegion(this);
36279 this.panels.add(panel);
36280 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
36281 // sinle panel - no tab...?? would it not be better to render it with the tabs,
36282 // and hide them... ???
36283 this.bodyEl.dom.appendChild(panel.getEl().dom);
36284 if(panel.background !== true){
36285 this.setActivePanel(panel);
36287 this.fireEvent("paneladded", this, panel);
36294 this.initPanelAsTab(panel);
36298 if(panel.background !== true){
36299 this.tabs.activate(panel.getEl().id);
36301 this.fireEvent("paneladded", this, panel);
36306 * Hides the tab for the specified panel.
36307 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36309 hidePanel : function(panel){
36310 if(this.tabs && (panel = this.getPanel(panel))){
36311 this.tabs.hideTab(panel.getEl().id);
36316 * Unhides the tab for a previously hidden panel.
36317 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36319 unhidePanel : function(panel){
36320 if(this.tabs && (panel = this.getPanel(panel))){
36321 this.tabs.unhideTab(panel.getEl().id);
36325 clearPanels : function(){
36326 while(this.panels.getCount() > 0){
36327 this.remove(this.panels.first());
36332 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
36333 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36334 * @param {Boolean} preservePanel Overrides the config preservePanel option
36335 * @return {Roo.ContentPanel} The panel that was removed
36337 remove : function(panel, preservePanel)
36339 panel = this.getPanel(panel);
36344 this.fireEvent("beforeremove", this, panel, e);
36345 if(e.cancel === true){
36348 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
36349 var panelId = panel.getId();
36350 this.panels.removeKey(panelId);
36352 document.body.appendChild(panel.getEl().dom);
36355 this.tabs.removeTab(panel.getEl().id);
36356 }else if (!preservePanel){
36357 this.bodyEl.dom.removeChild(panel.getEl().dom);
36359 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
36360 var p = this.panels.first();
36361 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
36362 tempEl.appendChild(p.getEl().dom);
36363 this.bodyEl.update("");
36364 this.bodyEl.dom.appendChild(p.getEl().dom);
36366 this.updateTitle(p.getTitle());
36368 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
36369 this.setActivePanel(p);
36371 panel.setRegion(null);
36372 if(this.activePanel == panel){
36373 this.activePanel = null;
36375 if(this.config.autoDestroy !== false && preservePanel !== true){
36376 try{panel.destroy();}catch(e){}
36378 this.fireEvent("panelremoved", this, panel);
36383 * Returns the TabPanel component used by this region
36384 * @return {Roo.TabPanel}
36386 getTabs : function(){
36390 createTool : function(parentEl, className){
36391 var btn = Roo.DomHelper.append(parentEl, {
36393 cls: "x-layout-tools-button",
36396 cls: "roo-layout-tools-button-inner " + className,
36400 btn.addClassOnOver("roo-layout-tools-button-over");
36405 * Ext JS Library 1.1.1
36406 * Copyright(c) 2006-2007, Ext JS, LLC.
36408 * Originally Released Under LGPL - original licence link has changed is not relivant.
36411 * <script type="text/javascript">
36417 * @class Roo.SplitLayoutRegion
36418 * @extends Roo.LayoutRegion
36419 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
36421 Roo.bootstrap.layout.Split = function(config){
36422 this.cursor = config.cursor;
36423 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
36426 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
36428 splitTip : "Drag to resize.",
36429 collapsibleSplitTip : "Drag to resize. Double click to hide.",
36430 useSplitTips : false,
36432 applyConfig : function(config){
36433 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
36436 onRender : function(ctr,pos) {
36438 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
36439 if(!this.config.split){
36444 var splitEl = Roo.DomHelper.append(ctr.dom, {
36446 id: this.el.id + "-split",
36447 cls: "roo-layout-split roo-layout-split-"+this.position,
36450 /** The SplitBar for this region
36451 * @type Roo.SplitBar */
36452 // does not exist yet...
36453 Roo.log([this.position, this.orientation]);
36455 this.split = new Roo.bootstrap.SplitBar({
36456 dragElement : splitEl,
36457 resizingElement: this.el,
36458 orientation : this.orientation
36461 this.split.on("moved", this.onSplitMove, this);
36462 this.split.useShim = this.config.useShim === true;
36463 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
36464 if(this.useSplitTips){
36465 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
36467 //if(config.collapsible){
36468 // this.split.el.on("dblclick", this.collapse, this);
36471 if(typeof this.config.minSize != "undefined"){
36472 this.split.minSize = this.config.minSize;
36474 if(typeof this.config.maxSize != "undefined"){
36475 this.split.maxSize = this.config.maxSize;
36477 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
36478 this.hideSplitter();
36483 getHMaxSize : function(){
36484 var cmax = this.config.maxSize || 10000;
36485 var center = this.mgr.getRegion("center");
36486 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
36489 getVMaxSize : function(){
36490 var cmax = this.config.maxSize || 10000;
36491 var center = this.mgr.getRegion("center");
36492 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
36495 onSplitMove : function(split, newSize){
36496 this.fireEvent("resized", this, newSize);
36500 * Returns the {@link Roo.SplitBar} for this region.
36501 * @return {Roo.SplitBar}
36503 getSplitBar : function(){
36508 this.hideSplitter();
36509 Roo.bootstrap.layout.Split.superclass.hide.call(this);
36512 hideSplitter : function(){
36514 this.split.el.setLocation(-2000,-2000);
36515 this.split.el.hide();
36521 this.split.el.show();
36523 Roo.bootstrap.layout.Split.superclass.show.call(this);
36526 beforeSlide: function(){
36527 if(Roo.isGecko){// firefox overflow auto bug workaround
36528 this.bodyEl.clip();
36530 this.tabs.bodyEl.clip();
36532 if(this.activePanel){
36533 this.activePanel.getEl().clip();
36535 if(this.activePanel.beforeSlide){
36536 this.activePanel.beforeSlide();
36542 afterSlide : function(){
36543 if(Roo.isGecko){// firefox overflow auto bug workaround
36544 this.bodyEl.unclip();
36546 this.tabs.bodyEl.unclip();
36548 if(this.activePanel){
36549 this.activePanel.getEl().unclip();
36550 if(this.activePanel.afterSlide){
36551 this.activePanel.afterSlide();
36557 initAutoHide : function(){
36558 if(this.autoHide !== false){
36559 if(!this.autoHideHd){
36560 var st = new Roo.util.DelayedTask(this.slideIn, this);
36561 this.autoHideHd = {
36562 "mouseout": function(e){
36563 if(!e.within(this.el, true)){
36567 "mouseover" : function(e){
36573 this.el.on(this.autoHideHd);
36577 clearAutoHide : function(){
36578 if(this.autoHide !== false){
36579 this.el.un("mouseout", this.autoHideHd.mouseout);
36580 this.el.un("mouseover", this.autoHideHd.mouseover);
36584 clearMonitor : function(){
36585 Roo.get(document).un("click", this.slideInIf, this);
36588 // these names are backwards but not changed for compat
36589 slideOut : function(){
36590 if(this.isSlid || this.el.hasActiveFx()){
36593 this.isSlid = true;
36594 if(this.collapseBtn){
36595 this.collapseBtn.hide();
36597 this.closeBtnState = this.closeBtn.getStyle('display');
36598 this.closeBtn.hide();
36600 this.stickBtn.show();
36603 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
36604 this.beforeSlide();
36605 this.el.setStyle("z-index", 10001);
36606 this.el.slideIn(this.getSlideAnchor(), {
36607 callback: function(){
36609 this.initAutoHide();
36610 Roo.get(document).on("click", this.slideInIf, this);
36611 this.fireEvent("slideshow", this);
36618 afterSlideIn : function(){
36619 this.clearAutoHide();
36620 this.isSlid = false;
36621 this.clearMonitor();
36622 this.el.setStyle("z-index", "");
36623 if(this.collapseBtn){
36624 this.collapseBtn.show();
36626 this.closeBtn.setStyle('display', this.closeBtnState);
36628 this.stickBtn.hide();
36630 this.fireEvent("slidehide", this);
36633 slideIn : function(cb){
36634 if(!this.isSlid || this.el.hasActiveFx()){
36638 this.isSlid = false;
36639 this.beforeSlide();
36640 this.el.slideOut(this.getSlideAnchor(), {
36641 callback: function(){
36642 this.el.setLeftTop(-10000, -10000);
36644 this.afterSlideIn();
36652 slideInIf : function(e){
36653 if(!e.within(this.el)){
36658 animateCollapse : function(){
36659 this.beforeSlide();
36660 this.el.setStyle("z-index", 20000);
36661 var anchor = this.getSlideAnchor();
36662 this.el.slideOut(anchor, {
36663 callback : function(){
36664 this.el.setStyle("z-index", "");
36665 this.collapsedEl.slideIn(anchor, {duration:.3});
36667 this.el.setLocation(-10000,-10000);
36669 this.fireEvent("collapsed", this);
36676 animateExpand : function(){
36677 this.beforeSlide();
36678 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
36679 this.el.setStyle("z-index", 20000);
36680 this.collapsedEl.hide({
36683 this.el.slideIn(this.getSlideAnchor(), {
36684 callback : function(){
36685 this.el.setStyle("z-index", "");
36688 this.split.el.show();
36690 this.fireEvent("invalidated", this);
36691 this.fireEvent("expanded", this);
36719 getAnchor : function(){
36720 return this.anchors[this.position];
36723 getCollapseAnchor : function(){
36724 return this.canchors[this.position];
36727 getSlideAnchor : function(){
36728 return this.sanchors[this.position];
36731 getAlignAdj : function(){
36732 var cm = this.cmargins;
36733 switch(this.position){
36749 getExpandAdj : function(){
36750 var c = this.collapsedEl, cm = this.cmargins;
36751 switch(this.position){
36753 return [-(cm.right+c.getWidth()+cm.left), 0];
36756 return [cm.right+c.getWidth()+cm.left, 0];
36759 return [0, -(cm.top+cm.bottom+c.getHeight())];
36762 return [0, cm.top+cm.bottom+c.getHeight()];
36768 * Ext JS Library 1.1.1
36769 * Copyright(c) 2006-2007, Ext JS, LLC.
36771 * Originally Released Under LGPL - original licence link has changed is not relivant.
36774 * <script type="text/javascript">
36777 * These classes are private internal classes
36779 Roo.bootstrap.layout.Center = function(config){
36780 config.region = "center";
36781 Roo.bootstrap.layout.Region.call(this, config);
36782 this.visible = true;
36783 this.minWidth = config.minWidth || 20;
36784 this.minHeight = config.minHeight || 20;
36787 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
36789 // center panel can't be hidden
36793 // center panel can't be hidden
36796 getMinWidth: function(){
36797 return this.minWidth;
36800 getMinHeight: function(){
36801 return this.minHeight;
36814 Roo.bootstrap.layout.North = function(config)
36816 config.region = 'north';
36817 config.cursor = 'n-resize';
36819 Roo.bootstrap.layout.Split.call(this, config);
36823 this.split.placement = Roo.bootstrap.SplitBar.TOP;
36824 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36825 this.split.el.addClass("roo-layout-split-v");
36827 var size = config.initialSize || config.height;
36828 if(typeof size != "undefined"){
36829 this.el.setHeight(size);
36832 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
36834 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36838 getBox : function(){
36839 if(this.collapsed){
36840 return this.collapsedEl.getBox();
36842 var box = this.el.getBox();
36844 box.height += this.split.el.getHeight();
36849 updateBox : function(box){
36850 if(this.split && !this.collapsed){
36851 box.height -= this.split.el.getHeight();
36852 this.split.el.setLeft(box.x);
36853 this.split.el.setTop(box.y+box.height);
36854 this.split.el.setWidth(box.width);
36856 if(this.collapsed){
36857 this.updateBody(box.width, null);
36859 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36867 Roo.bootstrap.layout.South = function(config){
36868 config.region = 'south';
36869 config.cursor = 's-resize';
36870 Roo.bootstrap.layout.Split.call(this, config);
36872 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
36873 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36874 this.split.el.addClass("roo-layout-split-v");
36876 var size = config.initialSize || config.height;
36877 if(typeof size != "undefined"){
36878 this.el.setHeight(size);
36882 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
36883 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36884 getBox : function(){
36885 if(this.collapsed){
36886 return this.collapsedEl.getBox();
36888 var box = this.el.getBox();
36890 var sh = this.split.el.getHeight();
36897 updateBox : function(box){
36898 if(this.split && !this.collapsed){
36899 var sh = this.split.el.getHeight();
36902 this.split.el.setLeft(box.x);
36903 this.split.el.setTop(box.y-sh);
36904 this.split.el.setWidth(box.width);
36906 if(this.collapsed){
36907 this.updateBody(box.width, null);
36909 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36913 Roo.bootstrap.layout.East = function(config){
36914 config.region = "east";
36915 config.cursor = "e-resize";
36916 Roo.bootstrap.layout.Split.call(this, config);
36918 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
36919 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36920 this.split.el.addClass("roo-layout-split-h");
36922 var size = config.initialSize || config.width;
36923 if(typeof size != "undefined"){
36924 this.el.setWidth(size);
36927 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
36928 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36929 getBox : function(){
36930 if(this.collapsed){
36931 return this.collapsedEl.getBox();
36933 var box = this.el.getBox();
36935 var sw = this.split.el.getWidth();
36942 updateBox : function(box){
36943 if(this.split && !this.collapsed){
36944 var sw = this.split.el.getWidth();
36946 this.split.el.setLeft(box.x);
36947 this.split.el.setTop(box.y);
36948 this.split.el.setHeight(box.height);
36951 if(this.collapsed){
36952 this.updateBody(null, box.height);
36954 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36958 Roo.bootstrap.layout.West = function(config){
36959 config.region = "west";
36960 config.cursor = "w-resize";
36962 Roo.bootstrap.layout.Split.call(this, config);
36964 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
36965 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36966 this.split.el.addClass("roo-layout-split-h");
36970 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
36971 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36973 onRender: function(ctr, pos)
36975 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
36976 var size = this.config.initialSize || this.config.width;
36977 if(typeof size != "undefined"){
36978 this.el.setWidth(size);
36982 getBox : function(){
36983 if(this.collapsed){
36984 return this.collapsedEl.getBox();
36986 var box = this.el.getBox();
36988 box.width += this.split.el.getWidth();
36993 updateBox : function(box){
36994 if(this.split && !this.collapsed){
36995 var sw = this.split.el.getWidth();
36997 this.split.el.setLeft(box.x+box.width);
36998 this.split.el.setTop(box.y);
36999 this.split.el.setHeight(box.height);
37001 if(this.collapsed){
37002 this.updateBody(null, box.height);
37004 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37007 Roo.namespace("Roo.bootstrap.panel");/*
37009 * Ext JS Library 1.1.1
37010 * Copyright(c) 2006-2007, Ext JS, LLC.
37012 * Originally Released Under LGPL - original licence link has changed is not relivant.
37015 * <script type="text/javascript">
37018 * @class Roo.ContentPanel
37019 * @extends Roo.util.Observable
37020 * A basic ContentPanel element.
37021 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
37022 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
37023 * @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
37024 * @cfg {Boolean} closable True if the panel can be closed/removed
37025 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
37026 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
37027 * @cfg {Toolbar} toolbar A toolbar for this panel
37028 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
37029 * @cfg {String} title The title for this panel
37030 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
37031 * @cfg {String} url Calls {@link #setUrl} with this value
37032 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
37033 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
37034 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
37035 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
37036 * @cfg {Boolean} badges render the badges
37039 * Create a new ContentPanel.
37040 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
37041 * @param {String/Object} config A string to set only the title or a config object
37042 * @param {String} content (optional) Set the HTML content for this panel
37043 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
37045 Roo.bootstrap.panel.Content = function( config){
37047 this.tpl = config.tpl || false;
37049 var el = config.el;
37050 var content = config.content;
37052 if(config.autoCreate){ // xtype is available if this is called from factory
37055 this.el = Roo.get(el);
37056 if(!this.el && config && config.autoCreate){
37057 if(typeof config.autoCreate == "object"){
37058 if(!config.autoCreate.id){
37059 config.autoCreate.id = config.id||el;
37061 this.el = Roo.DomHelper.append(document.body,
37062 config.autoCreate, true);
37064 var elcfg = { tag: "div",
37065 cls: "roo-layout-inactive-content",
37069 elcfg.html = config.html;
37073 this.el = Roo.DomHelper.append(document.body, elcfg , true);
37076 this.closable = false;
37077 this.loaded = false;
37078 this.active = false;
37081 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
37083 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
37085 this.wrapEl = this.el; //this.el.wrap();
37087 if (config.toolbar.items) {
37088 ti = config.toolbar.items ;
37089 delete config.toolbar.items ;
37093 this.toolbar.render(this.wrapEl, 'before');
37094 for(var i =0;i < ti.length;i++) {
37095 // Roo.log(['add child', items[i]]);
37096 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37098 this.toolbar.items = nitems;
37099 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
37100 delete config.toolbar;
37104 // xtype created footer. - not sure if will work as we normally have to render first..
37105 if (this.footer && !this.footer.el && this.footer.xtype) {
37106 if (!this.wrapEl) {
37107 this.wrapEl = this.el.wrap();
37110 this.footer.container = this.wrapEl.createChild();
37112 this.footer = Roo.factory(this.footer, Roo);
37117 if(typeof config == "string"){
37118 this.title = config;
37120 Roo.apply(this, config);
37124 this.resizeEl = Roo.get(this.resizeEl, true);
37126 this.resizeEl = this.el;
37128 // handle view.xtype
37136 * Fires when this panel is activated.
37137 * @param {Roo.ContentPanel} this
37141 * @event deactivate
37142 * Fires when this panel is activated.
37143 * @param {Roo.ContentPanel} this
37145 "deactivate" : true,
37149 * Fires when this panel is resized if fitToFrame is true.
37150 * @param {Roo.ContentPanel} this
37151 * @param {Number} width The width after any component adjustments
37152 * @param {Number} height The height after any component adjustments
37158 * Fires when this tab is created
37159 * @param {Roo.ContentPanel} this
37170 if(this.autoScroll){
37171 this.resizeEl.setStyle("overflow", "auto");
37173 // fix randome scrolling
37174 //this.el.on('scroll', function() {
37175 // Roo.log('fix random scolling');
37176 // this.scrollTo('top',0);
37179 content = content || this.content;
37181 this.setContent(content);
37183 if(config && config.url){
37184 this.setUrl(this.url, this.params, this.loadOnce);
37189 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
37191 if (this.view && typeof(this.view.xtype) != 'undefined') {
37192 this.view.el = this.el.appendChild(document.createElement("div"));
37193 this.view = Roo.factory(this.view);
37194 this.view.render && this.view.render(false, '');
37198 this.fireEvent('render', this);
37201 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
37205 setRegion : function(region){
37206 this.region = region;
37207 this.setActiveClass(region && !this.background);
37211 setActiveClass: function(state)
37214 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
37215 this.el.setStyle('position','relative');
37217 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
37218 this.el.setStyle('position', 'absolute');
37223 * Returns the toolbar for this Panel if one was configured.
37224 * @return {Roo.Toolbar}
37226 getToolbar : function(){
37227 return this.toolbar;
37230 setActiveState : function(active)
37232 this.active = active;
37233 this.setActiveClass(active);
37235 if(this.fireEvent("deactivate", this) === false){
37240 this.fireEvent("activate", this);
37244 * Updates this panel's element
37245 * @param {String} content The new content
37246 * @param {Boolean} loadScripts (optional) true to look for and process scripts
37248 setContent : function(content, loadScripts){
37249 this.el.update(content, loadScripts);
37252 ignoreResize : function(w, h){
37253 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
37256 this.lastSize = {width: w, height: h};
37261 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
37262 * @return {Roo.UpdateManager} The UpdateManager
37264 getUpdateManager : function(){
37265 return this.el.getUpdateManager();
37268 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
37269 * @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:
37272 url: "your-url.php",
37273 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
37274 callback: yourFunction,
37275 scope: yourObject, //(optional scope)
37278 text: "Loading...",
37283 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
37284 * 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.
37285 * @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}
37286 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
37287 * @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.
37288 * @return {Roo.ContentPanel} this
37291 var um = this.el.getUpdateManager();
37292 um.update.apply(um, arguments);
37298 * 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.
37299 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
37300 * @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)
37301 * @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)
37302 * @return {Roo.UpdateManager} The UpdateManager
37304 setUrl : function(url, params, loadOnce){
37305 if(this.refreshDelegate){
37306 this.removeListener("activate", this.refreshDelegate);
37308 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
37309 this.on("activate", this.refreshDelegate);
37310 return this.el.getUpdateManager();
37313 _handleRefresh : function(url, params, loadOnce){
37314 if(!loadOnce || !this.loaded){
37315 var updater = this.el.getUpdateManager();
37316 updater.update(url, params, this._setLoaded.createDelegate(this));
37320 _setLoaded : function(){
37321 this.loaded = true;
37325 * Returns this panel's id
37328 getId : function(){
37333 * Returns this panel's element - used by regiosn to add.
37334 * @return {Roo.Element}
37336 getEl : function(){
37337 return this.wrapEl || this.el;
37342 adjustForComponents : function(width, height)
37344 //Roo.log('adjustForComponents ');
37345 if(this.resizeEl != this.el){
37346 width -= this.el.getFrameWidth('lr');
37347 height -= this.el.getFrameWidth('tb');
37350 var te = this.toolbar.getEl();
37351 te.setWidth(width);
37352 height -= te.getHeight();
37355 var te = this.footer.getEl();
37356 te.setWidth(width);
37357 height -= te.getHeight();
37361 if(this.adjustments){
37362 width += this.adjustments[0];
37363 height += this.adjustments[1];
37365 return {"width": width, "height": height};
37368 setSize : function(width, height){
37369 if(this.fitToFrame && !this.ignoreResize(width, height)){
37370 if(this.fitContainer && this.resizeEl != this.el){
37371 this.el.setSize(width, height);
37373 var size = this.adjustForComponents(width, height);
37374 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
37375 this.fireEvent('resize', this, size.width, size.height);
37380 * Returns this panel's title
37383 getTitle : function(){
37385 if (typeof(this.title) != 'object') {
37390 for (var k in this.title) {
37391 if (!this.title.hasOwnProperty(k)) {
37395 if (k.indexOf('-') >= 0) {
37396 var s = k.split('-');
37397 for (var i = 0; i<s.length; i++) {
37398 t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
37401 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
37408 * Set this panel's title
37409 * @param {String} title
37411 setTitle : function(title){
37412 this.title = title;
37414 this.region.updatePanelTitle(this, title);
37419 * Returns true is this panel was configured to be closable
37420 * @return {Boolean}
37422 isClosable : function(){
37423 return this.closable;
37426 beforeSlide : function(){
37428 this.resizeEl.clip();
37431 afterSlide : function(){
37433 this.resizeEl.unclip();
37437 * Force a content refresh from the URL specified in the {@link #setUrl} method.
37438 * Will fail silently if the {@link #setUrl} method has not been called.
37439 * This does not activate the panel, just updates its content.
37441 refresh : function(){
37442 if(this.refreshDelegate){
37443 this.loaded = false;
37444 this.refreshDelegate();
37449 * Destroys this panel
37451 destroy : function(){
37452 this.el.removeAllListeners();
37453 var tempEl = document.createElement("span");
37454 tempEl.appendChild(this.el.dom);
37455 tempEl.innerHTML = "";
37461 * form - if the content panel contains a form - this is a reference to it.
37462 * @type {Roo.form.Form}
37466 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
37467 * This contains a reference to it.
37473 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
37483 * @param {Object} cfg Xtype definition of item to add.
37487 getChildContainer: function () {
37488 return this.getEl();
37493 var ret = new Roo.factory(cfg);
37498 if (cfg.xtype.match(/^Form$/)) {
37501 //if (this.footer) {
37502 // el = this.footer.container.insertSibling(false, 'before');
37504 el = this.el.createChild();
37507 this.form = new Roo.form.Form(cfg);
37510 if ( this.form.allItems.length) {
37511 this.form.render(el.dom);
37515 // should only have one of theses..
37516 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
37517 // views.. should not be just added - used named prop 'view''
37519 cfg.el = this.el.appendChild(document.createElement("div"));
37522 var ret = new Roo.factory(cfg);
37524 ret.render && ret.render(false, ''); // render blank..
37534 * @class Roo.bootstrap.panel.Grid
37535 * @extends Roo.bootstrap.panel.Content
37537 * Create a new GridPanel.
37538 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
37539 * @param {Object} config A the config object
37545 Roo.bootstrap.panel.Grid = function(config)
37549 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
37550 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
37552 config.el = this.wrapper;
37553 //this.el = this.wrapper;
37555 if (config.container) {
37556 // ctor'ed from a Border/panel.grid
37559 this.wrapper.setStyle("overflow", "hidden");
37560 this.wrapper.addClass('roo-grid-container');
37565 if(config.toolbar){
37566 var tool_el = this.wrapper.createChild();
37567 this.toolbar = Roo.factory(config.toolbar);
37569 if (config.toolbar.items) {
37570 ti = config.toolbar.items ;
37571 delete config.toolbar.items ;
37575 this.toolbar.render(tool_el);
37576 for(var i =0;i < ti.length;i++) {
37577 // Roo.log(['add child', items[i]]);
37578 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37580 this.toolbar.items = nitems;
37582 delete config.toolbar;
37585 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
37586 config.grid.scrollBody = true;;
37587 config.grid.monitorWindowResize = false; // turn off autosizing
37588 config.grid.autoHeight = false;
37589 config.grid.autoWidth = false;
37591 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
37593 if (config.background) {
37594 // render grid on panel activation (if panel background)
37595 this.on('activate', function(gp) {
37596 if (!gp.grid.rendered) {
37597 gp.grid.render(this.wrapper);
37598 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37603 this.grid.render(this.wrapper);
37604 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37607 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
37608 // ??? needed ??? config.el = this.wrapper;
37613 // xtype created footer. - not sure if will work as we normally have to render first..
37614 if (this.footer && !this.footer.el && this.footer.xtype) {
37616 var ctr = this.grid.getView().getFooterPanel(true);
37617 this.footer.dataSource = this.grid.dataSource;
37618 this.footer = Roo.factory(this.footer, Roo);
37619 this.footer.render(ctr);
37629 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
37630 getId : function(){
37631 return this.grid.id;
37635 * Returns the grid for this panel
37636 * @return {Roo.bootstrap.Table}
37638 getGrid : function(){
37642 setSize : function(width, height){
37643 if(!this.ignoreResize(width, height)){
37644 var grid = this.grid;
37645 var size = this.adjustForComponents(width, height);
37646 var gridel = grid.getGridEl();
37647 gridel.setSize(size.width, size.height);
37649 var thd = grid.getGridEl().select('thead',true).first();
37650 var tbd = grid.getGridEl().select('tbody', true).first();
37652 tbd.setSize(width, height - thd.getHeight());
37661 beforeSlide : function(){
37662 this.grid.getView().scroller.clip();
37665 afterSlide : function(){
37666 this.grid.getView().scroller.unclip();
37669 destroy : function(){
37670 this.grid.destroy();
37672 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
37677 * @class Roo.bootstrap.panel.Nest
37678 * @extends Roo.bootstrap.panel.Content
37680 * Create a new Panel, that can contain a layout.Border.
37683 * @param {Roo.BorderLayout} layout The layout for this panel
37684 * @param {String/Object} config A string to set only the title or a config object
37686 Roo.bootstrap.panel.Nest = function(config)
37688 // construct with only one argument..
37689 /* FIXME - implement nicer consturctors
37690 if (layout.layout) {
37692 layout = config.layout;
37693 delete config.layout;
37695 if (layout.xtype && !layout.getEl) {
37696 // then layout needs constructing..
37697 layout = Roo.factory(layout, Roo);
37701 config.el = config.layout.getEl();
37703 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
37705 config.layout.monitorWindowResize = false; // turn off autosizing
37706 this.layout = config.layout;
37707 this.layout.getEl().addClass("roo-layout-nested-layout");
37714 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
37716 setSize : function(width, height){
37717 if(!this.ignoreResize(width, height)){
37718 var size = this.adjustForComponents(width, height);
37719 var el = this.layout.getEl();
37720 if (size.height < 1) {
37721 el.setWidth(size.width);
37723 el.setSize(size.width, size.height);
37725 var touch = el.dom.offsetWidth;
37726 this.layout.layout();
37727 // ie requires a double layout on the first pass
37728 if(Roo.isIE && !this.initialized){
37729 this.initialized = true;
37730 this.layout.layout();
37735 // activate all subpanels if not currently active..
37737 setActiveState : function(active){
37738 this.active = active;
37739 this.setActiveClass(active);
37742 this.fireEvent("deactivate", this);
37746 this.fireEvent("activate", this);
37747 // not sure if this should happen before or after..
37748 if (!this.layout) {
37749 return; // should not happen..
37752 for (var r in this.layout.regions) {
37753 reg = this.layout.getRegion(r);
37754 if (reg.getActivePanel()) {
37755 //reg.showPanel(reg.getActivePanel()); // force it to activate..
37756 reg.setActivePanel(reg.getActivePanel());
37759 if (!reg.panels.length) {
37762 reg.showPanel(reg.getPanel(0));
37771 * Returns the nested BorderLayout for this panel
37772 * @return {Roo.BorderLayout}
37774 getLayout : function(){
37775 return this.layout;
37779 * Adds a xtype elements to the layout of the nested panel
37783 xtype : 'ContentPanel',
37790 xtype : 'NestedLayoutPanel',
37796 items : [ ... list of content panels or nested layout panels.. ]
37800 * @param {Object} cfg Xtype definition of item to add.
37802 addxtype : function(cfg) {
37803 return this.layout.addxtype(cfg);
37808 * Ext JS Library 1.1.1
37809 * Copyright(c) 2006-2007, Ext JS, LLC.
37811 * Originally Released Under LGPL - original licence link has changed is not relivant.
37814 * <script type="text/javascript">
37817 * @class Roo.TabPanel
37818 * @extends Roo.util.Observable
37819 * A lightweight tab container.
37823 // basic tabs 1, built from existing content
37824 var tabs = new Roo.TabPanel("tabs1");
37825 tabs.addTab("script", "View Script");
37826 tabs.addTab("markup", "View Markup");
37827 tabs.activate("script");
37829 // more advanced tabs, built from javascript
37830 var jtabs = new Roo.TabPanel("jtabs");
37831 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
37833 // set up the UpdateManager
37834 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
37835 var updater = tab2.getUpdateManager();
37836 updater.setDefaultUrl("ajax1.htm");
37837 tab2.on('activate', updater.refresh, updater, true);
37839 // Use setUrl for Ajax loading
37840 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
37841 tab3.setUrl("ajax2.htm", null, true);
37844 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
37847 jtabs.activate("jtabs-1");
37850 * Create a new TabPanel.
37851 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
37852 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
37854 Roo.bootstrap.panel.Tabs = function(config){
37856 * The container element for this TabPanel.
37857 * @type Roo.Element
37859 this.el = Roo.get(config.el);
37862 if(typeof config == "boolean"){
37863 this.tabPosition = config ? "bottom" : "top";
37865 Roo.apply(this, config);
37869 if(this.tabPosition == "bottom"){
37870 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37871 this.el.addClass("roo-tabs-bottom");
37873 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
37874 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
37875 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
37877 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
37879 if(this.tabPosition != "bottom"){
37880 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
37881 * @type Roo.Element
37883 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37884 this.el.addClass("roo-tabs-top");
37888 this.bodyEl.setStyle("position", "relative");
37890 this.active = null;
37891 this.activateDelegate = this.activate.createDelegate(this);
37896 * Fires when the active tab changes
37897 * @param {Roo.TabPanel} this
37898 * @param {Roo.TabPanelItem} activePanel The new active tab
37902 * @event beforetabchange
37903 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
37904 * @param {Roo.TabPanel} this
37905 * @param {Object} e Set cancel to true on this object to cancel the tab change
37906 * @param {Roo.TabPanelItem} tab The tab being changed to
37908 "beforetabchange" : true
37911 Roo.EventManager.onWindowResize(this.onResize, this);
37912 this.cpad = this.el.getPadding("lr");
37913 this.hiddenCount = 0;
37916 // toolbar on the tabbar support...
37917 if (this.toolbar) {
37918 alert("no toolbar support yet");
37919 this.toolbar = false;
37921 var tcfg = this.toolbar;
37922 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
37923 this.toolbar = new Roo.Toolbar(tcfg);
37924 if (Roo.isSafari) {
37925 var tbl = tcfg.container.child('table', true);
37926 tbl.setAttribute('width', '100%');
37934 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
37937 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
37939 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
37941 tabPosition : "top",
37943 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
37945 currentTabWidth : 0,
37947 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
37951 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
37955 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
37957 preferredTabWidth : 175,
37959 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
37961 resizeTabs : false,
37963 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
37965 monitorResize : true,
37967 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
37972 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
37973 * @param {String} id The id of the div to use <b>or create</b>
37974 * @param {String} text The text for the tab
37975 * @param {String} content (optional) Content to put in the TabPanelItem body
37976 * @param {Boolean} closable (optional) True to create a close icon on the tab
37977 * @return {Roo.TabPanelItem} The created TabPanelItem
37979 addTab : function(id, text, content, closable, tpl)
37981 var item = new Roo.bootstrap.panel.TabItem({
37985 closable : closable,
37988 this.addTabItem(item);
37990 item.setContent(content);
37996 * Returns the {@link Roo.TabPanelItem} with the specified id/index
37997 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
37998 * @return {Roo.TabPanelItem}
38000 getTab : function(id){
38001 return this.items[id];
38005 * Hides the {@link Roo.TabPanelItem} with the specified id/index
38006 * @param {String/Number} id The id or index of the TabPanelItem to hide.
38008 hideTab : function(id){
38009 var t = this.items[id];
38012 this.hiddenCount++;
38013 this.autoSizeTabs();
38018 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
38019 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
38021 unhideTab : function(id){
38022 var t = this.items[id];
38024 t.setHidden(false);
38025 this.hiddenCount--;
38026 this.autoSizeTabs();
38031 * Adds an existing {@link Roo.TabPanelItem}.
38032 * @param {Roo.TabPanelItem} item The TabPanelItem to add
38034 addTabItem : function(item){
38035 this.items[item.id] = item;
38036 this.items.push(item);
38037 // if(this.resizeTabs){
38038 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
38039 // this.autoSizeTabs();
38041 // item.autoSize();
38046 * Removes a {@link Roo.TabPanelItem}.
38047 * @param {String/Number} id The id or index of the TabPanelItem to remove.
38049 removeTab : function(id){
38050 var items = this.items;
38051 var tab = items[id];
38052 if(!tab) { return; }
38053 var index = items.indexOf(tab);
38054 if(this.active == tab && items.length > 1){
38055 var newTab = this.getNextAvailable(index);
38060 this.stripEl.dom.removeChild(tab.pnode.dom);
38061 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
38062 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
38064 items.splice(index, 1);
38065 delete this.items[tab.id];
38066 tab.fireEvent("close", tab);
38067 tab.purgeListeners();
38068 this.autoSizeTabs();
38071 getNextAvailable : function(start){
38072 var items = this.items;
38074 // look for a next tab that will slide over to
38075 // replace the one being removed
38076 while(index < items.length){
38077 var item = items[++index];
38078 if(item && !item.isHidden()){
38082 // if one isn't found select the previous tab (on the left)
38085 var item = items[--index];
38086 if(item && !item.isHidden()){
38094 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
38095 * @param {String/Number} id The id or index of the TabPanelItem to disable.
38097 disableTab : function(id){
38098 var tab = this.items[id];
38099 if(tab && this.active != tab){
38105 * Enables a {@link Roo.TabPanelItem} that is disabled.
38106 * @param {String/Number} id The id or index of the TabPanelItem to enable.
38108 enableTab : function(id){
38109 var tab = this.items[id];
38114 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
38115 * @param {String/Number} id The id or index of the TabPanelItem to activate.
38116 * @return {Roo.TabPanelItem} The TabPanelItem.
38118 activate : function(id){
38119 var tab = this.items[id];
38123 if(tab == this.active || tab.disabled){
38127 this.fireEvent("beforetabchange", this, e, tab);
38128 if(e.cancel !== true && !tab.disabled){
38130 this.active.hide();
38132 this.active = this.items[id];
38133 this.active.show();
38134 this.fireEvent("tabchange", this, this.active);
38140 * Gets the active {@link Roo.TabPanelItem}.
38141 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
38143 getActiveTab : function(){
38144 return this.active;
38148 * Updates the tab body element to fit the height of the container element
38149 * for overflow scrolling
38150 * @param {Number} targetHeight (optional) Override the starting height from the elements height
38152 syncHeight : function(targetHeight){
38153 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
38154 var bm = this.bodyEl.getMargins();
38155 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
38156 this.bodyEl.setHeight(newHeight);
38160 onResize : function(){
38161 if(this.monitorResize){
38162 this.autoSizeTabs();
38167 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
38169 beginUpdate : function(){
38170 this.updating = true;
38174 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
38176 endUpdate : function(){
38177 this.updating = false;
38178 this.autoSizeTabs();
38182 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
38184 autoSizeTabs : function(){
38185 var count = this.items.length;
38186 var vcount = count - this.hiddenCount;
38187 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
38190 var w = Math.max(this.el.getWidth() - this.cpad, 10);
38191 var availWidth = Math.floor(w / vcount);
38192 var b = this.stripBody;
38193 if(b.getWidth() > w){
38194 var tabs = this.items;
38195 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
38196 if(availWidth < this.minTabWidth){
38197 /*if(!this.sleft){ // incomplete scrolling code
38198 this.createScrollButtons();
38201 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
38204 if(this.currentTabWidth < this.preferredTabWidth){
38205 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
38211 * Returns the number of tabs in this TabPanel.
38214 getCount : function(){
38215 return this.items.length;
38219 * Resizes all the tabs to the passed width
38220 * @param {Number} The new width
38222 setTabWidth : function(width){
38223 this.currentTabWidth = width;
38224 for(var i = 0, len = this.items.length; i < len; i++) {
38225 if(!this.items[i].isHidden()) {
38226 this.items[i].setWidth(width);
38232 * Destroys this TabPanel
38233 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
38235 destroy : function(removeEl){
38236 Roo.EventManager.removeResizeListener(this.onResize, this);
38237 for(var i = 0, len = this.items.length; i < len; i++){
38238 this.items[i].purgeListeners();
38240 if(removeEl === true){
38241 this.el.update("");
38246 createStrip : function(container)
38248 var strip = document.createElement("nav");
38249 strip.className = "navbar navbar-default"; //"x-tabs-wrap";
38250 container.appendChild(strip);
38254 createStripList : function(strip)
38256 // div wrapper for retard IE
38257 // returns the "tr" element.
38258 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
38259 //'<div class="x-tabs-strip-wrap">'+
38260 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
38261 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
38262 return strip.firstChild; //.firstChild.firstChild.firstChild;
38264 createBody : function(container)
38266 var body = document.createElement("div");
38267 Roo.id(body, "tab-body");
38268 //Roo.fly(body).addClass("x-tabs-body");
38269 Roo.fly(body).addClass("tab-content");
38270 container.appendChild(body);
38273 createItemBody :function(bodyEl, id){
38274 var body = Roo.getDom(id);
38276 body = document.createElement("div");
38279 //Roo.fly(body).addClass("x-tabs-item-body");
38280 Roo.fly(body).addClass("tab-pane");
38281 bodyEl.insertBefore(body, bodyEl.firstChild);
38285 createStripElements : function(stripEl, text, closable, tpl)
38287 var td = document.createElement("li"); // was td..
38290 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
38293 stripEl.appendChild(td);
38295 td.className = "x-tabs-closable";
38296 if(!this.closeTpl){
38297 this.closeTpl = new Roo.Template(
38298 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38299 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
38300 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
38303 var el = this.closeTpl.overwrite(td, {"text": text});
38304 var close = el.getElementsByTagName("div")[0];
38305 var inner = el.getElementsByTagName("em")[0];
38306 return {"el": el, "close": close, "inner": inner};
38309 // not sure what this is..
38310 // if(!this.tabTpl){
38311 //this.tabTpl = new Roo.Template(
38312 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38313 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
38315 // this.tabTpl = new Roo.Template(
38316 // '<a href="#">' +
38317 // '<span unselectable="on"' +
38318 // (this.disableTooltips ? '' : ' title="{text}"') +
38319 // ' >{text}</span></a>'
38325 var template = tpl || this.tabTpl || false;
38329 template = new Roo.Template(
38331 '<span unselectable="on"' +
38332 (this.disableTooltips ? '' : ' title="{text}"') +
38333 ' >{text}</span></a>'
38337 switch (typeof(template)) {
38341 template = new Roo.Template(template);
38347 var el = template.overwrite(td, {"text": text});
38349 var inner = el.getElementsByTagName("span")[0];
38351 return {"el": el, "inner": inner};
38359 * @class Roo.TabPanelItem
38360 * @extends Roo.util.Observable
38361 * Represents an individual item (tab plus body) in a TabPanel.
38362 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
38363 * @param {String} id The id of this TabPanelItem
38364 * @param {String} text The text for the tab of this TabPanelItem
38365 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
38367 Roo.bootstrap.panel.TabItem = function(config){
38369 * The {@link Roo.TabPanel} this TabPanelItem belongs to
38370 * @type Roo.TabPanel
38372 this.tabPanel = config.panel;
38374 * The id for this TabPanelItem
38377 this.id = config.id;
38379 this.disabled = false;
38381 this.text = config.text;
38383 this.loaded = false;
38384 this.closable = config.closable;
38387 * The body element for this TabPanelItem.
38388 * @type Roo.Element
38390 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
38391 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
38392 this.bodyEl.setStyle("display", "block");
38393 this.bodyEl.setStyle("zoom", "1");
38394 //this.hideAction();
38396 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
38398 this.el = Roo.get(els.el);
38399 this.inner = Roo.get(els.inner, true);
38400 this.textEl = Roo.get(this.el.dom.firstChild, true);
38401 this.pnode = Roo.get(els.el.parentNode, true);
38402 // this.el.on("mousedown", this.onTabMouseDown, this);
38403 this.el.on("click", this.onTabClick, this);
38405 if(config.closable){
38406 var c = Roo.get(els.close, true);
38407 c.dom.title = this.closeText;
38408 c.addClassOnOver("close-over");
38409 c.on("click", this.closeClick, this);
38415 * Fires when this tab becomes the active tab.
38416 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38417 * @param {Roo.TabPanelItem} this
38421 * @event beforeclose
38422 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
38423 * @param {Roo.TabPanelItem} this
38424 * @param {Object} e Set cancel to true on this object to cancel the close.
38426 "beforeclose": true,
38429 * Fires when this tab is closed.
38430 * @param {Roo.TabPanelItem} this
38434 * @event deactivate
38435 * Fires when this tab is no longer the active tab.
38436 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38437 * @param {Roo.TabPanelItem} this
38439 "deactivate" : true
38441 this.hidden = false;
38443 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
38446 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
38448 purgeListeners : function(){
38449 Roo.util.Observable.prototype.purgeListeners.call(this);
38450 this.el.removeAllListeners();
38453 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
38456 this.pnode.addClass("active");
38459 this.tabPanel.stripWrap.repaint();
38461 this.fireEvent("activate", this.tabPanel, this);
38465 * Returns true if this tab is the active tab.
38466 * @return {Boolean}
38468 isActive : function(){
38469 return this.tabPanel.getActiveTab() == this;
38473 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
38476 this.pnode.removeClass("active");
38478 this.fireEvent("deactivate", this.tabPanel, this);
38481 hideAction : function(){
38482 this.bodyEl.hide();
38483 this.bodyEl.setStyle("position", "absolute");
38484 this.bodyEl.setLeft("-20000px");
38485 this.bodyEl.setTop("-20000px");
38488 showAction : function(){
38489 this.bodyEl.setStyle("position", "relative");
38490 this.bodyEl.setTop("");
38491 this.bodyEl.setLeft("");
38492 this.bodyEl.show();
38496 * Set the tooltip for the tab.
38497 * @param {String} tooltip The tab's tooltip
38499 setTooltip : function(text){
38500 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
38501 this.textEl.dom.qtip = text;
38502 this.textEl.dom.removeAttribute('title');
38504 this.textEl.dom.title = text;
38508 onTabClick : function(e){
38509 e.preventDefault();
38510 this.tabPanel.activate(this.id);
38513 onTabMouseDown : function(e){
38514 e.preventDefault();
38515 this.tabPanel.activate(this.id);
38518 getWidth : function(){
38519 return this.inner.getWidth();
38522 setWidth : function(width){
38523 var iwidth = width - this.pnode.getPadding("lr");
38524 this.inner.setWidth(iwidth);
38525 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
38526 this.pnode.setWidth(width);
38530 * Show or hide the tab
38531 * @param {Boolean} hidden True to hide or false to show.
38533 setHidden : function(hidden){
38534 this.hidden = hidden;
38535 this.pnode.setStyle("display", hidden ? "none" : "");
38539 * Returns true if this tab is "hidden"
38540 * @return {Boolean}
38542 isHidden : function(){
38543 return this.hidden;
38547 * Returns the text for this tab
38550 getText : function(){
38554 autoSize : function(){
38555 //this.el.beginMeasure();
38556 this.textEl.setWidth(1);
38558 * #2804 [new] Tabs in Roojs
38559 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
38561 //this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
38562 //this.el.endMeasure();
38566 * Sets the text for the tab (Note: this also sets the tooltip text)
38567 * @param {String} text The tab's text and tooltip
38569 setText : function(text){
38571 this.textEl.update(text);
38572 this.setTooltip(text);
38573 //if(!this.tabPanel.resizeTabs){
38574 // this.autoSize();
38578 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
38580 activate : function(){
38581 this.tabPanel.activate(this.id);
38585 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
38587 disable : function(){
38588 if(this.tabPanel.active != this){
38589 this.disabled = true;
38590 this.pnode.addClass("disabled");
38595 * Enables this TabPanelItem if it was previously disabled.
38597 enable : function(){
38598 this.disabled = false;
38599 this.pnode.removeClass("disabled");
38603 * Sets the content for this TabPanelItem.
38604 * @param {String} content The content
38605 * @param {Boolean} loadScripts true to look for and load scripts
38607 setContent : function(content, loadScripts){
38608 this.bodyEl.update(content, loadScripts);
38612 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
38613 * @return {Roo.UpdateManager} The UpdateManager
38615 getUpdateManager : function(){
38616 return this.bodyEl.getUpdateManager();
38620 * Set a URL to be used to load the content for this TabPanelItem.
38621 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
38622 * @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)
38623 * @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)
38624 * @return {Roo.UpdateManager} The UpdateManager
38626 setUrl : function(url, params, loadOnce){
38627 if(this.refreshDelegate){
38628 this.un('activate', this.refreshDelegate);
38630 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
38631 this.on("activate", this.refreshDelegate);
38632 return this.bodyEl.getUpdateManager();
38636 _handleRefresh : function(url, params, loadOnce){
38637 if(!loadOnce || !this.loaded){
38638 var updater = this.bodyEl.getUpdateManager();
38639 updater.update(url, params, this._setLoaded.createDelegate(this));
38644 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
38645 * Will fail silently if the setUrl method has not been called.
38646 * This does not activate the panel, just updates its content.
38648 refresh : function(){
38649 if(this.refreshDelegate){
38650 this.loaded = false;
38651 this.refreshDelegate();
38656 _setLoaded : function(){
38657 this.loaded = true;
38661 closeClick : function(e){
38664 this.fireEvent("beforeclose", this, o);
38665 if(o.cancel !== true){
38666 this.tabPanel.removeTab(this.id);
38670 * The text displayed in the tooltip for the close icon.
38673 closeText : "Close this tab"
38676 * This script refer to:
38677 * Title: International Telephone Input
38678 * Author: Jack O'Connor
38679 * Code version: v12.1.12
38680 * Availability: https://github.com/jackocnr/intl-tel-input.git
38683 Roo.bootstrap.PhoneInputData = function() {
38686 "Afghanistan (افغانستان)",
38691 "Albania (Shqipëri)",
38696 "Algeria (الجزائر)",
38721 "Antigua and Barbuda",
38731 "Armenia (Հայաստան)",
38747 "Austria (Österreich)",
38752 "Azerbaijan (Azərbaycan)",
38762 "Bahrain (البحرين)",
38767 "Bangladesh (বাংলাদেশ)",
38777 "Belarus (Беларусь)",
38782 "Belgium (België)",
38812 "Bosnia and Herzegovina (Босна и Херцеговина)",
38827 "British Indian Ocean Territory",
38832 "British Virgin Islands",
38842 "Bulgaria (България)",
38852 "Burundi (Uburundi)",
38857 "Cambodia (កម្ពុជា)",
38862 "Cameroon (Cameroun)",
38871 ["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"]
38874 "Cape Verde (Kabu Verdi)",
38879 "Caribbean Netherlands",
38890 "Central African Republic (République centrafricaine)",
38910 "Christmas Island",
38916 "Cocos (Keeling) Islands",
38927 "Comoros (جزر القمر)",
38932 "Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)",
38937 "Congo (Republic) (Congo-Brazzaville)",
38957 "Croatia (Hrvatska)",
38978 "Czech Republic (Česká republika)",
38983 "Denmark (Danmark)",
38998 "Dominican Republic (República Dominicana)",
39002 ["809", "829", "849"]
39020 "Equatorial Guinea (Guinea Ecuatorial)",
39040 "Falkland Islands (Islas Malvinas)",
39045 "Faroe Islands (Føroyar)",
39066 "French Guiana (Guyane française)",
39071 "French Polynesia (Polynésie française)",
39086 "Georgia (საქართველო)",
39091 "Germany (Deutschland)",
39111 "Greenland (Kalaallit Nunaat)",
39148 "Guinea-Bissau (Guiné Bissau)",
39173 "Hungary (Magyarország)",
39178 "Iceland (Ísland)",
39198 "Iraq (العراق)",
39214 "Israel (ישראל)",
39241 "Jordan (الأردن)",
39246 "Kazakhstan (Казахстан)",
39267 "Kuwait (الكويت)",
39272 "Kyrgyzstan (Кыргызстан)",
39282 "Latvia (Latvija)",
39287 "Lebanon (لبنان)",
39302 "Libya (ليبيا)",
39312 "Lithuania (Lietuva)",
39327 "Macedonia (FYROM) (Македонија)",
39332 "Madagascar (Madagasikara)",
39362 "Marshall Islands",
39372 "Mauritania (موريتانيا)",
39377 "Mauritius (Moris)",
39398 "Moldova (Republica Moldova)",
39408 "Mongolia (Монгол)",
39413 "Montenegro (Crna Gora)",
39423 "Morocco (المغرب)",
39429 "Mozambique (Moçambique)",
39434 "Myanmar (Burma) (မြန်မာ)",
39439 "Namibia (Namibië)",
39454 "Netherlands (Nederland)",
39459 "New Caledonia (Nouvelle-Calédonie)",
39494 "North Korea (조선 민주주의 인민 공화국)",
39499 "Northern Mariana Islands",
39515 "Pakistan (پاکستان)",
39525 "Palestine (فلسطين)",
39535 "Papua New Guinea",
39577 "Réunion (La Réunion)",
39583 "Romania (România)",
39599 "Saint Barthélemy",
39610 "Saint Kitts and Nevis",
39620 "Saint Martin (Saint-Martin (partie française))",
39626 "Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)",
39631 "Saint Vincent and the Grenadines",
39646 "São Tomé and Príncipe (São Tomé e Príncipe)",
39651 "Saudi Arabia (المملكة العربية السعودية)",
39656 "Senegal (Sénégal)",
39686 "Slovakia (Slovensko)",
39691 "Slovenia (Slovenija)",
39701 "Somalia (Soomaaliya)",
39711 "South Korea (대한민국)",
39716 "South Sudan (جنوب السودان)",
39726 "Sri Lanka (ශ්රී ලංකාව)",
39731 "Sudan (السودان)",
39741 "Svalbard and Jan Mayen",
39752 "Sweden (Sverige)",
39757 "Switzerland (Schweiz)",
39762 "Syria (سوريا)",
39807 "Trinidad and Tobago",
39812 "Tunisia (تونس)",
39817 "Turkey (Türkiye)",
39827 "Turks and Caicos Islands",
39837 "U.S. Virgin Islands",
39847 "Ukraine (Україна)",
39852 "United Arab Emirates (الإمارات العربية المتحدة)",
39874 "Uzbekistan (Oʻzbekiston)",
39884 "Vatican City (Città del Vaticano)",
39895 "Vietnam (Việt Nam)",
39900 "Wallis and Futuna (Wallis-et-Futuna)",
39905 "Western Sahara (الصحراء الغربية)",
39911 "Yemen (اليمن)",
39935 * This script refer to:
39936 * Title: International Telephone Input
39937 * Author: Jack O'Connor
39938 * Code version: v12.1.12
39939 * Availability: https://github.com/jackocnr/intl-tel-input.git
39943 * @class Roo.bootstrap.PhoneInput
39944 * @extends Roo.bootstrap.TriggerField
39945 * An input with International dial-code selection
39947 * @cfg {String} defaultDialCode default '+852'
39948 * @cfg {Array} preferedCountries default []
39951 * Create a new PhoneInput.
39952 * @param {Object} config Configuration options
39955 Roo.bootstrap.PhoneInput = function(config) {
39956 Roo.bootstrap.PhoneInput.superclass.constructor.call(this, config);
39959 Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
39961 listWidth: undefined,
39963 selectedClass: 'active',
39965 invalidClass : "has-warning",
39967 validClass: 'has-success',
39969 allowed: '0123456789',
39974 * @cfg {String} defaultDialCode The default dial code when initializing the input
39976 defaultDialCode: '+852',
39979 * @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
39981 preferedCountries: false,
39983 getAutoCreate : function()
39985 var data = Roo.bootstrap.PhoneInputData();
39986 var align = this.labelAlign || this.parentLabelAlign();
39989 this.allCountries = [];
39990 this.dialCodeMapping = [];
39992 for (var i = 0; i < data.length; i++) {
39994 this.allCountries[i] = {
39998 priority: c[3] || 0,
39999 areaCodes: c[4] || null
40001 this.dialCodeMapping[c[2]] = {
40004 priority: c[3] || 0,
40005 areaCodes: c[4] || null
40017 // type: 'number', -- do not use number - we get the flaky up/down arrows.
40018 maxlength: this.max_length,
40019 cls : 'form-control tel-input',
40020 autocomplete: 'new-password'
40023 var hiddenInput = {
40026 cls: 'hidden-tel-input'
40030 hiddenInput.name = this.name;
40033 if (this.disabled) {
40034 input.disabled = true;
40037 var flag_container = {
40054 cls: this.hasFeedback ? 'has-feedback' : '',
40060 cls: 'dial-code-holder',
40067 cls: 'roo-select2-container input-group',
40074 if (this.fieldLabel.length) {
40077 tooltip: 'This field is required'
40083 cls: 'control-label',
40089 html: this.fieldLabel
40092 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40098 if(this.indicatorpos == 'right') {
40099 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40106 if(align == 'left') {
40114 if(this.labelWidth > 12){
40115 label.style = "width: " + this.labelWidth + 'px';
40117 if(this.labelWidth < 13 && this.labelmd == 0){
40118 this.labelmd = this.labelWidth;
40120 if(this.labellg > 0){
40121 label.cls += ' col-lg-' + this.labellg;
40122 input.cls += ' col-lg-' + (12 - this.labellg);
40124 if(this.labelmd > 0){
40125 label.cls += ' col-md-' + this.labelmd;
40126 container.cls += ' col-md-' + (12 - this.labelmd);
40128 if(this.labelsm > 0){
40129 label.cls += ' col-sm-' + this.labelsm;
40130 container.cls += ' col-sm-' + (12 - this.labelsm);
40132 if(this.labelxs > 0){
40133 label.cls += ' col-xs-' + this.labelxs;
40134 container.cls += ' col-xs-' + (12 - this.labelxs);
40144 var settings = this;
40146 ['xs','sm','md','lg'].map(function(size){
40147 if (settings[size]) {
40148 cfg.cls += ' col-' + size + '-' + settings[size];
40152 this.store = new Roo.data.Store({
40153 proxy : new Roo.data.MemoryProxy({}),
40154 reader : new Roo.data.JsonReader({
40165 'name' : 'dialCode',
40169 'name' : 'priority',
40173 'name' : 'areaCodes',
40180 if(!this.preferedCountries) {
40181 this.preferedCountries = [
40188 var p = this.preferedCountries.reverse();
40191 for (var i = 0; i < p.length; i++) {
40192 for (var j = 0; j < this.allCountries.length; j++) {
40193 if(this.allCountries[j].iso2 == p[i]) {
40194 var t = this.allCountries[j];
40195 this.allCountries.splice(j,1);
40196 this.allCountries.unshift(t);
40202 this.store.proxy.data = {
40204 data: this.allCountries
40210 initEvents : function()
40213 Roo.bootstrap.PhoneInput.superclass.initEvents.call(this);
40215 this.indicator = this.indicatorEl();
40216 this.flag = this.flagEl();
40217 this.dialCodeHolder = this.dialCodeHolderEl();
40219 this.trigger = this.el.select('div.flag-box',true).first();
40220 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
40225 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40226 _this.list.setWidth(lw);
40229 this.list.on('mouseover', this.onViewOver, this);
40230 this.list.on('mousemove', this.onViewMove, this);
40231 this.inputEl().on("keyup", this.onKeyUp, this);
40232 this.inputEl().on("keypress", this.onKeyPress, this);
40234 this.tpl = '<li><a href="#"><div class="flag {iso2}"></div>{name} <span class="dial-code">+{dialCode}</span></a></li>';
40236 this.view = new Roo.View(this.list, this.tpl, {
40237 singleSelect:true, store: this.store, selectedClass: this.selectedClass
40240 this.view.on('click', this.onViewClick, this);
40241 this.setValue(this.defaultDialCode);
40244 onTriggerClick : function(e)
40246 Roo.log('trigger click');
40251 if(this.isExpanded()){
40253 this.hasFocus = false;
40255 this.store.load({});
40256 this.hasFocus = true;
40261 isExpanded : function()
40263 return this.list.isVisible();
40266 collapse : function()
40268 if(!this.isExpanded()){
40272 Roo.get(document).un('mousedown', this.collapseIf, this);
40273 Roo.get(document).un('mousewheel', this.collapseIf, this);
40274 this.fireEvent('collapse', this);
40278 expand : function()
40282 if(this.isExpanded() || !this.hasFocus){
40286 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
40287 this.list.setWidth(lw);
40290 this.restrictHeight();
40292 Roo.get(document).on('mousedown', this.collapseIf, this);
40293 Roo.get(document).on('mousewheel', this.collapseIf, this);
40295 this.fireEvent('expand', this);
40298 restrictHeight : function()
40300 this.list.alignTo(this.inputEl(), this.listAlign);
40301 this.list.alignTo(this.inputEl(), this.listAlign);
40304 onViewOver : function(e, t)
40306 if(this.inKeyMode){
40309 var item = this.view.findItemFromChild(t);
40312 var index = this.view.indexOf(item);
40313 this.select(index, false);
40318 onViewClick : function(view, doFocus, el, e)
40320 var index = this.view.getSelectedIndexes()[0];
40322 var r = this.store.getAt(index);
40325 this.onSelect(r, index);
40327 if(doFocus !== false && !this.blockFocus){
40328 this.inputEl().focus();
40332 onViewMove : function(e, t)
40334 this.inKeyMode = false;
40337 select : function(index, scrollIntoView)
40339 this.selectedIndex = index;
40340 this.view.select(index);
40341 if(scrollIntoView !== false){
40342 var el = this.view.getNode(index);
40344 this.list.scrollChildIntoView(el, false);
40349 createList : function()
40351 this.list = Roo.get(document.body).createChild({
40353 cls: 'typeahead typeahead-long dropdown-menu tel-list',
40354 style: 'display:none'
40357 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
40360 collapseIf : function(e)
40362 var in_combo = e.within(this.el);
40363 var in_list = e.within(this.list);
40364 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
40366 if (in_combo || in_list || is_list) {
40372 onSelect : function(record, index)
40374 if(this.fireEvent('beforeselect', this, record, index) !== false){
40376 this.setFlagClass(record.data.iso2);
40377 this.setDialCode(record.data.dialCode);
40378 this.hasFocus = false;
40380 this.fireEvent('select', this, record, index);
40384 flagEl : function()
40386 var flag = this.el.select('div.flag',true).first();
40393 dialCodeHolderEl : function()
40395 var d = this.el.select('input.dial-code-holder',true).first();
40402 setDialCode : function(v)
40404 this.dialCodeHolder.dom.value = '+'+v;
40407 setFlagClass : function(n)
40409 this.flag.dom.className = 'flag '+n;
40412 getValue : function()
40414 var v = this.inputEl().getValue();
40415 if(this.dialCodeHolder) {
40416 v = this.dialCodeHolder.dom.value+this.inputEl().getValue();
40421 setValue : function(v)
40423 var d = this.getDialCode(v);
40425 //invalid dial code
40426 if(v.length == 0 || !d || d.length == 0) {
40428 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
40429 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
40435 this.setFlagClass(this.dialCodeMapping[d].iso2);
40436 this.setDialCode(d);
40437 this.inputEl().dom.value = v.replace('+'+d,'');
40438 this.hiddenEl().dom.value = this.getValue();
40443 getDialCode : function(v)
40447 if (v.length == 0) {
40448 return this.dialCodeHolder.dom.value;
40452 if (v.charAt(0) != "+") {
40455 var numericChars = "";
40456 for (var i = 1; i < v.length; i++) {
40457 var c = v.charAt(i);
40460 if (this.dialCodeMapping[numericChars]) {
40461 dialCode = v.substr(1, i);
40463 if (numericChars.length == 4) {
40473 this.setValue(this.defaultDialCode);
40477 hiddenEl : function()
40479 return this.el.select('input.hidden-tel-input',true).first();
40482 // after setting val
40483 onKeyUp : function(e){
40484 this.setValue(this.getValue());
40487 onKeyPress : function(e){
40488 if(this.allowed.indexOf(String.fromCharCode(e.getCharCode())) === -1){
40495 * @class Roo.bootstrap.MoneyField
40496 * @extends Roo.bootstrap.ComboBox
40497 * Bootstrap MoneyField class
40500 * Create a new MoneyField.
40501 * @param {Object} config Configuration options
40504 Roo.bootstrap.MoneyField = function(config) {
40506 Roo.bootstrap.MoneyField.superclass.constructor.call(this, config);
40510 Roo.extend(Roo.bootstrap.MoneyField, Roo.bootstrap.ComboBox, {
40513 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
40515 allowDecimals : true,
40517 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
40519 decimalSeparator : ".",
40521 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
40523 decimalPrecision : 0,
40525 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
40527 allowNegative : true,
40529 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
40533 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
40535 minValue : Number.NEGATIVE_INFINITY,
40537 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
40539 maxValue : Number.MAX_VALUE,
40541 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
40543 minText : "The minimum value for this field is {0}",
40545 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
40547 maxText : "The maximum value for this field is {0}",
40549 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
40550 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
40552 nanText : "{0} is not a valid number",
40554 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
40558 * @cfg {String} defaults currency of the MoneyField
40559 * value should be in lkey
40561 defaultCurrency : false,
40563 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
40565 thousandsDelimiter : false,
40567 * @cfg {Number} max_length Maximum input field length allowed (defaults to Number.MAX_VALUE)
40578 getAutoCreate : function()
40580 var align = this.labelAlign || this.parentLabelAlign();
40592 cls : 'form-control roo-money-amount-input',
40593 autocomplete: 'new-password'
40596 var hiddenInput = {
40600 cls: 'hidden-number-input'
40603 if(this.max_length) {
40604 input.maxlength = this.max_length;
40608 hiddenInput.name = this.name;
40611 if (this.disabled) {
40612 input.disabled = true;
40615 var clg = 12 - this.inputlg;
40616 var cmd = 12 - this.inputmd;
40617 var csm = 12 - this.inputsm;
40618 var cxs = 12 - this.inputxs;
40622 cls : 'row roo-money-field',
40626 cls : 'roo-money-currency column col-lg-' + clg + ' col-md-' + cmd + ' col-sm-' + csm + ' col-xs-' + cxs,
40630 cls: 'roo-select2-container input-group',
40634 cls : 'form-control roo-money-currency-input',
40635 autocomplete: 'new-password',
40637 name : this.currencyName
40641 cls : 'input-group-addon',
40655 cls : 'roo-money-amount column col-lg-' + this.inputlg + ' col-md-' + this.inputmd + ' col-sm-' + this.inputsm + ' col-xs-' + this.inputxs,
40659 cls: this.hasFeedback ? 'has-feedback' : '',
40670 if (this.fieldLabel.length) {
40673 tooltip: 'This field is required'
40679 cls: 'control-label',
40685 html: this.fieldLabel
40688 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40694 if(this.indicatorpos == 'right') {
40695 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40702 if(align == 'left') {
40710 if(this.labelWidth > 12){
40711 label.style = "width: " + this.labelWidth + 'px';
40713 if(this.labelWidth < 13 && this.labelmd == 0){
40714 this.labelmd = this.labelWidth;
40716 if(this.labellg > 0){
40717 label.cls += ' col-lg-' + this.labellg;
40718 input.cls += ' col-lg-' + (12 - this.labellg);
40720 if(this.labelmd > 0){
40721 label.cls += ' col-md-' + this.labelmd;
40722 container.cls += ' col-md-' + (12 - this.labelmd);
40724 if(this.labelsm > 0){
40725 label.cls += ' col-sm-' + this.labelsm;
40726 container.cls += ' col-sm-' + (12 - this.labelsm);
40728 if(this.labelxs > 0){
40729 label.cls += ' col-xs-' + this.labelxs;
40730 container.cls += ' col-xs-' + (12 - this.labelxs);
40741 var settings = this;
40743 ['xs','sm','md','lg'].map(function(size){
40744 if (settings[size]) {
40745 cfg.cls += ' col-' + size + '-' + settings[size];
40752 initEvents : function()
40754 this.indicator = this.indicatorEl();
40756 this.initCurrencyEvent();
40758 this.initNumberEvent();
40761 initCurrencyEvent : function()
40764 throw "can not find store for combo";
40767 this.store = Roo.factory(this.store, Roo.data);
40768 this.store.parent = this;
40772 this.triggerEl = this.el.select('.input-group-addon', true).first();
40774 this.triggerEl.on("click", this.onTriggerClick, this, { preventDefault : true });
40779 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40780 _this.list.setWidth(lw);
40783 this.list.on('mouseover', this.onViewOver, this);
40784 this.list.on('mousemove', this.onViewMove, this);
40785 this.list.on('scroll', this.onViewScroll, this);
40788 this.tpl = '<li><a href="#">{' + this.currencyField + '}</a></li>';
40791 this.view = new Roo.View(this.list, this.tpl, {
40792 singleSelect:true, store: this.store, selectedClass: this.selectedClass
40795 this.view.on('click', this.onViewClick, this);
40797 this.store.on('beforeload', this.onBeforeLoad, this);
40798 this.store.on('load', this.onLoad, this);
40799 this.store.on('loadexception', this.onLoadException, this);
40801 this.keyNav = new Roo.KeyNav(this.currencyEl(), {
40802 "up" : function(e){
40803 this.inKeyMode = true;
40807 "down" : function(e){
40808 if(!this.isExpanded()){
40809 this.onTriggerClick();
40811 this.inKeyMode = true;
40816 "enter" : function(e){
40819 if(this.fireEvent("specialkey", this, e)){
40820 this.onViewClick(false);
40826 "esc" : function(e){
40830 "tab" : function(e){
40833 if(this.fireEvent("specialkey", this, e)){
40834 this.onViewClick(false);
40842 doRelay : function(foo, bar, hname){
40843 if(hname == 'down' || this.scope.isExpanded()){
40844 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
40852 this.currencyEl().on("click", this.onTriggerClick, this, { preventDefault : true });
40856 initNumberEvent : function(e)
40858 this.inputEl().on("keydown" , this.fireKey, this);
40859 this.inputEl().on("focus", this.onFocus, this);
40860 this.inputEl().on("blur", this.onBlur, this);
40862 this.inputEl().relayEvent('keyup', this);
40864 if(this.indicator){
40865 this.indicator.addClass('invisible');
40868 this.originalValue = this.getValue();
40870 if(this.validationEvent == 'keyup'){
40871 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
40872 this.inputEl().on('keyup', this.filterValidation, this);
40874 else if(this.validationEvent !== false){
40875 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
40878 if(this.selectOnFocus){
40879 this.on("focus", this.preFocus, this);
40882 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
40883 this.inputEl().on("keypress", this.filterKeys, this);
40885 this.inputEl().relayEvent('keypress', this);
40888 var allowed = "0123456789";
40890 if(this.allowDecimals){
40891 allowed += this.decimalSeparator;
40894 if(this.allowNegative){
40898 if(this.thousandsDelimiter) {
40902 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
40904 var keyPress = function(e){
40906 var k = e.getKey();
40908 var c = e.getCharCode();
40911 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
40912 allowed.indexOf(String.fromCharCode(c)) === -1
40918 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
40922 if(allowed.indexOf(String.fromCharCode(c)) === -1){
40927 this.inputEl().on("keypress", keyPress, this);
40931 onTriggerClick : function(e)
40938 this.loadNext = false;
40940 if(this.isExpanded()){
40945 this.hasFocus = true;
40947 if(this.triggerAction == 'all') {
40948 this.doQuery(this.allQuery, true);
40952 this.doQuery(this.getRawValue());
40955 getCurrency : function()
40957 var v = this.currencyEl().getValue();
40962 restrictHeight : function()
40964 this.list.alignTo(this.currencyEl(), this.listAlign);
40965 this.list.alignTo(this.currencyEl(), this.listAlign);
40968 onViewClick : function(view, doFocus, el, e)
40970 var index = this.view.getSelectedIndexes()[0];
40972 var r = this.store.getAt(index);
40975 this.onSelect(r, index);
40979 onSelect : function(record, index){
40981 if(this.fireEvent('beforeselect', this, record, index) !== false){
40983 this.setFromCurrencyData(index > -1 ? record.data : false);
40987 this.fireEvent('select', this, record, index);
40991 setFromCurrencyData : function(o)
40995 this.lastCurrency = o;
40997 if (this.currencyField) {
40998 currency = !o || typeof(o[this.currencyField]) == 'undefined' ? '' : o[this.currencyField];
41000 Roo.log('no currencyField value set for '+ (this.name ? this.name : this.id));
41003 this.lastSelectionText = currency;
41005 //setting default currency
41006 if(o[this.currencyField] * 1 == 0 && this.defaultCurrency) {
41007 this.setCurrency(this.defaultCurrency);
41011 this.setCurrency(currency);
41014 setFromData : function(o)
41018 c[this.currencyField] = !o || typeof(o[this.currencyName]) == 'undefined' ? '' : o[this.currencyName];
41020 this.setFromCurrencyData(c);
41025 value = !o || typeof(o[this.name]) == 'undefined' ? '' : o[this.name];
41027 Roo.log('no value set for '+ (this.name ? this.name : this.id));
41030 this.setValue(value);
41034 setCurrency : function(v)
41036 this.currencyValue = v;
41039 this.currencyEl().dom.value = (v === null || v === undefined ? '' : v);
41044 setValue : function(v)
41046 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
41052 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
41054 this.inputEl().dom.value = (v == '') ? '' :
41055 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
41057 if(!this.allowZero && v === '0') {
41058 this.hiddenEl().dom.value = '';
41059 this.inputEl().dom.value = '';
41066 getRawValue : function()
41068 var v = this.inputEl().getValue();
41073 getValue : function()
41075 return this.fixPrecision(this.parseValue(this.getRawValue()));
41078 parseValue : function(value)
41080 if(this.thousandsDelimiter) {
41082 r = new RegExp(",", "g");
41083 value = value.replace(r, "");
41086 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
41087 return isNaN(value) ? '' : value;
41091 fixPrecision : function(value)
41093 if(this.thousandsDelimiter) {
41095 r = new RegExp(",", "g");
41096 value = value.replace(r, "");
41099 var nan = isNaN(value);
41101 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
41102 return nan ? '' : value;
41104 return parseFloat(value).toFixed(this.decimalPrecision);
41107 decimalPrecisionFcn : function(v)
41109 return Math.floor(v);
41112 validateValue : function(value)
41114 if(!Roo.bootstrap.MoneyField.superclass.validateValue.call(this, value)){
41118 var num = this.parseValue(value);
41121 this.markInvalid(String.format(this.nanText, value));
41125 if(num < this.minValue){
41126 this.markInvalid(String.format(this.minText, this.minValue));
41130 if(num > this.maxValue){
41131 this.markInvalid(String.format(this.maxText, this.maxValue));
41138 validate : function()
41140 if(this.disabled || this.allowBlank){
41145 var currency = this.getCurrency();
41147 if(this.validateValue(this.getRawValue()) && currency.length){
41152 this.markInvalid();
41156 getName: function()
41161 beforeBlur : function()
41167 var v = this.parseValue(this.getRawValue());
41174 onBlur : function()
41178 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
41179 //this.el.removeClass(this.focusClass);
41182 this.hasFocus = false;
41184 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
41188 var v = this.getValue();
41190 if(String(v) !== String(this.startValue)){
41191 this.fireEvent('change', this, v, this.startValue);
41194 this.fireEvent("blur", this);
41197 inputEl : function()
41199 return this.el.select('.roo-money-amount-input', true).first();
41202 currencyEl : function()
41204 return this.el.select('.roo-money-currency-input', true).first();
41207 hiddenEl : function()
41209 return this.el.select('input.hidden-number-input',true).first();