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 !== '') {
4141 cn[0].cn.unshift({ // changed from push ?? BS4 needs it at the start? - does this break or exsiting?
4143 href: this.brand_href ? this.brand_href : '#',
4144 cls: 'navbar-brand',
4152 cfg.cls += ' main-nav';
4160 getHeaderChildContainer : function()
4162 if (this.srButton && this.el.select('.navbar-header').getCount()) {
4163 return this.el.select('.navbar-header',true).first();
4166 return this.getChildContainer();
4170 initEvents : function()
4172 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
4174 if (this.autohide) {
4179 Roo.get(document).on('scroll',function(e) {
4180 var ns = Roo.get(document).getScroll().top;
4181 var os = prevScroll;
4185 ft.removeClass('slideDown');
4186 ft.addClass('slideUp');
4189 ft.removeClass('slideUp');
4190 ft.addClass('slideDown');
4211 * @class Roo.bootstrap.NavSidebar
4212 * @extends Roo.bootstrap.Navbar
4213 * Bootstrap Sidebar class
4216 * Create a new Sidebar
4217 * @param {Object} config The config object
4221 Roo.bootstrap.NavSidebar = function(config){
4222 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
4225 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
4227 sidebar : true, // used by Navbar Item and NavbarGroup at present...
4229 getAutoCreate : function(){
4234 cls: 'sidebar sidebar-nav'
4256 * @class Roo.bootstrap.NavGroup
4257 * @extends Roo.bootstrap.Component
4258 * Bootstrap NavGroup class
4259 * @cfg {String} align (left|right)
4260 * @cfg {Boolean} inverse
4261 * @cfg {String} type (nav|pills|tab) default nav
4262 * @cfg {String} navId - reference Id for navbar.
4266 * Create a new nav group
4267 * @param {Object} config The config object
4270 Roo.bootstrap.NavGroup = function(config){
4271 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
4274 Roo.bootstrap.NavGroup.register(this);
4278 * Fires when the active item changes
4279 * @param {Roo.bootstrap.NavGroup} this
4280 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
4281 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
4288 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
4299 getAutoCreate : function()
4301 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
4308 if (['tabs','pills'].indexOf(this.type)!==-1) {
4309 cfg.cls += ' nav-' + this.type
4311 if (this.type!=='nav') {
4312 Roo.log('nav type must be nav/tabs/pills')
4314 cfg.cls += ' navbar-nav'
4317 if (this.parent() && this.parent().sidebar) {
4320 cls: 'dashboard-menu sidebar-menu'
4326 if (this.form === true) {
4332 if (this.align === 'right') {
4333 cfg.cls += ' navbar-right ml-md-auto';
4335 cfg.cls += ' navbar-left';
4339 if (this.align === 'right') {
4340 cfg.cls += ' navbar-right ml-md-auto';
4342 cfg.cls += ' mr-auto';
4346 cfg.cls += ' navbar-inverse';
4354 * sets the active Navigation item
4355 * @param {Roo.bootstrap.NavItem} the new current navitem
4357 setActiveItem : function(item)
4360 Roo.each(this.navItems, function(v){
4365 v.setActive(false, true);
4372 item.setActive(true, true);
4373 this.fireEvent('changed', this, item, prev);
4378 * gets the active Navigation item
4379 * @return {Roo.bootstrap.NavItem} the current navitem
4381 getActive : function()
4385 Roo.each(this.navItems, function(v){
4396 indexOfNav : function()
4400 Roo.each(this.navItems, function(v,i){
4411 * adds a Navigation item
4412 * @param {Roo.bootstrap.NavItem} the navitem to add
4414 addItem : function(cfg)
4416 var cn = new Roo.bootstrap.NavItem(cfg);
4418 cn.parentId = this.id;
4419 cn.onRender(this.el, null);
4423 * register a Navigation item
4424 * @param {Roo.bootstrap.NavItem} the navitem to add
4426 register : function(item)
4428 this.navItems.push( item);
4429 item.navId = this.navId;
4434 * clear all the Navigation item
4437 clearAll : function()
4440 this.el.dom.innerHTML = '';
4443 getNavItem: function(tabId)
4446 Roo.each(this.navItems, function(e) {
4447 if (e.tabId == tabId) {
4457 setActiveNext : function()
4459 var i = this.indexOfNav(this.getActive());
4460 if (i > this.navItems.length) {
4463 this.setActiveItem(this.navItems[i+1]);
4465 setActivePrev : function()
4467 var i = this.indexOfNav(this.getActive());
4471 this.setActiveItem(this.navItems[i-1]);
4473 clearWasActive : function(except) {
4474 Roo.each(this.navItems, function(e) {
4475 if (e.tabId != except.tabId && e.was_active) {
4476 e.was_active = false;
4483 getWasActive : function ()
4486 Roo.each(this.navItems, function(e) {
4501 Roo.apply(Roo.bootstrap.NavGroup, {
4505 * register a Navigation Group
4506 * @param {Roo.bootstrap.NavGroup} the navgroup to add
4508 register : function(navgrp)
4510 this.groups[navgrp.navId] = navgrp;
4514 * fetch a Navigation Group based on the navigation ID
4515 * @param {string} the navgroup to add
4516 * @returns {Roo.bootstrap.NavGroup} the navgroup
4518 get: function(navId) {
4519 if (typeof(this.groups[navId]) == 'undefined') {
4521 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
4523 return this.groups[navId] ;
4538 * @class Roo.bootstrap.NavItem
4539 * @extends Roo.bootstrap.Component
4540 * Bootstrap Navbar.NavItem class
4541 * @cfg {String} href link to
4542 * @cfg {String} html content of button
4543 * @cfg {String} badge text inside badge
4544 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
4545 * @cfg {String} glyphicon DEPRICATED - use fa
4546 * @cfg {String} icon DEPRICATED - use fa
4547 * @cfg {String} fa - Fontawsome icon name (can add stuff to it like fa-2x)
4548 * @cfg {Boolean} active Is item active
4549 * @cfg {Boolean} disabled Is item disabled
4551 * @cfg {Boolean} preventDefault (true | false) default false
4552 * @cfg {String} tabId the tab that this item activates.
4553 * @cfg {String} tagtype (a|span) render as a href or span?
4554 * @cfg {Boolean} animateRef (true|false) link to element default false
4557 * Create a new Navbar Item
4558 * @param {Object} config The config object
4560 Roo.bootstrap.NavItem = function(config){
4561 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
4566 * The raw click event for the entire grid.
4567 * @param {Roo.EventObject} e
4572 * Fires when the active item active state changes
4573 * @param {Roo.bootstrap.NavItem} this
4574 * @param {boolean} state the new state
4580 * Fires when scroll to element
4581 * @param {Roo.bootstrap.NavItem} this
4582 * @param {Object} options
4583 * @param {Roo.EventObject} e
4591 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
4600 preventDefault : false,
4607 getAutoCreate : function(){
4616 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
4618 if (this.disabled) {
4619 cfg.cls += ' disabled';
4622 if (this.href || this.html || this.glyphicon || this.icon || this.fa) {
4626 href : this.href || "#",
4627 html: this.html || ''
4630 if (this.tagtype == 'a') {
4631 cfg.cn[0].cls = 'nav-link';
4634 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
4637 cfg.cn[0].html = '<i class="fa fas fa-'+this.fa+'"></i> <span>' + cfg.cn[0].html + '</span>'
4639 if(this.glyphicon) {
4640 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
4645 cfg.cn[0].html += " <span class='caret'></span>";
4649 if (this.badge !== '') {
4651 cfg.cn[0].html += ' <span class="badge badge-secondary">' + this.badge + '</span>';
4659 initEvents: function()
4661 if (typeof (this.menu) != 'undefined') {
4662 this.menu.parentType = this.xtype;
4663 this.menu.triggerEl = this.el;
4664 this.menu = this.addxtype(Roo.apply({}, this.menu));
4667 this.el.select('a',true).on('click', this.onClick, this);
4669 if(this.tagtype == 'span'){
4670 this.el.select('span',true).on('click', this.onClick, this);
4673 // at this point parent should be available..
4674 this.parent().register(this);
4677 onClick : function(e)
4679 if (e.getTarget('.dropdown-menu-item')) {
4680 // did you click on a menu itemm.... - then don't trigger onclick..
4685 this.preventDefault ||
4688 Roo.log("NavItem - prevent Default?");
4692 if (this.disabled) {
4696 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4697 if (tg && tg.transition) {
4698 Roo.log("waiting for the transitionend");
4704 //Roo.log("fire event clicked");
4705 if(this.fireEvent('click', this, e) === false){
4709 if(this.tagtype == 'span'){
4713 //Roo.log(this.href);
4714 var ael = this.el.select('a',true).first();
4717 if(ael && this.animateRef && this.href.indexOf('#') > -1){
4718 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4719 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4720 return; // ignore... - it's a 'hash' to another page.
4722 Roo.log("NavItem - prevent Default?");
4724 this.scrollToElement(e);
4728 var p = this.parent();
4730 if (['tabs','pills'].indexOf(p.type)!==-1) {
4731 if (typeof(p.setActiveItem) !== 'undefined') {
4732 p.setActiveItem(this);
4736 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4737 if (p.parentType == 'NavHeaderbar' && !this.menu) {
4738 // remove the collapsed menu expand...
4739 p.parent().el.select('.navbar-collapse',true).removeClass('in');
4743 isActive: function () {
4746 setActive : function(state, fire, is_was_active)
4748 if (this.active && !state && this.navId) {
4749 this.was_active = true;
4750 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4752 nv.clearWasActive(this);
4756 this.active = state;
4759 this.el.removeClass('active');
4760 } else if (!this.el.hasClass('active')) {
4761 this.el.addClass('active');
4764 this.fireEvent('changed', this, state);
4767 // show a panel if it's registered and related..
4769 if (!this.navId || !this.tabId || !state || is_was_active) {
4773 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4777 var pan = tg.getPanelByName(this.tabId);
4781 // if we can not flip to new panel - go back to old nav highlight..
4782 if (false == tg.showPanel(pan)) {
4783 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4785 var onav = nv.getWasActive();
4787 onav.setActive(true, false, true);
4796 // this should not be here...
4797 setDisabled : function(state)
4799 this.disabled = state;
4801 this.el.removeClass('disabled');
4802 } else if (!this.el.hasClass('disabled')) {
4803 this.el.addClass('disabled');
4809 * Fetch the element to display the tooltip on.
4810 * @return {Roo.Element} defaults to this.el
4812 tooltipEl : function()
4814 return this.el.select('' + this.tagtype + '', true).first();
4817 scrollToElement : function(e)
4819 var c = document.body;
4822 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
4824 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
4825 c = document.documentElement;
4828 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4834 var o = target.calcOffsetsTo(c);
4841 this.fireEvent('scrollto', this, options, e);
4843 Roo.get(c).scrollTo('top', options.value, true);
4856 * <span> icon </span>
4857 * <span> text </span>
4858 * <span>badge </span>
4862 * @class Roo.bootstrap.NavSidebarItem
4863 * @extends Roo.bootstrap.NavItem
4864 * Bootstrap Navbar.NavSidebarItem class
4865 * {String} badgeWeight (default|primary|success|info|warning|danger)the extra classes for the badge
4866 * {Boolean} open is the menu open
4867 * {Boolean} buttonView use button as the tigger el rather that a (default false)
4868 * {String} buttonWeight (default|primary|success|info|warning|danger)the extra classes for the button
4869 * {String} buttonSize (sm|md|lg)the extra classes for the button
4870 * {Boolean} showArrow show arrow next to the text (default true)
4872 * Create a new Navbar Button
4873 * @param {Object} config The config object
4875 Roo.bootstrap.NavSidebarItem = function(config){
4876 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4881 * The raw click event for the entire grid.
4882 * @param {Roo.EventObject} e
4887 * Fires when the active item active state changes
4888 * @param {Roo.bootstrap.NavSidebarItem} this
4889 * @param {boolean} state the new state
4897 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
4899 badgeWeight : 'default',
4905 buttonWeight : 'default',
4911 getAutoCreate : function(){
4916 href : this.href || '#',
4922 if(this.buttonView){
4925 href : this.href || '#',
4926 cls: 'btn btn-' + this.buttonWeight + ' btn-' + this.buttonSize + 'roo-button-dropdown-toggle',
4939 cfg.cls += ' active';
4942 if (this.disabled) {
4943 cfg.cls += ' disabled';
4946 cfg.cls += ' open x-open';
4949 if (this.glyphicon || this.icon) {
4950 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
4951 a.cn.push({ tag : 'i', cls : c }) ;
4954 if(!this.buttonView){
4957 html : this.html || ''
4964 if (this.badge !== '') {
4965 a.cn.push({ tag: 'span', cls : 'badge pull-right badge-' + this.badgeWeight, html: this.badge });
4971 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4974 a.cls += ' dropdown-toggle treeview' ;
4980 initEvents : function()
4982 if (typeof (this.menu) != 'undefined') {
4983 this.menu.parentType = this.xtype;
4984 this.menu.triggerEl = this.el;
4985 this.menu = this.addxtype(Roo.apply({}, this.menu));
4988 this.el.on('click', this.onClick, this);
4990 if(this.badge !== ''){
4991 this.badgeEl = this.el.select('.badge', true).first().setVisibilityMode(Roo.Element.DISPLAY);
4996 onClick : function(e)
5003 if(this.preventDefault){
5007 this.fireEvent('click', this);
5010 disable : function()
5012 this.setDisabled(true);
5017 this.setDisabled(false);
5020 setDisabled : function(state)
5022 if(this.disabled == state){
5026 this.disabled = state;
5029 this.el.addClass('disabled');
5033 this.el.removeClass('disabled');
5038 setActive : function(state)
5040 if(this.active == state){
5044 this.active = state;
5047 this.el.addClass('active');
5051 this.el.removeClass('active');
5056 isActive: function ()
5061 setBadge : function(str)
5067 this.badgeEl.dom.innerHTML = str;
5084 * @class Roo.bootstrap.Row
5085 * @extends Roo.bootstrap.Component
5086 * Bootstrap Row class (contains columns...)
5090 * @param {Object} config The config object
5093 Roo.bootstrap.Row = function(config){
5094 Roo.bootstrap.Row.superclass.constructor.call(this, config);
5097 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
5099 getAutoCreate : function(){
5118 * @class Roo.bootstrap.Element
5119 * @extends Roo.bootstrap.Component
5120 * Bootstrap Element class
5121 * @cfg {String} html contents of the element
5122 * @cfg {String} tag tag of the element
5123 * @cfg {String} cls class of the element
5124 * @cfg {Boolean} preventDefault (true|false) default false
5125 * @cfg {Boolean} clickable (true|false) default false
5128 * Create a new Element
5129 * @param {Object} config The config object
5132 Roo.bootstrap.Element = function(config){
5133 Roo.bootstrap.Element.superclass.constructor.call(this, config);
5139 * When a element is chick
5140 * @param {Roo.bootstrap.Element} this
5141 * @param {Roo.EventObject} e
5147 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
5152 preventDefault: false,
5155 getAutoCreate : function(){
5159 // cls: this.cls, double assign in parent class Component.js :: onRender
5166 initEvents: function()
5168 Roo.bootstrap.Element.superclass.initEvents.call(this);
5171 this.el.on('click', this.onClick, this);
5176 onClick : function(e)
5178 if(this.preventDefault){
5182 this.fireEvent('click', this, e);
5185 getValue : function()
5187 return this.el.dom.innerHTML;
5190 setValue : function(value)
5192 this.el.dom.innerHTML = value;
5207 * @class Roo.bootstrap.Pagination
5208 * @extends Roo.bootstrap.Component
5209 * Bootstrap Pagination class
5210 * @cfg {String} size xs | sm | md | lg
5211 * @cfg {Boolean} inverse false | true
5214 * Create a new Pagination
5215 * @param {Object} config The config object
5218 Roo.bootstrap.Pagination = function(config){
5219 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
5222 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
5228 getAutoCreate : function(){
5234 cfg.cls += ' inverse';
5240 cfg.cls += " " + this.cls;
5258 * @class Roo.bootstrap.PaginationItem
5259 * @extends Roo.bootstrap.Component
5260 * Bootstrap PaginationItem class
5261 * @cfg {String} html text
5262 * @cfg {String} href the link
5263 * @cfg {Boolean} preventDefault (true | false) default true
5264 * @cfg {Boolean} active (true | false) default false
5265 * @cfg {Boolean} disabled default false
5269 * Create a new PaginationItem
5270 * @param {Object} config The config object
5274 Roo.bootstrap.PaginationItem = function(config){
5275 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
5280 * The raw click event for the entire grid.
5281 * @param {Roo.EventObject} e
5287 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
5291 preventDefault: true,
5296 getAutoCreate : function(){
5302 href : this.href ? this.href : '#',
5303 html : this.html ? this.html : ''
5313 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
5317 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
5323 initEvents: function() {
5325 this.el.on('click', this.onClick, this);
5328 onClick : function(e)
5330 Roo.log('PaginationItem on click ');
5331 if(this.preventDefault){
5339 this.fireEvent('click', this, e);
5355 * @class Roo.bootstrap.Slider
5356 * @extends Roo.bootstrap.Component
5357 * Bootstrap Slider class
5360 * Create a new Slider
5361 * @param {Object} config The config object
5364 Roo.bootstrap.Slider = function(config){
5365 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
5368 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
5370 getAutoCreate : function(){
5374 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
5378 cls: 'ui-slider-handle ui-state-default ui-corner-all'
5390 * Ext JS Library 1.1.1
5391 * Copyright(c) 2006-2007, Ext JS, LLC.
5393 * Originally Released Under LGPL - original licence link has changed is not relivant.
5396 * <script type="text/javascript">
5401 * @class Roo.grid.ColumnModel
5402 * @extends Roo.util.Observable
5403 * This is the default implementation of a ColumnModel used by the Grid. It defines
5404 * the columns in the grid.
5407 var colModel = new Roo.grid.ColumnModel([
5408 {header: "Ticker", width: 60, sortable: true, locked: true},
5409 {header: "Company Name", width: 150, sortable: true},
5410 {header: "Market Cap.", width: 100, sortable: true},
5411 {header: "$ Sales", width: 100, sortable: true, renderer: money},
5412 {header: "Employees", width: 100, sortable: true, resizable: false}
5417 * The config options listed for this class are options which may appear in each
5418 * individual column definition.
5419 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
5421 * @param {Object} config An Array of column config objects. See this class's
5422 * config objects for details.
5424 Roo.grid.ColumnModel = function(config){
5426 * The config passed into the constructor
5428 this.config = config;
5431 // if no id, create one
5432 // if the column does not have a dataIndex mapping,
5433 // map it to the order it is in the config
5434 for(var i = 0, len = config.length; i < len; i++){
5436 if(typeof c.dataIndex == "undefined"){
5439 if(typeof c.renderer == "string"){
5440 c.renderer = Roo.util.Format[c.renderer];
5442 if(typeof c.id == "undefined"){
5445 if(c.editor && c.editor.xtype){
5446 c.editor = Roo.factory(c.editor, Roo.grid);
5448 if(c.editor && c.editor.isFormField){
5449 c.editor = new Roo.grid.GridEditor(c.editor);
5451 this.lookup[c.id] = c;
5455 * The width of columns which have no width specified (defaults to 100)
5458 this.defaultWidth = 100;
5461 * Default sortable of columns which have no sortable specified (defaults to false)
5464 this.defaultSortable = false;
5468 * @event widthchange
5469 * Fires when the width of a column changes.
5470 * @param {ColumnModel} this
5471 * @param {Number} columnIndex The column index
5472 * @param {Number} newWidth The new width
5474 "widthchange": true,
5476 * @event headerchange
5477 * Fires when the text of a header changes.
5478 * @param {ColumnModel} this
5479 * @param {Number} columnIndex The column index
5480 * @param {Number} newText The new header text
5482 "headerchange": true,
5484 * @event hiddenchange
5485 * Fires when a column is hidden or "unhidden".
5486 * @param {ColumnModel} this
5487 * @param {Number} columnIndex The column index
5488 * @param {Boolean} hidden true if hidden, false otherwise
5490 "hiddenchange": true,
5492 * @event columnmoved
5493 * Fires when a column is moved.
5494 * @param {ColumnModel} this
5495 * @param {Number} oldIndex
5496 * @param {Number} newIndex
5498 "columnmoved" : true,
5500 * @event columlockchange
5501 * Fires when a column's locked state is changed
5502 * @param {ColumnModel} this
5503 * @param {Number} colIndex
5504 * @param {Boolean} locked true if locked
5506 "columnlockchange" : true
5508 Roo.grid.ColumnModel.superclass.constructor.call(this);
5510 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
5512 * @cfg {String} header The header text to display in the Grid view.
5515 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
5516 * {@link Roo.data.Record} definition from which to draw the column's value. If not
5517 * specified, the column's index is used as an index into the Record's data Array.
5520 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
5521 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
5524 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
5525 * Defaults to the value of the {@link #defaultSortable} property.
5526 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
5529 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
5532 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
5535 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
5538 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
5541 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
5542 * given the cell's data value. See {@link #setRenderer}. If not specified, the
5543 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
5544 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
5547 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
5550 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
5553 * @cfg {String} valign (Optional) Set the CSS vertical-align property of the column (eg. middle, top, bottom etc). Defaults to undefined.
5556 * @cfg {String} cursor (Optional)
5559 * @cfg {String} tooltip (Optional)
5562 * @cfg {Number} xs (Optional)
5565 * @cfg {Number} sm (Optional)
5568 * @cfg {Number} md (Optional)
5571 * @cfg {Number} lg (Optional)
5574 * Returns the id of the column at the specified index.
5575 * @param {Number} index The column index
5576 * @return {String} the id
5578 getColumnId : function(index){
5579 return this.config[index].id;
5583 * Returns the column for a specified id.
5584 * @param {String} id The column id
5585 * @return {Object} the column
5587 getColumnById : function(id){
5588 return this.lookup[id];
5593 * Returns the column for a specified dataIndex.
5594 * @param {String} dataIndex The column dataIndex
5595 * @return {Object|Boolean} the column or false if not found
5597 getColumnByDataIndex: function(dataIndex){
5598 var index = this.findColumnIndex(dataIndex);
5599 return index > -1 ? this.config[index] : false;
5603 * Returns the index for a specified column id.
5604 * @param {String} id The column id
5605 * @return {Number} the index, or -1 if not found
5607 getIndexById : function(id){
5608 for(var i = 0, len = this.config.length; i < len; i++){
5609 if(this.config[i].id == id){
5617 * Returns the index for a specified column dataIndex.
5618 * @param {String} dataIndex The column dataIndex
5619 * @return {Number} the index, or -1 if not found
5622 findColumnIndex : function(dataIndex){
5623 for(var i = 0, len = this.config.length; i < len; i++){
5624 if(this.config[i].dataIndex == dataIndex){
5632 moveColumn : function(oldIndex, newIndex){
5633 var c = this.config[oldIndex];
5634 this.config.splice(oldIndex, 1);
5635 this.config.splice(newIndex, 0, c);
5636 this.dataMap = null;
5637 this.fireEvent("columnmoved", this, oldIndex, newIndex);
5640 isLocked : function(colIndex){
5641 return this.config[colIndex].locked === true;
5644 setLocked : function(colIndex, value, suppressEvent){
5645 if(this.isLocked(colIndex) == value){
5648 this.config[colIndex].locked = value;
5650 this.fireEvent("columnlockchange", this, colIndex, value);
5654 getTotalLockedWidth : function(){
5656 for(var i = 0; i < this.config.length; i++){
5657 if(this.isLocked(i) && !this.isHidden(i)){
5658 this.totalWidth += this.getColumnWidth(i);
5664 getLockedCount : function(){
5665 for(var i = 0, len = this.config.length; i < len; i++){
5666 if(!this.isLocked(i)){
5671 return this.config.length;
5675 * Returns the number of columns.
5678 getColumnCount : function(visibleOnly){
5679 if(visibleOnly === true){
5681 for(var i = 0, len = this.config.length; i < len; i++){
5682 if(!this.isHidden(i)){
5688 return this.config.length;
5692 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
5693 * @param {Function} fn
5694 * @param {Object} scope (optional)
5695 * @return {Array} result
5697 getColumnsBy : function(fn, scope){
5699 for(var i = 0, len = this.config.length; i < len; i++){
5700 var c = this.config[i];
5701 if(fn.call(scope||this, c, i) === true){
5709 * Returns true if the specified column is sortable.
5710 * @param {Number} col The column index
5713 isSortable : function(col){
5714 if(typeof this.config[col].sortable == "undefined"){
5715 return this.defaultSortable;
5717 return this.config[col].sortable;
5721 * Returns the rendering (formatting) function defined for the column.
5722 * @param {Number} col The column index.
5723 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
5725 getRenderer : function(col){
5726 if(!this.config[col].renderer){
5727 return Roo.grid.ColumnModel.defaultRenderer;
5729 return this.config[col].renderer;
5733 * Sets the rendering (formatting) function for a column.
5734 * @param {Number} col The column index
5735 * @param {Function} fn The function to use to process the cell's raw data
5736 * to return HTML markup for the grid view. The render function is called with
5737 * the following parameters:<ul>
5738 * <li>Data value.</li>
5739 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
5740 * <li>css A CSS style string to apply to the table cell.</li>
5741 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
5742 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
5743 * <li>Row index</li>
5744 * <li>Column index</li>
5745 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
5747 setRenderer : function(col, fn){
5748 this.config[col].renderer = fn;
5752 * Returns the width for the specified column.
5753 * @param {Number} col The column index
5756 getColumnWidth : function(col){
5757 return this.config[col].width * 1 || this.defaultWidth;
5761 * Sets the width for a column.
5762 * @param {Number} col The column index
5763 * @param {Number} width The new width
5765 setColumnWidth : function(col, width, suppressEvent){
5766 this.config[col].width = width;
5767 this.totalWidth = null;
5769 this.fireEvent("widthchange", this, col, width);
5774 * Returns the total width of all columns.
5775 * @param {Boolean} includeHidden True to include hidden column widths
5778 getTotalWidth : function(includeHidden){
5779 if(!this.totalWidth){
5780 this.totalWidth = 0;
5781 for(var i = 0, len = this.config.length; i < len; i++){
5782 if(includeHidden || !this.isHidden(i)){
5783 this.totalWidth += this.getColumnWidth(i);
5787 return this.totalWidth;
5791 * Returns the header for the specified column.
5792 * @param {Number} col The column index
5795 getColumnHeader : function(col){
5796 return this.config[col].header;
5800 * Sets the header for a column.
5801 * @param {Number} col The column index
5802 * @param {String} header The new header
5804 setColumnHeader : function(col, header){
5805 this.config[col].header = header;
5806 this.fireEvent("headerchange", this, col, header);
5810 * Returns the tooltip for the specified column.
5811 * @param {Number} col The column index
5814 getColumnTooltip : function(col){
5815 return this.config[col].tooltip;
5818 * Sets the tooltip for a column.
5819 * @param {Number} col The column index
5820 * @param {String} tooltip The new tooltip
5822 setColumnTooltip : function(col, tooltip){
5823 this.config[col].tooltip = tooltip;
5827 * Returns the dataIndex for the specified column.
5828 * @param {Number} col The column index
5831 getDataIndex : function(col){
5832 return this.config[col].dataIndex;
5836 * Sets the dataIndex for a column.
5837 * @param {Number} col The column index
5838 * @param {Number} dataIndex The new dataIndex
5840 setDataIndex : function(col, dataIndex){
5841 this.config[col].dataIndex = dataIndex;
5847 * Returns true if the cell is editable.
5848 * @param {Number} colIndex The column index
5849 * @param {Number} rowIndex The row index - this is nto actually used..?
5852 isCellEditable : function(colIndex, rowIndex){
5853 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
5857 * Returns the editor defined for the cell/column.
5858 * return false or null to disable editing.
5859 * @param {Number} colIndex The column index
5860 * @param {Number} rowIndex The row index
5863 getCellEditor : function(colIndex, rowIndex){
5864 return this.config[colIndex].editor;
5868 * Sets if a column is editable.
5869 * @param {Number} col The column index
5870 * @param {Boolean} editable True if the column is editable
5872 setEditable : function(col, editable){
5873 this.config[col].editable = editable;
5878 * Returns true if the column is hidden.
5879 * @param {Number} colIndex The column index
5882 isHidden : function(colIndex){
5883 return this.config[colIndex].hidden;
5888 * Returns true if the column width cannot be changed
5890 isFixed : function(colIndex){
5891 return this.config[colIndex].fixed;
5895 * Returns true if the column can be resized
5898 isResizable : function(colIndex){
5899 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
5902 * Sets if a column is hidden.
5903 * @param {Number} colIndex The column index
5904 * @param {Boolean} hidden True if the column is hidden
5906 setHidden : function(colIndex, hidden){
5907 this.config[colIndex].hidden = hidden;
5908 this.totalWidth = null;
5909 this.fireEvent("hiddenchange", this, colIndex, hidden);
5913 * Sets the editor for a column.
5914 * @param {Number} col The column index
5915 * @param {Object} editor The editor object
5917 setEditor : function(col, editor){
5918 this.config[col].editor = editor;
5922 Roo.grid.ColumnModel.defaultRenderer = function(value)
5924 if(typeof value == "object") {
5927 if(typeof value == "string" && value.length < 1){
5931 return String.format("{0}", value);
5934 // Alias for backwards compatibility
5935 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
5938 * Ext JS Library 1.1.1
5939 * Copyright(c) 2006-2007, Ext JS, LLC.
5941 * Originally Released Under LGPL - original licence link has changed is not relivant.
5944 * <script type="text/javascript">
5948 * @class Roo.LoadMask
5949 * A simple utility class for generically masking elements while loading data. If the element being masked has
5950 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
5951 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
5952 * element's UpdateManager load indicator and will be destroyed after the initial load.
5954 * Create a new LoadMask
5955 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
5956 * @param {Object} config The config object
5958 Roo.LoadMask = function(el, config){
5959 this.el = Roo.get(el);
5960 Roo.apply(this, config);
5962 this.store.on('beforeload', this.onBeforeLoad, this);
5963 this.store.on('load', this.onLoad, this);
5964 this.store.on('loadexception', this.onLoadException, this);
5965 this.removeMask = false;
5967 var um = this.el.getUpdateManager();
5968 um.showLoadIndicator = false; // disable the default indicator
5969 um.on('beforeupdate', this.onBeforeLoad, this);
5970 um.on('update', this.onLoad, this);
5971 um.on('failure', this.onLoad, this);
5972 this.removeMask = true;
5976 Roo.LoadMask.prototype = {
5978 * @cfg {Boolean} removeMask
5979 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
5980 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
5984 * The text to display in a centered loading message box (defaults to 'Loading...')
5988 * @cfg {String} msgCls
5989 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
5991 msgCls : 'x-mask-loading',
5994 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
6000 * Disables the mask to prevent it from being displayed
6002 disable : function(){
6003 this.disabled = true;
6007 * Enables the mask so that it can be displayed
6009 enable : function(){
6010 this.disabled = false;
6013 onLoadException : function()
6017 if (typeof(arguments[3]) != 'undefined') {
6018 Roo.MessageBox.alert("Error loading",arguments[3]);
6022 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
6023 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
6030 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
6035 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
6039 onBeforeLoad : function(){
6041 (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
6046 destroy : function(){
6048 this.store.un('beforeload', this.onBeforeLoad, this);
6049 this.store.un('load', this.onLoad, this);
6050 this.store.un('loadexception', this.onLoadException, this);
6052 var um = this.el.getUpdateManager();
6053 um.un('beforeupdate', this.onBeforeLoad, this);
6054 um.un('update', this.onLoad, this);
6055 um.un('failure', this.onLoad, this);
6066 * @class Roo.bootstrap.Table
6067 * @extends Roo.bootstrap.Component
6068 * Bootstrap Table class
6069 * @cfg {String} cls table class
6070 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
6071 * @cfg {String} bgcolor Specifies the background color for a table
6072 * @cfg {Number} border Specifies whether the table cells should have borders or not
6073 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
6074 * @cfg {Number} cellspacing Specifies the space between cells
6075 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
6076 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
6077 * @cfg {String} sortable Specifies that the table should be sortable
6078 * @cfg {String} summary Specifies a summary of the content of a table
6079 * @cfg {Number} width Specifies the width of a table
6080 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
6082 * @cfg {boolean} striped Should the rows be alternative striped
6083 * @cfg {boolean} bordered Add borders to the table
6084 * @cfg {boolean} hover Add hover highlighting
6085 * @cfg {boolean} condensed Format condensed
6086 * @cfg {boolean} responsive Format condensed
6087 * @cfg {Boolean} loadMask (true|false) default false
6088 * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
6089 * @cfg {Boolean} headerShow (true|false) generate thead, default true
6090 * @cfg {Boolean} rowSelection (true|false) default false
6091 * @cfg {Boolean} cellSelection (true|false) default false
6092 * @cfg {Boolean} scrollBody (true|false) default false - body scrolled / fixed header
6093 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
6094 * @cfg {Boolean} lazyLoad auto load data while scrolling to the end (default false)
6095 * @cfg {Boolean} auto_hide_footer auto hide footer if only one page (default false)
6099 * Create a new Table
6100 * @param {Object} config The config object
6103 Roo.bootstrap.Table = function(config){
6104 Roo.bootstrap.Table.superclass.constructor.call(this, config);
6109 this.rowSelection = (typeof(config.rowSelection) != 'undefined') ? config.rowSelection : this.rowSelection;
6110 this.cellSelection = (typeof(config.cellSelection) != 'undefined') ? config.cellSelection : this.cellSelection;
6111 this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
6112 this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
6114 this.sm = this.sm || {xtype: 'RowSelectionModel'};
6116 this.sm.grid = this;
6117 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
6118 this.sm = this.selModel;
6119 this.sm.xmodule = this.xmodule || false;
6122 if (this.cm && typeof(this.cm.config) == 'undefined') {
6123 this.colModel = new Roo.grid.ColumnModel(this.cm);
6124 this.cm = this.colModel;
6125 this.cm.xmodule = this.xmodule || false;
6128 this.store= Roo.factory(this.store, Roo.data);
6129 this.ds = this.store;
6130 this.ds.xmodule = this.xmodule || false;
6133 if (this.footer && this.store) {
6134 this.footer.dataSource = this.ds;
6135 this.footer = Roo.factory(this.footer);
6142 * Fires when a cell is clicked
6143 * @param {Roo.bootstrap.Table} this
6144 * @param {Roo.Element} el
6145 * @param {Number} rowIndex
6146 * @param {Number} columnIndex
6147 * @param {Roo.EventObject} e
6151 * @event celldblclick
6152 * Fires when a cell is double clicked
6153 * @param {Roo.bootstrap.Table} this
6154 * @param {Roo.Element} el
6155 * @param {Number} rowIndex
6156 * @param {Number} columnIndex
6157 * @param {Roo.EventObject} e
6159 "celldblclick" : true,
6162 * Fires when a row is clicked
6163 * @param {Roo.bootstrap.Table} this
6164 * @param {Roo.Element} el
6165 * @param {Number} rowIndex
6166 * @param {Roo.EventObject} e
6170 * @event rowdblclick
6171 * Fires when a row is double clicked
6172 * @param {Roo.bootstrap.Table} this
6173 * @param {Roo.Element} el
6174 * @param {Number} rowIndex
6175 * @param {Roo.EventObject} e
6177 "rowdblclick" : true,
6180 * Fires when a mouseover occur
6181 * @param {Roo.bootstrap.Table} this
6182 * @param {Roo.Element} el
6183 * @param {Number} rowIndex
6184 * @param {Number} columnIndex
6185 * @param {Roo.EventObject} e
6190 * Fires when a mouseout occur
6191 * @param {Roo.bootstrap.Table} this
6192 * @param {Roo.Element} el
6193 * @param {Number} rowIndex
6194 * @param {Number} columnIndex
6195 * @param {Roo.EventObject} e
6200 * Fires when a row is rendered, so you can change add a style to it.
6201 * @param {Roo.bootstrap.Table} this
6202 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
6206 * @event rowsrendered
6207 * Fires when all the rows have been rendered
6208 * @param {Roo.bootstrap.Table} this
6210 'rowsrendered' : true,
6212 * @event contextmenu
6213 * The raw contextmenu event for the entire grid.
6214 * @param {Roo.EventObject} e
6216 "contextmenu" : true,
6218 * @event rowcontextmenu
6219 * Fires when a row is right clicked
6220 * @param {Roo.bootstrap.Table} this
6221 * @param {Number} rowIndex
6222 * @param {Roo.EventObject} e
6224 "rowcontextmenu" : true,
6226 * @event cellcontextmenu
6227 * Fires when a cell is right clicked
6228 * @param {Roo.bootstrap.Table} this
6229 * @param {Number} rowIndex
6230 * @param {Number} cellIndex
6231 * @param {Roo.EventObject} e
6233 "cellcontextmenu" : true,
6235 * @event headercontextmenu
6236 * Fires when a header is right clicked
6237 * @param {Roo.bootstrap.Table} this
6238 * @param {Number} columnIndex
6239 * @param {Roo.EventObject} e
6241 "headercontextmenu" : true
6245 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
6271 rowSelection : false,
6272 cellSelection : false,
6275 // Roo.Element - the tbody
6277 // Roo.Element - thead element
6280 container: false, // used by gridpanel...
6286 auto_hide_footer : false,
6288 getAutoCreate : function()
6290 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
6297 if (this.scrollBody) {
6298 cfg.cls += ' table-body-fixed';
6301 cfg.cls += ' table-striped';
6305 cfg.cls += ' table-hover';
6307 if (this.bordered) {
6308 cfg.cls += ' table-bordered';
6310 if (this.condensed) {
6311 cfg.cls += ' table-condensed';
6313 if (this.responsive) {
6314 cfg.cls += ' table-responsive';
6318 cfg.cls+= ' ' +this.cls;
6321 // this lot should be simplifed...
6334 ].forEach(function(k) {
6342 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
6345 if(this.store || this.cm){
6346 if(this.headerShow){
6347 cfg.cn.push(this.renderHeader());
6350 cfg.cn.push(this.renderBody());
6352 if(this.footerShow){
6353 cfg.cn.push(this.renderFooter());
6355 // where does this come from?
6356 //cfg.cls+= ' TableGrid';
6359 return { cn : [ cfg ] };
6362 initEvents : function()
6364 if(!this.store || !this.cm){
6367 if (this.selModel) {
6368 this.selModel.initEvents();
6372 //Roo.log('initEvents with ds!!!!');
6374 this.mainBody = this.el.select('tbody', true).first();
6375 this.mainHead = this.el.select('thead', true).first();
6376 this.mainFoot = this.el.select('tfoot', true).first();
6382 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6383 e.on('click', _this.sort, _this);
6386 this.mainBody.on("click", this.onClick, this);
6387 this.mainBody.on("dblclick", this.onDblClick, this);
6389 // why is this done????? = it breaks dialogs??
6390 //this.parent().el.setStyle('position', 'relative');
6394 this.footer.parentId = this.id;
6395 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
6398 this.el.select('tfoot tr td').first().addClass('hide');
6403 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
6406 this.store.on('load', this.onLoad, this);
6407 this.store.on('beforeload', this.onBeforeLoad, this);
6408 this.store.on('update', this.onUpdate, this);
6409 this.store.on('add', this.onAdd, this);
6410 this.store.on("clear", this.clear, this);
6412 this.el.on("contextmenu", this.onContextMenu, this);
6414 this.mainBody.on('scroll', this.onBodyScroll, this);
6416 this.cm.on("headerchange", this.onHeaderChange, this);
6418 this.cm.on("hiddenchange", this.onHiddenChange, this, arguments);
6422 onContextMenu : function(e, t)
6424 this.processEvent("contextmenu", e);
6427 processEvent : function(name, e)
6429 if (name != 'touchstart' ) {
6430 this.fireEvent(name, e);
6433 var t = e.getTarget();
6435 var cell = Roo.get(t);
6441 if(cell.findParent('tfoot', false, true)){
6445 if(cell.findParent('thead', false, true)){
6447 if(e.getTarget().nodeName.toLowerCase() != 'th'){
6448 cell = Roo.get(t).findParent('th', false, true);
6450 Roo.log("failed to find th in thead?");
6451 Roo.log(e.getTarget());
6456 var cellIndex = cell.dom.cellIndex;
6458 var ename = name == 'touchstart' ? 'click' : name;
6459 this.fireEvent("header" + ename, this, cellIndex, e);
6464 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6465 cell = Roo.get(t).findParent('td', false, true);
6467 Roo.log("failed to find th in tbody?");
6468 Roo.log(e.getTarget());
6473 var row = cell.findParent('tr', false, true);
6474 var cellIndex = cell.dom.cellIndex;
6475 var rowIndex = row.dom.rowIndex - 1;
6479 this.fireEvent("row" + name, this, rowIndex, e);
6483 this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
6489 onMouseover : function(e, el)
6491 var cell = Roo.get(el);
6497 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6498 cell = cell.findParent('td', false, true);
6501 var row = cell.findParent('tr', false, true);
6502 var cellIndex = cell.dom.cellIndex;
6503 var rowIndex = row.dom.rowIndex - 1; // start from 0
6505 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
6509 onMouseout : function(e, el)
6511 var cell = Roo.get(el);
6517 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6518 cell = cell.findParent('td', false, true);
6521 var row = cell.findParent('tr', false, true);
6522 var cellIndex = cell.dom.cellIndex;
6523 var rowIndex = row.dom.rowIndex - 1; // start from 0
6525 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
6529 onClick : function(e, el)
6531 var cell = Roo.get(el);
6533 if(!cell || (!this.cellSelection && !this.rowSelection)){
6537 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6538 cell = cell.findParent('td', false, true);
6541 if(!cell || typeof(cell) == 'undefined'){
6545 var row = cell.findParent('tr', false, true);
6547 if(!row || typeof(row) == 'undefined'){
6551 var cellIndex = cell.dom.cellIndex;
6552 var rowIndex = this.getRowIndex(row);
6554 // why??? - should these not be based on SelectionModel?
6555 if(this.cellSelection){
6556 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
6559 if(this.rowSelection){
6560 this.fireEvent('rowclick', this, row, rowIndex, e);
6566 onDblClick : function(e,el)
6568 var cell = Roo.get(el);
6570 if(!cell || (!this.cellSelection && !this.rowSelection)){
6574 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6575 cell = cell.findParent('td', false, true);
6578 if(!cell || typeof(cell) == 'undefined'){
6582 var row = cell.findParent('tr', false, true);
6584 if(!row || typeof(row) == 'undefined'){
6588 var cellIndex = cell.dom.cellIndex;
6589 var rowIndex = this.getRowIndex(row);
6591 if(this.cellSelection){
6592 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
6595 if(this.rowSelection){
6596 this.fireEvent('rowdblclick', this, row, rowIndex, e);
6600 sort : function(e,el)
6602 var col = Roo.get(el);
6604 if(!col.hasClass('sortable')){
6608 var sort = col.attr('sort');
6611 if(col.select('i', true).first().hasClass('glyphicon-arrow-up')){
6615 this.store.sortInfo = {field : sort, direction : dir};
6618 Roo.log("calling footer first");
6619 this.footer.onClick('first');
6622 this.store.load({ params : { start : 0 } });
6626 renderHeader : function()
6634 this.totalWidth = 0;
6636 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6638 var config = cm.config[i];
6642 cls : 'x-hcol-' + i,
6644 html: cm.getColumnHeader(i)
6649 if(typeof(config.sortable) != 'undefined' && config.sortable){
6651 c.html = '<i class="glyphicon"></i>' + c.html;
6654 if(typeof(config.lgHeader) != 'undefined'){
6655 hh += '<span class="hidden-xs hidden-sm hidden-md">' + config.lgHeader + '</span>';
6658 if(typeof(config.mdHeader) != 'undefined'){
6659 hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
6662 if(typeof(config.smHeader) != 'undefined'){
6663 hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
6666 if(typeof(config.xsHeader) != 'undefined'){
6667 hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
6674 if(typeof(config.tooltip) != 'undefined'){
6675 c.tooltip = config.tooltip;
6678 if(typeof(config.colspan) != 'undefined'){
6679 c.colspan = config.colspan;
6682 if(typeof(config.hidden) != 'undefined' && config.hidden){
6683 c.style += ' display:none;';
6686 if(typeof(config.dataIndex) != 'undefined'){
6687 c.sort = config.dataIndex;
6692 if(typeof(config.align) != 'undefined' && config.align.length){
6693 c.style += ' text-align:' + config.align + ';';
6696 if(typeof(config.width) != 'undefined'){
6697 c.style += ' width:' + config.width + 'px;';
6698 this.totalWidth += config.width;
6700 this.totalWidth += 100; // assume minimum of 100 per column?
6703 if(typeof(config.cls) != 'undefined'){
6704 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
6707 ['xs','sm','md','lg'].map(function(size){
6709 if(typeof(config[size]) == 'undefined'){
6713 if (!config[size]) { // 0 = hidden
6714 c.cls += ' hidden-' + size;
6718 c.cls += ' col-' + size + '-' + config[size];
6728 renderBody : function()
6738 colspan : this.cm.getColumnCount()
6748 renderFooter : function()
6758 colspan : this.cm.getColumnCount()
6772 // Roo.log('ds onload');
6777 var ds = this.store;
6779 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6780 e.select('i', true).removeClass(['glyphicon-arrow-up', 'glyphicon-arrow-down']);
6781 if (_this.store.sortInfo) {
6783 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
6784 e.select('i', true).addClass(['glyphicon-arrow-up']);
6787 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
6788 e.select('i', true).addClass(['glyphicon-arrow-down']);
6793 var tbody = this.mainBody;
6795 if(ds.getCount() > 0){
6796 ds.data.each(function(d,rowIndex){
6797 var row = this.renderRow(cm, ds, rowIndex);
6799 tbody.createChild(row);
6803 if(row.cellObjects.length){
6804 Roo.each(row.cellObjects, function(r){
6805 _this.renderCellObject(r);
6812 var tfoot = this.el.select('tfoot', true).first();
6814 if(this.footerShow && this.auto_hide_footer && this.mainFoot){
6816 this.mainFoot.setVisibilityMode(Roo.Element.DISPLAY).hide();
6818 var total = this.ds.getTotalCount();
6820 if(this.footer.pageSize < total){
6821 this.mainFoot.show();
6825 Roo.each(this.el.select('tbody td', true).elements, function(e){
6826 e.on('mouseover', _this.onMouseover, _this);
6829 Roo.each(this.el.select('tbody td', true).elements, function(e){
6830 e.on('mouseout', _this.onMouseout, _this);
6832 this.fireEvent('rowsrendered', this);
6838 onUpdate : function(ds,record)
6840 this.refreshRow(record);
6844 onRemove : function(ds, record, index, isUpdate){
6845 if(isUpdate !== true){
6846 this.fireEvent("beforerowremoved", this, index, record);
6848 var bt = this.mainBody.dom;
6850 var rows = this.el.select('tbody > tr', true).elements;
6852 if(typeof(rows[index]) != 'undefined'){
6853 bt.removeChild(rows[index].dom);
6856 // if(bt.rows[index]){
6857 // bt.removeChild(bt.rows[index]);
6860 if(isUpdate !== true){
6861 //this.stripeRows(index);
6862 //this.syncRowHeights(index, index);
6864 this.fireEvent("rowremoved", this, index, record);
6868 onAdd : function(ds, records, rowIndex)
6870 //Roo.log('on Add called');
6871 // - note this does not handle multiple adding very well..
6872 var bt = this.mainBody.dom;
6873 for (var i =0 ; i < records.length;i++) {
6874 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
6875 //Roo.log(records[i]);
6876 //Roo.log(this.store.getAt(rowIndex+i));
6877 this.insertRow(this.store, rowIndex + i, false);
6884 refreshRow : function(record){
6885 var ds = this.store, index;
6886 if(typeof record == 'number'){
6888 record = ds.getAt(index);
6890 index = ds.indexOf(record);
6892 this.insertRow(ds, index, true);
6894 this.onRemove(ds, record, index+1, true);
6896 //this.syncRowHeights(index, index);
6898 this.fireEvent("rowupdated", this, index, record);
6901 insertRow : function(dm, rowIndex, isUpdate){
6904 this.fireEvent("beforerowsinserted", this, rowIndex);
6906 //var s = this.getScrollState();
6907 var row = this.renderRow(this.cm, this.store, rowIndex);
6908 // insert before rowIndex..
6909 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
6913 if(row.cellObjects.length){
6914 Roo.each(row.cellObjects, function(r){
6915 _this.renderCellObject(r);
6920 this.fireEvent("rowsinserted", this, rowIndex);
6921 //this.syncRowHeights(firstRow, lastRow);
6922 //this.stripeRows(firstRow);
6929 getRowDom : function(rowIndex)
6931 var rows = this.el.select('tbody > tr', true).elements;
6933 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
6936 // returns the object tree for a tr..
6939 renderRow : function(cm, ds, rowIndex)
6941 var d = ds.getAt(rowIndex);
6945 cls : 'x-row-' + rowIndex,
6949 var cellObjects = [];
6951 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6952 var config = cm.config[i];
6954 var renderer = cm.getRenderer(i);
6958 if(typeof(renderer) !== 'undefined'){
6959 value = renderer(d.data[cm.getDataIndex(i)], false, d);
6961 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
6962 // and are rendered into the cells after the row is rendered - using the id for the element.
6964 if(typeof(value) === 'object'){
6974 rowIndex : rowIndex,
6979 this.fireEvent('rowclass', this, rowcfg);
6983 cls : rowcfg.rowClass + ' x-col-' + i,
6985 html: (typeof(value) === 'object') ? '' : value
6992 if(typeof(config.colspan) != 'undefined'){
6993 td.colspan = config.colspan;
6996 if(typeof(config.hidden) != 'undefined' && config.hidden){
6997 td.style += ' display:none;';
7000 if(typeof(config.align) != 'undefined' && config.align.length){
7001 td.style += ' text-align:' + config.align + ';';
7003 if(typeof(config.valign) != 'undefined' && config.valign.length){
7004 td.style += ' vertical-align:' + config.valign + ';';
7007 if(typeof(config.width) != 'undefined'){
7008 td.style += ' width:' + config.width + 'px;';
7011 if(typeof(config.cursor) != 'undefined'){
7012 td.style += ' cursor:' + config.cursor + ';';
7015 if(typeof(config.cls) != 'undefined'){
7016 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
7019 ['xs','sm','md','lg'].map(function(size){
7021 if(typeof(config[size]) == 'undefined'){
7025 if (!config[size]) { // 0 = hidden
7026 td.cls += ' hidden-' + size;
7030 td.cls += ' col-' + size + '-' + config[size];
7038 row.cellObjects = cellObjects;
7046 onBeforeLoad : function()
7055 this.el.select('tbody', true).first().dom.innerHTML = '';
7058 * Show or hide a row.
7059 * @param {Number} rowIndex to show or hide
7060 * @param {Boolean} state hide
7062 setRowVisibility : function(rowIndex, state)
7064 var bt = this.mainBody.dom;
7066 var rows = this.el.select('tbody > tr', true).elements;
7068 if(typeof(rows[rowIndex]) == 'undefined'){
7071 rows[rowIndex].dom.style.display = state ? '' : 'none';
7075 getSelectionModel : function(){
7077 this.selModel = new Roo.bootstrap.Table.RowSelectionModel({grid: this});
7079 return this.selModel;
7082 * Render the Roo.bootstrap object from renderder
7084 renderCellObject : function(r)
7088 r.cfg.parentId = (typeof(r.container) == 'string') ? r.container : r.container.id;
7090 var t = r.cfg.render(r.container);
7093 Roo.each(r.cfg.cn, function(c){
7095 container: t.getChildContainer(),
7098 _this.renderCellObject(child);
7103 getRowIndex : function(row)
7107 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
7118 * Returns the grid's underlying element = used by panel.Grid
7119 * @return {Element} The element
7121 getGridEl : function(){
7125 * Forces a resize - used by panel.Grid
7126 * @return {Element} The element
7128 autoSize : function()
7130 //var ctr = Roo.get(this.container.dom.parentElement);
7131 var ctr = Roo.get(this.el.dom);
7133 var thd = this.getGridEl().select('thead',true).first();
7134 var tbd = this.getGridEl().select('tbody', true).first();
7135 var tfd = this.getGridEl().select('tfoot', true).first();
7137 var cw = ctr.getWidth();
7141 tbd.setSize(ctr.getWidth(),
7142 ctr.getHeight() - ((thd ? thd.getHeight() : 0) + (tfd ? tfd.getHeight() : 0))
7144 var barsize = (tbd.dom.offsetWidth - tbd.dom.clientWidth);
7147 cw = Math.max(cw, this.totalWidth);
7148 this.getGridEl().select('tr',true).setWidth(cw);
7149 // resize 'expandable coloumn?
7151 return; // we doe not have a view in this design..
7154 onBodyScroll: function()
7156 //Roo.log("body scrolled');" + this.mainBody.dom.scrollLeft);
7158 this.mainHead.setStyle({
7159 'position' : 'relative',
7160 'left': (-1* this.mainBody.dom.scrollLeft) + 'px'
7166 var scrollHeight = this.mainBody.dom.scrollHeight;
7168 var scrollTop = Math.ceil(this.mainBody.getScroll().top);
7170 var height = this.mainBody.getHeight();
7172 if(scrollHeight - height == scrollTop) {
7174 var total = this.ds.getTotalCount();
7176 if(this.footer.cursor + this.footer.pageSize < total){
7178 this.footer.ds.load({
7180 start : this.footer.cursor + this.footer.pageSize,
7181 limit : this.footer.pageSize
7191 onHeaderChange : function()
7193 var header = this.renderHeader();
7194 var table = this.el.select('table', true).first();
7196 this.mainHead.remove();
7197 this.mainHead = table.createChild(header, this.mainBody, false);
7200 onHiddenChange : function(colModel, colIndex, hidden)
7202 var thSelector = '#' + this.id + ' .x-hcol-' + colIndex;
7203 var tdSelector = '#' + this.id + ' .x-col-' + colIndex;
7205 this.CSS.updateRule(thSelector, "display", "");
7206 this.CSS.updateRule(tdSelector, "display", "");
7209 this.CSS.updateRule(thSelector, "display", "none");
7210 this.CSS.updateRule(tdSelector, "display", "none");
7213 this.onHeaderChange();
7217 setColumnWidth: function(col_index, width)
7219 // width = "md-2 xs-2..."
7220 if(!this.colModel.config[col_index]) {
7224 var w = width.split(" ");
7226 var rows = this.el.dom.getElementsByClassName("x-col-"+col_index);
7228 var h_row = this.el.dom.getElementsByClassName("x-hcol-"+col_index);
7231 for(var j = 0; j < w.length; j++) {
7237 var size_cls = w[j].split("-");
7239 if(!Number.isInteger(size_cls[1] * 1)) {
7243 if(!this.colModel.config[col_index][size_cls[0]]) {
7247 if(!h_row[0].classList.contains("col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]])) {
7251 h_row[0].classList.replace(
7252 "col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]],
7253 "col-"+size_cls[0]+"-"+size_cls[1]
7256 for(var i = 0; i < rows.length; i++) {
7258 var size_cls = w[j].split("-");
7260 if(!Number.isInteger(size_cls[1] * 1)) {
7264 if(!this.colModel.config[col_index][size_cls[0]]) {
7268 if(!rows[i].classList.contains("col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]])) {
7272 rows[i].classList.replace(
7273 "col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]],
7274 "col-"+size_cls[0]+"-"+size_cls[1]
7278 this.colModel.config[col_index][size_cls[0]] = size_cls[1];
7293 * @class Roo.bootstrap.TableCell
7294 * @extends Roo.bootstrap.Component
7295 * Bootstrap TableCell class
7296 * @cfg {String} html cell contain text
7297 * @cfg {String} cls cell class
7298 * @cfg {String} tag cell tag (td|th) default td
7299 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
7300 * @cfg {String} align Aligns the content in a cell
7301 * @cfg {String} axis Categorizes cells
7302 * @cfg {String} bgcolor Specifies the background color of a cell
7303 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7304 * @cfg {Number} colspan Specifies the number of columns a cell should span
7305 * @cfg {String} headers Specifies one or more header cells a cell is related to
7306 * @cfg {Number} height Sets the height of a cell
7307 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
7308 * @cfg {Number} rowspan Sets the number of rows a cell should span
7309 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
7310 * @cfg {String} valign Vertical aligns the content in a cell
7311 * @cfg {Number} width Specifies the width of a cell
7314 * Create a new TableCell
7315 * @param {Object} config The config object
7318 Roo.bootstrap.TableCell = function(config){
7319 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
7322 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
7342 getAutoCreate : function(){
7343 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
7363 cfg.align=this.align
7369 cfg.bgcolor=this.bgcolor
7372 cfg.charoff=this.charoff
7375 cfg.colspan=this.colspan
7378 cfg.headers=this.headers
7381 cfg.height=this.height
7384 cfg.nowrap=this.nowrap
7387 cfg.rowspan=this.rowspan
7390 cfg.scope=this.scope
7393 cfg.valign=this.valign
7396 cfg.width=this.width
7415 * @class Roo.bootstrap.TableRow
7416 * @extends Roo.bootstrap.Component
7417 * Bootstrap TableRow class
7418 * @cfg {String} cls row class
7419 * @cfg {String} align Aligns the content in a table row
7420 * @cfg {String} bgcolor Specifies a background color for a table row
7421 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7422 * @cfg {String} valign Vertical aligns the content in a table row
7425 * Create a new TableRow
7426 * @param {Object} config The config object
7429 Roo.bootstrap.TableRow = function(config){
7430 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
7433 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
7441 getAutoCreate : function(){
7442 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
7452 cfg.align = this.align;
7455 cfg.bgcolor = this.bgcolor;
7458 cfg.charoff = this.charoff;
7461 cfg.valign = this.valign;
7479 * @class Roo.bootstrap.TableBody
7480 * @extends Roo.bootstrap.Component
7481 * Bootstrap TableBody class
7482 * @cfg {String} cls element class
7483 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
7484 * @cfg {String} align Aligns the content inside the element
7485 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
7486 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
7489 * Create a new TableBody
7490 * @param {Object} config The config object
7493 Roo.bootstrap.TableBody = function(config){
7494 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
7497 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
7505 getAutoCreate : function(){
7506 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
7520 cfg.align = this.align;
7523 cfg.charoff = this.charoff;
7526 cfg.valign = this.valign;
7533 // initEvents : function()
7540 // this.store = Roo.factory(this.store, Roo.data);
7541 // this.store.on('load', this.onLoad, this);
7543 // this.store.load();
7547 // onLoad: function ()
7549 // this.fireEvent('load', this);
7559 * Ext JS Library 1.1.1
7560 * Copyright(c) 2006-2007, Ext JS, LLC.
7562 * Originally Released Under LGPL - original licence link has changed is not relivant.
7565 * <script type="text/javascript">
7568 // as we use this in bootstrap.
7569 Roo.namespace('Roo.form');
7571 * @class Roo.form.Action
7572 * Internal Class used to handle form actions
7574 * @param {Roo.form.BasicForm} el The form element or its id
7575 * @param {Object} config Configuration options
7580 // define the action interface
7581 Roo.form.Action = function(form, options){
7583 this.options = options || {};
7586 * Client Validation Failed
7589 Roo.form.Action.CLIENT_INVALID = 'client';
7591 * Server Validation Failed
7594 Roo.form.Action.SERVER_INVALID = 'server';
7596 * Connect to Server Failed
7599 Roo.form.Action.CONNECT_FAILURE = 'connect';
7601 * Reading Data from Server Failed
7604 Roo.form.Action.LOAD_FAILURE = 'load';
7606 Roo.form.Action.prototype = {
7608 failureType : undefined,
7609 response : undefined,
7613 run : function(options){
7618 success : function(response){
7623 handleResponse : function(response){
7627 // default connection failure
7628 failure : function(response){
7630 this.response = response;
7631 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7632 this.form.afterAction(this, false);
7635 processResponse : function(response){
7636 this.response = response;
7637 if(!response.responseText){
7640 this.result = this.handleResponse(response);
7644 // utility functions used internally
7645 getUrl : function(appendParams){
7646 var url = this.options.url || this.form.url || this.form.el.dom.action;
7648 var p = this.getParams();
7650 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
7656 getMethod : function(){
7657 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
7660 getParams : function(){
7661 var bp = this.form.baseParams;
7662 var p = this.options.params;
7664 if(typeof p == "object"){
7665 p = Roo.urlEncode(Roo.applyIf(p, bp));
7666 }else if(typeof p == 'string' && bp){
7667 p += '&' + Roo.urlEncode(bp);
7670 p = Roo.urlEncode(bp);
7675 createCallback : function(){
7677 success: this.success,
7678 failure: this.failure,
7680 timeout: (this.form.timeout*1000),
7681 upload: this.form.fileUpload ? this.success : undefined
7686 Roo.form.Action.Submit = function(form, options){
7687 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
7690 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
7693 haveProgress : false,
7694 uploadComplete : false,
7696 // uploadProgress indicator.
7697 uploadProgress : function()
7699 if (!this.form.progressUrl) {
7703 if (!this.haveProgress) {
7704 Roo.MessageBox.progress("Uploading", "Uploading");
7706 if (this.uploadComplete) {
7707 Roo.MessageBox.hide();
7711 this.haveProgress = true;
7713 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
7715 var c = new Roo.data.Connection();
7717 url : this.form.progressUrl,
7722 success : function(req){
7723 //console.log(data);
7727 rdata = Roo.decode(req.responseText)
7729 Roo.log("Invalid data from server..");
7733 if (!rdata || !rdata.success) {
7735 Roo.MessageBox.alert(Roo.encode(rdata));
7738 var data = rdata.data;
7740 if (this.uploadComplete) {
7741 Roo.MessageBox.hide();
7746 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
7747 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
7750 this.uploadProgress.defer(2000,this);
7753 failure: function(data) {
7754 Roo.log('progress url failed ');
7765 // run get Values on the form, so it syncs any secondary forms.
7766 this.form.getValues();
7768 var o = this.options;
7769 var method = this.getMethod();
7770 var isPost = method == 'POST';
7771 if(o.clientValidation === false || this.form.isValid()){
7773 if (this.form.progressUrl) {
7774 this.form.findField('UPLOAD_IDENTIFIER').setValue(
7775 (new Date() * 1) + '' + Math.random());
7780 Roo.Ajax.request(Roo.apply(this.createCallback(), {
7781 form:this.form.el.dom,
7782 url:this.getUrl(!isPost),
7784 params:isPost ? this.getParams() : null,
7785 isUpload: this.form.fileUpload
7788 this.uploadProgress();
7790 }else if (o.clientValidation !== false){ // client validation failed
7791 this.failureType = Roo.form.Action.CLIENT_INVALID;
7792 this.form.afterAction(this, false);
7796 success : function(response)
7798 this.uploadComplete= true;
7799 if (this.haveProgress) {
7800 Roo.MessageBox.hide();
7804 var result = this.processResponse(response);
7805 if(result === true || result.success){
7806 this.form.afterAction(this, true);
7810 this.form.markInvalid(result.errors);
7811 this.failureType = Roo.form.Action.SERVER_INVALID;
7813 this.form.afterAction(this, false);
7815 failure : function(response)
7817 this.uploadComplete= true;
7818 if (this.haveProgress) {
7819 Roo.MessageBox.hide();
7822 this.response = response;
7823 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7824 this.form.afterAction(this, false);
7827 handleResponse : function(response){
7828 if(this.form.errorReader){
7829 var rs = this.form.errorReader.read(response);
7832 for(var i = 0, len = rs.records.length; i < len; i++) {
7833 var r = rs.records[i];
7837 if(errors.length < 1){
7841 success : rs.success,
7847 ret = Roo.decode(response.responseText);
7851 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
7861 Roo.form.Action.Load = function(form, options){
7862 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
7863 this.reader = this.form.reader;
7866 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
7871 Roo.Ajax.request(Roo.apply(
7872 this.createCallback(), {
7873 method:this.getMethod(),
7874 url:this.getUrl(false),
7875 params:this.getParams()
7879 success : function(response){
7881 var result = this.processResponse(response);
7882 if(result === true || !result.success || !result.data){
7883 this.failureType = Roo.form.Action.LOAD_FAILURE;
7884 this.form.afterAction(this, false);
7887 this.form.clearInvalid();
7888 this.form.setValues(result.data);
7889 this.form.afterAction(this, true);
7892 handleResponse : function(response){
7893 if(this.form.reader){
7894 var rs = this.form.reader.read(response);
7895 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
7897 success : rs.success,
7901 return Roo.decode(response.responseText);
7905 Roo.form.Action.ACTION_TYPES = {
7906 'load' : Roo.form.Action.Load,
7907 'submit' : Roo.form.Action.Submit
7916 * @class Roo.bootstrap.Form
7917 * @extends Roo.bootstrap.Component
7918 * Bootstrap Form class
7919 * @cfg {String} method GET | POST (default POST)
7920 * @cfg {String} labelAlign top | left (default top)
7921 * @cfg {String} align left | right - for navbars
7922 * @cfg {Boolean} loadMask load mask when submit (default true)
7927 * @param {Object} config The config object
7931 Roo.bootstrap.Form = function(config){
7933 Roo.bootstrap.Form.superclass.constructor.call(this, config);
7935 Roo.bootstrap.Form.popover.apply();
7939 * @event clientvalidation
7940 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
7941 * @param {Form} this
7942 * @param {Boolean} valid true if the form has passed client-side validation
7944 clientvalidation: true,
7946 * @event beforeaction
7947 * Fires before any action is performed. Return false to cancel the action.
7948 * @param {Form} this
7949 * @param {Action} action The action to be performed
7953 * @event actionfailed
7954 * Fires when an action fails.
7955 * @param {Form} this
7956 * @param {Action} action The action that failed
7958 actionfailed : true,
7960 * @event actioncomplete
7961 * Fires when an action is completed.
7962 * @param {Form} this
7963 * @param {Action} action The action that completed
7965 actioncomplete : true
7969 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
7972 * @cfg {String} method
7973 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
7978 * The URL to use for form actions if one isn't supplied in the action options.
7981 * @cfg {Boolean} fileUpload
7982 * Set to true if this form is a file upload.
7986 * @cfg {Object} baseParams
7987 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
7991 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
7995 * @cfg {Sting} align (left|right) for navbar forms
8000 activeAction : null,
8003 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
8004 * element by passing it or its id or mask the form itself by passing in true.
8007 waitMsgTarget : false,
8012 * @cfg {Boolean} errorMask (true|false) default false
8017 * @cfg {Number} maskOffset Default 100
8022 * @cfg {Boolean} maskBody
8026 getAutoCreate : function(){
8030 method : this.method || 'POST',
8031 id : this.id || Roo.id(),
8034 if (this.parent().xtype.match(/^Nav/)) {
8035 cfg.cls = 'navbar-form form-inline navbar-' + this.align;
8039 if (this.labelAlign == 'left' ) {
8040 cfg.cls += ' form-horizontal';
8046 initEvents : function()
8048 this.el.on('submit', this.onSubmit, this);
8049 // this was added as random key presses on the form where triggering form submit.
8050 this.el.on('keypress', function(e) {
8051 if (e.getCharCode() != 13) {
8054 // we might need to allow it for textareas.. and some other items.
8055 // check e.getTarget().
8057 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
8061 Roo.log("keypress blocked");
8069 onSubmit : function(e){
8074 * Returns true if client-side validation on the form is successful.
8077 isValid : function(){
8078 var items = this.getItems();
8082 items.each(function(f){
8088 Roo.log('invalid field: ' + f.name);
8092 if(!target && f.el.isVisible(true)){
8098 if(this.errorMask && !valid){
8099 Roo.bootstrap.Form.popover.mask(this, target);
8106 * Returns true if any fields in this form have changed since their original load.
8109 isDirty : function(){
8111 var items = this.getItems();
8112 items.each(function(f){
8122 * Performs a predefined action (submit or load) or custom actions you define on this form.
8123 * @param {String} actionName The name of the action type
8124 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
8125 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
8126 * accept other config options):
8128 Property Type Description
8129 ---------------- --------------- ----------------------------------------------------------------------------------
8130 url String The url for the action (defaults to the form's url)
8131 method String The form method to use (defaults to the form's method, or POST if not defined)
8132 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
8133 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
8134 validate the form on the client (defaults to false)
8136 * @return {BasicForm} this
8138 doAction : function(action, options){
8139 if(typeof action == 'string'){
8140 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
8142 if(this.fireEvent('beforeaction', this, action) !== false){
8143 this.beforeAction(action);
8144 action.run.defer(100, action);
8150 beforeAction : function(action){
8151 var o = action.options;
8156 Roo.get(document.body).mask(o.waitMsg || "Sending", 'x-mask-loading')
8158 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
8161 // not really supported yet.. ??
8163 //if(this.waitMsgTarget === true){
8164 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
8165 //}else if(this.waitMsgTarget){
8166 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
8167 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
8169 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
8175 afterAction : function(action, success){
8176 this.activeAction = null;
8177 var o = action.options;
8182 Roo.get(document.body).unmask();
8188 //if(this.waitMsgTarget === true){
8189 // this.el.unmask();
8190 //}else if(this.waitMsgTarget){
8191 // this.waitMsgTarget.unmask();
8193 // Roo.MessageBox.updateProgress(1);
8194 // Roo.MessageBox.hide();
8201 Roo.callback(o.success, o.scope, [this, action]);
8202 this.fireEvent('actioncomplete', this, action);
8206 // failure condition..
8207 // we have a scenario where updates need confirming.
8208 // eg. if a locking scenario exists..
8209 // we look for { errors : { needs_confirm : true }} in the response.
8211 (typeof(action.result) != 'undefined') &&
8212 (typeof(action.result.errors) != 'undefined') &&
8213 (typeof(action.result.errors.needs_confirm) != 'undefined')
8216 Roo.log("not supported yet");
8219 Roo.MessageBox.confirm(
8220 "Change requires confirmation",
8221 action.result.errorMsg,
8226 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
8236 Roo.callback(o.failure, o.scope, [this, action]);
8237 // show an error message if no failed handler is set..
8238 if (!this.hasListener('actionfailed')) {
8239 Roo.log("need to add dialog support");
8241 Roo.MessageBox.alert("Error",
8242 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
8243 action.result.errorMsg :
8244 "Saving Failed, please check your entries or try again"
8249 this.fireEvent('actionfailed', this, action);
8254 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
8255 * @param {String} id The value to search for
8258 findField : function(id){
8259 var items = this.getItems();
8260 var field = items.get(id);
8262 items.each(function(f){
8263 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
8270 return field || null;
8273 * Mark fields in this form invalid in bulk.
8274 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
8275 * @return {BasicForm} this
8277 markInvalid : function(errors){
8278 if(errors instanceof Array){
8279 for(var i = 0, len = errors.length; i < len; i++){
8280 var fieldError = errors[i];
8281 var f = this.findField(fieldError.id);
8283 f.markInvalid(fieldError.msg);
8289 if(typeof errors[id] != 'function' && (field = this.findField(id))){
8290 field.markInvalid(errors[id]);
8294 //Roo.each(this.childForms || [], function (f) {
8295 // f.markInvalid(errors);
8302 * Set values for fields in this form in bulk.
8303 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
8304 * @return {BasicForm} this
8306 setValues : function(values){
8307 if(values instanceof Array){ // array of objects
8308 for(var i = 0, len = values.length; i < len; i++){
8310 var f = this.findField(v.id);
8312 f.setValue(v.value);
8313 if(this.trackResetOnLoad){
8314 f.originalValue = f.getValue();
8318 }else{ // object hash
8321 if(typeof values[id] != 'function' && (field = this.findField(id))){
8323 if (field.setFromData &&
8325 field.displayField &&
8326 // combos' with local stores can
8327 // be queried via setValue()
8328 // to set their value..
8329 (field.store && !field.store.isLocal)
8333 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
8334 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
8335 field.setFromData(sd);
8337 } else if(field.setFromData && (field.store && !field.store.isLocal)) {
8339 field.setFromData(values);
8342 field.setValue(values[id]);
8346 if(this.trackResetOnLoad){
8347 field.originalValue = field.getValue();
8353 //Roo.each(this.childForms || [], function (f) {
8354 // f.setValues(values);
8361 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
8362 * they are returned as an array.
8363 * @param {Boolean} asString
8366 getValues : function(asString){
8367 //if (this.childForms) {
8368 // copy values from the child forms
8369 // Roo.each(this.childForms, function (f) {
8370 // this.setValues(f.getValues());
8376 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
8377 if(asString === true){
8380 return Roo.urlDecode(fs);
8384 * Returns the fields in this form as an object with key/value pairs.
8385 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
8388 getFieldValues : function(with_hidden)
8390 var items = this.getItems();
8392 items.each(function(f){
8398 var v = f.getValue();
8400 if (f.inputType =='radio') {
8401 if (typeof(ret[f.getName()]) == 'undefined') {
8402 ret[f.getName()] = ''; // empty..
8405 if (!f.el.dom.checked) {
8413 if(f.xtype == 'MoneyField'){
8414 ret[f.currencyName] = f.getCurrency();
8417 // not sure if this supported any more..
8418 if ((typeof(v) == 'object') && f.getRawValue) {
8419 v = f.getRawValue() ; // dates..
8421 // combo boxes where name != hiddenName...
8422 if (f.name !== false && f.name != '' && f.name != f.getName()) {
8423 ret[f.name] = f.getRawValue();
8425 ret[f.getName()] = v;
8432 * Clears all invalid messages in this form.
8433 * @return {BasicForm} this
8435 clearInvalid : function(){
8436 var items = this.getItems();
8438 items.each(function(f){
8447 * @return {BasicForm} this
8450 var items = this.getItems();
8451 items.each(function(f){
8455 Roo.each(this.childForms || [], function (f) {
8463 getItems : function()
8465 var r=new Roo.util.MixedCollection(false, function(o){
8466 return o.id || (o.id = Roo.id());
8468 var iter = function(el) {
8475 Roo.each(el.items,function(e) {
8484 hideFields : function(items)
8486 Roo.each(items, function(i){
8488 var f = this.findField(i);
8499 showFields : function(items)
8501 Roo.each(items, function(i){
8503 var f = this.findField(i);
8516 Roo.apply(Roo.bootstrap.Form, {
8543 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
8544 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
8545 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
8546 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
8549 this.maskEl.top.enableDisplayMode("block");
8550 this.maskEl.left.enableDisplayMode("block");
8551 this.maskEl.bottom.enableDisplayMode("block");
8552 this.maskEl.right.enableDisplayMode("block");
8554 this.toolTip = new Roo.bootstrap.Tooltip({
8555 cls : 'roo-form-error-popover',
8557 'left' : ['r-l', [-2,0], 'right'],
8558 'right' : ['l-r', [2,0], 'left'],
8559 'bottom' : ['tl-bl', [0,2], 'top'],
8560 'top' : [ 'bl-tl', [0,-2], 'bottom']
8564 this.toolTip.render(Roo.get(document.body));
8566 this.toolTip.el.enableDisplayMode("block");
8568 Roo.get(document.body).on('click', function(){
8572 Roo.get(document.body).on('touchstart', function(){
8576 this.isApplied = true
8579 mask : function(form, target)
8583 this.target = target;
8585 if(!this.form.errorMask || !target.el){
8589 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.modal', 100, true) || Roo.get(document.body);
8591 Roo.log(scrollable);
8593 var ot = this.target.el.calcOffsetsTo(scrollable);
8595 var scrollTo = ot[1] - this.form.maskOffset;
8597 scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
8599 scrollable.scrollTo('top', scrollTo);
8601 var box = this.target.el.getBox();
8603 var zIndex = Roo.bootstrap.Modal.zIndex++;
8606 this.maskEl.top.setStyle('position', 'absolute');
8607 this.maskEl.top.setStyle('z-index', zIndex);
8608 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
8609 this.maskEl.top.setLeft(0);
8610 this.maskEl.top.setTop(0);
8611 this.maskEl.top.show();
8613 this.maskEl.left.setStyle('position', 'absolute');
8614 this.maskEl.left.setStyle('z-index', zIndex);
8615 this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
8616 this.maskEl.left.setLeft(0);
8617 this.maskEl.left.setTop(box.y - this.padding);
8618 this.maskEl.left.show();
8620 this.maskEl.bottom.setStyle('position', 'absolute');
8621 this.maskEl.bottom.setStyle('z-index', zIndex);
8622 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
8623 this.maskEl.bottom.setLeft(0);
8624 this.maskEl.bottom.setTop(box.bottom + this.padding);
8625 this.maskEl.bottom.show();
8627 this.maskEl.right.setStyle('position', 'absolute');
8628 this.maskEl.right.setStyle('z-index', zIndex);
8629 this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
8630 this.maskEl.right.setLeft(box.right + this.padding);
8631 this.maskEl.right.setTop(box.y - this.padding);
8632 this.maskEl.right.show();
8634 this.toolTip.bindEl = this.target.el;
8636 this.toolTip.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
8638 var tip = this.target.blankText;
8640 if(this.target.getValue() !== '' ) {
8642 if (this.target.invalidText.length) {
8643 tip = this.target.invalidText;
8644 } else if (this.target.regexText.length){
8645 tip = this.target.regexText;
8649 this.toolTip.show(tip);
8651 this.intervalID = window.setInterval(function() {
8652 Roo.bootstrap.Form.popover.unmask();
8655 window.onwheel = function(){ return false;};
8657 (function(){ this.isMasked = true; }).defer(500, this);
8663 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
8667 this.maskEl.top.setStyle('position', 'absolute');
8668 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
8669 this.maskEl.top.hide();
8671 this.maskEl.left.setStyle('position', 'absolute');
8672 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
8673 this.maskEl.left.hide();
8675 this.maskEl.bottom.setStyle('position', 'absolute');
8676 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
8677 this.maskEl.bottom.hide();
8679 this.maskEl.right.setStyle('position', 'absolute');
8680 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
8681 this.maskEl.right.hide();
8683 this.toolTip.hide();
8685 this.toolTip.el.hide();
8687 window.onwheel = function(){ return true;};
8689 if(this.intervalID){
8690 window.clearInterval(this.intervalID);
8691 this.intervalID = false;
8694 this.isMasked = false;
8704 * Ext JS Library 1.1.1
8705 * Copyright(c) 2006-2007, Ext JS, LLC.
8707 * Originally Released Under LGPL - original licence link has changed is not relivant.
8710 * <script type="text/javascript">
8713 * @class Roo.form.VTypes
8714 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
8717 Roo.form.VTypes = function(){
8718 // closure these in so they are only created once.
8719 var alpha = /^[a-zA-Z_]+$/;
8720 var alphanum = /^[a-zA-Z0-9_]+$/;
8721 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
8722 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
8724 // All these messages and functions are configurable
8727 * The function used to validate email addresses
8728 * @param {String} value The email address
8730 'email' : function(v){
8731 return email.test(v);
8734 * The error text to display when the email validation function returns false
8737 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
8739 * The keystroke filter mask to be applied on email input
8742 'emailMask' : /[a-z0-9_\.\-@]/i,
8745 * The function used to validate URLs
8746 * @param {String} value The URL
8748 'url' : function(v){
8752 * The error text to display when the url validation function returns false
8755 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
8758 * The function used to validate alpha values
8759 * @param {String} value The value
8761 'alpha' : function(v){
8762 return alpha.test(v);
8765 * The error text to display when the alpha validation function returns false
8768 'alphaText' : 'This field should only contain letters and _',
8770 * The keystroke filter mask to be applied on alpha input
8773 'alphaMask' : /[a-z_]/i,
8776 * The function used to validate alphanumeric values
8777 * @param {String} value The value
8779 'alphanum' : function(v){
8780 return alphanum.test(v);
8783 * The error text to display when the alphanumeric validation function returns false
8786 'alphanumText' : 'This field should only contain letters, numbers and _',
8788 * The keystroke filter mask to be applied on alphanumeric input
8791 'alphanumMask' : /[a-z0-9_]/i
8801 * @class Roo.bootstrap.Input
8802 * @extends Roo.bootstrap.Component
8803 * Bootstrap Input class
8804 * @cfg {Boolean} disabled is it disabled
8805 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
8806 * @cfg {String} name name of the input
8807 * @cfg {string} fieldLabel - the label associated
8808 * @cfg {string} placeholder - placeholder to put in text.
8809 * @cfg {string} before - input group add on before
8810 * @cfg {string} after - input group add on after
8811 * @cfg {string} size - (lg|sm) or leave empty..
8812 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
8813 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
8814 * @cfg {Number} md colspan out of 12 for computer-sized screens
8815 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
8816 * @cfg {string} value default value of the input
8817 * @cfg {Number} labelWidth set the width of label
8818 * @cfg {Number} labellg set the width of label (1-12)
8819 * @cfg {Number} labelmd set the width of label (1-12)
8820 * @cfg {Number} labelsm set the width of label (1-12)
8821 * @cfg {Number} labelxs set the width of label (1-12)
8822 * @cfg {String} labelAlign (top|left)
8823 * @cfg {Boolean} readOnly Specifies that the field should be read-only
8824 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
8825 * @cfg {String} indicatorpos (left|right) default left
8826 * @cfg {String} capture (user|camera) use for file input only. (default empty)
8827 * @cfg {String} accept (image|video|audio) use for file input only. (default empty)
8829 * @cfg {String} align (left|center|right) Default left
8830 * @cfg {Boolean} forceFeedback (true|false) Default false
8833 * Create a new Input
8834 * @param {Object} config The config object
8837 Roo.bootstrap.Input = function(config){
8839 Roo.bootstrap.Input.superclass.constructor.call(this, config);
8844 * Fires when this field receives input focus.
8845 * @param {Roo.form.Field} this
8850 * Fires when this field loses input focus.
8851 * @param {Roo.form.Field} this
8856 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
8857 * {@link Roo.EventObject#getKey} to determine which key was pressed.
8858 * @param {Roo.form.Field} this
8859 * @param {Roo.EventObject} e The event object
8864 * Fires just before the field blurs if the field value has changed.
8865 * @param {Roo.form.Field} this
8866 * @param {Mixed} newValue The new value
8867 * @param {Mixed} oldValue The original value
8872 * Fires after the field has been marked as invalid.
8873 * @param {Roo.form.Field} this
8874 * @param {String} msg The validation message
8879 * Fires after the field has been validated with no errors.
8880 * @param {Roo.form.Field} this
8885 * Fires after the key up
8886 * @param {Roo.form.Field} this
8887 * @param {Roo.EventObject} e The event Object
8893 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
8895 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
8896 automatic validation (defaults to "keyup").
8898 validationEvent : "keyup",
8900 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
8902 validateOnBlur : true,
8904 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
8906 validationDelay : 250,
8908 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
8910 focusClass : "x-form-focus", // not needed???
8914 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
8916 invalidClass : "has-warning",
8919 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
8921 validClass : "has-success",
8924 * @cfg {Boolean} hasFeedback (true|false) default true
8929 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8931 invalidFeedbackClass : "glyphicon-warning-sign",
8934 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8936 validFeedbackClass : "glyphicon-ok",
8939 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
8941 selectOnFocus : false,
8944 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
8948 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
8953 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
8955 disableKeyFilter : false,
8958 * @cfg {Boolean} disabled True to disable the field (defaults to false).
8962 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
8966 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
8968 blankText : "Please complete this mandatory field",
8971 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
8975 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
8977 maxLength : Number.MAX_VALUE,
8979 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
8981 minLengthText : "The minimum length for this field is {0}",
8983 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
8985 maxLengthText : "The maximum length for this field is {0}",
8989 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
8990 * If available, this function will be called only after the basic validators all return true, and will be passed the
8991 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
8995 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
8996 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
8997 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
9001 * @cfg {String} regexText -- Depricated - use Invalid Text
9006 * @cfg {String} invalidText The error text to display if {@link #validator} test fails during validation (defaults to "")
9012 autocomplete: false,
9031 formatedValue : false,
9032 forceFeedback : false,
9034 indicatorpos : 'left',
9044 parentLabelAlign : function()
9047 while (parent.parent()) {
9048 parent = parent.parent();
9049 if (typeof(parent.labelAlign) !='undefined') {
9050 return parent.labelAlign;
9057 getAutoCreate : function()
9059 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9065 if(this.inputType != 'hidden'){
9066 cfg.cls = 'form-group' //input-group
9072 type : this.inputType,
9074 cls : 'form-control',
9075 placeholder : this.placeholder || '',
9076 autocomplete : this.autocomplete || 'new-password'
9079 if(this.capture.length){
9080 input.capture = this.capture;
9083 if(this.accept.length){
9084 input.accept = this.accept + "/*";
9088 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
9091 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9092 input.maxLength = this.maxLength;
9095 if (this.disabled) {
9096 input.disabled=true;
9099 if (this.readOnly) {
9100 input.readonly=true;
9104 input.name = this.name;
9108 input.cls += ' input-' + this.size;
9112 ['xs','sm','md','lg'].map(function(size){
9113 if (settings[size]) {
9114 cfg.cls += ' col-' + size + '-' + settings[size];
9118 var inputblock = input;
9122 cls: 'glyphicon form-control-feedback'
9125 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9128 cls : 'has-feedback',
9136 if (this.before || this.after) {
9139 cls : 'input-group',
9143 if (this.before && typeof(this.before) == 'string') {
9145 inputblock.cn.push({
9147 cls : 'roo-input-before input-group-addon input-group-prepend input-group-text',
9151 if (this.before && typeof(this.before) == 'object') {
9152 this.before = Roo.factory(this.before);
9154 inputblock.cn.push({
9156 cls : 'roo-input-before input-group-prepend input-group-text input-group-' +
9157 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
9161 inputblock.cn.push(input);
9163 if (this.after && typeof(this.after) == 'string') {
9164 inputblock.cn.push({
9166 cls : 'roo-input-after input-group-append input-group-text input-group-addon',
9170 if (this.after && typeof(this.after) == 'object') {
9171 this.after = Roo.factory(this.after);
9173 inputblock.cn.push({
9175 cls : 'roo-input-after input-group-append input-group-text input-group-' +
9176 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
9180 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9181 inputblock.cls += ' has-feedback';
9182 inputblock.cn.push(feedback);
9187 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
9188 tooltip : 'This field is required'
9190 if (Roo.bootstrap.version == 4) {
9193 style : 'display-none'
9196 if (align ==='left' && this.fieldLabel.length) {
9198 cfg.cls += ' roo-form-group-label-left row';
9205 cls : 'control-label col-form-label',
9206 html : this.fieldLabel
9217 var labelCfg = cfg.cn[1];
9218 var contentCfg = cfg.cn[2];
9220 if(this.indicatorpos == 'right'){
9225 cls : 'control-label col-form-label',
9229 html : this.fieldLabel
9243 labelCfg = cfg.cn[0];
9244 contentCfg = cfg.cn[1];
9248 if(this.labelWidth > 12){
9249 labelCfg.style = "width: " + this.labelWidth + 'px';
9252 if(this.labelWidth < 13 && this.labelmd == 0){
9253 this.labelmd = this.labelWidth;
9256 if(this.labellg > 0){
9257 labelCfg.cls += ' col-lg-' + this.labellg;
9258 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
9261 if(this.labelmd > 0){
9262 labelCfg.cls += ' col-md-' + this.labelmd;
9263 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
9266 if(this.labelsm > 0){
9267 labelCfg.cls += ' col-sm-' + this.labelsm;
9268 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
9271 if(this.labelxs > 0){
9272 labelCfg.cls += ' col-xs-' + this.labelxs;
9273 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
9277 } else if ( this.fieldLabel.length) {
9282 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
9283 tooltip : 'This field is required'
9287 //cls : 'input-group-addon',
9288 html : this.fieldLabel
9296 if(this.indicatorpos == 'right'){
9301 //cls : 'input-group-addon',
9302 html : this.fieldLabel
9307 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9308 tooltip : 'This field is required'
9328 if (this.parentType === 'Navbar' && this.parent().bar) {
9329 cfg.cls += ' navbar-form';
9332 if (this.parentType === 'NavGroup') {
9333 cfg.cls += ' navbar-form';
9341 * return the real input element.
9343 inputEl: function ()
9345 return this.el.select('input.form-control',true).first();
9348 tooltipEl : function()
9350 return this.inputEl();
9353 indicatorEl : function()
9355 if (Roo.bootstrap.version == 4) {
9356 return false; // not enabled in v4 yet.
9359 var indicator = this.el.select('i.roo-required-indicator',true).first();
9369 setDisabled : function(v)
9371 var i = this.inputEl().dom;
9373 i.removeAttribute('disabled');
9377 i.setAttribute('disabled','true');
9379 initEvents : function()
9382 this.inputEl().on("keydown" , this.fireKey, this);
9383 this.inputEl().on("focus", this.onFocus, this);
9384 this.inputEl().on("blur", this.onBlur, this);
9386 this.inputEl().relayEvent('keyup', this);
9388 this.indicator = this.indicatorEl();
9391 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible'); // changed from invisible??? -
9394 // reference to original value for reset
9395 this.originalValue = this.getValue();
9396 //Roo.form.TextField.superclass.initEvents.call(this);
9397 if(this.validationEvent == 'keyup'){
9398 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
9399 this.inputEl().on('keyup', this.filterValidation, this);
9401 else if(this.validationEvent !== false){
9402 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
9405 if(this.selectOnFocus){
9406 this.on("focus", this.preFocus, this);
9409 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
9410 this.inputEl().on("keypress", this.filterKeys, this);
9412 this.inputEl().relayEvent('keypress', this);
9415 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
9416 this.el.on("click", this.autoSize, this);
9419 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
9420 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
9423 if (typeof(this.before) == 'object') {
9424 this.before.render(this.el.select('.roo-input-before',true).first());
9426 if (typeof(this.after) == 'object') {
9427 this.after.render(this.el.select('.roo-input-after',true).first());
9430 this.inputEl().on('change', this.onChange, this);
9433 filterValidation : function(e){
9434 if(!e.isNavKeyPress()){
9435 this.validationTask.delay(this.validationDelay);
9439 * Validates the field value
9440 * @return {Boolean} True if the value is valid, else false
9442 validate : function(){
9443 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
9444 if(this.disabled || this.validateValue(this.getRawValue())){
9455 * Validates a value according to the field's validation rules and marks the field as invalid
9456 * if the validation fails
9457 * @param {Mixed} value The value to validate
9458 * @return {Boolean} True if the value is valid, else false
9460 validateValue : function(value)
9462 if(this.getVisibilityEl().hasClass('hidden')){
9466 if(value.length < 1) { // if it's blank
9467 if(this.allowBlank){
9473 if(value.length < this.minLength){
9476 if(value.length > this.maxLength){
9480 var vt = Roo.form.VTypes;
9481 if(!vt[this.vtype](value, this)){
9485 if(typeof this.validator == "function"){
9486 var msg = this.validator(value);
9490 if (typeof(msg) == 'string') {
9491 this.invalidText = msg;
9495 if(this.regex && !this.regex.test(value)){
9503 fireKey : function(e){
9504 //Roo.log('field ' + e.getKey());
9505 if(e.isNavKeyPress()){
9506 this.fireEvent("specialkey", this, e);
9509 focus : function (selectText){
9511 this.inputEl().focus();
9512 if(selectText === true){
9513 this.inputEl().dom.select();
9519 onFocus : function(){
9520 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9521 // this.el.addClass(this.focusClass);
9524 this.hasFocus = true;
9525 this.startValue = this.getValue();
9526 this.fireEvent("focus", this);
9530 beforeBlur : Roo.emptyFn,
9534 onBlur : function(){
9536 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9537 //this.el.removeClass(this.focusClass);
9539 this.hasFocus = false;
9540 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
9543 var v = this.getValue();
9544 if(String(v) !== String(this.startValue)){
9545 this.fireEvent('change', this, v, this.startValue);
9547 this.fireEvent("blur", this);
9550 onChange : function(e)
9552 var v = this.getValue();
9553 if(String(v) !== String(this.startValue)){
9554 this.fireEvent('change', this, v, this.startValue);
9560 * Resets the current field value to the originally loaded value and clears any validation messages
9563 this.setValue(this.originalValue);
9567 * Returns the name of the field
9568 * @return {Mixed} name The name field
9570 getName: function(){
9574 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
9575 * @return {Mixed} value The field value
9577 getValue : function(){
9579 var v = this.inputEl().getValue();
9584 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
9585 * @return {Mixed} value The field value
9587 getRawValue : function(){
9588 var v = this.inputEl().getValue();
9594 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
9595 * @param {Mixed} value The value to set
9597 setRawValue : function(v){
9598 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9601 selectText : function(start, end){
9602 var v = this.getRawValue();
9604 start = start === undefined ? 0 : start;
9605 end = end === undefined ? v.length : end;
9606 var d = this.inputEl().dom;
9607 if(d.setSelectionRange){
9608 d.setSelectionRange(start, end);
9609 }else if(d.createTextRange){
9610 var range = d.createTextRange();
9611 range.moveStart("character", start);
9612 range.moveEnd("character", v.length-end);
9619 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
9620 * @param {Mixed} value The value to set
9622 setValue : function(v){
9625 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9631 processValue : function(value){
9632 if(this.stripCharsRe){
9633 var newValue = value.replace(this.stripCharsRe, '');
9634 if(newValue !== value){
9635 this.setRawValue(newValue);
9642 preFocus : function(){
9644 if(this.selectOnFocus){
9645 this.inputEl().dom.select();
9648 filterKeys : function(e){
9650 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
9653 var c = e.getCharCode(), cc = String.fromCharCode(c);
9654 if(Roo.isIE && (e.isSpecialKey() || !cc)){
9657 if(!this.maskRe.test(cc)){
9662 * Clear any invalid styles/messages for this field
9664 clearInvalid : function(){
9666 if(!this.el || this.preventMark){ // not rendered
9671 this.el.removeClass(this.invalidClass);
9673 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9675 var feedback = this.el.select('.form-control-feedback', true).first();
9678 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9684 this.indicator.removeClass('visible');
9685 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9688 this.fireEvent('valid', this);
9692 * Mark this field as valid
9694 markValid : function()
9696 if(!this.el || this.preventMark){ // not rendered...
9700 this.el.removeClass([this.invalidClass, this.validClass]);
9702 var feedback = this.el.select('.form-control-feedback', true).first();
9705 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9709 this.indicator.removeClass('visible');
9710 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9717 if(this.allowBlank && !this.getRawValue().length){
9721 this.el.addClass(this.validClass);
9723 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9725 var feedback = this.el.select('.form-control-feedback', true).first();
9728 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9729 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9734 this.fireEvent('valid', this);
9738 * Mark this field as invalid
9739 * @param {String} msg The validation message
9741 markInvalid : function(msg)
9743 if(!this.el || this.preventMark){ // not rendered
9747 this.el.removeClass([this.invalidClass, this.validClass]);
9749 var feedback = this.el.select('.form-control-feedback', true).first();
9752 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9759 if(this.allowBlank && !this.getRawValue().length){
9764 this.indicator.removeClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9765 this.indicator.addClass('visible');
9768 this.el.addClass(this.invalidClass);
9770 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9772 var feedback = this.el.select('.form-control-feedback', true).first();
9775 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9777 if(this.getValue().length || this.forceFeedback){
9778 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9785 this.fireEvent('invalid', this, msg);
9788 SafariOnKeyDown : function(event)
9790 // this is a workaround for a password hang bug on chrome/ webkit.
9791 if (this.inputEl().dom.type != 'password') {
9795 var isSelectAll = false;
9797 if(this.inputEl().dom.selectionEnd > 0){
9798 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
9800 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
9801 event.preventDefault();
9806 if(isSelectAll && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
9808 event.preventDefault();
9809 // this is very hacky as keydown always get's upper case.
9811 var cc = String.fromCharCode(event.getCharCode());
9812 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
9816 adjustWidth : function(tag, w){
9817 tag = tag.toLowerCase();
9818 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
9819 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
9823 if(tag == 'textarea'){
9826 }else if(Roo.isOpera){
9830 if(tag == 'textarea'){
9838 setFieldLabel : function(v)
9844 if(this.indicatorEl()){
9845 var ar = this.el.select('label > span',true);
9847 if (ar.elements.length) {
9848 this.el.select('label > span',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9849 this.fieldLabel = v;
9853 var br = this.el.select('label',true);
9855 if(br.elements.length) {
9856 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9857 this.fieldLabel = v;
9861 Roo.log('Cannot Found any of label > span || label in input');
9865 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9866 this.fieldLabel = v;
9881 * @class Roo.bootstrap.TextArea
9882 * @extends Roo.bootstrap.Input
9883 * Bootstrap TextArea class
9884 * @cfg {Number} cols Specifies the visible width of a text area
9885 * @cfg {Number} rows Specifies the visible number of lines in a text area
9886 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
9887 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
9888 * @cfg {string} html text
9891 * Create a new TextArea
9892 * @param {Object} config The config object
9895 Roo.bootstrap.TextArea = function(config){
9896 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
9900 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
9910 getAutoCreate : function(){
9912 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9918 if(this.inputType != 'hidden'){
9919 cfg.cls = 'form-group' //input-group
9927 value : this.value || '',
9928 html: this.html || '',
9929 cls : 'form-control',
9930 placeholder : this.placeholder || ''
9934 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9935 input.maxLength = this.maxLength;
9939 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
9943 input.cols = this.cols;
9946 if (this.readOnly) {
9947 input.readonly = true;
9951 input.name = this.name;
9955 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
9959 ['xs','sm','md','lg'].map(function(size){
9960 if (settings[size]) {
9961 cfg.cls += ' col-' + size + '-' + settings[size];
9965 var inputblock = input;
9967 if(this.hasFeedback && !this.allowBlank){
9971 cls: 'glyphicon form-control-feedback'
9975 cls : 'has-feedback',
9984 if (this.before || this.after) {
9987 cls : 'input-group',
9991 inputblock.cn.push({
9993 cls : 'input-group-addon',
9998 inputblock.cn.push(input);
10000 if(this.hasFeedback && !this.allowBlank){
10001 inputblock.cls += ' has-feedback';
10002 inputblock.cn.push(feedback);
10006 inputblock.cn.push({
10008 cls : 'input-group-addon',
10015 if (align ==='left' && this.fieldLabel.length) {
10020 cls : 'control-label',
10021 html : this.fieldLabel
10032 if(this.labelWidth > 12){
10033 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
10036 if(this.labelWidth < 13 && this.labelmd == 0){
10037 this.labelmd = this.labelWidth;
10040 if(this.labellg > 0){
10041 cfg.cn[0].cls += ' col-lg-' + this.labellg;
10042 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
10045 if(this.labelmd > 0){
10046 cfg.cn[0].cls += ' col-md-' + this.labelmd;
10047 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
10050 if(this.labelsm > 0){
10051 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
10052 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
10055 if(this.labelxs > 0){
10056 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
10057 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
10060 } else if ( this.fieldLabel.length) {
10065 //cls : 'input-group-addon',
10066 html : this.fieldLabel
10084 if (this.disabled) {
10085 input.disabled=true;
10092 * return the real textarea element.
10094 inputEl: function ()
10096 return this.el.select('textarea.form-control',true).first();
10100 * Clear any invalid styles/messages for this field
10102 clearInvalid : function()
10105 if(!this.el || this.preventMark){ // not rendered
10109 var label = this.el.select('label', true).first();
10110 var icon = this.el.select('i.fa-star', true).first();
10116 this.el.removeClass(this.invalidClass);
10118 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10120 var feedback = this.el.select('.form-control-feedback', true).first();
10123 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
10128 this.fireEvent('valid', this);
10132 * Mark this field as valid
10134 markValid : function()
10136 if(!this.el || this.preventMark){ // not rendered
10140 this.el.removeClass([this.invalidClass, this.validClass]);
10142 var feedback = this.el.select('.form-control-feedback', true).first();
10145 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10148 if(this.disabled || this.allowBlank){
10152 var label = this.el.select('label', true).first();
10153 var icon = this.el.select('i.fa-star', true).first();
10159 this.el.addClass(this.validClass);
10161 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
10163 var feedback = this.el.select('.form-control-feedback', true).first();
10166 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10167 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
10172 this.fireEvent('valid', this);
10176 * Mark this field as invalid
10177 * @param {String} msg The validation message
10179 markInvalid : function(msg)
10181 if(!this.el || this.preventMark){ // not rendered
10185 this.el.removeClass([this.invalidClass, this.validClass]);
10187 var feedback = this.el.select('.form-control-feedback', true).first();
10190 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10193 if(this.disabled || this.allowBlank){
10197 var label = this.el.select('label', true).first();
10198 var icon = this.el.select('i.fa-star', true).first();
10200 if(!this.getValue().length && label && !icon){
10201 this.el.createChild({
10203 cls : 'text-danger fa fa-lg fa-star',
10204 tooltip : 'This field is required',
10205 style : 'margin-right:5px;'
10209 this.el.addClass(this.invalidClass);
10211 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10213 var feedback = this.el.select('.form-control-feedback', true).first();
10216 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10218 if(this.getValue().length || this.forceFeedback){
10219 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
10226 this.fireEvent('invalid', this, msg);
10234 * trigger field - base class for combo..
10239 * @class Roo.bootstrap.TriggerField
10240 * @extends Roo.bootstrap.Input
10241 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
10242 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
10243 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
10244 * for which you can provide a custom implementation. For example:
10246 var trigger = new Roo.bootstrap.TriggerField();
10247 trigger.onTriggerClick = myTriggerFn;
10248 trigger.applyTo('my-field');
10251 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
10252 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
10253 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
10254 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
10255 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
10258 * Create a new TriggerField.
10259 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
10260 * to the base TextField)
10262 Roo.bootstrap.TriggerField = function(config){
10263 this.mimicing = false;
10264 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
10267 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
10269 * @cfg {String} triggerClass A CSS class to apply to the trigger
10272 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
10277 * @cfg {Boolean} removable (true|false) special filter default false
10281 /** @cfg {Boolean} grow @hide */
10282 /** @cfg {Number} growMin @hide */
10283 /** @cfg {Number} growMax @hide */
10289 autoSize: Roo.emptyFn,
10293 deferHeight : true,
10296 actionMode : 'wrap',
10301 getAutoCreate : function(){
10303 var align = this.labelAlign || this.parentLabelAlign();
10308 cls: 'form-group' //input-group
10315 type : this.inputType,
10316 cls : 'form-control',
10317 autocomplete: 'new-password',
10318 placeholder : this.placeholder || ''
10322 input.name = this.name;
10325 input.cls += ' input-' + this.size;
10328 if (this.disabled) {
10329 input.disabled=true;
10332 var inputblock = input;
10334 if(this.hasFeedback && !this.allowBlank){
10338 cls: 'glyphicon form-control-feedback'
10341 if(this.removable && !this.editable && !this.tickable){
10343 cls : 'has-feedback',
10349 cls : 'roo-combo-removable-btn close'
10356 cls : 'has-feedback',
10365 if(this.removable && !this.editable && !this.tickable){
10367 cls : 'roo-removable',
10373 cls : 'roo-combo-removable-btn close'
10380 if (this.before || this.after) {
10383 cls : 'input-group',
10387 inputblock.cn.push({
10389 cls : 'input-group-addon input-group-prepend input-group-text',
10394 inputblock.cn.push(input);
10396 if(this.hasFeedback && !this.allowBlank){
10397 inputblock.cls += ' has-feedback';
10398 inputblock.cn.push(feedback);
10402 inputblock.cn.push({
10404 cls : 'input-group-addon input-group-append input-group-text',
10413 var ibwrap = inputblock;
10418 cls: 'roo-select2-choices',
10422 cls: 'roo-select2-search-field',
10434 cls: 'roo-select2-container input-group',
10439 cls: 'form-hidden-field'
10445 if(!this.multiple && this.showToggleBtn){
10451 if (this.caret != false) {
10454 cls: 'fa fa-' + this.caret
10461 cls : 'input-group-addon input-group-append input-group-text btn dropdown-toggle',
10466 cls: 'combobox-clear',
10480 combobox.cls += ' roo-select2-container-multi';
10484 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
10485 tooltip : 'This field is required'
10487 if (Roo.bootstrap.version == 4) {
10490 style : 'display:none'
10495 if (align ==='left' && this.fieldLabel.length) {
10497 cfg.cls += ' roo-form-group-label-left row';
10504 cls : 'control-label',
10505 html : this.fieldLabel
10517 var labelCfg = cfg.cn[1];
10518 var contentCfg = cfg.cn[2];
10520 if(this.indicatorpos == 'right'){
10525 cls : 'control-label',
10529 html : this.fieldLabel
10543 labelCfg = cfg.cn[0];
10544 contentCfg = cfg.cn[1];
10547 if(this.labelWidth > 12){
10548 labelCfg.style = "width: " + this.labelWidth + 'px';
10551 if(this.labelWidth < 13 && this.labelmd == 0){
10552 this.labelmd = this.labelWidth;
10555 if(this.labellg > 0){
10556 labelCfg.cls += ' col-lg-' + this.labellg;
10557 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
10560 if(this.labelmd > 0){
10561 labelCfg.cls += ' col-md-' + this.labelmd;
10562 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
10565 if(this.labelsm > 0){
10566 labelCfg.cls += ' col-sm-' + this.labelsm;
10567 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
10570 if(this.labelxs > 0){
10571 labelCfg.cls += ' col-xs-' + this.labelxs;
10572 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
10575 } else if ( this.fieldLabel.length) {
10576 // Roo.log(" label");
10581 //cls : 'input-group-addon',
10582 html : this.fieldLabel
10590 if(this.indicatorpos == 'right'){
10598 html : this.fieldLabel
10612 // Roo.log(" no label && no align");
10619 ['xs','sm','md','lg'].map(function(size){
10620 if (settings[size]) {
10621 cfg.cls += ' col-' + size + '-' + settings[size];
10632 onResize : function(w, h){
10633 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
10634 // if(typeof w == 'number'){
10635 // var x = w - this.trigger.getWidth();
10636 // this.inputEl().setWidth(this.adjustWidth('input', x));
10637 // this.trigger.setStyle('left', x+'px');
10642 adjustSize : Roo.BoxComponent.prototype.adjustSize,
10645 getResizeEl : function(){
10646 return this.inputEl();
10650 getPositionEl : function(){
10651 return this.inputEl();
10655 alignErrorIcon : function(){
10656 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
10660 initEvents : function(){
10664 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
10665 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
10666 if(!this.multiple && this.showToggleBtn){
10667 this.trigger = this.el.select('span.dropdown-toggle',true).first();
10668 if(this.hideTrigger){
10669 this.trigger.setDisplayed(false);
10671 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10675 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
10678 if(this.removable && !this.editable && !this.tickable){
10679 var close = this.closeTriggerEl();
10682 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
10683 close.on('click', this.removeBtnClick, this, close);
10687 //this.trigger.addClassOnOver('x-form-trigger-over');
10688 //this.trigger.addClassOnClick('x-form-trigger-click');
10691 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
10695 closeTriggerEl : function()
10697 var close = this.el.select('.roo-combo-removable-btn', true).first();
10698 return close ? close : false;
10701 removeBtnClick : function(e, h, el)
10703 e.preventDefault();
10705 if(this.fireEvent("remove", this) !== false){
10707 this.fireEvent("afterremove", this)
10711 createList : function()
10713 this.list = Roo.get(document.body).createChild({
10714 tag: Roo.bootstrap.version == 4 ? 'div' : 'ul',
10715 cls: 'typeahead typeahead-long dropdown-menu',
10716 style: 'display:none'
10719 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
10724 initTrigger : function(){
10729 onDestroy : function(){
10731 this.trigger.removeAllListeners();
10732 // this.trigger.remove();
10735 // this.wrap.remove();
10737 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
10741 onFocus : function(){
10742 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
10744 if(!this.mimicing){
10745 this.wrap.addClass('x-trigger-wrap-focus');
10746 this.mimicing = true;
10747 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
10748 if(this.monitorTab){
10749 this.el.on("keydown", this.checkTab, this);
10756 checkTab : function(e){
10757 if(e.getKey() == e.TAB){
10758 this.triggerBlur();
10763 onBlur : function(){
10768 mimicBlur : function(e, t){
10770 if(!this.wrap.contains(t) && this.validateBlur()){
10771 this.triggerBlur();
10777 triggerBlur : function(){
10778 this.mimicing = false;
10779 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
10780 if(this.monitorTab){
10781 this.el.un("keydown", this.checkTab, this);
10783 //this.wrap.removeClass('x-trigger-wrap-focus');
10784 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
10788 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
10789 validateBlur : function(e, t){
10794 onDisable : function(){
10795 this.inputEl().dom.disabled = true;
10796 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
10798 // this.wrap.addClass('x-item-disabled');
10803 onEnable : function(){
10804 this.inputEl().dom.disabled = false;
10805 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
10807 // this.el.removeClass('x-item-disabled');
10812 onShow : function(){
10813 var ae = this.getActionEl();
10816 ae.dom.style.display = '';
10817 ae.dom.style.visibility = 'visible';
10823 onHide : function(){
10824 var ae = this.getActionEl();
10825 ae.dom.style.display = 'none';
10829 * The function that should handle the trigger's click event. This method does nothing by default until overridden
10830 * by an implementing function.
10832 * @param {EventObject} e
10834 onTriggerClick : Roo.emptyFn
10838 * Ext JS Library 1.1.1
10839 * Copyright(c) 2006-2007, Ext JS, LLC.
10841 * Originally Released Under LGPL - original licence link has changed is not relivant.
10844 * <script type="text/javascript">
10849 * @class Roo.data.SortTypes
10851 * Defines the default sorting (casting?) comparison functions used when sorting data.
10853 Roo.data.SortTypes = {
10855 * Default sort that does nothing
10856 * @param {Mixed} s The value being converted
10857 * @return {Mixed} The comparison value
10859 none : function(s){
10864 * The regular expression used to strip tags
10868 stripTagsRE : /<\/?[^>]+>/gi,
10871 * Strips all HTML tags to sort on text only
10872 * @param {Mixed} s The value being converted
10873 * @return {String} The comparison value
10875 asText : function(s){
10876 return String(s).replace(this.stripTagsRE, "");
10880 * Strips all HTML tags to sort on text only - Case insensitive
10881 * @param {Mixed} s The value being converted
10882 * @return {String} The comparison value
10884 asUCText : function(s){
10885 return String(s).toUpperCase().replace(this.stripTagsRE, "");
10889 * Case insensitive string
10890 * @param {Mixed} s The value being converted
10891 * @return {String} The comparison value
10893 asUCString : function(s) {
10894 return String(s).toUpperCase();
10899 * @param {Mixed} s The value being converted
10900 * @return {Number} The comparison value
10902 asDate : function(s) {
10906 if(s instanceof Date){
10907 return s.getTime();
10909 return Date.parse(String(s));
10914 * @param {Mixed} s The value being converted
10915 * @return {Float} The comparison value
10917 asFloat : function(s) {
10918 var val = parseFloat(String(s).replace(/,/g, ""));
10927 * @param {Mixed} s The value being converted
10928 * @return {Number} The comparison value
10930 asInt : function(s) {
10931 var val = parseInt(String(s).replace(/,/g, ""));
10939 * Ext JS Library 1.1.1
10940 * Copyright(c) 2006-2007, Ext JS, LLC.
10942 * Originally Released Under LGPL - original licence link has changed is not relivant.
10945 * <script type="text/javascript">
10949 * @class Roo.data.Record
10950 * Instances of this class encapsulate both record <em>definition</em> information, and record
10951 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
10952 * to access Records cached in an {@link Roo.data.Store} object.<br>
10954 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
10955 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
10958 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
10960 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
10961 * {@link #create}. The parameters are the same.
10962 * @param {Array} data An associative Array of data values keyed by the field name.
10963 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
10964 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
10965 * not specified an integer id is generated.
10967 Roo.data.Record = function(data, id){
10968 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
10973 * Generate a constructor for a specific record layout.
10974 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
10975 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
10976 * Each field definition object may contain the following properties: <ul>
10977 * <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,
10978 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
10979 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
10980 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
10981 * is being used, then this is a string containing the javascript expression to reference the data relative to
10982 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
10983 * to the data item relative to the record element. If the mapping expression is the same as the field name,
10984 * this may be omitted.</p></li>
10985 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
10986 * <ul><li>auto (Default, implies no conversion)</li>
10991 * <li>date</li></ul></p></li>
10992 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
10993 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
10994 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
10995 * by the Reader into an object that will be stored in the Record. It is passed the
10996 * following parameters:<ul>
10997 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
10999 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
11001 * <br>usage:<br><pre><code>
11002 var TopicRecord = Roo.data.Record.create(
11003 {name: 'title', mapping: 'topic_title'},
11004 {name: 'author', mapping: 'username'},
11005 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
11006 {name: 'lastPost', mapping: 'post_time', type: 'date'},
11007 {name: 'lastPoster', mapping: 'user2'},
11008 {name: 'excerpt', mapping: 'post_text'}
11011 var myNewRecord = new TopicRecord({
11012 title: 'Do my job please',
11015 lastPost: new Date(),
11016 lastPoster: 'Animal',
11017 excerpt: 'No way dude!'
11019 myStore.add(myNewRecord);
11024 Roo.data.Record.create = function(o){
11025 var f = function(){
11026 f.superclass.constructor.apply(this, arguments);
11028 Roo.extend(f, Roo.data.Record);
11029 var p = f.prototype;
11030 p.fields = new Roo.util.MixedCollection(false, function(field){
11033 for(var i = 0, len = o.length; i < len; i++){
11034 p.fields.add(new Roo.data.Field(o[i]));
11036 f.getField = function(name){
11037 return p.fields.get(name);
11042 Roo.data.Record.AUTO_ID = 1000;
11043 Roo.data.Record.EDIT = 'edit';
11044 Roo.data.Record.REJECT = 'reject';
11045 Roo.data.Record.COMMIT = 'commit';
11047 Roo.data.Record.prototype = {
11049 * Readonly flag - true if this record has been modified.
11058 join : function(store){
11059 this.store = store;
11063 * Set the named field to the specified value.
11064 * @param {String} name The name of the field to set.
11065 * @param {Object} value The value to set the field to.
11067 set : function(name, value){
11068 if(this.data[name] == value){
11072 if(!this.modified){
11073 this.modified = {};
11075 if(typeof this.modified[name] == 'undefined'){
11076 this.modified[name] = this.data[name];
11078 this.data[name] = value;
11079 if(!this.editing && this.store){
11080 this.store.afterEdit(this);
11085 * Get the value of the named field.
11086 * @param {String} name The name of the field to get the value of.
11087 * @return {Object} The value of the field.
11089 get : function(name){
11090 return this.data[name];
11094 beginEdit : function(){
11095 this.editing = true;
11096 this.modified = {};
11100 cancelEdit : function(){
11101 this.editing = false;
11102 delete this.modified;
11106 endEdit : function(){
11107 this.editing = false;
11108 if(this.dirty && this.store){
11109 this.store.afterEdit(this);
11114 * Usually called by the {@link Roo.data.Store} which owns the Record.
11115 * Rejects all changes made to the Record since either creation, or the last commit operation.
11116 * Modified fields are reverted to their original values.
11118 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
11119 * of reject operations.
11121 reject : function(){
11122 var m = this.modified;
11124 if(typeof m[n] != "function"){
11125 this.data[n] = m[n];
11128 this.dirty = false;
11129 delete this.modified;
11130 this.editing = false;
11132 this.store.afterReject(this);
11137 * Usually called by the {@link Roo.data.Store} which owns the Record.
11138 * Commits all changes made to the Record since either creation, or the last commit operation.
11140 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
11141 * of commit operations.
11143 commit : function(){
11144 this.dirty = false;
11145 delete this.modified;
11146 this.editing = false;
11148 this.store.afterCommit(this);
11153 hasError : function(){
11154 return this.error != null;
11158 clearError : function(){
11163 * Creates a copy of this record.
11164 * @param {String} id (optional) A new record id if you don't want to use this record's id
11167 copy : function(newId) {
11168 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
11172 * Ext JS Library 1.1.1
11173 * Copyright(c) 2006-2007, Ext JS, LLC.
11175 * Originally Released Under LGPL - original licence link has changed is not relivant.
11178 * <script type="text/javascript">
11184 * @class Roo.data.Store
11185 * @extends Roo.util.Observable
11186 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
11187 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
11189 * 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
11190 * has no knowledge of the format of the data returned by the Proxy.<br>
11192 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
11193 * instances from the data object. These records are cached and made available through accessor functions.
11195 * Creates a new Store.
11196 * @param {Object} config A config object containing the objects needed for the Store to access data,
11197 * and read the data into Records.
11199 Roo.data.Store = function(config){
11200 this.data = new Roo.util.MixedCollection(false);
11201 this.data.getKey = function(o){
11204 this.baseParams = {};
11206 this.paramNames = {
11211 "multisort" : "_multisort"
11214 if(config && config.data){
11215 this.inlineData = config.data;
11216 delete config.data;
11219 Roo.apply(this, config);
11221 if(this.reader){ // reader passed
11222 this.reader = Roo.factory(this.reader, Roo.data);
11223 this.reader.xmodule = this.xmodule || false;
11224 if(!this.recordType){
11225 this.recordType = this.reader.recordType;
11227 if(this.reader.onMetaChange){
11228 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
11232 if(this.recordType){
11233 this.fields = this.recordType.prototype.fields;
11235 this.modified = [];
11239 * @event datachanged
11240 * Fires when the data cache has changed, and a widget which is using this Store
11241 * as a Record cache should refresh its view.
11242 * @param {Store} this
11244 datachanged : true,
11246 * @event metachange
11247 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
11248 * @param {Store} this
11249 * @param {Object} meta The JSON metadata
11254 * Fires when Records have been added to the Store
11255 * @param {Store} this
11256 * @param {Roo.data.Record[]} records The array of Records added
11257 * @param {Number} index The index at which the record(s) were added
11262 * Fires when a Record has been removed from the Store
11263 * @param {Store} this
11264 * @param {Roo.data.Record} record The Record that was removed
11265 * @param {Number} index The index at which the record was removed
11270 * Fires when a Record has been updated
11271 * @param {Store} this
11272 * @param {Roo.data.Record} record The Record that was updated
11273 * @param {String} operation The update operation being performed. Value may be one of:
11275 Roo.data.Record.EDIT
11276 Roo.data.Record.REJECT
11277 Roo.data.Record.COMMIT
11283 * Fires when the data cache has been cleared.
11284 * @param {Store} this
11288 * @event beforeload
11289 * Fires before a request is made for a new data object. If the beforeload handler returns false
11290 * the load action will be canceled.
11291 * @param {Store} this
11292 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11296 * @event beforeloadadd
11297 * Fires after a new set of Records has been loaded.
11298 * @param {Store} this
11299 * @param {Roo.data.Record[]} records The Records that were loaded
11300 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11302 beforeloadadd : true,
11305 * Fires after a new set of Records has been loaded, before they are added to the store.
11306 * @param {Store} this
11307 * @param {Roo.data.Record[]} records The Records that were loaded
11308 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11309 * @params {Object} return from reader
11313 * @event loadexception
11314 * Fires if an exception occurs in the Proxy during loading.
11315 * Called with the signature of the Proxy's "loadexception" event.
11316 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
11319 * @param {Object} return from JsonData.reader() - success, totalRecords, records
11320 * @param {Object} load options
11321 * @param {Object} jsonData from your request (normally this contains the Exception)
11323 loadexception : true
11327 this.proxy = Roo.factory(this.proxy, Roo.data);
11328 this.proxy.xmodule = this.xmodule || false;
11329 this.relayEvents(this.proxy, ["loadexception"]);
11331 this.sortToggle = {};
11332 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
11334 Roo.data.Store.superclass.constructor.call(this);
11336 if(this.inlineData){
11337 this.loadData(this.inlineData);
11338 delete this.inlineData;
11342 Roo.extend(Roo.data.Store, Roo.util.Observable, {
11344 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
11345 * without a remote query - used by combo/forms at present.
11349 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
11352 * @cfg {Array} data Inline data to be loaded when the store is initialized.
11355 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
11356 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
11359 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
11360 * on any HTTP request
11363 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
11366 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
11370 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
11371 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
11373 remoteSort : false,
11376 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
11377 * loaded or when a record is removed. (defaults to false).
11379 pruneModifiedRecords : false,
11382 lastOptions : null,
11385 * Add Records to the Store and fires the add event.
11386 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11388 add : function(records){
11389 records = [].concat(records);
11390 for(var i = 0, len = records.length; i < len; i++){
11391 records[i].join(this);
11393 var index = this.data.length;
11394 this.data.addAll(records);
11395 this.fireEvent("add", this, records, index);
11399 * Remove a Record from the Store and fires the remove event.
11400 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
11402 remove : function(record){
11403 var index = this.data.indexOf(record);
11404 this.data.removeAt(index);
11406 if(this.pruneModifiedRecords){
11407 this.modified.remove(record);
11409 this.fireEvent("remove", this, record, index);
11413 * Remove all Records from the Store and fires the clear event.
11415 removeAll : function(){
11417 if(this.pruneModifiedRecords){
11418 this.modified = [];
11420 this.fireEvent("clear", this);
11424 * Inserts Records to the Store at the given index and fires the add event.
11425 * @param {Number} index The start index at which to insert the passed Records.
11426 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11428 insert : function(index, records){
11429 records = [].concat(records);
11430 for(var i = 0, len = records.length; i < len; i++){
11431 this.data.insert(index, records[i]);
11432 records[i].join(this);
11434 this.fireEvent("add", this, records, index);
11438 * Get the index within the cache of the passed Record.
11439 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
11440 * @return {Number} The index of the passed Record. Returns -1 if not found.
11442 indexOf : function(record){
11443 return this.data.indexOf(record);
11447 * Get the index within the cache of the Record with the passed id.
11448 * @param {String} id The id of the Record to find.
11449 * @return {Number} The index of the Record. Returns -1 if not found.
11451 indexOfId : function(id){
11452 return this.data.indexOfKey(id);
11456 * Get the Record with the specified id.
11457 * @param {String} id The id of the Record to find.
11458 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
11460 getById : function(id){
11461 return this.data.key(id);
11465 * Get the Record at the specified index.
11466 * @param {Number} index The index of the Record to find.
11467 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
11469 getAt : function(index){
11470 return this.data.itemAt(index);
11474 * Returns a range of Records between specified indices.
11475 * @param {Number} startIndex (optional) The starting index (defaults to 0)
11476 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
11477 * @return {Roo.data.Record[]} An array of Records
11479 getRange : function(start, end){
11480 return this.data.getRange(start, end);
11484 storeOptions : function(o){
11485 o = Roo.apply({}, o);
11488 this.lastOptions = o;
11492 * Loads the Record cache from the configured Proxy using the configured Reader.
11494 * If using remote paging, then the first load call must specify the <em>start</em>
11495 * and <em>limit</em> properties in the options.params property to establish the initial
11496 * position within the dataset, and the number of Records to cache on each read from the Proxy.
11498 * <strong>It is important to note that for remote data sources, loading is asynchronous,
11499 * and this call will return before the new data has been loaded. Perform any post-processing
11500 * in a callback function, or in a "load" event handler.</strong>
11502 * @param {Object} options An object containing properties which control loading options:<ul>
11503 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
11504 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
11505 * passed the following arguments:<ul>
11506 * <li>r : Roo.data.Record[]</li>
11507 * <li>options: Options object from the load call</li>
11508 * <li>success: Boolean success indicator</li></ul></li>
11509 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
11510 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
11513 load : function(options){
11514 options = options || {};
11515 if(this.fireEvent("beforeload", this, options) !== false){
11516 this.storeOptions(options);
11517 var p = Roo.apply(options.params || {}, this.baseParams);
11518 // if meta was not loaded from remote source.. try requesting it.
11519 if (!this.reader.metaFromRemote) {
11520 p._requestMeta = 1;
11522 if(this.sortInfo && this.remoteSort){
11523 var pn = this.paramNames;
11524 p[pn["sort"]] = this.sortInfo.field;
11525 p[pn["dir"]] = this.sortInfo.direction;
11527 if (this.multiSort) {
11528 var pn = this.paramNames;
11529 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
11532 this.proxy.load(p, this.reader, this.loadRecords, this, options);
11537 * Reloads the Record cache from the configured Proxy using the configured Reader and
11538 * the options from the last load operation performed.
11539 * @param {Object} options (optional) An object containing properties which may override the options
11540 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
11541 * the most recently used options are reused).
11543 reload : function(options){
11544 this.load(Roo.applyIf(options||{}, this.lastOptions));
11548 // Called as a callback by the Reader during a load operation.
11549 loadRecords : function(o, options, success){
11550 if(!o || success === false){
11551 if(success !== false){
11552 this.fireEvent("load", this, [], options, o);
11554 if(options.callback){
11555 options.callback.call(options.scope || this, [], options, false);
11559 // if data returned failure - throw an exception.
11560 if (o.success === false) {
11561 // show a message if no listener is registered.
11562 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
11563 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
11565 // loadmask wil be hooked into this..
11566 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
11569 var r = o.records, t = o.totalRecords || r.length;
11571 this.fireEvent("beforeloadadd", this, r, options, o);
11573 if(!options || options.add !== true){
11574 if(this.pruneModifiedRecords){
11575 this.modified = [];
11577 for(var i = 0, len = r.length; i < len; i++){
11581 this.data = this.snapshot;
11582 delete this.snapshot;
11585 this.data.addAll(r);
11586 this.totalLength = t;
11588 this.fireEvent("datachanged", this);
11590 this.totalLength = Math.max(t, this.data.length+r.length);
11594 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
11596 var e = new Roo.data.Record({});
11598 e.set(this.parent.displayField, this.parent.emptyTitle);
11599 e.set(this.parent.valueField, '');
11604 this.fireEvent("load", this, r, options, o);
11605 if(options.callback){
11606 options.callback.call(options.scope || this, r, options, true);
11612 * Loads data from a passed data block. A Reader which understands the format of the data
11613 * must have been configured in the constructor.
11614 * @param {Object} data The data block from which to read the Records. The format of the data expected
11615 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
11616 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
11618 loadData : function(o, append){
11619 var r = this.reader.readRecords(o);
11620 this.loadRecords(r, {add: append}, true);
11624 * Gets the number of cached records.
11626 * <em>If using paging, this may not be the total size of the dataset. If the data object
11627 * used by the Reader contains the dataset size, then the getTotalCount() function returns
11628 * the data set size</em>
11630 getCount : function(){
11631 return this.data.length || 0;
11635 * Gets the total number of records in the dataset as returned by the server.
11637 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
11638 * the dataset size</em>
11640 getTotalCount : function(){
11641 return this.totalLength || 0;
11645 * Returns the sort state of the Store as an object with two properties:
11647 field {String} The name of the field by which the Records are sorted
11648 direction {String} The sort order, "ASC" or "DESC"
11651 getSortState : function(){
11652 return this.sortInfo;
11656 applySort : function(){
11657 if(this.sortInfo && !this.remoteSort){
11658 var s = this.sortInfo, f = s.field;
11659 var st = this.fields.get(f).sortType;
11660 var fn = function(r1, r2){
11661 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
11662 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
11664 this.data.sort(s.direction, fn);
11665 if(this.snapshot && this.snapshot != this.data){
11666 this.snapshot.sort(s.direction, fn);
11672 * Sets the default sort column and order to be used by the next load operation.
11673 * @param {String} fieldName The name of the field to sort by.
11674 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11676 setDefaultSort : function(field, dir){
11677 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
11681 * Sort the Records.
11682 * If remote sorting is used, the sort is performed on the server, and the cache is
11683 * reloaded. If local sorting is used, the cache is sorted internally.
11684 * @param {String} fieldName The name of the field to sort by.
11685 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11687 sort : function(fieldName, dir){
11688 var f = this.fields.get(fieldName);
11690 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
11692 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
11693 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
11698 this.sortToggle[f.name] = dir;
11699 this.sortInfo = {field: f.name, direction: dir};
11700 if(!this.remoteSort){
11702 this.fireEvent("datachanged", this);
11704 this.load(this.lastOptions);
11709 * Calls the specified function for each of the Records in the cache.
11710 * @param {Function} fn The function to call. The Record is passed as the first parameter.
11711 * Returning <em>false</em> aborts and exits the iteration.
11712 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
11714 each : function(fn, scope){
11715 this.data.each(fn, scope);
11719 * Gets all records modified since the last commit. Modified records are persisted across load operations
11720 * (e.g., during paging).
11721 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
11723 getModifiedRecords : function(){
11724 return this.modified;
11728 createFilterFn : function(property, value, anyMatch){
11729 if(!value.exec){ // not a regex
11730 value = String(value);
11731 if(value.length == 0){
11734 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
11736 return function(r){
11737 return value.test(r.data[property]);
11742 * Sums the value of <i>property</i> for each record between start and end and returns the result.
11743 * @param {String} property A field on your records
11744 * @param {Number} start The record index to start at (defaults to 0)
11745 * @param {Number} end The last record index to include (defaults to length - 1)
11746 * @return {Number} The sum
11748 sum : function(property, start, end){
11749 var rs = this.data.items, v = 0;
11750 start = start || 0;
11751 end = (end || end === 0) ? end : rs.length-1;
11753 for(var i = start; i <= end; i++){
11754 v += (rs[i].data[property] || 0);
11760 * Filter the records by a specified property.
11761 * @param {String} field A field on your records
11762 * @param {String/RegExp} value Either a string that the field
11763 * should start with or a RegExp to test against the field
11764 * @param {Boolean} anyMatch True to match any part not just the beginning
11766 filter : function(property, value, anyMatch){
11767 var fn = this.createFilterFn(property, value, anyMatch);
11768 return fn ? this.filterBy(fn) : this.clearFilter();
11772 * Filter by a function. The specified function will be called with each
11773 * record in this data source. If the function returns true the record is included,
11774 * otherwise it is filtered.
11775 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11776 * @param {Object} scope (optional) The scope of the function (defaults to this)
11778 filterBy : function(fn, scope){
11779 this.snapshot = this.snapshot || this.data;
11780 this.data = this.queryBy(fn, scope||this);
11781 this.fireEvent("datachanged", this);
11785 * Query the records by a specified property.
11786 * @param {String} field A field on your records
11787 * @param {String/RegExp} value Either a string that the field
11788 * should start with or a RegExp to test against the field
11789 * @param {Boolean} anyMatch True to match any part not just the beginning
11790 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11792 query : function(property, value, anyMatch){
11793 var fn = this.createFilterFn(property, value, anyMatch);
11794 return fn ? this.queryBy(fn) : this.data.clone();
11798 * Query by a function. The specified function will be called with each
11799 * record in this data source. If the function returns true the record is included
11801 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11802 * @param {Object} scope (optional) The scope of the function (defaults to this)
11803 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11805 queryBy : function(fn, scope){
11806 var data = this.snapshot || this.data;
11807 return data.filterBy(fn, scope||this);
11811 * Collects unique values for a particular dataIndex from this store.
11812 * @param {String} dataIndex The property to collect
11813 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
11814 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
11815 * @return {Array} An array of the unique values
11817 collect : function(dataIndex, allowNull, bypassFilter){
11818 var d = (bypassFilter === true && this.snapshot) ?
11819 this.snapshot.items : this.data.items;
11820 var v, sv, r = [], l = {};
11821 for(var i = 0, len = d.length; i < len; i++){
11822 v = d[i].data[dataIndex];
11824 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
11833 * Revert to a view of the Record cache with no filtering applied.
11834 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
11836 clearFilter : function(suppressEvent){
11837 if(this.snapshot && this.snapshot != this.data){
11838 this.data = this.snapshot;
11839 delete this.snapshot;
11840 if(suppressEvent !== true){
11841 this.fireEvent("datachanged", this);
11847 afterEdit : function(record){
11848 if(this.modified.indexOf(record) == -1){
11849 this.modified.push(record);
11851 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
11855 afterReject : function(record){
11856 this.modified.remove(record);
11857 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
11861 afterCommit : function(record){
11862 this.modified.remove(record);
11863 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
11867 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
11868 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
11870 commitChanges : function(){
11871 var m = this.modified.slice(0);
11872 this.modified = [];
11873 for(var i = 0, len = m.length; i < len; i++){
11879 * Cancel outstanding changes on all changed records.
11881 rejectChanges : function(){
11882 var m = this.modified.slice(0);
11883 this.modified = [];
11884 for(var i = 0, len = m.length; i < len; i++){
11889 onMetaChange : function(meta, rtype, o){
11890 this.recordType = rtype;
11891 this.fields = rtype.prototype.fields;
11892 delete this.snapshot;
11893 this.sortInfo = meta.sortInfo || this.sortInfo;
11894 this.modified = [];
11895 this.fireEvent('metachange', this, this.reader.meta);
11898 moveIndex : function(data, type)
11900 var index = this.indexOf(data);
11902 var newIndex = index + type;
11906 this.insert(newIndex, data);
11911 * Ext JS Library 1.1.1
11912 * Copyright(c) 2006-2007, Ext JS, LLC.
11914 * Originally Released Under LGPL - original licence link has changed is not relivant.
11917 * <script type="text/javascript">
11921 * @class Roo.data.SimpleStore
11922 * @extends Roo.data.Store
11923 * Small helper class to make creating Stores from Array data easier.
11924 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
11925 * @cfg {Array} fields An array of field definition objects, or field name strings.
11926 * @cfg {Array} data The multi-dimensional array of data
11928 * @param {Object} config
11930 Roo.data.SimpleStore = function(config){
11931 Roo.data.SimpleStore.superclass.constructor.call(this, {
11933 reader: new Roo.data.ArrayReader({
11936 Roo.data.Record.create(config.fields)
11938 proxy : new Roo.data.MemoryProxy(config.data)
11942 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
11944 * Ext JS Library 1.1.1
11945 * Copyright(c) 2006-2007, Ext JS, LLC.
11947 * Originally Released Under LGPL - original licence link has changed is not relivant.
11950 * <script type="text/javascript">
11955 * @extends Roo.data.Store
11956 * @class Roo.data.JsonStore
11957 * Small helper class to make creating Stores for JSON data easier. <br/>
11959 var store = new Roo.data.JsonStore({
11960 url: 'get-images.php',
11962 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
11965 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
11966 * JsonReader and HttpProxy (unless inline data is provided).</b>
11967 * @cfg {Array} fields An array of field definition objects, or field name strings.
11969 * @param {Object} config
11971 Roo.data.JsonStore = function(c){
11972 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
11973 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
11974 reader: new Roo.data.JsonReader(c, c.fields)
11977 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
11979 * Ext JS Library 1.1.1
11980 * Copyright(c) 2006-2007, Ext JS, LLC.
11982 * Originally Released Under LGPL - original licence link has changed is not relivant.
11985 * <script type="text/javascript">
11989 Roo.data.Field = function(config){
11990 if(typeof config == "string"){
11991 config = {name: config};
11993 Roo.apply(this, config);
11996 this.type = "auto";
11999 var st = Roo.data.SortTypes;
12000 // named sortTypes are supported, here we look them up
12001 if(typeof this.sortType == "string"){
12002 this.sortType = st[this.sortType];
12005 // set default sortType for strings and dates
12006 if(!this.sortType){
12009 this.sortType = st.asUCString;
12012 this.sortType = st.asDate;
12015 this.sortType = st.none;
12020 var stripRe = /[\$,%]/g;
12022 // prebuilt conversion function for this field, instead of
12023 // switching every time we're reading a value
12025 var cv, dateFormat = this.dateFormat;
12030 cv = function(v){ return v; };
12033 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
12037 return v !== undefined && v !== null && v !== '' ?
12038 parseInt(String(v).replace(stripRe, ""), 10) : '';
12043 return v !== undefined && v !== null && v !== '' ?
12044 parseFloat(String(v).replace(stripRe, ""), 10) : '';
12049 cv = function(v){ return v === true || v === "true" || v == 1; };
12056 if(v instanceof Date){
12060 if(dateFormat == "timestamp"){
12061 return new Date(v*1000);
12063 return Date.parseDate(v, dateFormat);
12065 var parsed = Date.parse(v);
12066 return parsed ? new Date(parsed) : null;
12075 Roo.data.Field.prototype = {
12083 * Ext JS Library 1.1.1
12084 * Copyright(c) 2006-2007, Ext JS, LLC.
12086 * Originally Released Under LGPL - original licence link has changed is not relivant.
12089 * <script type="text/javascript">
12092 // Base class for reading structured data from a data source. This class is intended to be
12093 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
12096 * @class Roo.data.DataReader
12097 * Base class for reading structured data from a data source. This class is intended to be
12098 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
12101 Roo.data.DataReader = function(meta, recordType){
12105 this.recordType = recordType instanceof Array ?
12106 Roo.data.Record.create(recordType) : recordType;
12109 Roo.data.DataReader.prototype = {
12111 * Create an empty record
12112 * @param {Object} data (optional) - overlay some values
12113 * @return {Roo.data.Record} record created.
12115 newRow : function(d) {
12117 this.recordType.prototype.fields.each(function(c) {
12119 case 'int' : da[c.name] = 0; break;
12120 case 'date' : da[c.name] = new Date(); break;
12121 case 'float' : da[c.name] = 0.0; break;
12122 case 'boolean' : da[c.name] = false; break;
12123 default : da[c.name] = ""; break;
12127 return new this.recordType(Roo.apply(da, d));
12132 * Ext JS Library 1.1.1
12133 * Copyright(c) 2006-2007, Ext JS, LLC.
12135 * Originally Released Under LGPL - original licence link has changed is not relivant.
12138 * <script type="text/javascript">
12142 * @class Roo.data.DataProxy
12143 * @extends Roo.data.Observable
12144 * This class is an abstract base class for implementations which provide retrieval of
12145 * unformatted data objects.<br>
12147 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
12148 * (of the appropriate type which knows how to parse the data object) to provide a block of
12149 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
12151 * Custom implementations must implement the load method as described in
12152 * {@link Roo.data.HttpProxy#load}.
12154 Roo.data.DataProxy = function(){
12157 * @event beforeload
12158 * Fires before a network request is made to retrieve a data object.
12159 * @param {Object} This DataProxy object.
12160 * @param {Object} params The params parameter to the load function.
12165 * Fires before the load method's callback is called.
12166 * @param {Object} This DataProxy object.
12167 * @param {Object} o The data object.
12168 * @param {Object} arg The callback argument object passed to the load function.
12172 * @event loadexception
12173 * Fires if an Exception occurs during data retrieval.
12174 * @param {Object} This DataProxy object.
12175 * @param {Object} o The data object.
12176 * @param {Object} arg The callback argument object passed to the load function.
12177 * @param {Object} e The Exception.
12179 loadexception : true
12181 Roo.data.DataProxy.superclass.constructor.call(this);
12184 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
12187 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
12191 * Ext JS Library 1.1.1
12192 * Copyright(c) 2006-2007, Ext JS, LLC.
12194 * Originally Released Under LGPL - original licence link has changed is not relivant.
12197 * <script type="text/javascript">
12200 * @class Roo.data.MemoryProxy
12201 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
12202 * to the Reader when its load method is called.
12204 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
12206 Roo.data.MemoryProxy = function(data){
12210 Roo.data.MemoryProxy.superclass.constructor.call(this);
12214 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
12217 * Load data from the requested source (in this case an in-memory
12218 * data object passed to the constructor), read the data object into
12219 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12220 * process that block using the passed callback.
12221 * @param {Object} params This parameter is not used by the MemoryProxy class.
12222 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12223 * object into a block of Roo.data.Records.
12224 * @param {Function} callback The function into which to pass the block of Roo.data.records.
12225 * The function must be passed <ul>
12226 * <li>The Record block object</li>
12227 * <li>The "arg" argument from the load function</li>
12228 * <li>A boolean success indicator</li>
12230 * @param {Object} scope The scope in which to call the callback
12231 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12233 load : function(params, reader, callback, scope, arg){
12234 params = params || {};
12237 result = reader.readRecords(this.data);
12239 this.fireEvent("loadexception", this, arg, null, e);
12240 callback.call(scope, null, arg, false);
12243 callback.call(scope, result, arg, true);
12247 update : function(params, records){
12252 * Ext JS Library 1.1.1
12253 * Copyright(c) 2006-2007, Ext JS, LLC.
12255 * Originally Released Under LGPL - original licence link has changed is not relivant.
12258 * <script type="text/javascript">
12261 * @class Roo.data.HttpProxy
12262 * @extends Roo.data.DataProxy
12263 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
12264 * configured to reference a certain URL.<br><br>
12266 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
12267 * from which the running page was served.<br><br>
12269 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
12271 * Be aware that to enable the browser to parse an XML document, the server must set
12272 * the Content-Type header in the HTTP response to "text/xml".
12274 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
12275 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
12276 * will be used to make the request.
12278 Roo.data.HttpProxy = function(conn){
12279 Roo.data.HttpProxy.superclass.constructor.call(this);
12280 // is conn a conn config or a real conn?
12282 this.useAjax = !conn || !conn.events;
12286 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
12287 // thse are take from connection...
12290 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
12293 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
12294 * extra parameters to each request made by this object. (defaults to undefined)
12297 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
12298 * to each request made by this object. (defaults to undefined)
12301 * @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)
12304 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
12307 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
12313 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
12317 * Return the {@link Roo.data.Connection} object being used by this Proxy.
12318 * @return {Connection} The Connection object. This object may be used to subscribe to events on
12319 * a finer-grained basis than the DataProxy events.
12321 getConnection : function(){
12322 return this.useAjax ? Roo.Ajax : this.conn;
12326 * Load data from the configured {@link Roo.data.Connection}, read the data object into
12327 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
12328 * process that block using the passed callback.
12329 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12330 * for the request to the remote server.
12331 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12332 * object into a block of Roo.data.Records.
12333 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12334 * The function must be passed <ul>
12335 * <li>The Record block object</li>
12336 * <li>The "arg" argument from the load function</li>
12337 * <li>A boolean success indicator</li>
12339 * @param {Object} scope The scope in which to call the callback
12340 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12342 load : function(params, reader, callback, scope, arg){
12343 if(this.fireEvent("beforeload", this, params) !== false){
12345 params : params || {},
12347 callback : callback,
12352 callback : this.loadResponse,
12356 Roo.applyIf(o, this.conn);
12357 if(this.activeRequest){
12358 Roo.Ajax.abort(this.activeRequest);
12360 this.activeRequest = Roo.Ajax.request(o);
12362 this.conn.request(o);
12365 callback.call(scope||this, null, arg, false);
12370 loadResponse : function(o, success, response){
12371 delete this.activeRequest;
12373 this.fireEvent("loadexception", this, o, response);
12374 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12379 result = o.reader.read(response);
12381 this.fireEvent("loadexception", this, o, response, e);
12382 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12386 this.fireEvent("load", this, o, o.request.arg);
12387 o.request.callback.call(o.request.scope, result, o.request.arg, true);
12391 update : function(dataSet){
12396 updateResponse : function(dataSet){
12401 * Ext JS Library 1.1.1
12402 * Copyright(c) 2006-2007, Ext JS, LLC.
12404 * Originally Released Under LGPL - original licence link has changed is not relivant.
12407 * <script type="text/javascript">
12411 * @class Roo.data.ScriptTagProxy
12412 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
12413 * other than the originating domain of the running page.<br><br>
12415 * <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
12416 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
12418 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
12419 * source code that is used as the source inside a <script> tag.<br><br>
12421 * In order for the browser to process the returned data, the server must wrap the data object
12422 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
12423 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
12424 * depending on whether the callback name was passed:
12427 boolean scriptTag = false;
12428 String cb = request.getParameter("callback");
12431 response.setContentType("text/javascript");
12433 response.setContentType("application/x-json");
12435 Writer out = response.getWriter();
12437 out.write(cb + "(");
12439 out.print(dataBlock.toJsonString());
12446 * @param {Object} config A configuration object.
12448 Roo.data.ScriptTagProxy = function(config){
12449 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
12450 Roo.apply(this, config);
12451 this.head = document.getElementsByTagName("head")[0];
12454 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
12456 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
12458 * @cfg {String} url The URL from which to request the data object.
12461 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
12465 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
12466 * the server the name of the callback function set up by the load call to process the returned data object.
12467 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
12468 * javascript output which calls this named function passing the data object as its only parameter.
12470 callbackParam : "callback",
12472 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
12473 * name to the request.
12478 * Load data from the configured URL, read the data object into
12479 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12480 * process that block using the passed callback.
12481 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12482 * for the request to the remote server.
12483 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12484 * object into a block of Roo.data.Records.
12485 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12486 * The function must be passed <ul>
12487 * <li>The Record block object</li>
12488 * <li>The "arg" argument from the load function</li>
12489 * <li>A boolean success indicator</li>
12491 * @param {Object} scope The scope in which to call the callback
12492 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12494 load : function(params, reader, callback, scope, arg){
12495 if(this.fireEvent("beforeload", this, params) !== false){
12497 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
12499 var url = this.url;
12500 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
12502 url += "&_dc=" + (new Date().getTime());
12504 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
12507 cb : "stcCallback"+transId,
12508 scriptId : "stcScript"+transId,
12512 callback : callback,
12518 window[trans.cb] = function(o){
12519 conn.handleResponse(o, trans);
12522 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
12524 if(this.autoAbort !== false){
12528 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
12530 var script = document.createElement("script");
12531 script.setAttribute("src", url);
12532 script.setAttribute("type", "text/javascript");
12533 script.setAttribute("id", trans.scriptId);
12534 this.head.appendChild(script);
12536 this.trans = trans;
12538 callback.call(scope||this, null, arg, false);
12543 isLoading : function(){
12544 return this.trans ? true : false;
12548 * Abort the current server request.
12550 abort : function(){
12551 if(this.isLoading()){
12552 this.destroyTrans(this.trans);
12557 destroyTrans : function(trans, isLoaded){
12558 this.head.removeChild(document.getElementById(trans.scriptId));
12559 clearTimeout(trans.timeoutId);
12561 window[trans.cb] = undefined;
12563 delete window[trans.cb];
12566 // if hasn't been loaded, wait for load to remove it to prevent script error
12567 window[trans.cb] = function(){
12568 window[trans.cb] = undefined;
12570 delete window[trans.cb];
12577 handleResponse : function(o, trans){
12578 this.trans = false;
12579 this.destroyTrans(trans, true);
12582 result = trans.reader.readRecords(o);
12584 this.fireEvent("loadexception", this, o, trans.arg, e);
12585 trans.callback.call(trans.scope||window, null, trans.arg, false);
12588 this.fireEvent("load", this, o, trans.arg);
12589 trans.callback.call(trans.scope||window, result, trans.arg, true);
12593 handleFailure : function(trans){
12594 this.trans = false;
12595 this.destroyTrans(trans, false);
12596 this.fireEvent("loadexception", this, null, trans.arg);
12597 trans.callback.call(trans.scope||window, null, trans.arg, false);
12601 * Ext JS Library 1.1.1
12602 * Copyright(c) 2006-2007, Ext JS, LLC.
12604 * Originally Released Under LGPL - original licence link has changed is not relivant.
12607 * <script type="text/javascript">
12611 * @class Roo.data.JsonReader
12612 * @extends Roo.data.DataReader
12613 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
12614 * based on mappings in a provided Roo.data.Record constructor.
12616 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
12617 * in the reply previously.
12622 var RecordDef = Roo.data.Record.create([
12623 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
12624 {name: 'occupation'} // This field will use "occupation" as the mapping.
12626 var myReader = new Roo.data.JsonReader({
12627 totalProperty: "results", // The property which contains the total dataset size (optional)
12628 root: "rows", // The property which contains an Array of row objects
12629 id: "id" // The property within each row object that provides an ID for the record (optional)
12633 * This would consume a JSON file like this:
12635 { 'results': 2, 'rows': [
12636 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
12637 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
12640 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
12641 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
12642 * paged from the remote server.
12643 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
12644 * @cfg {String} root name of the property which contains the Array of row objects.
12645 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
12646 * @cfg {Array} fields Array of field definition objects
12648 * Create a new JsonReader
12649 * @param {Object} meta Metadata configuration options
12650 * @param {Object} recordType Either an Array of field definition objects,
12651 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
12653 Roo.data.JsonReader = function(meta, recordType){
12656 // set some defaults:
12657 Roo.applyIf(meta, {
12658 totalProperty: 'total',
12659 successProperty : 'success',
12664 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
12666 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
12669 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
12670 * Used by Store query builder to append _requestMeta to params.
12673 metaFromRemote : false,
12675 * This method is only used by a DataProxy which has retrieved data from a remote server.
12676 * @param {Object} response The XHR object which contains the JSON data in its responseText.
12677 * @return {Object} data A data block which is used by an Roo.data.Store object as
12678 * a cache of Roo.data.Records.
12680 read : function(response){
12681 var json = response.responseText;
12683 var o = /* eval:var:o */ eval("("+json+")");
12685 throw {message: "JsonReader.read: Json object not found"};
12691 this.metaFromRemote = true;
12692 this.meta = o.metaData;
12693 this.recordType = Roo.data.Record.create(o.metaData.fields);
12694 this.onMetaChange(this.meta, this.recordType, o);
12696 return this.readRecords(o);
12699 // private function a store will implement
12700 onMetaChange : function(meta, recordType, o){
12707 simpleAccess: function(obj, subsc) {
12714 getJsonAccessor: function(){
12716 return function(expr) {
12718 return(re.test(expr))
12719 ? new Function("obj", "return obj." + expr)
12724 return Roo.emptyFn;
12729 * Create a data block containing Roo.data.Records from an XML document.
12730 * @param {Object} o An object which contains an Array of row objects in the property specified
12731 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
12732 * which contains the total size of the dataset.
12733 * @return {Object} data A data block which is used by an Roo.data.Store object as
12734 * a cache of Roo.data.Records.
12736 readRecords : function(o){
12738 * After any data loads, the raw JSON data is available for further custom processing.
12742 var s = this.meta, Record = this.recordType,
12743 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
12745 // Generate extraction functions for the totalProperty, the root, the id, and for each field
12747 if(s.totalProperty) {
12748 this.getTotal = this.getJsonAccessor(s.totalProperty);
12750 if(s.successProperty) {
12751 this.getSuccess = this.getJsonAccessor(s.successProperty);
12753 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
12755 var g = this.getJsonAccessor(s.id);
12756 this.getId = function(rec) {
12758 return (r === undefined || r === "") ? null : r;
12761 this.getId = function(){return null;};
12764 for(var jj = 0; jj < fl; jj++){
12766 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
12767 this.ef[jj] = this.getJsonAccessor(map);
12771 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
12772 if(s.totalProperty){
12773 var vt = parseInt(this.getTotal(o), 10);
12778 if(s.successProperty){
12779 var vs = this.getSuccess(o);
12780 if(vs === false || vs === 'false'){
12785 for(var i = 0; i < c; i++){
12788 var id = this.getId(n);
12789 for(var j = 0; j < fl; j++){
12791 var v = this.ef[j](n);
12793 Roo.log('missing convert for ' + f.name);
12797 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
12799 var record = new Record(values, id);
12801 records[i] = record;
12807 totalRecords : totalRecords
12812 * Ext JS Library 1.1.1
12813 * Copyright(c) 2006-2007, Ext JS, LLC.
12815 * Originally Released Under LGPL - original licence link has changed is not relivant.
12818 * <script type="text/javascript">
12822 * @class Roo.data.ArrayReader
12823 * @extends Roo.data.DataReader
12824 * Data reader class to create an Array of Roo.data.Record objects from an Array.
12825 * Each element of that Array represents a row of data fields. The
12826 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
12827 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
12831 var RecordDef = Roo.data.Record.create([
12832 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
12833 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
12835 var myReader = new Roo.data.ArrayReader({
12836 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
12840 * This would consume an Array like this:
12842 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
12844 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
12846 * Create a new JsonReader
12847 * @param {Object} meta Metadata configuration options.
12848 * @param {Object} recordType Either an Array of field definition objects
12849 * as specified to {@link Roo.data.Record#create},
12850 * or an {@link Roo.data.Record} object
12851 * created using {@link Roo.data.Record#create}.
12853 Roo.data.ArrayReader = function(meta, recordType){
12854 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
12857 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
12859 * Create a data block containing Roo.data.Records from an XML document.
12860 * @param {Object} o An Array of row objects which represents the dataset.
12861 * @return {Object} data A data block which is used by an Roo.data.Store object as
12862 * a cache of Roo.data.Records.
12864 readRecords : function(o){
12865 var sid = this.meta ? this.meta.id : null;
12866 var recordType = this.recordType, fields = recordType.prototype.fields;
12869 for(var i = 0; i < root.length; i++){
12872 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
12873 for(var j = 0, jlen = fields.length; j < jlen; j++){
12874 var f = fields.items[j];
12875 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
12876 var v = n[k] !== undefined ? n[k] : f.defaultValue;
12878 values[f.name] = v;
12880 var record = new recordType(values, id);
12882 records[records.length] = record;
12886 totalRecords : records.length
12895 * @class Roo.bootstrap.ComboBox
12896 * @extends Roo.bootstrap.TriggerField
12897 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
12898 * @cfg {Boolean} append (true|false) default false
12899 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
12900 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
12901 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
12902 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
12903 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
12904 * @cfg {Boolean} animate default true
12905 * @cfg {Boolean} emptyResultText only for touch device
12906 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
12907 * @cfg {String} emptyTitle default ''
12909 * Create a new ComboBox.
12910 * @param {Object} config Configuration options
12912 Roo.bootstrap.ComboBox = function(config){
12913 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
12917 * Fires when the dropdown list is expanded
12918 * @param {Roo.bootstrap.ComboBox} combo This combo box
12923 * Fires when the dropdown list is collapsed
12924 * @param {Roo.bootstrap.ComboBox} combo This combo box
12928 * @event beforeselect
12929 * Fires before a list item is selected. Return false to cancel the selection.
12930 * @param {Roo.bootstrap.ComboBox} combo This combo box
12931 * @param {Roo.data.Record} record The data record returned from the underlying store
12932 * @param {Number} index The index of the selected item in the dropdown list
12934 'beforeselect' : true,
12937 * Fires when a list item is selected
12938 * @param {Roo.bootstrap.ComboBox} combo This combo box
12939 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
12940 * @param {Number} index The index of the selected item in the dropdown list
12944 * @event beforequery
12945 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
12946 * The event object passed has these properties:
12947 * @param {Roo.bootstrap.ComboBox} combo This combo box
12948 * @param {String} query The query
12949 * @param {Boolean} forceAll true to force "all" query
12950 * @param {Boolean} cancel true to cancel the query
12951 * @param {Object} e The query event object
12953 'beforequery': true,
12956 * Fires when the 'add' icon is pressed (add a listener to enable add button)
12957 * @param {Roo.bootstrap.ComboBox} combo This combo box
12962 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
12963 * @param {Roo.bootstrap.ComboBox} combo This combo box
12964 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
12969 * Fires when the remove value from the combobox array
12970 * @param {Roo.bootstrap.ComboBox} combo This combo box
12974 * @event afterremove
12975 * Fires when the remove value from the combobox array
12976 * @param {Roo.bootstrap.ComboBox} combo This combo box
12978 'afterremove' : true,
12980 * @event specialfilter
12981 * Fires when specialfilter
12982 * @param {Roo.bootstrap.ComboBox} combo This combo box
12984 'specialfilter' : true,
12987 * Fires when tick the element
12988 * @param {Roo.bootstrap.ComboBox} combo This combo box
12992 * @event touchviewdisplay
12993 * Fires when touch view require special display (default is using displayField)
12994 * @param {Roo.bootstrap.ComboBox} combo This combo box
12995 * @param {Object} cfg set html .
12997 'touchviewdisplay' : true
13002 this.tickItems = [];
13004 this.selectedIndex = -1;
13005 if(this.mode == 'local'){
13006 if(config.queryDelay === undefined){
13007 this.queryDelay = 10;
13009 if(config.minChars === undefined){
13015 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
13018 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
13019 * rendering into an Roo.Editor, defaults to false)
13022 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
13023 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
13026 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
13029 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
13030 * the dropdown list (defaults to undefined, with no header element)
13034 * @cfg {String/Roo.Template} tpl The template to use to render the output
13038 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
13040 listWidth: undefined,
13042 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
13043 * mode = 'remote' or 'text' if mode = 'local')
13045 displayField: undefined,
13048 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
13049 * mode = 'remote' or 'value' if mode = 'local').
13050 * Note: use of a valueField requires the user make a selection
13051 * in order for a value to be mapped.
13053 valueField: undefined,
13055 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
13060 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
13061 * field's data value (defaults to the underlying DOM element's name)
13063 hiddenName: undefined,
13065 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
13069 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
13071 selectedClass: 'active',
13074 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
13078 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
13079 * anchor positions (defaults to 'tl-bl')
13081 listAlign: 'tl-bl?',
13083 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
13087 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
13088 * query specified by the allQuery config option (defaults to 'query')
13090 triggerAction: 'query',
13092 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
13093 * (defaults to 4, does not apply if editable = false)
13097 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
13098 * delay (typeAheadDelay) if it matches a known value (defaults to false)
13102 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
13103 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
13107 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
13108 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
13112 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
13113 * when editable = true (defaults to false)
13115 selectOnFocus:false,
13117 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
13119 queryParam: 'query',
13121 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
13122 * when mode = 'remote' (defaults to 'Loading...')
13124 loadingText: 'Loading...',
13126 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
13130 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
13134 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
13135 * traditional select (defaults to true)
13139 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
13143 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
13147 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
13148 * listWidth has a higher value)
13152 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
13153 * allow the user to set arbitrary text into the field (defaults to false)
13155 forceSelection:false,
13157 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
13158 * if typeAhead = true (defaults to 250)
13160 typeAheadDelay : 250,
13162 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
13163 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
13165 valueNotFoundText : undefined,
13167 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
13169 blockFocus : false,
13172 * @cfg {Boolean} disableClear Disable showing of clear button.
13174 disableClear : false,
13176 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
13178 alwaysQuery : false,
13181 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
13186 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
13188 invalidClass : "has-warning",
13191 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
13193 validClass : "has-success",
13196 * @cfg {Boolean} specialFilter (true|false) special filter default false
13198 specialFilter : false,
13201 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
13203 mobileTouchView : true,
13206 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
13208 useNativeIOS : false,
13211 * @cfg {Boolean} mobile_restrict_height (true|false) restrict height for touch view
13213 mobile_restrict_height : false,
13215 ios_options : false,
13227 btnPosition : 'right',
13228 triggerList : true,
13229 showToggleBtn : true,
13231 emptyResultText: 'Empty',
13232 triggerText : 'Select',
13235 // element that contains real text value.. (when hidden is used..)
13237 getAutoCreate : function()
13242 * Render classic select for iso
13245 if(Roo.isIOS && this.useNativeIOS){
13246 cfg = this.getAutoCreateNativeIOS();
13254 if(Roo.isTouch && this.mobileTouchView){
13255 cfg = this.getAutoCreateTouchView();
13262 if(!this.tickable){
13263 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
13268 * ComboBox with tickable selections
13271 var align = this.labelAlign || this.parentLabelAlign();
13274 cls : 'form-group roo-combobox-tickable' //input-group
13277 var btn_text_select = '';
13278 var btn_text_done = '';
13279 var btn_text_cancel = '';
13281 if (this.btn_text_show) {
13282 btn_text_select = 'Select';
13283 btn_text_done = 'Done';
13284 btn_text_cancel = 'Cancel';
13289 cls : 'tickable-buttons',
13294 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
13295 //html : this.triggerText
13296 html: btn_text_select
13302 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
13304 html: btn_text_done
13310 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
13312 html: btn_text_cancel
13318 buttons.cn.unshift({
13320 cls: 'roo-select2-search-field-input'
13326 Roo.each(buttons.cn, function(c){
13328 c.cls += ' btn-' + _this.size;
13331 if (_this.disabled) {
13342 cls: 'form-hidden-field'
13346 cls: 'roo-select2-choices',
13350 cls: 'roo-select2-search-field',
13361 cls: 'roo-select2-container input-group roo-select2-container-multi',
13367 // cls: 'typeahead typeahead-long dropdown-menu',
13368 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
13373 if(this.hasFeedback && !this.allowBlank){
13377 cls: 'glyphicon form-control-feedback'
13380 combobox.cn.push(feedback);
13385 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
13386 tooltip : 'This field is required'
13388 if (Roo.bootstrap.version == 4) {
13391 style : 'display:none'
13394 if (align ==='left' && this.fieldLabel.length) {
13396 cfg.cls += ' roo-form-group-label-left row';
13403 cls : 'control-label col-form-label',
13404 html : this.fieldLabel
13416 var labelCfg = cfg.cn[1];
13417 var contentCfg = cfg.cn[2];
13420 if(this.indicatorpos == 'right'){
13426 cls : 'control-label col-form-label',
13430 html : this.fieldLabel
13446 labelCfg = cfg.cn[0];
13447 contentCfg = cfg.cn[1];
13451 if(this.labelWidth > 12){
13452 labelCfg.style = "width: " + this.labelWidth + 'px';
13455 if(this.labelWidth < 13 && this.labelmd == 0){
13456 this.labelmd = this.labelWidth;
13459 if(this.labellg > 0){
13460 labelCfg.cls += ' col-lg-' + this.labellg;
13461 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
13464 if(this.labelmd > 0){
13465 labelCfg.cls += ' col-md-' + this.labelmd;
13466 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
13469 if(this.labelsm > 0){
13470 labelCfg.cls += ' col-sm-' + this.labelsm;
13471 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
13474 if(this.labelxs > 0){
13475 labelCfg.cls += ' col-xs-' + this.labelxs;
13476 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
13480 } else if ( this.fieldLabel.length) {
13481 // Roo.log(" label");
13486 //cls : 'input-group-addon',
13487 html : this.fieldLabel
13492 if(this.indicatorpos == 'right'){
13496 //cls : 'input-group-addon',
13497 html : this.fieldLabel
13507 // Roo.log(" no label && no align");
13514 ['xs','sm','md','lg'].map(function(size){
13515 if (settings[size]) {
13516 cfg.cls += ' col-' + size + '-' + settings[size];
13524 _initEventsCalled : false,
13527 initEvents: function()
13529 if (this._initEventsCalled) { // as we call render... prevent looping...
13532 this._initEventsCalled = true;
13535 throw "can not find store for combo";
13538 this.indicator = this.indicatorEl();
13540 this.store = Roo.factory(this.store, Roo.data);
13541 this.store.parent = this;
13543 // if we are building from html. then this element is so complex, that we can not really
13544 // use the rendered HTML.
13545 // so we have to trash and replace the previous code.
13546 if (Roo.XComponent.build_from_html) {
13547 // remove this element....
13548 var e = this.el.dom, k=0;
13549 while (e ) { e = e.previousSibling; ++k;}
13554 this.rendered = false;
13556 this.render(this.parent().getChildContainer(true), k);
13559 if(Roo.isIOS && this.useNativeIOS){
13560 this.initIOSView();
13568 if(Roo.isTouch && this.mobileTouchView){
13569 this.initTouchView();
13574 this.initTickableEvents();
13578 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
13580 if(this.hiddenName){
13582 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13584 this.hiddenField.dom.value =
13585 this.hiddenValue !== undefined ? this.hiddenValue :
13586 this.value !== undefined ? this.value : '';
13588 // prevent input submission
13589 this.el.dom.removeAttribute('name');
13590 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13595 // this.el.dom.setAttribute('autocomplete', 'off');
13598 var cls = 'x-combo-list';
13600 //this.list = new Roo.Layer({
13601 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
13607 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13608 _this.list.setWidth(lw);
13611 this.list.on('mouseover', this.onViewOver, this);
13612 this.list.on('mousemove', this.onViewMove, this);
13613 this.list.on('scroll', this.onViewScroll, this);
13616 this.list.swallowEvent('mousewheel');
13617 this.assetHeight = 0;
13620 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
13621 this.assetHeight += this.header.getHeight();
13624 this.innerList = this.list.createChild({cls:cls+'-inner'});
13625 this.innerList.on('mouseover', this.onViewOver, this);
13626 this.innerList.on('mousemove', this.onViewMove, this);
13627 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13629 if(this.allowBlank && !this.pageSize && !this.disableClear){
13630 this.footer = this.list.createChild({cls:cls+'-ft'});
13631 this.pageTb = new Roo.Toolbar(this.footer);
13635 this.footer = this.list.createChild({cls:cls+'-ft'});
13636 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
13637 {pageSize: this.pageSize});
13641 if (this.pageTb && this.allowBlank && !this.disableClear) {
13643 this.pageTb.add(new Roo.Toolbar.Fill(), {
13644 cls: 'x-btn-icon x-btn-clear',
13646 handler: function()
13649 _this.clearValue();
13650 _this.onSelect(false, -1);
13655 this.assetHeight += this.footer.getHeight();
13660 this.tpl = Roo.bootstrap.version == 4 ?
13661 '<a class="dropdown-item" href="#">{' + this.displayField + '}</a>' : // 4 does not need <li> and it get's really confisued.
13662 '<li><a class="dropdown-item" href="#">{' + this.displayField + '}</a></li>';
13665 this.view = new Roo.View(this.list, this.tpl, {
13666 singleSelect:true, store: this.store, selectedClass: this.selectedClass
13668 //this.view.wrapEl.setDisplayed(false);
13669 this.view.on('click', this.onViewClick, this);
13672 this.store.on('beforeload', this.onBeforeLoad, this);
13673 this.store.on('load', this.onLoad, this);
13674 this.store.on('loadexception', this.onLoadException, this);
13676 if(this.resizable){
13677 this.resizer = new Roo.Resizable(this.list, {
13678 pinned:true, handles:'se'
13680 this.resizer.on('resize', function(r, w, h){
13681 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
13682 this.listWidth = w;
13683 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
13684 this.restrictHeight();
13686 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
13689 if(!this.editable){
13690 this.editable = true;
13691 this.setEditable(false);
13696 if (typeof(this.events.add.listeners) != 'undefined') {
13698 this.addicon = this.wrap.createChild(
13699 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
13701 this.addicon.on('click', function(e) {
13702 this.fireEvent('add', this);
13705 if (typeof(this.events.edit.listeners) != 'undefined') {
13707 this.editicon = this.wrap.createChild(
13708 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
13709 if (this.addicon) {
13710 this.editicon.setStyle('margin-left', '40px');
13712 this.editicon.on('click', function(e) {
13714 // we fire even if inothing is selected..
13715 this.fireEvent('edit', this, this.lastData );
13721 this.keyNav = new Roo.KeyNav(this.inputEl(), {
13722 "up" : function(e){
13723 this.inKeyMode = true;
13727 "down" : function(e){
13728 if(!this.isExpanded()){
13729 this.onTriggerClick();
13731 this.inKeyMode = true;
13736 "enter" : function(e){
13737 // this.onViewClick();
13741 if(this.fireEvent("specialkey", this, e)){
13742 this.onViewClick(false);
13748 "esc" : function(e){
13752 "tab" : function(e){
13755 if(this.fireEvent("specialkey", this, e)){
13756 this.onViewClick(false);
13764 doRelay : function(foo, bar, hname){
13765 if(hname == 'down' || this.scope.isExpanded()){
13766 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13775 this.queryDelay = Math.max(this.queryDelay || 10,
13776 this.mode == 'local' ? 10 : 250);
13779 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13781 if(this.typeAhead){
13782 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13784 if(this.editable !== false){
13785 this.inputEl().on("keyup", this.onKeyUp, this);
13787 if(this.forceSelection){
13788 this.inputEl().on('blur', this.doForce, this);
13792 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13793 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13797 initTickableEvents: function()
13801 if(this.hiddenName){
13803 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13805 this.hiddenField.dom.value =
13806 this.hiddenValue !== undefined ? this.hiddenValue :
13807 this.value !== undefined ? this.value : '';
13809 // prevent input submission
13810 this.el.dom.removeAttribute('name');
13811 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13816 // this.list = this.el.select('ul.dropdown-menu',true).first();
13818 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13819 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13820 if(this.triggerList){
13821 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
13824 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
13825 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
13827 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
13828 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
13830 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
13831 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
13833 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
13834 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
13835 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
13838 this.cancelBtn.hide();
13843 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13844 _this.list.setWidth(lw);
13847 this.list.on('mouseover', this.onViewOver, this);
13848 this.list.on('mousemove', this.onViewMove, this);
13850 this.list.on('scroll', this.onViewScroll, this);
13853 this.tpl = '<li class="roo-select2-result"><div class="checkbox"><input id="{roo-id}"' +
13854 'type="checkbox" {roo-data-checked}><label for="{roo-id}"><b>{' + this.displayField + '}</b></label></div></li>';
13857 this.view = new Roo.View(this.list, this.tpl, {
13862 selectedClass: this.selectedClass
13865 //this.view.wrapEl.setDisplayed(false);
13866 this.view.on('click', this.onViewClick, this);
13870 this.store.on('beforeload', this.onBeforeLoad, this);
13871 this.store.on('load', this.onLoad, this);
13872 this.store.on('loadexception', this.onLoadException, this);
13875 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
13876 "up" : function(e){
13877 this.inKeyMode = true;
13881 "down" : function(e){
13882 this.inKeyMode = true;
13886 "enter" : function(e){
13887 if(this.fireEvent("specialkey", this, e)){
13888 this.onViewClick(false);
13894 "esc" : function(e){
13895 this.onTickableFooterButtonClick(e, false, false);
13898 "tab" : function(e){
13899 this.fireEvent("specialkey", this, e);
13901 this.onTickableFooterButtonClick(e, false, false);
13908 doRelay : function(e, fn, key){
13909 if(this.scope.isExpanded()){
13910 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13919 this.queryDelay = Math.max(this.queryDelay || 10,
13920 this.mode == 'local' ? 10 : 250);
13923 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13925 if(this.typeAhead){
13926 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13929 if(this.editable !== false){
13930 this.tickableInputEl().on("keyup", this.onKeyUp, this);
13933 this.indicator = this.indicatorEl();
13935 if(this.indicator){
13936 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
13937 this.indicator.hide();
13942 onDestroy : function(){
13944 this.view.setStore(null);
13945 this.view.el.removeAllListeners();
13946 this.view.el.remove();
13947 this.view.purgeListeners();
13950 this.list.dom.innerHTML = '';
13954 this.store.un('beforeload', this.onBeforeLoad, this);
13955 this.store.un('load', this.onLoad, this);
13956 this.store.un('loadexception', this.onLoadException, this);
13958 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
13962 fireKey : function(e){
13963 if(e.isNavKeyPress() && !this.list.isVisible()){
13964 this.fireEvent("specialkey", this, e);
13969 onResize: function(w, h){
13970 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
13972 // if(typeof w != 'number'){
13973 // // we do not handle it!?!?
13976 // var tw = this.trigger.getWidth();
13977 // // tw += this.addicon ? this.addicon.getWidth() : 0;
13978 // // tw += this.editicon ? this.editicon.getWidth() : 0;
13980 // this.inputEl().setWidth( this.adjustWidth('input', x));
13982 // //this.trigger.setStyle('left', x+'px');
13984 // if(this.list && this.listWidth === undefined){
13985 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
13986 // this.list.setWidth(lw);
13987 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13995 * Allow or prevent the user from directly editing the field text. If false is passed,
13996 * the user will only be able to select from the items defined in the dropdown list. This method
13997 * is the runtime equivalent of setting the 'editable' config option at config time.
13998 * @param {Boolean} value True to allow the user to directly edit the field text
14000 setEditable : function(value){
14001 if(value == this.editable){
14004 this.editable = value;
14006 this.inputEl().dom.setAttribute('readOnly', true);
14007 this.inputEl().on('mousedown', this.onTriggerClick, this);
14008 this.inputEl().addClass('x-combo-noedit');
14010 this.inputEl().dom.setAttribute('readOnly', false);
14011 this.inputEl().un('mousedown', this.onTriggerClick, this);
14012 this.inputEl().removeClass('x-combo-noedit');
14018 onBeforeLoad : function(combo,opts){
14019 if(!this.hasFocus){
14023 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
14025 this.restrictHeight();
14026 this.selectedIndex = -1;
14030 onLoad : function(){
14032 this.hasQuery = false;
14034 if(!this.hasFocus){
14038 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
14039 this.loading.hide();
14042 if(this.store.getCount() > 0){
14045 this.restrictHeight();
14046 if(this.lastQuery == this.allQuery){
14047 if(this.editable && !this.tickable){
14048 this.inputEl().dom.select();
14052 !this.selectByValue(this.value, true) &&
14055 !this.store.lastOptions ||
14056 typeof(this.store.lastOptions.add) == 'undefined' ||
14057 this.store.lastOptions.add != true
14060 this.select(0, true);
14063 if(this.autoFocus){
14066 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
14067 this.taTask.delay(this.typeAheadDelay);
14071 this.onEmptyResults();
14077 onLoadException : function()
14079 this.hasQuery = false;
14081 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
14082 this.loading.hide();
14085 if(this.tickable && this.editable){
14090 // only causes errors at present
14091 //Roo.log(this.store.reader.jsonData);
14092 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
14094 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
14100 onTypeAhead : function(){
14101 if(this.store.getCount() > 0){
14102 var r = this.store.getAt(0);
14103 var newValue = r.data[this.displayField];
14104 var len = newValue.length;
14105 var selStart = this.getRawValue().length;
14107 if(selStart != len){
14108 this.setRawValue(newValue);
14109 this.selectText(selStart, newValue.length);
14115 onSelect : function(record, index){
14117 if(this.fireEvent('beforeselect', this, record, index) !== false){
14119 this.setFromData(index > -1 ? record.data : false);
14122 this.fireEvent('select', this, record, index);
14127 * Returns the currently selected field value or empty string if no value is set.
14128 * @return {String} value The selected value
14130 getValue : function()
14132 if(Roo.isIOS && this.useNativeIOS){
14133 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
14137 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
14140 if(this.valueField){
14141 return typeof this.value != 'undefined' ? this.value : '';
14143 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
14147 getRawValue : function()
14149 if(Roo.isIOS && this.useNativeIOS){
14150 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
14153 var v = this.inputEl().getValue();
14159 * Clears any text/value currently set in the field
14161 clearValue : function(){
14163 if(this.hiddenField){
14164 this.hiddenField.dom.value = '';
14167 this.setRawValue('');
14168 this.lastSelectionText = '';
14169 this.lastData = false;
14171 var close = this.closeTriggerEl();
14182 * Sets the specified value into the field. If the value finds a match, the corresponding record text
14183 * will be displayed in the field. If the value does not match the data value of an existing item,
14184 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
14185 * Otherwise the field will be blank (although the value will still be set).
14186 * @param {String} value The value to match
14188 setValue : function(v)
14190 if(Roo.isIOS && this.useNativeIOS){
14191 this.setIOSValue(v);
14201 if(this.valueField){
14202 var r = this.findRecord(this.valueField, v);
14204 text = r.data[this.displayField];
14205 }else if(this.valueNotFoundText !== undefined){
14206 text = this.valueNotFoundText;
14209 this.lastSelectionText = text;
14210 if(this.hiddenField){
14211 this.hiddenField.dom.value = v;
14213 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
14216 var close = this.closeTriggerEl();
14219 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
14225 * @property {Object} the last set data for the element
14230 * Sets the value of the field based on a object which is related to the record format for the store.
14231 * @param {Object} value the value to set as. or false on reset?
14233 setFromData : function(o){
14240 var dv = ''; // display value
14241 var vv = ''; // value value..
14243 if (this.displayField) {
14244 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14246 // this is an error condition!!!
14247 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14250 if(this.valueField){
14251 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
14254 var close = this.closeTriggerEl();
14257 if(dv.length || vv * 1 > 0){
14259 this.blockFocus=true;
14265 if(this.hiddenField){
14266 this.hiddenField.dom.value = vv;
14268 this.lastSelectionText = dv;
14269 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14273 // no hidden field.. - we store the value in 'value', but still display
14274 // display field!!!!
14275 this.lastSelectionText = dv;
14276 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14283 reset : function(){
14284 // overridden so that last data is reset..
14291 this.setValue(this.originalValue);
14292 //this.clearInvalid();
14293 this.lastData = false;
14295 this.view.clearSelections();
14301 findRecord : function(prop, value){
14303 if(this.store.getCount() > 0){
14304 this.store.each(function(r){
14305 if(r.data[prop] == value){
14315 getName: function()
14317 // returns hidden if it's set..
14318 if (!this.rendered) {return ''};
14319 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
14323 onViewMove : function(e, t){
14324 this.inKeyMode = false;
14328 onViewOver : function(e, t){
14329 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
14332 var item = this.view.findItemFromChild(t);
14335 var index = this.view.indexOf(item);
14336 this.select(index, false);
14341 onViewClick : function(view, doFocus, el, e)
14343 var index = this.view.getSelectedIndexes()[0];
14345 var r = this.store.getAt(index);
14349 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
14356 Roo.each(this.tickItems, function(v,k){
14358 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
14360 _this.tickItems.splice(k, 1);
14362 if(typeof(e) == 'undefined' && view == false){
14363 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
14375 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
14376 this.tickItems.push(r.data);
14379 if(typeof(e) == 'undefined' && view == false){
14380 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
14387 this.onSelect(r, index);
14389 if(doFocus !== false && !this.blockFocus){
14390 this.inputEl().focus();
14395 restrictHeight : function(){
14396 //this.innerList.dom.style.height = '';
14397 //var inner = this.innerList.dom;
14398 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
14399 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
14400 //this.list.beginUpdate();
14401 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
14402 this.list.alignTo(this.inputEl(), this.listAlign);
14403 this.list.alignTo(this.inputEl(), this.listAlign);
14404 //this.list.endUpdate();
14408 onEmptyResults : function(){
14410 if(this.tickable && this.editable){
14411 this.hasFocus = false;
14412 this.restrictHeight();
14420 * Returns true if the dropdown list is expanded, else false.
14422 isExpanded : function(){
14423 return this.list.isVisible();
14427 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
14428 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14429 * @param {String} value The data value of the item to select
14430 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14431 * selected item if it is not currently in view (defaults to true)
14432 * @return {Boolean} True if the value matched an item in the list, else false
14434 selectByValue : function(v, scrollIntoView){
14435 if(v !== undefined && v !== null){
14436 var r = this.findRecord(this.valueField || this.displayField, v);
14438 this.select(this.store.indexOf(r), scrollIntoView);
14446 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
14447 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14448 * @param {Number} index The zero-based index of the list item to select
14449 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14450 * selected item if it is not currently in view (defaults to true)
14452 select : function(index, scrollIntoView){
14453 this.selectedIndex = index;
14454 this.view.select(index);
14455 if(scrollIntoView !== false){
14456 var el = this.view.getNode(index);
14458 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
14461 this.list.scrollChildIntoView(el, false);
14467 selectNext : function(){
14468 var ct = this.store.getCount();
14470 if(this.selectedIndex == -1){
14472 }else if(this.selectedIndex < ct-1){
14473 this.select(this.selectedIndex+1);
14479 selectPrev : function(){
14480 var ct = this.store.getCount();
14482 if(this.selectedIndex == -1){
14484 }else if(this.selectedIndex != 0){
14485 this.select(this.selectedIndex-1);
14491 onKeyUp : function(e){
14492 if(this.editable !== false && !e.isSpecialKey()){
14493 this.lastKey = e.getKey();
14494 this.dqTask.delay(this.queryDelay);
14499 validateBlur : function(){
14500 return !this.list || !this.list.isVisible();
14504 initQuery : function(){
14506 var v = this.getRawValue();
14508 if(this.tickable && this.editable){
14509 v = this.tickableInputEl().getValue();
14516 doForce : function(){
14517 if(this.inputEl().dom.value.length > 0){
14518 this.inputEl().dom.value =
14519 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
14525 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
14526 * query allowing the query action to be canceled if needed.
14527 * @param {String} query The SQL query to execute
14528 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
14529 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
14530 * saved in the current store (defaults to false)
14532 doQuery : function(q, forceAll){
14534 if(q === undefined || q === null){
14539 forceAll: forceAll,
14543 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
14548 forceAll = qe.forceAll;
14549 if(forceAll === true || (q.length >= this.minChars)){
14551 this.hasQuery = true;
14553 if(this.lastQuery != q || this.alwaysQuery){
14554 this.lastQuery = q;
14555 if(this.mode == 'local'){
14556 this.selectedIndex = -1;
14558 this.store.clearFilter();
14561 if(this.specialFilter){
14562 this.fireEvent('specialfilter', this);
14567 this.store.filter(this.displayField, q);
14570 this.store.fireEvent("datachanged", this.store);
14577 this.store.baseParams[this.queryParam] = q;
14579 var options = {params : this.getParams(q)};
14582 options.add = true;
14583 options.params.start = this.page * this.pageSize;
14586 this.store.load(options);
14589 * this code will make the page width larger, at the beginning, the list not align correctly,
14590 * we should expand the list on onLoad
14591 * so command out it
14596 this.selectedIndex = -1;
14601 this.loadNext = false;
14605 getParams : function(q){
14607 //p[this.queryParam] = q;
14611 p.limit = this.pageSize;
14617 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
14619 collapse : function(){
14620 if(!this.isExpanded()){
14626 this.hasFocus = false;
14630 this.cancelBtn.hide();
14631 this.trigger.show();
14634 this.tickableInputEl().dom.value = '';
14635 this.tickableInputEl().blur();
14640 Roo.get(document).un('mousedown', this.collapseIf, this);
14641 Roo.get(document).un('mousewheel', this.collapseIf, this);
14642 if (!this.editable) {
14643 Roo.get(document).un('keydown', this.listKeyPress, this);
14645 this.fireEvent('collapse', this);
14651 collapseIf : function(e){
14652 var in_combo = e.within(this.el);
14653 var in_list = e.within(this.list);
14654 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
14656 if (in_combo || in_list || is_list) {
14657 //e.stopPropagation();
14662 this.onTickableFooterButtonClick(e, false, false);
14670 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
14672 expand : function(){
14674 if(this.isExpanded() || !this.hasFocus){
14678 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
14679 this.list.setWidth(lw);
14685 this.restrictHeight();
14689 this.tickItems = Roo.apply([], this.item);
14692 this.cancelBtn.show();
14693 this.trigger.hide();
14696 this.tickableInputEl().focus();
14701 Roo.get(document).on('mousedown', this.collapseIf, this);
14702 Roo.get(document).on('mousewheel', this.collapseIf, this);
14703 if (!this.editable) {
14704 Roo.get(document).on('keydown', this.listKeyPress, this);
14707 this.fireEvent('expand', this);
14711 // Implements the default empty TriggerField.onTriggerClick function
14712 onTriggerClick : function(e)
14714 Roo.log('trigger click');
14716 if(this.disabled || !this.triggerList){
14721 this.loadNext = false;
14723 if(this.isExpanded()){
14725 if (!this.blockFocus) {
14726 this.inputEl().focus();
14730 this.hasFocus = true;
14731 if(this.triggerAction == 'all') {
14732 this.doQuery(this.allQuery, true);
14734 this.doQuery(this.getRawValue());
14736 if (!this.blockFocus) {
14737 this.inputEl().focus();
14742 onTickableTriggerClick : function(e)
14749 this.loadNext = false;
14750 this.hasFocus = true;
14752 if(this.triggerAction == 'all') {
14753 this.doQuery(this.allQuery, true);
14755 this.doQuery(this.getRawValue());
14759 onSearchFieldClick : function(e)
14761 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
14762 this.onTickableFooterButtonClick(e, false, false);
14766 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
14771 this.loadNext = false;
14772 this.hasFocus = true;
14774 if(this.triggerAction == 'all') {
14775 this.doQuery(this.allQuery, true);
14777 this.doQuery(this.getRawValue());
14781 listKeyPress : function(e)
14783 //Roo.log('listkeypress');
14784 // scroll to first matching element based on key pres..
14785 if (e.isSpecialKey()) {
14788 var k = String.fromCharCode(e.getKey()).toUpperCase();
14791 var csel = this.view.getSelectedNodes();
14792 var cselitem = false;
14794 var ix = this.view.indexOf(csel[0]);
14795 cselitem = this.store.getAt(ix);
14796 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
14802 this.store.each(function(v) {
14804 // start at existing selection.
14805 if (cselitem.id == v.id) {
14811 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
14812 match = this.store.indexOf(v);
14818 if (match === false) {
14819 return true; // no more action?
14822 this.view.select(match);
14823 var sn = Roo.get(this.view.getSelectedNodes()[0]);
14824 sn.scrollIntoView(sn.dom.parentNode, false);
14827 onViewScroll : function(e, t){
14829 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){
14833 this.hasQuery = true;
14835 this.loading = this.list.select('.loading', true).first();
14837 if(this.loading === null){
14838 this.list.createChild({
14840 cls: 'loading roo-select2-more-results roo-select2-active',
14841 html: 'Loading more results...'
14844 this.loading = this.list.select('.loading', true).first();
14846 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
14848 this.loading.hide();
14851 this.loading.show();
14856 this.loadNext = true;
14858 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
14863 addItem : function(o)
14865 var dv = ''; // display value
14867 if (this.displayField) {
14868 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14870 // this is an error condition!!!
14871 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14878 var choice = this.choices.createChild({
14880 cls: 'roo-select2-search-choice',
14889 cls: 'roo-select2-search-choice-close fa fa-times',
14894 }, this.searchField);
14896 var close = choice.select('a.roo-select2-search-choice-close', true).first();
14898 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
14906 this.inputEl().dom.value = '';
14911 onRemoveItem : function(e, _self, o)
14913 e.preventDefault();
14915 this.lastItem = Roo.apply([], this.item);
14917 var index = this.item.indexOf(o.data) * 1;
14920 Roo.log('not this item?!');
14924 this.item.splice(index, 1);
14929 this.fireEvent('remove', this, e);
14935 syncValue : function()
14937 if(!this.item.length){
14944 Roo.each(this.item, function(i){
14945 if(_this.valueField){
14946 value.push(i[_this.valueField]);
14953 this.value = value.join(',');
14955 if(this.hiddenField){
14956 this.hiddenField.dom.value = this.value;
14959 this.store.fireEvent("datachanged", this.store);
14964 clearItem : function()
14966 if(!this.multiple){
14972 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
14980 if(this.tickable && !Roo.isTouch){
14981 this.view.refresh();
14985 inputEl: function ()
14987 if(Roo.isIOS && this.useNativeIOS){
14988 return this.el.select('select.roo-ios-select', true).first();
14991 if(Roo.isTouch && this.mobileTouchView){
14992 return this.el.select('input.form-control',true).first();
14996 return this.searchField;
14999 return this.el.select('input.form-control',true).first();
15002 onTickableFooterButtonClick : function(e, btn, el)
15004 e.preventDefault();
15006 this.lastItem = Roo.apply([], this.item);
15008 if(btn && btn.name == 'cancel'){
15009 this.tickItems = Roo.apply([], this.item);
15018 Roo.each(this.tickItems, function(o){
15026 validate : function()
15028 if(this.getVisibilityEl().hasClass('hidden')){
15032 var v = this.getRawValue();
15035 v = this.getValue();
15038 if(this.disabled || this.allowBlank || v.length){
15043 this.markInvalid();
15047 tickableInputEl : function()
15049 if(!this.tickable || !this.editable){
15050 return this.inputEl();
15053 return this.inputEl().select('.roo-select2-search-field-input', true).first();
15057 getAutoCreateTouchView : function()
15062 cls: 'form-group' //input-group
15068 type : this.inputType,
15069 cls : 'form-control x-combo-noedit',
15070 autocomplete: 'new-password',
15071 placeholder : this.placeholder || '',
15076 input.name = this.name;
15080 input.cls += ' input-' + this.size;
15083 if (this.disabled) {
15084 input.disabled = true;
15095 inputblock.cls += ' input-group';
15097 inputblock.cn.unshift({
15099 cls : 'input-group-addon input-group-prepend input-group-text',
15104 if(this.removable && !this.multiple){
15105 inputblock.cls += ' roo-removable';
15107 inputblock.cn.push({
15110 cls : 'roo-combo-removable-btn close'
15114 if(this.hasFeedback && !this.allowBlank){
15116 inputblock.cls += ' has-feedback';
15118 inputblock.cn.push({
15120 cls: 'glyphicon form-control-feedback'
15127 inputblock.cls += (this.before) ? '' : ' input-group';
15129 inputblock.cn.push({
15131 cls : 'input-group-addon input-group-append input-group-text',
15137 var ibwrap = inputblock;
15142 cls: 'roo-select2-choices',
15146 cls: 'roo-select2-search-field',
15159 cls: 'roo-select2-container input-group roo-touchview-combobox ',
15164 cls: 'form-hidden-field'
15170 if(!this.multiple && this.showToggleBtn){
15177 if (this.caret != false) {
15180 cls: 'fa fa-' + this.caret
15187 cls : 'input-group-addon input-group-append input-group-text btn dropdown-toggle',
15192 cls: 'combobox-clear',
15206 combobox.cls += ' roo-select2-container-multi';
15209 var align = this.labelAlign || this.parentLabelAlign();
15211 if (align ==='left' && this.fieldLabel.length) {
15216 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15217 tooltip : 'This field is required'
15221 cls : 'control-label col-form-label',
15222 html : this.fieldLabel
15233 var labelCfg = cfg.cn[1];
15234 var contentCfg = cfg.cn[2];
15237 if(this.indicatorpos == 'right'){
15242 cls : 'control-label col-form-label',
15246 html : this.fieldLabel
15250 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15251 tooltip : 'This field is required'
15264 labelCfg = cfg.cn[0];
15265 contentCfg = cfg.cn[1];
15270 if(this.labelWidth > 12){
15271 labelCfg.style = "width: " + this.labelWidth + 'px';
15274 if(this.labelWidth < 13 && this.labelmd == 0){
15275 this.labelmd = this.labelWidth;
15278 if(this.labellg > 0){
15279 labelCfg.cls += ' col-lg-' + this.labellg;
15280 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
15283 if(this.labelmd > 0){
15284 labelCfg.cls += ' col-md-' + this.labelmd;
15285 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
15288 if(this.labelsm > 0){
15289 labelCfg.cls += ' col-sm-' + this.labelsm;
15290 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
15293 if(this.labelxs > 0){
15294 labelCfg.cls += ' col-xs-' + this.labelxs;
15295 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
15299 } else if ( this.fieldLabel.length) {
15303 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15304 tooltip : 'This field is required'
15308 cls : 'control-label',
15309 html : this.fieldLabel
15320 if(this.indicatorpos == 'right'){
15324 cls : 'control-label',
15325 html : this.fieldLabel,
15329 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15330 tooltip : 'This field is required'
15347 var settings = this;
15349 ['xs','sm','md','lg'].map(function(size){
15350 if (settings[size]) {
15351 cfg.cls += ' col-' + size + '-' + settings[size];
15358 initTouchView : function()
15360 this.renderTouchView();
15362 this.touchViewEl.on('scroll', function(){
15363 this.el.dom.scrollTop = 0;
15366 this.originalValue = this.getValue();
15368 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
15370 this.inputEl().on("click", this.showTouchView, this);
15371 if (this.triggerEl) {
15372 this.triggerEl.on("click", this.showTouchView, this);
15376 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
15377 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
15379 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
15381 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
15382 this.store.on('load', this.onTouchViewLoad, this);
15383 this.store.on('loadexception', this.onTouchViewLoadException, this);
15385 if(this.hiddenName){
15387 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
15389 this.hiddenField.dom.value =
15390 this.hiddenValue !== undefined ? this.hiddenValue :
15391 this.value !== undefined ? this.value : '';
15393 this.el.dom.removeAttribute('name');
15394 this.hiddenField.dom.setAttribute('name', this.hiddenName);
15398 this.choices = this.el.select('ul.roo-select2-choices', true).first();
15399 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
15402 if(this.removable && !this.multiple){
15403 var close = this.closeTriggerEl();
15405 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
15406 close.on('click', this.removeBtnClick, this, close);
15410 * fix the bug in Safari iOS8
15412 this.inputEl().on("focus", function(e){
15413 document.activeElement.blur();
15416 this._touchViewMask = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
15423 renderTouchView : function()
15425 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
15426 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15428 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
15429 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15431 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
15432 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15433 this.touchViewBodyEl.setStyle('overflow', 'auto');
15435 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
15436 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15438 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
15439 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15443 showTouchView : function()
15449 this.touchViewHeaderEl.hide();
15451 if(this.modalTitle.length){
15452 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
15453 this.touchViewHeaderEl.show();
15456 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
15457 this.touchViewEl.show();
15459 this.touchViewEl.select('.modal-dialog', true).first().setStyle({ margin : '0px', width : '100%'});
15461 //this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
15462 // Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15464 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15466 if(this.modalTitle.length){
15467 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15470 this.touchViewBodyEl.setHeight(bodyHeight);
15474 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
15476 this.touchViewEl.addClass('in');
15479 if(this._touchViewMask){
15480 Roo.get(document.body).addClass("x-body-masked");
15481 this._touchViewMask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15482 this._touchViewMask.setStyle('z-index', 10000);
15483 this._touchViewMask.addClass('show');
15486 this.doTouchViewQuery();
15490 hideTouchView : function()
15492 this.touchViewEl.removeClass('in');
15496 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
15498 this.touchViewEl.setStyle('display', 'none');
15501 if(this._touchViewMask){
15502 this._touchViewMask.removeClass('show');
15503 Roo.get(document.body).removeClass("x-body-masked");
15507 setTouchViewValue : function()
15514 Roo.each(this.tickItems, function(o){
15519 this.hideTouchView();
15522 doTouchViewQuery : function()
15531 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
15535 if(!this.alwaysQuery || this.mode == 'local'){
15536 this.onTouchViewLoad();
15543 onTouchViewBeforeLoad : function(combo,opts)
15549 onTouchViewLoad : function()
15551 if(this.store.getCount() < 1){
15552 this.onTouchViewEmptyResults();
15556 this.clearTouchView();
15558 var rawValue = this.getRawValue();
15560 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
15562 this.tickItems = [];
15564 this.store.data.each(function(d, rowIndex){
15565 var row = this.touchViewListGroup.createChild(template);
15567 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
15568 row.addClass(d.data.cls);
15571 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15574 html : d.data[this.displayField]
15577 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
15578 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
15581 row.removeClass('selected');
15582 if(!this.multiple && this.valueField &&
15583 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
15586 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15587 row.addClass('selected');
15590 if(this.multiple && this.valueField &&
15591 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
15595 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15596 this.tickItems.push(d.data);
15599 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
15603 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
15605 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15607 if(this.modalTitle.length){
15608 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15611 var listHeight = this.touchViewListGroup.getHeight() + this.touchViewBodyEl.getPadding('tb') * 2;
15613 if(this.mobile_restrict_height && listHeight < bodyHeight){
15614 this.touchViewBodyEl.setHeight(listHeight);
15619 if(firstChecked && listHeight > bodyHeight){
15620 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
15625 onTouchViewLoadException : function()
15627 this.hideTouchView();
15630 onTouchViewEmptyResults : function()
15632 this.clearTouchView();
15634 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
15636 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
15640 clearTouchView : function()
15642 this.touchViewListGroup.dom.innerHTML = '';
15645 onTouchViewClick : function(e, el, o)
15647 e.preventDefault();
15650 var rowIndex = o.rowIndex;
15652 var r = this.store.getAt(rowIndex);
15654 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
15656 if(!this.multiple){
15657 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
15658 c.dom.removeAttribute('checked');
15661 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15663 this.setFromData(r.data);
15665 var close = this.closeTriggerEl();
15671 this.hideTouchView();
15673 this.fireEvent('select', this, r, rowIndex);
15678 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
15679 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
15680 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
15684 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15685 this.addItem(r.data);
15686 this.tickItems.push(r.data);
15690 getAutoCreateNativeIOS : function()
15693 cls: 'form-group' //input-group,
15698 cls : 'roo-ios-select'
15702 combobox.name = this.name;
15705 if (this.disabled) {
15706 combobox.disabled = true;
15709 var settings = this;
15711 ['xs','sm','md','lg'].map(function(size){
15712 if (settings[size]) {
15713 cfg.cls += ' col-' + size + '-' + settings[size];
15723 initIOSView : function()
15725 this.store.on('load', this.onIOSViewLoad, this);
15730 onIOSViewLoad : function()
15732 if(this.store.getCount() < 1){
15736 this.clearIOSView();
15738 if(this.allowBlank) {
15740 var default_text = '-- SELECT --';
15742 if(this.placeholder.length){
15743 default_text = this.placeholder;
15746 if(this.emptyTitle.length){
15747 default_text += ' - ' + this.emptyTitle + ' -';
15750 var opt = this.inputEl().createChild({
15753 html : default_text
15757 o[this.valueField] = 0;
15758 o[this.displayField] = default_text;
15760 this.ios_options.push({
15767 this.store.data.each(function(d, rowIndex){
15771 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15772 html = d.data[this.displayField];
15777 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
15778 value = d.data[this.valueField];
15787 if(this.value == d.data[this.valueField]){
15788 option['selected'] = true;
15791 var opt = this.inputEl().createChild(option);
15793 this.ios_options.push({
15800 this.inputEl().on('change', function(){
15801 this.fireEvent('select', this);
15806 clearIOSView: function()
15808 this.inputEl().dom.innerHTML = '';
15810 this.ios_options = [];
15813 setIOSValue: function(v)
15817 if(!this.ios_options){
15821 Roo.each(this.ios_options, function(opts){
15823 opts.el.dom.removeAttribute('selected');
15825 if(opts.data[this.valueField] != v){
15829 opts.el.dom.setAttribute('selected', true);
15835 * @cfg {Boolean} grow
15839 * @cfg {Number} growMin
15843 * @cfg {Number} growMax
15852 Roo.apply(Roo.bootstrap.ComboBox, {
15856 cls: 'modal-header',
15878 cls: 'list-group-item',
15882 cls: 'roo-combobox-list-group-item-value'
15886 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
15900 listItemCheckbox : {
15902 cls: 'list-group-item',
15906 cls: 'roo-combobox-list-group-item-value'
15910 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
15926 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
15931 cls: 'modal-footer',
15939 cls: 'col-xs-6 text-left',
15942 cls: 'btn btn-danger roo-touch-view-cancel',
15948 cls: 'col-xs-6 text-right',
15951 cls: 'btn btn-success roo-touch-view-ok',
15962 Roo.apply(Roo.bootstrap.ComboBox, {
15964 touchViewTemplate : {
15966 cls: 'modal fade roo-combobox-touch-view',
15970 cls: 'modal-dialog',
15971 style : 'position:fixed', // we have to fix position....
15975 cls: 'modal-content',
15977 Roo.bootstrap.ComboBox.header,
15978 Roo.bootstrap.ComboBox.body,
15979 Roo.bootstrap.ComboBox.footer
15988 * Ext JS Library 1.1.1
15989 * Copyright(c) 2006-2007, Ext JS, LLC.
15991 * Originally Released Under LGPL - original licence link has changed is not relivant.
15994 * <script type="text/javascript">
15999 * @extends Roo.util.Observable
16000 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
16001 * This class also supports single and multi selection modes. <br>
16002 * Create a data model bound view:
16004 var store = new Roo.data.Store(...);
16006 var view = new Roo.View({
16008 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
16010 singleSelect: true,
16011 selectedClass: "ydataview-selected",
16015 // listen for node click?
16016 view.on("click", function(vw, index, node, e){
16017 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
16021 dataModel.load("foobar.xml");
16023 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
16025 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
16026 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
16028 * Note: old style constructor is still suported (container, template, config)
16031 * Create a new View
16032 * @param {Object} config The config object
16035 Roo.View = function(config, depreciated_tpl, depreciated_config){
16037 this.parent = false;
16039 if (typeof(depreciated_tpl) == 'undefined') {
16040 // new way.. - universal constructor.
16041 Roo.apply(this, config);
16042 this.el = Roo.get(this.el);
16045 this.el = Roo.get(config);
16046 this.tpl = depreciated_tpl;
16047 Roo.apply(this, depreciated_config);
16049 this.wrapEl = this.el.wrap().wrap();
16050 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
16053 if(typeof(this.tpl) == "string"){
16054 this.tpl = new Roo.Template(this.tpl);
16056 // support xtype ctors..
16057 this.tpl = new Roo.factory(this.tpl, Roo);
16061 this.tpl.compile();
16066 * @event beforeclick
16067 * Fires before a click is processed. Returns false to cancel the default action.
16068 * @param {Roo.View} this
16069 * @param {Number} index The index of the target node
16070 * @param {HTMLElement} node The target node
16071 * @param {Roo.EventObject} e The raw event object
16073 "beforeclick" : true,
16076 * Fires when a template node is clicked.
16077 * @param {Roo.View} this
16078 * @param {Number} index The index of the target node
16079 * @param {HTMLElement} node The target node
16080 * @param {Roo.EventObject} e The raw event object
16085 * Fires when a template node is double clicked.
16086 * @param {Roo.View} this
16087 * @param {Number} index The index of the target node
16088 * @param {HTMLElement} node The target node
16089 * @param {Roo.EventObject} e The raw event object
16093 * @event contextmenu
16094 * Fires when a template node is right clicked.
16095 * @param {Roo.View} this
16096 * @param {Number} index The index of the target node
16097 * @param {HTMLElement} node The target node
16098 * @param {Roo.EventObject} e The raw event object
16100 "contextmenu" : true,
16102 * @event selectionchange
16103 * Fires when the selected nodes change.
16104 * @param {Roo.View} this
16105 * @param {Array} selections Array of the selected nodes
16107 "selectionchange" : true,
16110 * @event beforeselect
16111 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
16112 * @param {Roo.View} this
16113 * @param {HTMLElement} node The node to be selected
16114 * @param {Array} selections Array of currently selected nodes
16116 "beforeselect" : true,
16118 * @event preparedata
16119 * Fires on every row to render, to allow you to change the data.
16120 * @param {Roo.View} this
16121 * @param {Object} data to be rendered (change this)
16123 "preparedata" : true
16131 "click": this.onClick,
16132 "dblclick": this.onDblClick,
16133 "contextmenu": this.onContextMenu,
16137 this.selections = [];
16139 this.cmp = new Roo.CompositeElementLite([]);
16141 this.store = Roo.factory(this.store, Roo.data);
16142 this.setStore(this.store, true);
16145 if ( this.footer && this.footer.xtype) {
16147 var fctr = this.wrapEl.appendChild(document.createElement("div"));
16149 this.footer.dataSource = this.store;
16150 this.footer.container = fctr;
16151 this.footer = Roo.factory(this.footer, Roo);
16152 fctr.insertFirst(this.el);
16154 // this is a bit insane - as the paging toolbar seems to detach the el..
16155 // dom.parentNode.parentNode.parentNode
16156 // they get detached?
16160 Roo.View.superclass.constructor.call(this);
16165 Roo.extend(Roo.View, Roo.util.Observable, {
16168 * @cfg {Roo.data.Store} store Data store to load data from.
16173 * @cfg {String|Roo.Element} el The container element.
16178 * @cfg {String|Roo.Template} tpl The template used by this View
16182 * @cfg {String} dataName the named area of the template to use as the data area
16183 * Works with domtemplates roo-name="name"
16187 * @cfg {String} selectedClass The css class to add to selected nodes
16189 selectedClass : "x-view-selected",
16191 * @cfg {String} emptyText The empty text to show when nothing is loaded.
16196 * @cfg {String} text to display on mask (default Loading)
16200 * @cfg {Boolean} multiSelect Allow multiple selection
16202 multiSelect : false,
16204 * @cfg {Boolean} singleSelect Allow single selection
16206 singleSelect: false,
16209 * @cfg {Boolean} toggleSelect - selecting
16211 toggleSelect : false,
16214 * @cfg {Boolean} tickable - selecting
16219 * Returns the element this view is bound to.
16220 * @return {Roo.Element}
16222 getEl : function(){
16223 return this.wrapEl;
16229 * Refreshes the view. - called by datachanged on the store. - do not call directly.
16231 refresh : function(){
16232 //Roo.log('refresh');
16235 // if we are using something like 'domtemplate', then
16236 // the what gets used is:
16237 // t.applySubtemplate(NAME, data, wrapping data..)
16238 // the outer template then get' applied with
16239 // the store 'extra data'
16240 // and the body get's added to the
16241 // roo-name="data" node?
16242 // <span class='roo-tpl-{name}'></span> ?????
16246 this.clearSelections();
16247 this.el.update("");
16249 var records = this.store.getRange();
16250 if(records.length < 1) {
16252 // is this valid?? = should it render a template??
16254 this.el.update(this.emptyText);
16258 if (this.dataName) {
16259 this.el.update(t.apply(this.store.meta)); //????
16260 el = this.el.child('.roo-tpl-' + this.dataName);
16263 for(var i = 0, len = records.length; i < len; i++){
16264 var data = this.prepareData(records[i].data, i, records[i]);
16265 this.fireEvent("preparedata", this, data, i, records[i]);
16267 var d = Roo.apply({}, data);
16270 Roo.apply(d, {'roo-id' : Roo.id()});
16274 Roo.each(this.parent.item, function(item){
16275 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
16278 Roo.apply(d, {'roo-data-checked' : 'checked'});
16282 html[html.length] = Roo.util.Format.trim(
16284 t.applySubtemplate(this.dataName, d, this.store.meta) :
16291 el.update(html.join(""));
16292 this.nodes = el.dom.childNodes;
16293 this.updateIndexes(0);
16298 * Function to override to reformat the data that is sent to
16299 * the template for each node.
16300 * DEPRICATED - use the preparedata event handler.
16301 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
16302 * a JSON object for an UpdateManager bound view).
16304 prepareData : function(data, index, record)
16306 this.fireEvent("preparedata", this, data, index, record);
16310 onUpdate : function(ds, record){
16311 // Roo.log('on update');
16312 this.clearSelections();
16313 var index = this.store.indexOf(record);
16314 var n = this.nodes[index];
16315 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
16316 n.parentNode.removeChild(n);
16317 this.updateIndexes(index, index);
16323 onAdd : function(ds, records, index)
16325 //Roo.log(['on Add', ds, records, index] );
16326 this.clearSelections();
16327 if(this.nodes.length == 0){
16331 var n = this.nodes[index];
16332 for(var i = 0, len = records.length; i < len; i++){
16333 var d = this.prepareData(records[i].data, i, records[i]);
16335 this.tpl.insertBefore(n, d);
16338 this.tpl.append(this.el, d);
16341 this.updateIndexes(index);
16344 onRemove : function(ds, record, index){
16345 // Roo.log('onRemove');
16346 this.clearSelections();
16347 var el = this.dataName ?
16348 this.el.child('.roo-tpl-' + this.dataName) :
16351 el.dom.removeChild(this.nodes[index]);
16352 this.updateIndexes(index);
16356 * Refresh an individual node.
16357 * @param {Number} index
16359 refreshNode : function(index){
16360 this.onUpdate(this.store, this.store.getAt(index));
16363 updateIndexes : function(startIndex, endIndex){
16364 var ns = this.nodes;
16365 startIndex = startIndex || 0;
16366 endIndex = endIndex || ns.length - 1;
16367 for(var i = startIndex; i <= endIndex; i++){
16368 ns[i].nodeIndex = i;
16373 * Changes the data store this view uses and refresh the view.
16374 * @param {Store} store
16376 setStore : function(store, initial){
16377 if(!initial && this.store){
16378 this.store.un("datachanged", this.refresh);
16379 this.store.un("add", this.onAdd);
16380 this.store.un("remove", this.onRemove);
16381 this.store.un("update", this.onUpdate);
16382 this.store.un("clear", this.refresh);
16383 this.store.un("beforeload", this.onBeforeLoad);
16384 this.store.un("load", this.onLoad);
16385 this.store.un("loadexception", this.onLoad);
16389 store.on("datachanged", this.refresh, this);
16390 store.on("add", this.onAdd, this);
16391 store.on("remove", this.onRemove, this);
16392 store.on("update", this.onUpdate, this);
16393 store.on("clear", this.refresh, this);
16394 store.on("beforeload", this.onBeforeLoad, this);
16395 store.on("load", this.onLoad, this);
16396 store.on("loadexception", this.onLoad, this);
16404 * onbeforeLoad - masks the loading area.
16407 onBeforeLoad : function(store,opts)
16409 //Roo.log('onBeforeLoad');
16411 this.el.update("");
16413 this.el.mask(this.mask ? this.mask : "Loading" );
16415 onLoad : function ()
16422 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
16423 * @param {HTMLElement} node
16424 * @return {HTMLElement} The template node
16426 findItemFromChild : function(node){
16427 var el = this.dataName ?
16428 this.el.child('.roo-tpl-' + this.dataName,true) :
16431 if(!node || node.parentNode == el){
16434 var p = node.parentNode;
16435 while(p && p != el){
16436 if(p.parentNode == el){
16445 onClick : function(e){
16446 var item = this.findItemFromChild(e.getTarget());
16448 var index = this.indexOf(item);
16449 if(this.onItemClick(item, index, e) !== false){
16450 this.fireEvent("click", this, index, item, e);
16453 this.clearSelections();
16458 onContextMenu : function(e){
16459 var item = this.findItemFromChild(e.getTarget());
16461 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
16466 onDblClick : function(e){
16467 var item = this.findItemFromChild(e.getTarget());
16469 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
16473 onItemClick : function(item, index, e)
16475 if(this.fireEvent("beforeclick", this, index, item, e) === false){
16478 if (this.toggleSelect) {
16479 var m = this.isSelected(item) ? 'unselect' : 'select';
16482 _t[m](item, true, false);
16485 if(this.multiSelect || this.singleSelect){
16486 if(this.multiSelect && e.shiftKey && this.lastSelection){
16487 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
16489 this.select(item, this.multiSelect && e.ctrlKey);
16490 this.lastSelection = item;
16493 if(!this.tickable){
16494 e.preventDefault();
16502 * Get the number of selected nodes.
16505 getSelectionCount : function(){
16506 return this.selections.length;
16510 * Get the currently selected nodes.
16511 * @return {Array} An array of HTMLElements
16513 getSelectedNodes : function(){
16514 return this.selections;
16518 * Get the indexes of the selected nodes.
16521 getSelectedIndexes : function(){
16522 var indexes = [], s = this.selections;
16523 for(var i = 0, len = s.length; i < len; i++){
16524 indexes.push(s[i].nodeIndex);
16530 * Clear all selections
16531 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
16533 clearSelections : function(suppressEvent){
16534 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
16535 this.cmp.elements = this.selections;
16536 this.cmp.removeClass(this.selectedClass);
16537 this.selections = [];
16538 if(!suppressEvent){
16539 this.fireEvent("selectionchange", this, this.selections);
16545 * Returns true if the passed node is selected
16546 * @param {HTMLElement/Number} node The node or node index
16547 * @return {Boolean}
16549 isSelected : function(node){
16550 var s = this.selections;
16554 node = this.getNode(node);
16555 return s.indexOf(node) !== -1;
16560 * @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
16561 * @param {Boolean} keepExisting (optional) true to keep existing selections
16562 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16564 select : function(nodeInfo, keepExisting, suppressEvent){
16565 if(nodeInfo instanceof Array){
16567 this.clearSelections(true);
16569 for(var i = 0, len = nodeInfo.length; i < len; i++){
16570 this.select(nodeInfo[i], true, true);
16574 var node = this.getNode(nodeInfo);
16575 if(!node || this.isSelected(node)){
16576 return; // already selected.
16579 this.clearSelections(true);
16582 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
16583 Roo.fly(node).addClass(this.selectedClass);
16584 this.selections.push(node);
16585 if(!suppressEvent){
16586 this.fireEvent("selectionchange", this, this.selections);
16594 * @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
16595 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
16596 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16598 unselect : function(nodeInfo, keepExisting, suppressEvent)
16600 if(nodeInfo instanceof Array){
16601 Roo.each(this.selections, function(s) {
16602 this.unselect(s, nodeInfo);
16606 var node = this.getNode(nodeInfo);
16607 if(!node || !this.isSelected(node)){
16608 //Roo.log("not selected");
16609 return; // not selected.
16613 Roo.each(this.selections, function(s) {
16615 Roo.fly(node).removeClass(this.selectedClass);
16622 this.selections= ns;
16623 this.fireEvent("selectionchange", this, this.selections);
16627 * Gets a template node.
16628 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16629 * @return {HTMLElement} The node or null if it wasn't found
16631 getNode : function(nodeInfo){
16632 if(typeof nodeInfo == "string"){
16633 return document.getElementById(nodeInfo);
16634 }else if(typeof nodeInfo == "number"){
16635 return this.nodes[nodeInfo];
16641 * Gets a range template nodes.
16642 * @param {Number} startIndex
16643 * @param {Number} endIndex
16644 * @return {Array} An array of nodes
16646 getNodes : function(start, end){
16647 var ns = this.nodes;
16648 start = start || 0;
16649 end = typeof end == "undefined" ? ns.length - 1 : end;
16652 for(var i = start; i <= end; i++){
16656 for(var i = start; i >= end; i--){
16664 * Finds the index of the passed node
16665 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16666 * @return {Number} The index of the node or -1
16668 indexOf : function(node){
16669 node = this.getNode(node);
16670 if(typeof node.nodeIndex == "number"){
16671 return node.nodeIndex;
16673 var ns = this.nodes;
16674 for(var i = 0, len = ns.length; i < len; i++){
16685 * based on jquery fullcalendar
16689 Roo.bootstrap = Roo.bootstrap || {};
16691 * @class Roo.bootstrap.Calendar
16692 * @extends Roo.bootstrap.Component
16693 * Bootstrap Calendar class
16694 * @cfg {Boolean} loadMask (true|false) default false
16695 * @cfg {Object} header generate the user specific header of the calendar, default false
16698 * Create a new Container
16699 * @param {Object} config The config object
16704 Roo.bootstrap.Calendar = function(config){
16705 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
16709 * Fires when a date is selected
16710 * @param {DatePicker} this
16711 * @param {Date} date The selected date
16715 * @event monthchange
16716 * Fires when the displayed month changes
16717 * @param {DatePicker} this
16718 * @param {Date} date The selected month
16720 'monthchange': true,
16722 * @event evententer
16723 * Fires when mouse over an event
16724 * @param {Calendar} this
16725 * @param {event} Event
16727 'evententer': true,
16729 * @event eventleave
16730 * Fires when the mouse leaves an
16731 * @param {Calendar} this
16734 'eventleave': true,
16736 * @event eventclick
16737 * Fires when the mouse click an
16738 * @param {Calendar} this
16747 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
16750 * @cfg {Number} startDay
16751 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16759 getAutoCreate : function(){
16762 var fc_button = function(name, corner, style, content ) {
16763 return Roo.apply({},{
16765 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
16767 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
16770 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
16781 style : 'width:100%',
16788 cls : 'fc-header-left',
16790 fc_button('prev', 'left', 'arrow', '‹' ),
16791 fc_button('next', 'right', 'arrow', '›' ),
16792 { tag: 'span', cls: 'fc-header-space' },
16793 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
16801 cls : 'fc-header-center',
16805 cls: 'fc-header-title',
16808 html : 'month / year'
16816 cls : 'fc-header-right',
16818 /* fc_button('month', 'left', '', 'month' ),
16819 fc_button('week', '', '', 'week' ),
16820 fc_button('day', 'right', '', 'day' )
16832 header = this.header;
16835 var cal_heads = function() {
16837 // fixme - handle this.
16839 for (var i =0; i < Date.dayNames.length; i++) {
16840 var d = Date.dayNames[i];
16843 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
16844 html : d.substring(0,3)
16848 ret[0].cls += ' fc-first';
16849 ret[6].cls += ' fc-last';
16852 var cal_cell = function(n) {
16855 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
16860 cls: 'fc-day-number',
16864 cls: 'fc-day-content',
16868 style: 'position: relative;' // height: 17px;
16880 var cal_rows = function() {
16883 for (var r = 0; r < 6; r++) {
16890 for (var i =0; i < Date.dayNames.length; i++) {
16891 var d = Date.dayNames[i];
16892 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
16895 row.cn[0].cls+=' fc-first';
16896 row.cn[0].cn[0].style = 'min-height:90px';
16897 row.cn[6].cls+=' fc-last';
16901 ret[0].cls += ' fc-first';
16902 ret[4].cls += ' fc-prev-last';
16903 ret[5].cls += ' fc-last';
16910 cls: 'fc-border-separate',
16911 style : 'width:100%',
16919 cls : 'fc-first fc-last',
16937 cls : 'fc-content',
16938 style : "position: relative;",
16941 cls : 'fc-view fc-view-month fc-grid',
16942 style : 'position: relative',
16943 unselectable : 'on',
16946 cls : 'fc-event-container',
16947 style : 'position:absolute;z-index:8;top:0;left:0;'
16965 initEvents : function()
16968 throw "can not find store for calendar";
16974 style: "text-align:center",
16978 style: "background-color:white;width:50%;margin:250 auto",
16982 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
16993 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
16995 var size = this.el.select('.fc-content', true).first().getSize();
16996 this.maskEl.setSize(size.width, size.height);
16997 this.maskEl.enableDisplayMode("block");
16998 if(!this.loadMask){
16999 this.maskEl.hide();
17002 this.store = Roo.factory(this.store, Roo.data);
17003 this.store.on('load', this.onLoad, this);
17004 this.store.on('beforeload', this.onBeforeLoad, this);
17008 this.cells = this.el.select('.fc-day',true);
17009 //Roo.log(this.cells);
17010 this.textNodes = this.el.query('.fc-day-number');
17011 this.cells.addClassOnOver('fc-state-hover');
17013 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
17014 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
17015 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
17016 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
17018 this.on('monthchange', this.onMonthChange, this);
17020 this.update(new Date().clearTime());
17023 resize : function() {
17024 var sz = this.el.getSize();
17026 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
17027 this.el.select('.fc-day-content div',true).setHeight(34);
17032 showPrevMonth : function(e){
17033 this.update(this.activeDate.add("mo", -1));
17035 showToday : function(e){
17036 this.update(new Date().clearTime());
17039 showNextMonth : function(e){
17040 this.update(this.activeDate.add("mo", 1));
17044 showPrevYear : function(){
17045 this.update(this.activeDate.add("y", -1));
17049 showNextYear : function(){
17050 this.update(this.activeDate.add("y", 1));
17055 update : function(date)
17057 var vd = this.activeDate;
17058 this.activeDate = date;
17059 // if(vd && this.el){
17060 // var t = date.getTime();
17061 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
17062 // Roo.log('using add remove');
17064 // this.fireEvent('monthchange', this, date);
17066 // this.cells.removeClass("fc-state-highlight");
17067 // this.cells.each(function(c){
17068 // if(c.dateValue == t){
17069 // c.addClass("fc-state-highlight");
17070 // setTimeout(function(){
17071 // try{c.dom.firstChild.focus();}catch(e){}
17081 var days = date.getDaysInMonth();
17083 var firstOfMonth = date.getFirstDateOfMonth();
17084 var startingPos = firstOfMonth.getDay()-this.startDay;
17086 if(startingPos < this.startDay){
17090 var pm = date.add(Date.MONTH, -1);
17091 var prevStart = pm.getDaysInMonth()-startingPos;
17093 this.cells = this.el.select('.fc-day',true);
17094 this.textNodes = this.el.query('.fc-day-number');
17095 this.cells.addClassOnOver('fc-state-hover');
17097 var cells = this.cells.elements;
17098 var textEls = this.textNodes;
17100 Roo.each(cells, function(cell){
17101 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
17104 days += startingPos;
17106 // convert everything to numbers so it's fast
17107 var day = 86400000;
17108 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
17111 //Roo.log(prevStart);
17113 var today = new Date().clearTime().getTime();
17114 var sel = date.clearTime().getTime();
17115 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
17116 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
17117 var ddMatch = this.disabledDatesRE;
17118 var ddText = this.disabledDatesText;
17119 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
17120 var ddaysText = this.disabledDaysText;
17121 var format = this.format;
17123 var setCellClass = function(cal, cell){
17127 //Roo.log('set Cell Class');
17129 var t = d.getTime();
17133 cell.dateValue = t;
17135 cell.className += " fc-today";
17136 cell.className += " fc-state-highlight";
17137 cell.title = cal.todayText;
17140 // disable highlight in other month..
17141 //cell.className += " fc-state-highlight";
17146 cell.className = " fc-state-disabled";
17147 cell.title = cal.minText;
17151 cell.className = " fc-state-disabled";
17152 cell.title = cal.maxText;
17156 if(ddays.indexOf(d.getDay()) != -1){
17157 cell.title = ddaysText;
17158 cell.className = " fc-state-disabled";
17161 if(ddMatch && format){
17162 var fvalue = d.dateFormat(format);
17163 if(ddMatch.test(fvalue)){
17164 cell.title = ddText.replace("%0", fvalue);
17165 cell.className = " fc-state-disabled";
17169 if (!cell.initialClassName) {
17170 cell.initialClassName = cell.dom.className;
17173 cell.dom.className = cell.initialClassName + ' ' + cell.className;
17178 for(; i < startingPos; i++) {
17179 textEls[i].innerHTML = (++prevStart);
17180 d.setDate(d.getDate()+1);
17182 cells[i].className = "fc-past fc-other-month";
17183 setCellClass(this, cells[i]);
17188 for(; i < days; i++){
17189 intDay = i - startingPos + 1;
17190 textEls[i].innerHTML = (intDay);
17191 d.setDate(d.getDate()+1);
17193 cells[i].className = ''; // "x-date-active";
17194 setCellClass(this, cells[i]);
17198 for(; i < 42; i++) {
17199 textEls[i].innerHTML = (++extraDays);
17200 d.setDate(d.getDate()+1);
17202 cells[i].className = "fc-future fc-other-month";
17203 setCellClass(this, cells[i]);
17206 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
17208 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
17210 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
17211 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
17213 if(totalRows != 6){
17214 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
17215 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
17218 this.fireEvent('monthchange', this, date);
17222 if(!this.internalRender){
17223 var main = this.el.dom.firstChild;
17224 var w = main.offsetWidth;
17225 this.el.setWidth(w + this.el.getBorderWidth("lr"));
17226 Roo.fly(main).setWidth(w);
17227 this.internalRender = true;
17228 // opera does not respect the auto grow header center column
17229 // then, after it gets a width opera refuses to recalculate
17230 // without a second pass
17231 if(Roo.isOpera && !this.secondPass){
17232 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
17233 this.secondPass = true;
17234 this.update.defer(10, this, [date]);
17241 findCell : function(dt) {
17242 dt = dt.clearTime().getTime();
17244 this.cells.each(function(c){
17245 //Roo.log("check " +c.dateValue + '?=' + dt);
17246 if(c.dateValue == dt){
17256 findCells : function(ev) {
17257 var s = ev.start.clone().clearTime().getTime();
17259 var e= ev.end.clone().clearTime().getTime();
17262 this.cells.each(function(c){
17263 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
17265 if(c.dateValue > e){
17268 if(c.dateValue < s){
17277 // findBestRow: function(cells)
17281 // for (var i =0 ; i < cells.length;i++) {
17282 // ret = Math.max(cells[i].rows || 0,ret);
17289 addItem : function(ev)
17291 // look for vertical location slot in
17292 var cells = this.findCells(ev);
17294 // ev.row = this.findBestRow(cells);
17296 // work out the location.
17300 for(var i =0; i < cells.length; i++) {
17302 cells[i].row = cells[0].row;
17305 cells[i].row = cells[i].row + 1;
17315 if (crow.start.getY() == cells[i].getY()) {
17317 crow.end = cells[i];
17334 cells[0].events.push(ev);
17336 this.calevents.push(ev);
17339 clearEvents: function() {
17341 if(!this.calevents){
17345 Roo.each(this.cells.elements, function(c){
17351 Roo.each(this.calevents, function(e) {
17352 Roo.each(e.els, function(el) {
17353 el.un('mouseenter' ,this.onEventEnter, this);
17354 el.un('mouseleave' ,this.onEventLeave, this);
17359 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
17365 renderEvents: function()
17369 this.cells.each(function(c) {
17378 if(c.row != c.events.length){
17379 r = 4 - (4 - (c.row - c.events.length));
17382 c.events = ev.slice(0, r);
17383 c.more = ev.slice(r);
17385 if(c.more.length && c.more.length == 1){
17386 c.events.push(c.more.pop());
17389 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
17393 this.cells.each(function(c) {
17395 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
17398 for (var e = 0; e < c.events.length; e++){
17399 var ev = c.events[e];
17400 var rows = ev.rows;
17402 for(var i = 0; i < rows.length; i++) {
17404 // how many rows should it span..
17407 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
17408 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
17410 unselectable : "on",
17413 cls: 'fc-event-inner',
17417 // cls: 'fc-event-time',
17418 // html : cells.length > 1 ? '' : ev.time
17422 cls: 'fc-event-title',
17423 html : String.format('{0}', ev.title)
17430 cls: 'ui-resizable-handle ui-resizable-e',
17431 html : '  '
17438 cfg.cls += ' fc-event-start';
17440 if ((i+1) == rows.length) {
17441 cfg.cls += ' fc-event-end';
17444 var ctr = _this.el.select('.fc-event-container',true).first();
17445 var cg = ctr.createChild(cfg);
17447 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
17448 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
17450 var r = (c.more.length) ? 1 : 0;
17451 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
17452 cg.setWidth(ebox.right - sbox.x -2);
17454 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
17455 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
17456 cg.on('click', _this.onEventClick, _this, ev);
17467 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
17468 style : 'position: absolute',
17469 unselectable : "on",
17472 cls: 'fc-event-inner',
17476 cls: 'fc-event-title',
17484 cls: 'ui-resizable-handle ui-resizable-e',
17485 html : '  '
17491 var ctr = _this.el.select('.fc-event-container',true).first();
17492 var cg = ctr.createChild(cfg);
17494 var sbox = c.select('.fc-day-content',true).first().getBox();
17495 var ebox = c.select('.fc-day-content',true).first().getBox();
17497 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
17498 cg.setWidth(ebox.right - sbox.x -2);
17500 cg.on('click', _this.onMoreEventClick, _this, c.more);
17510 onEventEnter: function (e, el,event,d) {
17511 this.fireEvent('evententer', this, el, event);
17514 onEventLeave: function (e, el,event,d) {
17515 this.fireEvent('eventleave', this, el, event);
17518 onEventClick: function (e, el,event,d) {
17519 this.fireEvent('eventclick', this, el, event);
17522 onMonthChange: function () {
17526 onMoreEventClick: function(e, el, more)
17530 this.calpopover.placement = 'right';
17531 this.calpopover.setTitle('More');
17533 this.calpopover.setContent('');
17535 var ctr = this.calpopover.el.select('.popover-content', true).first();
17537 Roo.each(more, function(m){
17539 cls : 'fc-event-hori fc-event-draggable',
17542 var cg = ctr.createChild(cfg);
17544 cg.on('click', _this.onEventClick, _this, m);
17547 this.calpopover.show(el);
17552 onLoad: function ()
17554 this.calevents = [];
17557 if(this.store.getCount() > 0){
17558 this.store.data.each(function(d){
17561 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
17562 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
17563 time : d.data.start_time,
17564 title : d.data.title,
17565 description : d.data.description,
17566 venue : d.data.venue
17571 this.renderEvents();
17573 if(this.calevents.length && this.loadMask){
17574 this.maskEl.hide();
17578 onBeforeLoad: function()
17580 this.clearEvents();
17582 this.maskEl.show();
17596 * @class Roo.bootstrap.Popover
17597 * @extends Roo.bootstrap.Component
17598 * Bootstrap Popover class
17599 * @cfg {String} html contents of the popover (or false to use children..)
17600 * @cfg {String} title of popover (or false to hide)
17601 * @cfg {String} placement how it is placed
17602 * @cfg {String} trigger click || hover (or false to trigger manually)
17603 * @cfg {String} over what (parent or false to trigger manually.)
17604 * @cfg {Number} delay - delay before showing
17607 * Create a new Popover
17608 * @param {Object} config The config object
17611 Roo.bootstrap.Popover = function(config){
17612 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
17618 * After the popover show
17620 * @param {Roo.bootstrap.Popover} this
17625 * After the popover hide
17627 * @param {Roo.bootstrap.Popover} this
17633 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
17635 title: 'Fill in a title',
17638 placement : 'right',
17639 trigger : 'hover', // hover
17645 can_build_overlaid : false,
17647 getChildContainer : function()
17649 return this.el.select('.popover-content',true).first();
17652 getAutoCreate : function(){
17655 cls : 'popover roo-dynamic',
17656 style: 'display:block',
17662 cls : 'popover-inner',
17666 cls: 'popover-title popover-header',
17670 cls : 'popover-content popover-body',
17681 setTitle: function(str)
17684 this.el.select('.popover-title',true).first().dom.innerHTML = str;
17686 setContent: function(str)
17689 this.el.select('.popover-content',true).first().dom.innerHTML = str;
17691 // as it get's added to the bottom of the page.
17692 onRender : function(ct, position)
17694 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17696 var cfg = Roo.apply({}, this.getAutoCreate());
17700 cfg.cls += ' ' + this.cls;
17703 cfg.style = this.style;
17705 //Roo.log("adding to ");
17706 this.el = Roo.get(document.body).createChild(cfg, position);
17707 // Roo.log(this.el);
17712 initEvents : function()
17714 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
17715 this.el.enableDisplayMode('block');
17717 if (this.over === false) {
17720 if (this.triggers === false) {
17723 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17724 var triggers = this.trigger ? this.trigger.split(' ') : [];
17725 Roo.each(triggers, function(trigger) {
17727 if (trigger == 'click') {
17728 on_el.on('click', this.toggle, this);
17729 } else if (trigger != 'manual') {
17730 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
17731 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
17733 on_el.on(eventIn ,this.enter, this);
17734 on_el.on(eventOut, this.leave, this);
17745 toggle : function () {
17746 this.hoverState == 'in' ? this.leave() : this.enter();
17749 enter : function () {
17751 clearTimeout(this.timeout);
17753 this.hoverState = 'in';
17755 if (!this.delay || !this.delay.show) {
17760 this.timeout = setTimeout(function () {
17761 if (_t.hoverState == 'in') {
17764 }, this.delay.show)
17767 leave : function() {
17768 clearTimeout(this.timeout);
17770 this.hoverState = 'out';
17772 if (!this.delay || !this.delay.hide) {
17777 this.timeout = setTimeout(function () {
17778 if (_t.hoverState == 'out') {
17781 }, this.delay.hide)
17784 show : function (on_el)
17787 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17791 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
17792 if (this.html !== false) {
17793 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
17795 this.el.removeClass([
17796 'fade','top','bottom', 'left', 'right','in',
17797 'bs-popover-top','bs-popover-bottom', 'bs-popover-left', 'bs-popover-right'
17799 if (!this.title.length) {
17800 this.el.select('.popover-title',true).hide();
17803 var placement = typeof this.placement == 'function' ?
17804 this.placement.call(this, this.el, on_el) :
17807 var autoToken = /\s?auto?\s?/i;
17808 var autoPlace = autoToken.test(placement);
17810 placement = placement.replace(autoToken, '') || 'top';
17814 //this.el.setXY([0,0]);
17816 this.el.dom.style.display='block';
17817 this.el.addClass(placement);
17819 //this.el.appendTo(on_el);
17821 var p = this.getPosition();
17822 var box = this.el.getBox();
17827 var align = Roo.bootstrap.Popover.alignment[placement];
17830 this.el.alignTo(on_el, align[0],align[1]);
17831 //var arrow = this.el.select('.arrow',true).first();
17832 //arrow.set(align[2],
17834 this.el.addClass('in');
17837 if (this.el.hasClass('fade')) {
17841 this.hoverState = 'in';
17843 this.fireEvent('show', this);
17848 this.el.setXY([0,0]);
17849 this.el.removeClass('in');
17851 this.hoverState = null;
17853 this.fireEvent('hide', this);
17858 Roo.bootstrap.Popover.alignment = {
17859 'left' : ['r-l', [-10,0], 'right bs-popover-right'],
17860 'right' : ['l-r', [10,0], 'left bs-popover-left'],
17861 'bottom' : ['t-b', [0,10], 'top bs-popover-top'],
17862 'top' : [ 'b-t', [0,-10], 'bottom bs-popover-bottom']
17873 * @class Roo.bootstrap.Progress
17874 * @extends Roo.bootstrap.Component
17875 * Bootstrap Progress class
17876 * @cfg {Boolean} striped striped of the progress bar
17877 * @cfg {Boolean} active animated of the progress bar
17881 * Create a new Progress
17882 * @param {Object} config The config object
17885 Roo.bootstrap.Progress = function(config){
17886 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
17889 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
17894 getAutoCreate : function(){
17902 cfg.cls += ' progress-striped';
17906 cfg.cls += ' active';
17925 * @class Roo.bootstrap.ProgressBar
17926 * @extends Roo.bootstrap.Component
17927 * Bootstrap ProgressBar class
17928 * @cfg {Number} aria_valuenow aria-value now
17929 * @cfg {Number} aria_valuemin aria-value min
17930 * @cfg {Number} aria_valuemax aria-value max
17931 * @cfg {String} label label for the progress bar
17932 * @cfg {String} panel (success | info | warning | danger )
17933 * @cfg {String} role role of the progress bar
17934 * @cfg {String} sr_only text
17938 * Create a new ProgressBar
17939 * @param {Object} config The config object
17942 Roo.bootstrap.ProgressBar = function(config){
17943 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
17946 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
17950 aria_valuemax : 100,
17956 getAutoCreate : function()
17961 cls: 'progress-bar',
17962 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
17974 cfg.role = this.role;
17977 if(this.aria_valuenow){
17978 cfg['aria-valuenow'] = this.aria_valuenow;
17981 if(this.aria_valuemin){
17982 cfg['aria-valuemin'] = this.aria_valuemin;
17985 if(this.aria_valuemax){
17986 cfg['aria-valuemax'] = this.aria_valuemax;
17989 if(this.label && !this.sr_only){
17990 cfg.html = this.label;
17994 cfg.cls += ' progress-bar-' + this.panel;
18000 update : function(aria_valuenow)
18002 this.aria_valuenow = aria_valuenow;
18004 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
18019 * @class Roo.bootstrap.TabGroup
18020 * @extends Roo.bootstrap.Column
18021 * Bootstrap Column class
18022 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
18023 * @cfg {Boolean} carousel true to make the group behave like a carousel
18024 * @cfg {Boolean} bullets show bullets for the panels
18025 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
18026 * @cfg {Number} timer auto slide timer .. default 0 millisecond
18027 * @cfg {Boolean} showarrow (true|false) show arrow default true
18030 * Create a new TabGroup
18031 * @param {Object} config The config object
18034 Roo.bootstrap.TabGroup = function(config){
18035 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
18037 this.navId = Roo.id();
18040 Roo.bootstrap.TabGroup.register(this);
18044 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
18047 transition : false,
18052 slideOnTouch : false,
18055 getAutoCreate : function()
18057 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
18059 cfg.cls += ' tab-content';
18061 if (this.carousel) {
18062 cfg.cls += ' carousel slide';
18065 cls : 'carousel-inner',
18069 if(this.bullets && !Roo.isTouch){
18072 cls : 'carousel-bullets',
18076 if(this.bullets_cls){
18077 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
18084 cfg.cn[0].cn.push(bullets);
18087 if(this.showarrow){
18088 cfg.cn[0].cn.push({
18090 class : 'carousel-arrow',
18094 class : 'carousel-prev',
18098 class : 'fa fa-chevron-left'
18104 class : 'carousel-next',
18108 class : 'fa fa-chevron-right'
18121 initEvents: function()
18123 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
18124 // this.el.on("touchstart", this.onTouchStart, this);
18127 if(this.autoslide){
18130 this.slideFn = window.setInterval(function() {
18131 _this.showPanelNext();
18135 if(this.showarrow){
18136 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
18137 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
18143 // onTouchStart : function(e, el, o)
18145 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
18149 // this.showPanelNext();
18153 getChildContainer : function()
18155 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
18159 * register a Navigation item
18160 * @param {Roo.bootstrap.NavItem} the navitem to add
18162 register : function(item)
18164 this.tabs.push( item);
18165 item.navId = this.navId; // not really needed..
18170 getActivePanel : function()
18173 Roo.each(this.tabs, function(t) {
18183 getPanelByName : function(n)
18186 Roo.each(this.tabs, function(t) {
18187 if (t.tabId == n) {
18195 indexOfPanel : function(p)
18198 Roo.each(this.tabs, function(t,i) {
18199 if (t.tabId == p.tabId) {
18208 * show a specific panel
18209 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
18210 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
18212 showPanel : function (pan)
18214 if(this.transition || typeof(pan) == 'undefined'){
18215 Roo.log("waiting for the transitionend");
18219 if (typeof(pan) == 'number') {
18220 pan = this.tabs[pan];
18223 if (typeof(pan) == 'string') {
18224 pan = this.getPanelByName(pan);
18227 var cur = this.getActivePanel();
18230 Roo.log('pan or acitve pan is undefined');
18234 if (pan.tabId == this.getActivePanel().tabId) {
18238 if (false === cur.fireEvent('beforedeactivate')) {
18242 if(this.bullets > 0 && !Roo.isTouch){
18243 this.setActiveBullet(this.indexOfPanel(pan));
18246 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
18248 this.transition = true;
18249 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
18250 var lr = dir == 'next' ? 'left' : 'right';
18251 pan.el.addClass(dir); // or prev
18252 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
18253 cur.el.addClass(lr); // or right
18254 pan.el.addClass(lr);
18257 cur.el.on('transitionend', function() {
18258 Roo.log("trans end?");
18260 pan.el.removeClass([lr,dir]);
18261 pan.setActive(true);
18263 cur.el.removeClass([lr]);
18264 cur.setActive(false);
18266 _this.transition = false;
18268 }, this, { single: true } );
18273 cur.setActive(false);
18274 pan.setActive(true);
18279 showPanelNext : function()
18281 var i = this.indexOfPanel(this.getActivePanel());
18283 if (i >= this.tabs.length - 1 && !this.autoslide) {
18287 if (i >= this.tabs.length - 1 && this.autoslide) {
18291 this.showPanel(this.tabs[i+1]);
18294 showPanelPrev : function()
18296 var i = this.indexOfPanel(this.getActivePanel());
18298 if (i < 1 && !this.autoslide) {
18302 if (i < 1 && this.autoslide) {
18303 i = this.tabs.length;
18306 this.showPanel(this.tabs[i-1]);
18310 addBullet: function()
18312 if(!this.bullets || Roo.isTouch){
18315 var ctr = this.el.select('.carousel-bullets',true).first();
18316 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
18317 var bullet = ctr.createChild({
18318 cls : 'bullet bullet-' + i
18319 },ctr.dom.lastChild);
18324 bullet.on('click', (function(e, el, o, ii, t){
18326 e.preventDefault();
18328 this.showPanel(ii);
18330 if(this.autoslide && this.slideFn){
18331 clearInterval(this.slideFn);
18332 this.slideFn = window.setInterval(function() {
18333 _this.showPanelNext();
18337 }).createDelegate(this, [i, bullet], true));
18342 setActiveBullet : function(i)
18348 Roo.each(this.el.select('.bullet', true).elements, function(el){
18349 el.removeClass('selected');
18352 var bullet = this.el.select('.bullet-' + i, true).first();
18358 bullet.addClass('selected');
18369 Roo.apply(Roo.bootstrap.TabGroup, {
18373 * register a Navigation Group
18374 * @param {Roo.bootstrap.NavGroup} the navgroup to add
18376 register : function(navgrp)
18378 this.groups[navgrp.navId] = navgrp;
18382 * fetch a Navigation Group based on the navigation ID
18383 * if one does not exist , it will get created.
18384 * @param {string} the navgroup to add
18385 * @returns {Roo.bootstrap.NavGroup} the navgroup
18387 get: function(navId) {
18388 if (typeof(this.groups[navId]) == 'undefined') {
18389 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
18391 return this.groups[navId] ;
18406 * @class Roo.bootstrap.TabPanel
18407 * @extends Roo.bootstrap.Component
18408 * Bootstrap TabPanel class
18409 * @cfg {Boolean} active panel active
18410 * @cfg {String} html panel content
18411 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
18412 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
18413 * @cfg {String} href click to link..
18417 * Create a new TabPanel
18418 * @param {Object} config The config object
18421 Roo.bootstrap.TabPanel = function(config){
18422 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
18426 * Fires when the active status changes
18427 * @param {Roo.bootstrap.TabPanel} this
18428 * @param {Boolean} state the new state
18433 * @event beforedeactivate
18434 * Fires before a tab is de-activated - can be used to do validation on a form.
18435 * @param {Roo.bootstrap.TabPanel} this
18436 * @return {Boolean} false if there is an error
18439 'beforedeactivate': true
18442 this.tabId = this.tabId || Roo.id();
18446 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
18454 getAutoCreate : function(){
18457 // item is needed for carousel - not sure if it has any effect otherwise
18458 cls: 'tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
18459 html: this.html || ''
18463 cfg.cls += ' active';
18467 cfg.tabId = this.tabId;
18474 initEvents: function()
18476 var p = this.parent();
18478 this.navId = this.navId || p.navId;
18480 if (typeof(this.navId) != 'undefined') {
18481 // not really needed.. but just in case.. parent should be a NavGroup.
18482 var tg = Roo.bootstrap.TabGroup.get(this.navId);
18486 var i = tg.tabs.length - 1;
18488 if(this.active && tg.bullets > 0 && i < tg.bullets){
18489 tg.setActiveBullet(i);
18493 this.el.on('click', this.onClick, this);
18496 this.el.on("touchstart", this.onTouchStart, this);
18497 this.el.on("touchmove", this.onTouchMove, this);
18498 this.el.on("touchend", this.onTouchEnd, this);
18503 onRender : function(ct, position)
18505 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
18508 setActive : function(state)
18510 Roo.log("panel - set active " + this.tabId + "=" + state);
18512 this.active = state;
18514 this.el.removeClass('active');
18516 } else if (!this.el.hasClass('active')) {
18517 this.el.addClass('active');
18520 this.fireEvent('changed', this, state);
18523 onClick : function(e)
18525 e.preventDefault();
18527 if(!this.href.length){
18531 window.location.href = this.href;
18540 onTouchStart : function(e)
18542 this.swiping = false;
18544 this.startX = e.browserEvent.touches[0].clientX;
18545 this.startY = e.browserEvent.touches[0].clientY;
18548 onTouchMove : function(e)
18550 this.swiping = true;
18552 this.endX = e.browserEvent.touches[0].clientX;
18553 this.endY = e.browserEvent.touches[0].clientY;
18556 onTouchEnd : function(e)
18563 var tabGroup = this.parent();
18565 if(this.endX > this.startX){ // swiping right
18566 tabGroup.showPanelPrev();
18570 if(this.startX > this.endX){ // swiping left
18571 tabGroup.showPanelNext();
18590 * @class Roo.bootstrap.DateField
18591 * @extends Roo.bootstrap.Input
18592 * Bootstrap DateField class
18593 * @cfg {Number} weekStart default 0
18594 * @cfg {String} viewMode default empty, (months|years)
18595 * @cfg {String} minViewMode default empty, (months|years)
18596 * @cfg {Number} startDate default -Infinity
18597 * @cfg {Number} endDate default Infinity
18598 * @cfg {Boolean} todayHighlight default false
18599 * @cfg {Boolean} todayBtn default false
18600 * @cfg {Boolean} calendarWeeks default false
18601 * @cfg {Object} daysOfWeekDisabled default empty
18602 * @cfg {Boolean} singleMode default false (true | false)
18604 * @cfg {Boolean} keyboardNavigation default true
18605 * @cfg {String} language default en
18608 * Create a new DateField
18609 * @param {Object} config The config object
18612 Roo.bootstrap.DateField = function(config){
18613 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
18617 * Fires when this field show.
18618 * @param {Roo.bootstrap.DateField} this
18619 * @param {Mixed} date The date value
18624 * Fires when this field hide.
18625 * @param {Roo.bootstrap.DateField} this
18626 * @param {Mixed} date The date value
18631 * Fires when select a date.
18632 * @param {Roo.bootstrap.DateField} this
18633 * @param {Mixed} date The date value
18637 * @event beforeselect
18638 * Fires when before select a date.
18639 * @param {Roo.bootstrap.DateField} this
18640 * @param {Mixed} date The date value
18642 beforeselect : true
18646 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
18649 * @cfg {String} format
18650 * The default date format string which can be overriden for localization support. The format must be
18651 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
18655 * @cfg {String} altFormats
18656 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
18657 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
18659 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
18667 todayHighlight : false,
18673 keyboardNavigation: true,
18675 calendarWeeks: false,
18677 startDate: -Infinity,
18681 daysOfWeekDisabled: [],
18685 singleMode : false,
18687 UTCDate: function()
18689 return new Date(Date.UTC.apply(Date, arguments));
18692 UTCToday: function()
18694 var today = new Date();
18695 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
18698 getDate: function() {
18699 var d = this.getUTCDate();
18700 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
18703 getUTCDate: function() {
18707 setDate: function(d) {
18708 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
18711 setUTCDate: function(d) {
18713 this.setValue(this.formatDate(this.date));
18716 onRender: function(ct, position)
18719 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
18721 this.language = this.language || 'en';
18722 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
18723 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
18725 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
18726 this.format = this.format || 'm/d/y';
18727 this.isInline = false;
18728 this.isInput = true;
18729 this.component = this.el.select('.add-on', true).first() || false;
18730 this.component = (this.component && this.component.length === 0) ? false : this.component;
18731 this.hasInput = this.component && this.inputEl().length;
18733 if (typeof(this.minViewMode === 'string')) {
18734 switch (this.minViewMode) {
18736 this.minViewMode = 1;
18739 this.minViewMode = 2;
18742 this.minViewMode = 0;
18747 if (typeof(this.viewMode === 'string')) {
18748 switch (this.viewMode) {
18761 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
18763 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
18765 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18767 this.picker().on('mousedown', this.onMousedown, this);
18768 this.picker().on('click', this.onClick, this);
18770 this.picker().addClass('datepicker-dropdown');
18772 this.startViewMode = this.viewMode;
18774 if(this.singleMode){
18775 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
18776 v.setVisibilityMode(Roo.Element.DISPLAY);
18780 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
18781 v.setStyle('width', '189px');
18785 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
18786 if(!this.calendarWeeks){
18791 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18792 v.attr('colspan', function(i, val){
18793 return parseInt(val) + 1;
18798 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
18800 this.setStartDate(this.startDate);
18801 this.setEndDate(this.endDate);
18803 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
18810 if(this.isInline) {
18815 picker : function()
18817 return this.pickerEl;
18818 // return this.el.select('.datepicker', true).first();
18821 fillDow: function()
18823 var dowCnt = this.weekStart;
18832 if(this.calendarWeeks){
18840 while (dowCnt < this.weekStart + 7) {
18844 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
18848 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
18851 fillMonths: function()
18854 var months = this.picker().select('>.datepicker-months td', true).first();
18856 months.dom.innerHTML = '';
18862 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
18865 months.createChild(month);
18872 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;
18874 if (this.date < this.startDate) {
18875 this.viewDate = new Date(this.startDate);
18876 } else if (this.date > this.endDate) {
18877 this.viewDate = new Date(this.endDate);
18879 this.viewDate = new Date(this.date);
18887 var d = new Date(this.viewDate),
18888 year = d.getUTCFullYear(),
18889 month = d.getUTCMonth(),
18890 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
18891 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
18892 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
18893 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
18894 currentDate = this.date && this.date.valueOf(),
18895 today = this.UTCToday();
18897 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
18899 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18901 // this.picker.select('>tfoot th.today').
18902 // .text(dates[this.language].today)
18903 // .toggle(this.todayBtn !== false);
18905 this.updateNavArrows();
18908 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
18910 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
18912 prevMonth.setUTCDate(day);
18914 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
18916 var nextMonth = new Date(prevMonth);
18918 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
18920 nextMonth = nextMonth.valueOf();
18922 var fillMonths = false;
18924 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
18926 while(prevMonth.valueOf() <= nextMonth) {
18929 if (prevMonth.getUTCDay() === this.weekStart) {
18931 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
18939 if(this.calendarWeeks){
18940 // ISO 8601: First week contains first thursday.
18941 // ISO also states week starts on Monday, but we can be more abstract here.
18943 // Start of current week: based on weekstart/current date
18944 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
18945 // Thursday of this week
18946 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
18947 // First Thursday of year, year from thursday
18948 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
18949 // Calendar week: ms between thursdays, div ms per day, div 7 days
18950 calWeek = (th - yth) / 864e5 / 7 + 1;
18952 fillMonths.cn.push({
18960 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
18962 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
18965 if (this.todayHighlight &&
18966 prevMonth.getUTCFullYear() == today.getFullYear() &&
18967 prevMonth.getUTCMonth() == today.getMonth() &&
18968 prevMonth.getUTCDate() == today.getDate()) {
18969 clsName += ' today';
18972 if (currentDate && prevMonth.valueOf() === currentDate) {
18973 clsName += ' active';
18976 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
18977 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
18978 clsName += ' disabled';
18981 fillMonths.cn.push({
18983 cls: 'day ' + clsName,
18984 html: prevMonth.getDate()
18987 prevMonth.setDate(prevMonth.getDate()+1);
18990 var currentYear = this.date && this.date.getUTCFullYear();
18991 var currentMonth = this.date && this.date.getUTCMonth();
18993 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
18995 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
18996 v.removeClass('active');
18998 if(currentYear === year && k === currentMonth){
18999 v.addClass('active');
19002 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
19003 v.addClass('disabled');
19009 year = parseInt(year/10, 10) * 10;
19011 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
19013 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
19016 for (var i = -1; i < 11; i++) {
19017 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
19019 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
19027 showMode: function(dir)
19030 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
19033 Roo.each(this.picker().select('>div',true).elements, function(v){
19034 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19037 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
19042 if(this.isInline) {
19046 this.picker().removeClass(['bottom', 'top']);
19048 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
19050 * place to the top of element!
19054 this.picker().addClass('top');
19055 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
19060 this.picker().addClass('bottom');
19062 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
19065 parseDate : function(value)
19067 if(!value || value instanceof Date){
19070 var v = Date.parseDate(value, this.format);
19071 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
19072 v = Date.parseDate(value, 'Y-m-d');
19074 if(!v && this.altFormats){
19075 if(!this.altFormatsArray){
19076 this.altFormatsArray = this.altFormats.split("|");
19078 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
19079 v = Date.parseDate(value, this.altFormatsArray[i]);
19085 formatDate : function(date, fmt)
19087 return (!date || !(date instanceof Date)) ?
19088 date : date.dateFormat(fmt || this.format);
19091 onFocus : function()
19093 Roo.bootstrap.DateField.superclass.onFocus.call(this);
19097 onBlur : function()
19099 Roo.bootstrap.DateField.superclass.onBlur.call(this);
19101 var d = this.inputEl().getValue();
19108 showPopup : function()
19110 this.picker().show();
19114 this.fireEvent('showpopup', this, this.date);
19117 hidePopup : function()
19119 if(this.isInline) {
19122 this.picker().hide();
19123 this.viewMode = this.startViewMode;
19126 this.fireEvent('hidepopup', this, this.date);
19130 onMousedown: function(e)
19132 e.stopPropagation();
19133 e.preventDefault();
19138 Roo.bootstrap.DateField.superclass.keyup.call(this);
19142 setValue: function(v)
19144 if(this.fireEvent('beforeselect', this, v) !== false){
19145 var d = new Date(this.parseDate(v) ).clearTime();
19147 if(isNaN(d.getTime())){
19148 this.date = this.viewDate = '';
19149 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
19153 v = this.formatDate(d);
19155 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
19157 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
19161 this.fireEvent('select', this, this.date);
19165 getValue: function()
19167 return this.formatDate(this.date);
19170 fireKey: function(e)
19172 if (!this.picker().isVisible()){
19173 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19179 var dateChanged = false,
19181 newDate, newViewDate;
19186 e.preventDefault();
19190 if (!this.keyboardNavigation) {
19193 dir = e.keyCode == 37 ? -1 : 1;
19196 newDate = this.moveYear(this.date, dir);
19197 newViewDate = this.moveYear(this.viewDate, dir);
19198 } else if (e.shiftKey){
19199 newDate = this.moveMonth(this.date, dir);
19200 newViewDate = this.moveMonth(this.viewDate, dir);
19202 newDate = new Date(this.date);
19203 newDate.setUTCDate(this.date.getUTCDate() + dir);
19204 newViewDate = new Date(this.viewDate);
19205 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
19207 if (this.dateWithinRange(newDate)){
19208 this.date = newDate;
19209 this.viewDate = newViewDate;
19210 this.setValue(this.formatDate(this.date));
19212 e.preventDefault();
19213 dateChanged = true;
19218 if (!this.keyboardNavigation) {
19221 dir = e.keyCode == 38 ? -1 : 1;
19223 newDate = this.moveYear(this.date, dir);
19224 newViewDate = this.moveYear(this.viewDate, dir);
19225 } else if (e.shiftKey){
19226 newDate = this.moveMonth(this.date, dir);
19227 newViewDate = this.moveMonth(this.viewDate, dir);
19229 newDate = new Date(this.date);
19230 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
19231 newViewDate = new Date(this.viewDate);
19232 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
19234 if (this.dateWithinRange(newDate)){
19235 this.date = newDate;
19236 this.viewDate = newViewDate;
19237 this.setValue(this.formatDate(this.date));
19239 e.preventDefault();
19240 dateChanged = true;
19244 this.setValue(this.formatDate(this.date));
19246 e.preventDefault();
19249 this.setValue(this.formatDate(this.date));
19263 onClick: function(e)
19265 e.stopPropagation();
19266 e.preventDefault();
19268 var target = e.getTarget();
19270 if(target.nodeName.toLowerCase() === 'i'){
19271 target = Roo.get(target).dom.parentNode;
19274 var nodeName = target.nodeName;
19275 var className = target.className;
19276 var html = target.innerHTML;
19277 //Roo.log(nodeName);
19279 switch(nodeName.toLowerCase()) {
19281 switch(className) {
19287 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
19288 switch(this.viewMode){
19290 this.viewDate = this.moveMonth(this.viewDate, dir);
19294 this.viewDate = this.moveYear(this.viewDate, dir);
19300 var date = new Date();
19301 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
19303 this.setValue(this.formatDate(this.date));
19310 if (className.indexOf('disabled') < 0) {
19311 this.viewDate.setUTCDate(1);
19312 if (className.indexOf('month') > -1) {
19313 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
19315 var year = parseInt(html, 10) || 0;
19316 this.viewDate.setUTCFullYear(year);
19320 if(this.singleMode){
19321 this.setValue(this.formatDate(this.viewDate));
19332 //Roo.log(className);
19333 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
19334 var day = parseInt(html, 10) || 1;
19335 var year = this.viewDate.getUTCFullYear(),
19336 month = this.viewDate.getUTCMonth();
19338 if (className.indexOf('old') > -1) {
19345 } else if (className.indexOf('new') > -1) {
19353 //Roo.log([year,month,day]);
19354 this.date = this.UTCDate(year, month, day,0,0,0,0);
19355 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
19357 //Roo.log(this.formatDate(this.date));
19358 this.setValue(this.formatDate(this.date));
19365 setStartDate: function(startDate)
19367 this.startDate = startDate || -Infinity;
19368 if (this.startDate !== -Infinity) {
19369 this.startDate = this.parseDate(this.startDate);
19372 this.updateNavArrows();
19375 setEndDate: function(endDate)
19377 this.endDate = endDate || Infinity;
19378 if (this.endDate !== Infinity) {
19379 this.endDate = this.parseDate(this.endDate);
19382 this.updateNavArrows();
19385 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
19387 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
19388 if (typeof(this.daysOfWeekDisabled) !== 'object') {
19389 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
19391 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
19392 return parseInt(d, 10);
19395 this.updateNavArrows();
19398 updateNavArrows: function()
19400 if(this.singleMode){
19404 var d = new Date(this.viewDate),
19405 year = d.getUTCFullYear(),
19406 month = d.getUTCMonth();
19408 Roo.each(this.picker().select('.prev', true).elements, function(v){
19410 switch (this.viewMode) {
19413 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
19419 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
19426 Roo.each(this.picker().select('.next', true).elements, function(v){
19428 switch (this.viewMode) {
19431 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
19437 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
19445 moveMonth: function(date, dir)
19450 var new_date = new Date(date.valueOf()),
19451 day = new_date.getUTCDate(),
19452 month = new_date.getUTCMonth(),
19453 mag = Math.abs(dir),
19455 dir = dir > 0 ? 1 : -1;
19458 // If going back one month, make sure month is not current month
19459 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
19461 return new_date.getUTCMonth() == month;
19463 // If going forward one month, make sure month is as expected
19464 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
19466 return new_date.getUTCMonth() != new_month;
19468 new_month = month + dir;
19469 new_date.setUTCMonth(new_month);
19470 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
19471 if (new_month < 0 || new_month > 11) {
19472 new_month = (new_month + 12) % 12;
19475 // For magnitudes >1, move one month at a time...
19476 for (var i=0; i<mag; i++) {
19477 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
19478 new_date = this.moveMonth(new_date, dir);
19480 // ...then reset the day, keeping it in the new month
19481 new_month = new_date.getUTCMonth();
19482 new_date.setUTCDate(day);
19484 return new_month != new_date.getUTCMonth();
19487 // Common date-resetting loop -- if date is beyond end of month, make it
19490 new_date.setUTCDate(--day);
19491 new_date.setUTCMonth(new_month);
19496 moveYear: function(date, dir)
19498 return this.moveMonth(date, dir*12);
19501 dateWithinRange: function(date)
19503 return date >= this.startDate && date <= this.endDate;
19509 this.picker().remove();
19512 validateValue : function(value)
19514 if(this.getVisibilityEl().hasClass('hidden')){
19518 if(value.length < 1) {
19519 if(this.allowBlank){
19525 if(value.length < this.minLength){
19528 if(value.length > this.maxLength){
19532 var vt = Roo.form.VTypes;
19533 if(!vt[this.vtype](value, this)){
19537 if(typeof this.validator == "function"){
19538 var msg = this.validator(value);
19544 if(this.regex && !this.regex.test(value)){
19548 if(typeof(this.parseDate(value)) == 'undefined'){
19552 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
19556 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
19566 this.date = this.viewDate = '';
19568 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
19573 Roo.apply(Roo.bootstrap.DateField, {
19584 html: '<i class="fa fa-arrow-left"/>'
19594 html: '<i class="fa fa-arrow-right"/>'
19636 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
19637 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
19638 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
19639 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19640 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
19653 navFnc: 'FullYear',
19658 navFnc: 'FullYear',
19663 Roo.apply(Roo.bootstrap.DateField, {
19667 cls: 'datepicker dropdown-menu roo-dynamic',
19671 cls: 'datepicker-days',
19675 cls: 'table-condensed',
19677 Roo.bootstrap.DateField.head,
19681 Roo.bootstrap.DateField.footer
19688 cls: 'datepicker-months',
19692 cls: 'table-condensed',
19694 Roo.bootstrap.DateField.head,
19695 Roo.bootstrap.DateField.content,
19696 Roo.bootstrap.DateField.footer
19703 cls: 'datepicker-years',
19707 cls: 'table-condensed',
19709 Roo.bootstrap.DateField.head,
19710 Roo.bootstrap.DateField.content,
19711 Roo.bootstrap.DateField.footer
19730 * @class Roo.bootstrap.TimeField
19731 * @extends Roo.bootstrap.Input
19732 * Bootstrap DateField class
19736 * Create a new TimeField
19737 * @param {Object} config The config object
19740 Roo.bootstrap.TimeField = function(config){
19741 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
19745 * Fires when this field show.
19746 * @param {Roo.bootstrap.DateField} thisthis
19747 * @param {Mixed} date The date value
19752 * Fires when this field hide.
19753 * @param {Roo.bootstrap.DateField} this
19754 * @param {Mixed} date The date value
19759 * Fires when select a date.
19760 * @param {Roo.bootstrap.DateField} this
19761 * @param {Mixed} date The date value
19767 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
19770 * @cfg {String} format
19771 * The default time format string which can be overriden for localization support. The format must be
19772 * valid according to {@link Date#parseDate} (defaults to 'H:i').
19776 onRender: function(ct, position)
19779 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
19781 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
19783 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19785 this.pop = this.picker().select('>.datepicker-time',true).first();
19786 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19788 this.picker().on('mousedown', this.onMousedown, this);
19789 this.picker().on('click', this.onClick, this);
19791 this.picker().addClass('datepicker-dropdown');
19796 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
19797 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
19798 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
19799 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
19800 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
19801 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
19805 fireKey: function(e){
19806 if (!this.picker().isVisible()){
19807 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19813 e.preventDefault();
19821 this.onTogglePeriod();
19824 this.onIncrementMinutes();
19827 this.onDecrementMinutes();
19836 onClick: function(e) {
19837 e.stopPropagation();
19838 e.preventDefault();
19841 picker : function()
19843 return this.el.select('.datepicker', true).first();
19846 fillTime: function()
19848 var time = this.pop.select('tbody', true).first();
19850 time.dom.innerHTML = '';
19865 cls: 'hours-up glyphicon glyphicon-chevron-up'
19885 cls: 'minutes-up glyphicon glyphicon-chevron-up'
19906 cls: 'timepicker-hour',
19921 cls: 'timepicker-minute',
19936 cls: 'btn btn-primary period',
19958 cls: 'hours-down glyphicon glyphicon-chevron-down'
19978 cls: 'minutes-down glyphicon glyphicon-chevron-down'
19996 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
20003 var hours = this.time.getHours();
20004 var minutes = this.time.getMinutes();
20017 hours = hours - 12;
20021 hours = '0' + hours;
20025 minutes = '0' + minutes;
20028 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
20029 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
20030 this.pop.select('button', true).first().dom.innerHTML = period;
20036 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
20038 var cls = ['bottom'];
20040 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
20047 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
20052 this.picker().addClass(cls.join('-'));
20056 Roo.each(cls, function(c){
20058 _this.picker().setTop(_this.inputEl().getHeight());
20062 _this.picker().setTop(0 - _this.picker().getHeight());
20067 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
20071 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
20078 onFocus : function()
20080 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
20084 onBlur : function()
20086 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
20092 this.picker().show();
20097 this.fireEvent('show', this, this.date);
20102 this.picker().hide();
20105 this.fireEvent('hide', this, this.date);
20108 setTime : function()
20111 this.setValue(this.time.format(this.format));
20113 this.fireEvent('select', this, this.date);
20118 onMousedown: function(e){
20119 e.stopPropagation();
20120 e.preventDefault();
20123 onIncrementHours: function()
20125 Roo.log('onIncrementHours');
20126 this.time = this.time.add(Date.HOUR, 1);
20131 onDecrementHours: function()
20133 Roo.log('onDecrementHours');
20134 this.time = this.time.add(Date.HOUR, -1);
20138 onIncrementMinutes: function()
20140 Roo.log('onIncrementMinutes');
20141 this.time = this.time.add(Date.MINUTE, 1);
20145 onDecrementMinutes: function()
20147 Roo.log('onDecrementMinutes');
20148 this.time = this.time.add(Date.MINUTE, -1);
20152 onTogglePeriod: function()
20154 Roo.log('onTogglePeriod');
20155 this.time = this.time.add(Date.HOUR, 12);
20162 Roo.apply(Roo.bootstrap.TimeField, {
20192 cls: 'btn btn-info ok',
20204 Roo.apply(Roo.bootstrap.TimeField, {
20208 cls: 'datepicker dropdown-menu',
20212 cls: 'datepicker-time',
20216 cls: 'table-condensed',
20218 Roo.bootstrap.TimeField.content,
20219 Roo.bootstrap.TimeField.footer
20238 * @class Roo.bootstrap.MonthField
20239 * @extends Roo.bootstrap.Input
20240 * Bootstrap MonthField class
20242 * @cfg {String} language default en
20245 * Create a new MonthField
20246 * @param {Object} config The config object
20249 Roo.bootstrap.MonthField = function(config){
20250 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
20255 * Fires when this field show.
20256 * @param {Roo.bootstrap.MonthField} this
20257 * @param {Mixed} date The date value
20262 * Fires when this field hide.
20263 * @param {Roo.bootstrap.MonthField} this
20264 * @param {Mixed} date The date value
20269 * Fires when select a date.
20270 * @param {Roo.bootstrap.MonthField} this
20271 * @param {String} oldvalue The old value
20272 * @param {String} newvalue The new value
20278 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
20280 onRender: function(ct, position)
20283 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
20285 this.language = this.language || 'en';
20286 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
20287 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
20289 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
20290 this.isInline = false;
20291 this.isInput = true;
20292 this.component = this.el.select('.add-on', true).first() || false;
20293 this.component = (this.component && this.component.length === 0) ? false : this.component;
20294 this.hasInput = this.component && this.inputEL().length;
20296 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
20298 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
20300 this.picker().on('mousedown', this.onMousedown, this);
20301 this.picker().on('click', this.onClick, this);
20303 this.picker().addClass('datepicker-dropdown');
20305 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
20306 v.setStyle('width', '189px');
20313 if(this.isInline) {
20319 setValue: function(v, suppressEvent)
20321 var o = this.getValue();
20323 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
20327 if(suppressEvent !== true){
20328 this.fireEvent('select', this, o, v);
20333 getValue: function()
20338 onClick: function(e)
20340 e.stopPropagation();
20341 e.preventDefault();
20343 var target = e.getTarget();
20345 if(target.nodeName.toLowerCase() === 'i'){
20346 target = Roo.get(target).dom.parentNode;
20349 var nodeName = target.nodeName;
20350 var className = target.className;
20351 var html = target.innerHTML;
20353 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
20357 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
20359 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20365 picker : function()
20367 return this.pickerEl;
20370 fillMonths: function()
20373 var months = this.picker().select('>.datepicker-months td', true).first();
20375 months.dom.innerHTML = '';
20381 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
20384 months.createChild(month);
20393 if(typeof(this.vIndex) == 'undefined' && this.value.length){
20394 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
20397 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
20398 e.removeClass('active');
20400 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
20401 e.addClass('active');
20408 if(this.isInline) {
20412 this.picker().removeClass(['bottom', 'top']);
20414 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
20416 * place to the top of element!
20420 this.picker().addClass('top');
20421 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
20426 this.picker().addClass('bottom');
20428 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
20431 onFocus : function()
20433 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
20437 onBlur : function()
20439 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
20441 var d = this.inputEl().getValue();
20450 this.picker().show();
20451 this.picker().select('>.datepicker-months', true).first().show();
20455 this.fireEvent('show', this, this.date);
20460 if(this.isInline) {
20463 this.picker().hide();
20464 this.fireEvent('hide', this, this.date);
20468 onMousedown: function(e)
20470 e.stopPropagation();
20471 e.preventDefault();
20476 Roo.bootstrap.MonthField.superclass.keyup.call(this);
20480 fireKey: function(e)
20482 if (!this.picker().isVisible()){
20483 if (e.keyCode == 27) {// allow escape to hide and re-show picker
20494 e.preventDefault();
20498 dir = e.keyCode == 37 ? -1 : 1;
20500 this.vIndex = this.vIndex + dir;
20502 if(this.vIndex < 0){
20506 if(this.vIndex > 11){
20510 if(isNaN(this.vIndex)){
20514 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20520 dir = e.keyCode == 38 ? -1 : 1;
20522 this.vIndex = this.vIndex + dir * 4;
20524 if(this.vIndex < 0){
20528 if(this.vIndex > 11){
20532 if(isNaN(this.vIndex)){
20536 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20541 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20542 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20546 e.preventDefault();
20549 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20550 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20566 this.picker().remove();
20571 Roo.apply(Roo.bootstrap.MonthField, {
20590 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
20591 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
20596 Roo.apply(Roo.bootstrap.MonthField, {
20600 cls: 'datepicker dropdown-menu roo-dynamic',
20604 cls: 'datepicker-months',
20608 cls: 'table-condensed',
20610 Roo.bootstrap.DateField.content
20630 * @class Roo.bootstrap.CheckBox
20631 * @extends Roo.bootstrap.Input
20632 * Bootstrap CheckBox class
20634 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
20635 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
20636 * @cfg {String} boxLabel The text that appears beside the checkbox
20637 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
20638 * @cfg {Boolean} checked initnal the element
20639 * @cfg {Boolean} inline inline the element (default false)
20640 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
20641 * @cfg {String} tooltip label tooltip
20644 * Create a new CheckBox
20645 * @param {Object} config The config object
20648 Roo.bootstrap.CheckBox = function(config){
20649 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
20654 * Fires when the element is checked or unchecked.
20655 * @param {Roo.bootstrap.CheckBox} this This input
20656 * @param {Boolean} checked The new checked value
20661 * Fires when the element is click.
20662 * @param {Roo.bootstrap.CheckBox} this This input
20669 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
20671 inputType: 'checkbox',
20680 getAutoCreate : function()
20682 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20688 cfg.cls = 'form-group ' + this.inputType; //input-group
20691 cfg.cls += ' ' + this.inputType + '-inline';
20697 type : this.inputType,
20698 value : this.inputValue,
20699 cls : 'roo-' + this.inputType, //'form-box',
20700 placeholder : this.placeholder || ''
20704 if(this.inputType != 'radio'){
20708 cls : 'roo-hidden-value',
20709 value : this.checked ? this.inputValue : this.valueOff
20714 if (this.weight) { // Validity check?
20715 cfg.cls += " " + this.inputType + "-" + this.weight;
20718 if (this.disabled) {
20719 input.disabled=true;
20723 input.checked = this.checked;
20728 input.name = this.name;
20730 if(this.inputType != 'radio'){
20731 hidden.name = this.name;
20732 input.name = '_hidden_' + this.name;
20737 input.cls += ' input-' + this.size;
20742 ['xs','sm','md','lg'].map(function(size){
20743 if (settings[size]) {
20744 cfg.cls += ' col-' + size + '-' + settings[size];
20748 var inputblock = input;
20750 if (this.before || this.after) {
20753 cls : 'input-group',
20758 inputblock.cn.push({
20760 cls : 'input-group-addon',
20765 inputblock.cn.push(input);
20767 if(this.inputType != 'radio'){
20768 inputblock.cn.push(hidden);
20772 inputblock.cn.push({
20774 cls : 'input-group-addon',
20781 if (align ==='left' && this.fieldLabel.length) {
20782 // Roo.log("left and has label");
20787 cls : 'control-label',
20788 html : this.fieldLabel
20798 if(this.labelWidth > 12){
20799 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
20802 if(this.labelWidth < 13 && this.labelmd == 0){
20803 this.labelmd = this.labelWidth;
20806 if(this.labellg > 0){
20807 cfg.cn[0].cls += ' col-lg-' + this.labellg;
20808 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
20811 if(this.labelmd > 0){
20812 cfg.cn[0].cls += ' col-md-' + this.labelmd;
20813 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
20816 if(this.labelsm > 0){
20817 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
20818 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
20821 if(this.labelxs > 0){
20822 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
20823 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
20826 } else if ( this.fieldLabel.length) {
20827 // Roo.log(" label");
20831 tag: this.boxLabel ? 'span' : 'label',
20833 cls: 'control-label box-input-label',
20834 //cls : 'input-group-addon',
20835 html : this.fieldLabel
20844 // Roo.log(" no label && no align");
20845 cfg.cn = [ inputblock ] ;
20851 var boxLabelCfg = {
20853 //'for': id, // box label is handled by onclick - so no for...
20855 html: this.boxLabel
20859 boxLabelCfg.tooltip = this.tooltip;
20862 cfg.cn.push(boxLabelCfg);
20865 if(this.inputType != 'radio'){
20866 cfg.cn.push(hidden);
20874 * return the real input element.
20876 inputEl: function ()
20878 return this.el.select('input.roo-' + this.inputType,true).first();
20880 hiddenEl: function ()
20882 return this.el.select('input.roo-hidden-value',true).first();
20885 labelEl: function()
20887 return this.el.select('label.control-label',true).first();
20889 /* depricated... */
20893 return this.labelEl();
20896 boxLabelEl: function()
20898 return this.el.select('label.box-label',true).first();
20901 initEvents : function()
20903 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
20905 this.inputEl().on('click', this.onClick, this);
20907 if (this.boxLabel) {
20908 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
20911 this.startValue = this.getValue();
20914 Roo.bootstrap.CheckBox.register(this);
20918 onClick : function(e)
20920 if(this.fireEvent('click', this, e) !== false){
20921 this.setChecked(!this.checked);
20926 setChecked : function(state,suppressEvent)
20928 this.startValue = this.getValue();
20930 if(this.inputType == 'radio'){
20932 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20933 e.dom.checked = false;
20936 this.inputEl().dom.checked = true;
20938 this.inputEl().dom.value = this.inputValue;
20940 if(suppressEvent !== true){
20941 this.fireEvent('check', this, true);
20949 this.checked = state;
20951 this.inputEl().dom.checked = state;
20954 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
20956 if(suppressEvent !== true){
20957 this.fireEvent('check', this, state);
20963 getValue : function()
20965 if(this.inputType == 'radio'){
20966 return this.getGroupValue();
20969 return this.hiddenEl().dom.value;
20973 getGroupValue : function()
20975 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
20979 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
20982 setValue : function(v,suppressEvent)
20984 if(this.inputType == 'radio'){
20985 this.setGroupValue(v, suppressEvent);
20989 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
20994 setGroupValue : function(v, suppressEvent)
20996 this.startValue = this.getValue();
20998 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20999 e.dom.checked = false;
21001 if(e.dom.value == v){
21002 e.dom.checked = true;
21006 if(suppressEvent !== true){
21007 this.fireEvent('check', this, true);
21015 validate : function()
21017 if(this.getVisibilityEl().hasClass('hidden')){
21023 (this.inputType == 'radio' && this.validateRadio()) ||
21024 (this.inputType == 'checkbox' && this.validateCheckbox())
21030 this.markInvalid();
21034 validateRadio : function()
21036 if(this.getVisibilityEl().hasClass('hidden')){
21040 if(this.allowBlank){
21046 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21047 if(!e.dom.checked){
21059 validateCheckbox : function()
21062 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
21063 //return (this.getValue() == this.inputValue) ? true : false;
21066 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21074 for(var i in group){
21075 if(group[i].el.isVisible(true)){
21083 for(var i in group){
21088 r = (group[i].getValue() == group[i].inputValue) ? true : false;
21095 * Mark this field as valid
21097 markValid : function()
21101 this.fireEvent('valid', this);
21103 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21106 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
21113 if(this.inputType == 'radio'){
21114 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21115 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
21116 e.findParent('.form-group', false, true).addClass(_this.validClass);
21123 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21124 this.el.findParent('.form-group', false, true).addClass(this.validClass);
21128 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21134 for(var i in group){
21135 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21136 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
21141 * Mark this field as invalid
21142 * @param {String} msg The validation message
21144 markInvalid : function(msg)
21146 if(this.allowBlank){
21152 this.fireEvent('invalid', this, msg);
21154 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21157 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
21161 label.markInvalid();
21164 if(this.inputType == 'radio'){
21165 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21166 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
21167 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
21174 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21175 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
21179 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21185 for(var i in group){
21186 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21187 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
21192 clearInvalid : function()
21194 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
21196 // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21198 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21200 if (label && label.iconEl) {
21201 label.iconEl.removeClass(label.validClass);
21202 label.iconEl.removeClass(label.invalidClass);
21206 disable : function()
21208 if(this.inputType != 'radio'){
21209 Roo.bootstrap.CheckBox.superclass.disable.call(this);
21216 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21217 _this.getActionEl().addClass(this.disabledClass);
21218 e.dom.disabled = true;
21222 this.disabled = true;
21223 this.fireEvent("disable", this);
21227 enable : function()
21229 if(this.inputType != 'radio'){
21230 Roo.bootstrap.CheckBox.superclass.enable.call(this);
21237 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21238 _this.getActionEl().removeClass(this.disabledClass);
21239 e.dom.disabled = false;
21243 this.disabled = false;
21244 this.fireEvent("enable", this);
21248 setBoxLabel : function(v)
21253 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21259 Roo.apply(Roo.bootstrap.CheckBox, {
21264 * register a CheckBox Group
21265 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
21267 register : function(checkbox)
21269 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
21270 this.groups[checkbox.groupId] = {};
21273 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
21277 this.groups[checkbox.groupId][checkbox.name] = checkbox;
21281 * fetch a CheckBox Group based on the group ID
21282 * @param {string} the group ID
21283 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
21285 get: function(groupId) {
21286 if (typeof(this.groups[groupId]) == 'undefined') {
21290 return this.groups[groupId] ;
21303 * @class Roo.bootstrap.Radio
21304 * @extends Roo.bootstrap.Component
21305 * Bootstrap Radio class
21306 * @cfg {String} boxLabel - the label associated
21307 * @cfg {String} value - the value of radio
21310 * Create a new Radio
21311 * @param {Object} config The config object
21313 Roo.bootstrap.Radio = function(config){
21314 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
21318 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
21324 getAutoCreate : function()
21328 cls : 'form-group radio',
21333 html : this.boxLabel
21341 initEvents : function()
21343 this.parent().register(this);
21345 this.el.on('click', this.onClick, this);
21349 onClick : function(e)
21351 if(this.parent().fireEvent('click', this.parent(), this, e) !== false){
21352 this.setChecked(true);
21356 setChecked : function(state, suppressEvent)
21358 this.parent().setValue(this.value, suppressEvent);
21362 setBoxLabel : function(v)
21367 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21382 * @class Roo.bootstrap.SecurePass
21383 * @extends Roo.bootstrap.Input
21384 * Bootstrap SecurePass class
21388 * Create a new SecurePass
21389 * @param {Object} config The config object
21392 Roo.bootstrap.SecurePass = function (config) {
21393 // these go here, so the translation tool can replace them..
21395 PwdEmpty: "Please type a password, and then retype it to confirm.",
21396 PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21397 PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21398 PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21399 IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21400 FNInPwd: "Your password can't contain your first name. Please type a different password.",
21401 LNInPwd: "Your password can't contain your last name. Please type a different password.",
21402 TooWeak: "Your password is Too Weak."
21404 this.meterLabel = "Password strength:";
21405 this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
21406 this.meterClass = [
21407 "roo-password-meter-tooweak",
21408 "roo-password-meter-weak",
21409 "roo-password-meter-medium",
21410 "roo-password-meter-strong",
21411 "roo-password-meter-grey"
21416 Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
21419 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
21421 * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
21423 * PwdEmpty: "Please type a password, and then retype it to confirm.",
21424 * PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21425 * PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21426 * PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21427 * IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21428 * FNInPwd: "Your password can't contain your first name. Please type a different password.",
21429 * LNInPwd: "Your password can't contain your last name. Please type a different password."
21439 * @cfg {String/Object} Label for the strength meter (defaults to
21440 * 'Password strength:')
21445 * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
21446 * ['Weak', 'Medium', 'Strong'])
21449 pwdStrengths: false,
21462 initEvents: function ()
21464 Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
21466 if (this.el.is('input[type=password]') && Roo.isSafari) {
21467 this.el.on('keydown', this.SafariOnKeyDown, this);
21470 this.el.on('keyup', this.checkStrength, this, {buffer: 50});
21473 onRender: function (ct, position)
21475 Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
21476 this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
21477 this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
21479 this.trigger.createChild({
21484 cls: 'roo-password-meter-grey col-xs-12',
21487 //width: this.meterWidth + 'px'
21491 cls: 'roo-password-meter-text'
21497 if (this.hideTrigger) {
21498 this.trigger.setDisplayed(false);
21500 this.setSize(this.width || '', this.height || '');
21503 onDestroy: function ()
21505 if (this.trigger) {
21506 this.trigger.removeAllListeners();
21507 this.trigger.remove();
21510 this.wrap.remove();
21512 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
21515 checkStrength: function ()
21517 var pwd = this.inputEl().getValue();
21518 if (pwd == this._lastPwd) {
21523 if (this.ClientSideStrongPassword(pwd)) {
21525 } else if (this.ClientSideMediumPassword(pwd)) {
21527 } else if (this.ClientSideWeakPassword(pwd)) {
21533 Roo.log('strength1: ' + strength);
21535 //var pm = this.trigger.child('div/div/div').dom;
21536 var pm = this.trigger.child('div/div');
21537 pm.removeClass(this.meterClass);
21538 pm.addClass(this.meterClass[strength]);
21541 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21543 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21545 this._lastPwd = pwd;
21549 Roo.bootstrap.SecurePass.superclass.reset.call(this);
21551 this._lastPwd = '';
21553 var pm = this.trigger.child('div/div');
21554 pm.removeClass(this.meterClass);
21555 pm.addClass('roo-password-meter-grey');
21558 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21561 this.inputEl().dom.type='password';
21564 validateValue: function (value)
21567 if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
21570 if (value.length == 0) {
21571 if (this.allowBlank) {
21572 this.clearInvalid();
21576 this.markInvalid(this.errors.PwdEmpty);
21577 this.errorMsg = this.errors.PwdEmpty;
21585 if ('[\x21-\x7e]*'.match(value)) {
21586 this.markInvalid(this.errors.PwdBadChar);
21587 this.errorMsg = this.errors.PwdBadChar;
21590 if (value.length < 6) {
21591 this.markInvalid(this.errors.PwdShort);
21592 this.errorMsg = this.errors.PwdShort;
21595 if (value.length > 16) {
21596 this.markInvalid(this.errors.PwdLong);
21597 this.errorMsg = this.errors.PwdLong;
21601 if (this.ClientSideStrongPassword(value)) {
21603 } else if (this.ClientSideMediumPassword(value)) {
21605 } else if (this.ClientSideWeakPassword(value)) {
21612 if (strength < 2) {
21613 //this.markInvalid(this.errors.TooWeak);
21614 this.errorMsg = this.errors.TooWeak;
21619 console.log('strength2: ' + strength);
21621 //var pm = this.trigger.child('div/div/div').dom;
21623 var pm = this.trigger.child('div/div');
21624 pm.removeClass(this.meterClass);
21625 pm.addClass(this.meterClass[strength]);
21627 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21629 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21631 this.errorMsg = '';
21635 CharacterSetChecks: function (type)
21638 this.fResult = false;
21641 isctype: function (character, type)
21644 case this.kCapitalLetter:
21645 if (character >= 'A' && character <= 'Z') {
21650 case this.kSmallLetter:
21651 if (character >= 'a' && character <= 'z') {
21657 if (character >= '0' && character <= '9') {
21662 case this.kPunctuation:
21663 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
21674 IsLongEnough: function (pwd, size)
21676 return !(pwd == null || isNaN(size) || pwd.length < size);
21679 SpansEnoughCharacterSets: function (word, nb)
21681 if (!this.IsLongEnough(word, nb))
21686 var characterSetChecks = new Array(
21687 new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
21688 new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
21691 for (var index = 0; index < word.length; ++index) {
21692 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21693 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
21694 characterSetChecks[nCharSet].fResult = true;
21701 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21702 if (characterSetChecks[nCharSet].fResult) {
21707 if (nCharSets < nb) {
21713 ClientSideStrongPassword: function (pwd)
21715 return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
21718 ClientSideMediumPassword: function (pwd)
21720 return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
21723 ClientSideWeakPassword: function (pwd)
21725 return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
21728 })//<script type="text/javascript">
21731 * Based Ext JS Library 1.1.1
21732 * Copyright(c) 2006-2007, Ext JS, LLC.
21738 * @class Roo.HtmlEditorCore
21739 * @extends Roo.Component
21740 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
21742 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
21745 Roo.HtmlEditorCore = function(config){
21748 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
21753 * @event initialize
21754 * Fires when the editor is fully initialized (including the iframe)
21755 * @param {Roo.HtmlEditorCore} this
21760 * Fires when the editor is first receives the focus. Any insertion must wait
21761 * until after this event.
21762 * @param {Roo.HtmlEditorCore} this
21766 * @event beforesync
21767 * Fires before the textarea is updated with content from the editor iframe. Return false
21768 * to cancel the sync.
21769 * @param {Roo.HtmlEditorCore} this
21770 * @param {String} html
21774 * @event beforepush
21775 * Fires before the iframe editor is updated with content from the textarea. Return false
21776 * to cancel the push.
21777 * @param {Roo.HtmlEditorCore} this
21778 * @param {String} html
21783 * Fires when the textarea is updated with content from the editor iframe.
21784 * @param {Roo.HtmlEditorCore} this
21785 * @param {String} html
21790 * Fires when the iframe editor is updated with content from the textarea.
21791 * @param {Roo.HtmlEditorCore} this
21792 * @param {String} html
21797 * @event editorevent
21798 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
21799 * @param {Roo.HtmlEditorCore} this
21805 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
21807 // defaults : white / black...
21808 this.applyBlacklists();
21815 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
21819 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
21825 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
21830 * @cfg {Number} height (in pixels)
21834 * @cfg {Number} width (in pixels)
21839 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
21842 stylesheets: false,
21847 // private properties
21848 validationEvent : false,
21850 initialized : false,
21852 sourceEditMode : false,
21853 onFocus : Roo.emptyFn,
21855 hideMode:'offsets',
21859 // blacklist + whitelisted elements..
21866 * Protected method that will not generally be called directly. It
21867 * is called when the editor initializes the iframe with HTML contents. Override this method if you
21868 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
21870 getDocMarkup : function(){
21874 // inherit styels from page...??
21875 if (this.stylesheets === false) {
21877 Roo.get(document.head).select('style').each(function(node) {
21878 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21881 Roo.get(document.head).select('link').each(function(node) {
21882 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21885 } else if (!this.stylesheets.length) {
21887 st = '<style type="text/css">' +
21888 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21891 st = '<style type="text/css">' +
21896 st += '<style type="text/css">' +
21897 'IMG { cursor: pointer } ' +
21900 var cls = 'roo-htmleditor-body';
21902 if(this.bodyCls.length){
21903 cls += ' ' + this.bodyCls;
21906 return '<html><head>' + st +
21907 //<style type="text/css">' +
21908 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21910 ' </head><body class="' + cls + '"></body></html>';
21914 onRender : function(ct, position)
21917 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
21918 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
21921 this.el.dom.style.border = '0 none';
21922 this.el.dom.setAttribute('tabIndex', -1);
21923 this.el.addClass('x-hidden hide');
21927 if(Roo.isIE){ // fix IE 1px bogus margin
21928 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
21932 this.frameId = Roo.id();
21936 var iframe = this.owner.wrap.createChild({
21938 cls: 'form-control', // bootstrap..
21940 name: this.frameId,
21941 frameBorder : 'no',
21942 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
21947 this.iframe = iframe.dom;
21949 this.assignDocWin();
21951 this.doc.designMode = 'on';
21954 this.doc.write(this.getDocMarkup());
21958 var task = { // must defer to wait for browser to be ready
21960 //console.log("run task?" + this.doc.readyState);
21961 this.assignDocWin();
21962 if(this.doc.body || this.doc.readyState == 'complete'){
21964 this.doc.designMode="on";
21968 Roo.TaskMgr.stop(task);
21969 this.initEditor.defer(10, this);
21976 Roo.TaskMgr.start(task);
21981 onResize : function(w, h)
21983 Roo.log('resize: ' +w + ',' + h );
21984 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
21988 if(typeof w == 'number'){
21990 this.iframe.style.width = w + 'px';
21992 if(typeof h == 'number'){
21994 this.iframe.style.height = h + 'px';
21996 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
22003 * Toggles the editor between standard and source edit mode.
22004 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
22006 toggleSourceEdit : function(sourceEditMode){
22008 this.sourceEditMode = sourceEditMode === true;
22010 if(this.sourceEditMode){
22012 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
22015 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
22016 //this.iframe.className = '';
22019 //this.setSize(this.owner.wrap.getSize());
22020 //this.fireEvent('editmodechange', this, this.sourceEditMode);
22027 * Protected method that will not generally be called directly. If you need/want
22028 * custom HTML cleanup, this is the method you should override.
22029 * @param {String} html The HTML to be cleaned
22030 * return {String} The cleaned HTML
22032 cleanHtml : function(html){
22033 html = String(html);
22034 if(html.length > 5){
22035 if(Roo.isSafari){ // strip safari nonsense
22036 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
22039 if(html == ' '){
22046 * HTML Editor -> Textarea
22047 * Protected method that will not generally be called directly. Syncs the contents
22048 * of the editor iframe with the textarea.
22050 syncValue : function(){
22051 if(this.initialized){
22052 var bd = (this.doc.body || this.doc.documentElement);
22053 //this.cleanUpPaste(); -- this is done else where and causes havoc..
22054 var html = bd.innerHTML;
22056 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
22057 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
22059 html = '<div style="'+m[0]+'">' + html + '</div>';
22062 html = this.cleanHtml(html);
22063 // fix up the special chars.. normaly like back quotes in word...
22064 // however we do not want to do this with chinese..
22065 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
22066 var cc = b.charCodeAt();
22068 (cc >= 0x4E00 && cc < 0xA000 ) ||
22069 (cc >= 0x3400 && cc < 0x4E00 ) ||
22070 (cc >= 0xf900 && cc < 0xfb00 )
22076 if(this.owner.fireEvent('beforesync', this, html) !== false){
22077 this.el.dom.value = html;
22078 this.owner.fireEvent('sync', this, html);
22084 * Protected method that will not generally be called directly. Pushes the value of the textarea
22085 * into the iframe editor.
22087 pushValue : function(){
22088 if(this.initialized){
22089 var v = this.el.dom.value.trim();
22091 // if(v.length < 1){
22095 if(this.owner.fireEvent('beforepush', this, v) !== false){
22096 var d = (this.doc.body || this.doc.documentElement);
22098 this.cleanUpPaste();
22099 this.el.dom.value = d.innerHTML;
22100 this.owner.fireEvent('push', this, v);
22106 deferFocus : function(){
22107 this.focus.defer(10, this);
22111 focus : function(){
22112 if(this.win && !this.sourceEditMode){
22119 assignDocWin: function()
22121 var iframe = this.iframe;
22124 this.doc = iframe.contentWindow.document;
22125 this.win = iframe.contentWindow;
22127 // if (!Roo.get(this.frameId)) {
22130 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
22131 // this.win = Roo.get(this.frameId).dom.contentWindow;
22133 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
22137 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
22138 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
22143 initEditor : function(){
22144 //console.log("INIT EDITOR");
22145 this.assignDocWin();
22149 this.doc.designMode="on";
22151 this.doc.write(this.getDocMarkup());
22154 var dbody = (this.doc.body || this.doc.documentElement);
22155 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
22156 // this copies styles from the containing element into thsi one..
22157 // not sure why we need all of this..
22158 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
22160 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
22161 //ss['background-attachment'] = 'fixed'; // w3c
22162 dbody.bgProperties = 'fixed'; // ie
22163 //Roo.DomHelper.applyStyles(dbody, ss);
22164 Roo.EventManager.on(this.doc, {
22165 //'mousedown': this.onEditorEvent,
22166 'mouseup': this.onEditorEvent,
22167 'dblclick': this.onEditorEvent,
22168 'click': this.onEditorEvent,
22169 'keyup': this.onEditorEvent,
22174 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
22176 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
22177 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
22179 this.initialized = true;
22181 this.owner.fireEvent('initialize', this);
22186 onDestroy : function(){
22192 //for (var i =0; i < this.toolbars.length;i++) {
22193 // // fixme - ask toolbars for heights?
22194 // this.toolbars[i].onDestroy();
22197 //this.wrap.dom.innerHTML = '';
22198 //this.wrap.remove();
22203 onFirstFocus : function(){
22205 this.assignDocWin();
22208 this.activated = true;
22211 if(Roo.isGecko){ // prevent silly gecko errors
22213 var s = this.win.getSelection();
22214 if(!s.focusNode || s.focusNode.nodeType != 3){
22215 var r = s.getRangeAt(0);
22216 r.selectNodeContents((this.doc.body || this.doc.documentElement));
22221 this.execCmd('useCSS', true);
22222 this.execCmd('styleWithCSS', false);
22225 this.owner.fireEvent('activate', this);
22229 adjustFont: function(btn){
22230 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
22231 //if(Roo.isSafari){ // safari
22234 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
22235 if(Roo.isSafari){ // safari
22236 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
22237 v = (v < 10) ? 10 : v;
22238 v = (v > 48) ? 48 : v;
22239 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
22244 v = Math.max(1, v+adjust);
22246 this.execCmd('FontSize', v );
22249 onEditorEvent : function(e)
22251 this.owner.fireEvent('editorevent', this, e);
22252 // this.updateToolbar();
22253 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
22256 insertTag : function(tg)
22258 // could be a bit smarter... -> wrap the current selected tRoo..
22259 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
22261 range = this.createRange(this.getSelection());
22262 var wrappingNode = this.doc.createElement(tg.toLowerCase());
22263 wrappingNode.appendChild(range.extractContents());
22264 range.insertNode(wrappingNode);
22271 this.execCmd("formatblock", tg);
22275 insertText : function(txt)
22279 var range = this.createRange();
22280 range.deleteContents();
22281 //alert(Sender.getAttribute('label'));
22283 range.insertNode(this.doc.createTextNode(txt));
22289 * Executes a Midas editor command on the editor document and performs necessary focus and
22290 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
22291 * @param {String} cmd The Midas command
22292 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22294 relayCmd : function(cmd, value){
22296 this.execCmd(cmd, value);
22297 this.owner.fireEvent('editorevent', this);
22298 //this.updateToolbar();
22299 this.owner.deferFocus();
22303 * Executes a Midas editor command directly on the editor document.
22304 * For visual commands, you should use {@link #relayCmd} instead.
22305 * <b>This should only be called after the editor is initialized.</b>
22306 * @param {String} cmd The Midas command
22307 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22309 execCmd : function(cmd, value){
22310 this.doc.execCommand(cmd, false, value === undefined ? null : value);
22317 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
22319 * @param {String} text | dom node..
22321 insertAtCursor : function(text)
22324 if(!this.activated){
22330 var r = this.doc.selection.createRange();
22341 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
22345 // from jquery ui (MIT licenced)
22347 var win = this.win;
22349 if (win.getSelection && win.getSelection().getRangeAt) {
22350 range = win.getSelection().getRangeAt(0);
22351 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
22352 range.insertNode(node);
22353 } else if (win.document.selection && win.document.selection.createRange) {
22354 // no firefox support
22355 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22356 win.document.selection.createRange().pasteHTML(txt);
22358 // no firefox support
22359 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22360 this.execCmd('InsertHTML', txt);
22369 mozKeyPress : function(e){
22371 var c = e.getCharCode(), cmd;
22374 c = String.fromCharCode(c).toLowerCase();
22388 this.cleanUpPaste.defer(100, this);
22396 e.preventDefault();
22404 fixKeys : function(){ // load time branching for fastest keydown performance
22406 return function(e){
22407 var k = e.getKey(), r;
22410 r = this.doc.selection.createRange();
22413 r.pasteHTML('    ');
22420 r = this.doc.selection.createRange();
22422 var target = r.parentElement();
22423 if(!target || target.tagName.toLowerCase() != 'li'){
22425 r.pasteHTML('<br />');
22431 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22432 this.cleanUpPaste.defer(100, this);
22438 }else if(Roo.isOpera){
22439 return function(e){
22440 var k = e.getKey();
22444 this.execCmd('InsertHTML','    ');
22447 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22448 this.cleanUpPaste.defer(100, this);
22453 }else if(Roo.isSafari){
22454 return function(e){
22455 var k = e.getKey();
22459 this.execCmd('InsertText','\t');
22463 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22464 this.cleanUpPaste.defer(100, this);
22472 getAllAncestors: function()
22474 var p = this.getSelectedNode();
22477 a.push(p); // push blank onto stack..
22478 p = this.getParentElement();
22482 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
22486 a.push(this.doc.body);
22490 lastSelNode : false,
22493 getSelection : function()
22495 this.assignDocWin();
22496 return Roo.isIE ? this.doc.selection : this.win.getSelection();
22499 getSelectedNode: function()
22501 // this may only work on Gecko!!!
22503 // should we cache this!!!!
22508 var range = this.createRange(this.getSelection()).cloneRange();
22511 var parent = range.parentElement();
22513 var testRange = range.duplicate();
22514 testRange.moveToElementText(parent);
22515 if (testRange.inRange(range)) {
22518 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
22521 parent = parent.parentElement;
22526 // is ancestor a text element.
22527 var ac = range.commonAncestorContainer;
22528 if (ac.nodeType == 3) {
22529 ac = ac.parentNode;
22532 var ar = ac.childNodes;
22535 var other_nodes = [];
22536 var has_other_nodes = false;
22537 for (var i=0;i<ar.length;i++) {
22538 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
22541 // fullly contained node.
22543 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
22548 // probably selected..
22549 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
22550 other_nodes.push(ar[i]);
22554 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
22559 has_other_nodes = true;
22561 if (!nodes.length && other_nodes.length) {
22562 nodes= other_nodes;
22564 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
22570 createRange: function(sel)
22572 // this has strange effects when using with
22573 // top toolbar - not sure if it's a great idea.
22574 //this.editor.contentWindow.focus();
22575 if (typeof sel != "undefined") {
22577 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
22579 return this.doc.createRange();
22582 return this.doc.createRange();
22585 getParentElement: function()
22588 this.assignDocWin();
22589 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
22591 var range = this.createRange(sel);
22594 var p = range.commonAncestorContainer;
22595 while (p.nodeType == 3) { // text node
22606 * Range intersection.. the hard stuff...
22610 * [ -- selected range --- ]
22614 * if end is before start or hits it. fail.
22615 * if start is after end or hits it fail.
22617 * if either hits (but other is outside. - then it's not
22623 // @see http://www.thismuchiknow.co.uk/?p=64.
22624 rangeIntersectsNode : function(range, node)
22626 var nodeRange = node.ownerDocument.createRange();
22628 nodeRange.selectNode(node);
22630 nodeRange.selectNodeContents(node);
22633 var rangeStartRange = range.cloneRange();
22634 rangeStartRange.collapse(true);
22636 var rangeEndRange = range.cloneRange();
22637 rangeEndRange.collapse(false);
22639 var nodeStartRange = nodeRange.cloneRange();
22640 nodeStartRange.collapse(true);
22642 var nodeEndRange = nodeRange.cloneRange();
22643 nodeEndRange.collapse(false);
22645 return rangeStartRange.compareBoundaryPoints(
22646 Range.START_TO_START, nodeEndRange) == -1 &&
22647 rangeEndRange.compareBoundaryPoints(
22648 Range.START_TO_START, nodeStartRange) == 1;
22652 rangeCompareNode : function(range, node)
22654 var nodeRange = node.ownerDocument.createRange();
22656 nodeRange.selectNode(node);
22658 nodeRange.selectNodeContents(node);
22662 range.collapse(true);
22664 nodeRange.collapse(true);
22666 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
22667 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
22669 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
22671 var nodeIsBefore = ss == 1;
22672 var nodeIsAfter = ee == -1;
22674 if (nodeIsBefore && nodeIsAfter) {
22677 if (!nodeIsBefore && nodeIsAfter) {
22678 return 1; //right trailed.
22681 if (nodeIsBefore && !nodeIsAfter) {
22682 return 2; // left trailed.
22688 // private? - in a new class?
22689 cleanUpPaste : function()
22691 // cleans up the whole document..
22692 Roo.log('cleanuppaste');
22694 this.cleanUpChildren(this.doc.body);
22695 var clean = this.cleanWordChars(this.doc.body.innerHTML);
22696 if (clean != this.doc.body.innerHTML) {
22697 this.doc.body.innerHTML = clean;
22702 cleanWordChars : function(input) {// change the chars to hex code
22703 var he = Roo.HtmlEditorCore;
22705 var output = input;
22706 Roo.each(he.swapCodes, function(sw) {
22707 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
22709 output = output.replace(swapper, sw[1]);
22716 cleanUpChildren : function (n)
22718 if (!n.childNodes.length) {
22721 for (var i = n.childNodes.length-1; i > -1 ; i--) {
22722 this.cleanUpChild(n.childNodes[i]);
22729 cleanUpChild : function (node)
22732 //console.log(node);
22733 if (node.nodeName == "#text") {
22734 // clean up silly Windows -- stuff?
22737 if (node.nodeName == "#comment") {
22738 node.parentNode.removeChild(node);
22739 // clean up silly Windows -- stuff?
22742 var lcname = node.tagName.toLowerCase();
22743 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
22744 // whitelist of tags..
22746 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
22748 node.parentNode.removeChild(node);
22753 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
22755 // remove <a name=....> as rendering on yahoo mailer is borked with this.
22756 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
22758 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
22759 // remove_keep_children = true;
22762 if (remove_keep_children) {
22763 this.cleanUpChildren(node);
22764 // inserts everything just before this node...
22765 while (node.childNodes.length) {
22766 var cn = node.childNodes[0];
22767 node.removeChild(cn);
22768 node.parentNode.insertBefore(cn, node);
22770 node.parentNode.removeChild(node);
22774 if (!node.attributes || !node.attributes.length) {
22775 this.cleanUpChildren(node);
22779 function cleanAttr(n,v)
22782 if (v.match(/^\./) || v.match(/^\//)) {
22785 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/) || v.match(/^ftp:/)) {
22788 if (v.match(/^#/)) {
22791 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
22792 node.removeAttribute(n);
22796 var cwhite = this.cwhite;
22797 var cblack = this.cblack;
22799 function cleanStyle(n,v)
22801 if (v.match(/expression/)) { //XSS?? should we even bother..
22802 node.removeAttribute(n);
22806 var parts = v.split(/;/);
22809 Roo.each(parts, function(p) {
22810 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
22814 var l = p.split(':').shift().replace(/\s+/g,'');
22815 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
22817 if ( cwhite.length && cblack.indexOf(l) > -1) {
22818 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22819 //node.removeAttribute(n);
22823 // only allow 'c whitelisted system attributes'
22824 if ( cwhite.length && cwhite.indexOf(l) < 0) {
22825 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22826 //node.removeAttribute(n);
22836 if (clean.length) {
22837 node.setAttribute(n, clean.join(';'));
22839 node.removeAttribute(n);
22845 for (var i = node.attributes.length-1; i > -1 ; i--) {
22846 var a = node.attributes[i];
22849 if (a.name.toLowerCase().substr(0,2)=='on') {
22850 node.removeAttribute(a.name);
22853 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
22854 node.removeAttribute(a.name);
22857 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
22858 cleanAttr(a.name,a.value); // fixme..
22861 if (a.name == 'style') {
22862 cleanStyle(a.name,a.value);
22865 /// clean up MS crap..
22866 // tecnically this should be a list of valid class'es..
22869 if (a.name == 'class') {
22870 if (a.value.match(/^Mso/)) {
22871 node.className = '';
22874 if (a.value.match(/^body$/)) {
22875 node.className = '';
22886 this.cleanUpChildren(node);
22892 * Clean up MS wordisms...
22894 cleanWord : function(node)
22899 this.cleanWord(this.doc.body);
22902 if (node.nodeName == "#text") {
22903 // clean up silly Windows -- stuff?
22906 if (node.nodeName == "#comment") {
22907 node.parentNode.removeChild(node);
22908 // clean up silly Windows -- stuff?
22912 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
22913 node.parentNode.removeChild(node);
22917 // remove - but keep children..
22918 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
22919 while (node.childNodes.length) {
22920 var cn = node.childNodes[0];
22921 node.removeChild(cn);
22922 node.parentNode.insertBefore(cn, node);
22924 node.parentNode.removeChild(node);
22925 this.iterateChildren(node, this.cleanWord);
22929 if (node.className.length) {
22931 var cn = node.className.split(/\W+/);
22933 Roo.each(cn, function(cls) {
22934 if (cls.match(/Mso[a-zA-Z]+/)) {
22939 node.className = cna.length ? cna.join(' ') : '';
22941 node.removeAttribute("class");
22945 if (node.hasAttribute("lang")) {
22946 node.removeAttribute("lang");
22949 if (node.hasAttribute("style")) {
22951 var styles = node.getAttribute("style").split(";");
22953 Roo.each(styles, function(s) {
22954 if (!s.match(/:/)) {
22957 var kv = s.split(":");
22958 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
22961 // what ever is left... we allow.
22964 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22965 if (!nstyle.length) {
22966 node.removeAttribute('style');
22969 this.iterateChildren(node, this.cleanWord);
22975 * iterateChildren of a Node, calling fn each time, using this as the scole..
22976 * @param {DomNode} node node to iterate children of.
22977 * @param {Function} fn method of this class to call on each item.
22979 iterateChildren : function(node, fn)
22981 if (!node.childNodes.length) {
22984 for (var i = node.childNodes.length-1; i > -1 ; i--) {
22985 fn.call(this, node.childNodes[i])
22991 * cleanTableWidths.
22993 * Quite often pasting from word etc.. results in tables with column and widths.
22994 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
22997 cleanTableWidths : function(node)
23002 this.cleanTableWidths(this.doc.body);
23007 if (node.nodeName == "#text" || node.nodeName == "#comment") {
23010 Roo.log(node.tagName);
23011 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
23012 this.iterateChildren(node, this.cleanTableWidths);
23015 if (node.hasAttribute('width')) {
23016 node.removeAttribute('width');
23020 if (node.hasAttribute("style")) {
23023 var styles = node.getAttribute("style").split(";");
23025 Roo.each(styles, function(s) {
23026 if (!s.match(/:/)) {
23029 var kv = s.split(":");
23030 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
23033 // what ever is left... we allow.
23036 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
23037 if (!nstyle.length) {
23038 node.removeAttribute('style');
23042 this.iterateChildren(node, this.cleanTableWidths);
23050 domToHTML : function(currentElement, depth, nopadtext) {
23052 depth = depth || 0;
23053 nopadtext = nopadtext || false;
23055 if (!currentElement) {
23056 return this.domToHTML(this.doc.body);
23059 //Roo.log(currentElement);
23061 var allText = false;
23062 var nodeName = currentElement.nodeName;
23063 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
23065 if (nodeName == '#text') {
23067 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
23072 if (nodeName != 'BODY') {
23075 // Prints the node tagName, such as <A>, <IMG>, etc
23078 for(i = 0; i < currentElement.attributes.length;i++) {
23080 var aname = currentElement.attributes.item(i).name;
23081 if (!currentElement.attributes.item(i).value.length) {
23084 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
23087 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
23096 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
23099 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
23104 // Traverse the tree
23106 var currentElementChild = currentElement.childNodes.item(i);
23107 var allText = true;
23108 var innerHTML = '';
23110 while (currentElementChild) {
23111 // Formatting code (indent the tree so it looks nice on the screen)
23112 var nopad = nopadtext;
23113 if (lastnode == 'SPAN') {
23117 if (currentElementChild.nodeName == '#text') {
23118 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
23119 toadd = nopadtext ? toadd : toadd.trim();
23120 if (!nopad && toadd.length > 80) {
23121 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
23123 innerHTML += toadd;
23126 currentElementChild = currentElement.childNodes.item(i);
23132 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
23134 // Recursively traverse the tree structure of the child node
23135 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
23136 lastnode = currentElementChild.nodeName;
23138 currentElementChild=currentElement.childNodes.item(i);
23144 // The remaining code is mostly for formatting the tree
23145 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
23150 ret+= "</"+tagName+">";
23156 applyBlacklists : function()
23158 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
23159 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
23163 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
23164 if (b.indexOf(tag) > -1) {
23167 this.white.push(tag);
23171 Roo.each(w, function(tag) {
23172 if (b.indexOf(tag) > -1) {
23175 if (this.white.indexOf(tag) > -1) {
23178 this.white.push(tag);
23183 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
23184 if (w.indexOf(tag) > -1) {
23187 this.black.push(tag);
23191 Roo.each(b, function(tag) {
23192 if (w.indexOf(tag) > -1) {
23195 if (this.black.indexOf(tag) > -1) {
23198 this.black.push(tag);
23203 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
23204 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
23208 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
23209 if (b.indexOf(tag) > -1) {
23212 this.cwhite.push(tag);
23216 Roo.each(w, function(tag) {
23217 if (b.indexOf(tag) > -1) {
23220 if (this.cwhite.indexOf(tag) > -1) {
23223 this.cwhite.push(tag);
23228 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
23229 if (w.indexOf(tag) > -1) {
23232 this.cblack.push(tag);
23236 Roo.each(b, function(tag) {
23237 if (w.indexOf(tag) > -1) {
23240 if (this.cblack.indexOf(tag) > -1) {
23243 this.cblack.push(tag);
23248 setStylesheets : function(stylesheets)
23250 if(typeof(stylesheets) == 'string'){
23251 Roo.get(this.iframe.contentDocument.head).createChild({
23253 rel : 'stylesheet',
23262 Roo.each(stylesheets, function(s) {
23267 Roo.get(_this.iframe.contentDocument.head).createChild({
23269 rel : 'stylesheet',
23278 removeStylesheets : function()
23282 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
23287 setStyle : function(style)
23289 Roo.get(this.iframe.contentDocument.head).createChild({
23298 // hide stuff that is not compatible
23312 * @event specialkey
23316 * @cfg {String} fieldClass @hide
23319 * @cfg {String} focusClass @hide
23322 * @cfg {String} autoCreate @hide
23325 * @cfg {String} inputType @hide
23328 * @cfg {String} invalidClass @hide
23331 * @cfg {String} invalidText @hide
23334 * @cfg {String} msgFx @hide
23337 * @cfg {String} validateOnBlur @hide
23341 Roo.HtmlEditorCore.white = [
23342 'area', 'br', 'img', 'input', 'hr', 'wbr',
23344 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
23345 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
23346 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
23347 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
23348 'table', 'ul', 'xmp',
23350 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
23353 'dir', 'menu', 'ol', 'ul', 'dl',
23359 Roo.HtmlEditorCore.black = [
23360 // 'embed', 'object', // enable - backend responsiblity to clean thiese
23362 'base', 'basefont', 'bgsound', 'blink', 'body',
23363 'frame', 'frameset', 'head', 'html', 'ilayer',
23364 'iframe', 'layer', 'link', 'meta', 'object',
23365 'script', 'style' ,'title', 'xml' // clean later..
23367 Roo.HtmlEditorCore.clean = [
23368 'script', 'style', 'title', 'xml'
23370 Roo.HtmlEditorCore.remove = [
23375 Roo.HtmlEditorCore.ablack = [
23379 Roo.HtmlEditorCore.aclean = [
23380 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
23384 Roo.HtmlEditorCore.pwhite= [
23385 'http', 'https', 'mailto'
23388 // white listed style attributes.
23389 Roo.HtmlEditorCore.cwhite= [
23390 // 'text-align', /// default is to allow most things..
23396 // black listed style attributes.
23397 Roo.HtmlEditorCore.cblack= [
23398 // 'font-size' -- this can be set by the project
23402 Roo.HtmlEditorCore.swapCodes =[
23421 * @class Roo.bootstrap.HtmlEditor
23422 * @extends Roo.bootstrap.TextArea
23423 * Bootstrap HtmlEditor class
23426 * Create a new HtmlEditor
23427 * @param {Object} config The config object
23430 Roo.bootstrap.HtmlEditor = function(config){
23431 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
23432 if (!this.toolbars) {
23433 this.toolbars = [];
23436 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
23439 * @event initialize
23440 * Fires when the editor is fully initialized (including the iframe)
23441 * @param {HtmlEditor} this
23446 * Fires when the editor is first receives the focus. Any insertion must wait
23447 * until after this event.
23448 * @param {HtmlEditor} this
23452 * @event beforesync
23453 * Fires before the textarea is updated with content from the editor iframe. Return false
23454 * to cancel the sync.
23455 * @param {HtmlEditor} this
23456 * @param {String} html
23460 * @event beforepush
23461 * Fires before the iframe editor is updated with content from the textarea. Return false
23462 * to cancel the push.
23463 * @param {HtmlEditor} this
23464 * @param {String} html
23469 * Fires when the textarea is updated with content from the editor iframe.
23470 * @param {HtmlEditor} this
23471 * @param {String} html
23476 * Fires when the iframe editor is updated with content from the textarea.
23477 * @param {HtmlEditor} this
23478 * @param {String} html
23482 * @event editmodechange
23483 * Fires when the editor switches edit modes
23484 * @param {HtmlEditor} this
23485 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
23487 editmodechange: true,
23489 * @event editorevent
23490 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
23491 * @param {HtmlEditor} this
23495 * @event firstfocus
23496 * Fires when on first focus - needed by toolbars..
23497 * @param {HtmlEditor} this
23502 * Auto save the htmlEditor value as a file into Events
23503 * @param {HtmlEditor} this
23507 * @event savedpreview
23508 * preview the saved version of htmlEditor
23509 * @param {HtmlEditor} this
23516 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
23520 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
23525 * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
23530 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
23535 * @cfg {Number} height (in pixels)
23539 * @cfg {Number} width (in pixels)
23544 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
23547 stylesheets: false,
23552 // private properties
23553 validationEvent : false,
23555 initialized : false,
23558 onFocus : Roo.emptyFn,
23560 hideMode:'offsets',
23562 tbContainer : false,
23566 toolbarContainer :function() {
23567 return this.wrap.select('.x-html-editor-tb',true).first();
23571 * Protected method that will not generally be called directly. It
23572 * is called when the editor creates its toolbar. Override this method if you need to
23573 * add custom toolbar buttons.
23574 * @param {HtmlEditor} editor
23576 createToolbar : function(){
23577 Roo.log('renewing');
23578 Roo.log("create toolbars");
23580 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
23581 this.toolbars[0].render(this.toolbarContainer());
23585 // if (!editor.toolbars || !editor.toolbars.length) {
23586 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
23589 // for (var i =0 ; i < editor.toolbars.length;i++) {
23590 // editor.toolbars[i] = Roo.factory(
23591 // typeof(editor.toolbars[i]) == 'string' ?
23592 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
23593 // Roo.bootstrap.HtmlEditor);
23594 // editor.toolbars[i].init(editor);
23600 onRender : function(ct, position)
23602 // Roo.log("Call onRender: " + this.xtype);
23604 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
23606 this.wrap = this.inputEl().wrap({
23607 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
23610 this.editorcore.onRender(ct, position);
23612 if (this.resizable) {
23613 this.resizeEl = new Roo.Resizable(this.wrap, {
23617 minHeight : this.height,
23618 height: this.height,
23619 handles : this.resizable,
23622 resize : function(r, w, h) {
23623 _t.onResize(w,h); // -something
23629 this.createToolbar(this);
23632 if(!this.width && this.resizable){
23633 this.setSize(this.wrap.getSize());
23635 if (this.resizeEl) {
23636 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
23637 // should trigger onReize..
23643 onResize : function(w, h)
23645 Roo.log('resize: ' +w + ',' + h );
23646 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
23650 if(this.inputEl() ){
23651 if(typeof w == 'number'){
23652 var aw = w - this.wrap.getFrameWidth('lr');
23653 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
23656 if(typeof h == 'number'){
23657 var tbh = -11; // fixme it needs to tool bar size!
23658 for (var i =0; i < this.toolbars.length;i++) {
23659 // fixme - ask toolbars for heights?
23660 tbh += this.toolbars[i].el.getHeight();
23661 //if (this.toolbars[i].footer) {
23662 // tbh += this.toolbars[i].footer.el.getHeight();
23670 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
23671 ah -= 5; // knock a few pixes off for look..
23672 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
23676 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
23677 this.editorcore.onResize(ew,eh);
23682 * Toggles the editor between standard and source edit mode.
23683 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
23685 toggleSourceEdit : function(sourceEditMode)
23687 this.editorcore.toggleSourceEdit(sourceEditMode);
23689 if(this.editorcore.sourceEditMode){
23690 Roo.log('editor - showing textarea');
23693 // Roo.log(this.syncValue());
23695 this.inputEl().removeClass(['hide', 'x-hidden']);
23696 this.inputEl().dom.removeAttribute('tabIndex');
23697 this.inputEl().focus();
23699 Roo.log('editor - hiding textarea');
23701 // Roo.log(this.pushValue());
23704 this.inputEl().addClass(['hide', 'x-hidden']);
23705 this.inputEl().dom.setAttribute('tabIndex', -1);
23706 //this.deferFocus();
23709 if(this.resizable){
23710 this.setSize(this.wrap.getSize());
23713 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
23716 // private (for BoxComponent)
23717 adjustSize : Roo.BoxComponent.prototype.adjustSize,
23719 // private (for BoxComponent)
23720 getResizeEl : function(){
23724 // private (for BoxComponent)
23725 getPositionEl : function(){
23730 initEvents : function(){
23731 this.originalValue = this.getValue();
23735 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23738 // markInvalid : Roo.emptyFn,
23740 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23743 // clearInvalid : Roo.emptyFn,
23745 setValue : function(v){
23746 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
23747 this.editorcore.pushValue();
23752 deferFocus : function(){
23753 this.focus.defer(10, this);
23757 focus : function(){
23758 this.editorcore.focus();
23764 onDestroy : function(){
23770 for (var i =0; i < this.toolbars.length;i++) {
23771 // fixme - ask toolbars for heights?
23772 this.toolbars[i].onDestroy();
23775 this.wrap.dom.innerHTML = '';
23776 this.wrap.remove();
23781 onFirstFocus : function(){
23782 //Roo.log("onFirstFocus");
23783 this.editorcore.onFirstFocus();
23784 for (var i =0; i < this.toolbars.length;i++) {
23785 this.toolbars[i].onFirstFocus();
23791 syncValue : function()
23793 this.editorcore.syncValue();
23796 pushValue : function()
23798 this.editorcore.pushValue();
23802 // hide stuff that is not compatible
23816 * @event specialkey
23820 * @cfg {String} fieldClass @hide
23823 * @cfg {String} focusClass @hide
23826 * @cfg {String} autoCreate @hide
23829 * @cfg {String} inputType @hide
23832 * @cfg {String} invalidClass @hide
23835 * @cfg {String} invalidText @hide
23838 * @cfg {String} msgFx @hide
23841 * @cfg {String} validateOnBlur @hide
23850 Roo.namespace('Roo.bootstrap.htmleditor');
23852 * @class Roo.bootstrap.HtmlEditorToolbar1
23857 new Roo.bootstrap.HtmlEditor({
23860 new Roo.bootstrap.HtmlEditorToolbar1({
23861 disable : { fonts: 1 , format: 1, ..., ... , ...],
23867 * @cfg {Object} disable List of elements to disable..
23868 * @cfg {Array} btns List of additional buttons.
23872 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
23875 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
23878 Roo.apply(this, config);
23880 // default disabled, based on 'good practice'..
23881 this.disable = this.disable || {};
23882 Roo.applyIf(this.disable, {
23885 specialElements : true
23887 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
23889 this.editor = config.editor;
23890 this.editorcore = config.editor.editorcore;
23892 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
23894 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
23895 // dont call parent... till later.
23897 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
23902 editorcore : false,
23907 "h1","h2","h3","h4","h5","h6",
23909 "abbr", "acronym", "address", "cite", "samp", "var",
23913 onRender : function(ct, position)
23915 // Roo.log("Call onRender: " + this.xtype);
23917 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
23919 this.el.dom.style.marginBottom = '0';
23921 var editorcore = this.editorcore;
23922 var editor= this.editor;
23925 var btn = function(id,cmd , toggle, handler, html){
23927 var event = toggle ? 'toggle' : 'click';
23932 xns: Roo.bootstrap,
23935 enableToggle:toggle !== false,
23937 pressed : toggle ? false : null,
23940 a.listeners[toggle ? 'toggle' : 'click'] = function() {
23941 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
23947 // var cb_box = function...
23952 xns: Roo.bootstrap,
23953 glyphicon : 'font',
23957 xns: Roo.bootstrap,
23961 Roo.each(this.formats, function(f) {
23962 style.menu.items.push({
23964 xns: Roo.bootstrap,
23965 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
23970 editorcore.insertTag(this.tagname);
23977 children.push(style);
23979 btn('bold',false,true);
23980 btn('italic',false,true);
23981 btn('align-left', 'justifyleft',true);
23982 btn('align-center', 'justifycenter',true);
23983 btn('align-right' , 'justifyright',true);
23984 btn('link', false, false, function(btn) {
23985 //Roo.log("create link?");
23986 var url = prompt(this.createLinkText, this.defaultLinkValue);
23987 if(url && url != 'http:/'+'/'){
23988 this.editorcore.relayCmd('createlink', url);
23991 btn('list','insertunorderedlist',true);
23992 btn('pencil', false,true, function(btn){
23994 this.toggleSourceEdit(btn.pressed);
23997 if (this.editor.btns.length > 0) {
23998 for (var i = 0; i<this.editor.btns.length; i++) {
23999 children.push(this.editor.btns[i]);
24007 xns: Roo.bootstrap,
24012 xns: Roo.bootstrap,
24017 cog.menu.items.push({
24019 xns: Roo.bootstrap,
24020 html : Clean styles,
24025 editorcore.insertTag(this.tagname);
24034 this.xtype = 'NavSimplebar';
24036 for(var i=0;i< children.length;i++) {
24038 this.buttons.add(this.addxtypeChild(children[i]));
24042 editor.on('editorevent', this.updateToolbar, this);
24044 onBtnClick : function(id)
24046 this.editorcore.relayCmd(id);
24047 this.editorcore.focus();
24051 * Protected method that will not generally be called directly. It triggers
24052 * a toolbar update by reading the markup state of the current selection in the editor.
24054 updateToolbar: function(){
24056 if(!this.editorcore.activated){
24057 this.editor.onFirstFocus(); // is this neeed?
24061 var btns = this.buttons;
24062 var doc = this.editorcore.doc;
24063 btns.get('bold').setActive(doc.queryCommandState('bold'));
24064 btns.get('italic').setActive(doc.queryCommandState('italic'));
24065 //btns.get('underline').setActive(doc.queryCommandState('underline'));
24067 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
24068 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
24069 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
24071 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
24072 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
24075 var ans = this.editorcore.getAllAncestors();
24076 if (this.formatCombo) {
24079 var store = this.formatCombo.store;
24080 this.formatCombo.setValue("");
24081 for (var i =0; i < ans.length;i++) {
24082 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
24084 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
24092 // hides menus... - so this cant be on a menu...
24093 Roo.bootstrap.MenuMgr.hideAll();
24095 Roo.bootstrap.MenuMgr.hideAll();
24096 //this.editorsyncValue();
24098 onFirstFocus: function() {
24099 this.buttons.each(function(item){
24103 toggleSourceEdit : function(sourceEditMode){
24106 if(sourceEditMode){
24107 Roo.log("disabling buttons");
24108 this.buttons.each( function(item){
24109 if(item.cmd != 'pencil'){
24115 Roo.log("enabling buttons");
24116 if(this.editorcore.initialized){
24117 this.buttons.each( function(item){
24123 Roo.log("calling toggole on editor");
24124 // tell the editor that it's been pressed..
24125 this.editor.toggleSourceEdit(sourceEditMode);
24135 * @class Roo.bootstrap.Table.AbstractSelectionModel
24136 * @extends Roo.util.Observable
24137 * Abstract base class for grid SelectionModels. It provides the interface that should be
24138 * implemented by descendant classes. This class should not be directly instantiated.
24141 Roo.bootstrap.Table.AbstractSelectionModel = function(){
24142 this.locked = false;
24143 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
24147 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
24148 /** @ignore Called by the grid automatically. Do not call directly. */
24149 init : function(grid){
24155 * Locks the selections.
24158 this.locked = true;
24162 * Unlocks the selections.
24164 unlock : function(){
24165 this.locked = false;
24169 * Returns true if the selections are locked.
24170 * @return {Boolean}
24172 isLocked : function(){
24173 return this.locked;
24177 * @extends Roo.bootstrap.Table.AbstractSelectionModel
24178 * @class Roo.bootstrap.Table.RowSelectionModel
24179 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
24180 * It supports multiple selections and keyboard selection/navigation.
24182 * @param {Object} config
24185 Roo.bootstrap.Table.RowSelectionModel = function(config){
24186 Roo.apply(this, config);
24187 this.selections = new Roo.util.MixedCollection(false, function(o){
24192 this.lastActive = false;
24196 * @event selectionchange
24197 * Fires when the selection changes
24198 * @param {SelectionModel} this
24200 "selectionchange" : true,
24202 * @event afterselectionchange
24203 * Fires after the selection changes (eg. by key press or clicking)
24204 * @param {SelectionModel} this
24206 "afterselectionchange" : true,
24208 * @event beforerowselect
24209 * Fires when a row is selected being selected, return false to cancel.
24210 * @param {SelectionModel} this
24211 * @param {Number} rowIndex The selected index
24212 * @param {Boolean} keepExisting False if other selections will be cleared
24214 "beforerowselect" : true,
24217 * Fires when a row is selected.
24218 * @param {SelectionModel} this
24219 * @param {Number} rowIndex The selected index
24220 * @param {Roo.data.Record} r The record
24222 "rowselect" : true,
24224 * @event rowdeselect
24225 * Fires when a row is deselected.
24226 * @param {SelectionModel} this
24227 * @param {Number} rowIndex The selected index
24229 "rowdeselect" : true
24231 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
24232 this.locked = false;
24235 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
24237 * @cfg {Boolean} singleSelect
24238 * True to allow selection of only one row at a time (defaults to false)
24240 singleSelect : false,
24243 initEvents : function()
24246 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
24247 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
24248 //}else{ // allow click to work like normal
24249 // this.grid.on("rowclick", this.handleDragableRowClick, this);
24251 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
24252 this.grid.on("rowclick", this.handleMouseDown, this);
24254 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
24255 "up" : function(e){
24257 this.selectPrevious(e.shiftKey);
24258 }else if(this.last !== false && this.lastActive !== false){
24259 var last = this.last;
24260 this.selectRange(this.last, this.lastActive-1);
24261 this.grid.getView().focusRow(this.lastActive);
24262 if(last !== false){
24266 this.selectFirstRow();
24268 this.fireEvent("afterselectionchange", this);
24270 "down" : function(e){
24272 this.selectNext(e.shiftKey);
24273 }else if(this.last !== false && this.lastActive !== false){
24274 var last = this.last;
24275 this.selectRange(this.last, this.lastActive+1);
24276 this.grid.getView().focusRow(this.lastActive);
24277 if(last !== false){
24281 this.selectFirstRow();
24283 this.fireEvent("afterselectionchange", this);
24287 this.grid.store.on('load', function(){
24288 this.selections.clear();
24291 var view = this.grid.view;
24292 view.on("refresh", this.onRefresh, this);
24293 view.on("rowupdated", this.onRowUpdated, this);
24294 view.on("rowremoved", this.onRemove, this);
24299 onRefresh : function()
24301 var ds = this.grid.store, i, v = this.grid.view;
24302 var s = this.selections;
24303 s.each(function(r){
24304 if((i = ds.indexOfId(r.id)) != -1){
24313 onRemove : function(v, index, r){
24314 this.selections.remove(r);
24318 onRowUpdated : function(v, index, r){
24319 if(this.isSelected(r)){
24320 v.onRowSelect(index);
24326 * @param {Array} records The records to select
24327 * @param {Boolean} keepExisting (optional) True to keep existing selections
24329 selectRecords : function(records, keepExisting)
24332 this.clearSelections();
24334 var ds = this.grid.store;
24335 for(var i = 0, len = records.length; i < len; i++){
24336 this.selectRow(ds.indexOf(records[i]), true);
24341 * Gets the number of selected rows.
24344 getCount : function(){
24345 return this.selections.length;
24349 * Selects the first row in the grid.
24351 selectFirstRow : function(){
24356 * Select the last row.
24357 * @param {Boolean} keepExisting (optional) True to keep existing selections
24359 selectLastRow : function(keepExisting){
24360 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
24361 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
24365 * Selects the row immediately following the last selected row.
24366 * @param {Boolean} keepExisting (optional) True to keep existing selections
24368 selectNext : function(keepExisting)
24370 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
24371 this.selectRow(this.last+1, keepExisting);
24372 this.grid.getView().focusRow(this.last);
24377 * Selects the row that precedes the last selected row.
24378 * @param {Boolean} keepExisting (optional) True to keep existing selections
24380 selectPrevious : function(keepExisting){
24382 this.selectRow(this.last-1, keepExisting);
24383 this.grid.getView().focusRow(this.last);
24388 * Returns the selected records
24389 * @return {Array} Array of selected records
24391 getSelections : function(){
24392 return [].concat(this.selections.items);
24396 * Returns the first selected record.
24399 getSelected : function(){
24400 return this.selections.itemAt(0);
24405 * Clears all selections.
24407 clearSelections : function(fast)
24413 var ds = this.grid.store;
24414 var s = this.selections;
24415 s.each(function(r){
24416 this.deselectRow(ds.indexOfId(r.id));
24420 this.selections.clear();
24427 * Selects all rows.
24429 selectAll : function(){
24433 this.selections.clear();
24434 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
24435 this.selectRow(i, true);
24440 * Returns True if there is a selection.
24441 * @return {Boolean}
24443 hasSelection : function(){
24444 return this.selections.length > 0;
24448 * Returns True if the specified row is selected.
24449 * @param {Number/Record} record The record or index of the record to check
24450 * @return {Boolean}
24452 isSelected : function(index){
24453 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
24454 return (r && this.selections.key(r.id) ? true : false);
24458 * Returns True if the specified record id is selected.
24459 * @param {String} id The id of record to check
24460 * @return {Boolean}
24462 isIdSelected : function(id){
24463 return (this.selections.key(id) ? true : false);
24468 handleMouseDBClick : function(e, t){
24472 handleMouseDown : function(e, t)
24474 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
24475 if(this.isLocked() || rowIndex < 0 ){
24478 if(e.shiftKey && this.last !== false){
24479 var last = this.last;
24480 this.selectRange(last, rowIndex, e.ctrlKey);
24481 this.last = last; // reset the last
24485 var isSelected = this.isSelected(rowIndex);
24486 //Roo.log("select row:" + rowIndex);
24488 this.deselectRow(rowIndex);
24490 this.selectRow(rowIndex, true);
24494 if(e.button !== 0 && isSelected){
24495 alert('rowIndex 2: ' + rowIndex);
24496 view.focusRow(rowIndex);
24497 }else if(e.ctrlKey && isSelected){
24498 this.deselectRow(rowIndex);
24499 }else if(!isSelected){
24500 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
24501 view.focusRow(rowIndex);
24505 this.fireEvent("afterselectionchange", this);
24508 handleDragableRowClick : function(grid, rowIndex, e)
24510 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
24511 this.selectRow(rowIndex, false);
24512 grid.view.focusRow(rowIndex);
24513 this.fireEvent("afterselectionchange", this);
24518 * Selects multiple rows.
24519 * @param {Array} rows Array of the indexes of the row to select
24520 * @param {Boolean} keepExisting (optional) True to keep existing selections
24522 selectRows : function(rows, keepExisting){
24524 this.clearSelections();
24526 for(var i = 0, len = rows.length; i < len; i++){
24527 this.selectRow(rows[i], true);
24532 * Selects a range of rows. All rows in between startRow and endRow are also selected.
24533 * @param {Number} startRow The index of the first row in the range
24534 * @param {Number} endRow The index of the last row in the range
24535 * @param {Boolean} keepExisting (optional) True to retain existing selections
24537 selectRange : function(startRow, endRow, keepExisting){
24542 this.clearSelections();
24544 if(startRow <= endRow){
24545 for(var i = startRow; i <= endRow; i++){
24546 this.selectRow(i, true);
24549 for(var i = startRow; i >= endRow; i--){
24550 this.selectRow(i, true);
24556 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
24557 * @param {Number} startRow The index of the first row in the range
24558 * @param {Number} endRow The index of the last row in the range
24560 deselectRange : function(startRow, endRow, preventViewNotify){
24564 for(var i = startRow; i <= endRow; i++){
24565 this.deselectRow(i, preventViewNotify);
24571 * @param {Number} row The index of the row to select
24572 * @param {Boolean} keepExisting (optional) True to keep existing selections
24574 selectRow : function(index, keepExisting, preventViewNotify)
24576 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
24579 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
24580 if(!keepExisting || this.singleSelect){
24581 this.clearSelections();
24584 var r = this.grid.store.getAt(index);
24585 //console.log('selectRow - record id :' + r.id);
24587 this.selections.add(r);
24588 this.last = this.lastActive = index;
24589 if(!preventViewNotify){
24590 var proxy = new Roo.Element(
24591 this.grid.getRowDom(index)
24593 proxy.addClass('bg-info info');
24595 this.fireEvent("rowselect", this, index, r);
24596 this.fireEvent("selectionchange", this);
24602 * @param {Number} row The index of the row to deselect
24604 deselectRow : function(index, preventViewNotify)
24609 if(this.last == index){
24612 if(this.lastActive == index){
24613 this.lastActive = false;
24616 var r = this.grid.store.getAt(index);
24621 this.selections.remove(r);
24622 //.console.log('deselectRow - record id :' + r.id);
24623 if(!preventViewNotify){
24625 var proxy = new Roo.Element(
24626 this.grid.getRowDom(index)
24628 proxy.removeClass('bg-info info');
24630 this.fireEvent("rowdeselect", this, index);
24631 this.fireEvent("selectionchange", this);
24635 restoreLast : function(){
24637 this.last = this._last;
24642 acceptsNav : function(row, col, cm){
24643 return !cm.isHidden(col) && cm.isCellEditable(col, row);
24647 onEditorKey : function(field, e){
24648 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
24653 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
24655 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
24657 }else if(k == e.ENTER && !e.ctrlKey){
24661 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
24663 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
24665 }else if(k == e.ESC){
24669 g.startEditing(newCell[0], newCell[1]);
24675 * Ext JS Library 1.1.1
24676 * Copyright(c) 2006-2007, Ext JS, LLC.
24678 * Originally Released Under LGPL - original licence link has changed is not relivant.
24681 * <script type="text/javascript">
24685 * @class Roo.bootstrap.PagingToolbar
24686 * @extends Roo.bootstrap.NavSimplebar
24687 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
24689 * Create a new PagingToolbar
24690 * @param {Object} config The config object
24691 * @param {Roo.data.Store} store
24693 Roo.bootstrap.PagingToolbar = function(config)
24695 // old args format still supported... - xtype is prefered..
24696 // created from xtype...
24698 this.ds = config.dataSource;
24700 if (config.store && !this.ds) {
24701 this.store= Roo.factory(config.store, Roo.data);
24702 this.ds = this.store;
24703 this.ds.xmodule = this.xmodule || false;
24706 this.toolbarItems = [];
24707 if (config.items) {
24708 this.toolbarItems = config.items;
24711 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
24716 this.bind(this.ds);
24719 if (Roo.bootstrap.version == 4) {
24720 this.navgroup = new Roo.bootstrap.ButtonGroup({ cls: 'pagination' });
24722 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
24727 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
24729 * @cfg {Roo.data.Store} dataSource
24730 * The underlying data store providing the paged data
24733 * @cfg {String/HTMLElement/Element} container
24734 * container The id or element that will contain the toolbar
24737 * @cfg {Boolean} displayInfo
24738 * True to display the displayMsg (defaults to false)
24741 * @cfg {Number} pageSize
24742 * The number of records to display per page (defaults to 20)
24746 * @cfg {String} displayMsg
24747 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
24749 displayMsg : 'Displaying {0} - {1} of {2}',
24751 * @cfg {String} emptyMsg
24752 * The message to display when no records are found (defaults to "No data to display")
24754 emptyMsg : 'No data to display',
24756 * Customizable piece of the default paging text (defaults to "Page")
24759 beforePageText : "Page",
24761 * Customizable piece of the default paging text (defaults to "of %0")
24764 afterPageText : "of {0}",
24766 * Customizable piece of the default paging text (defaults to "First Page")
24769 firstText : "First Page",
24771 * Customizable piece of the default paging text (defaults to "Previous Page")
24774 prevText : "Previous Page",
24776 * Customizable piece of the default paging text (defaults to "Next Page")
24779 nextText : "Next Page",
24781 * Customizable piece of the default paging text (defaults to "Last Page")
24784 lastText : "Last Page",
24786 * Customizable piece of the default paging text (defaults to "Refresh")
24789 refreshText : "Refresh",
24793 onRender : function(ct, position)
24795 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
24796 this.navgroup.parentId = this.id;
24797 this.navgroup.onRender(this.el, null);
24798 // add the buttons to the navgroup
24800 if(this.displayInfo){
24801 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
24802 this.displayEl = this.el.select('.x-paging-info', true).first();
24803 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
24804 // this.displayEl = navel.el.select('span',true).first();
24810 Roo.each(_this.buttons, function(e){ // this might need to use render????
24811 Roo.factory(e).render(_this.el);
24815 Roo.each(_this.toolbarItems, function(e) {
24816 _this.navgroup.addItem(e);
24820 this.first = this.navgroup.addItem({
24821 tooltip: this.firstText,
24822 cls: "prev btn-outline-secondary",
24823 html : ' <i class="fa fa-step-backward"></i>',
24825 preventDefault: true,
24826 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
24829 this.prev = this.navgroup.addItem({
24830 tooltip: this.prevText,
24831 cls: "prev btn-outline-secondary",
24832 html : ' <i class="fa fa-backward"></i>',
24834 preventDefault: true,
24835 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
24837 //this.addSeparator();
24840 var field = this.navgroup.addItem( {
24842 cls : 'x-paging-position btn-outline-secondary',
24844 html : this.beforePageText +
24845 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
24846 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
24849 this.field = field.el.select('input', true).first();
24850 this.field.on("keydown", this.onPagingKeydown, this);
24851 this.field.on("focus", function(){this.dom.select();});
24854 this.afterTextEl = field.el.select('.x-paging-after',true).first();
24855 //this.field.setHeight(18);
24856 //this.addSeparator();
24857 this.next = this.navgroup.addItem({
24858 tooltip: this.nextText,
24859 cls: "next btn-outline-secondary",
24860 html : ' <i class="fa fa-forward"></i>',
24862 preventDefault: true,
24863 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
24865 this.last = this.navgroup.addItem({
24866 tooltip: this.lastText,
24867 html : ' <i class="fa fa-step-forward"></i>',
24868 cls: "next btn-outline-secondary",
24870 preventDefault: true,
24871 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
24873 //this.addSeparator();
24874 this.loading = this.navgroup.addItem({
24875 tooltip: this.refreshText,
24876 cls: "btn-outline-secondary",
24877 html : ' <i class="fa fa-refresh"></i>',
24878 preventDefault: true,
24879 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
24885 updateInfo : function(){
24886 if(this.displayEl){
24887 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
24888 var msg = count == 0 ?
24892 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
24894 this.displayEl.update(msg);
24899 onLoad : function(ds, r, o)
24901 this.cursor = o.params.start ? o.params.start : 0;
24903 var d = this.getPageData(),
24908 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
24909 this.field.dom.value = ap;
24910 this.first.setDisabled(ap == 1);
24911 this.prev.setDisabled(ap == 1);
24912 this.next.setDisabled(ap == ps);
24913 this.last.setDisabled(ap == ps);
24914 this.loading.enable();
24919 getPageData : function(){
24920 var total = this.ds.getTotalCount();
24923 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
24924 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
24929 onLoadError : function(){
24930 this.loading.enable();
24934 onPagingKeydown : function(e){
24935 var k = e.getKey();
24936 var d = this.getPageData();
24938 var v = this.field.dom.value, pageNum;
24939 if(!v || isNaN(pageNum = parseInt(v, 10))){
24940 this.field.dom.value = d.activePage;
24943 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
24944 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24947 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))
24949 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
24950 this.field.dom.value = pageNum;
24951 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
24954 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
24956 var v = this.field.dom.value, pageNum;
24957 var increment = (e.shiftKey) ? 10 : 1;
24958 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
24961 if(!v || isNaN(pageNum = parseInt(v, 10))) {
24962 this.field.dom.value = d.activePage;
24965 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
24967 this.field.dom.value = parseInt(v, 10) + increment;
24968 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
24969 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24976 beforeLoad : function(){
24978 this.loading.disable();
24983 onClick : function(which){
24992 ds.load({params:{start: 0, limit: this.pageSize}});
24995 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
24998 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
25001 var total = ds.getTotalCount();
25002 var extra = total % this.pageSize;
25003 var lastStart = extra ? (total - extra) : total-this.pageSize;
25004 ds.load({params:{start: lastStart, limit: this.pageSize}});
25007 ds.load({params:{start: this.cursor, limit: this.pageSize}});
25013 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
25014 * @param {Roo.data.Store} store The data store to unbind
25016 unbind : function(ds){
25017 ds.un("beforeload", this.beforeLoad, this);
25018 ds.un("load", this.onLoad, this);
25019 ds.un("loadexception", this.onLoadError, this);
25020 ds.un("remove", this.updateInfo, this);
25021 ds.un("add", this.updateInfo, this);
25022 this.ds = undefined;
25026 * Binds the paging toolbar to the specified {@link Roo.data.Store}
25027 * @param {Roo.data.Store} store The data store to bind
25029 bind : function(ds){
25030 ds.on("beforeload", this.beforeLoad, this);
25031 ds.on("load", this.onLoad, this);
25032 ds.on("loadexception", this.onLoadError, this);
25033 ds.on("remove", this.updateInfo, this);
25034 ds.on("add", this.updateInfo, this);
25045 * @class Roo.bootstrap.MessageBar
25046 * @extends Roo.bootstrap.Component
25047 * Bootstrap MessageBar class
25048 * @cfg {String} html contents of the MessageBar
25049 * @cfg {String} weight (info | success | warning | danger) default info
25050 * @cfg {String} beforeClass insert the bar before the given class
25051 * @cfg {Boolean} closable (true | false) default false
25052 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
25055 * Create a new Element
25056 * @param {Object} config The config object
25059 Roo.bootstrap.MessageBar = function(config){
25060 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
25063 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
25069 beforeClass: 'bootstrap-sticky-wrap',
25071 getAutoCreate : function(){
25075 cls: 'alert alert-dismissable alert-' + this.weight,
25080 html: this.html || ''
25086 cfg.cls += ' alert-messages-fixed';
25100 onRender : function(ct, position)
25102 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
25105 var cfg = Roo.apply({}, this.getAutoCreate());
25109 cfg.cls += ' ' + this.cls;
25112 cfg.style = this.style;
25114 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
25116 this.el.setVisibilityMode(Roo.Element.DISPLAY);
25119 this.el.select('>button.close').on('click', this.hide, this);
25125 if (!this.rendered) {
25131 this.fireEvent('show', this);
25137 if (!this.rendered) {
25143 this.fireEvent('hide', this);
25146 update : function()
25148 // var e = this.el.dom.firstChild;
25150 // if(this.closable){
25151 // e = e.nextSibling;
25154 // e.data = this.html || '';
25156 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
25172 * @class Roo.bootstrap.Graph
25173 * @extends Roo.bootstrap.Component
25174 * Bootstrap Graph class
25178 @cfg {String} graphtype bar | vbar | pie
25179 @cfg {number} g_x coodinator | centre x (pie)
25180 @cfg {number} g_y coodinator | centre y (pie)
25181 @cfg {number} g_r radius (pie)
25182 @cfg {number} g_height height of the chart (respected by all elements in the set)
25183 @cfg {number} g_width width of the chart (respected by all elements in the set)
25184 @cfg {Object} title The title of the chart
25187 -opts (object) options for the chart
25189 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
25190 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
25192 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.
25193 o stacked (boolean) whether or not to tread values as in a stacked bar chart
25195 o stretch (boolean)
25197 -opts (object) options for the pie
25200 o startAngle (number)
25201 o endAngle (number)
25205 * Create a new Input
25206 * @param {Object} config The config object
25209 Roo.bootstrap.Graph = function(config){
25210 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
25216 * The img click event for the img.
25217 * @param {Roo.EventObject} e
25223 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
25234 //g_colors: this.colors,
25241 getAutoCreate : function(){
25252 onRender : function(ct,position){
25255 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
25257 if (typeof(Raphael) == 'undefined') {
25258 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
25262 this.raphael = Raphael(this.el.dom);
25264 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25265 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25266 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25267 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
25269 r.text(160, 10, "Single Series Chart").attr(txtattr);
25270 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
25271 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
25272 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
25274 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
25275 r.barchart(330, 10, 300, 220, data1);
25276 r.barchart(10, 250, 300, 220, data2, {stacked: true});
25277 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
25280 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25281 // r.barchart(30, 30, 560, 250, xdata, {
25282 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
25283 // axis : "0 0 1 1",
25284 // axisxlabels : xdata
25285 // //yvalues : cols,
25288 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25290 // this.load(null,xdata,{
25291 // axis : "0 0 1 1",
25292 // axisxlabels : xdata
25297 load : function(graphtype,xdata,opts)
25299 this.raphael.clear();
25301 graphtype = this.graphtype;
25306 var r = this.raphael,
25307 fin = function () {
25308 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
25310 fout = function () {
25311 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
25313 pfin = function() {
25314 this.sector.stop();
25315 this.sector.scale(1.1, 1.1, this.cx, this.cy);
25318 this.label[0].stop();
25319 this.label[0].attr({ r: 7.5 });
25320 this.label[1].attr({ "font-weight": 800 });
25323 pfout = function() {
25324 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
25327 this.label[0].animate({ r: 5 }, 500, "bounce");
25328 this.label[1].attr({ "font-weight": 400 });
25334 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25337 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25340 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
25341 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
25343 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
25350 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
25355 setTitle: function(o)
25360 initEvents: function() {
25363 this.el.on('click', this.onClick, this);
25367 onClick : function(e)
25369 Roo.log('img onclick');
25370 this.fireEvent('click', this, e);
25382 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25385 * @class Roo.bootstrap.dash.NumberBox
25386 * @extends Roo.bootstrap.Component
25387 * Bootstrap NumberBox class
25388 * @cfg {String} headline Box headline
25389 * @cfg {String} content Box content
25390 * @cfg {String} icon Box icon
25391 * @cfg {String} footer Footer text
25392 * @cfg {String} fhref Footer href
25395 * Create a new NumberBox
25396 * @param {Object} config The config object
25400 Roo.bootstrap.dash.NumberBox = function(config){
25401 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
25405 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
25414 getAutoCreate : function(){
25418 cls : 'small-box ',
25426 cls : 'roo-headline',
25427 html : this.headline
25431 cls : 'roo-content',
25432 html : this.content
25446 cls : 'ion ' + this.icon
25455 cls : 'small-box-footer',
25456 href : this.fhref || '#',
25460 cfg.cn.push(footer);
25467 onRender : function(ct,position){
25468 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
25475 setHeadline: function (value)
25477 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
25480 setFooter: function (value, href)
25482 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
25485 this.el.select('a.small-box-footer',true).first().attr('href', href);
25490 setContent: function (value)
25492 this.el.select('.roo-content',true).first().dom.innerHTML = value;
25495 initEvents: function()
25509 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25512 * @class Roo.bootstrap.dash.TabBox
25513 * @extends Roo.bootstrap.Component
25514 * Bootstrap TabBox class
25515 * @cfg {String} title Title of the TabBox
25516 * @cfg {String} icon Icon of the TabBox
25517 * @cfg {Boolean} showtabs (true|false) show the tabs default true
25518 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
25521 * Create a new TabBox
25522 * @param {Object} config The config object
25526 Roo.bootstrap.dash.TabBox = function(config){
25527 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
25532 * When a pane is added
25533 * @param {Roo.bootstrap.dash.TabPane} pane
25537 * @event activatepane
25538 * When a pane is activated
25539 * @param {Roo.bootstrap.dash.TabPane} pane
25541 "activatepane" : true
25549 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
25554 tabScrollable : false,
25556 getChildContainer : function()
25558 return this.el.select('.tab-content', true).first();
25561 getAutoCreate : function(){
25565 cls: 'pull-left header',
25573 cls: 'fa ' + this.icon
25579 cls: 'nav nav-tabs pull-right',
25585 if(this.tabScrollable){
25592 cls: 'nav nav-tabs pull-right',
25603 cls: 'nav-tabs-custom',
25608 cls: 'tab-content no-padding',
25616 initEvents : function()
25618 //Roo.log('add add pane handler');
25619 this.on('addpane', this.onAddPane, this);
25622 * Updates the box title
25623 * @param {String} html to set the title to.
25625 setTitle : function(value)
25627 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
25629 onAddPane : function(pane)
25631 this.panes.push(pane);
25632 //Roo.log('addpane');
25634 // tabs are rendere left to right..
25635 if(!this.showtabs){
25639 var ctr = this.el.select('.nav-tabs', true).first();
25642 var existing = ctr.select('.nav-tab',true);
25643 var qty = existing.getCount();;
25646 var tab = ctr.createChild({
25648 cls : 'nav-tab' + (qty ? '' : ' active'),
25656 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
25659 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
25661 pane.el.addClass('active');
25666 onTabClick : function(ev,un,ob,pane)
25668 //Roo.log('tab - prev default');
25669 ev.preventDefault();
25672 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
25673 pane.tab.addClass('active');
25674 //Roo.log(pane.title);
25675 this.getChildContainer().select('.tab-pane',true).removeClass('active');
25676 // technically we should have a deactivate event.. but maybe add later.
25677 // and it should not de-activate the selected tab...
25678 this.fireEvent('activatepane', pane);
25679 pane.el.addClass('active');
25680 pane.fireEvent('activate');
25685 getActivePane : function()
25688 Roo.each(this.panes, function(p) {
25689 if(p.el.hasClass('active')){
25710 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25712 * @class Roo.bootstrap.TabPane
25713 * @extends Roo.bootstrap.Component
25714 * Bootstrap TabPane class
25715 * @cfg {Boolean} active (false | true) Default false
25716 * @cfg {String} title title of panel
25720 * Create a new TabPane
25721 * @param {Object} config The config object
25724 Roo.bootstrap.dash.TabPane = function(config){
25725 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
25731 * When a pane is activated
25732 * @param {Roo.bootstrap.dash.TabPane} pane
25739 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
25744 // the tabBox that this is attached to.
25747 getAutoCreate : function()
25755 cfg.cls += ' active';
25760 initEvents : function()
25762 //Roo.log('trigger add pane handler');
25763 this.parent().fireEvent('addpane', this)
25767 * Updates the tab title
25768 * @param {String} html to set the title to.
25770 setTitle: function(str)
25776 this.tab.select('a', true).first().dom.innerHTML = str;
25793 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25796 * @class Roo.bootstrap.menu.Menu
25797 * @extends Roo.bootstrap.Component
25798 * Bootstrap Menu class - container for Menu
25799 * @cfg {String} html Text of the menu
25800 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
25801 * @cfg {String} icon Font awesome icon
25802 * @cfg {String} pos Menu align to (top | bottom) default bottom
25806 * Create a new Menu
25807 * @param {Object} config The config object
25811 Roo.bootstrap.menu.Menu = function(config){
25812 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
25816 * @event beforeshow
25817 * Fires before this menu is displayed
25818 * @param {Roo.bootstrap.menu.Menu} this
25822 * @event beforehide
25823 * Fires before this menu is hidden
25824 * @param {Roo.bootstrap.menu.Menu} this
25829 * Fires after this menu is displayed
25830 * @param {Roo.bootstrap.menu.Menu} this
25835 * Fires after this menu is hidden
25836 * @param {Roo.bootstrap.menu.Menu} this
25841 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
25842 * @param {Roo.bootstrap.menu.Menu} this
25843 * @param {Roo.EventObject} e
25850 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
25854 weight : 'default',
25859 getChildContainer : function() {
25860 if(this.isSubMenu){
25864 return this.el.select('ul.dropdown-menu', true).first();
25867 getAutoCreate : function()
25872 cls : 'roo-menu-text',
25880 cls : 'fa ' + this.icon
25891 cls : 'dropdown-button btn btn-' + this.weight,
25896 cls : 'dropdown-toggle btn btn-' + this.weight,
25906 cls : 'dropdown-menu'
25912 if(this.pos == 'top'){
25913 cfg.cls += ' dropup';
25916 if(this.isSubMenu){
25919 cls : 'dropdown-menu'
25926 onRender : function(ct, position)
25928 this.isSubMenu = ct.hasClass('dropdown-submenu');
25930 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
25933 initEvents : function()
25935 if(this.isSubMenu){
25939 this.hidden = true;
25941 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
25942 this.triggerEl.on('click', this.onTriggerPress, this);
25944 this.buttonEl = this.el.select('button.dropdown-button', true).first();
25945 this.buttonEl.on('click', this.onClick, this);
25951 if(this.isSubMenu){
25955 return this.el.select('ul.dropdown-menu', true).first();
25958 onClick : function(e)
25960 this.fireEvent("click", this, e);
25963 onTriggerPress : function(e)
25965 if (this.isVisible()) {
25972 isVisible : function(){
25973 return !this.hidden;
25978 this.fireEvent("beforeshow", this);
25980 this.hidden = false;
25981 this.el.addClass('open');
25983 Roo.get(document).on("mouseup", this.onMouseUp, this);
25985 this.fireEvent("show", this);
25992 this.fireEvent("beforehide", this);
25994 this.hidden = true;
25995 this.el.removeClass('open');
25997 Roo.get(document).un("mouseup", this.onMouseUp);
25999 this.fireEvent("hide", this);
26002 onMouseUp : function()
26016 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
26019 * @class Roo.bootstrap.menu.Item
26020 * @extends Roo.bootstrap.Component
26021 * Bootstrap MenuItem class
26022 * @cfg {Boolean} submenu (true | false) default false
26023 * @cfg {String} html text of the item
26024 * @cfg {String} href the link
26025 * @cfg {Boolean} disable (true | false) default false
26026 * @cfg {Boolean} preventDefault (true | false) default true
26027 * @cfg {String} icon Font awesome icon
26028 * @cfg {String} pos Submenu align to (left | right) default right
26032 * Create a new Item
26033 * @param {Object} config The config object
26037 Roo.bootstrap.menu.Item = function(config){
26038 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
26042 * Fires when the mouse is hovering over this menu
26043 * @param {Roo.bootstrap.menu.Item} this
26044 * @param {Roo.EventObject} e
26049 * Fires when the mouse exits this menu
26050 * @param {Roo.bootstrap.menu.Item} this
26051 * @param {Roo.EventObject} e
26057 * The raw click event for the entire grid.
26058 * @param {Roo.EventObject} e
26064 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
26069 preventDefault: true,
26074 getAutoCreate : function()
26079 cls : 'roo-menu-item-text',
26087 cls : 'fa ' + this.icon
26096 href : this.href || '#',
26103 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
26107 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
26109 if(this.pos == 'left'){
26110 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
26117 initEvents : function()
26119 this.el.on('mouseover', this.onMouseOver, this);
26120 this.el.on('mouseout', this.onMouseOut, this);
26122 this.el.select('a', true).first().on('click', this.onClick, this);
26126 onClick : function(e)
26128 if(this.preventDefault){
26129 e.preventDefault();
26132 this.fireEvent("click", this, e);
26135 onMouseOver : function(e)
26137 if(this.submenu && this.pos == 'left'){
26138 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
26141 this.fireEvent("mouseover", this, e);
26144 onMouseOut : function(e)
26146 this.fireEvent("mouseout", this, e);
26158 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
26161 * @class Roo.bootstrap.menu.Separator
26162 * @extends Roo.bootstrap.Component
26163 * Bootstrap Separator class
26166 * Create a new Separator
26167 * @param {Object} config The config object
26171 Roo.bootstrap.menu.Separator = function(config){
26172 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
26175 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
26177 getAutoCreate : function(){
26198 * @class Roo.bootstrap.Tooltip
26199 * Bootstrap Tooltip class
26200 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
26201 * to determine which dom element triggers the tooltip.
26203 * It needs to add support for additional attributes like tooltip-position
26206 * Create a new Toolti
26207 * @param {Object} config The config object
26210 Roo.bootstrap.Tooltip = function(config){
26211 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
26213 this.alignment = Roo.bootstrap.Tooltip.alignment;
26215 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
26216 this.alignment = config.alignment;
26221 Roo.apply(Roo.bootstrap.Tooltip, {
26223 * @function init initialize tooltip monitoring.
26227 currentTip : false,
26228 currentRegion : false,
26234 Roo.get(document).on('mouseover', this.enter ,this);
26235 Roo.get(document).on('mouseout', this.leave, this);
26238 this.currentTip = new Roo.bootstrap.Tooltip();
26241 enter : function(ev)
26243 var dom = ev.getTarget();
26245 //Roo.log(['enter',dom]);
26246 var el = Roo.fly(dom);
26247 if (this.currentEl) {
26249 //Roo.log(this.currentEl);
26250 //Roo.log(this.currentEl.contains(dom));
26251 if (this.currentEl == el) {
26254 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
26260 if (this.currentTip.el) {
26261 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
26265 if(!el || el.dom == document){
26271 // you can not look for children, as if el is the body.. then everythign is the child..
26272 if (!el.attr('tooltip')) { //
26273 if (!el.select("[tooltip]").elements.length) {
26276 // is the mouse over this child...?
26277 bindEl = el.select("[tooltip]").first();
26278 var xy = ev.getXY();
26279 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
26280 //Roo.log("not in region.");
26283 //Roo.log("child element over..");
26286 this.currentEl = bindEl;
26287 this.currentTip.bind(bindEl);
26288 this.currentRegion = Roo.lib.Region.getRegion(dom);
26289 this.currentTip.enter();
26292 leave : function(ev)
26294 var dom = ev.getTarget();
26295 //Roo.log(['leave',dom]);
26296 if (!this.currentEl) {
26301 if (dom != this.currentEl.dom) {
26304 var xy = ev.getXY();
26305 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
26308 // only activate leave if mouse cursor is outside... bounding box..
26313 if (this.currentTip) {
26314 this.currentTip.leave();
26316 //Roo.log('clear currentEl');
26317 this.currentEl = false;
26322 'left' : ['r-l', [-2,0], 'right'],
26323 'right' : ['l-r', [2,0], 'left'],
26324 'bottom' : ['t-b', [0,2], 'top'],
26325 'top' : [ 'b-t', [0,-2], 'bottom']
26331 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
26336 delay : null, // can be { show : 300 , hide: 500}
26340 hoverState : null, //???
26342 placement : 'bottom',
26346 getAutoCreate : function(){
26353 cls : 'tooltip-arrow'
26356 cls : 'tooltip-inner'
26363 bind : function(el)
26369 enter : function () {
26371 if (this.timeout != null) {
26372 clearTimeout(this.timeout);
26375 this.hoverState = 'in';
26376 //Roo.log("enter - show");
26377 if (!this.delay || !this.delay.show) {
26382 this.timeout = setTimeout(function () {
26383 if (_t.hoverState == 'in') {
26386 }, this.delay.show);
26390 clearTimeout(this.timeout);
26392 this.hoverState = 'out';
26393 if (!this.delay || !this.delay.hide) {
26399 this.timeout = setTimeout(function () {
26400 //Roo.log("leave - timeout");
26402 if (_t.hoverState == 'out') {
26404 Roo.bootstrap.Tooltip.currentEl = false;
26409 show : function (msg)
26412 this.render(document.body);
26415 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
26417 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
26419 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
26421 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
26423 var placement = typeof this.placement == 'function' ?
26424 this.placement.call(this, this.el, on_el) :
26427 var autoToken = /\s?auto?\s?/i;
26428 var autoPlace = autoToken.test(placement);
26430 placement = placement.replace(autoToken, '') || 'top';
26434 //this.el.setXY([0,0]);
26436 //this.el.dom.style.display='block';
26438 //this.el.appendTo(on_el);
26440 var p = this.getPosition();
26441 var box = this.el.getBox();
26447 var align = this.alignment[placement];
26449 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
26451 if(placement == 'top' || placement == 'bottom'){
26453 placement = 'right';
26456 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
26457 placement = 'left';
26460 var scroll = Roo.select('body', true).first().getScroll();
26462 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
26466 align = this.alignment[placement];
26469 this.el.alignTo(this.bindEl, align[0],align[1]);
26470 //var arrow = this.el.select('.arrow',true).first();
26471 //arrow.set(align[2],
26473 this.el.addClass(placement);
26475 this.el.addClass('in fade');
26477 this.hoverState = null;
26479 if (this.el.hasClass('fade')) {
26490 //this.el.setXY([0,0]);
26491 this.el.removeClass('in');
26507 * @class Roo.bootstrap.LocationPicker
26508 * @extends Roo.bootstrap.Component
26509 * Bootstrap LocationPicker class
26510 * @cfg {Number} latitude Position when init default 0
26511 * @cfg {Number} longitude Position when init default 0
26512 * @cfg {Number} zoom default 15
26513 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
26514 * @cfg {Boolean} mapTypeControl default false
26515 * @cfg {Boolean} disableDoubleClickZoom default false
26516 * @cfg {Boolean} scrollwheel default true
26517 * @cfg {Boolean} streetViewControl default false
26518 * @cfg {Number} radius default 0
26519 * @cfg {String} locationName
26520 * @cfg {Boolean} draggable default true
26521 * @cfg {Boolean} enableAutocomplete default false
26522 * @cfg {Boolean} enableReverseGeocode default true
26523 * @cfg {String} markerTitle
26526 * Create a new LocationPicker
26527 * @param {Object} config The config object
26531 Roo.bootstrap.LocationPicker = function(config){
26533 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
26538 * Fires when the picker initialized.
26539 * @param {Roo.bootstrap.LocationPicker} this
26540 * @param {Google Location} location
26544 * @event positionchanged
26545 * Fires when the picker position changed.
26546 * @param {Roo.bootstrap.LocationPicker} this
26547 * @param {Google Location} location
26549 positionchanged : true,
26552 * Fires when the map resize.
26553 * @param {Roo.bootstrap.LocationPicker} this
26558 * Fires when the map show.
26559 * @param {Roo.bootstrap.LocationPicker} this
26564 * Fires when the map hide.
26565 * @param {Roo.bootstrap.LocationPicker} this
26570 * Fires when click the map.
26571 * @param {Roo.bootstrap.LocationPicker} this
26572 * @param {Map event} e
26576 * @event mapRightClick
26577 * Fires when right click the map.
26578 * @param {Roo.bootstrap.LocationPicker} this
26579 * @param {Map event} e
26581 mapRightClick : true,
26583 * @event markerClick
26584 * Fires when click the marker.
26585 * @param {Roo.bootstrap.LocationPicker} this
26586 * @param {Map event} e
26588 markerClick : true,
26590 * @event markerRightClick
26591 * Fires when right click the marker.
26592 * @param {Roo.bootstrap.LocationPicker} this
26593 * @param {Map event} e
26595 markerRightClick : true,
26597 * @event OverlayViewDraw
26598 * Fires when OverlayView Draw
26599 * @param {Roo.bootstrap.LocationPicker} this
26601 OverlayViewDraw : true,
26603 * @event OverlayViewOnAdd
26604 * Fires when OverlayView Draw
26605 * @param {Roo.bootstrap.LocationPicker} this
26607 OverlayViewOnAdd : true,
26609 * @event OverlayViewOnRemove
26610 * Fires when OverlayView Draw
26611 * @param {Roo.bootstrap.LocationPicker} this
26613 OverlayViewOnRemove : true,
26615 * @event OverlayViewShow
26616 * Fires when OverlayView Draw
26617 * @param {Roo.bootstrap.LocationPicker} this
26618 * @param {Pixel} cpx
26620 OverlayViewShow : true,
26622 * @event OverlayViewHide
26623 * Fires when OverlayView Draw
26624 * @param {Roo.bootstrap.LocationPicker} this
26626 OverlayViewHide : true,
26628 * @event loadexception
26629 * Fires when load google lib failed.
26630 * @param {Roo.bootstrap.LocationPicker} this
26632 loadexception : true
26637 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
26639 gMapContext: false,
26645 mapTypeControl: false,
26646 disableDoubleClickZoom: false,
26648 streetViewControl: false,
26652 enableAutocomplete: false,
26653 enableReverseGeocode: true,
26656 getAutoCreate: function()
26661 cls: 'roo-location-picker'
26667 initEvents: function(ct, position)
26669 if(!this.el.getWidth() || this.isApplied()){
26673 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26678 initial: function()
26680 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
26681 this.fireEvent('loadexception', this);
26685 if(!this.mapTypeId){
26686 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
26689 this.gMapContext = this.GMapContext();
26691 this.initOverlayView();
26693 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
26697 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
26698 _this.setPosition(_this.gMapContext.marker.position);
26701 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
26702 _this.fireEvent('mapClick', this, event);
26706 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
26707 _this.fireEvent('mapRightClick', this, event);
26711 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
26712 _this.fireEvent('markerClick', this, event);
26716 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
26717 _this.fireEvent('markerRightClick', this, event);
26721 this.setPosition(this.gMapContext.location);
26723 this.fireEvent('initial', this, this.gMapContext.location);
26726 initOverlayView: function()
26730 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
26734 _this.fireEvent('OverlayViewDraw', _this);
26739 _this.fireEvent('OverlayViewOnAdd', _this);
26742 onRemove: function()
26744 _this.fireEvent('OverlayViewOnRemove', _this);
26747 show: function(cpx)
26749 _this.fireEvent('OverlayViewShow', _this, cpx);
26754 _this.fireEvent('OverlayViewHide', _this);
26760 fromLatLngToContainerPixel: function(event)
26762 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
26765 isApplied: function()
26767 return this.getGmapContext() == false ? false : true;
26770 getGmapContext: function()
26772 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
26775 GMapContext: function()
26777 var position = new google.maps.LatLng(this.latitude, this.longitude);
26779 var _map = new google.maps.Map(this.el.dom, {
26782 mapTypeId: this.mapTypeId,
26783 mapTypeControl: this.mapTypeControl,
26784 disableDoubleClickZoom: this.disableDoubleClickZoom,
26785 scrollwheel: this.scrollwheel,
26786 streetViewControl: this.streetViewControl,
26787 locationName: this.locationName,
26788 draggable: this.draggable,
26789 enableAutocomplete: this.enableAutocomplete,
26790 enableReverseGeocode: this.enableReverseGeocode
26793 var _marker = new google.maps.Marker({
26794 position: position,
26796 title: this.markerTitle,
26797 draggable: this.draggable
26804 location: position,
26805 radius: this.radius,
26806 locationName: this.locationName,
26807 addressComponents: {
26808 formatted_address: null,
26809 addressLine1: null,
26810 addressLine2: null,
26812 streetNumber: null,
26816 stateOrProvince: null
26819 domContainer: this.el.dom,
26820 geodecoder: new google.maps.Geocoder()
26824 drawCircle: function(center, radius, options)
26826 if (this.gMapContext.circle != null) {
26827 this.gMapContext.circle.setMap(null);
26831 options = Roo.apply({}, options, {
26832 strokeColor: "#0000FF",
26833 strokeOpacity: .35,
26835 fillColor: "#0000FF",
26839 options.map = this.gMapContext.map;
26840 options.radius = radius;
26841 options.center = center;
26842 this.gMapContext.circle = new google.maps.Circle(options);
26843 return this.gMapContext.circle;
26849 setPosition: function(location)
26851 this.gMapContext.location = location;
26852 this.gMapContext.marker.setPosition(location);
26853 this.gMapContext.map.panTo(location);
26854 this.drawCircle(location, this.gMapContext.radius, {});
26858 if (this.gMapContext.settings.enableReverseGeocode) {
26859 this.gMapContext.geodecoder.geocode({
26860 latLng: this.gMapContext.location
26861 }, function(results, status) {
26863 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
26864 _this.gMapContext.locationName = results[0].formatted_address;
26865 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
26867 _this.fireEvent('positionchanged', this, location);
26874 this.fireEvent('positionchanged', this, location);
26879 google.maps.event.trigger(this.gMapContext.map, "resize");
26881 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
26883 this.fireEvent('resize', this);
26886 setPositionByLatLng: function(latitude, longitude)
26888 this.setPosition(new google.maps.LatLng(latitude, longitude));
26891 getCurrentPosition: function()
26894 latitude: this.gMapContext.location.lat(),
26895 longitude: this.gMapContext.location.lng()
26899 getAddressName: function()
26901 return this.gMapContext.locationName;
26904 getAddressComponents: function()
26906 return this.gMapContext.addressComponents;
26909 address_component_from_google_geocode: function(address_components)
26913 for (var i = 0; i < address_components.length; i++) {
26914 var component = address_components[i];
26915 if (component.types.indexOf("postal_code") >= 0) {
26916 result.postalCode = component.short_name;
26917 } else if (component.types.indexOf("street_number") >= 0) {
26918 result.streetNumber = component.short_name;
26919 } else if (component.types.indexOf("route") >= 0) {
26920 result.streetName = component.short_name;
26921 } else if (component.types.indexOf("neighborhood") >= 0) {
26922 result.city = component.short_name;
26923 } else if (component.types.indexOf("locality") >= 0) {
26924 result.city = component.short_name;
26925 } else if (component.types.indexOf("sublocality") >= 0) {
26926 result.district = component.short_name;
26927 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
26928 result.stateOrProvince = component.short_name;
26929 } else if (component.types.indexOf("country") >= 0) {
26930 result.country = component.short_name;
26934 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
26935 result.addressLine2 = "";
26939 setZoomLevel: function(zoom)
26941 this.gMapContext.map.setZoom(zoom);
26954 this.fireEvent('show', this);
26965 this.fireEvent('hide', this);
26970 Roo.apply(Roo.bootstrap.LocationPicker, {
26972 OverlayView : function(map, options)
26974 options = options || {};
26988 * @class Roo.bootstrap.Alert
26989 * @extends Roo.bootstrap.Component
26990 * Bootstrap Alert class
26991 * @cfg {String} title The title of alert
26992 * @cfg {String} html The content of alert
26993 * @cfg {String} weight ( success | info | warning | danger )
26994 * @cfg {String} faicon font-awesomeicon
26997 * Create a new alert
26998 * @param {Object} config The config object
27002 Roo.bootstrap.Alert = function(config){
27003 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
27007 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
27014 getAutoCreate : function()
27023 cls : 'roo-alert-icon'
27028 cls : 'roo-alert-title',
27033 cls : 'roo-alert-text',
27040 cfg.cn[0].cls += ' fa ' + this.faicon;
27044 cfg.cls += ' alert-' + this.weight;
27050 initEvents: function()
27052 this.el.setVisibilityMode(Roo.Element.DISPLAY);
27055 setTitle : function(str)
27057 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
27060 setText : function(str)
27062 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
27065 setWeight : function(weight)
27068 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
27071 this.weight = weight;
27073 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
27076 setIcon : function(icon)
27079 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
27082 this.faicon = icon;
27084 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
27105 * @class Roo.bootstrap.UploadCropbox
27106 * @extends Roo.bootstrap.Component
27107 * Bootstrap UploadCropbox class
27108 * @cfg {String} emptyText show when image has been loaded
27109 * @cfg {String} rotateNotify show when image too small to rotate
27110 * @cfg {Number} errorTimeout default 3000
27111 * @cfg {Number} minWidth default 300
27112 * @cfg {Number} minHeight default 300
27113 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
27114 * @cfg {Boolean} isDocument (true|false) default false
27115 * @cfg {String} url action url
27116 * @cfg {String} paramName default 'imageUpload'
27117 * @cfg {String} method default POST
27118 * @cfg {Boolean} loadMask (true|false) default true
27119 * @cfg {Boolean} loadingText default 'Loading...'
27122 * Create a new UploadCropbox
27123 * @param {Object} config The config object
27126 Roo.bootstrap.UploadCropbox = function(config){
27127 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
27131 * @event beforeselectfile
27132 * Fire before select file
27133 * @param {Roo.bootstrap.UploadCropbox} this
27135 "beforeselectfile" : true,
27138 * Fire after initEvent
27139 * @param {Roo.bootstrap.UploadCropbox} this
27144 * Fire after initEvent
27145 * @param {Roo.bootstrap.UploadCropbox} this
27146 * @param {String} data
27151 * Fire when preparing the file data
27152 * @param {Roo.bootstrap.UploadCropbox} this
27153 * @param {Object} file
27158 * Fire when get exception
27159 * @param {Roo.bootstrap.UploadCropbox} this
27160 * @param {XMLHttpRequest} xhr
27162 "exception" : true,
27164 * @event beforeloadcanvas
27165 * Fire before load the canvas
27166 * @param {Roo.bootstrap.UploadCropbox} this
27167 * @param {String} src
27169 "beforeloadcanvas" : true,
27172 * Fire when trash image
27173 * @param {Roo.bootstrap.UploadCropbox} this
27178 * Fire when download the image
27179 * @param {Roo.bootstrap.UploadCropbox} this
27183 * @event footerbuttonclick
27184 * Fire when footerbuttonclick
27185 * @param {Roo.bootstrap.UploadCropbox} this
27186 * @param {String} type
27188 "footerbuttonclick" : true,
27192 * @param {Roo.bootstrap.UploadCropbox} this
27197 * Fire when rotate the image
27198 * @param {Roo.bootstrap.UploadCropbox} this
27199 * @param {String} pos
27204 * Fire when inspect the file
27205 * @param {Roo.bootstrap.UploadCropbox} this
27206 * @param {Object} file
27211 * Fire when xhr upload the file
27212 * @param {Roo.bootstrap.UploadCropbox} this
27213 * @param {Object} data
27218 * Fire when arrange the file data
27219 * @param {Roo.bootstrap.UploadCropbox} this
27220 * @param {Object} formData
27225 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
27228 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
27230 emptyText : 'Click to upload image',
27231 rotateNotify : 'Image is too small to rotate',
27232 errorTimeout : 3000,
27246 cropType : 'image/jpeg',
27248 canvasLoaded : false,
27249 isDocument : false,
27251 paramName : 'imageUpload',
27253 loadingText : 'Loading...',
27256 getAutoCreate : function()
27260 cls : 'roo-upload-cropbox',
27264 cls : 'roo-upload-cropbox-selector',
27269 cls : 'roo-upload-cropbox-body',
27270 style : 'cursor:pointer',
27274 cls : 'roo-upload-cropbox-preview'
27278 cls : 'roo-upload-cropbox-thumb'
27282 cls : 'roo-upload-cropbox-empty-notify',
27283 html : this.emptyText
27287 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
27288 html : this.rotateNotify
27294 cls : 'roo-upload-cropbox-footer',
27297 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
27307 onRender : function(ct, position)
27309 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
27311 if (this.buttons.length) {
27313 Roo.each(this.buttons, function(bb) {
27315 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
27317 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
27323 this.maskEl = this.el;
27327 initEvents : function()
27329 this.urlAPI = (window.createObjectURL && window) ||
27330 (window.URL && URL.revokeObjectURL && URL) ||
27331 (window.webkitURL && webkitURL);
27333 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
27334 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27336 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
27337 this.selectorEl.hide();
27339 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
27340 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27342 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
27343 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27344 this.thumbEl.hide();
27346 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
27347 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27349 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
27350 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27351 this.errorEl.hide();
27353 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
27354 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27355 this.footerEl.hide();
27357 this.setThumbBoxSize();
27363 this.fireEvent('initial', this);
27370 window.addEventListener("resize", function() { _this.resize(); } );
27372 this.bodyEl.on('click', this.beforeSelectFile, this);
27375 this.bodyEl.on('touchstart', this.onTouchStart, this);
27376 this.bodyEl.on('touchmove', this.onTouchMove, this);
27377 this.bodyEl.on('touchend', this.onTouchEnd, this);
27381 this.bodyEl.on('mousedown', this.onMouseDown, this);
27382 this.bodyEl.on('mousemove', this.onMouseMove, this);
27383 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
27384 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
27385 Roo.get(document).on('mouseup', this.onMouseUp, this);
27388 this.selectorEl.on('change', this.onFileSelected, this);
27394 this.baseScale = 1;
27396 this.baseRotate = 1;
27397 this.dragable = false;
27398 this.pinching = false;
27401 this.cropData = false;
27402 this.notifyEl.dom.innerHTML = this.emptyText;
27404 this.selectorEl.dom.value = '';
27408 resize : function()
27410 if(this.fireEvent('resize', this) != false){
27411 this.setThumbBoxPosition();
27412 this.setCanvasPosition();
27416 onFooterButtonClick : function(e, el, o, type)
27419 case 'rotate-left' :
27420 this.onRotateLeft(e);
27422 case 'rotate-right' :
27423 this.onRotateRight(e);
27426 this.beforeSelectFile(e);
27441 this.fireEvent('footerbuttonclick', this, type);
27444 beforeSelectFile : function(e)
27446 e.preventDefault();
27448 if(this.fireEvent('beforeselectfile', this) != false){
27449 this.selectorEl.dom.click();
27453 onFileSelected : function(e)
27455 e.preventDefault();
27457 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
27461 var file = this.selectorEl.dom.files[0];
27463 if(this.fireEvent('inspect', this, file) != false){
27464 this.prepare(file);
27469 trash : function(e)
27471 this.fireEvent('trash', this);
27474 download : function(e)
27476 this.fireEvent('download', this);
27479 loadCanvas : function(src)
27481 if(this.fireEvent('beforeloadcanvas', this, src) != false){
27485 this.imageEl = document.createElement('img');
27489 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
27491 this.imageEl.src = src;
27495 onLoadCanvas : function()
27497 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
27498 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
27500 this.bodyEl.un('click', this.beforeSelectFile, this);
27502 this.notifyEl.hide();
27503 this.thumbEl.show();
27504 this.footerEl.show();
27506 this.baseRotateLevel();
27508 if(this.isDocument){
27509 this.setThumbBoxSize();
27512 this.setThumbBoxPosition();
27514 this.baseScaleLevel();
27520 this.canvasLoaded = true;
27523 this.maskEl.unmask();
27528 setCanvasPosition : function()
27530 if(!this.canvasEl){
27534 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
27535 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
27537 this.previewEl.setLeft(pw);
27538 this.previewEl.setTop(ph);
27542 onMouseDown : function(e)
27546 this.dragable = true;
27547 this.pinching = false;
27549 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
27550 this.dragable = false;
27554 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27555 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27559 onMouseMove : function(e)
27563 if(!this.canvasLoaded){
27567 if (!this.dragable){
27571 var minX = Math.ceil(this.thumbEl.getLeft(true));
27572 var minY = Math.ceil(this.thumbEl.getTop(true));
27574 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
27575 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
27577 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27578 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27580 x = x - this.mouseX;
27581 y = y - this.mouseY;
27583 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
27584 var bgY = Math.ceil(y + this.previewEl.getTop(true));
27586 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
27587 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
27589 this.previewEl.setLeft(bgX);
27590 this.previewEl.setTop(bgY);
27592 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27593 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27596 onMouseUp : function(e)
27600 this.dragable = false;
27603 onMouseWheel : function(e)
27607 this.startScale = this.scale;
27609 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
27611 if(!this.zoomable()){
27612 this.scale = this.startScale;
27621 zoomable : function()
27623 var minScale = this.thumbEl.getWidth() / this.minWidth;
27625 if(this.minWidth < this.minHeight){
27626 minScale = this.thumbEl.getHeight() / this.minHeight;
27629 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
27630 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
27634 (this.rotate == 0 || this.rotate == 180) &&
27636 width > this.imageEl.OriginWidth ||
27637 height > this.imageEl.OriginHeight ||
27638 (width < this.minWidth && height < this.minHeight)
27646 (this.rotate == 90 || this.rotate == 270) &&
27648 width > this.imageEl.OriginWidth ||
27649 height > this.imageEl.OriginHeight ||
27650 (width < this.minHeight && height < this.minWidth)
27657 !this.isDocument &&
27658 (this.rotate == 0 || this.rotate == 180) &&
27660 width < this.minWidth ||
27661 width > this.imageEl.OriginWidth ||
27662 height < this.minHeight ||
27663 height > this.imageEl.OriginHeight
27670 !this.isDocument &&
27671 (this.rotate == 90 || this.rotate == 270) &&
27673 width < this.minHeight ||
27674 width > this.imageEl.OriginWidth ||
27675 height < this.minWidth ||
27676 height > this.imageEl.OriginHeight
27686 onRotateLeft : function(e)
27688 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27690 var minScale = this.thumbEl.getWidth() / this.minWidth;
27692 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27693 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27695 this.startScale = this.scale;
27697 while (this.getScaleLevel() < minScale){
27699 this.scale = this.scale + 1;
27701 if(!this.zoomable()){
27706 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27707 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27712 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27719 this.scale = this.startScale;
27721 this.onRotateFail();
27726 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27728 if(this.isDocument){
27729 this.setThumbBoxSize();
27730 this.setThumbBoxPosition();
27731 this.setCanvasPosition();
27736 this.fireEvent('rotate', this, 'left');
27740 onRotateRight : function(e)
27742 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27744 var minScale = this.thumbEl.getWidth() / this.minWidth;
27746 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27747 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27749 this.startScale = this.scale;
27751 while (this.getScaleLevel() < minScale){
27753 this.scale = this.scale + 1;
27755 if(!this.zoomable()){
27760 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27761 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27766 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27773 this.scale = this.startScale;
27775 this.onRotateFail();
27780 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27782 if(this.isDocument){
27783 this.setThumbBoxSize();
27784 this.setThumbBoxPosition();
27785 this.setCanvasPosition();
27790 this.fireEvent('rotate', this, 'right');
27793 onRotateFail : function()
27795 this.errorEl.show(true);
27799 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
27804 this.previewEl.dom.innerHTML = '';
27806 var canvasEl = document.createElement("canvas");
27808 var contextEl = canvasEl.getContext("2d");
27810 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27811 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27812 var center = this.imageEl.OriginWidth / 2;
27814 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
27815 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27816 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27817 center = this.imageEl.OriginHeight / 2;
27820 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
27822 contextEl.translate(center, center);
27823 contextEl.rotate(this.rotate * Math.PI / 180);
27825 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27827 this.canvasEl = document.createElement("canvas");
27829 this.contextEl = this.canvasEl.getContext("2d");
27831 switch (this.rotate) {
27834 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27835 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27837 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27842 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27843 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27845 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27846 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);
27850 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27855 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27856 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27858 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27859 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);
27863 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);
27868 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27869 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27871 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27872 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27876 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);
27883 this.previewEl.appendChild(this.canvasEl);
27885 this.setCanvasPosition();
27890 if(!this.canvasLoaded){
27894 var imageCanvas = document.createElement("canvas");
27896 var imageContext = imageCanvas.getContext("2d");
27898 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27899 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27901 var center = imageCanvas.width / 2;
27903 imageContext.translate(center, center);
27905 imageContext.rotate(this.rotate * Math.PI / 180);
27907 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27909 var canvas = document.createElement("canvas");
27911 var context = canvas.getContext("2d");
27913 canvas.width = this.minWidth;
27914 canvas.height = this.minHeight;
27916 switch (this.rotate) {
27919 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27920 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27922 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27923 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27925 var targetWidth = this.minWidth - 2 * x;
27926 var targetHeight = this.minHeight - 2 * y;
27930 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27931 scale = targetWidth / width;
27934 if(x > 0 && y == 0){
27935 scale = targetHeight / height;
27938 if(x > 0 && y > 0){
27939 scale = targetWidth / width;
27941 if(width < height){
27942 scale = targetHeight / height;
27946 context.scale(scale, scale);
27948 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27949 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27951 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27952 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27954 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27959 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27960 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27962 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27963 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27965 var targetWidth = this.minWidth - 2 * x;
27966 var targetHeight = this.minHeight - 2 * y;
27970 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27971 scale = targetWidth / width;
27974 if(x > 0 && y == 0){
27975 scale = targetHeight / height;
27978 if(x > 0 && y > 0){
27979 scale = targetWidth / width;
27981 if(width < height){
27982 scale = targetHeight / height;
27986 context.scale(scale, scale);
27988 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27989 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27991 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27992 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27994 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
27996 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28001 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
28002 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
28004 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28005 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28007 var targetWidth = this.minWidth - 2 * x;
28008 var targetHeight = this.minHeight - 2 * y;
28012 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28013 scale = targetWidth / width;
28016 if(x > 0 && y == 0){
28017 scale = targetHeight / height;
28020 if(x > 0 && y > 0){
28021 scale = targetWidth / width;
28023 if(width < height){
28024 scale = targetHeight / height;
28028 context.scale(scale, scale);
28030 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28031 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28033 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28034 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28036 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
28037 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
28039 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28044 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
28045 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
28047 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28048 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28050 var targetWidth = this.minWidth - 2 * x;
28051 var targetHeight = this.minHeight - 2 * y;
28055 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28056 scale = targetWidth / width;
28059 if(x > 0 && y == 0){
28060 scale = targetHeight / height;
28063 if(x > 0 && y > 0){
28064 scale = targetWidth / width;
28066 if(width < height){
28067 scale = targetHeight / height;
28071 context.scale(scale, scale);
28073 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28074 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28076 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28077 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28079 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
28081 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28088 this.cropData = canvas.toDataURL(this.cropType);
28090 if(this.fireEvent('crop', this, this.cropData) !== false){
28091 this.process(this.file, this.cropData);
28098 setThumbBoxSize : function()
28102 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
28103 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
28104 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
28106 this.minWidth = width;
28107 this.minHeight = height;
28109 if(this.rotate == 90 || this.rotate == 270){
28110 this.minWidth = height;
28111 this.minHeight = width;
28116 width = Math.ceil(this.minWidth * height / this.minHeight);
28118 if(this.minWidth > this.minHeight){
28120 height = Math.ceil(this.minHeight * width / this.minWidth);
28123 this.thumbEl.setStyle({
28124 width : width + 'px',
28125 height : height + 'px'
28132 setThumbBoxPosition : function()
28134 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
28135 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
28137 this.thumbEl.setLeft(x);
28138 this.thumbEl.setTop(y);
28142 baseRotateLevel : function()
28144 this.baseRotate = 1;
28147 typeof(this.exif) != 'undefined' &&
28148 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
28149 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
28151 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
28154 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
28158 baseScaleLevel : function()
28162 if(this.isDocument){
28164 if(this.baseRotate == 6 || this.baseRotate == 8){
28166 height = this.thumbEl.getHeight();
28167 this.baseScale = height / this.imageEl.OriginWidth;
28169 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
28170 width = this.thumbEl.getWidth();
28171 this.baseScale = width / this.imageEl.OriginHeight;
28177 height = this.thumbEl.getHeight();
28178 this.baseScale = height / this.imageEl.OriginHeight;
28180 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
28181 width = this.thumbEl.getWidth();
28182 this.baseScale = width / this.imageEl.OriginWidth;
28188 if(this.baseRotate == 6 || this.baseRotate == 8){
28190 width = this.thumbEl.getHeight();
28191 this.baseScale = width / this.imageEl.OriginHeight;
28193 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
28194 height = this.thumbEl.getWidth();
28195 this.baseScale = height / this.imageEl.OriginHeight;
28198 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28199 height = this.thumbEl.getWidth();
28200 this.baseScale = height / this.imageEl.OriginHeight;
28202 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
28203 width = this.thumbEl.getHeight();
28204 this.baseScale = width / this.imageEl.OriginWidth;
28211 width = this.thumbEl.getWidth();
28212 this.baseScale = width / this.imageEl.OriginWidth;
28214 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
28215 height = this.thumbEl.getHeight();
28216 this.baseScale = height / this.imageEl.OriginHeight;
28219 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28221 height = this.thumbEl.getHeight();
28222 this.baseScale = height / this.imageEl.OriginHeight;
28224 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
28225 width = this.thumbEl.getWidth();
28226 this.baseScale = width / this.imageEl.OriginWidth;
28234 getScaleLevel : function()
28236 return this.baseScale * Math.pow(1.1, this.scale);
28239 onTouchStart : function(e)
28241 if(!this.canvasLoaded){
28242 this.beforeSelectFile(e);
28246 var touches = e.browserEvent.touches;
28252 if(touches.length == 1){
28253 this.onMouseDown(e);
28257 if(touches.length != 2){
28263 for(var i = 0, finger; finger = touches[i]; i++){
28264 coords.push(finger.pageX, finger.pageY);
28267 var x = Math.pow(coords[0] - coords[2], 2);
28268 var y = Math.pow(coords[1] - coords[3], 2);
28270 this.startDistance = Math.sqrt(x + y);
28272 this.startScale = this.scale;
28274 this.pinching = true;
28275 this.dragable = false;
28279 onTouchMove : function(e)
28281 if(!this.pinching && !this.dragable){
28285 var touches = e.browserEvent.touches;
28292 this.onMouseMove(e);
28298 for(var i = 0, finger; finger = touches[i]; i++){
28299 coords.push(finger.pageX, finger.pageY);
28302 var x = Math.pow(coords[0] - coords[2], 2);
28303 var y = Math.pow(coords[1] - coords[3], 2);
28305 this.endDistance = Math.sqrt(x + y);
28307 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
28309 if(!this.zoomable()){
28310 this.scale = this.startScale;
28318 onTouchEnd : function(e)
28320 this.pinching = false;
28321 this.dragable = false;
28325 process : function(file, crop)
28328 this.maskEl.mask(this.loadingText);
28331 this.xhr = new XMLHttpRequest();
28333 file.xhr = this.xhr;
28335 this.xhr.open(this.method, this.url, true);
28338 "Accept": "application/json",
28339 "Cache-Control": "no-cache",
28340 "X-Requested-With": "XMLHttpRequest"
28343 for (var headerName in headers) {
28344 var headerValue = headers[headerName];
28346 this.xhr.setRequestHeader(headerName, headerValue);
28352 this.xhr.onload = function()
28354 _this.xhrOnLoad(_this.xhr);
28357 this.xhr.onerror = function()
28359 _this.xhrOnError(_this.xhr);
28362 var formData = new FormData();
28364 formData.append('returnHTML', 'NO');
28367 formData.append('crop', crop);
28370 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
28371 formData.append(this.paramName, file, file.name);
28374 if(typeof(file.filename) != 'undefined'){
28375 formData.append('filename', file.filename);
28378 if(typeof(file.mimetype) != 'undefined'){
28379 formData.append('mimetype', file.mimetype);
28382 if(this.fireEvent('arrange', this, formData) != false){
28383 this.xhr.send(formData);
28387 xhrOnLoad : function(xhr)
28390 this.maskEl.unmask();
28393 if (xhr.readyState !== 4) {
28394 this.fireEvent('exception', this, xhr);
28398 var response = Roo.decode(xhr.responseText);
28400 if(!response.success){
28401 this.fireEvent('exception', this, xhr);
28405 var response = Roo.decode(xhr.responseText);
28407 this.fireEvent('upload', this, response);
28411 xhrOnError : function()
28414 this.maskEl.unmask();
28417 Roo.log('xhr on error');
28419 var response = Roo.decode(xhr.responseText);
28425 prepare : function(file)
28428 this.maskEl.mask(this.loadingText);
28434 if(typeof(file) === 'string'){
28435 this.loadCanvas(file);
28439 if(!file || !this.urlAPI){
28444 this.cropType = file.type;
28448 if(this.fireEvent('prepare', this, this.file) != false){
28450 var reader = new FileReader();
28452 reader.onload = function (e) {
28453 if (e.target.error) {
28454 Roo.log(e.target.error);
28458 var buffer = e.target.result,
28459 dataView = new DataView(buffer),
28461 maxOffset = dataView.byteLength - 4,
28465 if (dataView.getUint16(0) === 0xffd8) {
28466 while (offset < maxOffset) {
28467 markerBytes = dataView.getUint16(offset);
28469 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
28470 markerLength = dataView.getUint16(offset + 2) + 2;
28471 if (offset + markerLength > dataView.byteLength) {
28472 Roo.log('Invalid meta data: Invalid segment size.');
28476 if(markerBytes == 0xffe1){
28477 _this.parseExifData(
28484 offset += markerLength;
28494 var url = _this.urlAPI.createObjectURL(_this.file);
28496 _this.loadCanvas(url);
28501 reader.readAsArrayBuffer(this.file);
28507 parseExifData : function(dataView, offset, length)
28509 var tiffOffset = offset + 10,
28513 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28514 // No Exif data, might be XMP data instead
28518 // Check for the ASCII code for "Exif" (0x45786966):
28519 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28520 // No Exif data, might be XMP data instead
28523 if (tiffOffset + 8 > dataView.byteLength) {
28524 Roo.log('Invalid Exif data: Invalid segment size.');
28527 // Check for the two null bytes:
28528 if (dataView.getUint16(offset + 8) !== 0x0000) {
28529 Roo.log('Invalid Exif data: Missing byte alignment offset.');
28532 // Check the byte alignment:
28533 switch (dataView.getUint16(tiffOffset)) {
28535 littleEndian = true;
28538 littleEndian = false;
28541 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
28544 // Check for the TIFF tag marker (0x002A):
28545 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
28546 Roo.log('Invalid Exif data: Missing TIFF marker.');
28549 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
28550 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
28552 this.parseExifTags(
28555 tiffOffset + dirOffset,
28560 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
28565 if (dirOffset + 6 > dataView.byteLength) {
28566 Roo.log('Invalid Exif data: Invalid directory offset.');
28569 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
28570 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
28571 if (dirEndOffset + 4 > dataView.byteLength) {
28572 Roo.log('Invalid Exif data: Invalid directory size.');
28575 for (i = 0; i < tagsNumber; i += 1) {
28579 dirOffset + 2 + 12 * i, // tag offset
28583 // Return the offset to the next directory:
28584 return dataView.getUint32(dirEndOffset, littleEndian);
28587 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
28589 var tag = dataView.getUint16(offset, littleEndian);
28591 this.exif[tag] = this.getExifValue(
28595 dataView.getUint16(offset + 2, littleEndian), // tag type
28596 dataView.getUint32(offset + 4, littleEndian), // tag length
28601 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
28603 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
28612 Roo.log('Invalid Exif data: Invalid tag type.');
28616 tagSize = tagType.size * length;
28617 // Determine if the value is contained in the dataOffset bytes,
28618 // or if the value at the dataOffset is a pointer to the actual data:
28619 dataOffset = tagSize > 4 ?
28620 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
28621 if (dataOffset + tagSize > dataView.byteLength) {
28622 Roo.log('Invalid Exif data: Invalid data offset.');
28625 if (length === 1) {
28626 return tagType.getValue(dataView, dataOffset, littleEndian);
28629 for (i = 0; i < length; i += 1) {
28630 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
28633 if (tagType.ascii) {
28635 // Concatenate the chars:
28636 for (i = 0; i < values.length; i += 1) {
28638 // Ignore the terminating NULL byte(s):
28639 if (c === '\u0000') {
28651 Roo.apply(Roo.bootstrap.UploadCropbox, {
28653 'Orientation': 0x0112
28657 1: 0, //'top-left',
28659 3: 180, //'bottom-right',
28660 // 4: 'bottom-left',
28662 6: 90, //'right-top',
28663 // 7: 'right-bottom',
28664 8: 270 //'left-bottom'
28668 // byte, 8-bit unsigned int:
28670 getValue: function (dataView, dataOffset) {
28671 return dataView.getUint8(dataOffset);
28675 // ascii, 8-bit byte:
28677 getValue: function (dataView, dataOffset) {
28678 return String.fromCharCode(dataView.getUint8(dataOffset));
28683 // short, 16 bit int:
28685 getValue: function (dataView, dataOffset, littleEndian) {
28686 return dataView.getUint16(dataOffset, littleEndian);
28690 // long, 32 bit int:
28692 getValue: function (dataView, dataOffset, littleEndian) {
28693 return dataView.getUint32(dataOffset, littleEndian);
28697 // rational = two long values, first is numerator, second is denominator:
28699 getValue: function (dataView, dataOffset, littleEndian) {
28700 return dataView.getUint32(dataOffset, littleEndian) /
28701 dataView.getUint32(dataOffset + 4, littleEndian);
28705 // slong, 32 bit signed int:
28707 getValue: function (dataView, dataOffset, littleEndian) {
28708 return dataView.getInt32(dataOffset, littleEndian);
28712 // srational, two slongs, first is numerator, second is denominator:
28714 getValue: function (dataView, dataOffset, littleEndian) {
28715 return dataView.getInt32(dataOffset, littleEndian) /
28716 dataView.getInt32(dataOffset + 4, littleEndian);
28726 cls : 'btn-group roo-upload-cropbox-rotate-left',
28727 action : 'rotate-left',
28731 cls : 'btn btn-default',
28732 html : '<i class="fa fa-undo"></i>'
28738 cls : 'btn-group roo-upload-cropbox-picture',
28739 action : 'picture',
28743 cls : 'btn btn-default',
28744 html : '<i class="fa fa-picture-o"></i>'
28750 cls : 'btn-group roo-upload-cropbox-rotate-right',
28751 action : 'rotate-right',
28755 cls : 'btn btn-default',
28756 html : '<i class="fa fa-repeat"></i>'
28764 cls : 'btn-group roo-upload-cropbox-rotate-left',
28765 action : 'rotate-left',
28769 cls : 'btn btn-default',
28770 html : '<i class="fa fa-undo"></i>'
28776 cls : 'btn-group roo-upload-cropbox-download',
28777 action : 'download',
28781 cls : 'btn btn-default',
28782 html : '<i class="fa fa-download"></i>'
28788 cls : 'btn-group roo-upload-cropbox-crop',
28793 cls : 'btn btn-default',
28794 html : '<i class="fa fa-crop"></i>'
28800 cls : 'btn-group roo-upload-cropbox-trash',
28805 cls : 'btn btn-default',
28806 html : '<i class="fa fa-trash"></i>'
28812 cls : 'btn-group roo-upload-cropbox-rotate-right',
28813 action : 'rotate-right',
28817 cls : 'btn btn-default',
28818 html : '<i class="fa fa-repeat"></i>'
28826 cls : 'btn-group roo-upload-cropbox-rotate-left',
28827 action : 'rotate-left',
28831 cls : 'btn btn-default',
28832 html : '<i class="fa fa-undo"></i>'
28838 cls : 'btn-group roo-upload-cropbox-rotate-right',
28839 action : 'rotate-right',
28843 cls : 'btn btn-default',
28844 html : '<i class="fa fa-repeat"></i>'
28857 * @class Roo.bootstrap.DocumentManager
28858 * @extends Roo.bootstrap.Component
28859 * Bootstrap DocumentManager class
28860 * @cfg {String} paramName default 'imageUpload'
28861 * @cfg {String} toolTipName default 'filename'
28862 * @cfg {String} method default POST
28863 * @cfg {String} url action url
28864 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
28865 * @cfg {Boolean} multiple multiple upload default true
28866 * @cfg {Number} thumbSize default 300
28867 * @cfg {String} fieldLabel
28868 * @cfg {Number} labelWidth default 4
28869 * @cfg {String} labelAlign (left|top) default left
28870 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
28871 * @cfg {Number} labellg set the width of label (1-12)
28872 * @cfg {Number} labelmd set the width of label (1-12)
28873 * @cfg {Number} labelsm set the width of label (1-12)
28874 * @cfg {Number} labelxs set the width of label (1-12)
28877 * Create a new DocumentManager
28878 * @param {Object} config The config object
28881 Roo.bootstrap.DocumentManager = function(config){
28882 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
28885 this.delegates = [];
28890 * Fire when initial the DocumentManager
28891 * @param {Roo.bootstrap.DocumentManager} this
28896 * inspect selected file
28897 * @param {Roo.bootstrap.DocumentManager} this
28898 * @param {File} file
28903 * Fire when xhr load exception
28904 * @param {Roo.bootstrap.DocumentManager} this
28905 * @param {XMLHttpRequest} xhr
28907 "exception" : true,
28909 * @event afterupload
28910 * Fire when xhr load exception
28911 * @param {Roo.bootstrap.DocumentManager} this
28912 * @param {XMLHttpRequest} xhr
28914 "afterupload" : true,
28917 * prepare the form data
28918 * @param {Roo.bootstrap.DocumentManager} this
28919 * @param {Object} formData
28924 * Fire when remove the file
28925 * @param {Roo.bootstrap.DocumentManager} this
28926 * @param {Object} file
28931 * Fire after refresh the file
28932 * @param {Roo.bootstrap.DocumentManager} this
28937 * Fire after click the image
28938 * @param {Roo.bootstrap.DocumentManager} this
28939 * @param {Object} file
28944 * Fire when upload a image and editable set to true
28945 * @param {Roo.bootstrap.DocumentManager} this
28946 * @param {Object} file
28950 * @event beforeselectfile
28951 * Fire before select file
28952 * @param {Roo.bootstrap.DocumentManager} this
28954 "beforeselectfile" : true,
28957 * Fire before process file
28958 * @param {Roo.bootstrap.DocumentManager} this
28959 * @param {Object} file
28963 * @event previewrendered
28964 * Fire when preview rendered
28965 * @param {Roo.bootstrap.DocumentManager} this
28966 * @param {Object} file
28968 "previewrendered" : true,
28971 "previewResize" : true
28976 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
28985 paramName : 'imageUpload',
28986 toolTipName : 'filename',
28989 labelAlign : 'left',
28999 getAutoCreate : function()
29001 var managerWidget = {
29003 cls : 'roo-document-manager',
29007 cls : 'roo-document-manager-selector',
29012 cls : 'roo-document-manager-uploader',
29016 cls : 'roo-document-manager-upload-btn',
29017 html : '<i class="fa fa-plus"></i>'
29028 cls : 'column col-md-12',
29033 if(this.fieldLabel.length){
29038 cls : 'column col-md-12',
29039 html : this.fieldLabel
29043 cls : 'column col-md-12',
29048 if(this.labelAlign == 'left'){
29053 html : this.fieldLabel
29062 if(this.labelWidth > 12){
29063 content[0].style = "width: " + this.labelWidth + 'px';
29066 if(this.labelWidth < 13 && this.labelmd == 0){
29067 this.labelmd = this.labelWidth;
29070 if(this.labellg > 0){
29071 content[0].cls += ' col-lg-' + this.labellg;
29072 content[1].cls += ' col-lg-' + (12 - this.labellg);
29075 if(this.labelmd > 0){
29076 content[0].cls += ' col-md-' + this.labelmd;
29077 content[1].cls += ' col-md-' + (12 - this.labelmd);
29080 if(this.labelsm > 0){
29081 content[0].cls += ' col-sm-' + this.labelsm;
29082 content[1].cls += ' col-sm-' + (12 - this.labelsm);
29085 if(this.labelxs > 0){
29086 content[0].cls += ' col-xs-' + this.labelxs;
29087 content[1].cls += ' col-xs-' + (12 - this.labelxs);
29095 cls : 'row clearfix',
29103 initEvents : function()
29105 this.managerEl = this.el.select('.roo-document-manager', true).first();
29106 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29108 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
29109 this.selectorEl.hide();
29112 this.selectorEl.attr('multiple', 'multiple');
29115 this.selectorEl.on('change', this.onFileSelected, this);
29117 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
29118 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29120 this.uploader.on('click', this.onUploaderClick, this);
29122 this.renderProgressDialog();
29126 window.addEventListener("resize", function() { _this.refresh(); } );
29128 this.fireEvent('initial', this);
29131 renderProgressDialog : function()
29135 this.progressDialog = new Roo.bootstrap.Modal({
29136 cls : 'roo-document-manager-progress-dialog',
29137 allow_close : false,
29147 btnclick : function() {
29148 _this.uploadCancel();
29154 this.progressDialog.render(Roo.get(document.body));
29156 this.progress = new Roo.bootstrap.Progress({
29157 cls : 'roo-document-manager-progress',
29162 this.progress.render(this.progressDialog.getChildContainer());
29164 this.progressBar = new Roo.bootstrap.ProgressBar({
29165 cls : 'roo-document-manager-progress-bar',
29168 aria_valuemax : 12,
29172 this.progressBar.render(this.progress.getChildContainer());
29175 onUploaderClick : function(e)
29177 e.preventDefault();
29179 if(this.fireEvent('beforeselectfile', this) != false){
29180 this.selectorEl.dom.click();
29185 onFileSelected : function(e)
29187 e.preventDefault();
29189 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
29193 Roo.each(this.selectorEl.dom.files, function(file){
29194 if(this.fireEvent('inspect', this, file) != false){
29195 this.files.push(file);
29205 this.selectorEl.dom.value = '';
29207 if(!this.files || !this.files.length){
29211 if(this.boxes > 0 && this.files.length > this.boxes){
29212 this.files = this.files.slice(0, this.boxes);
29215 this.uploader.show();
29217 if(this.boxes > 0 && this.files.length > this.boxes - 1){
29218 this.uploader.hide();
29227 Roo.each(this.files, function(file){
29229 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29230 var f = this.renderPreview(file);
29235 if(file.type.indexOf('image') != -1){
29236 this.delegates.push(
29238 _this.process(file);
29239 }).createDelegate(this)
29247 _this.process(file);
29248 }).createDelegate(this)
29253 this.files = files;
29255 this.delegates = this.delegates.concat(docs);
29257 if(!this.delegates.length){
29262 this.progressBar.aria_valuemax = this.delegates.length;
29269 arrange : function()
29271 if(!this.delegates.length){
29272 this.progressDialog.hide();
29277 var delegate = this.delegates.shift();
29279 this.progressDialog.show();
29281 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
29283 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
29288 refresh : function()
29290 this.uploader.show();
29292 if(this.boxes > 0 && this.files.length > this.boxes - 1){
29293 this.uploader.hide();
29296 Roo.isTouch ? this.closable(false) : this.closable(true);
29298 this.fireEvent('refresh', this);
29301 onRemove : function(e, el, o)
29303 e.preventDefault();
29305 this.fireEvent('remove', this, o);
29309 remove : function(o)
29313 Roo.each(this.files, function(file){
29314 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
29323 this.files = files;
29330 Roo.each(this.files, function(file){
29335 file.target.remove();
29344 onClick : function(e, el, o)
29346 e.preventDefault();
29348 this.fireEvent('click', this, o);
29352 closable : function(closable)
29354 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
29356 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29368 xhrOnLoad : function(xhr)
29370 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29374 if (xhr.readyState !== 4) {
29376 this.fireEvent('exception', this, xhr);
29380 var response = Roo.decode(xhr.responseText);
29382 if(!response.success){
29384 this.fireEvent('exception', this, xhr);
29388 var file = this.renderPreview(response.data);
29390 this.files.push(file);
29394 this.fireEvent('afterupload', this, xhr);
29398 xhrOnError : function(xhr)
29400 Roo.log('xhr on error');
29402 var response = Roo.decode(xhr.responseText);
29409 process : function(file)
29411 if(this.fireEvent('process', this, file) !== false){
29412 if(this.editable && file.type.indexOf('image') != -1){
29413 this.fireEvent('edit', this, file);
29417 this.uploadStart(file, false);
29424 uploadStart : function(file, crop)
29426 this.xhr = new XMLHttpRequest();
29428 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29433 file.xhr = this.xhr;
29435 this.managerEl.createChild({
29437 cls : 'roo-document-manager-loading',
29441 tooltip : file.name,
29442 cls : 'roo-document-manager-thumb',
29443 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29449 this.xhr.open(this.method, this.url, true);
29452 "Accept": "application/json",
29453 "Cache-Control": "no-cache",
29454 "X-Requested-With": "XMLHttpRequest"
29457 for (var headerName in headers) {
29458 var headerValue = headers[headerName];
29460 this.xhr.setRequestHeader(headerName, headerValue);
29466 this.xhr.onload = function()
29468 _this.xhrOnLoad(_this.xhr);
29471 this.xhr.onerror = function()
29473 _this.xhrOnError(_this.xhr);
29476 var formData = new FormData();
29478 formData.append('returnHTML', 'NO');
29481 formData.append('crop', crop);
29484 formData.append(this.paramName, file, file.name);
29491 if(this.fireEvent('prepare', this, formData, options) != false){
29493 if(options.manually){
29497 this.xhr.send(formData);
29501 this.uploadCancel();
29504 uploadCancel : function()
29510 this.delegates = [];
29512 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29519 renderPreview : function(file)
29521 if(typeof(file.target) != 'undefined' && file.target){
29525 var img_src = encodeURI(baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename);
29527 var previewEl = this.managerEl.createChild({
29529 cls : 'roo-document-manager-preview',
29533 tooltip : file[this.toolTipName],
29534 cls : 'roo-document-manager-thumb',
29535 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + img_src + '">'
29540 html : '<i class="fa fa-times-circle"></i>'
29545 var close = previewEl.select('button.close', true).first();
29547 close.on('click', this.onRemove, this, file);
29549 file.target = previewEl;
29551 var image = previewEl.select('img', true).first();
29555 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
29557 image.on('click', this.onClick, this, file);
29559 this.fireEvent('previewrendered', this, file);
29565 onPreviewLoad : function(file, image)
29567 if(typeof(file.target) == 'undefined' || !file.target){
29571 var width = image.dom.naturalWidth || image.dom.width;
29572 var height = image.dom.naturalHeight || image.dom.height;
29574 if(!this.previewResize) {
29578 if(width > height){
29579 file.target.addClass('wide');
29583 file.target.addClass('tall');
29588 uploadFromSource : function(file, crop)
29590 this.xhr = new XMLHttpRequest();
29592 this.managerEl.createChild({
29594 cls : 'roo-document-manager-loading',
29598 tooltip : file.name,
29599 cls : 'roo-document-manager-thumb',
29600 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29606 this.xhr.open(this.method, this.url, true);
29609 "Accept": "application/json",
29610 "Cache-Control": "no-cache",
29611 "X-Requested-With": "XMLHttpRequest"
29614 for (var headerName in headers) {
29615 var headerValue = headers[headerName];
29617 this.xhr.setRequestHeader(headerName, headerValue);
29623 this.xhr.onload = function()
29625 _this.xhrOnLoad(_this.xhr);
29628 this.xhr.onerror = function()
29630 _this.xhrOnError(_this.xhr);
29633 var formData = new FormData();
29635 formData.append('returnHTML', 'NO');
29637 formData.append('crop', crop);
29639 if(typeof(file.filename) != 'undefined'){
29640 formData.append('filename', file.filename);
29643 if(typeof(file.mimetype) != 'undefined'){
29644 formData.append('mimetype', file.mimetype);
29649 if(this.fireEvent('prepare', this, formData) != false){
29650 this.xhr.send(formData);
29660 * @class Roo.bootstrap.DocumentViewer
29661 * @extends Roo.bootstrap.Component
29662 * Bootstrap DocumentViewer class
29663 * @cfg {Boolean} showDownload (true|false) show download button (default true)
29664 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
29667 * Create a new DocumentViewer
29668 * @param {Object} config The config object
29671 Roo.bootstrap.DocumentViewer = function(config){
29672 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
29677 * Fire after initEvent
29678 * @param {Roo.bootstrap.DocumentViewer} this
29684 * @param {Roo.bootstrap.DocumentViewer} this
29689 * Fire after download button
29690 * @param {Roo.bootstrap.DocumentViewer} this
29695 * Fire after trash button
29696 * @param {Roo.bootstrap.DocumentViewer} this
29703 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
29705 showDownload : true,
29709 getAutoCreate : function()
29713 cls : 'roo-document-viewer',
29717 cls : 'roo-document-viewer-body',
29721 cls : 'roo-document-viewer-thumb',
29725 cls : 'roo-document-viewer-image'
29733 cls : 'roo-document-viewer-footer',
29736 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
29740 cls : 'btn-group roo-document-viewer-download',
29744 cls : 'btn btn-default',
29745 html : '<i class="fa fa-download"></i>'
29751 cls : 'btn-group roo-document-viewer-trash',
29755 cls : 'btn btn-default',
29756 html : '<i class="fa fa-trash"></i>'
29769 initEvents : function()
29771 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
29772 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
29774 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
29775 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
29777 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
29778 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
29780 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
29781 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
29783 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
29784 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
29786 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
29787 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
29789 this.bodyEl.on('click', this.onClick, this);
29790 this.downloadBtn.on('click', this.onDownload, this);
29791 this.trashBtn.on('click', this.onTrash, this);
29793 this.downloadBtn.hide();
29794 this.trashBtn.hide();
29796 if(this.showDownload){
29797 this.downloadBtn.show();
29800 if(this.showTrash){
29801 this.trashBtn.show();
29804 if(!this.showDownload && !this.showTrash) {
29805 this.footerEl.hide();
29810 initial : function()
29812 this.fireEvent('initial', this);
29816 onClick : function(e)
29818 e.preventDefault();
29820 this.fireEvent('click', this);
29823 onDownload : function(e)
29825 e.preventDefault();
29827 this.fireEvent('download', this);
29830 onTrash : function(e)
29832 e.preventDefault();
29834 this.fireEvent('trash', this);
29846 * @class Roo.bootstrap.NavProgressBar
29847 * @extends Roo.bootstrap.Component
29848 * Bootstrap NavProgressBar class
29851 * Create a new nav progress bar
29852 * @param {Object} config The config object
29855 Roo.bootstrap.NavProgressBar = function(config){
29856 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
29858 this.bullets = this.bullets || [];
29860 // Roo.bootstrap.NavProgressBar.register(this);
29864 * Fires when the active item changes
29865 * @param {Roo.bootstrap.NavProgressBar} this
29866 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
29867 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
29874 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
29879 getAutoCreate : function()
29881 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
29885 cls : 'roo-navigation-bar-group',
29889 cls : 'roo-navigation-top-bar'
29893 cls : 'roo-navigation-bullets-bar',
29897 cls : 'roo-navigation-bar'
29904 cls : 'roo-navigation-bottom-bar'
29914 initEvents: function()
29919 onRender : function(ct, position)
29921 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
29923 if(this.bullets.length){
29924 Roo.each(this.bullets, function(b){
29933 addItem : function(cfg)
29935 var item = new Roo.bootstrap.NavProgressItem(cfg);
29937 item.parentId = this.id;
29938 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
29941 var top = new Roo.bootstrap.Element({
29943 cls : 'roo-navigation-bar-text'
29946 var bottom = new Roo.bootstrap.Element({
29948 cls : 'roo-navigation-bar-text'
29951 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
29952 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
29954 var topText = new Roo.bootstrap.Element({
29956 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
29959 var bottomText = new Roo.bootstrap.Element({
29961 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
29964 topText.onRender(top.el, null);
29965 bottomText.onRender(bottom.el, null);
29968 item.bottomEl = bottom;
29971 this.barItems.push(item);
29976 getActive : function()
29978 var active = false;
29980 Roo.each(this.barItems, function(v){
29982 if (!v.isActive()) {
29994 setActiveItem : function(item)
29998 Roo.each(this.barItems, function(v){
29999 if (v.rid == item.rid) {
30003 if (v.isActive()) {
30004 v.setActive(false);
30009 item.setActive(true);
30011 this.fireEvent('changed', this, item, prev);
30014 getBarItem: function(rid)
30018 Roo.each(this.barItems, function(e) {
30019 if (e.rid != rid) {
30030 indexOfItem : function(item)
30034 Roo.each(this.barItems, function(v, i){
30036 if (v.rid != item.rid) {
30047 setActiveNext : function()
30049 var i = this.indexOfItem(this.getActive());
30051 if (i > this.barItems.length) {
30055 this.setActiveItem(this.barItems[i+1]);
30058 setActivePrev : function()
30060 var i = this.indexOfItem(this.getActive());
30066 this.setActiveItem(this.barItems[i-1]);
30069 format : function()
30071 if(!this.barItems.length){
30075 var width = 100 / this.barItems.length;
30077 Roo.each(this.barItems, function(i){
30078 i.el.setStyle('width', width + '%');
30079 i.topEl.el.setStyle('width', width + '%');
30080 i.bottomEl.el.setStyle('width', width + '%');
30089 * Nav Progress Item
30094 * @class Roo.bootstrap.NavProgressItem
30095 * @extends Roo.bootstrap.Component
30096 * Bootstrap NavProgressItem class
30097 * @cfg {String} rid the reference id
30098 * @cfg {Boolean} active (true|false) Is item active default false
30099 * @cfg {Boolean} disabled (true|false) Is item active default false
30100 * @cfg {String} html
30101 * @cfg {String} position (top|bottom) text position default bottom
30102 * @cfg {String} icon show icon instead of number
30105 * Create a new NavProgressItem
30106 * @param {Object} config The config object
30108 Roo.bootstrap.NavProgressItem = function(config){
30109 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
30114 * The raw click event for the entire grid.
30115 * @param {Roo.bootstrap.NavProgressItem} this
30116 * @param {Roo.EventObject} e
30123 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
30129 position : 'bottom',
30132 getAutoCreate : function()
30134 var iconCls = 'roo-navigation-bar-item-icon';
30136 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
30140 cls: 'roo-navigation-bar-item',
30150 cfg.cls += ' active';
30153 cfg.cls += ' disabled';
30159 disable : function()
30161 this.setDisabled(true);
30164 enable : function()
30166 this.setDisabled(false);
30169 initEvents: function()
30171 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
30173 this.iconEl.on('click', this.onClick, this);
30176 onClick : function(e)
30178 e.preventDefault();
30184 if(this.fireEvent('click', this, e) === false){
30188 this.parent().setActiveItem(this);
30191 isActive: function ()
30193 return this.active;
30196 setActive : function(state)
30198 if(this.active == state){
30202 this.active = state;
30205 this.el.addClass('active');
30209 this.el.removeClass('active');
30214 setDisabled : function(state)
30216 if(this.disabled == state){
30220 this.disabled = state;
30223 this.el.addClass('disabled');
30227 this.el.removeClass('disabled');
30230 tooltipEl : function()
30232 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
30245 * @class Roo.bootstrap.FieldLabel
30246 * @extends Roo.bootstrap.Component
30247 * Bootstrap FieldLabel class
30248 * @cfg {String} html contents of the element
30249 * @cfg {String} tag tag of the element default label
30250 * @cfg {String} cls class of the element
30251 * @cfg {String} target label target
30252 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
30253 * @cfg {String} invalidClass default "text-warning"
30254 * @cfg {String} validClass default "text-success"
30255 * @cfg {String} iconTooltip default "This field is required"
30256 * @cfg {String} indicatorpos (left|right) default left
30259 * Create a new FieldLabel
30260 * @param {Object} config The config object
30263 Roo.bootstrap.FieldLabel = function(config){
30264 Roo.bootstrap.Element.superclass.constructor.call(this, config);
30269 * Fires after the field has been marked as invalid.
30270 * @param {Roo.form.FieldLabel} this
30271 * @param {String} msg The validation message
30276 * Fires after the field has been validated with no errors.
30277 * @param {Roo.form.FieldLabel} this
30283 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
30290 invalidClass : 'has-warning',
30291 validClass : 'has-success',
30292 iconTooltip : 'This field is required',
30293 indicatorpos : 'left',
30295 getAutoCreate : function(){
30298 if (!this.allowBlank) {
30304 cls : 'roo-bootstrap-field-label ' + this.cls,
30309 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star ' + cls,
30310 tooltip : this.iconTooltip
30319 if(this.indicatorpos == 'right'){
30322 cls : 'roo-bootstrap-field-label ' + this.cls,
30331 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star '+ cls,
30332 tooltip : this.iconTooltip
30341 initEvents: function()
30343 Roo.bootstrap.Element.superclass.initEvents.call(this);
30345 this.indicator = this.indicatorEl();
30347 if(this.indicator){
30348 this.indicator.removeClass('visible');
30349 this.indicator.addClass('invisible');
30352 Roo.bootstrap.FieldLabel.register(this);
30355 indicatorEl : function()
30357 var indicator = this.el.select('i.roo-required-indicator',true).first();
30368 * Mark this field as valid
30370 markValid : function()
30372 if(this.indicator){
30373 this.indicator.removeClass('visible');
30374 this.indicator.addClass('invisible');
30377 this.el.removeClass(this.invalidClass);
30379 this.el.addClass(this.validClass);
30381 this.fireEvent('valid', this);
30385 * Mark this field as invalid
30386 * @param {String} msg The validation message
30388 markInvalid : function(msg)
30390 if(this.indicator){
30391 this.indicator.removeClass('invisible');
30392 this.indicator.addClass('visible');
30395 this.el.removeClass(this.validClass);
30397 this.el.addClass(this.invalidClass);
30399 this.fireEvent('invalid', this, msg);
30405 Roo.apply(Roo.bootstrap.FieldLabel, {
30410 * register a FieldLabel Group
30411 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
30413 register : function(label)
30415 if(this.groups.hasOwnProperty(label.target)){
30419 this.groups[label.target] = label;
30423 * fetch a FieldLabel Group based on the target
30424 * @param {string} target
30425 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
30427 get: function(target) {
30428 if (typeof(this.groups[target]) == 'undefined') {
30432 return this.groups[target] ;
30441 * page DateSplitField.
30447 * @class Roo.bootstrap.DateSplitField
30448 * @extends Roo.bootstrap.Component
30449 * Bootstrap DateSplitField class
30450 * @cfg {string} fieldLabel - the label associated
30451 * @cfg {Number} labelWidth set the width of label (0-12)
30452 * @cfg {String} labelAlign (top|left)
30453 * @cfg {Boolean} dayAllowBlank (true|false) default false
30454 * @cfg {Boolean} monthAllowBlank (true|false) default false
30455 * @cfg {Boolean} yearAllowBlank (true|false) default false
30456 * @cfg {string} dayPlaceholder
30457 * @cfg {string} monthPlaceholder
30458 * @cfg {string} yearPlaceholder
30459 * @cfg {string} dayFormat default 'd'
30460 * @cfg {string} monthFormat default 'm'
30461 * @cfg {string} yearFormat default 'Y'
30462 * @cfg {Number} labellg set the width of label (1-12)
30463 * @cfg {Number} labelmd set the width of label (1-12)
30464 * @cfg {Number} labelsm set the width of label (1-12)
30465 * @cfg {Number} labelxs set the width of label (1-12)
30469 * Create a new DateSplitField
30470 * @param {Object} config The config object
30473 Roo.bootstrap.DateSplitField = function(config){
30474 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
30480 * getting the data of years
30481 * @param {Roo.bootstrap.DateSplitField} this
30482 * @param {Object} years
30487 * getting the data of days
30488 * @param {Roo.bootstrap.DateSplitField} this
30489 * @param {Object} days
30494 * Fires after the field has been marked as invalid.
30495 * @param {Roo.form.Field} this
30496 * @param {String} msg The validation message
30501 * Fires after the field has been validated with no errors.
30502 * @param {Roo.form.Field} this
30508 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
30511 labelAlign : 'top',
30513 dayAllowBlank : false,
30514 monthAllowBlank : false,
30515 yearAllowBlank : false,
30516 dayPlaceholder : '',
30517 monthPlaceholder : '',
30518 yearPlaceholder : '',
30522 isFormField : true,
30528 getAutoCreate : function()
30532 cls : 'row roo-date-split-field-group',
30537 cls : 'form-hidden-field roo-date-split-field-group-value',
30543 var labelCls = 'col-md-12';
30544 var contentCls = 'col-md-4';
30546 if(this.fieldLabel){
30550 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
30554 html : this.fieldLabel
30559 if(this.labelAlign == 'left'){
30561 if(this.labelWidth > 12){
30562 label.style = "width: " + this.labelWidth + 'px';
30565 if(this.labelWidth < 13 && this.labelmd == 0){
30566 this.labelmd = this.labelWidth;
30569 if(this.labellg > 0){
30570 labelCls = ' col-lg-' + this.labellg;
30571 contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
30574 if(this.labelmd > 0){
30575 labelCls = ' col-md-' + this.labelmd;
30576 contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
30579 if(this.labelsm > 0){
30580 labelCls = ' col-sm-' + this.labelsm;
30581 contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
30584 if(this.labelxs > 0){
30585 labelCls = ' col-xs-' + this.labelxs;
30586 contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
30590 label.cls += ' ' + labelCls;
30592 cfg.cn.push(label);
30595 Roo.each(['day', 'month', 'year'], function(t){
30598 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
30605 inputEl: function ()
30607 return this.el.select('.roo-date-split-field-group-value', true).first();
30610 onRender : function(ct, position)
30614 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30616 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
30618 this.dayField = new Roo.bootstrap.ComboBox({
30619 allowBlank : this.dayAllowBlank,
30620 alwaysQuery : true,
30621 displayField : 'value',
30624 forceSelection : true,
30626 placeholder : this.dayPlaceholder,
30627 selectOnFocus : true,
30628 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30629 triggerAction : 'all',
30631 valueField : 'value',
30632 store : new Roo.data.SimpleStore({
30633 data : (function() {
30635 _this.fireEvent('days', _this, days);
30638 fields : [ 'value' ]
30641 select : function (_self, record, index)
30643 _this.setValue(_this.getValue());
30648 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
30650 this.monthField = new Roo.bootstrap.MonthField({
30651 after : '<i class=\"fa fa-calendar\"></i>',
30652 allowBlank : this.monthAllowBlank,
30653 placeholder : this.monthPlaceholder,
30656 render : function (_self)
30658 this.el.select('span.input-group-addon', true).first().on('click', function(e){
30659 e.preventDefault();
30663 select : function (_self, oldvalue, newvalue)
30665 _this.setValue(_this.getValue());
30670 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
30672 this.yearField = new Roo.bootstrap.ComboBox({
30673 allowBlank : this.yearAllowBlank,
30674 alwaysQuery : true,
30675 displayField : 'value',
30678 forceSelection : true,
30680 placeholder : this.yearPlaceholder,
30681 selectOnFocus : true,
30682 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30683 triggerAction : 'all',
30685 valueField : 'value',
30686 store : new Roo.data.SimpleStore({
30687 data : (function() {
30689 _this.fireEvent('years', _this, years);
30692 fields : [ 'value' ]
30695 select : function (_self, record, index)
30697 _this.setValue(_this.getValue());
30702 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
30705 setValue : function(v, format)
30707 this.inputEl.dom.value = v;
30709 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
30711 var d = Date.parseDate(v, f);
30718 this.setDay(d.format(this.dayFormat));
30719 this.setMonth(d.format(this.monthFormat));
30720 this.setYear(d.format(this.yearFormat));
30727 setDay : function(v)
30729 this.dayField.setValue(v);
30730 this.inputEl.dom.value = this.getValue();
30735 setMonth : function(v)
30737 this.monthField.setValue(v, true);
30738 this.inputEl.dom.value = this.getValue();
30743 setYear : function(v)
30745 this.yearField.setValue(v);
30746 this.inputEl.dom.value = this.getValue();
30751 getDay : function()
30753 return this.dayField.getValue();
30756 getMonth : function()
30758 return this.monthField.getValue();
30761 getYear : function()
30763 return this.yearField.getValue();
30766 getValue : function()
30768 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
30770 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
30780 this.inputEl.dom.value = '';
30785 validate : function()
30787 var d = this.dayField.validate();
30788 var m = this.monthField.validate();
30789 var y = this.yearField.validate();
30794 (!this.dayAllowBlank && !d) ||
30795 (!this.monthAllowBlank && !m) ||
30796 (!this.yearAllowBlank && !y)
30801 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
30810 this.markInvalid();
30815 markValid : function()
30818 var label = this.el.select('label', true).first();
30819 var icon = this.el.select('i.fa-star', true).first();
30825 this.fireEvent('valid', this);
30829 * Mark this field as invalid
30830 * @param {String} msg The validation message
30832 markInvalid : function(msg)
30835 var label = this.el.select('label', true).first();
30836 var icon = this.el.select('i.fa-star', true).first();
30838 if(label && !icon){
30839 this.el.select('.roo-date-split-field-label', true).createChild({
30841 cls : 'text-danger fa fa-lg fa-star',
30842 tooltip : 'This field is required',
30843 style : 'margin-right:5px;'
30847 this.fireEvent('invalid', this, msg);
30850 clearInvalid : function()
30852 var label = this.el.select('label', true).first();
30853 var icon = this.el.select('i.fa-star', true).first();
30859 this.fireEvent('valid', this);
30862 getName: function()
30872 * http://masonry.desandro.com
30874 * The idea is to render all the bricks based on vertical width...
30876 * The original code extends 'outlayer' - we might need to use that....
30882 * @class Roo.bootstrap.LayoutMasonry
30883 * @extends Roo.bootstrap.Component
30884 * Bootstrap Layout Masonry class
30887 * Create a new Element
30888 * @param {Object} config The config object
30891 Roo.bootstrap.LayoutMasonry = function(config){
30893 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
30897 Roo.bootstrap.LayoutMasonry.register(this);
30903 * Fire after layout the items
30904 * @param {Roo.bootstrap.LayoutMasonry} this
30905 * @param {Roo.EventObject} e
30912 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
30915 * @cfg {Boolean} isLayoutInstant = no animation?
30917 isLayoutInstant : false, // needed?
30920 * @cfg {Number} boxWidth width of the columns
30925 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
30930 * @cfg {Number} padWidth padding below box..
30935 * @cfg {Number} gutter gutter width..
30940 * @cfg {Number} maxCols maximum number of columns
30946 * @cfg {Boolean} isAutoInitial defalut true
30948 isAutoInitial : true,
30953 * @cfg {Boolean} isHorizontal defalut false
30955 isHorizontal : false,
30957 currentSize : null,
30963 bricks: null, //CompositeElement
30967 _isLayoutInited : false,
30969 // isAlternative : false, // only use for vertical layout...
30972 * @cfg {Number} alternativePadWidth padding below box..
30974 alternativePadWidth : 50,
30976 selectedBrick : [],
30978 getAutoCreate : function(){
30980 var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
30984 cls: 'blog-masonary-wrapper ' + this.cls,
30986 cls : 'mas-boxes masonary'
30993 getChildContainer: function( )
30995 if (this.boxesEl) {
30996 return this.boxesEl;
30999 this.boxesEl = this.el.select('.mas-boxes').first();
31001 return this.boxesEl;
31005 initEvents : function()
31009 if(this.isAutoInitial){
31010 Roo.log('hook children rendered');
31011 this.on('childrenrendered', function() {
31012 Roo.log('children rendered');
31018 initial : function()
31020 this.selectedBrick = [];
31022 this.currentSize = this.el.getBox(true);
31024 Roo.EventManager.onWindowResize(this.resize, this);
31026 if(!this.isAutoInitial){
31034 //this.layout.defer(500,this);
31038 resize : function()
31040 var cs = this.el.getBox(true);
31043 this.currentSize.width == cs.width &&
31044 this.currentSize.x == cs.x &&
31045 this.currentSize.height == cs.height &&
31046 this.currentSize.y == cs.y
31048 Roo.log("no change in with or X or Y");
31052 this.currentSize = cs;
31058 layout : function()
31060 this._resetLayout();
31062 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
31064 this.layoutItems( isInstant );
31066 this._isLayoutInited = true;
31068 this.fireEvent('layout', this);
31072 _resetLayout : function()
31074 if(this.isHorizontal){
31075 this.horizontalMeasureColumns();
31079 this.verticalMeasureColumns();
31083 verticalMeasureColumns : function()
31085 this.getContainerWidth();
31087 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
31088 // this.colWidth = Math.floor(this.containerWidth * 0.8);
31092 var boxWidth = this.boxWidth + this.padWidth;
31094 if(this.containerWidth < this.boxWidth){
31095 boxWidth = this.containerWidth
31098 var containerWidth = this.containerWidth;
31100 var cols = Math.floor(containerWidth / boxWidth);
31102 this.cols = Math.max( cols, 1 );
31104 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
31106 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
31108 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
31110 this.colWidth = boxWidth + avail - this.padWidth;
31112 this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
31113 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
31116 horizontalMeasureColumns : function()
31118 this.getContainerWidth();
31120 var boxWidth = this.boxWidth;
31122 if(this.containerWidth < boxWidth){
31123 boxWidth = this.containerWidth;
31126 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
31128 this.el.setHeight(boxWidth);
31132 getContainerWidth : function()
31134 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
31137 layoutItems : function( isInstant )
31139 Roo.log(this.bricks);
31141 var items = Roo.apply([], this.bricks);
31143 if(this.isHorizontal){
31144 this._horizontalLayoutItems( items , isInstant );
31148 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
31149 // this._verticalAlternativeLayoutItems( items , isInstant );
31153 this._verticalLayoutItems( items , isInstant );
31157 _verticalLayoutItems : function ( items , isInstant)
31159 if ( !items || !items.length ) {
31164 ['xs', 'xs', 'xs', 'tall'],
31165 ['xs', 'xs', 'tall'],
31166 ['xs', 'xs', 'sm'],
31167 ['xs', 'xs', 'xs'],
31173 ['sm', 'xs', 'xs'],
31177 ['tall', 'xs', 'xs', 'xs'],
31178 ['tall', 'xs', 'xs'],
31190 Roo.each(items, function(item, k){
31192 switch (item.size) {
31193 // these layouts take up a full box,
31204 boxes.push([item]);
31227 var filterPattern = function(box, length)
31235 var pattern = box.slice(0, length);
31239 Roo.each(pattern, function(i){
31240 format.push(i.size);
31243 Roo.each(standard, function(s){
31245 if(String(s) != String(format)){
31254 if(!match && length == 1){
31259 filterPattern(box, length - 1);
31263 queue.push(pattern);
31265 box = box.slice(length, box.length);
31267 filterPattern(box, 4);
31273 Roo.each(boxes, function(box, k){
31279 if(box.length == 1){
31284 filterPattern(box, 4);
31288 this._processVerticalLayoutQueue( queue, isInstant );
31292 // _verticalAlternativeLayoutItems : function( items , isInstant )
31294 // if ( !items || !items.length ) {
31298 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
31302 _horizontalLayoutItems : function ( items , isInstant)
31304 if ( !items || !items.length || items.length < 3) {
31310 var eItems = items.slice(0, 3);
31312 items = items.slice(3, items.length);
31315 ['xs', 'xs', 'xs', 'wide'],
31316 ['xs', 'xs', 'wide'],
31317 ['xs', 'xs', 'sm'],
31318 ['xs', 'xs', 'xs'],
31324 ['sm', 'xs', 'xs'],
31328 ['wide', 'xs', 'xs', 'xs'],
31329 ['wide', 'xs', 'xs'],
31342 Roo.each(items, function(item, k){
31344 switch (item.size) {
31355 boxes.push([item]);
31379 var filterPattern = function(box, length)
31387 var pattern = box.slice(0, length);
31391 Roo.each(pattern, function(i){
31392 format.push(i.size);
31395 Roo.each(standard, function(s){
31397 if(String(s) != String(format)){
31406 if(!match && length == 1){
31411 filterPattern(box, length - 1);
31415 queue.push(pattern);
31417 box = box.slice(length, box.length);
31419 filterPattern(box, 4);
31425 Roo.each(boxes, function(box, k){
31431 if(box.length == 1){
31436 filterPattern(box, 4);
31443 var pos = this.el.getBox(true);
31447 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31449 var hit_end = false;
31451 Roo.each(queue, function(box){
31455 Roo.each(box, function(b){
31457 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31467 Roo.each(box, function(b){
31469 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31472 mx = Math.max(mx, b.x);
31476 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
31480 Roo.each(box, function(b){
31482 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31496 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
31499 /** Sets position of item in DOM
31500 * @param {Element} item
31501 * @param {Number} x - horizontal position
31502 * @param {Number} y - vertical position
31503 * @param {Boolean} isInstant - disables transitions
31505 _processVerticalLayoutQueue : function( queue, isInstant )
31507 var pos = this.el.getBox(true);
31512 for (var i = 0; i < this.cols; i++){
31516 Roo.each(queue, function(box, k){
31518 var col = k % this.cols;
31520 Roo.each(box, function(b,kk){
31522 b.el.position('absolute');
31524 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31525 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31527 if(b.size == 'md-left' || b.size == 'md-right'){
31528 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31529 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31532 b.el.setWidth(width);
31533 b.el.setHeight(height);
31535 b.el.select('iframe',true).setSize(width,height);
31539 for (var i = 0; i < this.cols; i++){
31541 if(maxY[i] < maxY[col]){
31546 col = Math.min(col, i);
31550 x = pos.x + col * (this.colWidth + this.padWidth);
31554 var positions = [];
31556 switch (box.length){
31558 positions = this.getVerticalOneBoxColPositions(x, y, box);
31561 positions = this.getVerticalTwoBoxColPositions(x, y, box);
31564 positions = this.getVerticalThreeBoxColPositions(x, y, box);
31567 positions = this.getVerticalFourBoxColPositions(x, y, box);
31573 Roo.each(box, function(b,kk){
31575 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31577 var sz = b.el.getSize();
31579 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
31587 for (var i = 0; i < this.cols; i++){
31588 mY = Math.max(mY, maxY[i]);
31591 this.el.setHeight(mY - pos.y);
31595 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
31597 // var pos = this.el.getBox(true);
31600 // var maxX = pos.right;
31602 // var maxHeight = 0;
31604 // Roo.each(items, function(item, k){
31608 // item.el.position('absolute');
31610 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
31612 // item.el.setWidth(width);
31614 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
31616 // item.el.setHeight(height);
31619 // item.el.setXY([x, y], isInstant ? false : true);
31621 // item.el.setXY([maxX - width, y], isInstant ? false : true);
31624 // y = y + height + this.alternativePadWidth;
31626 // maxHeight = maxHeight + height + this.alternativePadWidth;
31630 // this.el.setHeight(maxHeight);
31634 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
31636 var pos = this.el.getBox(true);
31641 var maxX = pos.right;
31643 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
31645 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31647 Roo.each(queue, function(box, k){
31649 Roo.each(box, function(b, kk){
31651 b.el.position('absolute');
31653 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31654 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31656 if(b.size == 'md-left' || b.size == 'md-right'){
31657 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31658 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31661 b.el.setWidth(width);
31662 b.el.setHeight(height);
31670 var positions = [];
31672 switch (box.length){
31674 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
31677 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
31680 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
31683 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
31689 Roo.each(box, function(b,kk){
31691 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31693 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
31701 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
31703 Roo.each(eItems, function(b,k){
31705 b.size = (k == 0) ? 'sm' : 'xs';
31706 b.x = (k == 0) ? 2 : 1;
31707 b.y = (k == 0) ? 2 : 1;
31709 b.el.position('absolute');
31711 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31713 b.el.setWidth(width);
31715 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31717 b.el.setHeight(height);
31721 var positions = [];
31724 x : maxX - this.unitWidth * 2 - this.gutter,
31729 x : maxX - this.unitWidth,
31730 y : minY + (this.unitWidth + this.gutter) * 2
31734 x : maxX - this.unitWidth * 3 - this.gutter * 2,
31738 Roo.each(eItems, function(b,k){
31740 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
31746 getVerticalOneBoxColPositions : function(x, y, box)
31750 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
31752 if(box[0].size == 'md-left'){
31756 if(box[0].size == 'md-right'){
31761 x : x + (this.unitWidth + this.gutter) * rand,
31768 getVerticalTwoBoxColPositions : function(x, y, box)
31772 if(box[0].size == 'xs'){
31776 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
31780 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
31794 x : x + (this.unitWidth + this.gutter) * 2,
31795 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
31802 getVerticalThreeBoxColPositions : function(x, y, box)
31806 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31814 x : x + (this.unitWidth + this.gutter) * 1,
31819 x : x + (this.unitWidth + this.gutter) * 2,
31827 if(box[0].size == 'xs' && box[1].size == 'xs'){
31836 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
31840 x : x + (this.unitWidth + this.gutter) * 1,
31854 x : x + (this.unitWidth + this.gutter) * 2,
31859 x : x + (this.unitWidth + this.gutter) * 2,
31860 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
31867 getVerticalFourBoxColPositions : function(x, y, box)
31871 if(box[0].size == 'xs'){
31880 y : y + (this.unitHeight + this.gutter) * 1
31885 y : y + (this.unitHeight + this.gutter) * 2
31889 x : x + (this.unitWidth + this.gutter) * 1,
31903 x : x + (this.unitWidth + this.gutter) * 2,
31908 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
31909 y : y + (this.unitHeight + this.gutter) * 1
31913 x : x + (this.unitWidth + this.gutter) * 2,
31914 y : y + (this.unitWidth + this.gutter) * 2
31921 getHorizontalOneBoxColPositions : function(maxX, minY, box)
31925 if(box[0].size == 'md-left'){
31927 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31934 if(box[0].size == 'md-right'){
31936 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31937 y : minY + (this.unitWidth + this.gutter) * 1
31943 var rand = Math.floor(Math.random() * (4 - box[0].y));
31946 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31947 y : minY + (this.unitWidth + this.gutter) * rand
31954 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
31958 if(box[0].size == 'xs'){
31961 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31966 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31967 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
31975 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31980 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31981 y : minY + (this.unitWidth + this.gutter) * 2
31988 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
31992 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31995 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32000 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32001 y : minY + (this.unitWidth + this.gutter) * 1
32005 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32006 y : minY + (this.unitWidth + this.gutter) * 2
32013 if(box[0].size == 'xs' && box[1].size == 'xs'){
32016 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32021 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32026 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32027 y : minY + (this.unitWidth + this.gutter) * 1
32035 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32040 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32041 y : minY + (this.unitWidth + this.gutter) * 2
32045 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32046 y : minY + (this.unitWidth + this.gutter) * 2
32053 getHorizontalFourBoxColPositions : function(maxX, minY, box)
32057 if(box[0].size == 'xs'){
32060 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32065 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32070 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),
32075 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
32076 y : minY + (this.unitWidth + this.gutter) * 1
32084 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32089 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32090 y : minY + (this.unitWidth + this.gutter) * 2
32094 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32095 y : minY + (this.unitWidth + this.gutter) * 2
32099 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),
32100 y : minY + (this.unitWidth + this.gutter) * 2
32108 * remove a Masonry Brick
32109 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
32111 removeBrick : function(brick_id)
32117 for (var i = 0; i<this.bricks.length; i++) {
32118 if (this.bricks[i].id == brick_id) {
32119 this.bricks.splice(i,1);
32120 this.el.dom.removeChild(Roo.get(brick_id).dom);
32127 * adds a Masonry Brick
32128 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32130 addBrick : function(cfg)
32132 var cn = new Roo.bootstrap.MasonryBrick(cfg);
32133 //this.register(cn);
32134 cn.parentId = this.id;
32135 cn.render(this.el);
32140 * register a Masonry Brick
32141 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32144 register : function(brick)
32146 this.bricks.push(brick);
32147 brick.masonryId = this.id;
32151 * clear all the Masonry Brick
32153 clearAll : function()
32156 //this.getChildContainer().dom.innerHTML = "";
32157 this.el.dom.innerHTML = '';
32160 getSelected : function()
32162 if (!this.selectedBrick) {
32166 return this.selectedBrick;
32170 Roo.apply(Roo.bootstrap.LayoutMasonry, {
32174 * register a Masonry Layout
32175 * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
32178 register : function(layout)
32180 this.groups[layout.id] = layout;
32183 * fetch a Masonry Layout based on the masonry layout ID
32184 * @param {string} the masonry layout to add
32185 * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
32188 get: function(layout_id) {
32189 if (typeof(this.groups[layout_id]) == 'undefined') {
32192 return this.groups[layout_id] ;
32204 * http://masonry.desandro.com
32206 * The idea is to render all the bricks based on vertical width...
32208 * The original code extends 'outlayer' - we might need to use that....
32214 * @class Roo.bootstrap.LayoutMasonryAuto
32215 * @extends Roo.bootstrap.Component
32216 * Bootstrap Layout Masonry class
32219 * Create a new Element
32220 * @param {Object} config The config object
32223 Roo.bootstrap.LayoutMasonryAuto = function(config){
32224 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
32227 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
32230 * @cfg {Boolean} isFitWidth - resize the width..
32232 isFitWidth : false, // options..
32234 * @cfg {Boolean} isOriginLeft = left align?
32236 isOriginLeft : true,
32238 * @cfg {Boolean} isOriginTop = top align?
32240 isOriginTop : false,
32242 * @cfg {Boolean} isLayoutInstant = no animation?
32244 isLayoutInstant : false, // needed?
32246 * @cfg {Boolean} isResizingContainer = not sure if this is used..
32248 isResizingContainer : true,
32250 * @cfg {Number} columnWidth width of the columns
32256 * @cfg {Number} maxCols maximum number of columns
32261 * @cfg {Number} padHeight padding below box..
32267 * @cfg {Boolean} isAutoInitial defalut true
32270 isAutoInitial : true,
32276 initialColumnWidth : 0,
32277 currentSize : null,
32279 colYs : null, // array.
32286 bricks: null, //CompositeElement
32287 cols : 0, // array?
32288 // element : null, // wrapped now this.el
32289 _isLayoutInited : null,
32292 getAutoCreate : function(){
32296 cls: 'blog-masonary-wrapper ' + this.cls,
32298 cls : 'mas-boxes masonary'
32305 getChildContainer: function( )
32307 if (this.boxesEl) {
32308 return this.boxesEl;
32311 this.boxesEl = this.el.select('.mas-boxes').first();
32313 return this.boxesEl;
32317 initEvents : function()
32321 if(this.isAutoInitial){
32322 Roo.log('hook children rendered');
32323 this.on('childrenrendered', function() {
32324 Roo.log('children rendered');
32331 initial : function()
32333 this.reloadItems();
32335 this.currentSize = this.el.getBox(true);
32337 /// was window resize... - let's see if this works..
32338 Roo.EventManager.onWindowResize(this.resize, this);
32340 if(!this.isAutoInitial){
32345 this.layout.defer(500,this);
32348 reloadItems: function()
32350 this.bricks = this.el.select('.masonry-brick', true);
32352 this.bricks.each(function(b) {
32353 //Roo.log(b.getSize());
32354 if (!b.attr('originalwidth')) {
32355 b.attr('originalwidth', b.getSize().width);
32360 Roo.log(this.bricks.elements.length);
32363 resize : function()
32366 var cs = this.el.getBox(true);
32368 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
32369 Roo.log("no change in with or X");
32372 this.currentSize = cs;
32376 layout : function()
32379 this._resetLayout();
32380 //this._manageStamps();
32382 // don't animate first layout
32383 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
32384 this.layoutItems( isInstant );
32386 // flag for initalized
32387 this._isLayoutInited = true;
32390 layoutItems : function( isInstant )
32392 //var items = this._getItemsForLayout( this.items );
32393 // original code supports filtering layout items.. we just ignore it..
32395 this._layoutItems( this.bricks , isInstant );
32397 this._postLayout();
32399 _layoutItems : function ( items , isInstant)
32401 //this.fireEvent( 'layout', this, items );
32404 if ( !items || !items.elements.length ) {
32405 // no items, emit event with empty array
32410 items.each(function(item) {
32411 Roo.log("layout item");
32413 // get x/y object from method
32414 var position = this._getItemLayoutPosition( item );
32416 position.item = item;
32417 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
32418 queue.push( position );
32421 this._processLayoutQueue( queue );
32423 /** Sets position of item in DOM
32424 * @param {Element} item
32425 * @param {Number} x - horizontal position
32426 * @param {Number} y - vertical position
32427 * @param {Boolean} isInstant - disables transitions
32429 _processLayoutQueue : function( queue )
32431 for ( var i=0, len = queue.length; i < len; i++ ) {
32432 var obj = queue[i];
32433 obj.item.position('absolute');
32434 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
32440 * Any logic you want to do after each layout,
32441 * i.e. size the container
32443 _postLayout : function()
32445 this.resizeContainer();
32448 resizeContainer : function()
32450 if ( !this.isResizingContainer ) {
32453 var size = this._getContainerSize();
32455 this.el.setSize(size.width,size.height);
32456 this.boxesEl.setSize(size.width,size.height);
32462 _resetLayout : function()
32464 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
32465 this.colWidth = this.el.getWidth();
32466 //this.gutter = this.el.getWidth();
32468 this.measureColumns();
32474 this.colYs.push( 0 );
32480 measureColumns : function()
32482 this.getContainerWidth();
32483 // if columnWidth is 0, default to outerWidth of first item
32484 if ( !this.columnWidth ) {
32485 var firstItem = this.bricks.first();
32486 Roo.log(firstItem);
32487 this.columnWidth = this.containerWidth;
32488 if (firstItem && firstItem.attr('originalwidth') ) {
32489 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
32491 // columnWidth fall back to item of first element
32492 Roo.log("set column width?");
32493 this.initialColumnWidth = this.columnWidth ;
32495 // if first elem has no width, default to size of container
32500 if (this.initialColumnWidth) {
32501 this.columnWidth = this.initialColumnWidth;
32506 // column width is fixed at the top - however if container width get's smaller we should
32509 // this bit calcs how man columns..
32511 var columnWidth = this.columnWidth += this.gutter;
32513 // calculate columns
32514 var containerWidth = this.containerWidth + this.gutter;
32516 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
32517 // fix rounding errors, typically with gutters
32518 var excess = columnWidth - containerWidth % columnWidth;
32521 // if overshoot is less than a pixel, round up, otherwise floor it
32522 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
32523 cols = Math[ mathMethod ]( cols );
32524 this.cols = Math.max( cols, 1 );
32525 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
32527 // padding positioning..
32528 var totalColWidth = this.cols * this.columnWidth;
32529 var padavail = this.containerWidth - totalColWidth;
32530 // so for 2 columns - we need 3 'pads'
32532 var padNeeded = (1+this.cols) * this.padWidth;
32534 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
32536 this.columnWidth += padExtra
32537 //this.padWidth = Math.floor(padavail / ( this.cols));
32539 // adjust colum width so that padding is fixed??
32541 // we have 3 columns ... total = width * 3
32542 // we have X left over... that should be used by
32544 //if (this.expandC) {
32552 getContainerWidth : function()
32554 /* // container is parent if fit width
32555 var container = this.isFitWidth ? this.element.parentNode : this.element;
32556 // check that this.size and size are there
32557 // IE8 triggers resize on body size change, so they might not be
32559 var size = getSize( container ); //FIXME
32560 this.containerWidth = size && size.innerWidth; //FIXME
32563 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
32567 _getItemLayoutPosition : function( item ) // what is item?
32569 // we resize the item to our columnWidth..
32571 item.setWidth(this.columnWidth);
32572 item.autoBoxAdjust = false;
32574 var sz = item.getSize();
32576 // how many columns does this brick span
32577 var remainder = this.containerWidth % this.columnWidth;
32579 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
32580 // round if off by 1 pixel, otherwise use ceil
32581 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
32582 colSpan = Math.min( colSpan, this.cols );
32584 // normally this should be '1' as we dont' currently allow multi width columns..
32586 var colGroup = this._getColGroup( colSpan );
32587 // get the minimum Y value from the columns
32588 var minimumY = Math.min.apply( Math, colGroup );
32589 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32591 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
32593 // position the brick
32595 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
32596 y: this.currentSize.y + minimumY + this.padHeight
32600 // apply setHeight to necessary columns
32601 var setHeight = minimumY + sz.height + this.padHeight;
32602 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32604 var setSpan = this.cols + 1 - colGroup.length;
32605 for ( var i = 0; i < setSpan; i++ ) {
32606 this.colYs[ shortColIndex + i ] = setHeight ;
32613 * @param {Number} colSpan - number of columns the element spans
32614 * @returns {Array} colGroup
32616 _getColGroup : function( colSpan )
32618 if ( colSpan < 2 ) {
32619 // if brick spans only one column, use all the column Ys
32624 // how many different places could this brick fit horizontally
32625 var groupCount = this.cols + 1 - colSpan;
32626 // for each group potential horizontal position
32627 for ( var i = 0; i < groupCount; i++ ) {
32628 // make an array of colY values for that one group
32629 var groupColYs = this.colYs.slice( i, i + colSpan );
32630 // and get the max value of the array
32631 colGroup[i] = Math.max.apply( Math, groupColYs );
32636 _manageStamp : function( stamp )
32638 var stampSize = stamp.getSize();
32639 var offset = stamp.getBox();
32640 // get the columns that this stamp affects
32641 var firstX = this.isOriginLeft ? offset.x : offset.right;
32642 var lastX = firstX + stampSize.width;
32643 var firstCol = Math.floor( firstX / this.columnWidth );
32644 firstCol = Math.max( 0, firstCol );
32646 var lastCol = Math.floor( lastX / this.columnWidth );
32647 // lastCol should not go over if multiple of columnWidth #425
32648 lastCol -= lastX % this.columnWidth ? 0 : 1;
32649 lastCol = Math.min( this.cols - 1, lastCol );
32651 // set colYs to bottom of the stamp
32652 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
32655 for ( var i = firstCol; i <= lastCol; i++ ) {
32656 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
32661 _getContainerSize : function()
32663 this.maxY = Math.max.apply( Math, this.colYs );
32668 if ( this.isFitWidth ) {
32669 size.width = this._getContainerFitWidth();
32675 _getContainerFitWidth : function()
32677 var unusedCols = 0;
32678 // count unused columns
32681 if ( this.colYs[i] !== 0 ) {
32686 // fit container to columns that have been used
32687 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
32690 needsResizeLayout : function()
32692 var previousWidth = this.containerWidth;
32693 this.getContainerWidth();
32694 return previousWidth !== this.containerWidth;
32709 * @class Roo.bootstrap.MasonryBrick
32710 * @extends Roo.bootstrap.Component
32711 * Bootstrap MasonryBrick class
32714 * Create a new MasonryBrick
32715 * @param {Object} config The config object
32718 Roo.bootstrap.MasonryBrick = function(config){
32720 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
32722 Roo.bootstrap.MasonryBrick.register(this);
32728 * When a MasonryBrick is clcik
32729 * @param {Roo.bootstrap.MasonryBrick} this
32730 * @param {Roo.EventObject} e
32736 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
32739 * @cfg {String} title
32743 * @cfg {String} html
32747 * @cfg {String} bgimage
32751 * @cfg {String} videourl
32755 * @cfg {String} cls
32759 * @cfg {String} href
32763 * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
32768 * @cfg {String} placetitle (center|bottom)
32773 * @cfg {Boolean} isFitContainer defalut true
32775 isFitContainer : true,
32778 * @cfg {Boolean} preventDefault defalut false
32780 preventDefault : false,
32783 * @cfg {Boolean} inverse defalut false
32785 maskInverse : false,
32787 getAutoCreate : function()
32789 if(!this.isFitContainer){
32790 return this.getSplitAutoCreate();
32793 var cls = 'masonry-brick masonry-brick-full';
32795 if(this.href.length){
32796 cls += ' masonry-brick-link';
32799 if(this.bgimage.length){
32800 cls += ' masonry-brick-image';
32803 if(this.maskInverse){
32804 cls += ' mask-inverse';
32807 if(!this.html.length && !this.maskInverse && !this.videourl.length){
32808 cls += ' enable-mask';
32812 cls += ' masonry-' + this.size + '-brick';
32815 if(this.placetitle.length){
32817 switch (this.placetitle) {
32819 cls += ' masonry-center-title';
32822 cls += ' masonry-bottom-title';
32829 if(!this.html.length && !this.bgimage.length){
32830 cls += ' masonry-center-title';
32833 if(!this.html.length && this.bgimage.length){
32834 cls += ' masonry-bottom-title';
32839 cls += ' ' + this.cls;
32843 tag: (this.href.length) ? 'a' : 'div',
32848 cls: 'masonry-brick-mask'
32852 cls: 'masonry-brick-paragraph',
32858 if(this.href.length){
32859 cfg.href = this.href;
32862 var cn = cfg.cn[1].cn;
32864 if(this.title.length){
32867 cls: 'masonry-brick-title',
32872 if(this.html.length){
32875 cls: 'masonry-brick-text',
32880 if (!this.title.length && !this.html.length) {
32881 cfg.cn[1].cls += ' hide';
32884 if(this.bgimage.length){
32887 cls: 'masonry-brick-image-view',
32892 if(this.videourl.length){
32893 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32894 // youtube support only?
32897 cls: 'masonry-brick-image-view',
32900 allowfullscreen : true
32908 getSplitAutoCreate : function()
32910 var cls = 'masonry-brick masonry-brick-split';
32912 if(this.href.length){
32913 cls += ' masonry-brick-link';
32916 if(this.bgimage.length){
32917 cls += ' masonry-brick-image';
32921 cls += ' masonry-' + this.size + '-brick';
32924 switch (this.placetitle) {
32926 cls += ' masonry-center-title';
32929 cls += ' masonry-bottom-title';
32932 if(!this.bgimage.length){
32933 cls += ' masonry-center-title';
32936 if(this.bgimage.length){
32937 cls += ' masonry-bottom-title';
32943 cls += ' ' + this.cls;
32947 tag: (this.href.length) ? 'a' : 'div',
32952 cls: 'masonry-brick-split-head',
32956 cls: 'masonry-brick-paragraph',
32963 cls: 'masonry-brick-split-body',
32969 if(this.href.length){
32970 cfg.href = this.href;
32973 if(this.title.length){
32974 cfg.cn[0].cn[0].cn.push({
32976 cls: 'masonry-brick-title',
32981 if(this.html.length){
32982 cfg.cn[1].cn.push({
32984 cls: 'masonry-brick-text',
32989 if(this.bgimage.length){
32990 cfg.cn[0].cn.push({
32992 cls: 'masonry-brick-image-view',
32997 if(this.videourl.length){
32998 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32999 // youtube support only?
33000 cfg.cn[0].cn.cn.push({
33002 cls: 'masonry-brick-image-view',
33005 allowfullscreen : true
33012 initEvents: function()
33014 switch (this.size) {
33047 this.el.on('touchstart', this.onTouchStart, this);
33048 this.el.on('touchmove', this.onTouchMove, this);
33049 this.el.on('touchend', this.onTouchEnd, this);
33050 this.el.on('contextmenu', this.onContextMenu, this);
33052 this.el.on('mouseenter' ,this.enter, this);
33053 this.el.on('mouseleave', this.leave, this);
33054 this.el.on('click', this.onClick, this);
33057 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
33058 this.parent().bricks.push(this);
33063 onClick: function(e, el)
33065 var time = this.endTimer - this.startTimer;
33066 // Roo.log(e.preventDefault());
33069 e.preventDefault();
33074 if(!this.preventDefault){
33078 e.preventDefault();
33080 if (this.activeClass != '') {
33081 this.selectBrick();
33084 this.fireEvent('click', this, e);
33087 enter: function(e, el)
33089 e.preventDefault();
33091 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
33095 if(this.bgimage.length && this.html.length){
33096 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
33100 leave: function(e, el)
33102 e.preventDefault();
33104 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
33108 if(this.bgimage.length && this.html.length){
33109 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
33113 onTouchStart: function(e, el)
33115 // e.preventDefault();
33117 this.touchmoved = false;
33119 if(!this.isFitContainer){
33123 if(!this.bgimage.length || !this.html.length){
33127 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
33129 this.timer = new Date().getTime();
33133 onTouchMove: function(e, el)
33135 this.touchmoved = true;
33138 onContextMenu : function(e,el)
33140 e.preventDefault();
33141 e.stopPropagation();
33145 onTouchEnd: function(e, el)
33147 // e.preventDefault();
33149 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
33156 if(!this.bgimage.length || !this.html.length){
33158 if(this.href.length){
33159 window.location.href = this.href;
33165 if(!this.isFitContainer){
33169 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
33171 window.location.href = this.href;
33174 //selection on single brick only
33175 selectBrick : function() {
33177 if (!this.parentId) {
33181 var m = Roo.bootstrap.LayoutMasonry.get(this.parentId);
33182 var index = m.selectedBrick.indexOf(this.id);
33185 m.selectedBrick.splice(index,1);
33186 this.el.removeClass(this.activeClass);
33190 for(var i = 0; i < m.selectedBrick.length; i++) {
33191 var b = Roo.bootstrap.MasonryBrick.get(m.selectedBrick[i]);
33192 b.el.removeClass(b.activeClass);
33195 m.selectedBrick = [];
33197 m.selectedBrick.push(this.id);
33198 this.el.addClass(this.activeClass);
33202 isSelected : function(){
33203 return this.el.hasClass(this.activeClass);
33208 Roo.apply(Roo.bootstrap.MasonryBrick, {
33211 groups : new Roo.util.MixedCollection(false, function(o) { return o.el.id; }),
33213 * register a Masonry Brick
33214 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
33217 register : function(brick)
33219 //this.groups[brick.id] = brick;
33220 this.groups.add(brick.id, brick);
33223 * fetch a masonry brick based on the masonry brick ID
33224 * @param {string} the masonry brick to add
33225 * @returns {Roo.bootstrap.MasonryBrick} the masonry brick
33228 get: function(brick_id)
33230 // if (typeof(this.groups[brick_id]) == 'undefined') {
33233 // return this.groups[brick_id] ;
33235 if(this.groups.key(brick_id)) {
33236 return this.groups.key(brick_id);
33254 * @class Roo.bootstrap.Brick
33255 * @extends Roo.bootstrap.Component
33256 * Bootstrap Brick class
33259 * Create a new Brick
33260 * @param {Object} config The config object
33263 Roo.bootstrap.Brick = function(config){
33264 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
33270 * When a Brick is click
33271 * @param {Roo.bootstrap.Brick} this
33272 * @param {Roo.EventObject} e
33278 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
33281 * @cfg {String} title
33285 * @cfg {String} html
33289 * @cfg {String} bgimage
33293 * @cfg {String} cls
33297 * @cfg {String} href
33301 * @cfg {String} video
33305 * @cfg {Boolean} square
33309 getAutoCreate : function()
33311 var cls = 'roo-brick';
33313 if(this.href.length){
33314 cls += ' roo-brick-link';
33317 if(this.bgimage.length){
33318 cls += ' roo-brick-image';
33321 if(!this.html.length && !this.bgimage.length){
33322 cls += ' roo-brick-center-title';
33325 if(!this.html.length && this.bgimage.length){
33326 cls += ' roo-brick-bottom-title';
33330 cls += ' ' + this.cls;
33334 tag: (this.href.length) ? 'a' : 'div',
33339 cls: 'roo-brick-paragraph',
33345 if(this.href.length){
33346 cfg.href = this.href;
33349 var cn = cfg.cn[0].cn;
33351 if(this.title.length){
33354 cls: 'roo-brick-title',
33359 if(this.html.length){
33362 cls: 'roo-brick-text',
33369 if(this.bgimage.length){
33372 cls: 'roo-brick-image-view',
33380 initEvents: function()
33382 if(this.title.length || this.html.length){
33383 this.el.on('mouseenter' ,this.enter, this);
33384 this.el.on('mouseleave', this.leave, this);
33387 Roo.EventManager.onWindowResize(this.resize, this);
33389 if(this.bgimage.length){
33390 this.imageEl = this.el.select('.roo-brick-image-view', true).first();
33391 this.imageEl.on('load', this.onImageLoad, this);
33398 onImageLoad : function()
33403 resize : function()
33405 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
33407 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
33409 if(this.bgimage.length){
33410 var image = this.el.select('.roo-brick-image-view', true).first();
33412 image.setWidth(paragraph.getWidth());
33415 image.setHeight(paragraph.getWidth());
33418 this.el.setHeight(image.getHeight());
33419 paragraph.setHeight(image.getHeight());
33425 enter: function(e, el)
33427 e.preventDefault();
33429 if(this.bgimage.length){
33430 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
33431 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
33435 leave: function(e, el)
33437 e.preventDefault();
33439 if(this.bgimage.length){
33440 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
33441 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
33456 * @class Roo.bootstrap.NumberField
33457 * @extends Roo.bootstrap.Input
33458 * Bootstrap NumberField class
33464 * Create a new NumberField
33465 * @param {Object} config The config object
33468 Roo.bootstrap.NumberField = function(config){
33469 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
33472 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
33475 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
33477 allowDecimals : true,
33479 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
33481 decimalSeparator : ".",
33483 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
33485 decimalPrecision : 2,
33487 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
33489 allowNegative : true,
33492 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
33496 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
33498 minValue : Number.NEGATIVE_INFINITY,
33500 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
33502 maxValue : Number.MAX_VALUE,
33504 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
33506 minText : "The minimum value for this field is {0}",
33508 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
33510 maxText : "The maximum value for this field is {0}",
33512 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
33513 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
33515 nanText : "{0} is not a valid number",
33517 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
33519 thousandsDelimiter : false,
33521 * @cfg {String} valueAlign alignment of value
33523 valueAlign : "left",
33525 getAutoCreate : function()
33527 var hiddenInput = {
33531 cls: 'hidden-number-input'
33535 hiddenInput.name = this.name;
33540 var cfg = Roo.bootstrap.NumberField.superclass.getAutoCreate.call(this);
33542 this.name = hiddenInput.name;
33544 if(cfg.cn.length > 0) {
33545 cfg.cn.push(hiddenInput);
33552 initEvents : function()
33554 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
33556 var allowed = "0123456789";
33558 if(this.allowDecimals){
33559 allowed += this.decimalSeparator;
33562 if(this.allowNegative){
33566 if(this.thousandsDelimiter) {
33570 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
33572 var keyPress = function(e){
33574 var k = e.getKey();
33576 var c = e.getCharCode();
33579 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
33580 allowed.indexOf(String.fromCharCode(c)) === -1
33586 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
33590 if(allowed.indexOf(String.fromCharCode(c)) === -1){
33595 this.el.on("keypress", keyPress, this);
33598 validateValue : function(value)
33601 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
33605 var num = this.parseValue(value);
33608 this.markInvalid(String.format(this.nanText, value));
33612 if(num < this.minValue){
33613 this.markInvalid(String.format(this.minText, this.minValue));
33617 if(num > this.maxValue){
33618 this.markInvalid(String.format(this.maxText, this.maxValue));
33625 getValue : function()
33627 var v = this.hiddenEl().getValue();
33629 return this.fixPrecision(this.parseValue(v));
33632 parseValue : function(value)
33634 if(this.thousandsDelimiter) {
33636 r = new RegExp(",", "g");
33637 value = value.replace(r, "");
33640 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
33641 return isNaN(value) ? '' : value;
33644 fixPrecision : function(value)
33646 if(this.thousandsDelimiter) {
33648 r = new RegExp(",", "g");
33649 value = value.replace(r, "");
33652 var nan = isNaN(value);
33654 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
33655 return nan ? '' : value;
33657 return parseFloat(value).toFixed(this.decimalPrecision);
33660 setValue : function(v)
33662 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
33668 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
33670 this.inputEl().dom.value = (v == '') ? '' :
33671 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
33673 if(!this.allowZero && v === '0') {
33674 this.hiddenEl().dom.value = '';
33675 this.inputEl().dom.value = '';
33682 decimalPrecisionFcn : function(v)
33684 return Math.floor(v);
33687 beforeBlur : function()
33689 var v = this.parseValue(this.getRawValue());
33691 if(v || v === 0 || v === ''){
33696 hiddenEl : function()
33698 return this.el.select('input.hidden-number-input',true).first();
33710 * @class Roo.bootstrap.DocumentSlider
33711 * @extends Roo.bootstrap.Component
33712 * Bootstrap DocumentSlider class
33715 * Create a new DocumentViewer
33716 * @param {Object} config The config object
33719 Roo.bootstrap.DocumentSlider = function(config){
33720 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
33727 * Fire after initEvent
33728 * @param {Roo.bootstrap.DocumentSlider} this
33733 * Fire after update
33734 * @param {Roo.bootstrap.DocumentSlider} this
33740 * @param {Roo.bootstrap.DocumentSlider} this
33746 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
33752 getAutoCreate : function()
33756 cls : 'roo-document-slider',
33760 cls : 'roo-document-slider-header',
33764 cls : 'roo-document-slider-header-title'
33770 cls : 'roo-document-slider-body',
33774 cls : 'roo-document-slider-prev',
33778 cls : 'fa fa-chevron-left'
33784 cls : 'roo-document-slider-thumb',
33788 cls : 'roo-document-slider-image'
33794 cls : 'roo-document-slider-next',
33798 cls : 'fa fa-chevron-right'
33810 initEvents : function()
33812 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
33813 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
33815 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
33816 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
33818 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
33819 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
33821 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
33822 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
33824 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
33825 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
33827 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
33828 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33830 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
33831 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33833 this.thumbEl.on('click', this.onClick, this);
33835 this.prevIndicator.on('click', this.prev, this);
33837 this.nextIndicator.on('click', this.next, this);
33841 initial : function()
33843 if(this.files.length){
33844 this.indicator = 1;
33848 this.fireEvent('initial', this);
33851 update : function()
33853 this.imageEl.attr('src', this.files[this.indicator - 1]);
33855 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
33857 this.prevIndicator.show();
33859 if(this.indicator == 1){
33860 this.prevIndicator.hide();
33863 this.nextIndicator.show();
33865 if(this.indicator == this.files.length){
33866 this.nextIndicator.hide();
33869 this.thumbEl.scrollTo('top');
33871 this.fireEvent('update', this);
33874 onClick : function(e)
33876 e.preventDefault();
33878 this.fireEvent('click', this);
33883 e.preventDefault();
33885 this.indicator = Math.max(1, this.indicator - 1);
33892 e.preventDefault();
33894 this.indicator = Math.min(this.files.length, this.indicator + 1);
33908 * @class Roo.bootstrap.RadioSet
33909 * @extends Roo.bootstrap.Input
33910 * Bootstrap RadioSet class
33911 * @cfg {String} indicatorpos (left|right) default left
33912 * @cfg {Boolean} inline (true|false) inline the element (default true)
33913 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
33915 * Create a new RadioSet
33916 * @param {Object} config The config object
33919 Roo.bootstrap.RadioSet = function(config){
33921 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
33925 Roo.bootstrap.RadioSet.register(this);
33930 * Fires when the element is checked or unchecked.
33931 * @param {Roo.bootstrap.RadioSet} this This radio
33932 * @param {Roo.bootstrap.Radio} item The checked item
33937 * Fires when the element is click.
33938 * @param {Roo.bootstrap.RadioSet} this This radio set
33939 * @param {Roo.bootstrap.Radio} item The checked item
33940 * @param {Roo.EventObject} e The event object
33947 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
33955 indicatorpos : 'left',
33957 getAutoCreate : function()
33961 cls : 'roo-radio-set-label',
33965 html : this.fieldLabel
33970 if(this.indicatorpos == 'left'){
33973 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
33974 tooltip : 'This field is required'
33979 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
33980 tooltip : 'This field is required'
33986 cls : 'roo-radio-set-items'
33989 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
33991 if (align === 'left' && this.fieldLabel.length) {
33994 cls : "roo-radio-set-right",
34000 if(this.labelWidth > 12){
34001 label.style = "width: " + this.labelWidth + 'px';
34004 if(this.labelWidth < 13 && this.labelmd == 0){
34005 this.labelmd = this.labelWidth;
34008 if(this.labellg > 0){
34009 label.cls += ' col-lg-' + this.labellg;
34010 items.cls += ' col-lg-' + (12 - this.labellg);
34013 if(this.labelmd > 0){
34014 label.cls += ' col-md-' + this.labelmd;
34015 items.cls += ' col-md-' + (12 - this.labelmd);
34018 if(this.labelsm > 0){
34019 label.cls += ' col-sm-' + this.labelsm;
34020 items.cls += ' col-sm-' + (12 - this.labelsm);
34023 if(this.labelxs > 0){
34024 label.cls += ' col-xs-' + this.labelxs;
34025 items.cls += ' col-xs-' + (12 - this.labelxs);
34031 cls : 'roo-radio-set',
34035 cls : 'roo-radio-set-input',
34038 value : this.value ? this.value : ''
34045 if(this.weight.length){
34046 cfg.cls += ' roo-radio-' + this.weight;
34050 cfg.cls += ' roo-radio-set-inline';
34054 ['xs','sm','md','lg'].map(function(size){
34055 if (settings[size]) {
34056 cfg.cls += ' col-' + size + '-' + settings[size];
34064 initEvents : function()
34066 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
34067 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
34069 if(!this.fieldLabel.length){
34070 this.labelEl.hide();
34073 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
34074 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
34076 this.indicator = this.indicatorEl();
34078 if(this.indicator){
34079 this.indicator.addClass('invisible');
34082 this.originalValue = this.getValue();
34086 inputEl: function ()
34088 return this.el.select('.roo-radio-set-input', true).first();
34091 getChildContainer : function()
34093 return this.itemsEl;
34096 register : function(item)
34098 this.radioes.push(item);
34102 validate : function()
34104 if(this.getVisibilityEl().hasClass('hidden')){
34110 Roo.each(this.radioes, function(i){
34119 if(this.allowBlank) {
34123 if(this.disabled || valid){
34128 this.markInvalid();
34133 markValid : function()
34135 if(this.labelEl.isVisible(true)){
34136 this.indicatorEl().removeClass('visible');
34137 this.indicatorEl().addClass('invisible');
34140 this.el.removeClass([this.invalidClass, this.validClass]);
34141 this.el.addClass(this.validClass);
34143 this.fireEvent('valid', this);
34146 markInvalid : function(msg)
34148 if(this.allowBlank || this.disabled){
34152 if(this.labelEl.isVisible(true)){
34153 this.indicatorEl().removeClass('invisible');
34154 this.indicatorEl().addClass('visible');
34157 this.el.removeClass([this.invalidClass, this.validClass]);
34158 this.el.addClass(this.invalidClass);
34160 this.fireEvent('invalid', this, msg);
34164 setValue : function(v, suppressEvent)
34166 if(this.value === v){
34173 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
34176 Roo.each(this.radioes, function(i){
34178 i.el.removeClass('checked');
34181 Roo.each(this.radioes, function(i){
34183 if(i.value === v || i.value.toString() === v.toString()){
34185 i.el.addClass('checked');
34187 if(suppressEvent !== true){
34188 this.fireEvent('check', this, i);
34199 clearInvalid : function(){
34201 if(!this.el || this.preventMark){
34205 this.el.removeClass([this.invalidClass]);
34207 this.fireEvent('valid', this);
34212 Roo.apply(Roo.bootstrap.RadioSet, {
34216 register : function(set)
34218 this.groups[set.name] = set;
34221 get: function(name)
34223 if (typeof(this.groups[name]) == 'undefined') {
34227 return this.groups[name] ;
34233 * Ext JS Library 1.1.1
34234 * Copyright(c) 2006-2007, Ext JS, LLC.
34236 * Originally Released Under LGPL - original licence link has changed is not relivant.
34239 * <script type="text/javascript">
34244 * @class Roo.bootstrap.SplitBar
34245 * @extends Roo.util.Observable
34246 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
34250 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
34251 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
34252 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
34253 split.minSize = 100;
34254 split.maxSize = 600;
34255 split.animate = true;
34256 split.on('moved', splitterMoved);
34259 * Create a new SplitBar
34260 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
34261 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
34262 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34263 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
34264 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
34265 position of the SplitBar).
34267 Roo.bootstrap.SplitBar = function(cfg){
34272 // dragElement : elm
34273 // resizingElement: el,
34275 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
34276 // placement : Roo.bootstrap.SplitBar.LEFT ,
34277 // existingProxy ???
34280 this.el = Roo.get(cfg.dragElement, true);
34281 this.el.dom.unselectable = "on";
34283 this.resizingEl = Roo.get(cfg.resizingElement, true);
34287 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34288 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
34291 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
34294 * The minimum size of the resizing element. (Defaults to 0)
34300 * The maximum size of the resizing element. (Defaults to 2000)
34303 this.maxSize = 2000;
34306 * Whether to animate the transition to the new size
34309 this.animate = false;
34312 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
34315 this.useShim = false;
34320 if(!cfg.existingProxy){
34322 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
34324 this.proxy = Roo.get(cfg.existingProxy).dom;
34327 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
34330 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
34333 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
34336 this.dragSpecs = {};
34339 * @private The adapter to use to positon and resize elements
34341 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34342 this.adapter.init(this);
34344 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34346 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
34347 this.el.addClass("roo-splitbar-h");
34350 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
34351 this.el.addClass("roo-splitbar-v");
34357 * Fires when the splitter is moved (alias for {@link #event-moved})
34358 * @param {Roo.bootstrap.SplitBar} this
34359 * @param {Number} newSize the new width or height
34364 * Fires when the splitter is moved
34365 * @param {Roo.bootstrap.SplitBar} this
34366 * @param {Number} newSize the new width or height
34370 * @event beforeresize
34371 * Fires before the splitter is dragged
34372 * @param {Roo.bootstrap.SplitBar} this
34374 "beforeresize" : true,
34376 "beforeapply" : true
34379 Roo.util.Observable.call(this);
34382 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
34383 onStartProxyDrag : function(x, y){
34384 this.fireEvent("beforeresize", this);
34386 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
34388 o.enableDisplayMode("block");
34389 // all splitbars share the same overlay
34390 Roo.bootstrap.SplitBar.prototype.overlay = o;
34392 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
34393 this.overlay.show();
34394 Roo.get(this.proxy).setDisplayed("block");
34395 var size = this.adapter.getElementSize(this);
34396 this.activeMinSize = this.getMinimumSize();;
34397 this.activeMaxSize = this.getMaximumSize();;
34398 var c1 = size - this.activeMinSize;
34399 var c2 = Math.max(this.activeMaxSize - size, 0);
34400 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34401 this.dd.resetConstraints();
34402 this.dd.setXConstraint(
34403 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
34404 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
34406 this.dd.setYConstraint(0, 0);
34408 this.dd.resetConstraints();
34409 this.dd.setXConstraint(0, 0);
34410 this.dd.setYConstraint(
34411 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
34412 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
34415 this.dragSpecs.startSize = size;
34416 this.dragSpecs.startPoint = [x, y];
34417 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
34421 * @private Called after the drag operation by the DDProxy
34423 onEndProxyDrag : function(e){
34424 Roo.get(this.proxy).setDisplayed(false);
34425 var endPoint = Roo.lib.Event.getXY(e);
34427 this.overlay.hide();
34430 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34431 newSize = this.dragSpecs.startSize +
34432 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
34433 endPoint[0] - this.dragSpecs.startPoint[0] :
34434 this.dragSpecs.startPoint[0] - endPoint[0]
34437 newSize = this.dragSpecs.startSize +
34438 (this.placement == Roo.bootstrap.SplitBar.TOP ?
34439 endPoint[1] - this.dragSpecs.startPoint[1] :
34440 this.dragSpecs.startPoint[1] - endPoint[1]
34443 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
34444 if(newSize != this.dragSpecs.startSize){
34445 if(this.fireEvent('beforeapply', this, newSize) !== false){
34446 this.adapter.setElementSize(this, newSize);
34447 this.fireEvent("moved", this, newSize);
34448 this.fireEvent("resize", this, newSize);
34454 * Get the adapter this SplitBar uses
34455 * @return The adapter object
34457 getAdapter : function(){
34458 return this.adapter;
34462 * Set the adapter this SplitBar uses
34463 * @param {Object} adapter A SplitBar adapter object
34465 setAdapter : function(adapter){
34466 this.adapter = adapter;
34467 this.adapter.init(this);
34471 * Gets the minimum size for the resizing element
34472 * @return {Number} The minimum size
34474 getMinimumSize : function(){
34475 return this.minSize;
34479 * Sets the minimum size for the resizing element
34480 * @param {Number} minSize The minimum size
34482 setMinimumSize : function(minSize){
34483 this.minSize = minSize;
34487 * Gets the maximum size for the resizing element
34488 * @return {Number} The maximum size
34490 getMaximumSize : function(){
34491 return this.maxSize;
34495 * Sets the maximum size for the resizing element
34496 * @param {Number} maxSize The maximum size
34498 setMaximumSize : function(maxSize){
34499 this.maxSize = maxSize;
34503 * Sets the initialize size for the resizing element
34504 * @param {Number} size The initial size
34506 setCurrentSize : function(size){
34507 var oldAnimate = this.animate;
34508 this.animate = false;
34509 this.adapter.setElementSize(this, size);
34510 this.animate = oldAnimate;
34514 * Destroy this splitbar.
34515 * @param {Boolean} removeEl True to remove the element
34517 destroy : function(removeEl){
34519 this.shim.remove();
34522 this.proxy.parentNode.removeChild(this.proxy);
34530 * @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.
34532 Roo.bootstrap.SplitBar.createProxy = function(dir){
34533 var proxy = new Roo.Element(document.createElement("div"));
34534 proxy.unselectable();
34535 var cls = 'roo-splitbar-proxy';
34536 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
34537 document.body.appendChild(proxy.dom);
34542 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
34543 * Default Adapter. It assumes the splitter and resizing element are not positioned
34544 * elements and only gets/sets the width of the element. Generally used for table based layouts.
34546 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
34549 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
34550 // do nothing for now
34551 init : function(s){
34555 * Called before drag operations to get the current size of the resizing element.
34556 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34558 getElementSize : function(s){
34559 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34560 return s.resizingEl.getWidth();
34562 return s.resizingEl.getHeight();
34567 * Called after drag operations to set the size of the resizing element.
34568 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34569 * @param {Number} newSize The new size to set
34570 * @param {Function} onComplete A function to be invoked when resizing is complete
34572 setElementSize : function(s, newSize, onComplete){
34573 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34575 s.resizingEl.setWidth(newSize);
34577 onComplete(s, newSize);
34580 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
34585 s.resizingEl.setHeight(newSize);
34587 onComplete(s, newSize);
34590 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
34597 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
34598 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
34599 * Adapter that moves the splitter element to align with the resized sizing element.
34600 * Used with an absolute positioned SplitBar.
34601 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
34602 * document.body, make sure you assign an id to the body element.
34604 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
34605 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34606 this.container = Roo.get(container);
34609 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
34610 init : function(s){
34611 this.basic.init(s);
34614 getElementSize : function(s){
34615 return this.basic.getElementSize(s);
34618 setElementSize : function(s, newSize, onComplete){
34619 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
34622 moveSplitter : function(s){
34623 var yes = Roo.bootstrap.SplitBar;
34624 switch(s.placement){
34626 s.el.setX(s.resizingEl.getRight());
34629 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
34632 s.el.setY(s.resizingEl.getBottom());
34635 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
34642 * Orientation constant - Create a vertical SplitBar
34646 Roo.bootstrap.SplitBar.VERTICAL = 1;
34649 * Orientation constant - Create a horizontal SplitBar
34653 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
34656 * Placement constant - The resizing element is to the left of the splitter element
34660 Roo.bootstrap.SplitBar.LEFT = 1;
34663 * Placement constant - The resizing element is to the right of the splitter element
34667 Roo.bootstrap.SplitBar.RIGHT = 2;
34670 * Placement constant - The resizing element is positioned above the splitter element
34674 Roo.bootstrap.SplitBar.TOP = 3;
34677 * Placement constant - The resizing element is positioned under splitter element
34681 Roo.bootstrap.SplitBar.BOTTOM = 4;
34682 Roo.namespace("Roo.bootstrap.layout");/*
34684 * Ext JS Library 1.1.1
34685 * Copyright(c) 2006-2007, Ext JS, LLC.
34687 * Originally Released Under LGPL - original licence link has changed is not relivant.
34690 * <script type="text/javascript">
34694 * @class Roo.bootstrap.layout.Manager
34695 * @extends Roo.bootstrap.Component
34696 * Base class for layout managers.
34698 Roo.bootstrap.layout.Manager = function(config)
34700 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
34706 /** false to disable window resize monitoring @type Boolean */
34707 this.monitorWindowResize = true;
34712 * Fires when a layout is performed.
34713 * @param {Roo.LayoutManager} this
34717 * @event regionresized
34718 * Fires when the user resizes a region.
34719 * @param {Roo.LayoutRegion} region The resized region
34720 * @param {Number} newSize The new size (width for east/west, height for north/south)
34722 "regionresized" : true,
34724 * @event regioncollapsed
34725 * Fires when a region is collapsed.
34726 * @param {Roo.LayoutRegion} region The collapsed region
34728 "regioncollapsed" : true,
34730 * @event regionexpanded
34731 * Fires when a region is expanded.
34732 * @param {Roo.LayoutRegion} region The expanded region
34734 "regionexpanded" : true
34736 this.updating = false;
34739 this.el = Roo.get(config.el);
34745 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
34750 monitorWindowResize : true,
34756 onRender : function(ct, position)
34759 this.el = Roo.get(ct);
34762 //this.fireEvent('render',this);
34766 initEvents: function()
34770 // ie scrollbar fix
34771 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
34772 document.body.scroll = "no";
34773 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
34774 this.el.position('relative');
34776 this.id = this.el.id;
34777 this.el.addClass("roo-layout-container");
34778 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
34779 if(this.el.dom != document.body ) {
34780 this.el.on('resize', this.layout,this);
34781 this.el.on('show', this.layout,this);
34787 * Returns true if this layout is currently being updated
34788 * @return {Boolean}
34790 isUpdating : function(){
34791 return this.updating;
34795 * Suspend the LayoutManager from doing auto-layouts while
34796 * making multiple add or remove calls
34798 beginUpdate : function(){
34799 this.updating = true;
34803 * Restore auto-layouts and optionally disable the manager from performing a layout
34804 * @param {Boolean} noLayout true to disable a layout update
34806 endUpdate : function(noLayout){
34807 this.updating = false;
34813 layout: function(){
34817 onRegionResized : function(region, newSize){
34818 this.fireEvent("regionresized", region, newSize);
34822 onRegionCollapsed : function(region){
34823 this.fireEvent("regioncollapsed", region);
34826 onRegionExpanded : function(region){
34827 this.fireEvent("regionexpanded", region);
34831 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
34832 * performs box-model adjustments.
34833 * @return {Object} The size as an object {width: (the width), height: (the height)}
34835 getViewSize : function()
34838 if(this.el.dom != document.body){
34839 size = this.el.getSize();
34841 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
34843 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
34844 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
34849 * Returns the Element this layout is bound to.
34850 * @return {Roo.Element}
34852 getEl : function(){
34857 * Returns the specified region.
34858 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
34859 * @return {Roo.LayoutRegion}
34861 getRegion : function(target){
34862 return this.regions[target.toLowerCase()];
34865 onWindowResize : function(){
34866 if(this.monitorWindowResize){
34873 * Ext JS Library 1.1.1
34874 * Copyright(c) 2006-2007, Ext JS, LLC.
34876 * Originally Released Under LGPL - original licence link has changed is not relivant.
34879 * <script type="text/javascript">
34882 * @class Roo.bootstrap.layout.Border
34883 * @extends Roo.bootstrap.layout.Manager
34884 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
34885 * please see: examples/bootstrap/nested.html<br><br>
34887 <b>The container the layout is rendered into can be either the body element or any other element.
34888 If it is not the body element, the container needs to either be an absolute positioned element,
34889 or you will need to add "position:relative" to the css of the container. You will also need to specify
34890 the container size if it is not the body element.</b>
34893 * Create a new Border
34894 * @param {Object} config Configuration options
34896 Roo.bootstrap.layout.Border = function(config){
34897 config = config || {};
34898 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
34902 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34903 if(config[region]){
34904 config[region].region = region;
34905 this.addRegion(config[region]);
34911 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
34913 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
34915 * Creates and adds a new region if it doesn't already exist.
34916 * @param {String} target The target region key (north, south, east, west or center).
34917 * @param {Object} config The regions config object
34918 * @return {BorderLayoutRegion} The new region
34920 addRegion : function(config)
34922 if(!this.regions[config.region]){
34923 var r = this.factory(config);
34924 this.bindRegion(r);
34926 return this.regions[config.region];
34930 bindRegion : function(r){
34931 this.regions[r.config.region] = r;
34933 r.on("visibilitychange", this.layout, this);
34934 r.on("paneladded", this.layout, this);
34935 r.on("panelremoved", this.layout, this);
34936 r.on("invalidated", this.layout, this);
34937 r.on("resized", this.onRegionResized, this);
34938 r.on("collapsed", this.onRegionCollapsed, this);
34939 r.on("expanded", this.onRegionExpanded, this);
34943 * Performs a layout update.
34945 layout : function()
34947 if(this.updating) {
34951 // render all the rebions if they have not been done alreayd?
34952 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34953 if(this.regions[region] && !this.regions[region].bodyEl){
34954 this.regions[region].onRender(this.el)
34958 var size = this.getViewSize();
34959 var w = size.width;
34960 var h = size.height;
34965 //var x = 0, y = 0;
34967 var rs = this.regions;
34968 var north = rs["north"];
34969 var south = rs["south"];
34970 var west = rs["west"];
34971 var east = rs["east"];
34972 var center = rs["center"];
34973 //if(this.hideOnLayout){ // not supported anymore
34974 //c.el.setStyle("display", "none");
34976 if(north && north.isVisible()){
34977 var b = north.getBox();
34978 var m = north.getMargins();
34979 b.width = w - (m.left+m.right);
34982 centerY = b.height + b.y + m.bottom;
34983 centerH -= centerY;
34984 north.updateBox(this.safeBox(b));
34986 if(south && south.isVisible()){
34987 var b = south.getBox();
34988 var m = south.getMargins();
34989 b.width = w - (m.left+m.right);
34991 var totalHeight = (b.height + m.top + m.bottom);
34992 b.y = h - totalHeight + m.top;
34993 centerH -= totalHeight;
34994 south.updateBox(this.safeBox(b));
34996 if(west && west.isVisible()){
34997 var b = west.getBox();
34998 var m = west.getMargins();
34999 b.height = centerH - (m.top+m.bottom);
35001 b.y = centerY + m.top;
35002 var totalWidth = (b.width + m.left + m.right);
35003 centerX += totalWidth;
35004 centerW -= totalWidth;
35005 west.updateBox(this.safeBox(b));
35007 if(east && east.isVisible()){
35008 var b = east.getBox();
35009 var m = east.getMargins();
35010 b.height = centerH - (m.top+m.bottom);
35011 var totalWidth = (b.width + m.left + m.right);
35012 b.x = w - totalWidth + m.left;
35013 b.y = centerY + m.top;
35014 centerW -= totalWidth;
35015 east.updateBox(this.safeBox(b));
35018 var m = center.getMargins();
35020 x: centerX + m.left,
35021 y: centerY + m.top,
35022 width: centerW - (m.left+m.right),
35023 height: centerH - (m.top+m.bottom)
35025 //if(this.hideOnLayout){
35026 //center.el.setStyle("display", "block");
35028 center.updateBox(this.safeBox(centerBox));
35031 this.fireEvent("layout", this);
35035 safeBox : function(box){
35036 box.width = Math.max(0, box.width);
35037 box.height = Math.max(0, box.height);
35042 * Adds a ContentPanel (or subclass) to this layout.
35043 * @param {String} target The target region key (north, south, east, west or center).
35044 * @param {Roo.ContentPanel} panel The panel to add
35045 * @return {Roo.ContentPanel} The added panel
35047 add : function(target, panel){
35049 target = target.toLowerCase();
35050 return this.regions[target].add(panel);
35054 * Remove a ContentPanel (or subclass) to this layout.
35055 * @param {String} target The target region key (north, south, east, west or center).
35056 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
35057 * @return {Roo.ContentPanel} The removed panel
35059 remove : function(target, panel){
35060 target = target.toLowerCase();
35061 return this.regions[target].remove(panel);
35065 * Searches all regions for a panel with the specified id
35066 * @param {String} panelId
35067 * @return {Roo.ContentPanel} The panel or null if it wasn't found
35069 findPanel : function(panelId){
35070 var rs = this.regions;
35071 for(var target in rs){
35072 if(typeof rs[target] != "function"){
35073 var p = rs[target].getPanel(panelId);
35083 * Searches all regions for a panel with the specified id and activates (shows) it.
35084 * @param {String/ContentPanel} panelId The panels id or the panel itself
35085 * @return {Roo.ContentPanel} The shown panel or null
35087 showPanel : function(panelId) {
35088 var rs = this.regions;
35089 for(var target in rs){
35090 var r = rs[target];
35091 if(typeof r != "function"){
35092 if(r.hasPanel(panelId)){
35093 return r.showPanel(panelId);
35101 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
35102 * @param {Roo.state.Provider} provider (optional) An alternate state provider
35105 restoreState : function(provider){
35107 provider = Roo.state.Manager;
35109 var sm = new Roo.LayoutStateManager();
35110 sm.init(this, provider);
35116 * Adds a xtype elements to the layout.
35120 xtype : 'ContentPanel',
35127 xtype : 'NestedLayoutPanel',
35133 items : [ ... list of content panels or nested layout panels.. ]
35137 * @param {Object} cfg Xtype definition of item to add.
35139 addxtype : function(cfg)
35141 // basically accepts a pannel...
35142 // can accept a layout region..!?!?
35143 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
35146 // theory? children can only be panels??
35148 //if (!cfg.xtype.match(/Panel$/)) {
35153 if (typeof(cfg.region) == 'undefined') {
35154 Roo.log("Failed to add Panel, region was not set");
35158 var region = cfg.region;
35164 xitems = cfg.items;
35171 case 'Content': // ContentPanel (el, cfg)
35172 case 'Scroll': // ContentPanel (el, cfg)
35174 cfg.autoCreate = true;
35175 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35177 // var el = this.el.createChild();
35178 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
35181 this.add(region, ret);
35185 case 'TreePanel': // our new panel!
35186 cfg.el = this.el.createChild();
35187 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
35188 this.add(region, ret);
35193 // create a new Layout (which is a Border Layout...
35195 var clayout = cfg.layout;
35196 clayout.el = this.el.createChild();
35197 clayout.items = clayout.items || [];
35201 // replace this exitems with the clayout ones..
35202 xitems = clayout.items;
35204 // force background off if it's in center...
35205 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
35206 cfg.background = false;
35208 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
35211 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35212 //console.log('adding nested layout panel ' + cfg.toSource());
35213 this.add(region, ret);
35214 nb = {}; /// find first...
35219 // needs grid and region
35221 //var el = this.getRegion(region).el.createChild();
35223 *var el = this.el.createChild();
35224 // create the grid first...
35225 cfg.grid.container = el;
35226 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
35229 if (region == 'center' && this.active ) {
35230 cfg.background = false;
35233 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35235 this.add(region, ret);
35237 if (cfg.background) {
35238 // render grid on panel activation (if panel background)
35239 ret.on('activate', function(gp) {
35240 if (!gp.grid.rendered) {
35241 // gp.grid.render(el);
35245 // cfg.grid.render(el);
35251 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
35252 // it was the old xcomponent building that caused this before.
35253 // espeically if border is the top element in the tree.
35263 if (typeof(Roo[cfg.xtype]) != 'undefined') {
35265 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
35266 this.add(region, ret);
35270 throw "Can not add '" + cfg.xtype + "' to Border";
35276 this.beginUpdate();
35280 Roo.each(xitems, function(i) {
35281 region = nb && i.region ? i.region : false;
35283 var add = ret.addxtype(i);
35286 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
35287 if (!i.background) {
35288 abn[region] = nb[region] ;
35295 // make the last non-background panel active..
35296 //if (nb) { Roo.log(abn); }
35299 for(var r in abn) {
35300 region = this.getRegion(r);
35302 // tried using nb[r], but it does not work..
35304 region.showPanel(abn[r]);
35315 factory : function(cfg)
35318 var validRegions = Roo.bootstrap.layout.Border.regions;
35320 var target = cfg.region;
35323 var r = Roo.bootstrap.layout;
35327 return new r.North(cfg);
35329 return new r.South(cfg);
35331 return new r.East(cfg);
35333 return new r.West(cfg);
35335 return new r.Center(cfg);
35337 throw 'Layout region "'+target+'" not supported.';
35344 * Ext JS Library 1.1.1
35345 * Copyright(c) 2006-2007, Ext JS, LLC.
35347 * Originally Released Under LGPL - original licence link has changed is not relivant.
35350 * <script type="text/javascript">
35354 * @class Roo.bootstrap.layout.Basic
35355 * @extends Roo.util.Observable
35356 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
35357 * and does not have a titlebar, tabs or any other features. All it does is size and position
35358 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
35359 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35360 * @cfg {string} region the region that it inhabits..
35361 * @cfg {bool} skipConfig skip config?
35365 Roo.bootstrap.layout.Basic = function(config){
35367 this.mgr = config.mgr;
35369 this.position = config.region;
35371 var skipConfig = config.skipConfig;
35375 * @scope Roo.BasicLayoutRegion
35379 * @event beforeremove
35380 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
35381 * @param {Roo.LayoutRegion} this
35382 * @param {Roo.ContentPanel} panel The panel
35383 * @param {Object} e The cancel event object
35385 "beforeremove" : true,
35387 * @event invalidated
35388 * Fires when the layout for this region is changed.
35389 * @param {Roo.LayoutRegion} this
35391 "invalidated" : true,
35393 * @event visibilitychange
35394 * Fires when this region is shown or hidden
35395 * @param {Roo.LayoutRegion} this
35396 * @param {Boolean} visibility true or false
35398 "visibilitychange" : true,
35400 * @event paneladded
35401 * Fires when a panel is added.
35402 * @param {Roo.LayoutRegion} this
35403 * @param {Roo.ContentPanel} panel The panel
35405 "paneladded" : true,
35407 * @event panelremoved
35408 * Fires when a panel is removed.
35409 * @param {Roo.LayoutRegion} this
35410 * @param {Roo.ContentPanel} panel The panel
35412 "panelremoved" : true,
35414 * @event beforecollapse
35415 * Fires when this region before collapse.
35416 * @param {Roo.LayoutRegion} this
35418 "beforecollapse" : true,
35421 * Fires when this region is collapsed.
35422 * @param {Roo.LayoutRegion} this
35424 "collapsed" : true,
35427 * Fires when this region is expanded.
35428 * @param {Roo.LayoutRegion} this
35433 * Fires when this region is slid into view.
35434 * @param {Roo.LayoutRegion} this
35436 "slideshow" : true,
35439 * Fires when this region slides out of view.
35440 * @param {Roo.LayoutRegion} this
35442 "slidehide" : true,
35444 * @event panelactivated
35445 * Fires when a panel is activated.
35446 * @param {Roo.LayoutRegion} this
35447 * @param {Roo.ContentPanel} panel The activated panel
35449 "panelactivated" : true,
35452 * Fires when the user resizes this region.
35453 * @param {Roo.LayoutRegion} this
35454 * @param {Number} newSize The new size (width for east/west, height for north/south)
35458 /** A collection of panels in this region. @type Roo.util.MixedCollection */
35459 this.panels = new Roo.util.MixedCollection();
35460 this.panels.getKey = this.getPanelId.createDelegate(this);
35462 this.activePanel = null;
35463 // ensure listeners are added...
35465 if (config.listeners || config.events) {
35466 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
35467 listeners : config.listeners || {},
35468 events : config.events || {}
35472 if(skipConfig !== true){
35473 this.applyConfig(config);
35477 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
35479 getPanelId : function(p){
35483 applyConfig : function(config){
35484 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35485 this.config = config;
35490 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
35491 * the width, for horizontal (north, south) the height.
35492 * @param {Number} newSize The new width or height
35494 resizeTo : function(newSize){
35495 var el = this.el ? this.el :
35496 (this.activePanel ? this.activePanel.getEl() : null);
35498 switch(this.position){
35501 el.setWidth(newSize);
35502 this.fireEvent("resized", this, newSize);
35506 el.setHeight(newSize);
35507 this.fireEvent("resized", this, newSize);
35513 getBox : function(){
35514 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
35517 getMargins : function(){
35518 return this.margins;
35521 updateBox : function(box){
35523 var el = this.activePanel.getEl();
35524 el.dom.style.left = box.x + "px";
35525 el.dom.style.top = box.y + "px";
35526 this.activePanel.setSize(box.width, box.height);
35530 * Returns the container element for this region.
35531 * @return {Roo.Element}
35533 getEl : function(){
35534 return this.activePanel;
35538 * Returns true if this region is currently visible.
35539 * @return {Boolean}
35541 isVisible : function(){
35542 return this.activePanel ? true : false;
35545 setActivePanel : function(panel){
35546 panel = this.getPanel(panel);
35547 if(this.activePanel && this.activePanel != panel){
35548 this.activePanel.setActiveState(false);
35549 this.activePanel.getEl().setLeftTop(-10000,-10000);
35551 this.activePanel = panel;
35552 panel.setActiveState(true);
35554 panel.setSize(this.box.width, this.box.height);
35556 this.fireEvent("panelactivated", this, panel);
35557 this.fireEvent("invalidated");
35561 * Show the specified panel.
35562 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
35563 * @return {Roo.ContentPanel} The shown panel or null
35565 showPanel : function(panel){
35566 panel = this.getPanel(panel);
35568 this.setActivePanel(panel);
35574 * Get the active panel for this region.
35575 * @return {Roo.ContentPanel} The active panel or null
35577 getActivePanel : function(){
35578 return this.activePanel;
35582 * Add the passed ContentPanel(s)
35583 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35584 * @return {Roo.ContentPanel} The panel added (if only one was added)
35586 add : function(panel){
35587 if(arguments.length > 1){
35588 for(var i = 0, len = arguments.length; i < len; i++) {
35589 this.add(arguments[i]);
35593 if(this.hasPanel(panel)){
35594 this.showPanel(panel);
35597 var el = panel.getEl();
35598 if(el.dom.parentNode != this.mgr.el.dom){
35599 this.mgr.el.dom.appendChild(el.dom);
35601 if(panel.setRegion){
35602 panel.setRegion(this);
35604 this.panels.add(panel);
35605 el.setStyle("position", "absolute");
35606 if(!panel.background){
35607 this.setActivePanel(panel);
35608 if(this.config.initialSize && this.panels.getCount()==1){
35609 this.resizeTo(this.config.initialSize);
35612 this.fireEvent("paneladded", this, panel);
35617 * Returns true if the panel is in this region.
35618 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35619 * @return {Boolean}
35621 hasPanel : function(panel){
35622 if(typeof panel == "object"){ // must be panel obj
35623 panel = panel.getId();
35625 return this.getPanel(panel) ? true : false;
35629 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35630 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35631 * @param {Boolean} preservePanel Overrides the config preservePanel option
35632 * @return {Roo.ContentPanel} The panel that was removed
35634 remove : function(panel, preservePanel){
35635 panel = this.getPanel(panel);
35640 this.fireEvent("beforeremove", this, panel, e);
35641 if(e.cancel === true){
35644 var panelId = panel.getId();
35645 this.panels.removeKey(panelId);
35650 * Returns the panel specified or null if it's not in this region.
35651 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35652 * @return {Roo.ContentPanel}
35654 getPanel : function(id){
35655 if(typeof id == "object"){ // must be panel obj
35658 return this.panels.get(id);
35662 * Returns this regions position (north/south/east/west/center).
35665 getPosition: function(){
35666 return this.position;
35670 * Ext JS Library 1.1.1
35671 * Copyright(c) 2006-2007, Ext JS, LLC.
35673 * Originally Released Under LGPL - original licence link has changed is not relivant.
35676 * <script type="text/javascript">
35680 * @class Roo.bootstrap.layout.Region
35681 * @extends Roo.bootstrap.layout.Basic
35682 * This class represents a region in a layout manager.
35684 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
35685 * @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})
35686 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
35687 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
35688 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
35689 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
35690 * @cfg {String} title The title for the region (overrides panel titles)
35691 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
35692 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
35693 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
35694 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
35695 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
35696 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
35697 * the space available, similar to FireFox 1.5 tabs (defaults to false)
35698 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
35699 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
35700 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
35702 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
35703 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
35704 * @cfg {Boolean} disableTabTips True to disable tab tooltips
35705 * @cfg {Number} width For East/West panels
35706 * @cfg {Number} height For North/South panels
35707 * @cfg {Boolean} split To show the splitter
35708 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
35710 * @cfg {string} cls Extra CSS classes to add to region
35712 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35713 * @cfg {string} region the region that it inhabits..
35716 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
35717 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
35719 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
35720 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
35721 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
35723 Roo.bootstrap.layout.Region = function(config)
35725 this.applyConfig(config);
35727 var mgr = config.mgr;
35728 var pos = config.region;
35729 config.skipConfig = true;
35730 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
35733 this.onRender(mgr.el);
35736 this.visible = true;
35737 this.collapsed = false;
35738 this.unrendered_panels = [];
35741 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
35743 position: '', // set by wrapper (eg. north/south etc..)
35744 unrendered_panels : null, // unrendered panels.
35745 createBody : function(){
35746 /** This region's body element
35747 * @type Roo.Element */
35748 this.bodyEl = this.el.createChild({
35750 cls: "roo-layout-panel-body tab-content" // bootstrap added...
35754 onRender: function(ctr, pos)
35756 var dh = Roo.DomHelper;
35757 /** This region's container element
35758 * @type Roo.Element */
35759 this.el = dh.append(ctr.dom, {
35761 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
35763 /** This region's title element
35764 * @type Roo.Element */
35766 this.titleEl = dh.append(this.el.dom,
35769 unselectable: "on",
35770 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
35772 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
35773 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
35776 this.titleEl.enableDisplayMode();
35777 /** This region's title text element
35778 * @type HTMLElement */
35779 this.titleTextEl = this.titleEl.dom.firstChild;
35780 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
35782 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
35783 this.closeBtn.enableDisplayMode();
35784 this.closeBtn.on("click", this.closeClicked, this);
35785 this.closeBtn.hide();
35787 this.createBody(this.config);
35788 if(this.config.hideWhenEmpty){
35790 this.on("paneladded", this.validateVisibility, this);
35791 this.on("panelremoved", this.validateVisibility, this);
35793 if(this.autoScroll){
35794 this.bodyEl.setStyle("overflow", "auto");
35796 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
35798 //if(c.titlebar !== false){
35799 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
35800 this.titleEl.hide();
35802 this.titleEl.show();
35803 if(this.config.title){
35804 this.titleTextEl.innerHTML = this.config.title;
35808 if(this.config.collapsed){
35809 this.collapse(true);
35811 if(this.config.hidden){
35815 if (this.unrendered_panels && this.unrendered_panels.length) {
35816 for (var i =0;i< this.unrendered_panels.length; i++) {
35817 this.add(this.unrendered_panels[i]);
35819 this.unrendered_panels = null;
35825 applyConfig : function(c)
35828 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
35829 var dh = Roo.DomHelper;
35830 if(c.titlebar !== false){
35831 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
35832 this.collapseBtn.on("click", this.collapse, this);
35833 this.collapseBtn.enableDisplayMode();
35835 if(c.showPin === true || this.showPin){
35836 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
35837 this.stickBtn.enableDisplayMode();
35838 this.stickBtn.on("click", this.expand, this);
35839 this.stickBtn.hide();
35844 /** This region's collapsed element
35845 * @type Roo.Element */
35848 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
35849 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
35852 if(c.floatable !== false){
35853 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
35854 this.collapsedEl.on("click", this.collapseClick, this);
35857 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
35858 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
35859 id: "message", unselectable: "on", style:{"float":"left"}});
35860 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
35862 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
35863 this.expandBtn.on("click", this.expand, this);
35867 if(this.collapseBtn){
35868 this.collapseBtn.setVisible(c.collapsible == true);
35871 this.cmargins = c.cmargins || this.cmargins ||
35872 (this.position == "west" || this.position == "east" ?
35873 {top: 0, left: 2, right:2, bottom: 0} :
35874 {top: 2, left: 0, right:0, bottom: 2});
35876 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35879 this.bottomTabs = c.tabPosition != "top";
35881 this.autoScroll = c.autoScroll || false;
35886 this.duration = c.duration || .30;
35887 this.slideDuration = c.slideDuration || .45;
35892 * Returns true if this region is currently visible.
35893 * @return {Boolean}
35895 isVisible : function(){
35896 return this.visible;
35900 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
35901 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
35903 //setCollapsedTitle : function(title){
35904 // title = title || " ";
35905 // if(this.collapsedTitleTextEl){
35906 // this.collapsedTitleTextEl.innerHTML = title;
35910 getBox : function(){
35912 // if(!this.collapsed){
35913 b = this.el.getBox(false, true);
35915 // b = this.collapsedEl.getBox(false, true);
35920 getMargins : function(){
35921 return this.margins;
35922 //return this.collapsed ? this.cmargins : this.margins;
35925 highlight : function(){
35926 this.el.addClass("x-layout-panel-dragover");
35929 unhighlight : function(){
35930 this.el.removeClass("x-layout-panel-dragover");
35933 updateBox : function(box)
35935 if (!this.bodyEl) {
35936 return; // not rendered yet..
35940 if(!this.collapsed){
35941 this.el.dom.style.left = box.x + "px";
35942 this.el.dom.style.top = box.y + "px";
35943 this.updateBody(box.width, box.height);
35945 this.collapsedEl.dom.style.left = box.x + "px";
35946 this.collapsedEl.dom.style.top = box.y + "px";
35947 this.collapsedEl.setSize(box.width, box.height);
35950 this.tabs.autoSizeTabs();
35954 updateBody : function(w, h)
35957 this.el.setWidth(w);
35958 w -= this.el.getBorderWidth("rl");
35959 if(this.config.adjustments){
35960 w += this.config.adjustments[0];
35963 if(h !== null && h > 0){
35964 this.el.setHeight(h);
35965 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
35966 h -= this.el.getBorderWidth("tb");
35967 if(this.config.adjustments){
35968 h += this.config.adjustments[1];
35970 this.bodyEl.setHeight(h);
35972 h = this.tabs.syncHeight(h);
35975 if(this.panelSize){
35976 w = w !== null ? w : this.panelSize.width;
35977 h = h !== null ? h : this.panelSize.height;
35979 if(this.activePanel){
35980 var el = this.activePanel.getEl();
35981 w = w !== null ? w : el.getWidth();
35982 h = h !== null ? h : el.getHeight();
35983 this.panelSize = {width: w, height: h};
35984 this.activePanel.setSize(w, h);
35986 if(Roo.isIE && this.tabs){
35987 this.tabs.el.repaint();
35992 * Returns the container element for this region.
35993 * @return {Roo.Element}
35995 getEl : function(){
36000 * Hides this region.
36003 //if(!this.collapsed){
36004 this.el.dom.style.left = "-2000px";
36007 // this.collapsedEl.dom.style.left = "-2000px";
36008 // this.collapsedEl.hide();
36010 this.visible = false;
36011 this.fireEvent("visibilitychange", this, false);
36015 * Shows this region if it was previously hidden.
36018 //if(!this.collapsed){
36021 // this.collapsedEl.show();
36023 this.visible = true;
36024 this.fireEvent("visibilitychange", this, true);
36027 closeClicked : function(){
36028 if(this.activePanel){
36029 this.remove(this.activePanel);
36033 collapseClick : function(e){
36035 e.stopPropagation();
36038 e.stopPropagation();
36044 * Collapses this region.
36045 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
36048 collapse : function(skipAnim, skipCheck = false){
36049 if(this.collapsed) {
36053 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
36055 this.collapsed = true;
36057 this.split.el.hide();
36059 if(this.config.animate && skipAnim !== true){
36060 this.fireEvent("invalidated", this);
36061 this.animateCollapse();
36063 this.el.setLocation(-20000,-20000);
36065 this.collapsedEl.show();
36066 this.fireEvent("collapsed", this);
36067 this.fireEvent("invalidated", this);
36073 animateCollapse : function(){
36078 * Expands this region if it was previously collapsed.
36079 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
36080 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
36083 expand : function(e, skipAnim){
36085 e.stopPropagation();
36087 if(!this.collapsed || this.el.hasActiveFx()) {
36091 this.afterSlideIn();
36094 this.collapsed = false;
36095 if(this.config.animate && skipAnim !== true){
36096 this.animateExpand();
36100 this.split.el.show();
36102 this.collapsedEl.setLocation(-2000,-2000);
36103 this.collapsedEl.hide();
36104 this.fireEvent("invalidated", this);
36105 this.fireEvent("expanded", this);
36109 animateExpand : function(){
36113 initTabs : function()
36115 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
36117 var ts = new Roo.bootstrap.panel.Tabs({
36118 el: this.bodyEl.dom,
36119 tabPosition: this.bottomTabs ? 'bottom' : 'top',
36120 disableTooltips: this.config.disableTabTips,
36121 toolbar : this.config.toolbar
36124 if(this.config.hideTabs){
36125 ts.stripWrap.setDisplayed(false);
36128 ts.resizeTabs = this.config.resizeTabs === true;
36129 ts.minTabWidth = this.config.minTabWidth || 40;
36130 ts.maxTabWidth = this.config.maxTabWidth || 250;
36131 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
36132 ts.monitorResize = false;
36133 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
36134 ts.bodyEl.addClass('roo-layout-tabs-body');
36135 this.panels.each(this.initPanelAsTab, this);
36138 initPanelAsTab : function(panel){
36139 var ti = this.tabs.addTab(
36143 this.config.closeOnTab && panel.isClosable(),
36146 if(panel.tabTip !== undefined){
36147 ti.setTooltip(panel.tabTip);
36149 ti.on("activate", function(){
36150 this.setActivePanel(panel);
36153 if(this.config.closeOnTab){
36154 ti.on("beforeclose", function(t, e){
36156 this.remove(panel);
36160 panel.tabItem = ti;
36165 updatePanelTitle : function(panel, title)
36167 if(this.activePanel == panel){
36168 this.updateTitle(title);
36171 var ti = this.tabs.getTab(panel.getEl().id);
36173 if(panel.tabTip !== undefined){
36174 ti.setTooltip(panel.tabTip);
36179 updateTitle : function(title){
36180 if(this.titleTextEl && !this.config.title){
36181 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
36185 setActivePanel : function(panel)
36187 panel = this.getPanel(panel);
36188 if(this.activePanel && this.activePanel != panel){
36189 if(this.activePanel.setActiveState(false) === false){
36193 this.activePanel = panel;
36194 panel.setActiveState(true);
36195 if(this.panelSize){
36196 panel.setSize(this.panelSize.width, this.panelSize.height);
36199 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
36201 this.updateTitle(panel.getTitle());
36203 this.fireEvent("invalidated", this);
36205 this.fireEvent("panelactivated", this, panel);
36209 * Shows the specified panel.
36210 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
36211 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
36213 showPanel : function(panel)
36215 panel = this.getPanel(panel);
36218 var tab = this.tabs.getTab(panel.getEl().id);
36219 if(tab.isHidden()){
36220 this.tabs.unhideTab(tab.id);
36224 this.setActivePanel(panel);
36231 * Get the active panel for this region.
36232 * @return {Roo.ContentPanel} The active panel or null
36234 getActivePanel : function(){
36235 return this.activePanel;
36238 validateVisibility : function(){
36239 if(this.panels.getCount() < 1){
36240 this.updateTitle(" ");
36241 this.closeBtn.hide();
36244 if(!this.isVisible()){
36251 * Adds the passed ContentPanel(s) to this region.
36252 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
36253 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
36255 add : function(panel)
36257 if(arguments.length > 1){
36258 for(var i = 0, len = arguments.length; i < len; i++) {
36259 this.add(arguments[i]);
36264 // if we have not been rendered yet, then we can not really do much of this..
36265 if (!this.bodyEl) {
36266 this.unrendered_panels.push(panel);
36273 if(this.hasPanel(panel)){
36274 this.showPanel(panel);
36277 panel.setRegion(this);
36278 this.panels.add(panel);
36279 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
36280 // sinle panel - no tab...?? would it not be better to render it with the tabs,
36281 // and hide them... ???
36282 this.bodyEl.dom.appendChild(panel.getEl().dom);
36283 if(panel.background !== true){
36284 this.setActivePanel(panel);
36286 this.fireEvent("paneladded", this, panel);
36293 this.initPanelAsTab(panel);
36297 if(panel.background !== true){
36298 this.tabs.activate(panel.getEl().id);
36300 this.fireEvent("paneladded", this, panel);
36305 * Hides the tab for the specified panel.
36306 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36308 hidePanel : function(panel){
36309 if(this.tabs && (panel = this.getPanel(panel))){
36310 this.tabs.hideTab(panel.getEl().id);
36315 * Unhides the tab for a previously hidden panel.
36316 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36318 unhidePanel : function(panel){
36319 if(this.tabs && (panel = this.getPanel(panel))){
36320 this.tabs.unhideTab(panel.getEl().id);
36324 clearPanels : function(){
36325 while(this.panels.getCount() > 0){
36326 this.remove(this.panels.first());
36331 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
36332 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36333 * @param {Boolean} preservePanel Overrides the config preservePanel option
36334 * @return {Roo.ContentPanel} The panel that was removed
36336 remove : function(panel, preservePanel)
36338 panel = this.getPanel(panel);
36343 this.fireEvent("beforeremove", this, panel, e);
36344 if(e.cancel === true){
36347 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
36348 var panelId = panel.getId();
36349 this.panels.removeKey(panelId);
36351 document.body.appendChild(panel.getEl().dom);
36354 this.tabs.removeTab(panel.getEl().id);
36355 }else if (!preservePanel){
36356 this.bodyEl.dom.removeChild(panel.getEl().dom);
36358 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
36359 var p = this.panels.first();
36360 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
36361 tempEl.appendChild(p.getEl().dom);
36362 this.bodyEl.update("");
36363 this.bodyEl.dom.appendChild(p.getEl().dom);
36365 this.updateTitle(p.getTitle());
36367 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
36368 this.setActivePanel(p);
36370 panel.setRegion(null);
36371 if(this.activePanel == panel){
36372 this.activePanel = null;
36374 if(this.config.autoDestroy !== false && preservePanel !== true){
36375 try{panel.destroy();}catch(e){}
36377 this.fireEvent("panelremoved", this, panel);
36382 * Returns the TabPanel component used by this region
36383 * @return {Roo.TabPanel}
36385 getTabs : function(){
36389 createTool : function(parentEl, className){
36390 var btn = Roo.DomHelper.append(parentEl, {
36392 cls: "x-layout-tools-button",
36395 cls: "roo-layout-tools-button-inner " + className,
36399 btn.addClassOnOver("roo-layout-tools-button-over");
36404 * Ext JS Library 1.1.1
36405 * Copyright(c) 2006-2007, Ext JS, LLC.
36407 * Originally Released Under LGPL - original licence link has changed is not relivant.
36410 * <script type="text/javascript">
36416 * @class Roo.SplitLayoutRegion
36417 * @extends Roo.LayoutRegion
36418 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
36420 Roo.bootstrap.layout.Split = function(config){
36421 this.cursor = config.cursor;
36422 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
36425 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
36427 splitTip : "Drag to resize.",
36428 collapsibleSplitTip : "Drag to resize. Double click to hide.",
36429 useSplitTips : false,
36431 applyConfig : function(config){
36432 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
36435 onRender : function(ctr,pos) {
36437 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
36438 if(!this.config.split){
36443 var splitEl = Roo.DomHelper.append(ctr.dom, {
36445 id: this.el.id + "-split",
36446 cls: "roo-layout-split roo-layout-split-"+this.position,
36449 /** The SplitBar for this region
36450 * @type Roo.SplitBar */
36451 // does not exist yet...
36452 Roo.log([this.position, this.orientation]);
36454 this.split = new Roo.bootstrap.SplitBar({
36455 dragElement : splitEl,
36456 resizingElement: this.el,
36457 orientation : this.orientation
36460 this.split.on("moved", this.onSplitMove, this);
36461 this.split.useShim = this.config.useShim === true;
36462 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
36463 if(this.useSplitTips){
36464 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
36466 //if(config.collapsible){
36467 // this.split.el.on("dblclick", this.collapse, this);
36470 if(typeof this.config.minSize != "undefined"){
36471 this.split.minSize = this.config.minSize;
36473 if(typeof this.config.maxSize != "undefined"){
36474 this.split.maxSize = this.config.maxSize;
36476 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
36477 this.hideSplitter();
36482 getHMaxSize : function(){
36483 var cmax = this.config.maxSize || 10000;
36484 var center = this.mgr.getRegion("center");
36485 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
36488 getVMaxSize : function(){
36489 var cmax = this.config.maxSize || 10000;
36490 var center = this.mgr.getRegion("center");
36491 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
36494 onSplitMove : function(split, newSize){
36495 this.fireEvent("resized", this, newSize);
36499 * Returns the {@link Roo.SplitBar} for this region.
36500 * @return {Roo.SplitBar}
36502 getSplitBar : function(){
36507 this.hideSplitter();
36508 Roo.bootstrap.layout.Split.superclass.hide.call(this);
36511 hideSplitter : function(){
36513 this.split.el.setLocation(-2000,-2000);
36514 this.split.el.hide();
36520 this.split.el.show();
36522 Roo.bootstrap.layout.Split.superclass.show.call(this);
36525 beforeSlide: function(){
36526 if(Roo.isGecko){// firefox overflow auto bug workaround
36527 this.bodyEl.clip();
36529 this.tabs.bodyEl.clip();
36531 if(this.activePanel){
36532 this.activePanel.getEl().clip();
36534 if(this.activePanel.beforeSlide){
36535 this.activePanel.beforeSlide();
36541 afterSlide : function(){
36542 if(Roo.isGecko){// firefox overflow auto bug workaround
36543 this.bodyEl.unclip();
36545 this.tabs.bodyEl.unclip();
36547 if(this.activePanel){
36548 this.activePanel.getEl().unclip();
36549 if(this.activePanel.afterSlide){
36550 this.activePanel.afterSlide();
36556 initAutoHide : function(){
36557 if(this.autoHide !== false){
36558 if(!this.autoHideHd){
36559 var st = new Roo.util.DelayedTask(this.slideIn, this);
36560 this.autoHideHd = {
36561 "mouseout": function(e){
36562 if(!e.within(this.el, true)){
36566 "mouseover" : function(e){
36572 this.el.on(this.autoHideHd);
36576 clearAutoHide : function(){
36577 if(this.autoHide !== false){
36578 this.el.un("mouseout", this.autoHideHd.mouseout);
36579 this.el.un("mouseover", this.autoHideHd.mouseover);
36583 clearMonitor : function(){
36584 Roo.get(document).un("click", this.slideInIf, this);
36587 // these names are backwards but not changed for compat
36588 slideOut : function(){
36589 if(this.isSlid || this.el.hasActiveFx()){
36592 this.isSlid = true;
36593 if(this.collapseBtn){
36594 this.collapseBtn.hide();
36596 this.closeBtnState = this.closeBtn.getStyle('display');
36597 this.closeBtn.hide();
36599 this.stickBtn.show();
36602 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
36603 this.beforeSlide();
36604 this.el.setStyle("z-index", 10001);
36605 this.el.slideIn(this.getSlideAnchor(), {
36606 callback: function(){
36608 this.initAutoHide();
36609 Roo.get(document).on("click", this.slideInIf, this);
36610 this.fireEvent("slideshow", this);
36617 afterSlideIn : function(){
36618 this.clearAutoHide();
36619 this.isSlid = false;
36620 this.clearMonitor();
36621 this.el.setStyle("z-index", "");
36622 if(this.collapseBtn){
36623 this.collapseBtn.show();
36625 this.closeBtn.setStyle('display', this.closeBtnState);
36627 this.stickBtn.hide();
36629 this.fireEvent("slidehide", this);
36632 slideIn : function(cb){
36633 if(!this.isSlid || this.el.hasActiveFx()){
36637 this.isSlid = false;
36638 this.beforeSlide();
36639 this.el.slideOut(this.getSlideAnchor(), {
36640 callback: function(){
36641 this.el.setLeftTop(-10000, -10000);
36643 this.afterSlideIn();
36651 slideInIf : function(e){
36652 if(!e.within(this.el)){
36657 animateCollapse : function(){
36658 this.beforeSlide();
36659 this.el.setStyle("z-index", 20000);
36660 var anchor = this.getSlideAnchor();
36661 this.el.slideOut(anchor, {
36662 callback : function(){
36663 this.el.setStyle("z-index", "");
36664 this.collapsedEl.slideIn(anchor, {duration:.3});
36666 this.el.setLocation(-10000,-10000);
36668 this.fireEvent("collapsed", this);
36675 animateExpand : function(){
36676 this.beforeSlide();
36677 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
36678 this.el.setStyle("z-index", 20000);
36679 this.collapsedEl.hide({
36682 this.el.slideIn(this.getSlideAnchor(), {
36683 callback : function(){
36684 this.el.setStyle("z-index", "");
36687 this.split.el.show();
36689 this.fireEvent("invalidated", this);
36690 this.fireEvent("expanded", this);
36718 getAnchor : function(){
36719 return this.anchors[this.position];
36722 getCollapseAnchor : function(){
36723 return this.canchors[this.position];
36726 getSlideAnchor : function(){
36727 return this.sanchors[this.position];
36730 getAlignAdj : function(){
36731 var cm = this.cmargins;
36732 switch(this.position){
36748 getExpandAdj : function(){
36749 var c = this.collapsedEl, cm = this.cmargins;
36750 switch(this.position){
36752 return [-(cm.right+c.getWidth()+cm.left), 0];
36755 return [cm.right+c.getWidth()+cm.left, 0];
36758 return [0, -(cm.top+cm.bottom+c.getHeight())];
36761 return [0, cm.top+cm.bottom+c.getHeight()];
36767 * Ext JS Library 1.1.1
36768 * Copyright(c) 2006-2007, Ext JS, LLC.
36770 * Originally Released Under LGPL - original licence link has changed is not relivant.
36773 * <script type="text/javascript">
36776 * These classes are private internal classes
36778 Roo.bootstrap.layout.Center = function(config){
36779 config.region = "center";
36780 Roo.bootstrap.layout.Region.call(this, config);
36781 this.visible = true;
36782 this.minWidth = config.minWidth || 20;
36783 this.minHeight = config.minHeight || 20;
36786 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
36788 // center panel can't be hidden
36792 // center panel can't be hidden
36795 getMinWidth: function(){
36796 return this.minWidth;
36799 getMinHeight: function(){
36800 return this.minHeight;
36813 Roo.bootstrap.layout.North = function(config)
36815 config.region = 'north';
36816 config.cursor = 'n-resize';
36818 Roo.bootstrap.layout.Split.call(this, config);
36822 this.split.placement = Roo.bootstrap.SplitBar.TOP;
36823 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36824 this.split.el.addClass("roo-layout-split-v");
36826 var size = config.initialSize || config.height;
36827 if(typeof size != "undefined"){
36828 this.el.setHeight(size);
36831 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
36833 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36837 getBox : function(){
36838 if(this.collapsed){
36839 return this.collapsedEl.getBox();
36841 var box = this.el.getBox();
36843 box.height += this.split.el.getHeight();
36848 updateBox : function(box){
36849 if(this.split && !this.collapsed){
36850 box.height -= this.split.el.getHeight();
36851 this.split.el.setLeft(box.x);
36852 this.split.el.setTop(box.y+box.height);
36853 this.split.el.setWidth(box.width);
36855 if(this.collapsed){
36856 this.updateBody(box.width, null);
36858 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36866 Roo.bootstrap.layout.South = function(config){
36867 config.region = 'south';
36868 config.cursor = 's-resize';
36869 Roo.bootstrap.layout.Split.call(this, config);
36871 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
36872 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36873 this.split.el.addClass("roo-layout-split-v");
36875 var size = config.initialSize || config.height;
36876 if(typeof size != "undefined"){
36877 this.el.setHeight(size);
36881 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
36882 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36883 getBox : function(){
36884 if(this.collapsed){
36885 return this.collapsedEl.getBox();
36887 var box = this.el.getBox();
36889 var sh = this.split.el.getHeight();
36896 updateBox : function(box){
36897 if(this.split && !this.collapsed){
36898 var sh = this.split.el.getHeight();
36901 this.split.el.setLeft(box.x);
36902 this.split.el.setTop(box.y-sh);
36903 this.split.el.setWidth(box.width);
36905 if(this.collapsed){
36906 this.updateBody(box.width, null);
36908 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36912 Roo.bootstrap.layout.East = function(config){
36913 config.region = "east";
36914 config.cursor = "e-resize";
36915 Roo.bootstrap.layout.Split.call(this, config);
36917 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
36918 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36919 this.split.el.addClass("roo-layout-split-h");
36921 var size = config.initialSize || config.width;
36922 if(typeof size != "undefined"){
36923 this.el.setWidth(size);
36926 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
36927 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36928 getBox : function(){
36929 if(this.collapsed){
36930 return this.collapsedEl.getBox();
36932 var box = this.el.getBox();
36934 var sw = this.split.el.getWidth();
36941 updateBox : function(box){
36942 if(this.split && !this.collapsed){
36943 var sw = this.split.el.getWidth();
36945 this.split.el.setLeft(box.x);
36946 this.split.el.setTop(box.y);
36947 this.split.el.setHeight(box.height);
36950 if(this.collapsed){
36951 this.updateBody(null, box.height);
36953 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36957 Roo.bootstrap.layout.West = function(config){
36958 config.region = "west";
36959 config.cursor = "w-resize";
36961 Roo.bootstrap.layout.Split.call(this, config);
36963 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
36964 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36965 this.split.el.addClass("roo-layout-split-h");
36969 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
36970 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36972 onRender: function(ctr, pos)
36974 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
36975 var size = this.config.initialSize || this.config.width;
36976 if(typeof size != "undefined"){
36977 this.el.setWidth(size);
36981 getBox : function(){
36982 if(this.collapsed){
36983 return this.collapsedEl.getBox();
36985 var box = this.el.getBox();
36987 box.width += this.split.el.getWidth();
36992 updateBox : function(box){
36993 if(this.split && !this.collapsed){
36994 var sw = this.split.el.getWidth();
36996 this.split.el.setLeft(box.x+box.width);
36997 this.split.el.setTop(box.y);
36998 this.split.el.setHeight(box.height);
37000 if(this.collapsed){
37001 this.updateBody(null, box.height);
37003 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37006 Roo.namespace("Roo.bootstrap.panel");/*
37008 * Ext JS Library 1.1.1
37009 * Copyright(c) 2006-2007, Ext JS, LLC.
37011 * Originally Released Under LGPL - original licence link has changed is not relivant.
37014 * <script type="text/javascript">
37017 * @class Roo.ContentPanel
37018 * @extends Roo.util.Observable
37019 * A basic ContentPanel element.
37020 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
37021 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
37022 * @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
37023 * @cfg {Boolean} closable True if the panel can be closed/removed
37024 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
37025 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
37026 * @cfg {Toolbar} toolbar A toolbar for this panel
37027 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
37028 * @cfg {String} title The title for this panel
37029 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
37030 * @cfg {String} url Calls {@link #setUrl} with this value
37031 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
37032 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
37033 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
37034 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
37035 * @cfg {Boolean} badges render the badges
37038 * Create a new ContentPanel.
37039 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
37040 * @param {String/Object} config A string to set only the title or a config object
37041 * @param {String} content (optional) Set the HTML content for this panel
37042 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
37044 Roo.bootstrap.panel.Content = function( config){
37046 this.tpl = config.tpl || false;
37048 var el = config.el;
37049 var content = config.content;
37051 if(config.autoCreate){ // xtype is available if this is called from factory
37054 this.el = Roo.get(el);
37055 if(!this.el && config && config.autoCreate){
37056 if(typeof config.autoCreate == "object"){
37057 if(!config.autoCreate.id){
37058 config.autoCreate.id = config.id||el;
37060 this.el = Roo.DomHelper.append(document.body,
37061 config.autoCreate, true);
37063 var elcfg = { tag: "div",
37064 cls: "roo-layout-inactive-content",
37068 elcfg.html = config.html;
37072 this.el = Roo.DomHelper.append(document.body, elcfg , true);
37075 this.closable = false;
37076 this.loaded = false;
37077 this.active = false;
37080 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
37082 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
37084 this.wrapEl = this.el; //this.el.wrap();
37086 if (config.toolbar.items) {
37087 ti = config.toolbar.items ;
37088 delete config.toolbar.items ;
37092 this.toolbar.render(this.wrapEl, 'before');
37093 for(var i =0;i < ti.length;i++) {
37094 // Roo.log(['add child', items[i]]);
37095 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37097 this.toolbar.items = nitems;
37098 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
37099 delete config.toolbar;
37103 // xtype created footer. - not sure if will work as we normally have to render first..
37104 if (this.footer && !this.footer.el && this.footer.xtype) {
37105 if (!this.wrapEl) {
37106 this.wrapEl = this.el.wrap();
37109 this.footer.container = this.wrapEl.createChild();
37111 this.footer = Roo.factory(this.footer, Roo);
37116 if(typeof config == "string"){
37117 this.title = config;
37119 Roo.apply(this, config);
37123 this.resizeEl = Roo.get(this.resizeEl, true);
37125 this.resizeEl = this.el;
37127 // handle view.xtype
37135 * Fires when this panel is activated.
37136 * @param {Roo.ContentPanel} this
37140 * @event deactivate
37141 * Fires when this panel is activated.
37142 * @param {Roo.ContentPanel} this
37144 "deactivate" : true,
37148 * Fires when this panel is resized if fitToFrame is true.
37149 * @param {Roo.ContentPanel} this
37150 * @param {Number} width The width after any component adjustments
37151 * @param {Number} height The height after any component adjustments
37157 * Fires when this tab is created
37158 * @param {Roo.ContentPanel} this
37169 if(this.autoScroll){
37170 this.resizeEl.setStyle("overflow", "auto");
37172 // fix randome scrolling
37173 //this.el.on('scroll', function() {
37174 // Roo.log('fix random scolling');
37175 // this.scrollTo('top',0);
37178 content = content || this.content;
37180 this.setContent(content);
37182 if(config && config.url){
37183 this.setUrl(this.url, this.params, this.loadOnce);
37188 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
37190 if (this.view && typeof(this.view.xtype) != 'undefined') {
37191 this.view.el = this.el.appendChild(document.createElement("div"));
37192 this.view = Roo.factory(this.view);
37193 this.view.render && this.view.render(false, '');
37197 this.fireEvent('render', this);
37200 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
37204 setRegion : function(region){
37205 this.region = region;
37206 this.setActiveClass(region && !this.background);
37210 setActiveClass: function(state)
37213 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
37214 this.el.setStyle('position','relative');
37216 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
37217 this.el.setStyle('position', 'absolute');
37222 * Returns the toolbar for this Panel if one was configured.
37223 * @return {Roo.Toolbar}
37225 getToolbar : function(){
37226 return this.toolbar;
37229 setActiveState : function(active)
37231 this.active = active;
37232 this.setActiveClass(active);
37234 if(this.fireEvent("deactivate", this) === false){
37239 this.fireEvent("activate", this);
37243 * Updates this panel's element
37244 * @param {String} content The new content
37245 * @param {Boolean} loadScripts (optional) true to look for and process scripts
37247 setContent : function(content, loadScripts){
37248 this.el.update(content, loadScripts);
37251 ignoreResize : function(w, h){
37252 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
37255 this.lastSize = {width: w, height: h};
37260 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
37261 * @return {Roo.UpdateManager} The UpdateManager
37263 getUpdateManager : function(){
37264 return this.el.getUpdateManager();
37267 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
37268 * @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:
37271 url: "your-url.php",
37272 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
37273 callback: yourFunction,
37274 scope: yourObject, //(optional scope)
37277 text: "Loading...",
37282 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
37283 * 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.
37284 * @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}
37285 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
37286 * @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.
37287 * @return {Roo.ContentPanel} this
37290 var um = this.el.getUpdateManager();
37291 um.update.apply(um, arguments);
37297 * 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.
37298 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
37299 * @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)
37300 * @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)
37301 * @return {Roo.UpdateManager} The UpdateManager
37303 setUrl : function(url, params, loadOnce){
37304 if(this.refreshDelegate){
37305 this.removeListener("activate", this.refreshDelegate);
37307 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
37308 this.on("activate", this.refreshDelegate);
37309 return this.el.getUpdateManager();
37312 _handleRefresh : function(url, params, loadOnce){
37313 if(!loadOnce || !this.loaded){
37314 var updater = this.el.getUpdateManager();
37315 updater.update(url, params, this._setLoaded.createDelegate(this));
37319 _setLoaded : function(){
37320 this.loaded = true;
37324 * Returns this panel's id
37327 getId : function(){
37332 * Returns this panel's element - used by regiosn to add.
37333 * @return {Roo.Element}
37335 getEl : function(){
37336 return this.wrapEl || this.el;
37341 adjustForComponents : function(width, height)
37343 //Roo.log('adjustForComponents ');
37344 if(this.resizeEl != this.el){
37345 width -= this.el.getFrameWidth('lr');
37346 height -= this.el.getFrameWidth('tb');
37349 var te = this.toolbar.getEl();
37350 te.setWidth(width);
37351 height -= te.getHeight();
37354 var te = this.footer.getEl();
37355 te.setWidth(width);
37356 height -= te.getHeight();
37360 if(this.adjustments){
37361 width += this.adjustments[0];
37362 height += this.adjustments[1];
37364 return {"width": width, "height": height};
37367 setSize : function(width, height){
37368 if(this.fitToFrame && !this.ignoreResize(width, height)){
37369 if(this.fitContainer && this.resizeEl != this.el){
37370 this.el.setSize(width, height);
37372 var size = this.adjustForComponents(width, height);
37373 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
37374 this.fireEvent('resize', this, size.width, size.height);
37379 * Returns this panel's title
37382 getTitle : function(){
37384 if (typeof(this.title) != 'object') {
37389 for (var k in this.title) {
37390 if (!this.title.hasOwnProperty(k)) {
37394 if (k.indexOf('-') >= 0) {
37395 var s = k.split('-');
37396 for (var i = 0; i<s.length; i++) {
37397 t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
37400 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
37407 * Set this panel's title
37408 * @param {String} title
37410 setTitle : function(title){
37411 this.title = title;
37413 this.region.updatePanelTitle(this, title);
37418 * Returns true is this panel was configured to be closable
37419 * @return {Boolean}
37421 isClosable : function(){
37422 return this.closable;
37425 beforeSlide : function(){
37427 this.resizeEl.clip();
37430 afterSlide : function(){
37432 this.resizeEl.unclip();
37436 * Force a content refresh from the URL specified in the {@link #setUrl} method.
37437 * Will fail silently if the {@link #setUrl} method has not been called.
37438 * This does not activate the panel, just updates its content.
37440 refresh : function(){
37441 if(this.refreshDelegate){
37442 this.loaded = false;
37443 this.refreshDelegate();
37448 * Destroys this panel
37450 destroy : function(){
37451 this.el.removeAllListeners();
37452 var tempEl = document.createElement("span");
37453 tempEl.appendChild(this.el.dom);
37454 tempEl.innerHTML = "";
37460 * form - if the content panel contains a form - this is a reference to it.
37461 * @type {Roo.form.Form}
37465 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
37466 * This contains a reference to it.
37472 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
37482 * @param {Object} cfg Xtype definition of item to add.
37486 getChildContainer: function () {
37487 return this.getEl();
37492 var ret = new Roo.factory(cfg);
37497 if (cfg.xtype.match(/^Form$/)) {
37500 //if (this.footer) {
37501 // el = this.footer.container.insertSibling(false, 'before');
37503 el = this.el.createChild();
37506 this.form = new Roo.form.Form(cfg);
37509 if ( this.form.allItems.length) {
37510 this.form.render(el.dom);
37514 // should only have one of theses..
37515 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
37516 // views.. should not be just added - used named prop 'view''
37518 cfg.el = this.el.appendChild(document.createElement("div"));
37521 var ret = new Roo.factory(cfg);
37523 ret.render && ret.render(false, ''); // render blank..
37533 * @class Roo.bootstrap.panel.Grid
37534 * @extends Roo.bootstrap.panel.Content
37536 * Create a new GridPanel.
37537 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
37538 * @param {Object} config A the config object
37544 Roo.bootstrap.panel.Grid = function(config)
37548 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
37549 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
37551 config.el = this.wrapper;
37552 //this.el = this.wrapper;
37554 if (config.container) {
37555 // ctor'ed from a Border/panel.grid
37558 this.wrapper.setStyle("overflow", "hidden");
37559 this.wrapper.addClass('roo-grid-container');
37564 if(config.toolbar){
37565 var tool_el = this.wrapper.createChild();
37566 this.toolbar = Roo.factory(config.toolbar);
37568 if (config.toolbar.items) {
37569 ti = config.toolbar.items ;
37570 delete config.toolbar.items ;
37574 this.toolbar.render(tool_el);
37575 for(var i =0;i < ti.length;i++) {
37576 // Roo.log(['add child', items[i]]);
37577 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37579 this.toolbar.items = nitems;
37581 delete config.toolbar;
37584 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
37585 config.grid.scrollBody = true;;
37586 config.grid.monitorWindowResize = false; // turn off autosizing
37587 config.grid.autoHeight = false;
37588 config.grid.autoWidth = false;
37590 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
37592 if (config.background) {
37593 // render grid on panel activation (if panel background)
37594 this.on('activate', function(gp) {
37595 if (!gp.grid.rendered) {
37596 gp.grid.render(this.wrapper);
37597 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37602 this.grid.render(this.wrapper);
37603 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37606 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
37607 // ??? needed ??? config.el = this.wrapper;
37612 // xtype created footer. - not sure if will work as we normally have to render first..
37613 if (this.footer && !this.footer.el && this.footer.xtype) {
37615 var ctr = this.grid.getView().getFooterPanel(true);
37616 this.footer.dataSource = this.grid.dataSource;
37617 this.footer = Roo.factory(this.footer, Roo);
37618 this.footer.render(ctr);
37628 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
37629 getId : function(){
37630 return this.grid.id;
37634 * Returns the grid for this panel
37635 * @return {Roo.bootstrap.Table}
37637 getGrid : function(){
37641 setSize : function(width, height){
37642 if(!this.ignoreResize(width, height)){
37643 var grid = this.grid;
37644 var size = this.adjustForComponents(width, height);
37645 var gridel = grid.getGridEl();
37646 gridel.setSize(size.width, size.height);
37648 var thd = grid.getGridEl().select('thead',true).first();
37649 var tbd = grid.getGridEl().select('tbody', true).first();
37651 tbd.setSize(width, height - thd.getHeight());
37660 beforeSlide : function(){
37661 this.grid.getView().scroller.clip();
37664 afterSlide : function(){
37665 this.grid.getView().scroller.unclip();
37668 destroy : function(){
37669 this.grid.destroy();
37671 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
37676 * @class Roo.bootstrap.panel.Nest
37677 * @extends Roo.bootstrap.panel.Content
37679 * Create a new Panel, that can contain a layout.Border.
37682 * @param {Roo.BorderLayout} layout The layout for this panel
37683 * @param {String/Object} config A string to set only the title or a config object
37685 Roo.bootstrap.panel.Nest = function(config)
37687 // construct with only one argument..
37688 /* FIXME - implement nicer consturctors
37689 if (layout.layout) {
37691 layout = config.layout;
37692 delete config.layout;
37694 if (layout.xtype && !layout.getEl) {
37695 // then layout needs constructing..
37696 layout = Roo.factory(layout, Roo);
37700 config.el = config.layout.getEl();
37702 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
37704 config.layout.monitorWindowResize = false; // turn off autosizing
37705 this.layout = config.layout;
37706 this.layout.getEl().addClass("roo-layout-nested-layout");
37713 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
37715 setSize : function(width, height){
37716 if(!this.ignoreResize(width, height)){
37717 var size = this.adjustForComponents(width, height);
37718 var el = this.layout.getEl();
37719 if (size.height < 1) {
37720 el.setWidth(size.width);
37722 el.setSize(size.width, size.height);
37724 var touch = el.dom.offsetWidth;
37725 this.layout.layout();
37726 // ie requires a double layout on the first pass
37727 if(Roo.isIE && !this.initialized){
37728 this.initialized = true;
37729 this.layout.layout();
37734 // activate all subpanels if not currently active..
37736 setActiveState : function(active){
37737 this.active = active;
37738 this.setActiveClass(active);
37741 this.fireEvent("deactivate", this);
37745 this.fireEvent("activate", this);
37746 // not sure if this should happen before or after..
37747 if (!this.layout) {
37748 return; // should not happen..
37751 for (var r in this.layout.regions) {
37752 reg = this.layout.getRegion(r);
37753 if (reg.getActivePanel()) {
37754 //reg.showPanel(reg.getActivePanel()); // force it to activate..
37755 reg.setActivePanel(reg.getActivePanel());
37758 if (!reg.panels.length) {
37761 reg.showPanel(reg.getPanel(0));
37770 * Returns the nested BorderLayout for this panel
37771 * @return {Roo.BorderLayout}
37773 getLayout : function(){
37774 return this.layout;
37778 * Adds a xtype elements to the layout of the nested panel
37782 xtype : 'ContentPanel',
37789 xtype : 'NestedLayoutPanel',
37795 items : [ ... list of content panels or nested layout panels.. ]
37799 * @param {Object} cfg Xtype definition of item to add.
37801 addxtype : function(cfg) {
37802 return this.layout.addxtype(cfg);
37807 * Ext JS Library 1.1.1
37808 * Copyright(c) 2006-2007, Ext JS, LLC.
37810 * Originally Released Under LGPL - original licence link has changed is not relivant.
37813 * <script type="text/javascript">
37816 * @class Roo.TabPanel
37817 * @extends Roo.util.Observable
37818 * A lightweight tab container.
37822 // basic tabs 1, built from existing content
37823 var tabs = new Roo.TabPanel("tabs1");
37824 tabs.addTab("script", "View Script");
37825 tabs.addTab("markup", "View Markup");
37826 tabs.activate("script");
37828 // more advanced tabs, built from javascript
37829 var jtabs = new Roo.TabPanel("jtabs");
37830 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
37832 // set up the UpdateManager
37833 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
37834 var updater = tab2.getUpdateManager();
37835 updater.setDefaultUrl("ajax1.htm");
37836 tab2.on('activate', updater.refresh, updater, true);
37838 // Use setUrl for Ajax loading
37839 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
37840 tab3.setUrl("ajax2.htm", null, true);
37843 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
37846 jtabs.activate("jtabs-1");
37849 * Create a new TabPanel.
37850 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
37851 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
37853 Roo.bootstrap.panel.Tabs = function(config){
37855 * The container element for this TabPanel.
37856 * @type Roo.Element
37858 this.el = Roo.get(config.el);
37861 if(typeof config == "boolean"){
37862 this.tabPosition = config ? "bottom" : "top";
37864 Roo.apply(this, config);
37868 if(this.tabPosition == "bottom"){
37869 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37870 this.el.addClass("roo-tabs-bottom");
37872 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
37873 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
37874 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
37876 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
37878 if(this.tabPosition != "bottom"){
37879 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
37880 * @type Roo.Element
37882 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37883 this.el.addClass("roo-tabs-top");
37887 this.bodyEl.setStyle("position", "relative");
37889 this.active = null;
37890 this.activateDelegate = this.activate.createDelegate(this);
37895 * Fires when the active tab changes
37896 * @param {Roo.TabPanel} this
37897 * @param {Roo.TabPanelItem} activePanel The new active tab
37901 * @event beforetabchange
37902 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
37903 * @param {Roo.TabPanel} this
37904 * @param {Object} e Set cancel to true on this object to cancel the tab change
37905 * @param {Roo.TabPanelItem} tab The tab being changed to
37907 "beforetabchange" : true
37910 Roo.EventManager.onWindowResize(this.onResize, this);
37911 this.cpad = this.el.getPadding("lr");
37912 this.hiddenCount = 0;
37915 // toolbar on the tabbar support...
37916 if (this.toolbar) {
37917 alert("no toolbar support yet");
37918 this.toolbar = false;
37920 var tcfg = this.toolbar;
37921 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
37922 this.toolbar = new Roo.Toolbar(tcfg);
37923 if (Roo.isSafari) {
37924 var tbl = tcfg.container.child('table', true);
37925 tbl.setAttribute('width', '100%');
37933 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
37936 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
37938 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
37940 tabPosition : "top",
37942 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
37944 currentTabWidth : 0,
37946 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
37950 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
37954 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
37956 preferredTabWidth : 175,
37958 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
37960 resizeTabs : false,
37962 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
37964 monitorResize : true,
37966 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
37971 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
37972 * @param {String} id The id of the div to use <b>or create</b>
37973 * @param {String} text The text for the tab
37974 * @param {String} content (optional) Content to put in the TabPanelItem body
37975 * @param {Boolean} closable (optional) True to create a close icon on the tab
37976 * @return {Roo.TabPanelItem} The created TabPanelItem
37978 addTab : function(id, text, content, closable, tpl)
37980 var item = new Roo.bootstrap.panel.TabItem({
37984 closable : closable,
37987 this.addTabItem(item);
37989 item.setContent(content);
37995 * Returns the {@link Roo.TabPanelItem} with the specified id/index
37996 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
37997 * @return {Roo.TabPanelItem}
37999 getTab : function(id){
38000 return this.items[id];
38004 * Hides the {@link Roo.TabPanelItem} with the specified id/index
38005 * @param {String/Number} id The id or index of the TabPanelItem to hide.
38007 hideTab : function(id){
38008 var t = this.items[id];
38011 this.hiddenCount++;
38012 this.autoSizeTabs();
38017 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
38018 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
38020 unhideTab : function(id){
38021 var t = this.items[id];
38023 t.setHidden(false);
38024 this.hiddenCount--;
38025 this.autoSizeTabs();
38030 * Adds an existing {@link Roo.TabPanelItem}.
38031 * @param {Roo.TabPanelItem} item The TabPanelItem to add
38033 addTabItem : function(item){
38034 this.items[item.id] = item;
38035 this.items.push(item);
38036 // if(this.resizeTabs){
38037 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
38038 // this.autoSizeTabs();
38040 // item.autoSize();
38045 * Removes a {@link Roo.TabPanelItem}.
38046 * @param {String/Number} id The id or index of the TabPanelItem to remove.
38048 removeTab : function(id){
38049 var items = this.items;
38050 var tab = items[id];
38051 if(!tab) { return; }
38052 var index = items.indexOf(tab);
38053 if(this.active == tab && items.length > 1){
38054 var newTab = this.getNextAvailable(index);
38059 this.stripEl.dom.removeChild(tab.pnode.dom);
38060 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
38061 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
38063 items.splice(index, 1);
38064 delete this.items[tab.id];
38065 tab.fireEvent("close", tab);
38066 tab.purgeListeners();
38067 this.autoSizeTabs();
38070 getNextAvailable : function(start){
38071 var items = this.items;
38073 // look for a next tab that will slide over to
38074 // replace the one being removed
38075 while(index < items.length){
38076 var item = items[++index];
38077 if(item && !item.isHidden()){
38081 // if one isn't found select the previous tab (on the left)
38084 var item = items[--index];
38085 if(item && !item.isHidden()){
38093 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
38094 * @param {String/Number} id The id or index of the TabPanelItem to disable.
38096 disableTab : function(id){
38097 var tab = this.items[id];
38098 if(tab && this.active != tab){
38104 * Enables a {@link Roo.TabPanelItem} that is disabled.
38105 * @param {String/Number} id The id or index of the TabPanelItem to enable.
38107 enableTab : function(id){
38108 var tab = this.items[id];
38113 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
38114 * @param {String/Number} id The id or index of the TabPanelItem to activate.
38115 * @return {Roo.TabPanelItem} The TabPanelItem.
38117 activate : function(id){
38118 var tab = this.items[id];
38122 if(tab == this.active || tab.disabled){
38126 this.fireEvent("beforetabchange", this, e, tab);
38127 if(e.cancel !== true && !tab.disabled){
38129 this.active.hide();
38131 this.active = this.items[id];
38132 this.active.show();
38133 this.fireEvent("tabchange", this, this.active);
38139 * Gets the active {@link Roo.TabPanelItem}.
38140 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
38142 getActiveTab : function(){
38143 return this.active;
38147 * Updates the tab body element to fit the height of the container element
38148 * for overflow scrolling
38149 * @param {Number} targetHeight (optional) Override the starting height from the elements height
38151 syncHeight : function(targetHeight){
38152 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
38153 var bm = this.bodyEl.getMargins();
38154 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
38155 this.bodyEl.setHeight(newHeight);
38159 onResize : function(){
38160 if(this.monitorResize){
38161 this.autoSizeTabs();
38166 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
38168 beginUpdate : function(){
38169 this.updating = true;
38173 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
38175 endUpdate : function(){
38176 this.updating = false;
38177 this.autoSizeTabs();
38181 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
38183 autoSizeTabs : function(){
38184 var count = this.items.length;
38185 var vcount = count - this.hiddenCount;
38186 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
38189 var w = Math.max(this.el.getWidth() - this.cpad, 10);
38190 var availWidth = Math.floor(w / vcount);
38191 var b = this.stripBody;
38192 if(b.getWidth() > w){
38193 var tabs = this.items;
38194 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
38195 if(availWidth < this.minTabWidth){
38196 /*if(!this.sleft){ // incomplete scrolling code
38197 this.createScrollButtons();
38200 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
38203 if(this.currentTabWidth < this.preferredTabWidth){
38204 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
38210 * Returns the number of tabs in this TabPanel.
38213 getCount : function(){
38214 return this.items.length;
38218 * Resizes all the tabs to the passed width
38219 * @param {Number} The new width
38221 setTabWidth : function(width){
38222 this.currentTabWidth = width;
38223 for(var i = 0, len = this.items.length; i < len; i++) {
38224 if(!this.items[i].isHidden()) {
38225 this.items[i].setWidth(width);
38231 * Destroys this TabPanel
38232 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
38234 destroy : function(removeEl){
38235 Roo.EventManager.removeResizeListener(this.onResize, this);
38236 for(var i = 0, len = this.items.length; i < len; i++){
38237 this.items[i].purgeListeners();
38239 if(removeEl === true){
38240 this.el.update("");
38245 createStrip : function(container)
38247 var strip = document.createElement("nav");
38248 strip.className = "navbar navbar-default"; //"x-tabs-wrap";
38249 container.appendChild(strip);
38253 createStripList : function(strip)
38255 // div wrapper for retard IE
38256 // returns the "tr" element.
38257 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
38258 //'<div class="x-tabs-strip-wrap">'+
38259 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
38260 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
38261 return strip.firstChild; //.firstChild.firstChild.firstChild;
38263 createBody : function(container)
38265 var body = document.createElement("div");
38266 Roo.id(body, "tab-body");
38267 //Roo.fly(body).addClass("x-tabs-body");
38268 Roo.fly(body).addClass("tab-content");
38269 container.appendChild(body);
38272 createItemBody :function(bodyEl, id){
38273 var body = Roo.getDom(id);
38275 body = document.createElement("div");
38278 //Roo.fly(body).addClass("x-tabs-item-body");
38279 Roo.fly(body).addClass("tab-pane");
38280 bodyEl.insertBefore(body, bodyEl.firstChild);
38284 createStripElements : function(stripEl, text, closable, tpl)
38286 var td = document.createElement("li"); // was td..
38289 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
38292 stripEl.appendChild(td);
38294 td.className = "x-tabs-closable";
38295 if(!this.closeTpl){
38296 this.closeTpl = new Roo.Template(
38297 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38298 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
38299 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
38302 var el = this.closeTpl.overwrite(td, {"text": text});
38303 var close = el.getElementsByTagName("div")[0];
38304 var inner = el.getElementsByTagName("em")[0];
38305 return {"el": el, "close": close, "inner": inner};
38308 // not sure what this is..
38309 // if(!this.tabTpl){
38310 //this.tabTpl = new Roo.Template(
38311 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38312 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
38314 // this.tabTpl = new Roo.Template(
38315 // '<a href="#">' +
38316 // '<span unselectable="on"' +
38317 // (this.disableTooltips ? '' : ' title="{text}"') +
38318 // ' >{text}</span></a>'
38324 var template = tpl || this.tabTpl || false;
38328 template = new Roo.Template(
38330 '<span unselectable="on"' +
38331 (this.disableTooltips ? '' : ' title="{text}"') +
38332 ' >{text}</span></a>'
38336 switch (typeof(template)) {
38340 template = new Roo.Template(template);
38346 var el = template.overwrite(td, {"text": text});
38348 var inner = el.getElementsByTagName("span")[0];
38350 return {"el": el, "inner": inner};
38358 * @class Roo.TabPanelItem
38359 * @extends Roo.util.Observable
38360 * Represents an individual item (tab plus body) in a TabPanel.
38361 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
38362 * @param {String} id The id of this TabPanelItem
38363 * @param {String} text The text for the tab of this TabPanelItem
38364 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
38366 Roo.bootstrap.panel.TabItem = function(config){
38368 * The {@link Roo.TabPanel} this TabPanelItem belongs to
38369 * @type Roo.TabPanel
38371 this.tabPanel = config.panel;
38373 * The id for this TabPanelItem
38376 this.id = config.id;
38378 this.disabled = false;
38380 this.text = config.text;
38382 this.loaded = false;
38383 this.closable = config.closable;
38386 * The body element for this TabPanelItem.
38387 * @type Roo.Element
38389 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
38390 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
38391 this.bodyEl.setStyle("display", "block");
38392 this.bodyEl.setStyle("zoom", "1");
38393 //this.hideAction();
38395 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
38397 this.el = Roo.get(els.el);
38398 this.inner = Roo.get(els.inner, true);
38399 this.textEl = Roo.get(this.el.dom.firstChild, true);
38400 this.pnode = Roo.get(els.el.parentNode, true);
38401 // this.el.on("mousedown", this.onTabMouseDown, this);
38402 this.el.on("click", this.onTabClick, this);
38404 if(config.closable){
38405 var c = Roo.get(els.close, true);
38406 c.dom.title = this.closeText;
38407 c.addClassOnOver("close-over");
38408 c.on("click", this.closeClick, this);
38414 * Fires when this tab becomes the active tab.
38415 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38416 * @param {Roo.TabPanelItem} this
38420 * @event beforeclose
38421 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
38422 * @param {Roo.TabPanelItem} this
38423 * @param {Object} e Set cancel to true on this object to cancel the close.
38425 "beforeclose": true,
38428 * Fires when this tab is closed.
38429 * @param {Roo.TabPanelItem} this
38433 * @event deactivate
38434 * Fires when this tab is no longer the active tab.
38435 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38436 * @param {Roo.TabPanelItem} this
38438 "deactivate" : true
38440 this.hidden = false;
38442 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
38445 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
38447 purgeListeners : function(){
38448 Roo.util.Observable.prototype.purgeListeners.call(this);
38449 this.el.removeAllListeners();
38452 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
38455 this.pnode.addClass("active");
38458 this.tabPanel.stripWrap.repaint();
38460 this.fireEvent("activate", this.tabPanel, this);
38464 * Returns true if this tab is the active tab.
38465 * @return {Boolean}
38467 isActive : function(){
38468 return this.tabPanel.getActiveTab() == this;
38472 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
38475 this.pnode.removeClass("active");
38477 this.fireEvent("deactivate", this.tabPanel, this);
38480 hideAction : function(){
38481 this.bodyEl.hide();
38482 this.bodyEl.setStyle("position", "absolute");
38483 this.bodyEl.setLeft("-20000px");
38484 this.bodyEl.setTop("-20000px");
38487 showAction : function(){
38488 this.bodyEl.setStyle("position", "relative");
38489 this.bodyEl.setTop("");
38490 this.bodyEl.setLeft("");
38491 this.bodyEl.show();
38495 * Set the tooltip for the tab.
38496 * @param {String} tooltip The tab's tooltip
38498 setTooltip : function(text){
38499 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
38500 this.textEl.dom.qtip = text;
38501 this.textEl.dom.removeAttribute('title');
38503 this.textEl.dom.title = text;
38507 onTabClick : function(e){
38508 e.preventDefault();
38509 this.tabPanel.activate(this.id);
38512 onTabMouseDown : function(e){
38513 e.preventDefault();
38514 this.tabPanel.activate(this.id);
38517 getWidth : function(){
38518 return this.inner.getWidth();
38521 setWidth : function(width){
38522 var iwidth = width - this.pnode.getPadding("lr");
38523 this.inner.setWidth(iwidth);
38524 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
38525 this.pnode.setWidth(width);
38529 * Show or hide the tab
38530 * @param {Boolean} hidden True to hide or false to show.
38532 setHidden : function(hidden){
38533 this.hidden = hidden;
38534 this.pnode.setStyle("display", hidden ? "none" : "");
38538 * Returns true if this tab is "hidden"
38539 * @return {Boolean}
38541 isHidden : function(){
38542 return this.hidden;
38546 * Returns the text for this tab
38549 getText : function(){
38553 autoSize : function(){
38554 //this.el.beginMeasure();
38555 this.textEl.setWidth(1);
38557 * #2804 [new] Tabs in Roojs
38558 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
38560 //this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
38561 //this.el.endMeasure();
38565 * Sets the text for the tab (Note: this also sets the tooltip text)
38566 * @param {String} text The tab's text and tooltip
38568 setText : function(text){
38570 this.textEl.update(text);
38571 this.setTooltip(text);
38572 //if(!this.tabPanel.resizeTabs){
38573 // this.autoSize();
38577 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
38579 activate : function(){
38580 this.tabPanel.activate(this.id);
38584 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
38586 disable : function(){
38587 if(this.tabPanel.active != this){
38588 this.disabled = true;
38589 this.pnode.addClass("disabled");
38594 * Enables this TabPanelItem if it was previously disabled.
38596 enable : function(){
38597 this.disabled = false;
38598 this.pnode.removeClass("disabled");
38602 * Sets the content for this TabPanelItem.
38603 * @param {String} content The content
38604 * @param {Boolean} loadScripts true to look for and load scripts
38606 setContent : function(content, loadScripts){
38607 this.bodyEl.update(content, loadScripts);
38611 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
38612 * @return {Roo.UpdateManager} The UpdateManager
38614 getUpdateManager : function(){
38615 return this.bodyEl.getUpdateManager();
38619 * Set a URL to be used to load the content for this TabPanelItem.
38620 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
38621 * @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)
38622 * @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)
38623 * @return {Roo.UpdateManager} The UpdateManager
38625 setUrl : function(url, params, loadOnce){
38626 if(this.refreshDelegate){
38627 this.un('activate', this.refreshDelegate);
38629 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
38630 this.on("activate", this.refreshDelegate);
38631 return this.bodyEl.getUpdateManager();
38635 _handleRefresh : function(url, params, loadOnce){
38636 if(!loadOnce || !this.loaded){
38637 var updater = this.bodyEl.getUpdateManager();
38638 updater.update(url, params, this._setLoaded.createDelegate(this));
38643 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
38644 * Will fail silently if the setUrl method has not been called.
38645 * This does not activate the panel, just updates its content.
38647 refresh : function(){
38648 if(this.refreshDelegate){
38649 this.loaded = false;
38650 this.refreshDelegate();
38655 _setLoaded : function(){
38656 this.loaded = true;
38660 closeClick : function(e){
38663 this.fireEvent("beforeclose", this, o);
38664 if(o.cancel !== true){
38665 this.tabPanel.removeTab(this.id);
38669 * The text displayed in the tooltip for the close icon.
38672 closeText : "Close this tab"
38675 * This script refer to:
38676 * Title: International Telephone Input
38677 * Author: Jack O'Connor
38678 * Code version: v12.1.12
38679 * Availability: https://github.com/jackocnr/intl-tel-input.git
38682 Roo.bootstrap.PhoneInputData = function() {
38685 "Afghanistan (افغانستان)",
38690 "Albania (Shqipëri)",
38695 "Algeria (الجزائر)",
38720 "Antigua and Barbuda",
38730 "Armenia (Հայաստան)",
38746 "Austria (Österreich)",
38751 "Azerbaijan (Azərbaycan)",
38761 "Bahrain (البحرين)",
38766 "Bangladesh (বাংলাদেশ)",
38776 "Belarus (Беларусь)",
38781 "Belgium (België)",
38811 "Bosnia and Herzegovina (Босна и Херцеговина)",
38826 "British Indian Ocean Territory",
38831 "British Virgin Islands",
38841 "Bulgaria (България)",
38851 "Burundi (Uburundi)",
38856 "Cambodia (កម្ពុជា)",
38861 "Cameroon (Cameroun)",
38870 ["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"]
38873 "Cape Verde (Kabu Verdi)",
38878 "Caribbean Netherlands",
38889 "Central African Republic (République centrafricaine)",
38909 "Christmas Island",
38915 "Cocos (Keeling) Islands",
38926 "Comoros (جزر القمر)",
38931 "Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)",
38936 "Congo (Republic) (Congo-Brazzaville)",
38956 "Croatia (Hrvatska)",
38977 "Czech Republic (Česká republika)",
38982 "Denmark (Danmark)",
38997 "Dominican Republic (República Dominicana)",
39001 ["809", "829", "849"]
39019 "Equatorial Guinea (Guinea Ecuatorial)",
39039 "Falkland Islands (Islas Malvinas)",
39044 "Faroe Islands (Føroyar)",
39065 "French Guiana (Guyane française)",
39070 "French Polynesia (Polynésie française)",
39085 "Georgia (საქართველო)",
39090 "Germany (Deutschland)",
39110 "Greenland (Kalaallit Nunaat)",
39147 "Guinea-Bissau (Guiné Bissau)",
39172 "Hungary (Magyarország)",
39177 "Iceland (Ísland)",
39197 "Iraq (العراق)",
39213 "Israel (ישראל)",
39240 "Jordan (الأردن)",
39245 "Kazakhstan (Казахстан)",
39266 "Kuwait (الكويت)",
39271 "Kyrgyzstan (Кыргызстан)",
39281 "Latvia (Latvija)",
39286 "Lebanon (لبنان)",
39301 "Libya (ليبيا)",
39311 "Lithuania (Lietuva)",
39326 "Macedonia (FYROM) (Македонија)",
39331 "Madagascar (Madagasikara)",
39361 "Marshall Islands",
39371 "Mauritania (موريتانيا)",
39376 "Mauritius (Moris)",
39397 "Moldova (Republica Moldova)",
39407 "Mongolia (Монгол)",
39412 "Montenegro (Crna Gora)",
39422 "Morocco (المغرب)",
39428 "Mozambique (Moçambique)",
39433 "Myanmar (Burma) (မြန်မာ)",
39438 "Namibia (Namibië)",
39453 "Netherlands (Nederland)",
39458 "New Caledonia (Nouvelle-Calédonie)",
39493 "North Korea (조선 민주주의 인민 공화국)",
39498 "Northern Mariana Islands",
39514 "Pakistan (پاکستان)",
39524 "Palestine (فلسطين)",
39534 "Papua New Guinea",
39576 "Réunion (La Réunion)",
39582 "Romania (România)",
39598 "Saint Barthélemy",
39609 "Saint Kitts and Nevis",
39619 "Saint Martin (Saint-Martin (partie française))",
39625 "Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)",
39630 "Saint Vincent and the Grenadines",
39645 "São Tomé and Príncipe (São Tomé e Príncipe)",
39650 "Saudi Arabia (المملكة العربية السعودية)",
39655 "Senegal (Sénégal)",
39685 "Slovakia (Slovensko)",
39690 "Slovenia (Slovenija)",
39700 "Somalia (Soomaaliya)",
39710 "South Korea (대한민국)",
39715 "South Sudan (جنوب السودان)",
39725 "Sri Lanka (ශ්රී ලංකාව)",
39730 "Sudan (السودان)",
39740 "Svalbard and Jan Mayen",
39751 "Sweden (Sverige)",
39756 "Switzerland (Schweiz)",
39761 "Syria (سوريا)",
39806 "Trinidad and Tobago",
39811 "Tunisia (تونس)",
39816 "Turkey (Türkiye)",
39826 "Turks and Caicos Islands",
39836 "U.S. Virgin Islands",
39846 "Ukraine (Україна)",
39851 "United Arab Emirates (الإمارات العربية المتحدة)",
39873 "Uzbekistan (Oʻzbekiston)",
39883 "Vatican City (Città del Vaticano)",
39894 "Vietnam (Việt Nam)",
39899 "Wallis and Futuna (Wallis-et-Futuna)",
39904 "Western Sahara (الصحراء الغربية)",
39910 "Yemen (اليمن)",
39934 * This script refer to:
39935 * Title: International Telephone Input
39936 * Author: Jack O'Connor
39937 * Code version: v12.1.12
39938 * Availability: https://github.com/jackocnr/intl-tel-input.git
39942 * @class Roo.bootstrap.PhoneInput
39943 * @extends Roo.bootstrap.TriggerField
39944 * An input with International dial-code selection
39946 * @cfg {String} defaultDialCode default '+852'
39947 * @cfg {Array} preferedCountries default []
39950 * Create a new PhoneInput.
39951 * @param {Object} config Configuration options
39954 Roo.bootstrap.PhoneInput = function(config) {
39955 Roo.bootstrap.PhoneInput.superclass.constructor.call(this, config);
39958 Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
39960 listWidth: undefined,
39962 selectedClass: 'active',
39964 invalidClass : "has-warning",
39966 validClass: 'has-success',
39968 allowed: '0123456789',
39973 * @cfg {String} defaultDialCode The default dial code when initializing the input
39975 defaultDialCode: '+852',
39978 * @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
39980 preferedCountries: false,
39982 getAutoCreate : function()
39984 var data = Roo.bootstrap.PhoneInputData();
39985 var align = this.labelAlign || this.parentLabelAlign();
39988 this.allCountries = [];
39989 this.dialCodeMapping = [];
39991 for (var i = 0; i < data.length; i++) {
39993 this.allCountries[i] = {
39997 priority: c[3] || 0,
39998 areaCodes: c[4] || null
40000 this.dialCodeMapping[c[2]] = {
40003 priority: c[3] || 0,
40004 areaCodes: c[4] || null
40016 // type: 'number', -- do not use number - we get the flaky up/down arrows.
40017 maxlength: this.max_length,
40018 cls : 'form-control tel-input',
40019 autocomplete: 'new-password'
40022 var hiddenInput = {
40025 cls: 'hidden-tel-input'
40029 hiddenInput.name = this.name;
40032 if (this.disabled) {
40033 input.disabled = true;
40036 var flag_container = {
40053 cls: this.hasFeedback ? 'has-feedback' : '',
40059 cls: 'dial-code-holder',
40066 cls: 'roo-select2-container input-group',
40073 if (this.fieldLabel.length) {
40076 tooltip: 'This field is required'
40082 cls: 'control-label',
40088 html: this.fieldLabel
40091 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40097 if(this.indicatorpos == 'right') {
40098 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40105 if(align == 'left') {
40113 if(this.labelWidth > 12){
40114 label.style = "width: " + this.labelWidth + 'px';
40116 if(this.labelWidth < 13 && this.labelmd == 0){
40117 this.labelmd = this.labelWidth;
40119 if(this.labellg > 0){
40120 label.cls += ' col-lg-' + this.labellg;
40121 input.cls += ' col-lg-' + (12 - this.labellg);
40123 if(this.labelmd > 0){
40124 label.cls += ' col-md-' + this.labelmd;
40125 container.cls += ' col-md-' + (12 - this.labelmd);
40127 if(this.labelsm > 0){
40128 label.cls += ' col-sm-' + this.labelsm;
40129 container.cls += ' col-sm-' + (12 - this.labelsm);
40131 if(this.labelxs > 0){
40132 label.cls += ' col-xs-' + this.labelxs;
40133 container.cls += ' col-xs-' + (12 - this.labelxs);
40143 var settings = this;
40145 ['xs','sm','md','lg'].map(function(size){
40146 if (settings[size]) {
40147 cfg.cls += ' col-' + size + '-' + settings[size];
40151 this.store = new Roo.data.Store({
40152 proxy : new Roo.data.MemoryProxy({}),
40153 reader : new Roo.data.JsonReader({
40164 'name' : 'dialCode',
40168 'name' : 'priority',
40172 'name' : 'areaCodes',
40179 if(!this.preferedCountries) {
40180 this.preferedCountries = [
40187 var p = this.preferedCountries.reverse();
40190 for (var i = 0; i < p.length; i++) {
40191 for (var j = 0; j < this.allCountries.length; j++) {
40192 if(this.allCountries[j].iso2 == p[i]) {
40193 var t = this.allCountries[j];
40194 this.allCountries.splice(j,1);
40195 this.allCountries.unshift(t);
40201 this.store.proxy.data = {
40203 data: this.allCountries
40209 initEvents : function()
40212 Roo.bootstrap.PhoneInput.superclass.initEvents.call(this);
40214 this.indicator = this.indicatorEl();
40215 this.flag = this.flagEl();
40216 this.dialCodeHolder = this.dialCodeHolderEl();
40218 this.trigger = this.el.select('div.flag-box',true).first();
40219 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
40224 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40225 _this.list.setWidth(lw);
40228 this.list.on('mouseover', this.onViewOver, this);
40229 this.list.on('mousemove', this.onViewMove, this);
40230 this.inputEl().on("keyup", this.onKeyUp, this);
40231 this.inputEl().on("keypress", this.onKeyPress, this);
40233 this.tpl = '<li><a href="#"><div class="flag {iso2}"></div>{name} <span class="dial-code">+{dialCode}</span></a></li>';
40235 this.view = new Roo.View(this.list, this.tpl, {
40236 singleSelect:true, store: this.store, selectedClass: this.selectedClass
40239 this.view.on('click', this.onViewClick, this);
40240 this.setValue(this.defaultDialCode);
40243 onTriggerClick : function(e)
40245 Roo.log('trigger click');
40250 if(this.isExpanded()){
40252 this.hasFocus = false;
40254 this.store.load({});
40255 this.hasFocus = true;
40260 isExpanded : function()
40262 return this.list.isVisible();
40265 collapse : function()
40267 if(!this.isExpanded()){
40271 Roo.get(document).un('mousedown', this.collapseIf, this);
40272 Roo.get(document).un('mousewheel', this.collapseIf, this);
40273 this.fireEvent('collapse', this);
40277 expand : function()
40281 if(this.isExpanded() || !this.hasFocus){
40285 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
40286 this.list.setWidth(lw);
40289 this.restrictHeight();
40291 Roo.get(document).on('mousedown', this.collapseIf, this);
40292 Roo.get(document).on('mousewheel', this.collapseIf, this);
40294 this.fireEvent('expand', this);
40297 restrictHeight : function()
40299 this.list.alignTo(this.inputEl(), this.listAlign);
40300 this.list.alignTo(this.inputEl(), this.listAlign);
40303 onViewOver : function(e, t)
40305 if(this.inKeyMode){
40308 var item = this.view.findItemFromChild(t);
40311 var index = this.view.indexOf(item);
40312 this.select(index, false);
40317 onViewClick : function(view, doFocus, el, e)
40319 var index = this.view.getSelectedIndexes()[0];
40321 var r = this.store.getAt(index);
40324 this.onSelect(r, index);
40326 if(doFocus !== false && !this.blockFocus){
40327 this.inputEl().focus();
40331 onViewMove : function(e, t)
40333 this.inKeyMode = false;
40336 select : function(index, scrollIntoView)
40338 this.selectedIndex = index;
40339 this.view.select(index);
40340 if(scrollIntoView !== false){
40341 var el = this.view.getNode(index);
40343 this.list.scrollChildIntoView(el, false);
40348 createList : function()
40350 this.list = Roo.get(document.body).createChild({
40352 cls: 'typeahead typeahead-long dropdown-menu tel-list',
40353 style: 'display:none'
40356 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
40359 collapseIf : function(e)
40361 var in_combo = e.within(this.el);
40362 var in_list = e.within(this.list);
40363 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
40365 if (in_combo || in_list || is_list) {
40371 onSelect : function(record, index)
40373 if(this.fireEvent('beforeselect', this, record, index) !== false){
40375 this.setFlagClass(record.data.iso2);
40376 this.setDialCode(record.data.dialCode);
40377 this.hasFocus = false;
40379 this.fireEvent('select', this, record, index);
40383 flagEl : function()
40385 var flag = this.el.select('div.flag',true).first();
40392 dialCodeHolderEl : function()
40394 var d = this.el.select('input.dial-code-holder',true).first();
40401 setDialCode : function(v)
40403 this.dialCodeHolder.dom.value = '+'+v;
40406 setFlagClass : function(n)
40408 this.flag.dom.className = 'flag '+n;
40411 getValue : function()
40413 var v = this.inputEl().getValue();
40414 if(this.dialCodeHolder) {
40415 v = this.dialCodeHolder.dom.value+this.inputEl().getValue();
40420 setValue : function(v)
40422 var d = this.getDialCode(v);
40424 //invalid dial code
40425 if(v.length == 0 || !d || d.length == 0) {
40427 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
40428 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
40434 this.setFlagClass(this.dialCodeMapping[d].iso2);
40435 this.setDialCode(d);
40436 this.inputEl().dom.value = v.replace('+'+d,'');
40437 this.hiddenEl().dom.value = this.getValue();
40442 getDialCode : function(v)
40446 if (v.length == 0) {
40447 return this.dialCodeHolder.dom.value;
40451 if (v.charAt(0) != "+") {
40454 var numericChars = "";
40455 for (var i = 1; i < v.length; i++) {
40456 var c = v.charAt(i);
40459 if (this.dialCodeMapping[numericChars]) {
40460 dialCode = v.substr(1, i);
40462 if (numericChars.length == 4) {
40472 this.setValue(this.defaultDialCode);
40476 hiddenEl : function()
40478 return this.el.select('input.hidden-tel-input',true).first();
40481 // after setting val
40482 onKeyUp : function(e){
40483 this.setValue(this.getValue());
40486 onKeyPress : function(e){
40487 if(this.allowed.indexOf(String.fromCharCode(e.getCharCode())) === -1){
40494 * @class Roo.bootstrap.MoneyField
40495 * @extends Roo.bootstrap.ComboBox
40496 * Bootstrap MoneyField class
40499 * Create a new MoneyField.
40500 * @param {Object} config Configuration options
40503 Roo.bootstrap.MoneyField = function(config) {
40505 Roo.bootstrap.MoneyField.superclass.constructor.call(this, config);
40509 Roo.extend(Roo.bootstrap.MoneyField, Roo.bootstrap.ComboBox, {
40512 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
40514 allowDecimals : true,
40516 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
40518 decimalSeparator : ".",
40520 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
40522 decimalPrecision : 0,
40524 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
40526 allowNegative : true,
40528 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
40532 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
40534 minValue : Number.NEGATIVE_INFINITY,
40536 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
40538 maxValue : Number.MAX_VALUE,
40540 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
40542 minText : "The minimum value for this field is {0}",
40544 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
40546 maxText : "The maximum value for this field is {0}",
40548 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
40549 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
40551 nanText : "{0} is not a valid number",
40553 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
40557 * @cfg {String} defaults currency of the MoneyField
40558 * value should be in lkey
40560 defaultCurrency : false,
40562 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
40564 thousandsDelimiter : false,
40566 * @cfg {Number} max_length Maximum input field length allowed (defaults to Number.MAX_VALUE)
40577 getAutoCreate : function()
40579 var align = this.labelAlign || this.parentLabelAlign();
40591 cls : 'form-control roo-money-amount-input',
40592 autocomplete: 'new-password'
40595 var hiddenInput = {
40599 cls: 'hidden-number-input'
40602 if(this.max_length) {
40603 input.maxlength = this.max_length;
40607 hiddenInput.name = this.name;
40610 if (this.disabled) {
40611 input.disabled = true;
40614 var clg = 12 - this.inputlg;
40615 var cmd = 12 - this.inputmd;
40616 var csm = 12 - this.inputsm;
40617 var cxs = 12 - this.inputxs;
40621 cls : 'row roo-money-field',
40625 cls : 'roo-money-currency column col-lg-' + clg + ' col-md-' + cmd + ' col-sm-' + csm + ' col-xs-' + cxs,
40629 cls: 'roo-select2-container input-group',
40633 cls : 'form-control roo-money-currency-input',
40634 autocomplete: 'new-password',
40636 name : this.currencyName
40640 cls : 'input-group-addon',
40654 cls : 'roo-money-amount column col-lg-' + this.inputlg + ' col-md-' + this.inputmd + ' col-sm-' + this.inputsm + ' col-xs-' + this.inputxs,
40658 cls: this.hasFeedback ? 'has-feedback' : '',
40669 if (this.fieldLabel.length) {
40672 tooltip: 'This field is required'
40678 cls: 'control-label',
40684 html: this.fieldLabel
40687 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40693 if(this.indicatorpos == 'right') {
40694 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40701 if(align == 'left') {
40709 if(this.labelWidth > 12){
40710 label.style = "width: " + this.labelWidth + 'px';
40712 if(this.labelWidth < 13 && this.labelmd == 0){
40713 this.labelmd = this.labelWidth;
40715 if(this.labellg > 0){
40716 label.cls += ' col-lg-' + this.labellg;
40717 input.cls += ' col-lg-' + (12 - this.labellg);
40719 if(this.labelmd > 0){
40720 label.cls += ' col-md-' + this.labelmd;
40721 container.cls += ' col-md-' + (12 - this.labelmd);
40723 if(this.labelsm > 0){
40724 label.cls += ' col-sm-' + this.labelsm;
40725 container.cls += ' col-sm-' + (12 - this.labelsm);
40727 if(this.labelxs > 0){
40728 label.cls += ' col-xs-' + this.labelxs;
40729 container.cls += ' col-xs-' + (12 - this.labelxs);
40740 var settings = this;
40742 ['xs','sm','md','lg'].map(function(size){
40743 if (settings[size]) {
40744 cfg.cls += ' col-' + size + '-' + settings[size];
40751 initEvents : function()
40753 this.indicator = this.indicatorEl();
40755 this.initCurrencyEvent();
40757 this.initNumberEvent();
40760 initCurrencyEvent : function()
40763 throw "can not find store for combo";
40766 this.store = Roo.factory(this.store, Roo.data);
40767 this.store.parent = this;
40771 this.triggerEl = this.el.select('.input-group-addon', true).first();
40773 this.triggerEl.on("click", this.onTriggerClick, this, { preventDefault : true });
40778 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40779 _this.list.setWidth(lw);
40782 this.list.on('mouseover', this.onViewOver, this);
40783 this.list.on('mousemove', this.onViewMove, this);
40784 this.list.on('scroll', this.onViewScroll, this);
40787 this.tpl = '<li><a href="#">{' + this.currencyField + '}</a></li>';
40790 this.view = new Roo.View(this.list, this.tpl, {
40791 singleSelect:true, store: this.store, selectedClass: this.selectedClass
40794 this.view.on('click', this.onViewClick, this);
40796 this.store.on('beforeload', this.onBeforeLoad, this);
40797 this.store.on('load', this.onLoad, this);
40798 this.store.on('loadexception', this.onLoadException, this);
40800 this.keyNav = new Roo.KeyNav(this.currencyEl(), {
40801 "up" : function(e){
40802 this.inKeyMode = true;
40806 "down" : function(e){
40807 if(!this.isExpanded()){
40808 this.onTriggerClick();
40810 this.inKeyMode = true;
40815 "enter" : function(e){
40818 if(this.fireEvent("specialkey", this, e)){
40819 this.onViewClick(false);
40825 "esc" : function(e){
40829 "tab" : function(e){
40832 if(this.fireEvent("specialkey", this, e)){
40833 this.onViewClick(false);
40841 doRelay : function(foo, bar, hname){
40842 if(hname == 'down' || this.scope.isExpanded()){
40843 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
40851 this.currencyEl().on("click", this.onTriggerClick, this, { preventDefault : true });
40855 initNumberEvent : function(e)
40857 this.inputEl().on("keydown" , this.fireKey, this);
40858 this.inputEl().on("focus", this.onFocus, this);
40859 this.inputEl().on("blur", this.onBlur, this);
40861 this.inputEl().relayEvent('keyup', this);
40863 if(this.indicator){
40864 this.indicator.addClass('invisible');
40867 this.originalValue = this.getValue();
40869 if(this.validationEvent == 'keyup'){
40870 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
40871 this.inputEl().on('keyup', this.filterValidation, this);
40873 else if(this.validationEvent !== false){
40874 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
40877 if(this.selectOnFocus){
40878 this.on("focus", this.preFocus, this);
40881 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
40882 this.inputEl().on("keypress", this.filterKeys, this);
40884 this.inputEl().relayEvent('keypress', this);
40887 var allowed = "0123456789";
40889 if(this.allowDecimals){
40890 allowed += this.decimalSeparator;
40893 if(this.allowNegative){
40897 if(this.thousandsDelimiter) {
40901 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
40903 var keyPress = function(e){
40905 var k = e.getKey();
40907 var c = e.getCharCode();
40910 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
40911 allowed.indexOf(String.fromCharCode(c)) === -1
40917 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
40921 if(allowed.indexOf(String.fromCharCode(c)) === -1){
40926 this.inputEl().on("keypress", keyPress, this);
40930 onTriggerClick : function(e)
40937 this.loadNext = false;
40939 if(this.isExpanded()){
40944 this.hasFocus = true;
40946 if(this.triggerAction == 'all') {
40947 this.doQuery(this.allQuery, true);
40951 this.doQuery(this.getRawValue());
40954 getCurrency : function()
40956 var v = this.currencyEl().getValue();
40961 restrictHeight : function()
40963 this.list.alignTo(this.currencyEl(), this.listAlign);
40964 this.list.alignTo(this.currencyEl(), this.listAlign);
40967 onViewClick : function(view, doFocus, el, e)
40969 var index = this.view.getSelectedIndexes()[0];
40971 var r = this.store.getAt(index);
40974 this.onSelect(r, index);
40978 onSelect : function(record, index){
40980 if(this.fireEvent('beforeselect', this, record, index) !== false){
40982 this.setFromCurrencyData(index > -1 ? record.data : false);
40986 this.fireEvent('select', this, record, index);
40990 setFromCurrencyData : function(o)
40994 this.lastCurrency = o;
40996 if (this.currencyField) {
40997 currency = !o || typeof(o[this.currencyField]) == 'undefined' ? '' : o[this.currencyField];
40999 Roo.log('no currencyField value set for '+ (this.name ? this.name : this.id));
41002 this.lastSelectionText = currency;
41004 //setting default currency
41005 if(o[this.currencyField] * 1 == 0 && this.defaultCurrency) {
41006 this.setCurrency(this.defaultCurrency);
41010 this.setCurrency(currency);
41013 setFromData : function(o)
41017 c[this.currencyField] = !o || typeof(o[this.currencyName]) == 'undefined' ? '' : o[this.currencyName];
41019 this.setFromCurrencyData(c);
41024 value = !o || typeof(o[this.name]) == 'undefined' ? '' : o[this.name];
41026 Roo.log('no value set for '+ (this.name ? this.name : this.id));
41029 this.setValue(value);
41033 setCurrency : function(v)
41035 this.currencyValue = v;
41038 this.currencyEl().dom.value = (v === null || v === undefined ? '' : v);
41043 setValue : function(v)
41045 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
41051 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
41053 this.inputEl().dom.value = (v == '') ? '' :
41054 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
41056 if(!this.allowZero && v === '0') {
41057 this.hiddenEl().dom.value = '';
41058 this.inputEl().dom.value = '';
41065 getRawValue : function()
41067 var v = this.inputEl().getValue();
41072 getValue : function()
41074 return this.fixPrecision(this.parseValue(this.getRawValue()));
41077 parseValue : function(value)
41079 if(this.thousandsDelimiter) {
41081 r = new RegExp(",", "g");
41082 value = value.replace(r, "");
41085 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
41086 return isNaN(value) ? '' : value;
41090 fixPrecision : function(value)
41092 if(this.thousandsDelimiter) {
41094 r = new RegExp(",", "g");
41095 value = value.replace(r, "");
41098 var nan = isNaN(value);
41100 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
41101 return nan ? '' : value;
41103 return parseFloat(value).toFixed(this.decimalPrecision);
41106 decimalPrecisionFcn : function(v)
41108 return Math.floor(v);
41111 validateValue : function(value)
41113 if(!Roo.bootstrap.MoneyField.superclass.validateValue.call(this, value)){
41117 var num = this.parseValue(value);
41120 this.markInvalid(String.format(this.nanText, value));
41124 if(num < this.minValue){
41125 this.markInvalid(String.format(this.minText, this.minValue));
41129 if(num > this.maxValue){
41130 this.markInvalid(String.format(this.maxText, this.maxValue));
41137 validate : function()
41139 if(this.disabled || this.allowBlank){
41144 var currency = this.getCurrency();
41146 if(this.validateValue(this.getRawValue()) && currency.length){
41151 this.markInvalid();
41155 getName: function()
41160 beforeBlur : function()
41166 var v = this.parseValue(this.getRawValue());
41173 onBlur : function()
41177 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
41178 //this.el.removeClass(this.focusClass);
41181 this.hasFocus = false;
41183 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
41187 var v = this.getValue();
41189 if(String(v) !== String(this.startValue)){
41190 this.fireEvent('change', this, v, this.startValue);
41193 this.fireEvent("blur", this);
41196 inputEl : function()
41198 return this.el.select('.roo-money-amount-input', true).first();
41201 currencyEl : function()
41203 return this.el.select('.roo-money-currency-input', true).first();
41206 hiddenEl : function()
41208 return this.el.select('input.hidden-number-input',true).first();