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 var ce = this.el.select('.navbar-collapse',true).first();
3865 ce.toggleClass('in'); // old...
3866 if (ce.hasClass('collapse')) {
3868 ce.removeClass('collapse');
3869 ce.addClass('collapsing show');
3870 (function() { ce.removeClass('collapsing'); }).defer(50);
3872 ce.addClass('collapsing');
3873 ce.removeClass('show');
3875 ce.removeClass('collapsing');
3876 ce.addClass('collapse');
3889 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3891 var size = this.el.getSize();
3892 this.maskEl.setSize(size.width, size.height);
3893 this.maskEl.enableDisplayMode("block");
3902 getChildContainer : function()
3904 if (this.el.select('.collapse').getCount()) {
3905 return this.el.select('.collapse',true).first();
3938 * @class Roo.bootstrap.NavSimplebar
3939 * @extends Roo.bootstrap.Navbar
3940 * Bootstrap Sidebar class
3942 * @cfg {Boolean} inverse is inverted color
3944 * @cfg {String} type (nav | pills | tabs)
3945 * @cfg {Boolean} arrangement stacked | justified
3946 * @cfg {String} align (left | right) alignment
3948 * @cfg {Boolean} main (true|false) main nav bar? default false
3949 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3951 * @cfg {String} tag (header|footer|nav|div) default is nav
3953 * @cfg {String} weight (light|primary|secondary|success|danger|warning|info|dark|white) default is light.
3957 * Create a new Sidebar
3958 * @param {Object} config The config object
3962 Roo.bootstrap.NavSimplebar = function(config){
3963 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3966 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
3982 getAutoCreate : function(){
3986 tag : this.tag || 'div',
3987 cls : 'navbar navbar-expand-lg'
3989 if (['light','white'].indexOf(this.weight) > -1) {
3990 cfg.cls += ['light','white'].indexOf(this.weight) > -1 ? ' navbar-light' : ' navbar-dark';
3992 cfg.cls += ' bg-' + this.weight;
4004 this.type = this.type || 'nav';
4005 if (['tabs','pills'].indexOf(this.type)!==-1) {
4006 cfg.cn[0].cls += ' nav-' + this.type
4010 if (this.type!=='nav') {
4011 Roo.log('nav type must be nav/tabs/pills')
4013 cfg.cn[0].cls += ' navbar-nav'
4019 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
4020 cfg.cn[0].cls += ' nav-' + this.arrangement;
4024 if (this.align === 'right') {
4025 cfg.cn[0].cls += ' navbar-right';
4029 cfg.cls += ' navbar-inverse';
4053 * navbar-expand-md fixed-top
4057 * @class Roo.bootstrap.NavHeaderbar
4058 * @extends Roo.bootstrap.NavSimplebar
4059 * Bootstrap Sidebar class
4061 * @cfg {String} brand what is brand
4062 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
4063 * @cfg {String} brand_href href of the brand
4064 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
4065 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
4066 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
4067 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
4070 * Create a new Sidebar
4071 * @param {Object} config The config object
4075 Roo.bootstrap.NavHeaderbar = function(config){
4076 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
4080 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
4087 desktopCenter : false,
4090 getAutoCreate : function(){
4093 tag: this.nav || 'nav',
4094 cls: 'navbar navbar-expand-md',
4100 if (this.desktopCenter) {
4101 cn.push({cls : 'container', cn : []});
4109 cls: 'navbar-toggle navbar-toggler',
4110 'data-toggle': 'collapse',
4115 html: 'Toggle navigation'
4119 cls: 'icon-bar navbar-toggler-icon'
4132 cn.push( Roo.bootstrap.version == 4 ? btn : {
4134 cls: 'navbar-header',
4143 cls: 'collapse navbar-collapse',
4147 cfg.cls += this.inverse ? ' navbar-inverse navbar-dark bg-dark' : ' navbar-default';
4149 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
4150 cfg.cls += ' navbar-' + this.position + ' ' + this.position ;
4152 // tag can override this..
4154 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
4157 if (this.brand !== '') {
4158 var cp = Roo.bootstrap.version == 4 ? cn : cn[0].cn;
4159 cp.unshift({ // changed from push ?? BS4 needs it at the start? - does this break or exsiting?
4161 href: this.brand_href ? this.brand_href : '#',
4162 cls: 'navbar-brand',
4170 cfg.cls += ' main-nav';
4178 getHeaderChildContainer : function()
4180 if (this.srButton && this.el.select('.navbar-header').getCount()) {
4181 return this.el.select('.navbar-header',true).first();
4184 return this.getChildContainer();
4188 initEvents : function()
4190 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
4192 if (this.autohide) {
4197 Roo.get(document).on('scroll',function(e) {
4198 var ns = Roo.get(document).getScroll().top;
4199 var os = prevScroll;
4203 ft.removeClass('slideDown');
4204 ft.addClass('slideUp');
4207 ft.removeClass('slideUp');
4208 ft.addClass('slideDown');
4229 * @class Roo.bootstrap.NavSidebar
4230 * @extends Roo.bootstrap.Navbar
4231 * Bootstrap Sidebar class
4234 * Create a new Sidebar
4235 * @param {Object} config The config object
4239 Roo.bootstrap.NavSidebar = function(config){
4240 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
4243 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
4245 sidebar : true, // used by Navbar Item and NavbarGroup at present...
4247 getAutoCreate : function(){
4252 cls: 'sidebar sidebar-nav'
4274 * @class Roo.bootstrap.NavGroup
4275 * @extends Roo.bootstrap.Component
4276 * Bootstrap NavGroup class
4277 * @cfg {String} align (left|right)
4278 * @cfg {Boolean} inverse
4279 * @cfg {String} type (nav|pills|tab) default nav
4280 * @cfg {String} navId - reference Id for navbar.
4284 * Create a new nav group
4285 * @param {Object} config The config object
4288 Roo.bootstrap.NavGroup = function(config){
4289 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
4292 Roo.bootstrap.NavGroup.register(this);
4296 * Fires when the active item changes
4297 * @param {Roo.bootstrap.NavGroup} this
4298 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
4299 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
4306 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
4317 getAutoCreate : function()
4319 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
4326 if (['tabs','pills'].indexOf(this.type)!==-1) {
4327 cfg.cls += ' nav-' + this.type
4329 if (this.type!=='nav') {
4330 Roo.log('nav type must be nav/tabs/pills')
4332 cfg.cls += ' navbar-nav'
4335 if (this.parent() && this.parent().sidebar) {
4338 cls: 'dashboard-menu sidebar-menu'
4344 if (this.form === true) {
4350 if (this.align === 'right') {
4351 cfg.cls += ' navbar-right ml-md-auto';
4353 cfg.cls += ' navbar-left';
4357 if (this.align === 'right') {
4358 cfg.cls += ' navbar-right ml-md-auto';
4360 cfg.cls += ' mr-auto';
4364 cfg.cls += ' navbar-inverse';
4372 * sets the active Navigation item
4373 * @param {Roo.bootstrap.NavItem} the new current navitem
4375 setActiveItem : function(item)
4378 Roo.each(this.navItems, function(v){
4383 v.setActive(false, true);
4390 item.setActive(true, true);
4391 this.fireEvent('changed', this, item, prev);
4396 * gets the active Navigation item
4397 * @return {Roo.bootstrap.NavItem} the current navitem
4399 getActive : function()
4403 Roo.each(this.navItems, function(v){
4414 indexOfNav : function()
4418 Roo.each(this.navItems, function(v,i){
4429 * adds a Navigation item
4430 * @param {Roo.bootstrap.NavItem} the navitem to add
4432 addItem : function(cfg)
4434 var cn = new Roo.bootstrap.NavItem(cfg);
4436 cn.parentId = this.id;
4437 cn.onRender(this.el, null);
4441 * register a Navigation item
4442 * @param {Roo.bootstrap.NavItem} the navitem to add
4444 register : function(item)
4446 this.navItems.push( item);
4447 item.navId = this.navId;
4452 * clear all the Navigation item
4455 clearAll : function()
4458 this.el.dom.innerHTML = '';
4461 getNavItem: function(tabId)
4464 Roo.each(this.navItems, function(e) {
4465 if (e.tabId == tabId) {
4475 setActiveNext : function()
4477 var i = this.indexOfNav(this.getActive());
4478 if (i > this.navItems.length) {
4481 this.setActiveItem(this.navItems[i+1]);
4483 setActivePrev : function()
4485 var i = this.indexOfNav(this.getActive());
4489 this.setActiveItem(this.navItems[i-1]);
4491 clearWasActive : function(except) {
4492 Roo.each(this.navItems, function(e) {
4493 if (e.tabId != except.tabId && e.was_active) {
4494 e.was_active = false;
4501 getWasActive : function ()
4504 Roo.each(this.navItems, function(e) {
4519 Roo.apply(Roo.bootstrap.NavGroup, {
4523 * register a Navigation Group
4524 * @param {Roo.bootstrap.NavGroup} the navgroup to add
4526 register : function(navgrp)
4528 this.groups[navgrp.navId] = navgrp;
4532 * fetch a Navigation Group based on the navigation ID
4533 * @param {string} the navgroup to add
4534 * @returns {Roo.bootstrap.NavGroup} the navgroup
4536 get: function(navId) {
4537 if (typeof(this.groups[navId]) == 'undefined') {
4539 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
4541 return this.groups[navId] ;
4556 * @class Roo.bootstrap.NavItem
4557 * @extends Roo.bootstrap.Component
4558 * Bootstrap Navbar.NavItem class
4559 * @cfg {String} href link to
4560 * @cfg {String} html content of button
4561 * @cfg {String} badge text inside badge
4562 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
4563 * @cfg {String} glyphicon DEPRICATED - use fa
4564 * @cfg {String} icon DEPRICATED - use fa
4565 * @cfg {String} fa - Fontawsome icon name (can add stuff to it like fa-2x)
4566 * @cfg {Boolean} active Is item active
4567 * @cfg {Boolean} disabled Is item disabled
4569 * @cfg {Boolean} preventDefault (true | false) default false
4570 * @cfg {String} tabId the tab that this item activates.
4571 * @cfg {String} tagtype (a|span) render as a href or span?
4572 * @cfg {Boolean} animateRef (true|false) link to element default false
4575 * Create a new Navbar Item
4576 * @param {Object} config The config object
4578 Roo.bootstrap.NavItem = function(config){
4579 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
4584 * The raw click event for the entire grid.
4585 * @param {Roo.EventObject} e
4590 * Fires when the active item active state changes
4591 * @param {Roo.bootstrap.NavItem} this
4592 * @param {boolean} state the new state
4598 * Fires when scroll to element
4599 * @param {Roo.bootstrap.NavItem} this
4600 * @param {Object} options
4601 * @param {Roo.EventObject} e
4609 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
4618 preventDefault : false,
4625 getAutoCreate : function(){
4634 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
4636 if (this.disabled) {
4637 cfg.cls += ' disabled';
4640 if (this.href || this.html || this.glyphicon || this.icon || this.fa) {
4644 href : this.href || "#",
4645 html: this.html || ''
4648 if (this.tagtype == 'a') {
4649 cfg.cn[0].cls = 'nav-link';
4652 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
4655 cfg.cn[0].html = '<i class="fa fas fa-'+this.fa+'"></i> <span>' + cfg.cn[0].html + '</span>'
4657 if(this.glyphicon) {
4658 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
4663 cfg.cn[0].html += " <span class='caret'></span>";
4667 if (this.badge !== '') {
4669 cfg.cn[0].html += ' <span class="badge badge-secondary">' + this.badge + '</span>';
4677 initEvents: function()
4679 if (typeof (this.menu) != 'undefined') {
4680 this.menu.parentType = this.xtype;
4681 this.menu.triggerEl = this.el;
4682 this.menu = this.addxtype(Roo.apply({}, this.menu));
4685 this.el.select('a',true).on('click', this.onClick, this);
4687 if(this.tagtype == 'span'){
4688 this.el.select('span',true).on('click', this.onClick, this);
4691 // at this point parent should be available..
4692 this.parent().register(this);
4695 onClick : function(e)
4697 if (e.getTarget('.dropdown-menu-item')) {
4698 // did you click on a menu itemm.... - then don't trigger onclick..
4703 this.preventDefault ||
4706 Roo.log("NavItem - prevent Default?");
4710 if (this.disabled) {
4714 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4715 if (tg && tg.transition) {
4716 Roo.log("waiting for the transitionend");
4722 //Roo.log("fire event clicked");
4723 if(this.fireEvent('click', this, e) === false){
4727 if(this.tagtype == 'span'){
4731 //Roo.log(this.href);
4732 var ael = this.el.select('a',true).first();
4735 if(ael && this.animateRef && this.href.indexOf('#') > -1){
4736 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4737 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4738 return; // ignore... - it's a 'hash' to another page.
4740 Roo.log("NavItem - prevent Default?");
4742 this.scrollToElement(e);
4746 var p = this.parent();
4748 if (['tabs','pills'].indexOf(p.type)!==-1) {
4749 if (typeof(p.setActiveItem) !== 'undefined') {
4750 p.setActiveItem(this);
4754 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4755 if (p.parentType == 'NavHeaderbar' && !this.menu) {
4756 // remove the collapsed menu expand...
4757 p.parent().el.select('.navbar-collapse',true).removeClass('in');
4761 isActive: function () {
4764 setActive : function(state, fire, is_was_active)
4766 if (this.active && !state && this.navId) {
4767 this.was_active = true;
4768 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4770 nv.clearWasActive(this);
4774 this.active = state;
4777 this.el.removeClass('active');
4778 } else if (!this.el.hasClass('active')) {
4779 this.el.addClass('active');
4782 this.fireEvent('changed', this, state);
4785 // show a panel if it's registered and related..
4787 if (!this.navId || !this.tabId || !state || is_was_active) {
4791 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4795 var pan = tg.getPanelByName(this.tabId);
4799 // if we can not flip to new panel - go back to old nav highlight..
4800 if (false == tg.showPanel(pan)) {
4801 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4803 var onav = nv.getWasActive();
4805 onav.setActive(true, false, true);
4814 // this should not be here...
4815 setDisabled : function(state)
4817 this.disabled = state;
4819 this.el.removeClass('disabled');
4820 } else if (!this.el.hasClass('disabled')) {
4821 this.el.addClass('disabled');
4827 * Fetch the element to display the tooltip on.
4828 * @return {Roo.Element} defaults to this.el
4830 tooltipEl : function()
4832 return this.el.select('' + this.tagtype + '', true).first();
4835 scrollToElement : function(e)
4837 var c = document.body;
4840 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
4842 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
4843 c = document.documentElement;
4846 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4852 var o = target.calcOffsetsTo(c);
4859 this.fireEvent('scrollto', this, options, e);
4861 Roo.get(c).scrollTo('top', options.value, true);
4874 * <span> icon </span>
4875 * <span> text </span>
4876 * <span>badge </span>
4880 * @class Roo.bootstrap.NavSidebarItem
4881 * @extends Roo.bootstrap.NavItem
4882 * Bootstrap Navbar.NavSidebarItem class
4883 * {String} badgeWeight (default|primary|success|info|warning|danger)the extra classes for the badge
4884 * {Boolean} open is the menu open
4885 * {Boolean} buttonView use button as the tigger el rather that a (default false)
4886 * {String} buttonWeight (default|primary|success|info|warning|danger)the extra classes for the button
4887 * {String} buttonSize (sm|md|lg)the extra classes for the button
4888 * {Boolean} showArrow show arrow next to the text (default true)
4890 * Create a new Navbar Button
4891 * @param {Object} config The config object
4893 Roo.bootstrap.NavSidebarItem = function(config){
4894 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4899 * The raw click event for the entire grid.
4900 * @param {Roo.EventObject} e
4905 * Fires when the active item active state changes
4906 * @param {Roo.bootstrap.NavSidebarItem} this
4907 * @param {boolean} state the new state
4915 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
4917 badgeWeight : 'default',
4923 buttonWeight : 'default',
4929 getAutoCreate : function(){
4934 href : this.href || '#',
4940 if(this.buttonView){
4943 href : this.href || '#',
4944 cls: 'btn btn-' + this.buttonWeight + ' btn-' + this.buttonSize + 'roo-button-dropdown-toggle',
4957 cfg.cls += ' active';
4960 if (this.disabled) {
4961 cfg.cls += ' disabled';
4964 cfg.cls += ' open x-open';
4967 if (this.glyphicon || this.icon) {
4968 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
4969 a.cn.push({ tag : 'i', cls : c }) ;
4972 if(!this.buttonView){
4975 html : this.html || ''
4982 if (this.badge !== '') {
4983 a.cn.push({ tag: 'span', cls : 'badge pull-right badge-' + this.badgeWeight, html: this.badge });
4989 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4992 a.cls += ' dropdown-toggle treeview' ;
4998 initEvents : function()
5000 if (typeof (this.menu) != 'undefined') {
5001 this.menu.parentType = this.xtype;
5002 this.menu.triggerEl = this.el;
5003 this.menu = this.addxtype(Roo.apply({}, this.menu));
5006 this.el.on('click', this.onClick, this);
5008 if(this.badge !== ''){
5009 this.badgeEl = this.el.select('.badge', true).first().setVisibilityMode(Roo.Element.DISPLAY);
5014 onClick : function(e)
5021 if(this.preventDefault){
5025 this.fireEvent('click', this);
5028 disable : function()
5030 this.setDisabled(true);
5035 this.setDisabled(false);
5038 setDisabled : function(state)
5040 if(this.disabled == state){
5044 this.disabled = state;
5047 this.el.addClass('disabled');
5051 this.el.removeClass('disabled');
5056 setActive : function(state)
5058 if(this.active == state){
5062 this.active = state;
5065 this.el.addClass('active');
5069 this.el.removeClass('active');
5074 isActive: function ()
5079 setBadge : function(str)
5085 this.badgeEl.dom.innerHTML = str;
5102 * @class Roo.bootstrap.Row
5103 * @extends Roo.bootstrap.Component
5104 * Bootstrap Row class (contains columns...)
5108 * @param {Object} config The config object
5111 Roo.bootstrap.Row = function(config){
5112 Roo.bootstrap.Row.superclass.constructor.call(this, config);
5115 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
5117 getAutoCreate : function(){
5136 * @class Roo.bootstrap.Element
5137 * @extends Roo.bootstrap.Component
5138 * Bootstrap Element class
5139 * @cfg {String} html contents of the element
5140 * @cfg {String} tag tag of the element
5141 * @cfg {String} cls class of the element
5142 * @cfg {Boolean} preventDefault (true|false) default false
5143 * @cfg {Boolean} clickable (true|false) default false
5146 * Create a new Element
5147 * @param {Object} config The config object
5150 Roo.bootstrap.Element = function(config){
5151 Roo.bootstrap.Element.superclass.constructor.call(this, config);
5157 * When a element is chick
5158 * @param {Roo.bootstrap.Element} this
5159 * @param {Roo.EventObject} e
5165 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
5170 preventDefault: false,
5173 getAutoCreate : function(){
5177 // cls: this.cls, double assign in parent class Component.js :: onRender
5184 initEvents: function()
5186 Roo.bootstrap.Element.superclass.initEvents.call(this);
5189 this.el.on('click', this.onClick, this);
5194 onClick : function(e)
5196 if(this.preventDefault){
5200 this.fireEvent('click', this, e);
5203 getValue : function()
5205 return this.el.dom.innerHTML;
5208 setValue : function(value)
5210 this.el.dom.innerHTML = value;
5225 * @class Roo.bootstrap.Pagination
5226 * @extends Roo.bootstrap.Component
5227 * Bootstrap Pagination class
5228 * @cfg {String} size xs | sm | md | lg
5229 * @cfg {Boolean} inverse false | true
5232 * Create a new Pagination
5233 * @param {Object} config The config object
5236 Roo.bootstrap.Pagination = function(config){
5237 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
5240 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
5246 getAutoCreate : function(){
5252 cfg.cls += ' inverse';
5258 cfg.cls += " " + this.cls;
5276 * @class Roo.bootstrap.PaginationItem
5277 * @extends Roo.bootstrap.Component
5278 * Bootstrap PaginationItem class
5279 * @cfg {String} html text
5280 * @cfg {String} href the link
5281 * @cfg {Boolean} preventDefault (true | false) default true
5282 * @cfg {Boolean} active (true | false) default false
5283 * @cfg {Boolean} disabled default false
5287 * Create a new PaginationItem
5288 * @param {Object} config The config object
5292 Roo.bootstrap.PaginationItem = function(config){
5293 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
5298 * The raw click event for the entire grid.
5299 * @param {Roo.EventObject} e
5305 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
5309 preventDefault: true,
5314 getAutoCreate : function(){
5320 href : this.href ? this.href : '#',
5321 html : this.html ? this.html : ''
5331 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
5335 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
5341 initEvents: function() {
5343 this.el.on('click', this.onClick, this);
5346 onClick : function(e)
5348 Roo.log('PaginationItem on click ');
5349 if(this.preventDefault){
5357 this.fireEvent('click', this, e);
5373 * @class Roo.bootstrap.Slider
5374 * @extends Roo.bootstrap.Component
5375 * Bootstrap Slider class
5378 * Create a new Slider
5379 * @param {Object} config The config object
5382 Roo.bootstrap.Slider = function(config){
5383 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
5386 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
5388 getAutoCreate : function(){
5392 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
5396 cls: 'ui-slider-handle ui-state-default ui-corner-all'
5408 * Ext JS Library 1.1.1
5409 * Copyright(c) 2006-2007, Ext JS, LLC.
5411 * Originally Released Under LGPL - original licence link has changed is not relivant.
5414 * <script type="text/javascript">
5419 * @class Roo.grid.ColumnModel
5420 * @extends Roo.util.Observable
5421 * This is the default implementation of a ColumnModel used by the Grid. It defines
5422 * the columns in the grid.
5425 var colModel = new Roo.grid.ColumnModel([
5426 {header: "Ticker", width: 60, sortable: true, locked: true},
5427 {header: "Company Name", width: 150, sortable: true},
5428 {header: "Market Cap.", width: 100, sortable: true},
5429 {header: "$ Sales", width: 100, sortable: true, renderer: money},
5430 {header: "Employees", width: 100, sortable: true, resizable: false}
5435 * The config options listed for this class are options which may appear in each
5436 * individual column definition.
5437 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
5439 * @param {Object} config An Array of column config objects. See this class's
5440 * config objects for details.
5442 Roo.grid.ColumnModel = function(config){
5444 * The config passed into the constructor
5446 this.config = config;
5449 // if no id, create one
5450 // if the column does not have a dataIndex mapping,
5451 // map it to the order it is in the config
5452 for(var i = 0, len = config.length; i < len; i++){
5454 if(typeof c.dataIndex == "undefined"){
5457 if(typeof c.renderer == "string"){
5458 c.renderer = Roo.util.Format[c.renderer];
5460 if(typeof c.id == "undefined"){
5463 if(c.editor && c.editor.xtype){
5464 c.editor = Roo.factory(c.editor, Roo.grid);
5466 if(c.editor && c.editor.isFormField){
5467 c.editor = new Roo.grid.GridEditor(c.editor);
5469 this.lookup[c.id] = c;
5473 * The width of columns which have no width specified (defaults to 100)
5476 this.defaultWidth = 100;
5479 * Default sortable of columns which have no sortable specified (defaults to false)
5482 this.defaultSortable = false;
5486 * @event widthchange
5487 * Fires when the width of a column changes.
5488 * @param {ColumnModel} this
5489 * @param {Number} columnIndex The column index
5490 * @param {Number} newWidth The new width
5492 "widthchange": true,
5494 * @event headerchange
5495 * Fires when the text of a header changes.
5496 * @param {ColumnModel} this
5497 * @param {Number} columnIndex The column index
5498 * @param {Number} newText The new header text
5500 "headerchange": true,
5502 * @event hiddenchange
5503 * Fires when a column is hidden or "unhidden".
5504 * @param {ColumnModel} this
5505 * @param {Number} columnIndex The column index
5506 * @param {Boolean} hidden true if hidden, false otherwise
5508 "hiddenchange": true,
5510 * @event columnmoved
5511 * Fires when a column is moved.
5512 * @param {ColumnModel} this
5513 * @param {Number} oldIndex
5514 * @param {Number} newIndex
5516 "columnmoved" : true,
5518 * @event columlockchange
5519 * Fires when a column's locked state is changed
5520 * @param {ColumnModel} this
5521 * @param {Number} colIndex
5522 * @param {Boolean} locked true if locked
5524 "columnlockchange" : true
5526 Roo.grid.ColumnModel.superclass.constructor.call(this);
5528 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
5530 * @cfg {String} header The header text to display in the Grid view.
5533 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
5534 * {@link Roo.data.Record} definition from which to draw the column's value. If not
5535 * specified, the column's index is used as an index into the Record's data Array.
5538 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
5539 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
5542 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
5543 * Defaults to the value of the {@link #defaultSortable} property.
5544 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
5547 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
5550 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
5553 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
5556 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
5559 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
5560 * given the cell's data value. See {@link #setRenderer}. If not specified, the
5561 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
5562 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
5565 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
5568 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
5571 * @cfg {String} valign (Optional) Set the CSS vertical-align property of the column (eg. middle, top, bottom etc). Defaults to undefined.
5574 * @cfg {String} cursor (Optional)
5577 * @cfg {String} tooltip (Optional)
5580 * @cfg {Number} xs (Optional)
5583 * @cfg {Number} sm (Optional)
5586 * @cfg {Number} md (Optional)
5589 * @cfg {Number} lg (Optional)
5592 * Returns the id of the column at the specified index.
5593 * @param {Number} index The column index
5594 * @return {String} the id
5596 getColumnId : function(index){
5597 return this.config[index].id;
5601 * Returns the column for a specified id.
5602 * @param {String} id The column id
5603 * @return {Object} the column
5605 getColumnById : function(id){
5606 return this.lookup[id];
5611 * Returns the column for a specified dataIndex.
5612 * @param {String} dataIndex The column dataIndex
5613 * @return {Object|Boolean} the column or false if not found
5615 getColumnByDataIndex: function(dataIndex){
5616 var index = this.findColumnIndex(dataIndex);
5617 return index > -1 ? this.config[index] : false;
5621 * Returns the index for a specified column id.
5622 * @param {String} id The column id
5623 * @return {Number} the index, or -1 if not found
5625 getIndexById : function(id){
5626 for(var i = 0, len = this.config.length; i < len; i++){
5627 if(this.config[i].id == id){
5635 * Returns the index for a specified column dataIndex.
5636 * @param {String} dataIndex The column dataIndex
5637 * @return {Number} the index, or -1 if not found
5640 findColumnIndex : function(dataIndex){
5641 for(var i = 0, len = this.config.length; i < len; i++){
5642 if(this.config[i].dataIndex == dataIndex){
5650 moveColumn : function(oldIndex, newIndex){
5651 var c = this.config[oldIndex];
5652 this.config.splice(oldIndex, 1);
5653 this.config.splice(newIndex, 0, c);
5654 this.dataMap = null;
5655 this.fireEvent("columnmoved", this, oldIndex, newIndex);
5658 isLocked : function(colIndex){
5659 return this.config[colIndex].locked === true;
5662 setLocked : function(colIndex, value, suppressEvent){
5663 if(this.isLocked(colIndex) == value){
5666 this.config[colIndex].locked = value;
5668 this.fireEvent("columnlockchange", this, colIndex, value);
5672 getTotalLockedWidth : function(){
5674 for(var i = 0; i < this.config.length; i++){
5675 if(this.isLocked(i) && !this.isHidden(i)){
5676 this.totalWidth += this.getColumnWidth(i);
5682 getLockedCount : function(){
5683 for(var i = 0, len = this.config.length; i < len; i++){
5684 if(!this.isLocked(i)){
5689 return this.config.length;
5693 * Returns the number of columns.
5696 getColumnCount : function(visibleOnly){
5697 if(visibleOnly === true){
5699 for(var i = 0, len = this.config.length; i < len; i++){
5700 if(!this.isHidden(i)){
5706 return this.config.length;
5710 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
5711 * @param {Function} fn
5712 * @param {Object} scope (optional)
5713 * @return {Array} result
5715 getColumnsBy : function(fn, scope){
5717 for(var i = 0, len = this.config.length; i < len; i++){
5718 var c = this.config[i];
5719 if(fn.call(scope||this, c, i) === true){
5727 * Returns true if the specified column is sortable.
5728 * @param {Number} col The column index
5731 isSortable : function(col){
5732 if(typeof this.config[col].sortable == "undefined"){
5733 return this.defaultSortable;
5735 return this.config[col].sortable;
5739 * Returns the rendering (formatting) function defined for the column.
5740 * @param {Number} col The column index.
5741 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
5743 getRenderer : function(col){
5744 if(!this.config[col].renderer){
5745 return Roo.grid.ColumnModel.defaultRenderer;
5747 return this.config[col].renderer;
5751 * Sets the rendering (formatting) function for a column.
5752 * @param {Number} col The column index
5753 * @param {Function} fn The function to use to process the cell's raw data
5754 * to return HTML markup for the grid view. The render function is called with
5755 * the following parameters:<ul>
5756 * <li>Data value.</li>
5757 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
5758 * <li>css A CSS style string to apply to the table cell.</li>
5759 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
5760 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
5761 * <li>Row index</li>
5762 * <li>Column index</li>
5763 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
5765 setRenderer : function(col, fn){
5766 this.config[col].renderer = fn;
5770 * Returns the width for the specified column.
5771 * @param {Number} col The column index
5774 getColumnWidth : function(col){
5775 return this.config[col].width * 1 || this.defaultWidth;
5779 * Sets the width for a column.
5780 * @param {Number} col The column index
5781 * @param {Number} width The new width
5783 setColumnWidth : function(col, width, suppressEvent){
5784 this.config[col].width = width;
5785 this.totalWidth = null;
5787 this.fireEvent("widthchange", this, col, width);
5792 * Returns the total width of all columns.
5793 * @param {Boolean} includeHidden True to include hidden column widths
5796 getTotalWidth : function(includeHidden){
5797 if(!this.totalWidth){
5798 this.totalWidth = 0;
5799 for(var i = 0, len = this.config.length; i < len; i++){
5800 if(includeHidden || !this.isHidden(i)){
5801 this.totalWidth += this.getColumnWidth(i);
5805 return this.totalWidth;
5809 * Returns the header for the specified column.
5810 * @param {Number} col The column index
5813 getColumnHeader : function(col){
5814 return this.config[col].header;
5818 * Sets the header for a column.
5819 * @param {Number} col The column index
5820 * @param {String} header The new header
5822 setColumnHeader : function(col, header){
5823 this.config[col].header = header;
5824 this.fireEvent("headerchange", this, col, header);
5828 * Returns the tooltip for the specified column.
5829 * @param {Number} col The column index
5832 getColumnTooltip : function(col){
5833 return this.config[col].tooltip;
5836 * Sets the tooltip for a column.
5837 * @param {Number} col The column index
5838 * @param {String} tooltip The new tooltip
5840 setColumnTooltip : function(col, tooltip){
5841 this.config[col].tooltip = tooltip;
5845 * Returns the dataIndex for the specified column.
5846 * @param {Number} col The column index
5849 getDataIndex : function(col){
5850 return this.config[col].dataIndex;
5854 * Sets the dataIndex for a column.
5855 * @param {Number} col The column index
5856 * @param {Number} dataIndex The new dataIndex
5858 setDataIndex : function(col, dataIndex){
5859 this.config[col].dataIndex = dataIndex;
5865 * Returns true if the cell is editable.
5866 * @param {Number} colIndex The column index
5867 * @param {Number} rowIndex The row index - this is nto actually used..?
5870 isCellEditable : function(colIndex, rowIndex){
5871 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
5875 * Returns the editor defined for the cell/column.
5876 * return false or null to disable editing.
5877 * @param {Number} colIndex The column index
5878 * @param {Number} rowIndex The row index
5881 getCellEditor : function(colIndex, rowIndex){
5882 return this.config[colIndex].editor;
5886 * Sets if a column is editable.
5887 * @param {Number} col The column index
5888 * @param {Boolean} editable True if the column is editable
5890 setEditable : function(col, editable){
5891 this.config[col].editable = editable;
5896 * Returns true if the column is hidden.
5897 * @param {Number} colIndex The column index
5900 isHidden : function(colIndex){
5901 return this.config[colIndex].hidden;
5906 * Returns true if the column width cannot be changed
5908 isFixed : function(colIndex){
5909 return this.config[colIndex].fixed;
5913 * Returns true if the column can be resized
5916 isResizable : function(colIndex){
5917 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
5920 * Sets if a column is hidden.
5921 * @param {Number} colIndex The column index
5922 * @param {Boolean} hidden True if the column is hidden
5924 setHidden : function(colIndex, hidden){
5925 this.config[colIndex].hidden = hidden;
5926 this.totalWidth = null;
5927 this.fireEvent("hiddenchange", this, colIndex, hidden);
5931 * Sets the editor for a column.
5932 * @param {Number} col The column index
5933 * @param {Object} editor The editor object
5935 setEditor : function(col, editor){
5936 this.config[col].editor = editor;
5940 Roo.grid.ColumnModel.defaultRenderer = function(value)
5942 if(typeof value == "object") {
5945 if(typeof value == "string" && value.length < 1){
5949 return String.format("{0}", value);
5952 // Alias for backwards compatibility
5953 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
5956 * Ext JS Library 1.1.1
5957 * Copyright(c) 2006-2007, Ext JS, LLC.
5959 * Originally Released Under LGPL - original licence link has changed is not relivant.
5962 * <script type="text/javascript">
5966 * @class Roo.LoadMask
5967 * A simple utility class for generically masking elements while loading data. If the element being masked has
5968 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
5969 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
5970 * element's UpdateManager load indicator and will be destroyed after the initial load.
5972 * Create a new LoadMask
5973 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
5974 * @param {Object} config The config object
5976 Roo.LoadMask = function(el, config){
5977 this.el = Roo.get(el);
5978 Roo.apply(this, config);
5980 this.store.on('beforeload', this.onBeforeLoad, this);
5981 this.store.on('load', this.onLoad, this);
5982 this.store.on('loadexception', this.onLoadException, this);
5983 this.removeMask = false;
5985 var um = this.el.getUpdateManager();
5986 um.showLoadIndicator = false; // disable the default indicator
5987 um.on('beforeupdate', this.onBeforeLoad, this);
5988 um.on('update', this.onLoad, this);
5989 um.on('failure', this.onLoad, this);
5990 this.removeMask = true;
5994 Roo.LoadMask.prototype = {
5996 * @cfg {Boolean} removeMask
5997 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
5998 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
6002 * The text to display in a centered loading message box (defaults to 'Loading...')
6006 * @cfg {String} msgCls
6007 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
6009 msgCls : 'x-mask-loading',
6012 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
6018 * Disables the mask to prevent it from being displayed
6020 disable : function(){
6021 this.disabled = true;
6025 * Enables the mask so that it can be displayed
6027 enable : function(){
6028 this.disabled = false;
6031 onLoadException : function()
6035 if (typeof(arguments[3]) != 'undefined') {
6036 Roo.MessageBox.alert("Error loading",arguments[3]);
6040 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
6041 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
6048 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
6053 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
6057 onBeforeLoad : function(){
6059 (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
6064 destroy : function(){
6066 this.store.un('beforeload', this.onBeforeLoad, this);
6067 this.store.un('load', this.onLoad, this);
6068 this.store.un('loadexception', this.onLoadException, this);
6070 var um = this.el.getUpdateManager();
6071 um.un('beforeupdate', this.onBeforeLoad, this);
6072 um.un('update', this.onLoad, this);
6073 um.un('failure', this.onLoad, this);
6084 * @class Roo.bootstrap.Table
6085 * @extends Roo.bootstrap.Component
6086 * Bootstrap Table class
6087 * @cfg {String} cls table class
6088 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
6089 * @cfg {String} bgcolor Specifies the background color for a table
6090 * @cfg {Number} border Specifies whether the table cells should have borders or not
6091 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
6092 * @cfg {Number} cellspacing Specifies the space between cells
6093 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
6094 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
6095 * @cfg {String} sortable Specifies that the table should be sortable
6096 * @cfg {String} summary Specifies a summary of the content of a table
6097 * @cfg {Number} width Specifies the width of a table
6098 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
6100 * @cfg {boolean} striped Should the rows be alternative striped
6101 * @cfg {boolean} bordered Add borders to the table
6102 * @cfg {boolean} hover Add hover highlighting
6103 * @cfg {boolean} condensed Format condensed
6104 * @cfg {boolean} responsive Format condensed
6105 * @cfg {Boolean} loadMask (true|false) default false
6106 * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
6107 * @cfg {Boolean} headerShow (true|false) generate thead, default true
6108 * @cfg {Boolean} rowSelection (true|false) default false
6109 * @cfg {Boolean} cellSelection (true|false) default false
6110 * @cfg {Boolean} scrollBody (true|false) default false - body scrolled / fixed header
6111 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
6112 * @cfg {Boolean} lazyLoad auto load data while scrolling to the end (default false)
6113 * @cfg {Boolean} auto_hide_footer auto hide footer if only one page (default false)
6117 * Create a new Table
6118 * @param {Object} config The config object
6121 Roo.bootstrap.Table = function(config){
6122 Roo.bootstrap.Table.superclass.constructor.call(this, config);
6127 this.rowSelection = (typeof(config.rowSelection) != 'undefined') ? config.rowSelection : this.rowSelection;
6128 this.cellSelection = (typeof(config.cellSelection) != 'undefined') ? config.cellSelection : this.cellSelection;
6129 this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
6130 this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
6132 this.sm = this.sm || {xtype: 'RowSelectionModel'};
6134 this.sm.grid = this;
6135 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
6136 this.sm = this.selModel;
6137 this.sm.xmodule = this.xmodule || false;
6140 if (this.cm && typeof(this.cm.config) == 'undefined') {
6141 this.colModel = new Roo.grid.ColumnModel(this.cm);
6142 this.cm = this.colModel;
6143 this.cm.xmodule = this.xmodule || false;
6146 this.store= Roo.factory(this.store, Roo.data);
6147 this.ds = this.store;
6148 this.ds.xmodule = this.xmodule || false;
6151 if (this.footer && this.store) {
6152 this.footer.dataSource = this.ds;
6153 this.footer = Roo.factory(this.footer);
6160 * Fires when a cell is clicked
6161 * @param {Roo.bootstrap.Table} this
6162 * @param {Roo.Element} el
6163 * @param {Number} rowIndex
6164 * @param {Number} columnIndex
6165 * @param {Roo.EventObject} e
6169 * @event celldblclick
6170 * Fires when a cell is double clicked
6171 * @param {Roo.bootstrap.Table} this
6172 * @param {Roo.Element} el
6173 * @param {Number} rowIndex
6174 * @param {Number} columnIndex
6175 * @param {Roo.EventObject} e
6177 "celldblclick" : true,
6180 * Fires when a row is clicked
6181 * @param {Roo.bootstrap.Table} this
6182 * @param {Roo.Element} el
6183 * @param {Number} rowIndex
6184 * @param {Roo.EventObject} e
6188 * @event rowdblclick
6189 * Fires when a row is double clicked
6190 * @param {Roo.bootstrap.Table} this
6191 * @param {Roo.Element} el
6192 * @param {Number} rowIndex
6193 * @param {Roo.EventObject} e
6195 "rowdblclick" : true,
6198 * Fires when a mouseover occur
6199 * @param {Roo.bootstrap.Table} this
6200 * @param {Roo.Element} el
6201 * @param {Number} rowIndex
6202 * @param {Number} columnIndex
6203 * @param {Roo.EventObject} e
6208 * Fires when a mouseout occur
6209 * @param {Roo.bootstrap.Table} this
6210 * @param {Roo.Element} el
6211 * @param {Number} rowIndex
6212 * @param {Number} columnIndex
6213 * @param {Roo.EventObject} e
6218 * Fires when a row is rendered, so you can change add a style to it.
6219 * @param {Roo.bootstrap.Table} this
6220 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
6224 * @event rowsrendered
6225 * Fires when all the rows have been rendered
6226 * @param {Roo.bootstrap.Table} this
6228 'rowsrendered' : true,
6230 * @event contextmenu
6231 * The raw contextmenu event for the entire grid.
6232 * @param {Roo.EventObject} e
6234 "contextmenu" : true,
6236 * @event rowcontextmenu
6237 * Fires when a row is right clicked
6238 * @param {Roo.bootstrap.Table} this
6239 * @param {Number} rowIndex
6240 * @param {Roo.EventObject} e
6242 "rowcontextmenu" : true,
6244 * @event cellcontextmenu
6245 * Fires when a cell is right clicked
6246 * @param {Roo.bootstrap.Table} this
6247 * @param {Number} rowIndex
6248 * @param {Number} cellIndex
6249 * @param {Roo.EventObject} e
6251 "cellcontextmenu" : true,
6253 * @event headercontextmenu
6254 * Fires when a header is right clicked
6255 * @param {Roo.bootstrap.Table} this
6256 * @param {Number} columnIndex
6257 * @param {Roo.EventObject} e
6259 "headercontextmenu" : true
6263 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
6289 rowSelection : false,
6290 cellSelection : false,
6293 // Roo.Element - the tbody
6295 // Roo.Element - thead element
6298 container: false, // used by gridpanel...
6304 auto_hide_footer : false,
6306 getAutoCreate : function()
6308 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
6315 if (this.scrollBody) {
6316 cfg.cls += ' table-body-fixed';
6319 cfg.cls += ' table-striped';
6323 cfg.cls += ' table-hover';
6325 if (this.bordered) {
6326 cfg.cls += ' table-bordered';
6328 if (this.condensed) {
6329 cfg.cls += ' table-condensed';
6331 if (this.responsive) {
6332 cfg.cls += ' table-responsive';
6336 cfg.cls+= ' ' +this.cls;
6339 // this lot should be simplifed...
6352 ].forEach(function(k) {
6360 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
6363 if(this.store || this.cm){
6364 if(this.headerShow){
6365 cfg.cn.push(this.renderHeader());
6368 cfg.cn.push(this.renderBody());
6370 if(this.footerShow){
6371 cfg.cn.push(this.renderFooter());
6373 // where does this come from?
6374 //cfg.cls+= ' TableGrid';
6377 return { cn : [ cfg ] };
6380 initEvents : function()
6382 if(!this.store || !this.cm){
6385 if (this.selModel) {
6386 this.selModel.initEvents();
6390 //Roo.log('initEvents with ds!!!!');
6392 this.mainBody = this.el.select('tbody', true).first();
6393 this.mainHead = this.el.select('thead', true).first();
6394 this.mainFoot = this.el.select('tfoot', true).first();
6400 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6401 e.on('click', _this.sort, _this);
6404 this.mainBody.on("click", this.onClick, this);
6405 this.mainBody.on("dblclick", this.onDblClick, this);
6407 // why is this done????? = it breaks dialogs??
6408 //this.parent().el.setStyle('position', 'relative');
6412 this.footer.parentId = this.id;
6413 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
6416 this.el.select('tfoot tr td').first().addClass('hide');
6421 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
6424 this.store.on('load', this.onLoad, this);
6425 this.store.on('beforeload', this.onBeforeLoad, this);
6426 this.store.on('update', this.onUpdate, this);
6427 this.store.on('add', this.onAdd, this);
6428 this.store.on("clear", this.clear, this);
6430 this.el.on("contextmenu", this.onContextMenu, this);
6432 this.mainBody.on('scroll', this.onBodyScroll, this);
6434 this.cm.on("headerchange", this.onHeaderChange, this);
6436 this.cm.on("hiddenchange", this.onHiddenChange, this, arguments);
6440 onContextMenu : function(e, t)
6442 this.processEvent("contextmenu", e);
6445 processEvent : function(name, e)
6447 if (name != 'touchstart' ) {
6448 this.fireEvent(name, e);
6451 var t = e.getTarget();
6453 var cell = Roo.get(t);
6459 if(cell.findParent('tfoot', false, true)){
6463 if(cell.findParent('thead', false, true)){
6465 if(e.getTarget().nodeName.toLowerCase() != 'th'){
6466 cell = Roo.get(t).findParent('th', false, true);
6468 Roo.log("failed to find th in thead?");
6469 Roo.log(e.getTarget());
6474 var cellIndex = cell.dom.cellIndex;
6476 var ename = name == 'touchstart' ? 'click' : name;
6477 this.fireEvent("header" + ename, this, cellIndex, e);
6482 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6483 cell = Roo.get(t).findParent('td', false, true);
6485 Roo.log("failed to find th in tbody?");
6486 Roo.log(e.getTarget());
6491 var row = cell.findParent('tr', false, true);
6492 var cellIndex = cell.dom.cellIndex;
6493 var rowIndex = row.dom.rowIndex - 1;
6497 this.fireEvent("row" + name, this, rowIndex, e);
6501 this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
6507 onMouseover : function(e, el)
6509 var cell = Roo.get(el);
6515 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6516 cell = cell.findParent('td', false, true);
6519 var row = cell.findParent('tr', false, true);
6520 var cellIndex = cell.dom.cellIndex;
6521 var rowIndex = row.dom.rowIndex - 1; // start from 0
6523 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
6527 onMouseout : function(e, el)
6529 var cell = Roo.get(el);
6535 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6536 cell = cell.findParent('td', false, true);
6539 var row = cell.findParent('tr', false, true);
6540 var cellIndex = cell.dom.cellIndex;
6541 var rowIndex = row.dom.rowIndex - 1; // start from 0
6543 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
6547 onClick : function(e, el)
6549 var cell = Roo.get(el);
6551 if(!cell || (!this.cellSelection && !this.rowSelection)){
6555 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6556 cell = cell.findParent('td', false, true);
6559 if(!cell || typeof(cell) == 'undefined'){
6563 var row = cell.findParent('tr', false, true);
6565 if(!row || typeof(row) == 'undefined'){
6569 var cellIndex = cell.dom.cellIndex;
6570 var rowIndex = this.getRowIndex(row);
6572 // why??? - should these not be based on SelectionModel?
6573 if(this.cellSelection){
6574 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
6577 if(this.rowSelection){
6578 this.fireEvent('rowclick', this, row, rowIndex, e);
6584 onDblClick : function(e,el)
6586 var cell = Roo.get(el);
6588 if(!cell || (!this.cellSelection && !this.rowSelection)){
6592 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6593 cell = cell.findParent('td', false, true);
6596 if(!cell || typeof(cell) == 'undefined'){
6600 var row = cell.findParent('tr', false, true);
6602 if(!row || typeof(row) == 'undefined'){
6606 var cellIndex = cell.dom.cellIndex;
6607 var rowIndex = this.getRowIndex(row);
6609 if(this.cellSelection){
6610 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
6613 if(this.rowSelection){
6614 this.fireEvent('rowdblclick', this, row, rowIndex, e);
6618 sort : function(e,el)
6620 var col = Roo.get(el);
6622 if(!col.hasClass('sortable')){
6626 var sort = col.attr('sort');
6629 if(col.select('i', true).first().hasClass('glyphicon-arrow-up')){
6633 this.store.sortInfo = {field : sort, direction : dir};
6636 Roo.log("calling footer first");
6637 this.footer.onClick('first');
6640 this.store.load({ params : { start : 0 } });
6644 renderHeader : function()
6652 this.totalWidth = 0;
6654 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6656 var config = cm.config[i];
6660 cls : 'x-hcol-' + i,
6662 html: cm.getColumnHeader(i)
6667 if(typeof(config.sortable) != 'undefined' && config.sortable){
6669 c.html = '<i class="glyphicon"></i>' + c.html;
6672 if(typeof(config.lgHeader) != 'undefined'){
6673 hh += '<span class="hidden-xs hidden-sm hidden-md">' + config.lgHeader + '</span>';
6676 if(typeof(config.mdHeader) != 'undefined'){
6677 hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
6680 if(typeof(config.smHeader) != 'undefined'){
6681 hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
6684 if(typeof(config.xsHeader) != 'undefined'){
6685 hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
6692 if(typeof(config.tooltip) != 'undefined'){
6693 c.tooltip = config.tooltip;
6696 if(typeof(config.colspan) != 'undefined'){
6697 c.colspan = config.colspan;
6700 if(typeof(config.hidden) != 'undefined' && config.hidden){
6701 c.style += ' display:none;';
6704 if(typeof(config.dataIndex) != 'undefined'){
6705 c.sort = config.dataIndex;
6710 if(typeof(config.align) != 'undefined' && config.align.length){
6711 c.style += ' text-align:' + config.align + ';';
6714 if(typeof(config.width) != 'undefined'){
6715 c.style += ' width:' + config.width + 'px;';
6716 this.totalWidth += config.width;
6718 this.totalWidth += 100; // assume minimum of 100 per column?
6721 if(typeof(config.cls) != 'undefined'){
6722 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
6725 ['xs','sm','md','lg'].map(function(size){
6727 if(typeof(config[size]) == 'undefined'){
6731 if (!config[size]) { // 0 = hidden
6732 c.cls += ' hidden-' + size;
6736 c.cls += ' col-' + size + '-' + config[size];
6746 renderBody : function()
6756 colspan : this.cm.getColumnCount()
6766 renderFooter : function()
6776 colspan : this.cm.getColumnCount()
6790 // Roo.log('ds onload');
6795 var ds = this.store;
6797 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6798 e.select('i', true).removeClass(['glyphicon-arrow-up', 'glyphicon-arrow-down']);
6799 if (_this.store.sortInfo) {
6801 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
6802 e.select('i', true).addClass(['glyphicon-arrow-up']);
6805 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
6806 e.select('i', true).addClass(['glyphicon-arrow-down']);
6811 var tbody = this.mainBody;
6813 if(ds.getCount() > 0){
6814 ds.data.each(function(d,rowIndex){
6815 var row = this.renderRow(cm, ds, rowIndex);
6817 tbody.createChild(row);
6821 if(row.cellObjects.length){
6822 Roo.each(row.cellObjects, function(r){
6823 _this.renderCellObject(r);
6830 var tfoot = this.el.select('tfoot', true).first();
6832 if(this.footerShow && this.auto_hide_footer && this.mainFoot){
6834 this.mainFoot.setVisibilityMode(Roo.Element.DISPLAY).hide();
6836 var total = this.ds.getTotalCount();
6838 if(this.footer.pageSize < total){
6839 this.mainFoot.show();
6843 Roo.each(this.el.select('tbody td', true).elements, function(e){
6844 e.on('mouseover', _this.onMouseover, _this);
6847 Roo.each(this.el.select('tbody td', true).elements, function(e){
6848 e.on('mouseout', _this.onMouseout, _this);
6850 this.fireEvent('rowsrendered', this);
6856 onUpdate : function(ds,record)
6858 this.refreshRow(record);
6862 onRemove : function(ds, record, index, isUpdate){
6863 if(isUpdate !== true){
6864 this.fireEvent("beforerowremoved", this, index, record);
6866 var bt = this.mainBody.dom;
6868 var rows = this.el.select('tbody > tr', true).elements;
6870 if(typeof(rows[index]) != 'undefined'){
6871 bt.removeChild(rows[index].dom);
6874 // if(bt.rows[index]){
6875 // bt.removeChild(bt.rows[index]);
6878 if(isUpdate !== true){
6879 //this.stripeRows(index);
6880 //this.syncRowHeights(index, index);
6882 this.fireEvent("rowremoved", this, index, record);
6886 onAdd : function(ds, records, rowIndex)
6888 //Roo.log('on Add called');
6889 // - note this does not handle multiple adding very well..
6890 var bt = this.mainBody.dom;
6891 for (var i =0 ; i < records.length;i++) {
6892 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
6893 //Roo.log(records[i]);
6894 //Roo.log(this.store.getAt(rowIndex+i));
6895 this.insertRow(this.store, rowIndex + i, false);
6902 refreshRow : function(record){
6903 var ds = this.store, index;
6904 if(typeof record == 'number'){
6906 record = ds.getAt(index);
6908 index = ds.indexOf(record);
6910 this.insertRow(ds, index, true);
6912 this.onRemove(ds, record, index+1, true);
6914 //this.syncRowHeights(index, index);
6916 this.fireEvent("rowupdated", this, index, record);
6919 insertRow : function(dm, rowIndex, isUpdate){
6922 this.fireEvent("beforerowsinserted", this, rowIndex);
6924 //var s = this.getScrollState();
6925 var row = this.renderRow(this.cm, this.store, rowIndex);
6926 // insert before rowIndex..
6927 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
6931 if(row.cellObjects.length){
6932 Roo.each(row.cellObjects, function(r){
6933 _this.renderCellObject(r);
6938 this.fireEvent("rowsinserted", this, rowIndex);
6939 //this.syncRowHeights(firstRow, lastRow);
6940 //this.stripeRows(firstRow);
6947 getRowDom : function(rowIndex)
6949 var rows = this.el.select('tbody > tr', true).elements;
6951 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
6954 // returns the object tree for a tr..
6957 renderRow : function(cm, ds, rowIndex)
6959 var d = ds.getAt(rowIndex);
6963 cls : 'x-row-' + rowIndex,
6967 var cellObjects = [];
6969 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6970 var config = cm.config[i];
6972 var renderer = cm.getRenderer(i);
6976 if(typeof(renderer) !== 'undefined'){
6977 value = renderer(d.data[cm.getDataIndex(i)], false, d);
6979 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
6980 // and are rendered into the cells after the row is rendered - using the id for the element.
6982 if(typeof(value) === 'object'){
6992 rowIndex : rowIndex,
6997 this.fireEvent('rowclass', this, rowcfg);
7001 cls : rowcfg.rowClass + ' x-col-' + i,
7003 html: (typeof(value) === 'object') ? '' : value
7010 if(typeof(config.colspan) != 'undefined'){
7011 td.colspan = config.colspan;
7014 if(typeof(config.hidden) != 'undefined' && config.hidden){
7015 td.style += ' display:none;';
7018 if(typeof(config.align) != 'undefined' && config.align.length){
7019 td.style += ' text-align:' + config.align + ';';
7021 if(typeof(config.valign) != 'undefined' && config.valign.length){
7022 td.style += ' vertical-align:' + config.valign + ';';
7025 if(typeof(config.width) != 'undefined'){
7026 td.style += ' width:' + config.width + 'px;';
7029 if(typeof(config.cursor) != 'undefined'){
7030 td.style += ' cursor:' + config.cursor + ';';
7033 if(typeof(config.cls) != 'undefined'){
7034 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
7037 ['xs','sm','md','lg'].map(function(size){
7039 if(typeof(config[size]) == 'undefined'){
7043 if (!config[size]) { // 0 = hidden
7044 td.cls += ' hidden-' + size;
7048 td.cls += ' col-' + size + '-' + config[size];
7056 row.cellObjects = cellObjects;
7064 onBeforeLoad : function()
7073 this.el.select('tbody', true).first().dom.innerHTML = '';
7076 * Show or hide a row.
7077 * @param {Number} rowIndex to show or hide
7078 * @param {Boolean} state hide
7080 setRowVisibility : function(rowIndex, state)
7082 var bt = this.mainBody.dom;
7084 var rows = this.el.select('tbody > tr', true).elements;
7086 if(typeof(rows[rowIndex]) == 'undefined'){
7089 rows[rowIndex].dom.style.display = state ? '' : 'none';
7093 getSelectionModel : function(){
7095 this.selModel = new Roo.bootstrap.Table.RowSelectionModel({grid: this});
7097 return this.selModel;
7100 * Render the Roo.bootstrap object from renderder
7102 renderCellObject : function(r)
7106 r.cfg.parentId = (typeof(r.container) == 'string') ? r.container : r.container.id;
7108 var t = r.cfg.render(r.container);
7111 Roo.each(r.cfg.cn, function(c){
7113 container: t.getChildContainer(),
7116 _this.renderCellObject(child);
7121 getRowIndex : function(row)
7125 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
7136 * Returns the grid's underlying element = used by panel.Grid
7137 * @return {Element} The element
7139 getGridEl : function(){
7143 * Forces a resize - used by panel.Grid
7144 * @return {Element} The element
7146 autoSize : function()
7148 //var ctr = Roo.get(this.container.dom.parentElement);
7149 var ctr = Roo.get(this.el.dom);
7151 var thd = this.getGridEl().select('thead',true).first();
7152 var tbd = this.getGridEl().select('tbody', true).first();
7153 var tfd = this.getGridEl().select('tfoot', true).first();
7155 var cw = ctr.getWidth();
7159 tbd.setSize(ctr.getWidth(),
7160 ctr.getHeight() - ((thd ? thd.getHeight() : 0) + (tfd ? tfd.getHeight() : 0))
7162 var barsize = (tbd.dom.offsetWidth - tbd.dom.clientWidth);
7165 cw = Math.max(cw, this.totalWidth);
7166 this.getGridEl().select('tr',true).setWidth(cw);
7167 // resize 'expandable coloumn?
7169 return; // we doe not have a view in this design..
7172 onBodyScroll: function()
7174 //Roo.log("body scrolled');" + this.mainBody.dom.scrollLeft);
7176 this.mainHead.setStyle({
7177 'position' : 'relative',
7178 'left': (-1* this.mainBody.dom.scrollLeft) + 'px'
7184 var scrollHeight = this.mainBody.dom.scrollHeight;
7186 var scrollTop = Math.ceil(this.mainBody.getScroll().top);
7188 var height = this.mainBody.getHeight();
7190 if(scrollHeight - height == scrollTop) {
7192 var total = this.ds.getTotalCount();
7194 if(this.footer.cursor + this.footer.pageSize < total){
7196 this.footer.ds.load({
7198 start : this.footer.cursor + this.footer.pageSize,
7199 limit : this.footer.pageSize
7209 onHeaderChange : function()
7211 var header = this.renderHeader();
7212 var table = this.el.select('table', true).first();
7214 this.mainHead.remove();
7215 this.mainHead = table.createChild(header, this.mainBody, false);
7218 onHiddenChange : function(colModel, colIndex, hidden)
7220 var thSelector = '#' + this.id + ' .x-hcol-' + colIndex;
7221 var tdSelector = '#' + this.id + ' .x-col-' + colIndex;
7223 this.CSS.updateRule(thSelector, "display", "");
7224 this.CSS.updateRule(tdSelector, "display", "");
7227 this.CSS.updateRule(thSelector, "display", "none");
7228 this.CSS.updateRule(tdSelector, "display", "none");
7231 this.onHeaderChange();
7235 setColumnWidth: function(col_index, width)
7237 // width = "md-2 xs-2..."
7238 if(!this.colModel.config[col_index]) {
7242 var w = width.split(" ");
7244 var rows = this.el.dom.getElementsByClassName("x-col-"+col_index);
7246 var h_row = this.el.dom.getElementsByClassName("x-hcol-"+col_index);
7249 for(var j = 0; j < w.length; j++) {
7255 var size_cls = w[j].split("-");
7257 if(!Number.isInteger(size_cls[1] * 1)) {
7261 if(!this.colModel.config[col_index][size_cls[0]]) {
7265 if(!h_row[0].classList.contains("col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]])) {
7269 h_row[0].classList.replace(
7270 "col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]],
7271 "col-"+size_cls[0]+"-"+size_cls[1]
7274 for(var i = 0; i < rows.length; i++) {
7276 var size_cls = w[j].split("-");
7278 if(!Number.isInteger(size_cls[1] * 1)) {
7282 if(!this.colModel.config[col_index][size_cls[0]]) {
7286 if(!rows[i].classList.contains("col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]])) {
7290 rows[i].classList.replace(
7291 "col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]],
7292 "col-"+size_cls[0]+"-"+size_cls[1]
7296 this.colModel.config[col_index][size_cls[0]] = size_cls[1];
7311 * @class Roo.bootstrap.TableCell
7312 * @extends Roo.bootstrap.Component
7313 * Bootstrap TableCell class
7314 * @cfg {String} html cell contain text
7315 * @cfg {String} cls cell class
7316 * @cfg {String} tag cell tag (td|th) default td
7317 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
7318 * @cfg {String} align Aligns the content in a cell
7319 * @cfg {String} axis Categorizes cells
7320 * @cfg {String} bgcolor Specifies the background color of a cell
7321 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7322 * @cfg {Number} colspan Specifies the number of columns a cell should span
7323 * @cfg {String} headers Specifies one or more header cells a cell is related to
7324 * @cfg {Number} height Sets the height of a cell
7325 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
7326 * @cfg {Number} rowspan Sets the number of rows a cell should span
7327 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
7328 * @cfg {String} valign Vertical aligns the content in a cell
7329 * @cfg {Number} width Specifies the width of a cell
7332 * Create a new TableCell
7333 * @param {Object} config The config object
7336 Roo.bootstrap.TableCell = function(config){
7337 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
7340 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
7360 getAutoCreate : function(){
7361 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
7381 cfg.align=this.align
7387 cfg.bgcolor=this.bgcolor
7390 cfg.charoff=this.charoff
7393 cfg.colspan=this.colspan
7396 cfg.headers=this.headers
7399 cfg.height=this.height
7402 cfg.nowrap=this.nowrap
7405 cfg.rowspan=this.rowspan
7408 cfg.scope=this.scope
7411 cfg.valign=this.valign
7414 cfg.width=this.width
7433 * @class Roo.bootstrap.TableRow
7434 * @extends Roo.bootstrap.Component
7435 * Bootstrap TableRow class
7436 * @cfg {String} cls row class
7437 * @cfg {String} align Aligns the content in a table row
7438 * @cfg {String} bgcolor Specifies a background color for a table row
7439 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7440 * @cfg {String} valign Vertical aligns the content in a table row
7443 * Create a new TableRow
7444 * @param {Object} config The config object
7447 Roo.bootstrap.TableRow = function(config){
7448 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
7451 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
7459 getAutoCreate : function(){
7460 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
7470 cfg.align = this.align;
7473 cfg.bgcolor = this.bgcolor;
7476 cfg.charoff = this.charoff;
7479 cfg.valign = this.valign;
7497 * @class Roo.bootstrap.TableBody
7498 * @extends Roo.bootstrap.Component
7499 * Bootstrap TableBody class
7500 * @cfg {String} cls element class
7501 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
7502 * @cfg {String} align Aligns the content inside the element
7503 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
7504 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
7507 * Create a new TableBody
7508 * @param {Object} config The config object
7511 Roo.bootstrap.TableBody = function(config){
7512 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
7515 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
7523 getAutoCreate : function(){
7524 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
7538 cfg.align = this.align;
7541 cfg.charoff = this.charoff;
7544 cfg.valign = this.valign;
7551 // initEvents : function()
7558 // this.store = Roo.factory(this.store, Roo.data);
7559 // this.store.on('load', this.onLoad, this);
7561 // this.store.load();
7565 // onLoad: function ()
7567 // this.fireEvent('load', this);
7577 * Ext JS Library 1.1.1
7578 * Copyright(c) 2006-2007, Ext JS, LLC.
7580 * Originally Released Under LGPL - original licence link has changed is not relivant.
7583 * <script type="text/javascript">
7586 // as we use this in bootstrap.
7587 Roo.namespace('Roo.form');
7589 * @class Roo.form.Action
7590 * Internal Class used to handle form actions
7592 * @param {Roo.form.BasicForm} el The form element or its id
7593 * @param {Object} config Configuration options
7598 // define the action interface
7599 Roo.form.Action = function(form, options){
7601 this.options = options || {};
7604 * Client Validation Failed
7607 Roo.form.Action.CLIENT_INVALID = 'client';
7609 * Server Validation Failed
7612 Roo.form.Action.SERVER_INVALID = 'server';
7614 * Connect to Server Failed
7617 Roo.form.Action.CONNECT_FAILURE = 'connect';
7619 * Reading Data from Server Failed
7622 Roo.form.Action.LOAD_FAILURE = 'load';
7624 Roo.form.Action.prototype = {
7626 failureType : undefined,
7627 response : undefined,
7631 run : function(options){
7636 success : function(response){
7641 handleResponse : function(response){
7645 // default connection failure
7646 failure : function(response){
7648 this.response = response;
7649 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7650 this.form.afterAction(this, false);
7653 processResponse : function(response){
7654 this.response = response;
7655 if(!response.responseText){
7658 this.result = this.handleResponse(response);
7662 // utility functions used internally
7663 getUrl : function(appendParams){
7664 var url = this.options.url || this.form.url || this.form.el.dom.action;
7666 var p = this.getParams();
7668 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
7674 getMethod : function(){
7675 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
7678 getParams : function(){
7679 var bp = this.form.baseParams;
7680 var p = this.options.params;
7682 if(typeof p == "object"){
7683 p = Roo.urlEncode(Roo.applyIf(p, bp));
7684 }else if(typeof p == 'string' && bp){
7685 p += '&' + Roo.urlEncode(bp);
7688 p = Roo.urlEncode(bp);
7693 createCallback : function(){
7695 success: this.success,
7696 failure: this.failure,
7698 timeout: (this.form.timeout*1000),
7699 upload: this.form.fileUpload ? this.success : undefined
7704 Roo.form.Action.Submit = function(form, options){
7705 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
7708 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
7711 haveProgress : false,
7712 uploadComplete : false,
7714 // uploadProgress indicator.
7715 uploadProgress : function()
7717 if (!this.form.progressUrl) {
7721 if (!this.haveProgress) {
7722 Roo.MessageBox.progress("Uploading", "Uploading");
7724 if (this.uploadComplete) {
7725 Roo.MessageBox.hide();
7729 this.haveProgress = true;
7731 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
7733 var c = new Roo.data.Connection();
7735 url : this.form.progressUrl,
7740 success : function(req){
7741 //console.log(data);
7745 rdata = Roo.decode(req.responseText)
7747 Roo.log("Invalid data from server..");
7751 if (!rdata || !rdata.success) {
7753 Roo.MessageBox.alert(Roo.encode(rdata));
7756 var data = rdata.data;
7758 if (this.uploadComplete) {
7759 Roo.MessageBox.hide();
7764 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
7765 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
7768 this.uploadProgress.defer(2000,this);
7771 failure: function(data) {
7772 Roo.log('progress url failed ');
7783 // run get Values on the form, so it syncs any secondary forms.
7784 this.form.getValues();
7786 var o = this.options;
7787 var method = this.getMethod();
7788 var isPost = method == 'POST';
7789 if(o.clientValidation === false || this.form.isValid()){
7791 if (this.form.progressUrl) {
7792 this.form.findField('UPLOAD_IDENTIFIER').setValue(
7793 (new Date() * 1) + '' + Math.random());
7798 Roo.Ajax.request(Roo.apply(this.createCallback(), {
7799 form:this.form.el.dom,
7800 url:this.getUrl(!isPost),
7802 params:isPost ? this.getParams() : null,
7803 isUpload: this.form.fileUpload
7806 this.uploadProgress();
7808 }else if (o.clientValidation !== false){ // client validation failed
7809 this.failureType = Roo.form.Action.CLIENT_INVALID;
7810 this.form.afterAction(this, false);
7814 success : function(response)
7816 this.uploadComplete= true;
7817 if (this.haveProgress) {
7818 Roo.MessageBox.hide();
7822 var result = this.processResponse(response);
7823 if(result === true || result.success){
7824 this.form.afterAction(this, true);
7828 this.form.markInvalid(result.errors);
7829 this.failureType = Roo.form.Action.SERVER_INVALID;
7831 this.form.afterAction(this, false);
7833 failure : function(response)
7835 this.uploadComplete= true;
7836 if (this.haveProgress) {
7837 Roo.MessageBox.hide();
7840 this.response = response;
7841 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7842 this.form.afterAction(this, false);
7845 handleResponse : function(response){
7846 if(this.form.errorReader){
7847 var rs = this.form.errorReader.read(response);
7850 for(var i = 0, len = rs.records.length; i < len; i++) {
7851 var r = rs.records[i];
7855 if(errors.length < 1){
7859 success : rs.success,
7865 ret = Roo.decode(response.responseText);
7869 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
7879 Roo.form.Action.Load = function(form, options){
7880 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
7881 this.reader = this.form.reader;
7884 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
7889 Roo.Ajax.request(Roo.apply(
7890 this.createCallback(), {
7891 method:this.getMethod(),
7892 url:this.getUrl(false),
7893 params:this.getParams()
7897 success : function(response){
7899 var result = this.processResponse(response);
7900 if(result === true || !result.success || !result.data){
7901 this.failureType = Roo.form.Action.LOAD_FAILURE;
7902 this.form.afterAction(this, false);
7905 this.form.clearInvalid();
7906 this.form.setValues(result.data);
7907 this.form.afterAction(this, true);
7910 handleResponse : function(response){
7911 if(this.form.reader){
7912 var rs = this.form.reader.read(response);
7913 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
7915 success : rs.success,
7919 return Roo.decode(response.responseText);
7923 Roo.form.Action.ACTION_TYPES = {
7924 'load' : Roo.form.Action.Load,
7925 'submit' : Roo.form.Action.Submit
7934 * @class Roo.bootstrap.Form
7935 * @extends Roo.bootstrap.Component
7936 * Bootstrap Form class
7937 * @cfg {String} method GET | POST (default POST)
7938 * @cfg {String} labelAlign top | left (default top)
7939 * @cfg {String} align left | right - for navbars
7940 * @cfg {Boolean} loadMask load mask when submit (default true)
7945 * @param {Object} config The config object
7949 Roo.bootstrap.Form = function(config){
7951 Roo.bootstrap.Form.superclass.constructor.call(this, config);
7953 Roo.bootstrap.Form.popover.apply();
7957 * @event clientvalidation
7958 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
7959 * @param {Form} this
7960 * @param {Boolean} valid true if the form has passed client-side validation
7962 clientvalidation: true,
7964 * @event beforeaction
7965 * Fires before any action is performed. Return false to cancel the action.
7966 * @param {Form} this
7967 * @param {Action} action The action to be performed
7971 * @event actionfailed
7972 * Fires when an action fails.
7973 * @param {Form} this
7974 * @param {Action} action The action that failed
7976 actionfailed : true,
7978 * @event actioncomplete
7979 * Fires when an action is completed.
7980 * @param {Form} this
7981 * @param {Action} action The action that completed
7983 actioncomplete : true
7987 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
7990 * @cfg {String} method
7991 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
7996 * The URL to use for form actions if one isn't supplied in the action options.
7999 * @cfg {Boolean} fileUpload
8000 * Set to true if this form is a file upload.
8004 * @cfg {Object} baseParams
8005 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
8009 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
8013 * @cfg {Sting} align (left|right) for navbar forms
8018 activeAction : null,
8021 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
8022 * element by passing it or its id or mask the form itself by passing in true.
8025 waitMsgTarget : false,
8030 * @cfg {Boolean} errorMask (true|false) default false
8035 * @cfg {Number} maskOffset Default 100
8040 * @cfg {Boolean} maskBody
8044 getAutoCreate : function(){
8048 method : this.method || 'POST',
8049 id : this.id || Roo.id(),
8052 if (this.parent().xtype.match(/^Nav/)) {
8053 cfg.cls = 'navbar-form form-inline navbar-' + this.align;
8057 if (this.labelAlign == 'left' ) {
8058 cfg.cls += ' form-horizontal';
8064 initEvents : function()
8066 this.el.on('submit', this.onSubmit, this);
8067 // this was added as random key presses on the form where triggering form submit.
8068 this.el.on('keypress', function(e) {
8069 if (e.getCharCode() != 13) {
8072 // we might need to allow it for textareas.. and some other items.
8073 // check e.getTarget().
8075 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
8079 Roo.log("keypress blocked");
8087 onSubmit : function(e){
8092 * Returns true if client-side validation on the form is successful.
8095 isValid : function(){
8096 var items = this.getItems();
8100 items.each(function(f){
8106 Roo.log('invalid field: ' + f.name);
8110 if(!target && f.el.isVisible(true)){
8116 if(this.errorMask && !valid){
8117 Roo.bootstrap.Form.popover.mask(this, target);
8124 * Returns true if any fields in this form have changed since their original load.
8127 isDirty : function(){
8129 var items = this.getItems();
8130 items.each(function(f){
8140 * Performs a predefined action (submit or load) or custom actions you define on this form.
8141 * @param {String} actionName The name of the action type
8142 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
8143 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
8144 * accept other config options):
8146 Property Type Description
8147 ---------------- --------------- ----------------------------------------------------------------------------------
8148 url String The url for the action (defaults to the form's url)
8149 method String The form method to use (defaults to the form's method, or POST if not defined)
8150 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
8151 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
8152 validate the form on the client (defaults to false)
8154 * @return {BasicForm} this
8156 doAction : function(action, options){
8157 if(typeof action == 'string'){
8158 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
8160 if(this.fireEvent('beforeaction', this, action) !== false){
8161 this.beforeAction(action);
8162 action.run.defer(100, action);
8168 beforeAction : function(action){
8169 var o = action.options;
8174 Roo.get(document.body).mask(o.waitMsg || "Sending", 'x-mask-loading')
8176 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
8179 // not really supported yet.. ??
8181 //if(this.waitMsgTarget === true){
8182 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
8183 //}else if(this.waitMsgTarget){
8184 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
8185 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
8187 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
8193 afterAction : function(action, success){
8194 this.activeAction = null;
8195 var o = action.options;
8200 Roo.get(document.body).unmask();
8206 //if(this.waitMsgTarget === true){
8207 // this.el.unmask();
8208 //}else if(this.waitMsgTarget){
8209 // this.waitMsgTarget.unmask();
8211 // Roo.MessageBox.updateProgress(1);
8212 // Roo.MessageBox.hide();
8219 Roo.callback(o.success, o.scope, [this, action]);
8220 this.fireEvent('actioncomplete', this, action);
8224 // failure condition..
8225 // we have a scenario where updates need confirming.
8226 // eg. if a locking scenario exists..
8227 // we look for { errors : { needs_confirm : true }} in the response.
8229 (typeof(action.result) != 'undefined') &&
8230 (typeof(action.result.errors) != 'undefined') &&
8231 (typeof(action.result.errors.needs_confirm) != 'undefined')
8234 Roo.log("not supported yet");
8237 Roo.MessageBox.confirm(
8238 "Change requires confirmation",
8239 action.result.errorMsg,
8244 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
8254 Roo.callback(o.failure, o.scope, [this, action]);
8255 // show an error message if no failed handler is set..
8256 if (!this.hasListener('actionfailed')) {
8257 Roo.log("need to add dialog support");
8259 Roo.MessageBox.alert("Error",
8260 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
8261 action.result.errorMsg :
8262 "Saving Failed, please check your entries or try again"
8267 this.fireEvent('actionfailed', this, action);
8272 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
8273 * @param {String} id The value to search for
8276 findField : function(id){
8277 var items = this.getItems();
8278 var field = items.get(id);
8280 items.each(function(f){
8281 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
8288 return field || null;
8291 * Mark fields in this form invalid in bulk.
8292 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
8293 * @return {BasicForm} this
8295 markInvalid : function(errors){
8296 if(errors instanceof Array){
8297 for(var i = 0, len = errors.length; i < len; i++){
8298 var fieldError = errors[i];
8299 var f = this.findField(fieldError.id);
8301 f.markInvalid(fieldError.msg);
8307 if(typeof errors[id] != 'function' && (field = this.findField(id))){
8308 field.markInvalid(errors[id]);
8312 //Roo.each(this.childForms || [], function (f) {
8313 // f.markInvalid(errors);
8320 * Set values for fields in this form in bulk.
8321 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
8322 * @return {BasicForm} this
8324 setValues : function(values){
8325 if(values instanceof Array){ // array of objects
8326 for(var i = 0, len = values.length; i < len; i++){
8328 var f = this.findField(v.id);
8330 f.setValue(v.value);
8331 if(this.trackResetOnLoad){
8332 f.originalValue = f.getValue();
8336 }else{ // object hash
8339 if(typeof values[id] != 'function' && (field = this.findField(id))){
8341 if (field.setFromData &&
8343 field.displayField &&
8344 // combos' with local stores can
8345 // be queried via setValue()
8346 // to set their value..
8347 (field.store && !field.store.isLocal)
8351 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
8352 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
8353 field.setFromData(sd);
8355 } else if(field.setFromData && (field.store && !field.store.isLocal)) {
8357 field.setFromData(values);
8360 field.setValue(values[id]);
8364 if(this.trackResetOnLoad){
8365 field.originalValue = field.getValue();
8371 //Roo.each(this.childForms || [], function (f) {
8372 // f.setValues(values);
8379 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
8380 * they are returned as an array.
8381 * @param {Boolean} asString
8384 getValues : function(asString){
8385 //if (this.childForms) {
8386 // copy values from the child forms
8387 // Roo.each(this.childForms, function (f) {
8388 // this.setValues(f.getValues());
8394 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
8395 if(asString === true){
8398 return Roo.urlDecode(fs);
8402 * Returns the fields in this form as an object with key/value pairs.
8403 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
8406 getFieldValues : function(with_hidden)
8408 var items = this.getItems();
8410 items.each(function(f){
8416 var v = f.getValue();
8418 if (f.inputType =='radio') {
8419 if (typeof(ret[f.getName()]) == 'undefined') {
8420 ret[f.getName()] = ''; // empty..
8423 if (!f.el.dom.checked) {
8431 if(f.xtype == 'MoneyField'){
8432 ret[f.currencyName] = f.getCurrency();
8435 // not sure if this supported any more..
8436 if ((typeof(v) == 'object') && f.getRawValue) {
8437 v = f.getRawValue() ; // dates..
8439 // combo boxes where name != hiddenName...
8440 if (f.name !== false && f.name != '' && f.name != f.getName()) {
8441 ret[f.name] = f.getRawValue();
8443 ret[f.getName()] = v;
8450 * Clears all invalid messages in this form.
8451 * @return {BasicForm} this
8453 clearInvalid : function(){
8454 var items = this.getItems();
8456 items.each(function(f){
8465 * @return {BasicForm} this
8468 var items = this.getItems();
8469 items.each(function(f){
8473 Roo.each(this.childForms || [], function (f) {
8481 getItems : function()
8483 var r=new Roo.util.MixedCollection(false, function(o){
8484 return o.id || (o.id = Roo.id());
8486 var iter = function(el) {
8493 Roo.each(el.items,function(e) {
8502 hideFields : function(items)
8504 Roo.each(items, function(i){
8506 var f = this.findField(i);
8517 showFields : function(items)
8519 Roo.each(items, function(i){
8521 var f = this.findField(i);
8534 Roo.apply(Roo.bootstrap.Form, {
8561 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
8562 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
8563 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
8564 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
8567 this.maskEl.top.enableDisplayMode("block");
8568 this.maskEl.left.enableDisplayMode("block");
8569 this.maskEl.bottom.enableDisplayMode("block");
8570 this.maskEl.right.enableDisplayMode("block");
8572 this.toolTip = new Roo.bootstrap.Tooltip({
8573 cls : 'roo-form-error-popover',
8575 'left' : ['r-l', [-2,0], 'right'],
8576 'right' : ['l-r', [2,0], 'left'],
8577 'bottom' : ['tl-bl', [0,2], 'top'],
8578 'top' : [ 'bl-tl', [0,-2], 'bottom']
8582 this.toolTip.render(Roo.get(document.body));
8584 this.toolTip.el.enableDisplayMode("block");
8586 Roo.get(document.body).on('click', function(){
8590 Roo.get(document.body).on('touchstart', function(){
8594 this.isApplied = true
8597 mask : function(form, target)
8601 this.target = target;
8603 if(!this.form.errorMask || !target.el){
8607 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.modal', 100, true) || Roo.get(document.body);
8609 Roo.log(scrollable);
8611 var ot = this.target.el.calcOffsetsTo(scrollable);
8613 var scrollTo = ot[1] - this.form.maskOffset;
8615 scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
8617 scrollable.scrollTo('top', scrollTo);
8619 var box = this.target.el.getBox();
8621 var zIndex = Roo.bootstrap.Modal.zIndex++;
8624 this.maskEl.top.setStyle('position', 'absolute');
8625 this.maskEl.top.setStyle('z-index', zIndex);
8626 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
8627 this.maskEl.top.setLeft(0);
8628 this.maskEl.top.setTop(0);
8629 this.maskEl.top.show();
8631 this.maskEl.left.setStyle('position', 'absolute');
8632 this.maskEl.left.setStyle('z-index', zIndex);
8633 this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
8634 this.maskEl.left.setLeft(0);
8635 this.maskEl.left.setTop(box.y - this.padding);
8636 this.maskEl.left.show();
8638 this.maskEl.bottom.setStyle('position', 'absolute');
8639 this.maskEl.bottom.setStyle('z-index', zIndex);
8640 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
8641 this.maskEl.bottom.setLeft(0);
8642 this.maskEl.bottom.setTop(box.bottom + this.padding);
8643 this.maskEl.bottom.show();
8645 this.maskEl.right.setStyle('position', 'absolute');
8646 this.maskEl.right.setStyle('z-index', zIndex);
8647 this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
8648 this.maskEl.right.setLeft(box.right + this.padding);
8649 this.maskEl.right.setTop(box.y - this.padding);
8650 this.maskEl.right.show();
8652 this.toolTip.bindEl = this.target.el;
8654 this.toolTip.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
8656 var tip = this.target.blankText;
8658 if(this.target.getValue() !== '' ) {
8660 if (this.target.invalidText.length) {
8661 tip = this.target.invalidText;
8662 } else if (this.target.regexText.length){
8663 tip = this.target.regexText;
8667 this.toolTip.show(tip);
8669 this.intervalID = window.setInterval(function() {
8670 Roo.bootstrap.Form.popover.unmask();
8673 window.onwheel = function(){ return false;};
8675 (function(){ this.isMasked = true; }).defer(500, this);
8681 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
8685 this.maskEl.top.setStyle('position', 'absolute');
8686 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
8687 this.maskEl.top.hide();
8689 this.maskEl.left.setStyle('position', 'absolute');
8690 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
8691 this.maskEl.left.hide();
8693 this.maskEl.bottom.setStyle('position', 'absolute');
8694 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
8695 this.maskEl.bottom.hide();
8697 this.maskEl.right.setStyle('position', 'absolute');
8698 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
8699 this.maskEl.right.hide();
8701 this.toolTip.hide();
8703 this.toolTip.el.hide();
8705 window.onwheel = function(){ return true;};
8707 if(this.intervalID){
8708 window.clearInterval(this.intervalID);
8709 this.intervalID = false;
8712 this.isMasked = false;
8722 * Ext JS Library 1.1.1
8723 * Copyright(c) 2006-2007, Ext JS, LLC.
8725 * Originally Released Under LGPL - original licence link has changed is not relivant.
8728 * <script type="text/javascript">
8731 * @class Roo.form.VTypes
8732 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
8735 Roo.form.VTypes = function(){
8736 // closure these in so they are only created once.
8737 var alpha = /^[a-zA-Z_]+$/;
8738 var alphanum = /^[a-zA-Z0-9_]+$/;
8739 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
8740 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
8742 // All these messages and functions are configurable
8745 * The function used to validate email addresses
8746 * @param {String} value The email address
8748 'email' : function(v){
8749 return email.test(v);
8752 * The error text to display when the email validation function returns false
8755 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
8757 * The keystroke filter mask to be applied on email input
8760 'emailMask' : /[a-z0-9_\.\-@]/i,
8763 * The function used to validate URLs
8764 * @param {String} value The URL
8766 'url' : function(v){
8770 * The error text to display when the url validation function returns false
8773 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
8776 * The function used to validate alpha values
8777 * @param {String} value The value
8779 'alpha' : function(v){
8780 return alpha.test(v);
8783 * The error text to display when the alpha validation function returns false
8786 'alphaText' : 'This field should only contain letters and _',
8788 * The keystroke filter mask to be applied on alpha input
8791 'alphaMask' : /[a-z_]/i,
8794 * The function used to validate alphanumeric values
8795 * @param {String} value The value
8797 'alphanum' : function(v){
8798 return alphanum.test(v);
8801 * The error text to display when the alphanumeric validation function returns false
8804 'alphanumText' : 'This field should only contain letters, numbers and _',
8806 * The keystroke filter mask to be applied on alphanumeric input
8809 'alphanumMask' : /[a-z0-9_]/i
8819 * @class Roo.bootstrap.Input
8820 * @extends Roo.bootstrap.Component
8821 * Bootstrap Input class
8822 * @cfg {Boolean} disabled is it disabled
8823 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
8824 * @cfg {String} name name of the input
8825 * @cfg {string} fieldLabel - the label associated
8826 * @cfg {string} placeholder - placeholder to put in text.
8827 * @cfg {string} before - input group add on before
8828 * @cfg {string} after - input group add on after
8829 * @cfg {string} size - (lg|sm) or leave empty..
8830 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
8831 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
8832 * @cfg {Number} md colspan out of 12 for computer-sized screens
8833 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
8834 * @cfg {string} value default value of the input
8835 * @cfg {Number} labelWidth set the width of label
8836 * @cfg {Number} labellg set the width of label (1-12)
8837 * @cfg {Number} labelmd set the width of label (1-12)
8838 * @cfg {Number} labelsm set the width of label (1-12)
8839 * @cfg {Number} labelxs set the width of label (1-12)
8840 * @cfg {String} labelAlign (top|left)
8841 * @cfg {Boolean} readOnly Specifies that the field should be read-only
8842 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
8843 * @cfg {String} indicatorpos (left|right) default left
8844 * @cfg {String} capture (user|camera) use for file input only. (default empty)
8845 * @cfg {String} accept (image|video|audio) use for file input only. (default empty)
8847 * @cfg {String} align (left|center|right) Default left
8848 * @cfg {Boolean} forceFeedback (true|false) Default false
8851 * Create a new Input
8852 * @param {Object} config The config object
8855 Roo.bootstrap.Input = function(config){
8857 Roo.bootstrap.Input.superclass.constructor.call(this, config);
8862 * Fires when this field receives input focus.
8863 * @param {Roo.form.Field} this
8868 * Fires when this field loses input focus.
8869 * @param {Roo.form.Field} this
8874 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
8875 * {@link Roo.EventObject#getKey} to determine which key was pressed.
8876 * @param {Roo.form.Field} this
8877 * @param {Roo.EventObject} e The event object
8882 * Fires just before the field blurs if the field value has changed.
8883 * @param {Roo.form.Field} this
8884 * @param {Mixed} newValue The new value
8885 * @param {Mixed} oldValue The original value
8890 * Fires after the field has been marked as invalid.
8891 * @param {Roo.form.Field} this
8892 * @param {String} msg The validation message
8897 * Fires after the field has been validated with no errors.
8898 * @param {Roo.form.Field} this
8903 * Fires after the key up
8904 * @param {Roo.form.Field} this
8905 * @param {Roo.EventObject} e The event Object
8911 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
8913 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
8914 automatic validation (defaults to "keyup").
8916 validationEvent : "keyup",
8918 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
8920 validateOnBlur : true,
8922 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
8924 validationDelay : 250,
8926 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
8928 focusClass : "x-form-focus", // not needed???
8932 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
8934 invalidClass : "has-warning",
8937 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
8939 validClass : "has-success",
8942 * @cfg {Boolean} hasFeedback (true|false) default true
8947 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8949 invalidFeedbackClass : "glyphicon-warning-sign",
8952 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8954 validFeedbackClass : "glyphicon-ok",
8957 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
8959 selectOnFocus : false,
8962 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
8966 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
8971 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
8973 disableKeyFilter : false,
8976 * @cfg {Boolean} disabled True to disable the field (defaults to false).
8980 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
8984 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
8986 blankText : "Please complete this mandatory field",
8989 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
8993 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
8995 maxLength : Number.MAX_VALUE,
8997 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
8999 minLengthText : "The minimum length for this field is {0}",
9001 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
9003 maxLengthText : "The maximum length for this field is {0}",
9007 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
9008 * If available, this function will be called only after the basic validators all return true, and will be passed the
9009 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
9013 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
9014 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
9015 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
9019 * @cfg {String} regexText -- Depricated - use Invalid Text
9024 * @cfg {String} invalidText The error text to display if {@link #validator} test fails during validation (defaults to "")
9030 autocomplete: false,
9049 formatedValue : false,
9050 forceFeedback : false,
9052 indicatorpos : 'left',
9062 parentLabelAlign : function()
9065 while (parent.parent()) {
9066 parent = parent.parent();
9067 if (typeof(parent.labelAlign) !='undefined') {
9068 return parent.labelAlign;
9075 getAutoCreate : function()
9077 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9083 if(this.inputType != 'hidden'){
9084 cfg.cls = 'form-group' //input-group
9090 type : this.inputType,
9092 cls : 'form-control',
9093 placeholder : this.placeholder || '',
9094 autocomplete : this.autocomplete || 'new-password'
9097 if(this.capture.length){
9098 input.capture = this.capture;
9101 if(this.accept.length){
9102 input.accept = this.accept + "/*";
9106 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
9109 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9110 input.maxLength = this.maxLength;
9113 if (this.disabled) {
9114 input.disabled=true;
9117 if (this.readOnly) {
9118 input.readonly=true;
9122 input.name = this.name;
9126 input.cls += ' input-' + this.size;
9130 ['xs','sm','md','lg'].map(function(size){
9131 if (settings[size]) {
9132 cfg.cls += ' col-' + size + '-' + settings[size];
9136 var inputblock = input;
9140 cls: 'glyphicon form-control-feedback'
9143 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9146 cls : 'has-feedback',
9154 if (this.before || this.after) {
9157 cls : 'input-group',
9161 if (this.before && typeof(this.before) == 'string') {
9163 inputblock.cn.push({
9165 cls : 'roo-input-before input-group-addon input-group-prepend input-group-text',
9169 if (this.before && typeof(this.before) == 'object') {
9170 this.before = Roo.factory(this.before);
9172 inputblock.cn.push({
9174 cls : 'roo-input-before input-group-prepend input-group-text input-group-' +
9175 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
9179 inputblock.cn.push(input);
9181 if (this.after && typeof(this.after) == 'string') {
9182 inputblock.cn.push({
9184 cls : 'roo-input-after input-group-append input-group-text input-group-addon',
9188 if (this.after && typeof(this.after) == 'object') {
9189 this.after = Roo.factory(this.after);
9191 inputblock.cn.push({
9193 cls : 'roo-input-after input-group-append input-group-text input-group-' +
9194 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
9198 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9199 inputblock.cls += ' has-feedback';
9200 inputblock.cn.push(feedback);
9205 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
9206 tooltip : 'This field is required'
9208 if (Roo.bootstrap.version == 4) {
9211 style : 'display-none'
9214 if (align ==='left' && this.fieldLabel.length) {
9216 cfg.cls += ' roo-form-group-label-left row';
9223 cls : 'control-label col-form-label',
9224 html : this.fieldLabel
9235 var labelCfg = cfg.cn[1];
9236 var contentCfg = cfg.cn[2];
9238 if(this.indicatorpos == 'right'){
9243 cls : 'control-label col-form-label',
9247 html : this.fieldLabel
9261 labelCfg = cfg.cn[0];
9262 contentCfg = cfg.cn[1];
9266 if(this.labelWidth > 12){
9267 labelCfg.style = "width: " + this.labelWidth + 'px';
9270 if(this.labelWidth < 13 && this.labelmd == 0){
9271 this.labelmd = this.labelWidth;
9274 if(this.labellg > 0){
9275 labelCfg.cls += ' col-lg-' + this.labellg;
9276 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
9279 if(this.labelmd > 0){
9280 labelCfg.cls += ' col-md-' + this.labelmd;
9281 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
9284 if(this.labelsm > 0){
9285 labelCfg.cls += ' col-sm-' + this.labelsm;
9286 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
9289 if(this.labelxs > 0){
9290 labelCfg.cls += ' col-xs-' + this.labelxs;
9291 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
9295 } else if ( this.fieldLabel.length) {
9300 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
9301 tooltip : 'This field is required'
9305 //cls : 'input-group-addon',
9306 html : this.fieldLabel
9314 if(this.indicatorpos == 'right'){
9319 //cls : 'input-group-addon',
9320 html : this.fieldLabel
9325 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9326 tooltip : 'This field is required'
9346 if (this.parentType === 'Navbar' && this.parent().bar) {
9347 cfg.cls += ' navbar-form';
9350 if (this.parentType === 'NavGroup') {
9351 cfg.cls += ' navbar-form';
9359 * return the real input element.
9361 inputEl: function ()
9363 return this.el.select('input.form-control',true).first();
9366 tooltipEl : function()
9368 return this.inputEl();
9371 indicatorEl : function()
9373 if (Roo.bootstrap.version == 4) {
9374 return false; // not enabled in v4 yet.
9377 var indicator = this.el.select('i.roo-required-indicator',true).first();
9387 setDisabled : function(v)
9389 var i = this.inputEl().dom;
9391 i.removeAttribute('disabled');
9395 i.setAttribute('disabled','true');
9397 initEvents : function()
9400 this.inputEl().on("keydown" , this.fireKey, this);
9401 this.inputEl().on("focus", this.onFocus, this);
9402 this.inputEl().on("blur", this.onBlur, this);
9404 this.inputEl().relayEvent('keyup', this);
9406 this.indicator = this.indicatorEl();
9409 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible'); // changed from invisible??? -
9412 // reference to original value for reset
9413 this.originalValue = this.getValue();
9414 //Roo.form.TextField.superclass.initEvents.call(this);
9415 if(this.validationEvent == 'keyup'){
9416 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
9417 this.inputEl().on('keyup', this.filterValidation, this);
9419 else if(this.validationEvent !== false){
9420 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
9423 if(this.selectOnFocus){
9424 this.on("focus", this.preFocus, this);
9427 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
9428 this.inputEl().on("keypress", this.filterKeys, this);
9430 this.inputEl().relayEvent('keypress', this);
9433 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
9434 this.el.on("click", this.autoSize, this);
9437 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
9438 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
9441 if (typeof(this.before) == 'object') {
9442 this.before.render(this.el.select('.roo-input-before',true).first());
9444 if (typeof(this.after) == 'object') {
9445 this.after.render(this.el.select('.roo-input-after',true).first());
9448 this.inputEl().on('change', this.onChange, this);
9451 filterValidation : function(e){
9452 if(!e.isNavKeyPress()){
9453 this.validationTask.delay(this.validationDelay);
9457 * Validates the field value
9458 * @return {Boolean} True if the value is valid, else false
9460 validate : function(){
9461 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
9462 if(this.disabled || this.validateValue(this.getRawValue())){
9473 * Validates a value according to the field's validation rules and marks the field as invalid
9474 * if the validation fails
9475 * @param {Mixed} value The value to validate
9476 * @return {Boolean} True if the value is valid, else false
9478 validateValue : function(value)
9480 if(this.getVisibilityEl().hasClass('hidden')){
9484 if(value.length < 1) { // if it's blank
9485 if(this.allowBlank){
9491 if(value.length < this.minLength){
9494 if(value.length > this.maxLength){
9498 var vt = Roo.form.VTypes;
9499 if(!vt[this.vtype](value, this)){
9503 if(typeof this.validator == "function"){
9504 var msg = this.validator(value);
9508 if (typeof(msg) == 'string') {
9509 this.invalidText = msg;
9513 if(this.regex && !this.regex.test(value)){
9521 fireKey : function(e){
9522 //Roo.log('field ' + e.getKey());
9523 if(e.isNavKeyPress()){
9524 this.fireEvent("specialkey", this, e);
9527 focus : function (selectText){
9529 this.inputEl().focus();
9530 if(selectText === true){
9531 this.inputEl().dom.select();
9537 onFocus : function(){
9538 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9539 // this.el.addClass(this.focusClass);
9542 this.hasFocus = true;
9543 this.startValue = this.getValue();
9544 this.fireEvent("focus", this);
9548 beforeBlur : Roo.emptyFn,
9552 onBlur : function(){
9554 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9555 //this.el.removeClass(this.focusClass);
9557 this.hasFocus = false;
9558 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
9561 var v = this.getValue();
9562 if(String(v) !== String(this.startValue)){
9563 this.fireEvent('change', this, v, this.startValue);
9565 this.fireEvent("blur", this);
9568 onChange : function(e)
9570 var v = this.getValue();
9571 if(String(v) !== String(this.startValue)){
9572 this.fireEvent('change', this, v, this.startValue);
9578 * Resets the current field value to the originally loaded value and clears any validation messages
9581 this.setValue(this.originalValue);
9585 * Returns the name of the field
9586 * @return {Mixed} name The name field
9588 getName: function(){
9592 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
9593 * @return {Mixed} value The field value
9595 getValue : function(){
9597 var v = this.inputEl().getValue();
9602 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
9603 * @return {Mixed} value The field value
9605 getRawValue : function(){
9606 var v = this.inputEl().getValue();
9612 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
9613 * @param {Mixed} value The value to set
9615 setRawValue : function(v){
9616 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9619 selectText : function(start, end){
9620 var v = this.getRawValue();
9622 start = start === undefined ? 0 : start;
9623 end = end === undefined ? v.length : end;
9624 var d = this.inputEl().dom;
9625 if(d.setSelectionRange){
9626 d.setSelectionRange(start, end);
9627 }else if(d.createTextRange){
9628 var range = d.createTextRange();
9629 range.moveStart("character", start);
9630 range.moveEnd("character", v.length-end);
9637 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
9638 * @param {Mixed} value The value to set
9640 setValue : function(v){
9643 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9649 processValue : function(value){
9650 if(this.stripCharsRe){
9651 var newValue = value.replace(this.stripCharsRe, '');
9652 if(newValue !== value){
9653 this.setRawValue(newValue);
9660 preFocus : function(){
9662 if(this.selectOnFocus){
9663 this.inputEl().dom.select();
9666 filterKeys : function(e){
9668 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
9671 var c = e.getCharCode(), cc = String.fromCharCode(c);
9672 if(Roo.isIE && (e.isSpecialKey() || !cc)){
9675 if(!this.maskRe.test(cc)){
9680 * Clear any invalid styles/messages for this field
9682 clearInvalid : function(){
9684 if(!this.el || this.preventMark){ // not rendered
9689 this.el.removeClass(this.invalidClass);
9691 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9693 var feedback = this.el.select('.form-control-feedback', true).first();
9696 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9702 this.indicator.removeClass('visible');
9703 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9706 this.fireEvent('valid', this);
9710 * Mark this field as valid
9712 markValid : function()
9714 if(!this.el || this.preventMark){ // not rendered...
9718 this.el.removeClass([this.invalidClass, this.validClass]);
9720 var feedback = this.el.select('.form-control-feedback', true).first();
9723 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9727 this.indicator.removeClass('visible');
9728 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9735 if(this.allowBlank && !this.getRawValue().length){
9739 this.el.addClass(this.validClass);
9741 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9743 var feedback = this.el.select('.form-control-feedback', true).first();
9746 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9747 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9752 this.fireEvent('valid', this);
9756 * Mark this field as invalid
9757 * @param {String} msg The validation message
9759 markInvalid : function(msg)
9761 if(!this.el || this.preventMark){ // not rendered
9765 this.el.removeClass([this.invalidClass, this.validClass]);
9767 var feedback = this.el.select('.form-control-feedback', true).first();
9770 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9777 if(this.allowBlank && !this.getRawValue().length){
9782 this.indicator.removeClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9783 this.indicator.addClass('visible');
9786 this.el.addClass(this.invalidClass);
9788 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9790 var feedback = this.el.select('.form-control-feedback', true).first();
9793 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9795 if(this.getValue().length || this.forceFeedback){
9796 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9803 this.fireEvent('invalid', this, msg);
9806 SafariOnKeyDown : function(event)
9808 // this is a workaround for a password hang bug on chrome/ webkit.
9809 if (this.inputEl().dom.type != 'password') {
9813 var isSelectAll = false;
9815 if(this.inputEl().dom.selectionEnd > 0){
9816 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
9818 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
9819 event.preventDefault();
9824 if(isSelectAll && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
9826 event.preventDefault();
9827 // this is very hacky as keydown always get's upper case.
9829 var cc = String.fromCharCode(event.getCharCode());
9830 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
9834 adjustWidth : function(tag, w){
9835 tag = tag.toLowerCase();
9836 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
9837 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
9841 if(tag == 'textarea'){
9844 }else if(Roo.isOpera){
9848 if(tag == 'textarea'){
9856 setFieldLabel : function(v)
9862 if(this.indicatorEl()){
9863 var ar = this.el.select('label > span',true);
9865 if (ar.elements.length) {
9866 this.el.select('label > span',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9867 this.fieldLabel = v;
9871 var br = this.el.select('label',true);
9873 if(br.elements.length) {
9874 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9875 this.fieldLabel = v;
9879 Roo.log('Cannot Found any of label > span || label in input');
9883 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9884 this.fieldLabel = v;
9899 * @class Roo.bootstrap.TextArea
9900 * @extends Roo.bootstrap.Input
9901 * Bootstrap TextArea class
9902 * @cfg {Number} cols Specifies the visible width of a text area
9903 * @cfg {Number} rows Specifies the visible number of lines in a text area
9904 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
9905 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
9906 * @cfg {string} html text
9909 * Create a new TextArea
9910 * @param {Object} config The config object
9913 Roo.bootstrap.TextArea = function(config){
9914 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
9918 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
9928 getAutoCreate : function(){
9930 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9936 if(this.inputType != 'hidden'){
9937 cfg.cls = 'form-group' //input-group
9945 value : this.value || '',
9946 html: this.html || '',
9947 cls : 'form-control',
9948 placeholder : this.placeholder || ''
9952 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9953 input.maxLength = this.maxLength;
9957 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
9961 input.cols = this.cols;
9964 if (this.readOnly) {
9965 input.readonly = true;
9969 input.name = this.name;
9973 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
9977 ['xs','sm','md','lg'].map(function(size){
9978 if (settings[size]) {
9979 cfg.cls += ' col-' + size + '-' + settings[size];
9983 var inputblock = input;
9985 if(this.hasFeedback && !this.allowBlank){
9989 cls: 'glyphicon form-control-feedback'
9993 cls : 'has-feedback',
10002 if (this.before || this.after) {
10005 cls : 'input-group',
10009 inputblock.cn.push({
10011 cls : 'input-group-addon',
10016 inputblock.cn.push(input);
10018 if(this.hasFeedback && !this.allowBlank){
10019 inputblock.cls += ' has-feedback';
10020 inputblock.cn.push(feedback);
10024 inputblock.cn.push({
10026 cls : 'input-group-addon',
10033 if (align ==='left' && this.fieldLabel.length) {
10038 cls : 'control-label',
10039 html : this.fieldLabel
10050 if(this.labelWidth > 12){
10051 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
10054 if(this.labelWidth < 13 && this.labelmd == 0){
10055 this.labelmd = this.labelWidth;
10058 if(this.labellg > 0){
10059 cfg.cn[0].cls += ' col-lg-' + this.labellg;
10060 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
10063 if(this.labelmd > 0){
10064 cfg.cn[0].cls += ' col-md-' + this.labelmd;
10065 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
10068 if(this.labelsm > 0){
10069 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
10070 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
10073 if(this.labelxs > 0){
10074 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
10075 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
10078 } else if ( this.fieldLabel.length) {
10083 //cls : 'input-group-addon',
10084 html : this.fieldLabel
10102 if (this.disabled) {
10103 input.disabled=true;
10110 * return the real textarea element.
10112 inputEl: function ()
10114 return this.el.select('textarea.form-control',true).first();
10118 * Clear any invalid styles/messages for this field
10120 clearInvalid : function()
10123 if(!this.el || this.preventMark){ // not rendered
10127 var label = this.el.select('label', true).first();
10128 var icon = this.el.select('i.fa-star', true).first();
10134 this.el.removeClass(this.invalidClass);
10136 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10138 var feedback = this.el.select('.form-control-feedback', true).first();
10141 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
10146 this.fireEvent('valid', this);
10150 * Mark this field as valid
10152 markValid : function()
10154 if(!this.el || this.preventMark){ // not rendered
10158 this.el.removeClass([this.invalidClass, this.validClass]);
10160 var feedback = this.el.select('.form-control-feedback', true).first();
10163 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10166 if(this.disabled || this.allowBlank){
10170 var label = this.el.select('label', true).first();
10171 var icon = this.el.select('i.fa-star', true).first();
10177 this.el.addClass(this.validClass);
10179 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
10181 var feedback = this.el.select('.form-control-feedback', true).first();
10184 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10185 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
10190 this.fireEvent('valid', this);
10194 * Mark this field as invalid
10195 * @param {String} msg The validation message
10197 markInvalid : function(msg)
10199 if(!this.el || this.preventMark){ // not rendered
10203 this.el.removeClass([this.invalidClass, this.validClass]);
10205 var feedback = this.el.select('.form-control-feedback', true).first();
10208 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10211 if(this.disabled || this.allowBlank){
10215 var label = this.el.select('label', true).first();
10216 var icon = this.el.select('i.fa-star', true).first();
10218 if(!this.getValue().length && label && !icon){
10219 this.el.createChild({
10221 cls : 'text-danger fa fa-lg fa-star',
10222 tooltip : 'This field is required',
10223 style : 'margin-right:5px;'
10227 this.el.addClass(this.invalidClass);
10229 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10231 var feedback = this.el.select('.form-control-feedback', true).first();
10234 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10236 if(this.getValue().length || this.forceFeedback){
10237 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
10244 this.fireEvent('invalid', this, msg);
10252 * trigger field - base class for combo..
10257 * @class Roo.bootstrap.TriggerField
10258 * @extends Roo.bootstrap.Input
10259 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
10260 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
10261 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
10262 * for which you can provide a custom implementation. For example:
10264 var trigger = new Roo.bootstrap.TriggerField();
10265 trigger.onTriggerClick = myTriggerFn;
10266 trigger.applyTo('my-field');
10269 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
10270 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
10271 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
10272 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
10273 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
10276 * Create a new TriggerField.
10277 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
10278 * to the base TextField)
10280 Roo.bootstrap.TriggerField = function(config){
10281 this.mimicing = false;
10282 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
10285 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
10287 * @cfg {String} triggerClass A CSS class to apply to the trigger
10290 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
10295 * @cfg {Boolean} removable (true|false) special filter default false
10299 /** @cfg {Boolean} grow @hide */
10300 /** @cfg {Number} growMin @hide */
10301 /** @cfg {Number} growMax @hide */
10307 autoSize: Roo.emptyFn,
10311 deferHeight : true,
10314 actionMode : 'wrap',
10319 getAutoCreate : function(){
10321 var align = this.labelAlign || this.parentLabelAlign();
10326 cls: 'form-group' //input-group
10333 type : this.inputType,
10334 cls : 'form-control',
10335 autocomplete: 'new-password',
10336 placeholder : this.placeholder || ''
10340 input.name = this.name;
10343 input.cls += ' input-' + this.size;
10346 if (this.disabled) {
10347 input.disabled=true;
10350 var inputblock = input;
10352 if(this.hasFeedback && !this.allowBlank){
10356 cls: 'glyphicon form-control-feedback'
10359 if(this.removable && !this.editable && !this.tickable){
10361 cls : 'has-feedback',
10367 cls : 'roo-combo-removable-btn close'
10374 cls : 'has-feedback',
10383 if(this.removable && !this.editable && !this.tickable){
10385 cls : 'roo-removable',
10391 cls : 'roo-combo-removable-btn close'
10398 if (this.before || this.after) {
10401 cls : 'input-group',
10405 inputblock.cn.push({
10407 cls : 'input-group-addon input-group-prepend input-group-text',
10412 inputblock.cn.push(input);
10414 if(this.hasFeedback && !this.allowBlank){
10415 inputblock.cls += ' has-feedback';
10416 inputblock.cn.push(feedback);
10420 inputblock.cn.push({
10422 cls : 'input-group-addon input-group-append input-group-text',
10431 var ibwrap = inputblock;
10436 cls: 'roo-select2-choices',
10440 cls: 'roo-select2-search-field',
10452 cls: 'roo-select2-container input-group',
10457 cls: 'form-hidden-field'
10463 if(!this.multiple && this.showToggleBtn){
10469 if (this.caret != false) {
10472 cls: 'fa fa-' + this.caret
10479 cls : 'input-group-addon input-group-append input-group-text btn dropdown-toggle',
10484 cls: 'combobox-clear',
10498 combobox.cls += ' roo-select2-container-multi';
10502 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
10503 tooltip : 'This field is required'
10505 if (Roo.bootstrap.version == 4) {
10508 style : 'display:none'
10513 if (align ==='left' && this.fieldLabel.length) {
10515 cfg.cls += ' roo-form-group-label-left row';
10522 cls : 'control-label',
10523 html : this.fieldLabel
10535 var labelCfg = cfg.cn[1];
10536 var contentCfg = cfg.cn[2];
10538 if(this.indicatorpos == 'right'){
10543 cls : 'control-label',
10547 html : this.fieldLabel
10561 labelCfg = cfg.cn[0];
10562 contentCfg = cfg.cn[1];
10565 if(this.labelWidth > 12){
10566 labelCfg.style = "width: " + this.labelWidth + 'px';
10569 if(this.labelWidth < 13 && this.labelmd == 0){
10570 this.labelmd = this.labelWidth;
10573 if(this.labellg > 0){
10574 labelCfg.cls += ' col-lg-' + this.labellg;
10575 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
10578 if(this.labelmd > 0){
10579 labelCfg.cls += ' col-md-' + this.labelmd;
10580 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
10583 if(this.labelsm > 0){
10584 labelCfg.cls += ' col-sm-' + this.labelsm;
10585 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
10588 if(this.labelxs > 0){
10589 labelCfg.cls += ' col-xs-' + this.labelxs;
10590 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
10593 } else if ( this.fieldLabel.length) {
10594 // Roo.log(" label");
10599 //cls : 'input-group-addon',
10600 html : this.fieldLabel
10608 if(this.indicatorpos == 'right'){
10616 html : this.fieldLabel
10630 // Roo.log(" no label && no align");
10637 ['xs','sm','md','lg'].map(function(size){
10638 if (settings[size]) {
10639 cfg.cls += ' col-' + size + '-' + settings[size];
10650 onResize : function(w, h){
10651 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
10652 // if(typeof w == 'number'){
10653 // var x = w - this.trigger.getWidth();
10654 // this.inputEl().setWidth(this.adjustWidth('input', x));
10655 // this.trigger.setStyle('left', x+'px');
10660 adjustSize : Roo.BoxComponent.prototype.adjustSize,
10663 getResizeEl : function(){
10664 return this.inputEl();
10668 getPositionEl : function(){
10669 return this.inputEl();
10673 alignErrorIcon : function(){
10674 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
10678 initEvents : function(){
10682 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
10683 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
10684 if(!this.multiple && this.showToggleBtn){
10685 this.trigger = this.el.select('span.dropdown-toggle',true).first();
10686 if(this.hideTrigger){
10687 this.trigger.setDisplayed(false);
10689 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10693 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
10696 if(this.removable && !this.editable && !this.tickable){
10697 var close = this.closeTriggerEl();
10700 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
10701 close.on('click', this.removeBtnClick, this, close);
10705 //this.trigger.addClassOnOver('x-form-trigger-over');
10706 //this.trigger.addClassOnClick('x-form-trigger-click');
10709 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
10713 closeTriggerEl : function()
10715 var close = this.el.select('.roo-combo-removable-btn', true).first();
10716 return close ? close : false;
10719 removeBtnClick : function(e, h, el)
10721 e.preventDefault();
10723 if(this.fireEvent("remove", this) !== false){
10725 this.fireEvent("afterremove", this)
10729 createList : function()
10731 this.list = Roo.get(document.body).createChild({
10732 tag: Roo.bootstrap.version == 4 ? 'div' : 'ul',
10733 cls: 'typeahead typeahead-long dropdown-menu',
10734 style: 'display:none'
10737 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
10742 initTrigger : function(){
10747 onDestroy : function(){
10749 this.trigger.removeAllListeners();
10750 // this.trigger.remove();
10753 // this.wrap.remove();
10755 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
10759 onFocus : function(){
10760 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
10762 if(!this.mimicing){
10763 this.wrap.addClass('x-trigger-wrap-focus');
10764 this.mimicing = true;
10765 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
10766 if(this.monitorTab){
10767 this.el.on("keydown", this.checkTab, this);
10774 checkTab : function(e){
10775 if(e.getKey() == e.TAB){
10776 this.triggerBlur();
10781 onBlur : function(){
10786 mimicBlur : function(e, t){
10788 if(!this.wrap.contains(t) && this.validateBlur()){
10789 this.triggerBlur();
10795 triggerBlur : function(){
10796 this.mimicing = false;
10797 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
10798 if(this.monitorTab){
10799 this.el.un("keydown", this.checkTab, this);
10801 //this.wrap.removeClass('x-trigger-wrap-focus');
10802 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
10806 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
10807 validateBlur : function(e, t){
10812 onDisable : function(){
10813 this.inputEl().dom.disabled = true;
10814 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
10816 // this.wrap.addClass('x-item-disabled');
10821 onEnable : function(){
10822 this.inputEl().dom.disabled = false;
10823 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
10825 // this.el.removeClass('x-item-disabled');
10830 onShow : function(){
10831 var ae = this.getActionEl();
10834 ae.dom.style.display = '';
10835 ae.dom.style.visibility = 'visible';
10841 onHide : function(){
10842 var ae = this.getActionEl();
10843 ae.dom.style.display = 'none';
10847 * The function that should handle the trigger's click event. This method does nothing by default until overridden
10848 * by an implementing function.
10850 * @param {EventObject} e
10852 onTriggerClick : Roo.emptyFn
10856 * Ext JS Library 1.1.1
10857 * Copyright(c) 2006-2007, Ext JS, LLC.
10859 * Originally Released Under LGPL - original licence link has changed is not relivant.
10862 * <script type="text/javascript">
10867 * @class Roo.data.SortTypes
10869 * Defines the default sorting (casting?) comparison functions used when sorting data.
10871 Roo.data.SortTypes = {
10873 * Default sort that does nothing
10874 * @param {Mixed} s The value being converted
10875 * @return {Mixed} The comparison value
10877 none : function(s){
10882 * The regular expression used to strip tags
10886 stripTagsRE : /<\/?[^>]+>/gi,
10889 * Strips all HTML tags to sort on text only
10890 * @param {Mixed} s The value being converted
10891 * @return {String} The comparison value
10893 asText : function(s){
10894 return String(s).replace(this.stripTagsRE, "");
10898 * Strips all HTML tags to sort on text only - Case insensitive
10899 * @param {Mixed} s The value being converted
10900 * @return {String} The comparison value
10902 asUCText : function(s){
10903 return String(s).toUpperCase().replace(this.stripTagsRE, "");
10907 * Case insensitive string
10908 * @param {Mixed} s The value being converted
10909 * @return {String} The comparison value
10911 asUCString : function(s) {
10912 return String(s).toUpperCase();
10917 * @param {Mixed} s The value being converted
10918 * @return {Number} The comparison value
10920 asDate : function(s) {
10924 if(s instanceof Date){
10925 return s.getTime();
10927 return Date.parse(String(s));
10932 * @param {Mixed} s The value being converted
10933 * @return {Float} The comparison value
10935 asFloat : function(s) {
10936 var val = parseFloat(String(s).replace(/,/g, ""));
10945 * @param {Mixed} s The value being converted
10946 * @return {Number} The comparison value
10948 asInt : function(s) {
10949 var val = parseInt(String(s).replace(/,/g, ""));
10957 * Ext JS Library 1.1.1
10958 * Copyright(c) 2006-2007, Ext JS, LLC.
10960 * Originally Released Under LGPL - original licence link has changed is not relivant.
10963 * <script type="text/javascript">
10967 * @class Roo.data.Record
10968 * Instances of this class encapsulate both record <em>definition</em> information, and record
10969 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
10970 * to access Records cached in an {@link Roo.data.Store} object.<br>
10972 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
10973 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
10976 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
10978 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
10979 * {@link #create}. The parameters are the same.
10980 * @param {Array} data An associative Array of data values keyed by the field name.
10981 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
10982 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
10983 * not specified an integer id is generated.
10985 Roo.data.Record = function(data, id){
10986 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
10991 * Generate a constructor for a specific record layout.
10992 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
10993 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
10994 * Each field definition object may contain the following properties: <ul>
10995 * <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,
10996 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
10997 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
10998 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
10999 * is being used, then this is a string containing the javascript expression to reference the data relative to
11000 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
11001 * to the data item relative to the record element. If the mapping expression is the same as the field name,
11002 * this may be omitted.</p></li>
11003 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
11004 * <ul><li>auto (Default, implies no conversion)</li>
11009 * <li>date</li></ul></p></li>
11010 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
11011 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
11012 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
11013 * by the Reader into an object that will be stored in the Record. It is passed the
11014 * following parameters:<ul>
11015 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
11017 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
11019 * <br>usage:<br><pre><code>
11020 var TopicRecord = Roo.data.Record.create(
11021 {name: 'title', mapping: 'topic_title'},
11022 {name: 'author', mapping: 'username'},
11023 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
11024 {name: 'lastPost', mapping: 'post_time', type: 'date'},
11025 {name: 'lastPoster', mapping: 'user2'},
11026 {name: 'excerpt', mapping: 'post_text'}
11029 var myNewRecord = new TopicRecord({
11030 title: 'Do my job please',
11033 lastPost: new Date(),
11034 lastPoster: 'Animal',
11035 excerpt: 'No way dude!'
11037 myStore.add(myNewRecord);
11042 Roo.data.Record.create = function(o){
11043 var f = function(){
11044 f.superclass.constructor.apply(this, arguments);
11046 Roo.extend(f, Roo.data.Record);
11047 var p = f.prototype;
11048 p.fields = new Roo.util.MixedCollection(false, function(field){
11051 for(var i = 0, len = o.length; i < len; i++){
11052 p.fields.add(new Roo.data.Field(o[i]));
11054 f.getField = function(name){
11055 return p.fields.get(name);
11060 Roo.data.Record.AUTO_ID = 1000;
11061 Roo.data.Record.EDIT = 'edit';
11062 Roo.data.Record.REJECT = 'reject';
11063 Roo.data.Record.COMMIT = 'commit';
11065 Roo.data.Record.prototype = {
11067 * Readonly flag - true if this record has been modified.
11076 join : function(store){
11077 this.store = store;
11081 * Set the named field to the specified value.
11082 * @param {String} name The name of the field to set.
11083 * @param {Object} value The value to set the field to.
11085 set : function(name, value){
11086 if(this.data[name] == value){
11090 if(!this.modified){
11091 this.modified = {};
11093 if(typeof this.modified[name] == 'undefined'){
11094 this.modified[name] = this.data[name];
11096 this.data[name] = value;
11097 if(!this.editing && this.store){
11098 this.store.afterEdit(this);
11103 * Get the value of the named field.
11104 * @param {String} name The name of the field to get the value of.
11105 * @return {Object} The value of the field.
11107 get : function(name){
11108 return this.data[name];
11112 beginEdit : function(){
11113 this.editing = true;
11114 this.modified = {};
11118 cancelEdit : function(){
11119 this.editing = false;
11120 delete this.modified;
11124 endEdit : function(){
11125 this.editing = false;
11126 if(this.dirty && this.store){
11127 this.store.afterEdit(this);
11132 * Usually called by the {@link Roo.data.Store} which owns the Record.
11133 * Rejects all changes made to the Record since either creation, or the last commit operation.
11134 * Modified fields are reverted to their original values.
11136 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
11137 * of reject operations.
11139 reject : function(){
11140 var m = this.modified;
11142 if(typeof m[n] != "function"){
11143 this.data[n] = m[n];
11146 this.dirty = false;
11147 delete this.modified;
11148 this.editing = false;
11150 this.store.afterReject(this);
11155 * Usually called by the {@link Roo.data.Store} which owns the Record.
11156 * Commits all changes made to the Record since either creation, or the last commit operation.
11158 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
11159 * of commit operations.
11161 commit : function(){
11162 this.dirty = false;
11163 delete this.modified;
11164 this.editing = false;
11166 this.store.afterCommit(this);
11171 hasError : function(){
11172 return this.error != null;
11176 clearError : function(){
11181 * Creates a copy of this record.
11182 * @param {String} id (optional) A new record id if you don't want to use this record's id
11185 copy : function(newId) {
11186 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
11190 * Ext JS Library 1.1.1
11191 * Copyright(c) 2006-2007, Ext JS, LLC.
11193 * Originally Released Under LGPL - original licence link has changed is not relivant.
11196 * <script type="text/javascript">
11202 * @class Roo.data.Store
11203 * @extends Roo.util.Observable
11204 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
11205 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
11207 * 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
11208 * has no knowledge of the format of the data returned by the Proxy.<br>
11210 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
11211 * instances from the data object. These records are cached and made available through accessor functions.
11213 * Creates a new Store.
11214 * @param {Object} config A config object containing the objects needed for the Store to access data,
11215 * and read the data into Records.
11217 Roo.data.Store = function(config){
11218 this.data = new Roo.util.MixedCollection(false);
11219 this.data.getKey = function(o){
11222 this.baseParams = {};
11224 this.paramNames = {
11229 "multisort" : "_multisort"
11232 if(config && config.data){
11233 this.inlineData = config.data;
11234 delete config.data;
11237 Roo.apply(this, config);
11239 if(this.reader){ // reader passed
11240 this.reader = Roo.factory(this.reader, Roo.data);
11241 this.reader.xmodule = this.xmodule || false;
11242 if(!this.recordType){
11243 this.recordType = this.reader.recordType;
11245 if(this.reader.onMetaChange){
11246 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
11250 if(this.recordType){
11251 this.fields = this.recordType.prototype.fields;
11253 this.modified = [];
11257 * @event datachanged
11258 * Fires when the data cache has changed, and a widget which is using this Store
11259 * as a Record cache should refresh its view.
11260 * @param {Store} this
11262 datachanged : true,
11264 * @event metachange
11265 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
11266 * @param {Store} this
11267 * @param {Object} meta The JSON metadata
11272 * Fires when Records have been added to the Store
11273 * @param {Store} this
11274 * @param {Roo.data.Record[]} records The array of Records added
11275 * @param {Number} index The index at which the record(s) were added
11280 * Fires when a Record has been removed from the Store
11281 * @param {Store} this
11282 * @param {Roo.data.Record} record The Record that was removed
11283 * @param {Number} index The index at which the record was removed
11288 * Fires when a Record has been updated
11289 * @param {Store} this
11290 * @param {Roo.data.Record} record The Record that was updated
11291 * @param {String} operation The update operation being performed. Value may be one of:
11293 Roo.data.Record.EDIT
11294 Roo.data.Record.REJECT
11295 Roo.data.Record.COMMIT
11301 * Fires when the data cache has been cleared.
11302 * @param {Store} this
11306 * @event beforeload
11307 * Fires before a request is made for a new data object. If the beforeload handler returns false
11308 * the load action will be canceled.
11309 * @param {Store} this
11310 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11314 * @event beforeloadadd
11315 * Fires after a new set of Records has been loaded.
11316 * @param {Store} this
11317 * @param {Roo.data.Record[]} records The Records that were loaded
11318 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11320 beforeloadadd : true,
11323 * Fires after a new set of Records has been loaded, before they are added to the store.
11324 * @param {Store} this
11325 * @param {Roo.data.Record[]} records The Records that were loaded
11326 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11327 * @params {Object} return from reader
11331 * @event loadexception
11332 * Fires if an exception occurs in the Proxy during loading.
11333 * Called with the signature of the Proxy's "loadexception" event.
11334 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
11337 * @param {Object} return from JsonData.reader() - success, totalRecords, records
11338 * @param {Object} load options
11339 * @param {Object} jsonData from your request (normally this contains the Exception)
11341 loadexception : true
11345 this.proxy = Roo.factory(this.proxy, Roo.data);
11346 this.proxy.xmodule = this.xmodule || false;
11347 this.relayEvents(this.proxy, ["loadexception"]);
11349 this.sortToggle = {};
11350 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
11352 Roo.data.Store.superclass.constructor.call(this);
11354 if(this.inlineData){
11355 this.loadData(this.inlineData);
11356 delete this.inlineData;
11360 Roo.extend(Roo.data.Store, Roo.util.Observable, {
11362 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
11363 * without a remote query - used by combo/forms at present.
11367 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
11370 * @cfg {Array} data Inline data to be loaded when the store is initialized.
11373 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
11374 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
11377 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
11378 * on any HTTP request
11381 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
11384 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
11388 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
11389 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
11391 remoteSort : false,
11394 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
11395 * loaded or when a record is removed. (defaults to false).
11397 pruneModifiedRecords : false,
11400 lastOptions : null,
11403 * Add Records to the Store and fires the add event.
11404 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11406 add : function(records){
11407 records = [].concat(records);
11408 for(var i = 0, len = records.length; i < len; i++){
11409 records[i].join(this);
11411 var index = this.data.length;
11412 this.data.addAll(records);
11413 this.fireEvent("add", this, records, index);
11417 * Remove a Record from the Store and fires the remove event.
11418 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
11420 remove : function(record){
11421 var index = this.data.indexOf(record);
11422 this.data.removeAt(index);
11424 if(this.pruneModifiedRecords){
11425 this.modified.remove(record);
11427 this.fireEvent("remove", this, record, index);
11431 * Remove all Records from the Store and fires the clear event.
11433 removeAll : function(){
11435 if(this.pruneModifiedRecords){
11436 this.modified = [];
11438 this.fireEvent("clear", this);
11442 * Inserts Records to the Store at the given index and fires the add event.
11443 * @param {Number} index The start index at which to insert the passed Records.
11444 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11446 insert : function(index, records){
11447 records = [].concat(records);
11448 for(var i = 0, len = records.length; i < len; i++){
11449 this.data.insert(index, records[i]);
11450 records[i].join(this);
11452 this.fireEvent("add", this, records, index);
11456 * Get the index within the cache of the passed Record.
11457 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
11458 * @return {Number} The index of the passed Record. Returns -1 if not found.
11460 indexOf : function(record){
11461 return this.data.indexOf(record);
11465 * Get the index within the cache of the Record with the passed id.
11466 * @param {String} id The id of the Record to find.
11467 * @return {Number} The index of the Record. Returns -1 if not found.
11469 indexOfId : function(id){
11470 return this.data.indexOfKey(id);
11474 * Get the Record with the specified id.
11475 * @param {String} id The id of the Record to find.
11476 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
11478 getById : function(id){
11479 return this.data.key(id);
11483 * Get the Record at the specified index.
11484 * @param {Number} index The index of the Record to find.
11485 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
11487 getAt : function(index){
11488 return this.data.itemAt(index);
11492 * Returns a range of Records between specified indices.
11493 * @param {Number} startIndex (optional) The starting index (defaults to 0)
11494 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
11495 * @return {Roo.data.Record[]} An array of Records
11497 getRange : function(start, end){
11498 return this.data.getRange(start, end);
11502 storeOptions : function(o){
11503 o = Roo.apply({}, o);
11506 this.lastOptions = o;
11510 * Loads the Record cache from the configured Proxy using the configured Reader.
11512 * If using remote paging, then the first load call must specify the <em>start</em>
11513 * and <em>limit</em> properties in the options.params property to establish the initial
11514 * position within the dataset, and the number of Records to cache on each read from the Proxy.
11516 * <strong>It is important to note that for remote data sources, loading is asynchronous,
11517 * and this call will return before the new data has been loaded. Perform any post-processing
11518 * in a callback function, or in a "load" event handler.</strong>
11520 * @param {Object} options An object containing properties which control loading options:<ul>
11521 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
11522 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
11523 * passed the following arguments:<ul>
11524 * <li>r : Roo.data.Record[]</li>
11525 * <li>options: Options object from the load call</li>
11526 * <li>success: Boolean success indicator</li></ul></li>
11527 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
11528 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
11531 load : function(options){
11532 options = options || {};
11533 if(this.fireEvent("beforeload", this, options) !== false){
11534 this.storeOptions(options);
11535 var p = Roo.apply(options.params || {}, this.baseParams);
11536 // if meta was not loaded from remote source.. try requesting it.
11537 if (!this.reader.metaFromRemote) {
11538 p._requestMeta = 1;
11540 if(this.sortInfo && this.remoteSort){
11541 var pn = this.paramNames;
11542 p[pn["sort"]] = this.sortInfo.field;
11543 p[pn["dir"]] = this.sortInfo.direction;
11545 if (this.multiSort) {
11546 var pn = this.paramNames;
11547 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
11550 this.proxy.load(p, this.reader, this.loadRecords, this, options);
11555 * Reloads the Record cache from the configured Proxy using the configured Reader and
11556 * the options from the last load operation performed.
11557 * @param {Object} options (optional) An object containing properties which may override the options
11558 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
11559 * the most recently used options are reused).
11561 reload : function(options){
11562 this.load(Roo.applyIf(options||{}, this.lastOptions));
11566 // Called as a callback by the Reader during a load operation.
11567 loadRecords : function(o, options, success){
11568 if(!o || success === false){
11569 if(success !== false){
11570 this.fireEvent("load", this, [], options, o);
11572 if(options.callback){
11573 options.callback.call(options.scope || this, [], options, false);
11577 // if data returned failure - throw an exception.
11578 if (o.success === false) {
11579 // show a message if no listener is registered.
11580 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
11581 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
11583 // loadmask wil be hooked into this..
11584 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
11587 var r = o.records, t = o.totalRecords || r.length;
11589 this.fireEvent("beforeloadadd", this, r, options, o);
11591 if(!options || options.add !== true){
11592 if(this.pruneModifiedRecords){
11593 this.modified = [];
11595 for(var i = 0, len = r.length; i < len; i++){
11599 this.data = this.snapshot;
11600 delete this.snapshot;
11603 this.data.addAll(r);
11604 this.totalLength = t;
11606 this.fireEvent("datachanged", this);
11608 this.totalLength = Math.max(t, this.data.length+r.length);
11612 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
11614 var e = new Roo.data.Record({});
11616 e.set(this.parent.displayField, this.parent.emptyTitle);
11617 e.set(this.parent.valueField, '');
11622 this.fireEvent("load", this, r, options, o);
11623 if(options.callback){
11624 options.callback.call(options.scope || this, r, options, true);
11630 * Loads data from a passed data block. A Reader which understands the format of the data
11631 * must have been configured in the constructor.
11632 * @param {Object} data The data block from which to read the Records. The format of the data expected
11633 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
11634 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
11636 loadData : function(o, append){
11637 var r = this.reader.readRecords(o);
11638 this.loadRecords(r, {add: append}, true);
11642 * Gets the number of cached records.
11644 * <em>If using paging, this may not be the total size of the dataset. If the data object
11645 * used by the Reader contains the dataset size, then the getTotalCount() function returns
11646 * the data set size</em>
11648 getCount : function(){
11649 return this.data.length || 0;
11653 * Gets the total number of records in the dataset as returned by the server.
11655 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
11656 * the dataset size</em>
11658 getTotalCount : function(){
11659 return this.totalLength || 0;
11663 * Returns the sort state of the Store as an object with two properties:
11665 field {String} The name of the field by which the Records are sorted
11666 direction {String} The sort order, "ASC" or "DESC"
11669 getSortState : function(){
11670 return this.sortInfo;
11674 applySort : function(){
11675 if(this.sortInfo && !this.remoteSort){
11676 var s = this.sortInfo, f = s.field;
11677 var st = this.fields.get(f).sortType;
11678 var fn = function(r1, r2){
11679 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
11680 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
11682 this.data.sort(s.direction, fn);
11683 if(this.snapshot && this.snapshot != this.data){
11684 this.snapshot.sort(s.direction, fn);
11690 * Sets the default sort column and order to be used by the next load operation.
11691 * @param {String} fieldName The name of the field to sort by.
11692 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11694 setDefaultSort : function(field, dir){
11695 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
11699 * Sort the Records.
11700 * If remote sorting is used, the sort is performed on the server, and the cache is
11701 * reloaded. If local sorting is used, the cache is sorted internally.
11702 * @param {String} fieldName The name of the field to sort by.
11703 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11705 sort : function(fieldName, dir){
11706 var f = this.fields.get(fieldName);
11708 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
11710 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
11711 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
11716 this.sortToggle[f.name] = dir;
11717 this.sortInfo = {field: f.name, direction: dir};
11718 if(!this.remoteSort){
11720 this.fireEvent("datachanged", this);
11722 this.load(this.lastOptions);
11727 * Calls the specified function for each of the Records in the cache.
11728 * @param {Function} fn The function to call. The Record is passed as the first parameter.
11729 * Returning <em>false</em> aborts and exits the iteration.
11730 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
11732 each : function(fn, scope){
11733 this.data.each(fn, scope);
11737 * Gets all records modified since the last commit. Modified records are persisted across load operations
11738 * (e.g., during paging).
11739 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
11741 getModifiedRecords : function(){
11742 return this.modified;
11746 createFilterFn : function(property, value, anyMatch){
11747 if(!value.exec){ // not a regex
11748 value = String(value);
11749 if(value.length == 0){
11752 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
11754 return function(r){
11755 return value.test(r.data[property]);
11760 * Sums the value of <i>property</i> for each record between start and end and returns the result.
11761 * @param {String} property A field on your records
11762 * @param {Number} start The record index to start at (defaults to 0)
11763 * @param {Number} end The last record index to include (defaults to length - 1)
11764 * @return {Number} The sum
11766 sum : function(property, start, end){
11767 var rs = this.data.items, v = 0;
11768 start = start || 0;
11769 end = (end || end === 0) ? end : rs.length-1;
11771 for(var i = start; i <= end; i++){
11772 v += (rs[i].data[property] || 0);
11778 * Filter the records by a specified property.
11779 * @param {String} field A field on your records
11780 * @param {String/RegExp} value Either a string that the field
11781 * should start with or a RegExp to test against the field
11782 * @param {Boolean} anyMatch True to match any part not just the beginning
11784 filter : function(property, value, anyMatch){
11785 var fn = this.createFilterFn(property, value, anyMatch);
11786 return fn ? this.filterBy(fn) : this.clearFilter();
11790 * Filter by a function. The specified function will be called with each
11791 * record in this data source. If the function returns true the record is included,
11792 * otherwise it is filtered.
11793 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11794 * @param {Object} scope (optional) The scope of the function (defaults to this)
11796 filterBy : function(fn, scope){
11797 this.snapshot = this.snapshot || this.data;
11798 this.data = this.queryBy(fn, scope||this);
11799 this.fireEvent("datachanged", this);
11803 * Query the records by a specified property.
11804 * @param {String} field A field on your records
11805 * @param {String/RegExp} value Either a string that the field
11806 * should start with or a RegExp to test against the field
11807 * @param {Boolean} anyMatch True to match any part not just the beginning
11808 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11810 query : function(property, value, anyMatch){
11811 var fn = this.createFilterFn(property, value, anyMatch);
11812 return fn ? this.queryBy(fn) : this.data.clone();
11816 * Query by a function. The specified function will be called with each
11817 * record in this data source. If the function returns true the record is included
11819 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11820 * @param {Object} scope (optional) The scope of the function (defaults to this)
11821 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11823 queryBy : function(fn, scope){
11824 var data = this.snapshot || this.data;
11825 return data.filterBy(fn, scope||this);
11829 * Collects unique values for a particular dataIndex from this store.
11830 * @param {String} dataIndex The property to collect
11831 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
11832 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
11833 * @return {Array} An array of the unique values
11835 collect : function(dataIndex, allowNull, bypassFilter){
11836 var d = (bypassFilter === true && this.snapshot) ?
11837 this.snapshot.items : this.data.items;
11838 var v, sv, r = [], l = {};
11839 for(var i = 0, len = d.length; i < len; i++){
11840 v = d[i].data[dataIndex];
11842 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
11851 * Revert to a view of the Record cache with no filtering applied.
11852 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
11854 clearFilter : function(suppressEvent){
11855 if(this.snapshot && this.snapshot != this.data){
11856 this.data = this.snapshot;
11857 delete this.snapshot;
11858 if(suppressEvent !== true){
11859 this.fireEvent("datachanged", this);
11865 afterEdit : function(record){
11866 if(this.modified.indexOf(record) == -1){
11867 this.modified.push(record);
11869 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
11873 afterReject : function(record){
11874 this.modified.remove(record);
11875 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
11879 afterCommit : function(record){
11880 this.modified.remove(record);
11881 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
11885 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
11886 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
11888 commitChanges : function(){
11889 var m = this.modified.slice(0);
11890 this.modified = [];
11891 for(var i = 0, len = m.length; i < len; i++){
11897 * Cancel outstanding changes on all changed records.
11899 rejectChanges : function(){
11900 var m = this.modified.slice(0);
11901 this.modified = [];
11902 for(var i = 0, len = m.length; i < len; i++){
11907 onMetaChange : function(meta, rtype, o){
11908 this.recordType = rtype;
11909 this.fields = rtype.prototype.fields;
11910 delete this.snapshot;
11911 this.sortInfo = meta.sortInfo || this.sortInfo;
11912 this.modified = [];
11913 this.fireEvent('metachange', this, this.reader.meta);
11916 moveIndex : function(data, type)
11918 var index = this.indexOf(data);
11920 var newIndex = index + type;
11924 this.insert(newIndex, data);
11929 * Ext JS Library 1.1.1
11930 * Copyright(c) 2006-2007, Ext JS, LLC.
11932 * Originally Released Under LGPL - original licence link has changed is not relivant.
11935 * <script type="text/javascript">
11939 * @class Roo.data.SimpleStore
11940 * @extends Roo.data.Store
11941 * Small helper class to make creating Stores from Array data easier.
11942 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
11943 * @cfg {Array} fields An array of field definition objects, or field name strings.
11944 * @cfg {Array} data The multi-dimensional array of data
11946 * @param {Object} config
11948 Roo.data.SimpleStore = function(config){
11949 Roo.data.SimpleStore.superclass.constructor.call(this, {
11951 reader: new Roo.data.ArrayReader({
11954 Roo.data.Record.create(config.fields)
11956 proxy : new Roo.data.MemoryProxy(config.data)
11960 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
11962 * Ext JS Library 1.1.1
11963 * Copyright(c) 2006-2007, Ext JS, LLC.
11965 * Originally Released Under LGPL - original licence link has changed is not relivant.
11968 * <script type="text/javascript">
11973 * @extends Roo.data.Store
11974 * @class Roo.data.JsonStore
11975 * Small helper class to make creating Stores for JSON data easier. <br/>
11977 var store = new Roo.data.JsonStore({
11978 url: 'get-images.php',
11980 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
11983 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
11984 * JsonReader and HttpProxy (unless inline data is provided).</b>
11985 * @cfg {Array} fields An array of field definition objects, or field name strings.
11987 * @param {Object} config
11989 Roo.data.JsonStore = function(c){
11990 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
11991 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
11992 reader: new Roo.data.JsonReader(c, c.fields)
11995 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
11997 * Ext JS Library 1.1.1
11998 * Copyright(c) 2006-2007, Ext JS, LLC.
12000 * Originally Released Under LGPL - original licence link has changed is not relivant.
12003 * <script type="text/javascript">
12007 Roo.data.Field = function(config){
12008 if(typeof config == "string"){
12009 config = {name: config};
12011 Roo.apply(this, config);
12014 this.type = "auto";
12017 var st = Roo.data.SortTypes;
12018 // named sortTypes are supported, here we look them up
12019 if(typeof this.sortType == "string"){
12020 this.sortType = st[this.sortType];
12023 // set default sortType for strings and dates
12024 if(!this.sortType){
12027 this.sortType = st.asUCString;
12030 this.sortType = st.asDate;
12033 this.sortType = st.none;
12038 var stripRe = /[\$,%]/g;
12040 // prebuilt conversion function for this field, instead of
12041 // switching every time we're reading a value
12043 var cv, dateFormat = this.dateFormat;
12048 cv = function(v){ return v; };
12051 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
12055 return v !== undefined && v !== null && v !== '' ?
12056 parseInt(String(v).replace(stripRe, ""), 10) : '';
12061 return v !== undefined && v !== null && v !== '' ?
12062 parseFloat(String(v).replace(stripRe, ""), 10) : '';
12067 cv = function(v){ return v === true || v === "true" || v == 1; };
12074 if(v instanceof Date){
12078 if(dateFormat == "timestamp"){
12079 return new Date(v*1000);
12081 return Date.parseDate(v, dateFormat);
12083 var parsed = Date.parse(v);
12084 return parsed ? new Date(parsed) : null;
12093 Roo.data.Field.prototype = {
12101 * Ext JS Library 1.1.1
12102 * Copyright(c) 2006-2007, Ext JS, LLC.
12104 * Originally Released Under LGPL - original licence link has changed is not relivant.
12107 * <script type="text/javascript">
12110 // Base class for reading structured data from a data source. This class is intended to be
12111 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
12114 * @class Roo.data.DataReader
12115 * Base class for reading structured data from a data source. This class is intended to be
12116 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
12119 Roo.data.DataReader = function(meta, recordType){
12123 this.recordType = recordType instanceof Array ?
12124 Roo.data.Record.create(recordType) : recordType;
12127 Roo.data.DataReader.prototype = {
12129 * Create an empty record
12130 * @param {Object} data (optional) - overlay some values
12131 * @return {Roo.data.Record} record created.
12133 newRow : function(d) {
12135 this.recordType.prototype.fields.each(function(c) {
12137 case 'int' : da[c.name] = 0; break;
12138 case 'date' : da[c.name] = new Date(); break;
12139 case 'float' : da[c.name] = 0.0; break;
12140 case 'boolean' : da[c.name] = false; break;
12141 default : da[c.name] = ""; break;
12145 return new this.recordType(Roo.apply(da, d));
12150 * Ext JS Library 1.1.1
12151 * Copyright(c) 2006-2007, Ext JS, LLC.
12153 * Originally Released Under LGPL - original licence link has changed is not relivant.
12156 * <script type="text/javascript">
12160 * @class Roo.data.DataProxy
12161 * @extends Roo.data.Observable
12162 * This class is an abstract base class for implementations which provide retrieval of
12163 * unformatted data objects.<br>
12165 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
12166 * (of the appropriate type which knows how to parse the data object) to provide a block of
12167 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
12169 * Custom implementations must implement the load method as described in
12170 * {@link Roo.data.HttpProxy#load}.
12172 Roo.data.DataProxy = function(){
12175 * @event beforeload
12176 * Fires before a network request is made to retrieve a data object.
12177 * @param {Object} This DataProxy object.
12178 * @param {Object} params The params parameter to the load function.
12183 * Fires before the load method's callback is called.
12184 * @param {Object} This DataProxy object.
12185 * @param {Object} o The data object.
12186 * @param {Object} arg The callback argument object passed to the load function.
12190 * @event loadexception
12191 * Fires if an Exception occurs during data retrieval.
12192 * @param {Object} This DataProxy object.
12193 * @param {Object} o The data object.
12194 * @param {Object} arg The callback argument object passed to the load function.
12195 * @param {Object} e The Exception.
12197 loadexception : true
12199 Roo.data.DataProxy.superclass.constructor.call(this);
12202 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
12205 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
12209 * Ext JS Library 1.1.1
12210 * Copyright(c) 2006-2007, Ext JS, LLC.
12212 * Originally Released Under LGPL - original licence link has changed is not relivant.
12215 * <script type="text/javascript">
12218 * @class Roo.data.MemoryProxy
12219 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
12220 * to the Reader when its load method is called.
12222 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
12224 Roo.data.MemoryProxy = function(data){
12228 Roo.data.MemoryProxy.superclass.constructor.call(this);
12232 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
12235 * Load data from the requested source (in this case an in-memory
12236 * data object passed to the constructor), read the data object into
12237 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12238 * process that block using the passed callback.
12239 * @param {Object} params This parameter is not used by the MemoryProxy class.
12240 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12241 * object into a block of Roo.data.Records.
12242 * @param {Function} callback The function into which to pass the block of Roo.data.records.
12243 * The function must be passed <ul>
12244 * <li>The Record block object</li>
12245 * <li>The "arg" argument from the load function</li>
12246 * <li>A boolean success indicator</li>
12248 * @param {Object} scope The scope in which to call the callback
12249 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12251 load : function(params, reader, callback, scope, arg){
12252 params = params || {};
12255 result = reader.readRecords(this.data);
12257 this.fireEvent("loadexception", this, arg, null, e);
12258 callback.call(scope, null, arg, false);
12261 callback.call(scope, result, arg, true);
12265 update : function(params, records){
12270 * Ext JS Library 1.1.1
12271 * Copyright(c) 2006-2007, Ext JS, LLC.
12273 * Originally Released Under LGPL - original licence link has changed is not relivant.
12276 * <script type="text/javascript">
12279 * @class Roo.data.HttpProxy
12280 * @extends Roo.data.DataProxy
12281 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
12282 * configured to reference a certain URL.<br><br>
12284 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
12285 * from which the running page was served.<br><br>
12287 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
12289 * Be aware that to enable the browser to parse an XML document, the server must set
12290 * the Content-Type header in the HTTP response to "text/xml".
12292 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
12293 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
12294 * will be used to make the request.
12296 Roo.data.HttpProxy = function(conn){
12297 Roo.data.HttpProxy.superclass.constructor.call(this);
12298 // is conn a conn config or a real conn?
12300 this.useAjax = !conn || !conn.events;
12304 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
12305 // thse are take from connection...
12308 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
12311 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
12312 * extra parameters to each request made by this object. (defaults to undefined)
12315 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
12316 * to each request made by this object. (defaults to undefined)
12319 * @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)
12322 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
12325 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
12331 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
12335 * Return the {@link Roo.data.Connection} object being used by this Proxy.
12336 * @return {Connection} The Connection object. This object may be used to subscribe to events on
12337 * a finer-grained basis than the DataProxy events.
12339 getConnection : function(){
12340 return this.useAjax ? Roo.Ajax : this.conn;
12344 * Load data from the configured {@link Roo.data.Connection}, read the data object into
12345 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
12346 * process that block using the passed callback.
12347 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12348 * for the request to the remote server.
12349 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12350 * object into a block of Roo.data.Records.
12351 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12352 * The function must be passed <ul>
12353 * <li>The Record block object</li>
12354 * <li>The "arg" argument from the load function</li>
12355 * <li>A boolean success indicator</li>
12357 * @param {Object} scope The scope in which to call the callback
12358 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12360 load : function(params, reader, callback, scope, arg){
12361 if(this.fireEvent("beforeload", this, params) !== false){
12363 params : params || {},
12365 callback : callback,
12370 callback : this.loadResponse,
12374 Roo.applyIf(o, this.conn);
12375 if(this.activeRequest){
12376 Roo.Ajax.abort(this.activeRequest);
12378 this.activeRequest = Roo.Ajax.request(o);
12380 this.conn.request(o);
12383 callback.call(scope||this, null, arg, false);
12388 loadResponse : function(o, success, response){
12389 delete this.activeRequest;
12391 this.fireEvent("loadexception", this, o, response);
12392 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12397 result = o.reader.read(response);
12399 this.fireEvent("loadexception", this, o, response, e);
12400 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12404 this.fireEvent("load", this, o, o.request.arg);
12405 o.request.callback.call(o.request.scope, result, o.request.arg, true);
12409 update : function(dataSet){
12414 updateResponse : function(dataSet){
12419 * Ext JS Library 1.1.1
12420 * Copyright(c) 2006-2007, Ext JS, LLC.
12422 * Originally Released Under LGPL - original licence link has changed is not relivant.
12425 * <script type="text/javascript">
12429 * @class Roo.data.ScriptTagProxy
12430 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
12431 * other than the originating domain of the running page.<br><br>
12433 * <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
12434 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
12436 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
12437 * source code that is used as the source inside a <script> tag.<br><br>
12439 * In order for the browser to process the returned data, the server must wrap the data object
12440 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
12441 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
12442 * depending on whether the callback name was passed:
12445 boolean scriptTag = false;
12446 String cb = request.getParameter("callback");
12449 response.setContentType("text/javascript");
12451 response.setContentType("application/x-json");
12453 Writer out = response.getWriter();
12455 out.write(cb + "(");
12457 out.print(dataBlock.toJsonString());
12464 * @param {Object} config A configuration object.
12466 Roo.data.ScriptTagProxy = function(config){
12467 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
12468 Roo.apply(this, config);
12469 this.head = document.getElementsByTagName("head")[0];
12472 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
12474 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
12476 * @cfg {String} url The URL from which to request the data object.
12479 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
12483 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
12484 * the server the name of the callback function set up by the load call to process the returned data object.
12485 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
12486 * javascript output which calls this named function passing the data object as its only parameter.
12488 callbackParam : "callback",
12490 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
12491 * name to the request.
12496 * Load data from the configured URL, read the data object into
12497 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12498 * process that block using the passed callback.
12499 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12500 * for the request to the remote server.
12501 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12502 * object into a block of Roo.data.Records.
12503 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12504 * The function must be passed <ul>
12505 * <li>The Record block object</li>
12506 * <li>The "arg" argument from the load function</li>
12507 * <li>A boolean success indicator</li>
12509 * @param {Object} scope The scope in which to call the callback
12510 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12512 load : function(params, reader, callback, scope, arg){
12513 if(this.fireEvent("beforeload", this, params) !== false){
12515 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
12517 var url = this.url;
12518 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
12520 url += "&_dc=" + (new Date().getTime());
12522 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
12525 cb : "stcCallback"+transId,
12526 scriptId : "stcScript"+transId,
12530 callback : callback,
12536 window[trans.cb] = function(o){
12537 conn.handleResponse(o, trans);
12540 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
12542 if(this.autoAbort !== false){
12546 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
12548 var script = document.createElement("script");
12549 script.setAttribute("src", url);
12550 script.setAttribute("type", "text/javascript");
12551 script.setAttribute("id", trans.scriptId);
12552 this.head.appendChild(script);
12554 this.trans = trans;
12556 callback.call(scope||this, null, arg, false);
12561 isLoading : function(){
12562 return this.trans ? true : false;
12566 * Abort the current server request.
12568 abort : function(){
12569 if(this.isLoading()){
12570 this.destroyTrans(this.trans);
12575 destroyTrans : function(trans, isLoaded){
12576 this.head.removeChild(document.getElementById(trans.scriptId));
12577 clearTimeout(trans.timeoutId);
12579 window[trans.cb] = undefined;
12581 delete window[trans.cb];
12584 // if hasn't been loaded, wait for load to remove it to prevent script error
12585 window[trans.cb] = function(){
12586 window[trans.cb] = undefined;
12588 delete window[trans.cb];
12595 handleResponse : function(o, trans){
12596 this.trans = false;
12597 this.destroyTrans(trans, true);
12600 result = trans.reader.readRecords(o);
12602 this.fireEvent("loadexception", this, o, trans.arg, e);
12603 trans.callback.call(trans.scope||window, null, trans.arg, false);
12606 this.fireEvent("load", this, o, trans.arg);
12607 trans.callback.call(trans.scope||window, result, trans.arg, true);
12611 handleFailure : function(trans){
12612 this.trans = false;
12613 this.destroyTrans(trans, false);
12614 this.fireEvent("loadexception", this, null, trans.arg);
12615 trans.callback.call(trans.scope||window, null, trans.arg, false);
12619 * Ext JS Library 1.1.1
12620 * Copyright(c) 2006-2007, Ext JS, LLC.
12622 * Originally Released Under LGPL - original licence link has changed is not relivant.
12625 * <script type="text/javascript">
12629 * @class Roo.data.JsonReader
12630 * @extends Roo.data.DataReader
12631 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
12632 * based on mappings in a provided Roo.data.Record constructor.
12634 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
12635 * in the reply previously.
12640 var RecordDef = Roo.data.Record.create([
12641 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
12642 {name: 'occupation'} // This field will use "occupation" as the mapping.
12644 var myReader = new Roo.data.JsonReader({
12645 totalProperty: "results", // The property which contains the total dataset size (optional)
12646 root: "rows", // The property which contains an Array of row objects
12647 id: "id" // The property within each row object that provides an ID for the record (optional)
12651 * This would consume a JSON file like this:
12653 { 'results': 2, 'rows': [
12654 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
12655 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
12658 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
12659 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
12660 * paged from the remote server.
12661 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
12662 * @cfg {String} root name of the property which contains the Array of row objects.
12663 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
12664 * @cfg {Array} fields Array of field definition objects
12666 * Create a new JsonReader
12667 * @param {Object} meta Metadata configuration options
12668 * @param {Object} recordType Either an Array of field definition objects,
12669 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
12671 Roo.data.JsonReader = function(meta, recordType){
12674 // set some defaults:
12675 Roo.applyIf(meta, {
12676 totalProperty: 'total',
12677 successProperty : 'success',
12682 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
12684 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
12687 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
12688 * Used by Store query builder to append _requestMeta to params.
12691 metaFromRemote : false,
12693 * This method is only used by a DataProxy which has retrieved data from a remote server.
12694 * @param {Object} response The XHR object which contains the JSON data in its responseText.
12695 * @return {Object} data A data block which is used by an Roo.data.Store object as
12696 * a cache of Roo.data.Records.
12698 read : function(response){
12699 var json = response.responseText;
12701 var o = /* eval:var:o */ eval("("+json+")");
12703 throw {message: "JsonReader.read: Json object not found"};
12709 this.metaFromRemote = true;
12710 this.meta = o.metaData;
12711 this.recordType = Roo.data.Record.create(o.metaData.fields);
12712 this.onMetaChange(this.meta, this.recordType, o);
12714 return this.readRecords(o);
12717 // private function a store will implement
12718 onMetaChange : function(meta, recordType, o){
12725 simpleAccess: function(obj, subsc) {
12732 getJsonAccessor: function(){
12734 return function(expr) {
12736 return(re.test(expr))
12737 ? new Function("obj", "return obj." + expr)
12742 return Roo.emptyFn;
12747 * Create a data block containing Roo.data.Records from an XML document.
12748 * @param {Object} o An object which contains an Array of row objects in the property specified
12749 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
12750 * which contains the total size of the dataset.
12751 * @return {Object} data A data block which is used by an Roo.data.Store object as
12752 * a cache of Roo.data.Records.
12754 readRecords : function(o){
12756 * After any data loads, the raw JSON data is available for further custom processing.
12760 var s = this.meta, Record = this.recordType,
12761 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
12763 // Generate extraction functions for the totalProperty, the root, the id, and for each field
12765 if(s.totalProperty) {
12766 this.getTotal = this.getJsonAccessor(s.totalProperty);
12768 if(s.successProperty) {
12769 this.getSuccess = this.getJsonAccessor(s.successProperty);
12771 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
12773 var g = this.getJsonAccessor(s.id);
12774 this.getId = function(rec) {
12776 return (r === undefined || r === "") ? null : r;
12779 this.getId = function(){return null;};
12782 for(var jj = 0; jj < fl; jj++){
12784 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
12785 this.ef[jj] = this.getJsonAccessor(map);
12789 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
12790 if(s.totalProperty){
12791 var vt = parseInt(this.getTotal(o), 10);
12796 if(s.successProperty){
12797 var vs = this.getSuccess(o);
12798 if(vs === false || vs === 'false'){
12803 for(var i = 0; i < c; i++){
12806 var id = this.getId(n);
12807 for(var j = 0; j < fl; j++){
12809 var v = this.ef[j](n);
12811 Roo.log('missing convert for ' + f.name);
12815 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
12817 var record = new Record(values, id);
12819 records[i] = record;
12825 totalRecords : totalRecords
12830 * Ext JS Library 1.1.1
12831 * Copyright(c) 2006-2007, Ext JS, LLC.
12833 * Originally Released Under LGPL - original licence link has changed is not relivant.
12836 * <script type="text/javascript">
12840 * @class Roo.data.ArrayReader
12841 * @extends Roo.data.DataReader
12842 * Data reader class to create an Array of Roo.data.Record objects from an Array.
12843 * Each element of that Array represents a row of data fields. The
12844 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
12845 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
12849 var RecordDef = Roo.data.Record.create([
12850 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
12851 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
12853 var myReader = new Roo.data.ArrayReader({
12854 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
12858 * This would consume an Array like this:
12860 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
12862 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
12864 * Create a new JsonReader
12865 * @param {Object} meta Metadata configuration options.
12866 * @param {Object} recordType Either an Array of field definition objects
12867 * as specified to {@link Roo.data.Record#create},
12868 * or an {@link Roo.data.Record} object
12869 * created using {@link Roo.data.Record#create}.
12871 Roo.data.ArrayReader = function(meta, recordType){
12872 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
12875 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
12877 * Create a data block containing Roo.data.Records from an XML document.
12878 * @param {Object} o An Array of row objects which represents the dataset.
12879 * @return {Object} data A data block which is used by an Roo.data.Store object as
12880 * a cache of Roo.data.Records.
12882 readRecords : function(o){
12883 var sid = this.meta ? this.meta.id : null;
12884 var recordType = this.recordType, fields = recordType.prototype.fields;
12887 for(var i = 0; i < root.length; i++){
12890 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
12891 for(var j = 0, jlen = fields.length; j < jlen; j++){
12892 var f = fields.items[j];
12893 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
12894 var v = n[k] !== undefined ? n[k] : f.defaultValue;
12896 values[f.name] = v;
12898 var record = new recordType(values, id);
12900 records[records.length] = record;
12904 totalRecords : records.length
12913 * @class Roo.bootstrap.ComboBox
12914 * @extends Roo.bootstrap.TriggerField
12915 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
12916 * @cfg {Boolean} append (true|false) default false
12917 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
12918 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
12919 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
12920 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
12921 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
12922 * @cfg {Boolean} animate default true
12923 * @cfg {Boolean} emptyResultText only for touch device
12924 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
12925 * @cfg {String} emptyTitle default ''
12927 * Create a new ComboBox.
12928 * @param {Object} config Configuration options
12930 Roo.bootstrap.ComboBox = function(config){
12931 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
12935 * Fires when the dropdown list is expanded
12936 * @param {Roo.bootstrap.ComboBox} combo This combo box
12941 * Fires when the dropdown list is collapsed
12942 * @param {Roo.bootstrap.ComboBox} combo This combo box
12946 * @event beforeselect
12947 * Fires before a list item is selected. Return false to cancel the selection.
12948 * @param {Roo.bootstrap.ComboBox} combo This combo box
12949 * @param {Roo.data.Record} record The data record returned from the underlying store
12950 * @param {Number} index The index of the selected item in the dropdown list
12952 'beforeselect' : true,
12955 * Fires when a list item is selected
12956 * @param {Roo.bootstrap.ComboBox} combo This combo box
12957 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
12958 * @param {Number} index The index of the selected item in the dropdown list
12962 * @event beforequery
12963 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
12964 * The event object passed has these properties:
12965 * @param {Roo.bootstrap.ComboBox} combo This combo box
12966 * @param {String} query The query
12967 * @param {Boolean} forceAll true to force "all" query
12968 * @param {Boolean} cancel true to cancel the query
12969 * @param {Object} e The query event object
12971 'beforequery': true,
12974 * Fires when the 'add' icon is pressed (add a listener to enable add button)
12975 * @param {Roo.bootstrap.ComboBox} combo This combo box
12980 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
12981 * @param {Roo.bootstrap.ComboBox} combo This combo box
12982 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
12987 * Fires when the remove value from the combobox array
12988 * @param {Roo.bootstrap.ComboBox} combo This combo box
12992 * @event afterremove
12993 * Fires when the remove value from the combobox array
12994 * @param {Roo.bootstrap.ComboBox} combo This combo box
12996 'afterremove' : true,
12998 * @event specialfilter
12999 * Fires when specialfilter
13000 * @param {Roo.bootstrap.ComboBox} combo This combo box
13002 'specialfilter' : true,
13005 * Fires when tick the element
13006 * @param {Roo.bootstrap.ComboBox} combo This combo box
13010 * @event touchviewdisplay
13011 * Fires when touch view require special display (default is using displayField)
13012 * @param {Roo.bootstrap.ComboBox} combo This combo box
13013 * @param {Object} cfg set html .
13015 'touchviewdisplay' : true
13020 this.tickItems = [];
13022 this.selectedIndex = -1;
13023 if(this.mode == 'local'){
13024 if(config.queryDelay === undefined){
13025 this.queryDelay = 10;
13027 if(config.minChars === undefined){
13033 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
13036 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
13037 * rendering into an Roo.Editor, defaults to false)
13040 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
13041 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
13044 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
13047 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
13048 * the dropdown list (defaults to undefined, with no header element)
13052 * @cfg {String/Roo.Template} tpl The template to use to render the output
13056 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
13058 listWidth: undefined,
13060 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
13061 * mode = 'remote' or 'text' if mode = 'local')
13063 displayField: undefined,
13066 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
13067 * mode = 'remote' or 'value' if mode = 'local').
13068 * Note: use of a valueField requires the user make a selection
13069 * in order for a value to be mapped.
13071 valueField: undefined,
13073 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
13078 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
13079 * field's data value (defaults to the underlying DOM element's name)
13081 hiddenName: undefined,
13083 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
13087 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
13089 selectedClass: 'active',
13092 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
13096 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
13097 * anchor positions (defaults to 'tl-bl')
13099 listAlign: 'tl-bl?',
13101 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
13105 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
13106 * query specified by the allQuery config option (defaults to 'query')
13108 triggerAction: 'query',
13110 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
13111 * (defaults to 4, does not apply if editable = false)
13115 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
13116 * delay (typeAheadDelay) if it matches a known value (defaults to false)
13120 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
13121 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
13125 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
13126 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
13130 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
13131 * when editable = true (defaults to false)
13133 selectOnFocus:false,
13135 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
13137 queryParam: 'query',
13139 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
13140 * when mode = 'remote' (defaults to 'Loading...')
13142 loadingText: 'Loading...',
13144 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
13148 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
13152 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
13153 * traditional select (defaults to true)
13157 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
13161 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
13165 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
13166 * listWidth has a higher value)
13170 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
13171 * allow the user to set arbitrary text into the field (defaults to false)
13173 forceSelection:false,
13175 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
13176 * if typeAhead = true (defaults to 250)
13178 typeAheadDelay : 250,
13180 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
13181 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
13183 valueNotFoundText : undefined,
13185 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
13187 blockFocus : false,
13190 * @cfg {Boolean} disableClear Disable showing of clear button.
13192 disableClear : false,
13194 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
13196 alwaysQuery : false,
13199 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
13204 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
13206 invalidClass : "has-warning",
13209 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
13211 validClass : "has-success",
13214 * @cfg {Boolean} specialFilter (true|false) special filter default false
13216 specialFilter : false,
13219 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
13221 mobileTouchView : true,
13224 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
13226 useNativeIOS : false,
13229 * @cfg {Boolean} mobile_restrict_height (true|false) restrict height for touch view
13231 mobile_restrict_height : false,
13233 ios_options : false,
13245 btnPosition : 'right',
13246 triggerList : true,
13247 showToggleBtn : true,
13249 emptyResultText: 'Empty',
13250 triggerText : 'Select',
13253 // element that contains real text value.. (when hidden is used..)
13255 getAutoCreate : function()
13260 * Render classic select for iso
13263 if(Roo.isIOS && this.useNativeIOS){
13264 cfg = this.getAutoCreateNativeIOS();
13272 if(Roo.isTouch && this.mobileTouchView){
13273 cfg = this.getAutoCreateTouchView();
13280 if(!this.tickable){
13281 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
13286 * ComboBox with tickable selections
13289 var align = this.labelAlign || this.parentLabelAlign();
13292 cls : 'form-group roo-combobox-tickable' //input-group
13295 var btn_text_select = '';
13296 var btn_text_done = '';
13297 var btn_text_cancel = '';
13299 if (this.btn_text_show) {
13300 btn_text_select = 'Select';
13301 btn_text_done = 'Done';
13302 btn_text_cancel = 'Cancel';
13307 cls : 'tickable-buttons',
13312 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
13313 //html : this.triggerText
13314 html: btn_text_select
13320 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
13322 html: btn_text_done
13328 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
13330 html: btn_text_cancel
13336 buttons.cn.unshift({
13338 cls: 'roo-select2-search-field-input'
13344 Roo.each(buttons.cn, function(c){
13346 c.cls += ' btn-' + _this.size;
13349 if (_this.disabled) {
13360 cls: 'form-hidden-field'
13364 cls: 'roo-select2-choices',
13368 cls: 'roo-select2-search-field',
13379 cls: 'roo-select2-container input-group roo-select2-container-multi',
13385 // cls: 'typeahead typeahead-long dropdown-menu',
13386 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
13391 if(this.hasFeedback && !this.allowBlank){
13395 cls: 'glyphicon form-control-feedback'
13398 combobox.cn.push(feedback);
13403 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
13404 tooltip : 'This field is required'
13406 if (Roo.bootstrap.version == 4) {
13409 style : 'display:none'
13412 if (align ==='left' && this.fieldLabel.length) {
13414 cfg.cls += ' roo-form-group-label-left row';
13421 cls : 'control-label col-form-label',
13422 html : this.fieldLabel
13434 var labelCfg = cfg.cn[1];
13435 var contentCfg = cfg.cn[2];
13438 if(this.indicatorpos == 'right'){
13444 cls : 'control-label col-form-label',
13448 html : this.fieldLabel
13464 labelCfg = cfg.cn[0];
13465 contentCfg = cfg.cn[1];
13469 if(this.labelWidth > 12){
13470 labelCfg.style = "width: " + this.labelWidth + 'px';
13473 if(this.labelWidth < 13 && this.labelmd == 0){
13474 this.labelmd = this.labelWidth;
13477 if(this.labellg > 0){
13478 labelCfg.cls += ' col-lg-' + this.labellg;
13479 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
13482 if(this.labelmd > 0){
13483 labelCfg.cls += ' col-md-' + this.labelmd;
13484 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
13487 if(this.labelsm > 0){
13488 labelCfg.cls += ' col-sm-' + this.labelsm;
13489 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
13492 if(this.labelxs > 0){
13493 labelCfg.cls += ' col-xs-' + this.labelxs;
13494 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
13498 } else if ( this.fieldLabel.length) {
13499 // Roo.log(" label");
13504 //cls : 'input-group-addon',
13505 html : this.fieldLabel
13510 if(this.indicatorpos == 'right'){
13514 //cls : 'input-group-addon',
13515 html : this.fieldLabel
13525 // Roo.log(" no label && no align");
13532 ['xs','sm','md','lg'].map(function(size){
13533 if (settings[size]) {
13534 cfg.cls += ' col-' + size + '-' + settings[size];
13542 _initEventsCalled : false,
13545 initEvents: function()
13547 if (this._initEventsCalled) { // as we call render... prevent looping...
13550 this._initEventsCalled = true;
13553 throw "can not find store for combo";
13556 this.indicator = this.indicatorEl();
13558 this.store = Roo.factory(this.store, Roo.data);
13559 this.store.parent = this;
13561 // if we are building from html. then this element is so complex, that we can not really
13562 // use the rendered HTML.
13563 // so we have to trash and replace the previous code.
13564 if (Roo.XComponent.build_from_html) {
13565 // remove this element....
13566 var e = this.el.dom, k=0;
13567 while (e ) { e = e.previousSibling; ++k;}
13572 this.rendered = false;
13574 this.render(this.parent().getChildContainer(true), k);
13577 if(Roo.isIOS && this.useNativeIOS){
13578 this.initIOSView();
13586 if(Roo.isTouch && this.mobileTouchView){
13587 this.initTouchView();
13592 this.initTickableEvents();
13596 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
13598 if(this.hiddenName){
13600 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13602 this.hiddenField.dom.value =
13603 this.hiddenValue !== undefined ? this.hiddenValue :
13604 this.value !== undefined ? this.value : '';
13606 // prevent input submission
13607 this.el.dom.removeAttribute('name');
13608 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13613 // this.el.dom.setAttribute('autocomplete', 'off');
13616 var cls = 'x-combo-list';
13618 //this.list = new Roo.Layer({
13619 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
13625 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13626 _this.list.setWidth(lw);
13629 this.list.on('mouseover', this.onViewOver, this);
13630 this.list.on('mousemove', this.onViewMove, this);
13631 this.list.on('scroll', this.onViewScroll, this);
13634 this.list.swallowEvent('mousewheel');
13635 this.assetHeight = 0;
13638 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
13639 this.assetHeight += this.header.getHeight();
13642 this.innerList = this.list.createChild({cls:cls+'-inner'});
13643 this.innerList.on('mouseover', this.onViewOver, this);
13644 this.innerList.on('mousemove', this.onViewMove, this);
13645 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13647 if(this.allowBlank && !this.pageSize && !this.disableClear){
13648 this.footer = this.list.createChild({cls:cls+'-ft'});
13649 this.pageTb = new Roo.Toolbar(this.footer);
13653 this.footer = this.list.createChild({cls:cls+'-ft'});
13654 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
13655 {pageSize: this.pageSize});
13659 if (this.pageTb && this.allowBlank && !this.disableClear) {
13661 this.pageTb.add(new Roo.Toolbar.Fill(), {
13662 cls: 'x-btn-icon x-btn-clear',
13664 handler: function()
13667 _this.clearValue();
13668 _this.onSelect(false, -1);
13673 this.assetHeight += this.footer.getHeight();
13678 this.tpl = Roo.bootstrap.version == 4 ?
13679 '<a class="dropdown-item" href="#">{' + this.displayField + '}</a>' : // 4 does not need <li> and it get's really confisued.
13680 '<li><a class="dropdown-item" href="#">{' + this.displayField + '}</a></li>';
13683 this.view = new Roo.View(this.list, this.tpl, {
13684 singleSelect:true, store: this.store, selectedClass: this.selectedClass
13686 //this.view.wrapEl.setDisplayed(false);
13687 this.view.on('click', this.onViewClick, this);
13690 this.store.on('beforeload', this.onBeforeLoad, this);
13691 this.store.on('load', this.onLoad, this);
13692 this.store.on('loadexception', this.onLoadException, this);
13694 if(this.resizable){
13695 this.resizer = new Roo.Resizable(this.list, {
13696 pinned:true, handles:'se'
13698 this.resizer.on('resize', function(r, w, h){
13699 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
13700 this.listWidth = w;
13701 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
13702 this.restrictHeight();
13704 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
13707 if(!this.editable){
13708 this.editable = true;
13709 this.setEditable(false);
13714 if (typeof(this.events.add.listeners) != 'undefined') {
13716 this.addicon = this.wrap.createChild(
13717 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
13719 this.addicon.on('click', function(e) {
13720 this.fireEvent('add', this);
13723 if (typeof(this.events.edit.listeners) != 'undefined') {
13725 this.editicon = this.wrap.createChild(
13726 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
13727 if (this.addicon) {
13728 this.editicon.setStyle('margin-left', '40px');
13730 this.editicon.on('click', function(e) {
13732 // we fire even if inothing is selected..
13733 this.fireEvent('edit', this, this.lastData );
13739 this.keyNav = new Roo.KeyNav(this.inputEl(), {
13740 "up" : function(e){
13741 this.inKeyMode = true;
13745 "down" : function(e){
13746 if(!this.isExpanded()){
13747 this.onTriggerClick();
13749 this.inKeyMode = true;
13754 "enter" : function(e){
13755 // this.onViewClick();
13759 if(this.fireEvent("specialkey", this, e)){
13760 this.onViewClick(false);
13766 "esc" : function(e){
13770 "tab" : function(e){
13773 if(this.fireEvent("specialkey", this, e)){
13774 this.onViewClick(false);
13782 doRelay : function(foo, bar, hname){
13783 if(hname == 'down' || this.scope.isExpanded()){
13784 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13793 this.queryDelay = Math.max(this.queryDelay || 10,
13794 this.mode == 'local' ? 10 : 250);
13797 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13799 if(this.typeAhead){
13800 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13802 if(this.editable !== false){
13803 this.inputEl().on("keyup", this.onKeyUp, this);
13805 if(this.forceSelection){
13806 this.inputEl().on('blur', this.doForce, this);
13810 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13811 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13815 initTickableEvents: function()
13819 if(this.hiddenName){
13821 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13823 this.hiddenField.dom.value =
13824 this.hiddenValue !== undefined ? this.hiddenValue :
13825 this.value !== undefined ? this.value : '';
13827 // prevent input submission
13828 this.el.dom.removeAttribute('name');
13829 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13834 // this.list = this.el.select('ul.dropdown-menu',true).first();
13836 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13837 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13838 if(this.triggerList){
13839 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
13842 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
13843 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
13845 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
13846 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
13848 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
13849 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
13851 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
13852 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
13853 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
13856 this.cancelBtn.hide();
13861 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13862 _this.list.setWidth(lw);
13865 this.list.on('mouseover', this.onViewOver, this);
13866 this.list.on('mousemove', this.onViewMove, this);
13868 this.list.on('scroll', this.onViewScroll, this);
13871 this.tpl = '<li class="roo-select2-result"><div class="checkbox"><input id="{roo-id}"' +
13872 'type="checkbox" {roo-data-checked}><label for="{roo-id}"><b>{' + this.displayField + '}</b></label></div></li>';
13875 this.view = new Roo.View(this.list, this.tpl, {
13880 selectedClass: this.selectedClass
13883 //this.view.wrapEl.setDisplayed(false);
13884 this.view.on('click', this.onViewClick, this);
13888 this.store.on('beforeload', this.onBeforeLoad, this);
13889 this.store.on('load', this.onLoad, this);
13890 this.store.on('loadexception', this.onLoadException, this);
13893 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
13894 "up" : function(e){
13895 this.inKeyMode = true;
13899 "down" : function(e){
13900 this.inKeyMode = true;
13904 "enter" : function(e){
13905 if(this.fireEvent("specialkey", this, e)){
13906 this.onViewClick(false);
13912 "esc" : function(e){
13913 this.onTickableFooterButtonClick(e, false, false);
13916 "tab" : function(e){
13917 this.fireEvent("specialkey", this, e);
13919 this.onTickableFooterButtonClick(e, false, false);
13926 doRelay : function(e, fn, key){
13927 if(this.scope.isExpanded()){
13928 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13937 this.queryDelay = Math.max(this.queryDelay || 10,
13938 this.mode == 'local' ? 10 : 250);
13941 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13943 if(this.typeAhead){
13944 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13947 if(this.editable !== false){
13948 this.tickableInputEl().on("keyup", this.onKeyUp, this);
13951 this.indicator = this.indicatorEl();
13953 if(this.indicator){
13954 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
13955 this.indicator.hide();
13960 onDestroy : function(){
13962 this.view.setStore(null);
13963 this.view.el.removeAllListeners();
13964 this.view.el.remove();
13965 this.view.purgeListeners();
13968 this.list.dom.innerHTML = '';
13972 this.store.un('beforeload', this.onBeforeLoad, this);
13973 this.store.un('load', this.onLoad, this);
13974 this.store.un('loadexception', this.onLoadException, this);
13976 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
13980 fireKey : function(e){
13981 if(e.isNavKeyPress() && !this.list.isVisible()){
13982 this.fireEvent("specialkey", this, e);
13987 onResize: function(w, h){
13988 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
13990 // if(typeof w != 'number'){
13991 // // we do not handle it!?!?
13994 // var tw = this.trigger.getWidth();
13995 // // tw += this.addicon ? this.addicon.getWidth() : 0;
13996 // // tw += this.editicon ? this.editicon.getWidth() : 0;
13998 // this.inputEl().setWidth( this.adjustWidth('input', x));
14000 // //this.trigger.setStyle('left', x+'px');
14002 // if(this.list && this.listWidth === undefined){
14003 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
14004 // this.list.setWidth(lw);
14005 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
14013 * Allow or prevent the user from directly editing the field text. If false is passed,
14014 * the user will only be able to select from the items defined in the dropdown list. This method
14015 * is the runtime equivalent of setting the 'editable' config option at config time.
14016 * @param {Boolean} value True to allow the user to directly edit the field text
14018 setEditable : function(value){
14019 if(value == this.editable){
14022 this.editable = value;
14024 this.inputEl().dom.setAttribute('readOnly', true);
14025 this.inputEl().on('mousedown', this.onTriggerClick, this);
14026 this.inputEl().addClass('x-combo-noedit');
14028 this.inputEl().dom.setAttribute('readOnly', false);
14029 this.inputEl().un('mousedown', this.onTriggerClick, this);
14030 this.inputEl().removeClass('x-combo-noedit');
14036 onBeforeLoad : function(combo,opts){
14037 if(!this.hasFocus){
14041 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
14043 this.restrictHeight();
14044 this.selectedIndex = -1;
14048 onLoad : function(){
14050 this.hasQuery = false;
14052 if(!this.hasFocus){
14056 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
14057 this.loading.hide();
14060 if(this.store.getCount() > 0){
14063 this.restrictHeight();
14064 if(this.lastQuery == this.allQuery){
14065 if(this.editable && !this.tickable){
14066 this.inputEl().dom.select();
14070 !this.selectByValue(this.value, true) &&
14073 !this.store.lastOptions ||
14074 typeof(this.store.lastOptions.add) == 'undefined' ||
14075 this.store.lastOptions.add != true
14078 this.select(0, true);
14081 if(this.autoFocus){
14084 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
14085 this.taTask.delay(this.typeAheadDelay);
14089 this.onEmptyResults();
14095 onLoadException : function()
14097 this.hasQuery = false;
14099 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
14100 this.loading.hide();
14103 if(this.tickable && this.editable){
14108 // only causes errors at present
14109 //Roo.log(this.store.reader.jsonData);
14110 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
14112 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
14118 onTypeAhead : function(){
14119 if(this.store.getCount() > 0){
14120 var r = this.store.getAt(0);
14121 var newValue = r.data[this.displayField];
14122 var len = newValue.length;
14123 var selStart = this.getRawValue().length;
14125 if(selStart != len){
14126 this.setRawValue(newValue);
14127 this.selectText(selStart, newValue.length);
14133 onSelect : function(record, index){
14135 if(this.fireEvent('beforeselect', this, record, index) !== false){
14137 this.setFromData(index > -1 ? record.data : false);
14140 this.fireEvent('select', this, record, index);
14145 * Returns the currently selected field value or empty string if no value is set.
14146 * @return {String} value The selected value
14148 getValue : function()
14150 if(Roo.isIOS && this.useNativeIOS){
14151 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
14155 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
14158 if(this.valueField){
14159 return typeof this.value != 'undefined' ? this.value : '';
14161 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
14165 getRawValue : function()
14167 if(Roo.isIOS && this.useNativeIOS){
14168 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
14171 var v = this.inputEl().getValue();
14177 * Clears any text/value currently set in the field
14179 clearValue : function(){
14181 if(this.hiddenField){
14182 this.hiddenField.dom.value = '';
14185 this.setRawValue('');
14186 this.lastSelectionText = '';
14187 this.lastData = false;
14189 var close = this.closeTriggerEl();
14200 * Sets the specified value into the field. If the value finds a match, the corresponding record text
14201 * will be displayed in the field. If the value does not match the data value of an existing item,
14202 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
14203 * Otherwise the field will be blank (although the value will still be set).
14204 * @param {String} value The value to match
14206 setValue : function(v)
14208 if(Roo.isIOS && this.useNativeIOS){
14209 this.setIOSValue(v);
14219 if(this.valueField){
14220 var r = this.findRecord(this.valueField, v);
14222 text = r.data[this.displayField];
14223 }else if(this.valueNotFoundText !== undefined){
14224 text = this.valueNotFoundText;
14227 this.lastSelectionText = text;
14228 if(this.hiddenField){
14229 this.hiddenField.dom.value = v;
14231 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
14234 var close = this.closeTriggerEl();
14237 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
14243 * @property {Object} the last set data for the element
14248 * Sets the value of the field based on a object which is related to the record format for the store.
14249 * @param {Object} value the value to set as. or false on reset?
14251 setFromData : function(o){
14258 var dv = ''; // display value
14259 var vv = ''; // value value..
14261 if (this.displayField) {
14262 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14264 // this is an error condition!!!
14265 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14268 if(this.valueField){
14269 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
14272 var close = this.closeTriggerEl();
14275 if(dv.length || vv * 1 > 0){
14277 this.blockFocus=true;
14283 if(this.hiddenField){
14284 this.hiddenField.dom.value = vv;
14286 this.lastSelectionText = dv;
14287 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14291 // no hidden field.. - we store the value in 'value', but still display
14292 // display field!!!!
14293 this.lastSelectionText = dv;
14294 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14301 reset : function(){
14302 // overridden so that last data is reset..
14309 this.setValue(this.originalValue);
14310 //this.clearInvalid();
14311 this.lastData = false;
14313 this.view.clearSelections();
14319 findRecord : function(prop, value){
14321 if(this.store.getCount() > 0){
14322 this.store.each(function(r){
14323 if(r.data[prop] == value){
14333 getName: function()
14335 // returns hidden if it's set..
14336 if (!this.rendered) {return ''};
14337 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
14341 onViewMove : function(e, t){
14342 this.inKeyMode = false;
14346 onViewOver : function(e, t){
14347 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
14350 var item = this.view.findItemFromChild(t);
14353 var index = this.view.indexOf(item);
14354 this.select(index, false);
14359 onViewClick : function(view, doFocus, el, e)
14361 var index = this.view.getSelectedIndexes()[0];
14363 var r = this.store.getAt(index);
14367 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
14374 Roo.each(this.tickItems, function(v,k){
14376 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
14378 _this.tickItems.splice(k, 1);
14380 if(typeof(e) == 'undefined' && view == false){
14381 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
14393 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
14394 this.tickItems.push(r.data);
14397 if(typeof(e) == 'undefined' && view == false){
14398 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
14405 this.onSelect(r, index);
14407 if(doFocus !== false && !this.blockFocus){
14408 this.inputEl().focus();
14413 restrictHeight : function(){
14414 //this.innerList.dom.style.height = '';
14415 //var inner = this.innerList.dom;
14416 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
14417 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
14418 //this.list.beginUpdate();
14419 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
14420 this.list.alignTo(this.inputEl(), this.listAlign);
14421 this.list.alignTo(this.inputEl(), this.listAlign);
14422 //this.list.endUpdate();
14426 onEmptyResults : function(){
14428 if(this.tickable && this.editable){
14429 this.hasFocus = false;
14430 this.restrictHeight();
14438 * Returns true if the dropdown list is expanded, else false.
14440 isExpanded : function(){
14441 return this.list.isVisible();
14445 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
14446 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14447 * @param {String} value The data value of the item to select
14448 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14449 * selected item if it is not currently in view (defaults to true)
14450 * @return {Boolean} True if the value matched an item in the list, else false
14452 selectByValue : function(v, scrollIntoView){
14453 if(v !== undefined && v !== null){
14454 var r = this.findRecord(this.valueField || this.displayField, v);
14456 this.select(this.store.indexOf(r), scrollIntoView);
14464 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
14465 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14466 * @param {Number} index The zero-based index of the list item to select
14467 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14468 * selected item if it is not currently in view (defaults to true)
14470 select : function(index, scrollIntoView){
14471 this.selectedIndex = index;
14472 this.view.select(index);
14473 if(scrollIntoView !== false){
14474 var el = this.view.getNode(index);
14476 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
14479 this.list.scrollChildIntoView(el, false);
14485 selectNext : function(){
14486 var ct = this.store.getCount();
14488 if(this.selectedIndex == -1){
14490 }else if(this.selectedIndex < ct-1){
14491 this.select(this.selectedIndex+1);
14497 selectPrev : function(){
14498 var ct = this.store.getCount();
14500 if(this.selectedIndex == -1){
14502 }else if(this.selectedIndex != 0){
14503 this.select(this.selectedIndex-1);
14509 onKeyUp : function(e){
14510 if(this.editable !== false && !e.isSpecialKey()){
14511 this.lastKey = e.getKey();
14512 this.dqTask.delay(this.queryDelay);
14517 validateBlur : function(){
14518 return !this.list || !this.list.isVisible();
14522 initQuery : function(){
14524 var v = this.getRawValue();
14526 if(this.tickable && this.editable){
14527 v = this.tickableInputEl().getValue();
14534 doForce : function(){
14535 if(this.inputEl().dom.value.length > 0){
14536 this.inputEl().dom.value =
14537 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
14543 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
14544 * query allowing the query action to be canceled if needed.
14545 * @param {String} query The SQL query to execute
14546 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
14547 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
14548 * saved in the current store (defaults to false)
14550 doQuery : function(q, forceAll){
14552 if(q === undefined || q === null){
14557 forceAll: forceAll,
14561 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
14566 forceAll = qe.forceAll;
14567 if(forceAll === true || (q.length >= this.minChars)){
14569 this.hasQuery = true;
14571 if(this.lastQuery != q || this.alwaysQuery){
14572 this.lastQuery = q;
14573 if(this.mode == 'local'){
14574 this.selectedIndex = -1;
14576 this.store.clearFilter();
14579 if(this.specialFilter){
14580 this.fireEvent('specialfilter', this);
14585 this.store.filter(this.displayField, q);
14588 this.store.fireEvent("datachanged", this.store);
14595 this.store.baseParams[this.queryParam] = q;
14597 var options = {params : this.getParams(q)};
14600 options.add = true;
14601 options.params.start = this.page * this.pageSize;
14604 this.store.load(options);
14607 * this code will make the page width larger, at the beginning, the list not align correctly,
14608 * we should expand the list on onLoad
14609 * so command out it
14614 this.selectedIndex = -1;
14619 this.loadNext = false;
14623 getParams : function(q){
14625 //p[this.queryParam] = q;
14629 p.limit = this.pageSize;
14635 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
14637 collapse : function(){
14638 if(!this.isExpanded()){
14644 this.hasFocus = false;
14648 this.cancelBtn.hide();
14649 this.trigger.show();
14652 this.tickableInputEl().dom.value = '';
14653 this.tickableInputEl().blur();
14658 Roo.get(document).un('mousedown', this.collapseIf, this);
14659 Roo.get(document).un('mousewheel', this.collapseIf, this);
14660 if (!this.editable) {
14661 Roo.get(document).un('keydown', this.listKeyPress, this);
14663 this.fireEvent('collapse', this);
14669 collapseIf : function(e){
14670 var in_combo = e.within(this.el);
14671 var in_list = e.within(this.list);
14672 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
14674 if (in_combo || in_list || is_list) {
14675 //e.stopPropagation();
14680 this.onTickableFooterButtonClick(e, false, false);
14688 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
14690 expand : function(){
14692 if(this.isExpanded() || !this.hasFocus){
14696 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
14697 this.list.setWidth(lw);
14703 this.restrictHeight();
14707 this.tickItems = Roo.apply([], this.item);
14710 this.cancelBtn.show();
14711 this.trigger.hide();
14714 this.tickableInputEl().focus();
14719 Roo.get(document).on('mousedown', this.collapseIf, this);
14720 Roo.get(document).on('mousewheel', this.collapseIf, this);
14721 if (!this.editable) {
14722 Roo.get(document).on('keydown', this.listKeyPress, this);
14725 this.fireEvent('expand', this);
14729 // Implements the default empty TriggerField.onTriggerClick function
14730 onTriggerClick : function(e)
14732 Roo.log('trigger click');
14734 if(this.disabled || !this.triggerList){
14739 this.loadNext = false;
14741 if(this.isExpanded()){
14743 if (!this.blockFocus) {
14744 this.inputEl().focus();
14748 this.hasFocus = true;
14749 if(this.triggerAction == 'all') {
14750 this.doQuery(this.allQuery, true);
14752 this.doQuery(this.getRawValue());
14754 if (!this.blockFocus) {
14755 this.inputEl().focus();
14760 onTickableTriggerClick : function(e)
14767 this.loadNext = false;
14768 this.hasFocus = true;
14770 if(this.triggerAction == 'all') {
14771 this.doQuery(this.allQuery, true);
14773 this.doQuery(this.getRawValue());
14777 onSearchFieldClick : function(e)
14779 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
14780 this.onTickableFooterButtonClick(e, false, false);
14784 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
14789 this.loadNext = false;
14790 this.hasFocus = true;
14792 if(this.triggerAction == 'all') {
14793 this.doQuery(this.allQuery, true);
14795 this.doQuery(this.getRawValue());
14799 listKeyPress : function(e)
14801 //Roo.log('listkeypress');
14802 // scroll to first matching element based on key pres..
14803 if (e.isSpecialKey()) {
14806 var k = String.fromCharCode(e.getKey()).toUpperCase();
14809 var csel = this.view.getSelectedNodes();
14810 var cselitem = false;
14812 var ix = this.view.indexOf(csel[0]);
14813 cselitem = this.store.getAt(ix);
14814 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
14820 this.store.each(function(v) {
14822 // start at existing selection.
14823 if (cselitem.id == v.id) {
14829 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
14830 match = this.store.indexOf(v);
14836 if (match === false) {
14837 return true; // no more action?
14840 this.view.select(match);
14841 var sn = Roo.get(this.view.getSelectedNodes()[0]);
14842 sn.scrollIntoView(sn.dom.parentNode, false);
14845 onViewScroll : function(e, t){
14847 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){
14851 this.hasQuery = true;
14853 this.loading = this.list.select('.loading', true).first();
14855 if(this.loading === null){
14856 this.list.createChild({
14858 cls: 'loading roo-select2-more-results roo-select2-active',
14859 html: 'Loading more results...'
14862 this.loading = this.list.select('.loading', true).first();
14864 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
14866 this.loading.hide();
14869 this.loading.show();
14874 this.loadNext = true;
14876 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
14881 addItem : function(o)
14883 var dv = ''; // display value
14885 if (this.displayField) {
14886 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14888 // this is an error condition!!!
14889 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14896 var choice = this.choices.createChild({
14898 cls: 'roo-select2-search-choice',
14907 cls: 'roo-select2-search-choice-close fa fa-times',
14912 }, this.searchField);
14914 var close = choice.select('a.roo-select2-search-choice-close', true).first();
14916 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
14924 this.inputEl().dom.value = '';
14929 onRemoveItem : function(e, _self, o)
14931 e.preventDefault();
14933 this.lastItem = Roo.apply([], this.item);
14935 var index = this.item.indexOf(o.data) * 1;
14938 Roo.log('not this item?!');
14942 this.item.splice(index, 1);
14947 this.fireEvent('remove', this, e);
14953 syncValue : function()
14955 if(!this.item.length){
14962 Roo.each(this.item, function(i){
14963 if(_this.valueField){
14964 value.push(i[_this.valueField]);
14971 this.value = value.join(',');
14973 if(this.hiddenField){
14974 this.hiddenField.dom.value = this.value;
14977 this.store.fireEvent("datachanged", this.store);
14982 clearItem : function()
14984 if(!this.multiple){
14990 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
14998 if(this.tickable && !Roo.isTouch){
14999 this.view.refresh();
15003 inputEl: function ()
15005 if(Roo.isIOS && this.useNativeIOS){
15006 return this.el.select('select.roo-ios-select', true).first();
15009 if(Roo.isTouch && this.mobileTouchView){
15010 return this.el.select('input.form-control',true).first();
15014 return this.searchField;
15017 return this.el.select('input.form-control',true).first();
15020 onTickableFooterButtonClick : function(e, btn, el)
15022 e.preventDefault();
15024 this.lastItem = Roo.apply([], this.item);
15026 if(btn && btn.name == 'cancel'){
15027 this.tickItems = Roo.apply([], this.item);
15036 Roo.each(this.tickItems, function(o){
15044 validate : function()
15046 if(this.getVisibilityEl().hasClass('hidden')){
15050 var v = this.getRawValue();
15053 v = this.getValue();
15056 if(this.disabled || this.allowBlank || v.length){
15061 this.markInvalid();
15065 tickableInputEl : function()
15067 if(!this.tickable || !this.editable){
15068 return this.inputEl();
15071 return this.inputEl().select('.roo-select2-search-field-input', true).first();
15075 getAutoCreateTouchView : function()
15080 cls: 'form-group' //input-group
15086 type : this.inputType,
15087 cls : 'form-control x-combo-noedit',
15088 autocomplete: 'new-password',
15089 placeholder : this.placeholder || '',
15094 input.name = this.name;
15098 input.cls += ' input-' + this.size;
15101 if (this.disabled) {
15102 input.disabled = true;
15113 inputblock.cls += ' input-group';
15115 inputblock.cn.unshift({
15117 cls : 'input-group-addon input-group-prepend input-group-text',
15122 if(this.removable && !this.multiple){
15123 inputblock.cls += ' roo-removable';
15125 inputblock.cn.push({
15128 cls : 'roo-combo-removable-btn close'
15132 if(this.hasFeedback && !this.allowBlank){
15134 inputblock.cls += ' has-feedback';
15136 inputblock.cn.push({
15138 cls: 'glyphicon form-control-feedback'
15145 inputblock.cls += (this.before) ? '' : ' input-group';
15147 inputblock.cn.push({
15149 cls : 'input-group-addon input-group-append input-group-text',
15155 var ibwrap = inputblock;
15160 cls: 'roo-select2-choices',
15164 cls: 'roo-select2-search-field',
15177 cls: 'roo-select2-container input-group roo-touchview-combobox ',
15182 cls: 'form-hidden-field'
15188 if(!this.multiple && this.showToggleBtn){
15195 if (this.caret != false) {
15198 cls: 'fa fa-' + this.caret
15205 cls : 'input-group-addon input-group-append input-group-text btn dropdown-toggle',
15210 cls: 'combobox-clear',
15224 combobox.cls += ' roo-select2-container-multi';
15227 var align = this.labelAlign || this.parentLabelAlign();
15229 if (align ==='left' && this.fieldLabel.length) {
15234 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15235 tooltip : 'This field is required'
15239 cls : 'control-label col-form-label',
15240 html : this.fieldLabel
15251 var labelCfg = cfg.cn[1];
15252 var contentCfg = cfg.cn[2];
15255 if(this.indicatorpos == 'right'){
15260 cls : 'control-label col-form-label',
15264 html : this.fieldLabel
15268 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15269 tooltip : 'This field is required'
15282 labelCfg = cfg.cn[0];
15283 contentCfg = cfg.cn[1];
15288 if(this.labelWidth > 12){
15289 labelCfg.style = "width: " + this.labelWidth + 'px';
15292 if(this.labelWidth < 13 && this.labelmd == 0){
15293 this.labelmd = this.labelWidth;
15296 if(this.labellg > 0){
15297 labelCfg.cls += ' col-lg-' + this.labellg;
15298 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
15301 if(this.labelmd > 0){
15302 labelCfg.cls += ' col-md-' + this.labelmd;
15303 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
15306 if(this.labelsm > 0){
15307 labelCfg.cls += ' col-sm-' + this.labelsm;
15308 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
15311 if(this.labelxs > 0){
15312 labelCfg.cls += ' col-xs-' + this.labelxs;
15313 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
15317 } else if ( this.fieldLabel.length) {
15321 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15322 tooltip : 'This field is required'
15326 cls : 'control-label',
15327 html : this.fieldLabel
15338 if(this.indicatorpos == 'right'){
15342 cls : 'control-label',
15343 html : this.fieldLabel,
15347 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15348 tooltip : 'This field is required'
15365 var settings = this;
15367 ['xs','sm','md','lg'].map(function(size){
15368 if (settings[size]) {
15369 cfg.cls += ' col-' + size + '-' + settings[size];
15376 initTouchView : function()
15378 this.renderTouchView();
15380 this.touchViewEl.on('scroll', function(){
15381 this.el.dom.scrollTop = 0;
15384 this.originalValue = this.getValue();
15386 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
15388 this.inputEl().on("click", this.showTouchView, this);
15389 if (this.triggerEl) {
15390 this.triggerEl.on("click", this.showTouchView, this);
15394 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
15395 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
15397 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
15399 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
15400 this.store.on('load', this.onTouchViewLoad, this);
15401 this.store.on('loadexception', this.onTouchViewLoadException, this);
15403 if(this.hiddenName){
15405 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
15407 this.hiddenField.dom.value =
15408 this.hiddenValue !== undefined ? this.hiddenValue :
15409 this.value !== undefined ? this.value : '';
15411 this.el.dom.removeAttribute('name');
15412 this.hiddenField.dom.setAttribute('name', this.hiddenName);
15416 this.choices = this.el.select('ul.roo-select2-choices', true).first();
15417 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
15420 if(this.removable && !this.multiple){
15421 var close = this.closeTriggerEl();
15423 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
15424 close.on('click', this.removeBtnClick, this, close);
15428 * fix the bug in Safari iOS8
15430 this.inputEl().on("focus", function(e){
15431 document.activeElement.blur();
15434 this._touchViewMask = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
15441 renderTouchView : function()
15443 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
15444 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15446 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
15447 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15449 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
15450 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15451 this.touchViewBodyEl.setStyle('overflow', 'auto');
15453 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
15454 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15456 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
15457 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15461 showTouchView : function()
15467 this.touchViewHeaderEl.hide();
15469 if(this.modalTitle.length){
15470 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
15471 this.touchViewHeaderEl.show();
15474 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
15475 this.touchViewEl.show();
15477 this.touchViewEl.select('.modal-dialog', true).first().setStyle({ margin : '0px', width : '100%'});
15479 //this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
15480 // Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15482 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15484 if(this.modalTitle.length){
15485 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15488 this.touchViewBodyEl.setHeight(bodyHeight);
15492 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
15494 this.touchViewEl.addClass('in');
15497 if(this._touchViewMask){
15498 Roo.get(document.body).addClass("x-body-masked");
15499 this._touchViewMask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15500 this._touchViewMask.setStyle('z-index', 10000);
15501 this._touchViewMask.addClass('show');
15504 this.doTouchViewQuery();
15508 hideTouchView : function()
15510 this.touchViewEl.removeClass('in');
15514 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
15516 this.touchViewEl.setStyle('display', 'none');
15519 if(this._touchViewMask){
15520 this._touchViewMask.removeClass('show');
15521 Roo.get(document.body).removeClass("x-body-masked");
15525 setTouchViewValue : function()
15532 Roo.each(this.tickItems, function(o){
15537 this.hideTouchView();
15540 doTouchViewQuery : function()
15549 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
15553 if(!this.alwaysQuery || this.mode == 'local'){
15554 this.onTouchViewLoad();
15561 onTouchViewBeforeLoad : function(combo,opts)
15567 onTouchViewLoad : function()
15569 if(this.store.getCount() < 1){
15570 this.onTouchViewEmptyResults();
15574 this.clearTouchView();
15576 var rawValue = this.getRawValue();
15578 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
15580 this.tickItems = [];
15582 this.store.data.each(function(d, rowIndex){
15583 var row = this.touchViewListGroup.createChild(template);
15585 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
15586 row.addClass(d.data.cls);
15589 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15592 html : d.data[this.displayField]
15595 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
15596 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
15599 row.removeClass('selected');
15600 if(!this.multiple && this.valueField &&
15601 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
15604 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15605 row.addClass('selected');
15608 if(this.multiple && this.valueField &&
15609 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
15613 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15614 this.tickItems.push(d.data);
15617 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
15621 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
15623 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15625 if(this.modalTitle.length){
15626 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15629 var listHeight = this.touchViewListGroup.getHeight() + this.touchViewBodyEl.getPadding('tb') * 2;
15631 if(this.mobile_restrict_height && listHeight < bodyHeight){
15632 this.touchViewBodyEl.setHeight(listHeight);
15637 if(firstChecked && listHeight > bodyHeight){
15638 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
15643 onTouchViewLoadException : function()
15645 this.hideTouchView();
15648 onTouchViewEmptyResults : function()
15650 this.clearTouchView();
15652 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
15654 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
15658 clearTouchView : function()
15660 this.touchViewListGroup.dom.innerHTML = '';
15663 onTouchViewClick : function(e, el, o)
15665 e.preventDefault();
15668 var rowIndex = o.rowIndex;
15670 var r = this.store.getAt(rowIndex);
15672 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
15674 if(!this.multiple){
15675 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
15676 c.dom.removeAttribute('checked');
15679 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15681 this.setFromData(r.data);
15683 var close = this.closeTriggerEl();
15689 this.hideTouchView();
15691 this.fireEvent('select', this, r, rowIndex);
15696 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
15697 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
15698 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
15702 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15703 this.addItem(r.data);
15704 this.tickItems.push(r.data);
15708 getAutoCreateNativeIOS : function()
15711 cls: 'form-group' //input-group,
15716 cls : 'roo-ios-select'
15720 combobox.name = this.name;
15723 if (this.disabled) {
15724 combobox.disabled = true;
15727 var settings = this;
15729 ['xs','sm','md','lg'].map(function(size){
15730 if (settings[size]) {
15731 cfg.cls += ' col-' + size + '-' + settings[size];
15741 initIOSView : function()
15743 this.store.on('load', this.onIOSViewLoad, this);
15748 onIOSViewLoad : function()
15750 if(this.store.getCount() < 1){
15754 this.clearIOSView();
15756 if(this.allowBlank) {
15758 var default_text = '-- SELECT --';
15760 if(this.placeholder.length){
15761 default_text = this.placeholder;
15764 if(this.emptyTitle.length){
15765 default_text += ' - ' + this.emptyTitle + ' -';
15768 var opt = this.inputEl().createChild({
15771 html : default_text
15775 o[this.valueField] = 0;
15776 o[this.displayField] = default_text;
15778 this.ios_options.push({
15785 this.store.data.each(function(d, rowIndex){
15789 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15790 html = d.data[this.displayField];
15795 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
15796 value = d.data[this.valueField];
15805 if(this.value == d.data[this.valueField]){
15806 option['selected'] = true;
15809 var opt = this.inputEl().createChild(option);
15811 this.ios_options.push({
15818 this.inputEl().on('change', function(){
15819 this.fireEvent('select', this);
15824 clearIOSView: function()
15826 this.inputEl().dom.innerHTML = '';
15828 this.ios_options = [];
15831 setIOSValue: function(v)
15835 if(!this.ios_options){
15839 Roo.each(this.ios_options, function(opts){
15841 opts.el.dom.removeAttribute('selected');
15843 if(opts.data[this.valueField] != v){
15847 opts.el.dom.setAttribute('selected', true);
15853 * @cfg {Boolean} grow
15857 * @cfg {Number} growMin
15861 * @cfg {Number} growMax
15870 Roo.apply(Roo.bootstrap.ComboBox, {
15874 cls: 'modal-header',
15896 cls: 'list-group-item',
15900 cls: 'roo-combobox-list-group-item-value'
15904 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
15918 listItemCheckbox : {
15920 cls: 'list-group-item',
15924 cls: 'roo-combobox-list-group-item-value'
15928 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
15944 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
15949 cls: 'modal-footer',
15957 cls: 'col-xs-6 text-left',
15960 cls: 'btn btn-danger roo-touch-view-cancel',
15966 cls: 'col-xs-6 text-right',
15969 cls: 'btn btn-success roo-touch-view-ok',
15980 Roo.apply(Roo.bootstrap.ComboBox, {
15982 touchViewTemplate : {
15984 cls: 'modal fade roo-combobox-touch-view',
15988 cls: 'modal-dialog',
15989 style : 'position:fixed', // we have to fix position....
15993 cls: 'modal-content',
15995 Roo.bootstrap.ComboBox.header,
15996 Roo.bootstrap.ComboBox.body,
15997 Roo.bootstrap.ComboBox.footer
16006 * Ext JS Library 1.1.1
16007 * Copyright(c) 2006-2007, Ext JS, LLC.
16009 * Originally Released Under LGPL - original licence link has changed is not relivant.
16012 * <script type="text/javascript">
16017 * @extends Roo.util.Observable
16018 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
16019 * This class also supports single and multi selection modes. <br>
16020 * Create a data model bound view:
16022 var store = new Roo.data.Store(...);
16024 var view = new Roo.View({
16026 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
16028 singleSelect: true,
16029 selectedClass: "ydataview-selected",
16033 // listen for node click?
16034 view.on("click", function(vw, index, node, e){
16035 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
16039 dataModel.load("foobar.xml");
16041 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
16043 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
16044 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
16046 * Note: old style constructor is still suported (container, template, config)
16049 * Create a new View
16050 * @param {Object} config The config object
16053 Roo.View = function(config, depreciated_tpl, depreciated_config){
16055 this.parent = false;
16057 if (typeof(depreciated_tpl) == 'undefined') {
16058 // new way.. - universal constructor.
16059 Roo.apply(this, config);
16060 this.el = Roo.get(this.el);
16063 this.el = Roo.get(config);
16064 this.tpl = depreciated_tpl;
16065 Roo.apply(this, depreciated_config);
16067 this.wrapEl = this.el.wrap().wrap();
16068 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
16071 if(typeof(this.tpl) == "string"){
16072 this.tpl = new Roo.Template(this.tpl);
16074 // support xtype ctors..
16075 this.tpl = new Roo.factory(this.tpl, Roo);
16079 this.tpl.compile();
16084 * @event beforeclick
16085 * Fires before a click is processed. Returns false to cancel the default action.
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
16091 "beforeclick" : true,
16094 * Fires when a template node is 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
16103 * Fires when a template node is double clicked.
16104 * @param {Roo.View} this
16105 * @param {Number} index The index of the target node
16106 * @param {HTMLElement} node The target node
16107 * @param {Roo.EventObject} e The raw event object
16111 * @event contextmenu
16112 * Fires when a template node is right clicked.
16113 * @param {Roo.View} this
16114 * @param {Number} index The index of the target node
16115 * @param {HTMLElement} node The target node
16116 * @param {Roo.EventObject} e The raw event object
16118 "contextmenu" : true,
16120 * @event selectionchange
16121 * Fires when the selected nodes change.
16122 * @param {Roo.View} this
16123 * @param {Array} selections Array of the selected nodes
16125 "selectionchange" : true,
16128 * @event beforeselect
16129 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
16130 * @param {Roo.View} this
16131 * @param {HTMLElement} node The node to be selected
16132 * @param {Array} selections Array of currently selected nodes
16134 "beforeselect" : true,
16136 * @event preparedata
16137 * Fires on every row to render, to allow you to change the data.
16138 * @param {Roo.View} this
16139 * @param {Object} data to be rendered (change this)
16141 "preparedata" : true
16149 "click": this.onClick,
16150 "dblclick": this.onDblClick,
16151 "contextmenu": this.onContextMenu,
16155 this.selections = [];
16157 this.cmp = new Roo.CompositeElementLite([]);
16159 this.store = Roo.factory(this.store, Roo.data);
16160 this.setStore(this.store, true);
16163 if ( this.footer && this.footer.xtype) {
16165 var fctr = this.wrapEl.appendChild(document.createElement("div"));
16167 this.footer.dataSource = this.store;
16168 this.footer.container = fctr;
16169 this.footer = Roo.factory(this.footer, Roo);
16170 fctr.insertFirst(this.el);
16172 // this is a bit insane - as the paging toolbar seems to detach the el..
16173 // dom.parentNode.parentNode.parentNode
16174 // they get detached?
16178 Roo.View.superclass.constructor.call(this);
16183 Roo.extend(Roo.View, Roo.util.Observable, {
16186 * @cfg {Roo.data.Store} store Data store to load data from.
16191 * @cfg {String|Roo.Element} el The container element.
16196 * @cfg {String|Roo.Template} tpl The template used by this View
16200 * @cfg {String} dataName the named area of the template to use as the data area
16201 * Works with domtemplates roo-name="name"
16205 * @cfg {String} selectedClass The css class to add to selected nodes
16207 selectedClass : "x-view-selected",
16209 * @cfg {String} emptyText The empty text to show when nothing is loaded.
16214 * @cfg {String} text to display on mask (default Loading)
16218 * @cfg {Boolean} multiSelect Allow multiple selection
16220 multiSelect : false,
16222 * @cfg {Boolean} singleSelect Allow single selection
16224 singleSelect: false,
16227 * @cfg {Boolean} toggleSelect - selecting
16229 toggleSelect : false,
16232 * @cfg {Boolean} tickable - selecting
16237 * Returns the element this view is bound to.
16238 * @return {Roo.Element}
16240 getEl : function(){
16241 return this.wrapEl;
16247 * Refreshes the view. - called by datachanged on the store. - do not call directly.
16249 refresh : function(){
16250 //Roo.log('refresh');
16253 // if we are using something like 'domtemplate', then
16254 // the what gets used is:
16255 // t.applySubtemplate(NAME, data, wrapping data..)
16256 // the outer template then get' applied with
16257 // the store 'extra data'
16258 // and the body get's added to the
16259 // roo-name="data" node?
16260 // <span class='roo-tpl-{name}'></span> ?????
16264 this.clearSelections();
16265 this.el.update("");
16267 var records = this.store.getRange();
16268 if(records.length < 1) {
16270 // is this valid?? = should it render a template??
16272 this.el.update(this.emptyText);
16276 if (this.dataName) {
16277 this.el.update(t.apply(this.store.meta)); //????
16278 el = this.el.child('.roo-tpl-' + this.dataName);
16281 for(var i = 0, len = records.length; i < len; i++){
16282 var data = this.prepareData(records[i].data, i, records[i]);
16283 this.fireEvent("preparedata", this, data, i, records[i]);
16285 var d = Roo.apply({}, data);
16288 Roo.apply(d, {'roo-id' : Roo.id()});
16292 Roo.each(this.parent.item, function(item){
16293 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
16296 Roo.apply(d, {'roo-data-checked' : 'checked'});
16300 html[html.length] = Roo.util.Format.trim(
16302 t.applySubtemplate(this.dataName, d, this.store.meta) :
16309 el.update(html.join(""));
16310 this.nodes = el.dom.childNodes;
16311 this.updateIndexes(0);
16316 * Function to override to reformat the data that is sent to
16317 * the template for each node.
16318 * DEPRICATED - use the preparedata event handler.
16319 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
16320 * a JSON object for an UpdateManager bound view).
16322 prepareData : function(data, index, record)
16324 this.fireEvent("preparedata", this, data, index, record);
16328 onUpdate : function(ds, record){
16329 // Roo.log('on update');
16330 this.clearSelections();
16331 var index = this.store.indexOf(record);
16332 var n = this.nodes[index];
16333 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
16334 n.parentNode.removeChild(n);
16335 this.updateIndexes(index, index);
16341 onAdd : function(ds, records, index)
16343 //Roo.log(['on Add', ds, records, index] );
16344 this.clearSelections();
16345 if(this.nodes.length == 0){
16349 var n = this.nodes[index];
16350 for(var i = 0, len = records.length; i < len; i++){
16351 var d = this.prepareData(records[i].data, i, records[i]);
16353 this.tpl.insertBefore(n, d);
16356 this.tpl.append(this.el, d);
16359 this.updateIndexes(index);
16362 onRemove : function(ds, record, index){
16363 // Roo.log('onRemove');
16364 this.clearSelections();
16365 var el = this.dataName ?
16366 this.el.child('.roo-tpl-' + this.dataName) :
16369 el.dom.removeChild(this.nodes[index]);
16370 this.updateIndexes(index);
16374 * Refresh an individual node.
16375 * @param {Number} index
16377 refreshNode : function(index){
16378 this.onUpdate(this.store, this.store.getAt(index));
16381 updateIndexes : function(startIndex, endIndex){
16382 var ns = this.nodes;
16383 startIndex = startIndex || 0;
16384 endIndex = endIndex || ns.length - 1;
16385 for(var i = startIndex; i <= endIndex; i++){
16386 ns[i].nodeIndex = i;
16391 * Changes the data store this view uses and refresh the view.
16392 * @param {Store} store
16394 setStore : function(store, initial){
16395 if(!initial && this.store){
16396 this.store.un("datachanged", this.refresh);
16397 this.store.un("add", this.onAdd);
16398 this.store.un("remove", this.onRemove);
16399 this.store.un("update", this.onUpdate);
16400 this.store.un("clear", this.refresh);
16401 this.store.un("beforeload", this.onBeforeLoad);
16402 this.store.un("load", this.onLoad);
16403 this.store.un("loadexception", this.onLoad);
16407 store.on("datachanged", this.refresh, this);
16408 store.on("add", this.onAdd, this);
16409 store.on("remove", this.onRemove, this);
16410 store.on("update", this.onUpdate, this);
16411 store.on("clear", this.refresh, this);
16412 store.on("beforeload", this.onBeforeLoad, this);
16413 store.on("load", this.onLoad, this);
16414 store.on("loadexception", this.onLoad, this);
16422 * onbeforeLoad - masks the loading area.
16425 onBeforeLoad : function(store,opts)
16427 //Roo.log('onBeforeLoad');
16429 this.el.update("");
16431 this.el.mask(this.mask ? this.mask : "Loading" );
16433 onLoad : function ()
16440 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
16441 * @param {HTMLElement} node
16442 * @return {HTMLElement} The template node
16444 findItemFromChild : function(node){
16445 var el = this.dataName ?
16446 this.el.child('.roo-tpl-' + this.dataName,true) :
16449 if(!node || node.parentNode == el){
16452 var p = node.parentNode;
16453 while(p && p != el){
16454 if(p.parentNode == el){
16463 onClick : function(e){
16464 var item = this.findItemFromChild(e.getTarget());
16466 var index = this.indexOf(item);
16467 if(this.onItemClick(item, index, e) !== false){
16468 this.fireEvent("click", this, index, item, e);
16471 this.clearSelections();
16476 onContextMenu : function(e){
16477 var item = this.findItemFromChild(e.getTarget());
16479 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
16484 onDblClick : function(e){
16485 var item = this.findItemFromChild(e.getTarget());
16487 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
16491 onItemClick : function(item, index, e)
16493 if(this.fireEvent("beforeclick", this, index, item, e) === false){
16496 if (this.toggleSelect) {
16497 var m = this.isSelected(item) ? 'unselect' : 'select';
16500 _t[m](item, true, false);
16503 if(this.multiSelect || this.singleSelect){
16504 if(this.multiSelect && e.shiftKey && this.lastSelection){
16505 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
16507 this.select(item, this.multiSelect && e.ctrlKey);
16508 this.lastSelection = item;
16511 if(!this.tickable){
16512 e.preventDefault();
16520 * Get the number of selected nodes.
16523 getSelectionCount : function(){
16524 return this.selections.length;
16528 * Get the currently selected nodes.
16529 * @return {Array} An array of HTMLElements
16531 getSelectedNodes : function(){
16532 return this.selections;
16536 * Get the indexes of the selected nodes.
16539 getSelectedIndexes : function(){
16540 var indexes = [], s = this.selections;
16541 for(var i = 0, len = s.length; i < len; i++){
16542 indexes.push(s[i].nodeIndex);
16548 * Clear all selections
16549 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
16551 clearSelections : function(suppressEvent){
16552 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
16553 this.cmp.elements = this.selections;
16554 this.cmp.removeClass(this.selectedClass);
16555 this.selections = [];
16556 if(!suppressEvent){
16557 this.fireEvent("selectionchange", this, this.selections);
16563 * Returns true if the passed node is selected
16564 * @param {HTMLElement/Number} node The node or node index
16565 * @return {Boolean}
16567 isSelected : function(node){
16568 var s = this.selections;
16572 node = this.getNode(node);
16573 return s.indexOf(node) !== -1;
16578 * @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
16579 * @param {Boolean} keepExisting (optional) true to keep existing selections
16580 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16582 select : function(nodeInfo, keepExisting, suppressEvent){
16583 if(nodeInfo instanceof Array){
16585 this.clearSelections(true);
16587 for(var i = 0, len = nodeInfo.length; i < len; i++){
16588 this.select(nodeInfo[i], true, true);
16592 var node = this.getNode(nodeInfo);
16593 if(!node || this.isSelected(node)){
16594 return; // already selected.
16597 this.clearSelections(true);
16600 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
16601 Roo.fly(node).addClass(this.selectedClass);
16602 this.selections.push(node);
16603 if(!suppressEvent){
16604 this.fireEvent("selectionchange", this, this.selections);
16612 * @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
16613 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
16614 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16616 unselect : function(nodeInfo, keepExisting, suppressEvent)
16618 if(nodeInfo instanceof Array){
16619 Roo.each(this.selections, function(s) {
16620 this.unselect(s, nodeInfo);
16624 var node = this.getNode(nodeInfo);
16625 if(!node || !this.isSelected(node)){
16626 //Roo.log("not selected");
16627 return; // not selected.
16631 Roo.each(this.selections, function(s) {
16633 Roo.fly(node).removeClass(this.selectedClass);
16640 this.selections= ns;
16641 this.fireEvent("selectionchange", this, this.selections);
16645 * Gets a template node.
16646 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16647 * @return {HTMLElement} The node or null if it wasn't found
16649 getNode : function(nodeInfo){
16650 if(typeof nodeInfo == "string"){
16651 return document.getElementById(nodeInfo);
16652 }else if(typeof nodeInfo == "number"){
16653 return this.nodes[nodeInfo];
16659 * Gets a range template nodes.
16660 * @param {Number} startIndex
16661 * @param {Number} endIndex
16662 * @return {Array} An array of nodes
16664 getNodes : function(start, end){
16665 var ns = this.nodes;
16666 start = start || 0;
16667 end = typeof end == "undefined" ? ns.length - 1 : end;
16670 for(var i = start; i <= end; i++){
16674 for(var i = start; i >= end; i--){
16682 * Finds the index of the passed node
16683 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16684 * @return {Number} The index of the node or -1
16686 indexOf : function(node){
16687 node = this.getNode(node);
16688 if(typeof node.nodeIndex == "number"){
16689 return node.nodeIndex;
16691 var ns = this.nodes;
16692 for(var i = 0, len = ns.length; i < len; i++){
16703 * based on jquery fullcalendar
16707 Roo.bootstrap = Roo.bootstrap || {};
16709 * @class Roo.bootstrap.Calendar
16710 * @extends Roo.bootstrap.Component
16711 * Bootstrap Calendar class
16712 * @cfg {Boolean} loadMask (true|false) default false
16713 * @cfg {Object} header generate the user specific header of the calendar, default false
16716 * Create a new Container
16717 * @param {Object} config The config object
16722 Roo.bootstrap.Calendar = function(config){
16723 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
16727 * Fires when a date is selected
16728 * @param {DatePicker} this
16729 * @param {Date} date The selected date
16733 * @event monthchange
16734 * Fires when the displayed month changes
16735 * @param {DatePicker} this
16736 * @param {Date} date The selected month
16738 'monthchange': true,
16740 * @event evententer
16741 * Fires when mouse over an event
16742 * @param {Calendar} this
16743 * @param {event} Event
16745 'evententer': true,
16747 * @event eventleave
16748 * Fires when the mouse leaves an
16749 * @param {Calendar} this
16752 'eventleave': true,
16754 * @event eventclick
16755 * Fires when the mouse click an
16756 * @param {Calendar} this
16765 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
16768 * @cfg {Number} startDay
16769 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16777 getAutoCreate : function(){
16780 var fc_button = function(name, corner, style, content ) {
16781 return Roo.apply({},{
16783 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
16785 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
16788 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
16799 style : 'width:100%',
16806 cls : 'fc-header-left',
16808 fc_button('prev', 'left', 'arrow', '‹' ),
16809 fc_button('next', 'right', 'arrow', '›' ),
16810 { tag: 'span', cls: 'fc-header-space' },
16811 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
16819 cls : 'fc-header-center',
16823 cls: 'fc-header-title',
16826 html : 'month / year'
16834 cls : 'fc-header-right',
16836 /* fc_button('month', 'left', '', 'month' ),
16837 fc_button('week', '', '', 'week' ),
16838 fc_button('day', 'right', '', 'day' )
16850 header = this.header;
16853 var cal_heads = function() {
16855 // fixme - handle this.
16857 for (var i =0; i < Date.dayNames.length; i++) {
16858 var d = Date.dayNames[i];
16861 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
16862 html : d.substring(0,3)
16866 ret[0].cls += ' fc-first';
16867 ret[6].cls += ' fc-last';
16870 var cal_cell = function(n) {
16873 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
16878 cls: 'fc-day-number',
16882 cls: 'fc-day-content',
16886 style: 'position: relative;' // height: 17px;
16898 var cal_rows = function() {
16901 for (var r = 0; r < 6; r++) {
16908 for (var i =0; i < Date.dayNames.length; i++) {
16909 var d = Date.dayNames[i];
16910 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
16913 row.cn[0].cls+=' fc-first';
16914 row.cn[0].cn[0].style = 'min-height:90px';
16915 row.cn[6].cls+=' fc-last';
16919 ret[0].cls += ' fc-first';
16920 ret[4].cls += ' fc-prev-last';
16921 ret[5].cls += ' fc-last';
16928 cls: 'fc-border-separate',
16929 style : 'width:100%',
16937 cls : 'fc-first fc-last',
16955 cls : 'fc-content',
16956 style : "position: relative;",
16959 cls : 'fc-view fc-view-month fc-grid',
16960 style : 'position: relative',
16961 unselectable : 'on',
16964 cls : 'fc-event-container',
16965 style : 'position:absolute;z-index:8;top:0;left:0;'
16983 initEvents : function()
16986 throw "can not find store for calendar";
16992 style: "text-align:center",
16996 style: "background-color:white;width:50%;margin:250 auto",
17000 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
17011 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
17013 var size = this.el.select('.fc-content', true).first().getSize();
17014 this.maskEl.setSize(size.width, size.height);
17015 this.maskEl.enableDisplayMode("block");
17016 if(!this.loadMask){
17017 this.maskEl.hide();
17020 this.store = Roo.factory(this.store, Roo.data);
17021 this.store.on('load', this.onLoad, this);
17022 this.store.on('beforeload', this.onBeforeLoad, this);
17026 this.cells = this.el.select('.fc-day',true);
17027 //Roo.log(this.cells);
17028 this.textNodes = this.el.query('.fc-day-number');
17029 this.cells.addClassOnOver('fc-state-hover');
17031 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
17032 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
17033 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
17034 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
17036 this.on('monthchange', this.onMonthChange, this);
17038 this.update(new Date().clearTime());
17041 resize : function() {
17042 var sz = this.el.getSize();
17044 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
17045 this.el.select('.fc-day-content div',true).setHeight(34);
17050 showPrevMonth : function(e){
17051 this.update(this.activeDate.add("mo", -1));
17053 showToday : function(e){
17054 this.update(new Date().clearTime());
17057 showNextMonth : function(e){
17058 this.update(this.activeDate.add("mo", 1));
17062 showPrevYear : function(){
17063 this.update(this.activeDate.add("y", -1));
17067 showNextYear : function(){
17068 this.update(this.activeDate.add("y", 1));
17073 update : function(date)
17075 var vd = this.activeDate;
17076 this.activeDate = date;
17077 // if(vd && this.el){
17078 // var t = date.getTime();
17079 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
17080 // Roo.log('using add remove');
17082 // this.fireEvent('monthchange', this, date);
17084 // this.cells.removeClass("fc-state-highlight");
17085 // this.cells.each(function(c){
17086 // if(c.dateValue == t){
17087 // c.addClass("fc-state-highlight");
17088 // setTimeout(function(){
17089 // try{c.dom.firstChild.focus();}catch(e){}
17099 var days = date.getDaysInMonth();
17101 var firstOfMonth = date.getFirstDateOfMonth();
17102 var startingPos = firstOfMonth.getDay()-this.startDay;
17104 if(startingPos < this.startDay){
17108 var pm = date.add(Date.MONTH, -1);
17109 var prevStart = pm.getDaysInMonth()-startingPos;
17111 this.cells = this.el.select('.fc-day',true);
17112 this.textNodes = this.el.query('.fc-day-number');
17113 this.cells.addClassOnOver('fc-state-hover');
17115 var cells = this.cells.elements;
17116 var textEls = this.textNodes;
17118 Roo.each(cells, function(cell){
17119 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
17122 days += startingPos;
17124 // convert everything to numbers so it's fast
17125 var day = 86400000;
17126 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
17129 //Roo.log(prevStart);
17131 var today = new Date().clearTime().getTime();
17132 var sel = date.clearTime().getTime();
17133 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
17134 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
17135 var ddMatch = this.disabledDatesRE;
17136 var ddText = this.disabledDatesText;
17137 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
17138 var ddaysText = this.disabledDaysText;
17139 var format = this.format;
17141 var setCellClass = function(cal, cell){
17145 //Roo.log('set Cell Class');
17147 var t = d.getTime();
17151 cell.dateValue = t;
17153 cell.className += " fc-today";
17154 cell.className += " fc-state-highlight";
17155 cell.title = cal.todayText;
17158 // disable highlight in other month..
17159 //cell.className += " fc-state-highlight";
17164 cell.className = " fc-state-disabled";
17165 cell.title = cal.minText;
17169 cell.className = " fc-state-disabled";
17170 cell.title = cal.maxText;
17174 if(ddays.indexOf(d.getDay()) != -1){
17175 cell.title = ddaysText;
17176 cell.className = " fc-state-disabled";
17179 if(ddMatch && format){
17180 var fvalue = d.dateFormat(format);
17181 if(ddMatch.test(fvalue)){
17182 cell.title = ddText.replace("%0", fvalue);
17183 cell.className = " fc-state-disabled";
17187 if (!cell.initialClassName) {
17188 cell.initialClassName = cell.dom.className;
17191 cell.dom.className = cell.initialClassName + ' ' + cell.className;
17196 for(; i < startingPos; i++) {
17197 textEls[i].innerHTML = (++prevStart);
17198 d.setDate(d.getDate()+1);
17200 cells[i].className = "fc-past fc-other-month";
17201 setCellClass(this, cells[i]);
17206 for(; i < days; i++){
17207 intDay = i - startingPos + 1;
17208 textEls[i].innerHTML = (intDay);
17209 d.setDate(d.getDate()+1);
17211 cells[i].className = ''; // "x-date-active";
17212 setCellClass(this, cells[i]);
17216 for(; i < 42; i++) {
17217 textEls[i].innerHTML = (++extraDays);
17218 d.setDate(d.getDate()+1);
17220 cells[i].className = "fc-future fc-other-month";
17221 setCellClass(this, cells[i]);
17224 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
17226 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
17228 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
17229 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
17231 if(totalRows != 6){
17232 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
17233 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
17236 this.fireEvent('monthchange', this, date);
17240 if(!this.internalRender){
17241 var main = this.el.dom.firstChild;
17242 var w = main.offsetWidth;
17243 this.el.setWidth(w + this.el.getBorderWidth("lr"));
17244 Roo.fly(main).setWidth(w);
17245 this.internalRender = true;
17246 // opera does not respect the auto grow header center column
17247 // then, after it gets a width opera refuses to recalculate
17248 // without a second pass
17249 if(Roo.isOpera && !this.secondPass){
17250 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
17251 this.secondPass = true;
17252 this.update.defer(10, this, [date]);
17259 findCell : function(dt) {
17260 dt = dt.clearTime().getTime();
17262 this.cells.each(function(c){
17263 //Roo.log("check " +c.dateValue + '?=' + dt);
17264 if(c.dateValue == dt){
17274 findCells : function(ev) {
17275 var s = ev.start.clone().clearTime().getTime();
17277 var e= ev.end.clone().clearTime().getTime();
17280 this.cells.each(function(c){
17281 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
17283 if(c.dateValue > e){
17286 if(c.dateValue < s){
17295 // findBestRow: function(cells)
17299 // for (var i =0 ; i < cells.length;i++) {
17300 // ret = Math.max(cells[i].rows || 0,ret);
17307 addItem : function(ev)
17309 // look for vertical location slot in
17310 var cells = this.findCells(ev);
17312 // ev.row = this.findBestRow(cells);
17314 // work out the location.
17318 for(var i =0; i < cells.length; i++) {
17320 cells[i].row = cells[0].row;
17323 cells[i].row = cells[i].row + 1;
17333 if (crow.start.getY() == cells[i].getY()) {
17335 crow.end = cells[i];
17352 cells[0].events.push(ev);
17354 this.calevents.push(ev);
17357 clearEvents: function() {
17359 if(!this.calevents){
17363 Roo.each(this.cells.elements, function(c){
17369 Roo.each(this.calevents, function(e) {
17370 Roo.each(e.els, function(el) {
17371 el.un('mouseenter' ,this.onEventEnter, this);
17372 el.un('mouseleave' ,this.onEventLeave, this);
17377 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
17383 renderEvents: function()
17387 this.cells.each(function(c) {
17396 if(c.row != c.events.length){
17397 r = 4 - (4 - (c.row - c.events.length));
17400 c.events = ev.slice(0, r);
17401 c.more = ev.slice(r);
17403 if(c.more.length && c.more.length == 1){
17404 c.events.push(c.more.pop());
17407 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
17411 this.cells.each(function(c) {
17413 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
17416 for (var e = 0; e < c.events.length; e++){
17417 var ev = c.events[e];
17418 var rows = ev.rows;
17420 for(var i = 0; i < rows.length; i++) {
17422 // how many rows should it span..
17425 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
17426 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
17428 unselectable : "on",
17431 cls: 'fc-event-inner',
17435 // cls: 'fc-event-time',
17436 // html : cells.length > 1 ? '' : ev.time
17440 cls: 'fc-event-title',
17441 html : String.format('{0}', ev.title)
17448 cls: 'ui-resizable-handle ui-resizable-e',
17449 html : '  '
17456 cfg.cls += ' fc-event-start';
17458 if ((i+1) == rows.length) {
17459 cfg.cls += ' fc-event-end';
17462 var ctr = _this.el.select('.fc-event-container',true).first();
17463 var cg = ctr.createChild(cfg);
17465 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
17466 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
17468 var r = (c.more.length) ? 1 : 0;
17469 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
17470 cg.setWidth(ebox.right - sbox.x -2);
17472 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
17473 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
17474 cg.on('click', _this.onEventClick, _this, ev);
17485 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
17486 style : 'position: absolute',
17487 unselectable : "on",
17490 cls: 'fc-event-inner',
17494 cls: 'fc-event-title',
17502 cls: 'ui-resizable-handle ui-resizable-e',
17503 html : '  '
17509 var ctr = _this.el.select('.fc-event-container',true).first();
17510 var cg = ctr.createChild(cfg);
17512 var sbox = c.select('.fc-day-content',true).first().getBox();
17513 var ebox = c.select('.fc-day-content',true).first().getBox();
17515 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
17516 cg.setWidth(ebox.right - sbox.x -2);
17518 cg.on('click', _this.onMoreEventClick, _this, c.more);
17528 onEventEnter: function (e, el,event,d) {
17529 this.fireEvent('evententer', this, el, event);
17532 onEventLeave: function (e, el,event,d) {
17533 this.fireEvent('eventleave', this, el, event);
17536 onEventClick: function (e, el,event,d) {
17537 this.fireEvent('eventclick', this, el, event);
17540 onMonthChange: function () {
17544 onMoreEventClick: function(e, el, more)
17548 this.calpopover.placement = 'right';
17549 this.calpopover.setTitle('More');
17551 this.calpopover.setContent('');
17553 var ctr = this.calpopover.el.select('.popover-content', true).first();
17555 Roo.each(more, function(m){
17557 cls : 'fc-event-hori fc-event-draggable',
17560 var cg = ctr.createChild(cfg);
17562 cg.on('click', _this.onEventClick, _this, m);
17565 this.calpopover.show(el);
17570 onLoad: function ()
17572 this.calevents = [];
17575 if(this.store.getCount() > 0){
17576 this.store.data.each(function(d){
17579 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
17580 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
17581 time : d.data.start_time,
17582 title : d.data.title,
17583 description : d.data.description,
17584 venue : d.data.venue
17589 this.renderEvents();
17591 if(this.calevents.length && this.loadMask){
17592 this.maskEl.hide();
17596 onBeforeLoad: function()
17598 this.clearEvents();
17600 this.maskEl.show();
17614 * @class Roo.bootstrap.Popover
17615 * @extends Roo.bootstrap.Component
17616 * Bootstrap Popover class
17617 * @cfg {String} html contents of the popover (or false to use children..)
17618 * @cfg {String} title of popover (or false to hide)
17619 * @cfg {String} placement how it is placed
17620 * @cfg {String} trigger click || hover (or false to trigger manually)
17621 * @cfg {String} over what (parent or false to trigger manually.)
17622 * @cfg {Number} delay - delay before showing
17625 * Create a new Popover
17626 * @param {Object} config The config object
17629 Roo.bootstrap.Popover = function(config){
17630 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
17636 * After the popover show
17638 * @param {Roo.bootstrap.Popover} this
17643 * After the popover hide
17645 * @param {Roo.bootstrap.Popover} this
17651 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
17653 title: 'Fill in a title',
17656 placement : 'right',
17657 trigger : 'hover', // hover
17663 can_build_overlaid : false,
17665 getChildContainer : function()
17667 return this.el.select('.popover-content',true).first();
17670 getAutoCreate : function(){
17673 cls : 'popover roo-dynamic',
17674 style: 'display:block',
17680 cls : 'popover-inner',
17684 cls: 'popover-title popover-header',
17688 cls : 'popover-content popover-body',
17699 setTitle: function(str)
17702 this.el.select('.popover-title',true).first().dom.innerHTML = str;
17704 setContent: function(str)
17707 this.el.select('.popover-content',true).first().dom.innerHTML = str;
17709 // as it get's added to the bottom of the page.
17710 onRender : function(ct, position)
17712 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17714 var cfg = Roo.apply({}, this.getAutoCreate());
17718 cfg.cls += ' ' + this.cls;
17721 cfg.style = this.style;
17723 //Roo.log("adding to ");
17724 this.el = Roo.get(document.body).createChild(cfg, position);
17725 // Roo.log(this.el);
17730 initEvents : function()
17732 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
17733 this.el.enableDisplayMode('block');
17735 if (this.over === false) {
17738 if (this.triggers === false) {
17741 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17742 var triggers = this.trigger ? this.trigger.split(' ') : [];
17743 Roo.each(triggers, function(trigger) {
17745 if (trigger == 'click') {
17746 on_el.on('click', this.toggle, this);
17747 } else if (trigger != 'manual') {
17748 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
17749 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
17751 on_el.on(eventIn ,this.enter, this);
17752 on_el.on(eventOut, this.leave, this);
17763 toggle : function () {
17764 this.hoverState == 'in' ? this.leave() : this.enter();
17767 enter : function () {
17769 clearTimeout(this.timeout);
17771 this.hoverState = 'in';
17773 if (!this.delay || !this.delay.show) {
17778 this.timeout = setTimeout(function () {
17779 if (_t.hoverState == 'in') {
17782 }, this.delay.show)
17785 leave : function() {
17786 clearTimeout(this.timeout);
17788 this.hoverState = 'out';
17790 if (!this.delay || !this.delay.hide) {
17795 this.timeout = setTimeout(function () {
17796 if (_t.hoverState == 'out') {
17799 }, this.delay.hide)
17802 show : function (on_el)
17805 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17809 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
17810 if (this.html !== false) {
17811 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
17813 this.el.removeClass([
17814 'fade','top','bottom', 'left', 'right','in',
17815 'bs-popover-top','bs-popover-bottom', 'bs-popover-left', 'bs-popover-right'
17817 if (!this.title.length) {
17818 this.el.select('.popover-title',true).hide();
17821 var placement = typeof this.placement == 'function' ?
17822 this.placement.call(this, this.el, on_el) :
17825 var autoToken = /\s?auto?\s?/i;
17826 var autoPlace = autoToken.test(placement);
17828 placement = placement.replace(autoToken, '') || 'top';
17832 //this.el.setXY([0,0]);
17834 this.el.dom.style.display='block';
17835 this.el.addClass(placement);
17837 //this.el.appendTo(on_el);
17839 var p = this.getPosition();
17840 var box = this.el.getBox();
17845 var align = Roo.bootstrap.Popover.alignment[placement];
17848 this.el.alignTo(on_el, align[0],align[1]);
17849 //var arrow = this.el.select('.arrow',true).first();
17850 //arrow.set(align[2],
17852 this.el.addClass('in');
17855 if (this.el.hasClass('fade')) {
17859 this.hoverState = 'in';
17861 this.fireEvent('show', this);
17866 this.el.setXY([0,0]);
17867 this.el.removeClass('in');
17869 this.hoverState = null;
17871 this.fireEvent('hide', this);
17876 Roo.bootstrap.Popover.alignment = {
17877 'left' : ['r-l', [-10,0], 'right bs-popover-right'],
17878 'right' : ['l-r', [10,0], 'left bs-popover-left'],
17879 'bottom' : ['t-b', [0,10], 'top bs-popover-top'],
17880 'top' : [ 'b-t', [0,-10], 'bottom bs-popover-bottom']
17891 * @class Roo.bootstrap.Progress
17892 * @extends Roo.bootstrap.Component
17893 * Bootstrap Progress class
17894 * @cfg {Boolean} striped striped of the progress bar
17895 * @cfg {Boolean} active animated of the progress bar
17899 * Create a new Progress
17900 * @param {Object} config The config object
17903 Roo.bootstrap.Progress = function(config){
17904 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
17907 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
17912 getAutoCreate : function(){
17920 cfg.cls += ' progress-striped';
17924 cfg.cls += ' active';
17943 * @class Roo.bootstrap.ProgressBar
17944 * @extends Roo.bootstrap.Component
17945 * Bootstrap ProgressBar class
17946 * @cfg {Number} aria_valuenow aria-value now
17947 * @cfg {Number} aria_valuemin aria-value min
17948 * @cfg {Number} aria_valuemax aria-value max
17949 * @cfg {String} label label for the progress bar
17950 * @cfg {String} panel (success | info | warning | danger )
17951 * @cfg {String} role role of the progress bar
17952 * @cfg {String} sr_only text
17956 * Create a new ProgressBar
17957 * @param {Object} config The config object
17960 Roo.bootstrap.ProgressBar = function(config){
17961 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
17964 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
17968 aria_valuemax : 100,
17974 getAutoCreate : function()
17979 cls: 'progress-bar',
17980 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
17992 cfg.role = this.role;
17995 if(this.aria_valuenow){
17996 cfg['aria-valuenow'] = this.aria_valuenow;
17999 if(this.aria_valuemin){
18000 cfg['aria-valuemin'] = this.aria_valuemin;
18003 if(this.aria_valuemax){
18004 cfg['aria-valuemax'] = this.aria_valuemax;
18007 if(this.label && !this.sr_only){
18008 cfg.html = this.label;
18012 cfg.cls += ' progress-bar-' + this.panel;
18018 update : function(aria_valuenow)
18020 this.aria_valuenow = aria_valuenow;
18022 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
18037 * @class Roo.bootstrap.TabGroup
18038 * @extends Roo.bootstrap.Column
18039 * Bootstrap Column class
18040 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
18041 * @cfg {Boolean} carousel true to make the group behave like a carousel
18042 * @cfg {Boolean} bullets show bullets for the panels
18043 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
18044 * @cfg {Number} timer auto slide timer .. default 0 millisecond
18045 * @cfg {Boolean} showarrow (true|false) show arrow default true
18048 * Create a new TabGroup
18049 * @param {Object} config The config object
18052 Roo.bootstrap.TabGroup = function(config){
18053 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
18055 this.navId = Roo.id();
18058 Roo.bootstrap.TabGroup.register(this);
18062 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
18065 transition : false,
18070 slideOnTouch : false,
18073 getAutoCreate : function()
18075 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
18077 cfg.cls += ' tab-content';
18079 if (this.carousel) {
18080 cfg.cls += ' carousel slide';
18083 cls : 'carousel-inner',
18087 if(this.bullets && !Roo.isTouch){
18090 cls : 'carousel-bullets',
18094 if(this.bullets_cls){
18095 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
18102 cfg.cn[0].cn.push(bullets);
18105 if(this.showarrow){
18106 cfg.cn[0].cn.push({
18108 class : 'carousel-arrow',
18112 class : 'carousel-prev',
18116 class : 'fa fa-chevron-left'
18122 class : 'carousel-next',
18126 class : 'fa fa-chevron-right'
18139 initEvents: function()
18141 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
18142 // this.el.on("touchstart", this.onTouchStart, this);
18145 if(this.autoslide){
18148 this.slideFn = window.setInterval(function() {
18149 _this.showPanelNext();
18153 if(this.showarrow){
18154 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
18155 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
18161 // onTouchStart : function(e, el, o)
18163 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
18167 // this.showPanelNext();
18171 getChildContainer : function()
18173 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
18177 * register a Navigation item
18178 * @param {Roo.bootstrap.NavItem} the navitem to add
18180 register : function(item)
18182 this.tabs.push( item);
18183 item.navId = this.navId; // not really needed..
18188 getActivePanel : function()
18191 Roo.each(this.tabs, function(t) {
18201 getPanelByName : function(n)
18204 Roo.each(this.tabs, function(t) {
18205 if (t.tabId == n) {
18213 indexOfPanel : function(p)
18216 Roo.each(this.tabs, function(t,i) {
18217 if (t.tabId == p.tabId) {
18226 * show a specific panel
18227 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
18228 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
18230 showPanel : function (pan)
18232 if(this.transition || typeof(pan) == 'undefined'){
18233 Roo.log("waiting for the transitionend");
18237 if (typeof(pan) == 'number') {
18238 pan = this.tabs[pan];
18241 if (typeof(pan) == 'string') {
18242 pan = this.getPanelByName(pan);
18245 var cur = this.getActivePanel();
18248 Roo.log('pan or acitve pan is undefined');
18252 if (pan.tabId == this.getActivePanel().tabId) {
18256 if (false === cur.fireEvent('beforedeactivate')) {
18260 if(this.bullets > 0 && !Roo.isTouch){
18261 this.setActiveBullet(this.indexOfPanel(pan));
18264 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
18266 this.transition = true;
18267 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
18268 var lr = dir == 'next' ? 'left' : 'right';
18269 pan.el.addClass(dir); // or prev
18270 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
18271 cur.el.addClass(lr); // or right
18272 pan.el.addClass(lr);
18275 cur.el.on('transitionend', function() {
18276 Roo.log("trans end?");
18278 pan.el.removeClass([lr,dir]);
18279 pan.setActive(true);
18281 cur.el.removeClass([lr]);
18282 cur.setActive(false);
18284 _this.transition = false;
18286 }, this, { single: true } );
18291 cur.setActive(false);
18292 pan.setActive(true);
18297 showPanelNext : function()
18299 var i = this.indexOfPanel(this.getActivePanel());
18301 if (i >= this.tabs.length - 1 && !this.autoslide) {
18305 if (i >= this.tabs.length - 1 && this.autoslide) {
18309 this.showPanel(this.tabs[i+1]);
18312 showPanelPrev : function()
18314 var i = this.indexOfPanel(this.getActivePanel());
18316 if (i < 1 && !this.autoslide) {
18320 if (i < 1 && this.autoslide) {
18321 i = this.tabs.length;
18324 this.showPanel(this.tabs[i-1]);
18328 addBullet: function()
18330 if(!this.bullets || Roo.isTouch){
18333 var ctr = this.el.select('.carousel-bullets',true).first();
18334 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
18335 var bullet = ctr.createChild({
18336 cls : 'bullet bullet-' + i
18337 },ctr.dom.lastChild);
18342 bullet.on('click', (function(e, el, o, ii, t){
18344 e.preventDefault();
18346 this.showPanel(ii);
18348 if(this.autoslide && this.slideFn){
18349 clearInterval(this.slideFn);
18350 this.slideFn = window.setInterval(function() {
18351 _this.showPanelNext();
18355 }).createDelegate(this, [i, bullet], true));
18360 setActiveBullet : function(i)
18366 Roo.each(this.el.select('.bullet', true).elements, function(el){
18367 el.removeClass('selected');
18370 var bullet = this.el.select('.bullet-' + i, true).first();
18376 bullet.addClass('selected');
18387 Roo.apply(Roo.bootstrap.TabGroup, {
18391 * register a Navigation Group
18392 * @param {Roo.bootstrap.NavGroup} the navgroup to add
18394 register : function(navgrp)
18396 this.groups[navgrp.navId] = navgrp;
18400 * fetch a Navigation Group based on the navigation ID
18401 * if one does not exist , it will get created.
18402 * @param {string} the navgroup to add
18403 * @returns {Roo.bootstrap.NavGroup} the navgroup
18405 get: function(navId) {
18406 if (typeof(this.groups[navId]) == 'undefined') {
18407 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
18409 return this.groups[navId] ;
18424 * @class Roo.bootstrap.TabPanel
18425 * @extends Roo.bootstrap.Component
18426 * Bootstrap TabPanel class
18427 * @cfg {Boolean} active panel active
18428 * @cfg {String} html panel content
18429 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
18430 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
18431 * @cfg {String} href click to link..
18435 * Create a new TabPanel
18436 * @param {Object} config The config object
18439 Roo.bootstrap.TabPanel = function(config){
18440 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
18444 * Fires when the active status changes
18445 * @param {Roo.bootstrap.TabPanel} this
18446 * @param {Boolean} state the new state
18451 * @event beforedeactivate
18452 * Fires before a tab is de-activated - can be used to do validation on a form.
18453 * @param {Roo.bootstrap.TabPanel} this
18454 * @return {Boolean} false if there is an error
18457 'beforedeactivate': true
18460 this.tabId = this.tabId || Roo.id();
18464 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
18472 getAutoCreate : function(){
18475 // item is needed for carousel - not sure if it has any effect otherwise
18476 cls: 'tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
18477 html: this.html || ''
18481 cfg.cls += ' active';
18485 cfg.tabId = this.tabId;
18492 initEvents: function()
18494 var p = this.parent();
18496 this.navId = this.navId || p.navId;
18498 if (typeof(this.navId) != 'undefined') {
18499 // not really needed.. but just in case.. parent should be a NavGroup.
18500 var tg = Roo.bootstrap.TabGroup.get(this.navId);
18504 var i = tg.tabs.length - 1;
18506 if(this.active && tg.bullets > 0 && i < tg.bullets){
18507 tg.setActiveBullet(i);
18511 this.el.on('click', this.onClick, this);
18514 this.el.on("touchstart", this.onTouchStart, this);
18515 this.el.on("touchmove", this.onTouchMove, this);
18516 this.el.on("touchend", this.onTouchEnd, this);
18521 onRender : function(ct, position)
18523 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
18526 setActive : function(state)
18528 Roo.log("panel - set active " + this.tabId + "=" + state);
18530 this.active = state;
18532 this.el.removeClass('active');
18534 } else if (!this.el.hasClass('active')) {
18535 this.el.addClass('active');
18538 this.fireEvent('changed', this, state);
18541 onClick : function(e)
18543 e.preventDefault();
18545 if(!this.href.length){
18549 window.location.href = this.href;
18558 onTouchStart : function(e)
18560 this.swiping = false;
18562 this.startX = e.browserEvent.touches[0].clientX;
18563 this.startY = e.browserEvent.touches[0].clientY;
18566 onTouchMove : function(e)
18568 this.swiping = true;
18570 this.endX = e.browserEvent.touches[0].clientX;
18571 this.endY = e.browserEvent.touches[0].clientY;
18574 onTouchEnd : function(e)
18581 var tabGroup = this.parent();
18583 if(this.endX > this.startX){ // swiping right
18584 tabGroup.showPanelPrev();
18588 if(this.startX > this.endX){ // swiping left
18589 tabGroup.showPanelNext();
18608 * @class Roo.bootstrap.DateField
18609 * @extends Roo.bootstrap.Input
18610 * Bootstrap DateField class
18611 * @cfg {Number} weekStart default 0
18612 * @cfg {String} viewMode default empty, (months|years)
18613 * @cfg {String} minViewMode default empty, (months|years)
18614 * @cfg {Number} startDate default -Infinity
18615 * @cfg {Number} endDate default Infinity
18616 * @cfg {Boolean} todayHighlight default false
18617 * @cfg {Boolean} todayBtn default false
18618 * @cfg {Boolean} calendarWeeks default false
18619 * @cfg {Object} daysOfWeekDisabled default empty
18620 * @cfg {Boolean} singleMode default false (true | false)
18622 * @cfg {Boolean} keyboardNavigation default true
18623 * @cfg {String} language default en
18626 * Create a new DateField
18627 * @param {Object} config The config object
18630 Roo.bootstrap.DateField = function(config){
18631 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
18635 * Fires when this field show.
18636 * @param {Roo.bootstrap.DateField} this
18637 * @param {Mixed} date The date value
18642 * Fires when this field hide.
18643 * @param {Roo.bootstrap.DateField} this
18644 * @param {Mixed} date The date value
18649 * Fires when select a date.
18650 * @param {Roo.bootstrap.DateField} this
18651 * @param {Mixed} date The date value
18655 * @event beforeselect
18656 * Fires when before select a date.
18657 * @param {Roo.bootstrap.DateField} this
18658 * @param {Mixed} date The date value
18660 beforeselect : true
18664 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
18667 * @cfg {String} format
18668 * The default date format string which can be overriden for localization support. The format must be
18669 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
18673 * @cfg {String} altFormats
18674 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
18675 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
18677 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
18685 todayHighlight : false,
18691 keyboardNavigation: true,
18693 calendarWeeks: false,
18695 startDate: -Infinity,
18699 daysOfWeekDisabled: [],
18703 singleMode : false,
18705 UTCDate: function()
18707 return new Date(Date.UTC.apply(Date, arguments));
18710 UTCToday: function()
18712 var today = new Date();
18713 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
18716 getDate: function() {
18717 var d = this.getUTCDate();
18718 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
18721 getUTCDate: function() {
18725 setDate: function(d) {
18726 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
18729 setUTCDate: function(d) {
18731 this.setValue(this.formatDate(this.date));
18734 onRender: function(ct, position)
18737 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
18739 this.language = this.language || 'en';
18740 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
18741 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
18743 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
18744 this.format = this.format || 'm/d/y';
18745 this.isInline = false;
18746 this.isInput = true;
18747 this.component = this.el.select('.add-on', true).first() || false;
18748 this.component = (this.component && this.component.length === 0) ? false : this.component;
18749 this.hasInput = this.component && this.inputEl().length;
18751 if (typeof(this.minViewMode === 'string')) {
18752 switch (this.minViewMode) {
18754 this.minViewMode = 1;
18757 this.minViewMode = 2;
18760 this.minViewMode = 0;
18765 if (typeof(this.viewMode === 'string')) {
18766 switch (this.viewMode) {
18779 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
18781 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
18783 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18785 this.picker().on('mousedown', this.onMousedown, this);
18786 this.picker().on('click', this.onClick, this);
18788 this.picker().addClass('datepicker-dropdown');
18790 this.startViewMode = this.viewMode;
18792 if(this.singleMode){
18793 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
18794 v.setVisibilityMode(Roo.Element.DISPLAY);
18798 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
18799 v.setStyle('width', '189px');
18803 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
18804 if(!this.calendarWeeks){
18809 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18810 v.attr('colspan', function(i, val){
18811 return parseInt(val) + 1;
18816 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
18818 this.setStartDate(this.startDate);
18819 this.setEndDate(this.endDate);
18821 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
18828 if(this.isInline) {
18833 picker : function()
18835 return this.pickerEl;
18836 // return this.el.select('.datepicker', true).first();
18839 fillDow: function()
18841 var dowCnt = this.weekStart;
18850 if(this.calendarWeeks){
18858 while (dowCnt < this.weekStart + 7) {
18862 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
18866 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
18869 fillMonths: function()
18872 var months = this.picker().select('>.datepicker-months td', true).first();
18874 months.dom.innerHTML = '';
18880 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
18883 months.createChild(month);
18890 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;
18892 if (this.date < this.startDate) {
18893 this.viewDate = new Date(this.startDate);
18894 } else if (this.date > this.endDate) {
18895 this.viewDate = new Date(this.endDate);
18897 this.viewDate = new Date(this.date);
18905 var d = new Date(this.viewDate),
18906 year = d.getUTCFullYear(),
18907 month = d.getUTCMonth(),
18908 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
18909 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
18910 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
18911 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
18912 currentDate = this.date && this.date.valueOf(),
18913 today = this.UTCToday();
18915 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
18917 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18919 // this.picker.select('>tfoot th.today').
18920 // .text(dates[this.language].today)
18921 // .toggle(this.todayBtn !== false);
18923 this.updateNavArrows();
18926 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
18928 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
18930 prevMonth.setUTCDate(day);
18932 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
18934 var nextMonth = new Date(prevMonth);
18936 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
18938 nextMonth = nextMonth.valueOf();
18940 var fillMonths = false;
18942 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
18944 while(prevMonth.valueOf() <= nextMonth) {
18947 if (prevMonth.getUTCDay() === this.weekStart) {
18949 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
18957 if(this.calendarWeeks){
18958 // ISO 8601: First week contains first thursday.
18959 // ISO also states week starts on Monday, but we can be more abstract here.
18961 // Start of current week: based on weekstart/current date
18962 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
18963 // Thursday of this week
18964 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
18965 // First Thursday of year, year from thursday
18966 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
18967 // Calendar week: ms between thursdays, div ms per day, div 7 days
18968 calWeek = (th - yth) / 864e5 / 7 + 1;
18970 fillMonths.cn.push({
18978 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
18980 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
18983 if (this.todayHighlight &&
18984 prevMonth.getUTCFullYear() == today.getFullYear() &&
18985 prevMonth.getUTCMonth() == today.getMonth() &&
18986 prevMonth.getUTCDate() == today.getDate()) {
18987 clsName += ' today';
18990 if (currentDate && prevMonth.valueOf() === currentDate) {
18991 clsName += ' active';
18994 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
18995 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
18996 clsName += ' disabled';
18999 fillMonths.cn.push({
19001 cls: 'day ' + clsName,
19002 html: prevMonth.getDate()
19005 prevMonth.setDate(prevMonth.getDate()+1);
19008 var currentYear = this.date && this.date.getUTCFullYear();
19009 var currentMonth = this.date && this.date.getUTCMonth();
19011 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
19013 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
19014 v.removeClass('active');
19016 if(currentYear === year && k === currentMonth){
19017 v.addClass('active');
19020 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
19021 v.addClass('disabled');
19027 year = parseInt(year/10, 10) * 10;
19029 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
19031 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
19034 for (var i = -1; i < 11; i++) {
19035 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
19037 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
19045 showMode: function(dir)
19048 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
19051 Roo.each(this.picker().select('>div',true).elements, function(v){
19052 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19055 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
19060 if(this.isInline) {
19064 this.picker().removeClass(['bottom', 'top']);
19066 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
19068 * place to the top of element!
19072 this.picker().addClass('top');
19073 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
19078 this.picker().addClass('bottom');
19080 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
19083 parseDate : function(value)
19085 if(!value || value instanceof Date){
19088 var v = Date.parseDate(value, this.format);
19089 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
19090 v = Date.parseDate(value, 'Y-m-d');
19092 if(!v && this.altFormats){
19093 if(!this.altFormatsArray){
19094 this.altFormatsArray = this.altFormats.split("|");
19096 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
19097 v = Date.parseDate(value, this.altFormatsArray[i]);
19103 formatDate : function(date, fmt)
19105 return (!date || !(date instanceof Date)) ?
19106 date : date.dateFormat(fmt || this.format);
19109 onFocus : function()
19111 Roo.bootstrap.DateField.superclass.onFocus.call(this);
19115 onBlur : function()
19117 Roo.bootstrap.DateField.superclass.onBlur.call(this);
19119 var d = this.inputEl().getValue();
19126 showPopup : function()
19128 this.picker().show();
19132 this.fireEvent('showpopup', this, this.date);
19135 hidePopup : function()
19137 if(this.isInline) {
19140 this.picker().hide();
19141 this.viewMode = this.startViewMode;
19144 this.fireEvent('hidepopup', this, this.date);
19148 onMousedown: function(e)
19150 e.stopPropagation();
19151 e.preventDefault();
19156 Roo.bootstrap.DateField.superclass.keyup.call(this);
19160 setValue: function(v)
19162 if(this.fireEvent('beforeselect', this, v) !== false){
19163 var d = new Date(this.parseDate(v) ).clearTime();
19165 if(isNaN(d.getTime())){
19166 this.date = this.viewDate = '';
19167 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
19171 v = this.formatDate(d);
19173 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
19175 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
19179 this.fireEvent('select', this, this.date);
19183 getValue: function()
19185 return this.formatDate(this.date);
19188 fireKey: function(e)
19190 if (!this.picker().isVisible()){
19191 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19197 var dateChanged = false,
19199 newDate, newViewDate;
19204 e.preventDefault();
19208 if (!this.keyboardNavigation) {
19211 dir = e.keyCode == 37 ? -1 : 1;
19214 newDate = this.moveYear(this.date, dir);
19215 newViewDate = this.moveYear(this.viewDate, dir);
19216 } else if (e.shiftKey){
19217 newDate = this.moveMonth(this.date, dir);
19218 newViewDate = this.moveMonth(this.viewDate, dir);
19220 newDate = new Date(this.date);
19221 newDate.setUTCDate(this.date.getUTCDate() + dir);
19222 newViewDate = new Date(this.viewDate);
19223 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
19225 if (this.dateWithinRange(newDate)){
19226 this.date = newDate;
19227 this.viewDate = newViewDate;
19228 this.setValue(this.formatDate(this.date));
19230 e.preventDefault();
19231 dateChanged = true;
19236 if (!this.keyboardNavigation) {
19239 dir = e.keyCode == 38 ? -1 : 1;
19241 newDate = this.moveYear(this.date, dir);
19242 newViewDate = this.moveYear(this.viewDate, dir);
19243 } else if (e.shiftKey){
19244 newDate = this.moveMonth(this.date, dir);
19245 newViewDate = this.moveMonth(this.viewDate, dir);
19247 newDate = new Date(this.date);
19248 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
19249 newViewDate = new Date(this.viewDate);
19250 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
19252 if (this.dateWithinRange(newDate)){
19253 this.date = newDate;
19254 this.viewDate = newViewDate;
19255 this.setValue(this.formatDate(this.date));
19257 e.preventDefault();
19258 dateChanged = true;
19262 this.setValue(this.formatDate(this.date));
19264 e.preventDefault();
19267 this.setValue(this.formatDate(this.date));
19281 onClick: function(e)
19283 e.stopPropagation();
19284 e.preventDefault();
19286 var target = e.getTarget();
19288 if(target.nodeName.toLowerCase() === 'i'){
19289 target = Roo.get(target).dom.parentNode;
19292 var nodeName = target.nodeName;
19293 var className = target.className;
19294 var html = target.innerHTML;
19295 //Roo.log(nodeName);
19297 switch(nodeName.toLowerCase()) {
19299 switch(className) {
19305 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
19306 switch(this.viewMode){
19308 this.viewDate = this.moveMonth(this.viewDate, dir);
19312 this.viewDate = this.moveYear(this.viewDate, dir);
19318 var date = new Date();
19319 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
19321 this.setValue(this.formatDate(this.date));
19328 if (className.indexOf('disabled') < 0) {
19329 this.viewDate.setUTCDate(1);
19330 if (className.indexOf('month') > -1) {
19331 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
19333 var year = parseInt(html, 10) || 0;
19334 this.viewDate.setUTCFullYear(year);
19338 if(this.singleMode){
19339 this.setValue(this.formatDate(this.viewDate));
19350 //Roo.log(className);
19351 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
19352 var day = parseInt(html, 10) || 1;
19353 var year = this.viewDate.getUTCFullYear(),
19354 month = this.viewDate.getUTCMonth();
19356 if (className.indexOf('old') > -1) {
19363 } else if (className.indexOf('new') > -1) {
19371 //Roo.log([year,month,day]);
19372 this.date = this.UTCDate(year, month, day,0,0,0,0);
19373 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
19375 //Roo.log(this.formatDate(this.date));
19376 this.setValue(this.formatDate(this.date));
19383 setStartDate: function(startDate)
19385 this.startDate = startDate || -Infinity;
19386 if (this.startDate !== -Infinity) {
19387 this.startDate = this.parseDate(this.startDate);
19390 this.updateNavArrows();
19393 setEndDate: function(endDate)
19395 this.endDate = endDate || Infinity;
19396 if (this.endDate !== Infinity) {
19397 this.endDate = this.parseDate(this.endDate);
19400 this.updateNavArrows();
19403 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
19405 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
19406 if (typeof(this.daysOfWeekDisabled) !== 'object') {
19407 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
19409 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
19410 return parseInt(d, 10);
19413 this.updateNavArrows();
19416 updateNavArrows: function()
19418 if(this.singleMode){
19422 var d = new Date(this.viewDate),
19423 year = d.getUTCFullYear(),
19424 month = d.getUTCMonth();
19426 Roo.each(this.picker().select('.prev', true).elements, function(v){
19428 switch (this.viewMode) {
19431 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
19437 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
19444 Roo.each(this.picker().select('.next', true).elements, function(v){
19446 switch (this.viewMode) {
19449 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
19455 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
19463 moveMonth: function(date, dir)
19468 var new_date = new Date(date.valueOf()),
19469 day = new_date.getUTCDate(),
19470 month = new_date.getUTCMonth(),
19471 mag = Math.abs(dir),
19473 dir = dir > 0 ? 1 : -1;
19476 // If going back one month, make sure month is not current month
19477 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
19479 return new_date.getUTCMonth() == month;
19481 // If going forward one month, make sure month is as expected
19482 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
19484 return new_date.getUTCMonth() != new_month;
19486 new_month = month + dir;
19487 new_date.setUTCMonth(new_month);
19488 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
19489 if (new_month < 0 || new_month > 11) {
19490 new_month = (new_month + 12) % 12;
19493 // For magnitudes >1, move one month at a time...
19494 for (var i=0; i<mag; i++) {
19495 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
19496 new_date = this.moveMonth(new_date, dir);
19498 // ...then reset the day, keeping it in the new month
19499 new_month = new_date.getUTCMonth();
19500 new_date.setUTCDate(day);
19502 return new_month != new_date.getUTCMonth();
19505 // Common date-resetting loop -- if date is beyond end of month, make it
19508 new_date.setUTCDate(--day);
19509 new_date.setUTCMonth(new_month);
19514 moveYear: function(date, dir)
19516 return this.moveMonth(date, dir*12);
19519 dateWithinRange: function(date)
19521 return date >= this.startDate && date <= this.endDate;
19527 this.picker().remove();
19530 validateValue : function(value)
19532 if(this.getVisibilityEl().hasClass('hidden')){
19536 if(value.length < 1) {
19537 if(this.allowBlank){
19543 if(value.length < this.minLength){
19546 if(value.length > this.maxLength){
19550 var vt = Roo.form.VTypes;
19551 if(!vt[this.vtype](value, this)){
19555 if(typeof this.validator == "function"){
19556 var msg = this.validator(value);
19562 if(this.regex && !this.regex.test(value)){
19566 if(typeof(this.parseDate(value)) == 'undefined'){
19570 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
19574 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
19584 this.date = this.viewDate = '';
19586 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
19591 Roo.apply(Roo.bootstrap.DateField, {
19602 html: '<i class="fa fa-arrow-left"/>'
19612 html: '<i class="fa fa-arrow-right"/>'
19654 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
19655 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
19656 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
19657 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19658 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
19671 navFnc: 'FullYear',
19676 navFnc: 'FullYear',
19681 Roo.apply(Roo.bootstrap.DateField, {
19685 cls: 'datepicker dropdown-menu roo-dynamic',
19689 cls: 'datepicker-days',
19693 cls: 'table-condensed',
19695 Roo.bootstrap.DateField.head,
19699 Roo.bootstrap.DateField.footer
19706 cls: 'datepicker-months',
19710 cls: 'table-condensed',
19712 Roo.bootstrap.DateField.head,
19713 Roo.bootstrap.DateField.content,
19714 Roo.bootstrap.DateField.footer
19721 cls: 'datepicker-years',
19725 cls: 'table-condensed',
19727 Roo.bootstrap.DateField.head,
19728 Roo.bootstrap.DateField.content,
19729 Roo.bootstrap.DateField.footer
19748 * @class Roo.bootstrap.TimeField
19749 * @extends Roo.bootstrap.Input
19750 * Bootstrap DateField class
19754 * Create a new TimeField
19755 * @param {Object} config The config object
19758 Roo.bootstrap.TimeField = function(config){
19759 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
19763 * Fires when this field show.
19764 * @param {Roo.bootstrap.DateField} thisthis
19765 * @param {Mixed} date The date value
19770 * Fires when this field hide.
19771 * @param {Roo.bootstrap.DateField} this
19772 * @param {Mixed} date The date value
19777 * Fires when select a date.
19778 * @param {Roo.bootstrap.DateField} this
19779 * @param {Mixed} date The date value
19785 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
19788 * @cfg {String} format
19789 * The default time format string which can be overriden for localization support. The format must be
19790 * valid according to {@link Date#parseDate} (defaults to 'H:i').
19794 onRender: function(ct, position)
19797 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
19799 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
19801 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19803 this.pop = this.picker().select('>.datepicker-time',true).first();
19804 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19806 this.picker().on('mousedown', this.onMousedown, this);
19807 this.picker().on('click', this.onClick, this);
19809 this.picker().addClass('datepicker-dropdown');
19814 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
19815 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
19816 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
19817 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
19818 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
19819 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
19823 fireKey: function(e){
19824 if (!this.picker().isVisible()){
19825 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19831 e.preventDefault();
19839 this.onTogglePeriod();
19842 this.onIncrementMinutes();
19845 this.onDecrementMinutes();
19854 onClick: function(e) {
19855 e.stopPropagation();
19856 e.preventDefault();
19859 picker : function()
19861 return this.el.select('.datepicker', true).first();
19864 fillTime: function()
19866 var time = this.pop.select('tbody', true).first();
19868 time.dom.innerHTML = '';
19883 cls: 'hours-up glyphicon glyphicon-chevron-up'
19903 cls: 'minutes-up glyphicon glyphicon-chevron-up'
19924 cls: 'timepicker-hour',
19939 cls: 'timepicker-minute',
19954 cls: 'btn btn-primary period',
19976 cls: 'hours-down glyphicon glyphicon-chevron-down'
19996 cls: 'minutes-down glyphicon glyphicon-chevron-down'
20014 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
20021 var hours = this.time.getHours();
20022 var minutes = this.time.getMinutes();
20035 hours = hours - 12;
20039 hours = '0' + hours;
20043 minutes = '0' + minutes;
20046 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
20047 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
20048 this.pop.select('button', true).first().dom.innerHTML = period;
20054 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
20056 var cls = ['bottom'];
20058 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
20065 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
20070 this.picker().addClass(cls.join('-'));
20074 Roo.each(cls, function(c){
20076 _this.picker().setTop(_this.inputEl().getHeight());
20080 _this.picker().setTop(0 - _this.picker().getHeight());
20085 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
20089 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
20096 onFocus : function()
20098 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
20102 onBlur : function()
20104 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
20110 this.picker().show();
20115 this.fireEvent('show', this, this.date);
20120 this.picker().hide();
20123 this.fireEvent('hide', this, this.date);
20126 setTime : function()
20129 this.setValue(this.time.format(this.format));
20131 this.fireEvent('select', this, this.date);
20136 onMousedown: function(e){
20137 e.stopPropagation();
20138 e.preventDefault();
20141 onIncrementHours: function()
20143 Roo.log('onIncrementHours');
20144 this.time = this.time.add(Date.HOUR, 1);
20149 onDecrementHours: function()
20151 Roo.log('onDecrementHours');
20152 this.time = this.time.add(Date.HOUR, -1);
20156 onIncrementMinutes: function()
20158 Roo.log('onIncrementMinutes');
20159 this.time = this.time.add(Date.MINUTE, 1);
20163 onDecrementMinutes: function()
20165 Roo.log('onDecrementMinutes');
20166 this.time = this.time.add(Date.MINUTE, -1);
20170 onTogglePeriod: function()
20172 Roo.log('onTogglePeriod');
20173 this.time = this.time.add(Date.HOUR, 12);
20180 Roo.apply(Roo.bootstrap.TimeField, {
20210 cls: 'btn btn-info ok',
20222 Roo.apply(Roo.bootstrap.TimeField, {
20226 cls: 'datepicker dropdown-menu',
20230 cls: 'datepicker-time',
20234 cls: 'table-condensed',
20236 Roo.bootstrap.TimeField.content,
20237 Roo.bootstrap.TimeField.footer
20256 * @class Roo.bootstrap.MonthField
20257 * @extends Roo.bootstrap.Input
20258 * Bootstrap MonthField class
20260 * @cfg {String} language default en
20263 * Create a new MonthField
20264 * @param {Object} config The config object
20267 Roo.bootstrap.MonthField = function(config){
20268 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
20273 * Fires when this field show.
20274 * @param {Roo.bootstrap.MonthField} this
20275 * @param {Mixed} date The date value
20280 * Fires when this field hide.
20281 * @param {Roo.bootstrap.MonthField} this
20282 * @param {Mixed} date The date value
20287 * Fires when select a date.
20288 * @param {Roo.bootstrap.MonthField} this
20289 * @param {String} oldvalue The old value
20290 * @param {String} newvalue The new value
20296 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
20298 onRender: function(ct, position)
20301 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
20303 this.language = this.language || 'en';
20304 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
20305 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
20307 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
20308 this.isInline = false;
20309 this.isInput = true;
20310 this.component = this.el.select('.add-on', true).first() || false;
20311 this.component = (this.component && this.component.length === 0) ? false : this.component;
20312 this.hasInput = this.component && this.inputEL().length;
20314 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
20316 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
20318 this.picker().on('mousedown', this.onMousedown, this);
20319 this.picker().on('click', this.onClick, this);
20321 this.picker().addClass('datepicker-dropdown');
20323 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
20324 v.setStyle('width', '189px');
20331 if(this.isInline) {
20337 setValue: function(v, suppressEvent)
20339 var o = this.getValue();
20341 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
20345 if(suppressEvent !== true){
20346 this.fireEvent('select', this, o, v);
20351 getValue: function()
20356 onClick: function(e)
20358 e.stopPropagation();
20359 e.preventDefault();
20361 var target = e.getTarget();
20363 if(target.nodeName.toLowerCase() === 'i'){
20364 target = Roo.get(target).dom.parentNode;
20367 var nodeName = target.nodeName;
20368 var className = target.className;
20369 var html = target.innerHTML;
20371 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
20375 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
20377 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20383 picker : function()
20385 return this.pickerEl;
20388 fillMonths: function()
20391 var months = this.picker().select('>.datepicker-months td', true).first();
20393 months.dom.innerHTML = '';
20399 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
20402 months.createChild(month);
20411 if(typeof(this.vIndex) == 'undefined' && this.value.length){
20412 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
20415 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
20416 e.removeClass('active');
20418 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
20419 e.addClass('active');
20426 if(this.isInline) {
20430 this.picker().removeClass(['bottom', 'top']);
20432 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
20434 * place to the top of element!
20438 this.picker().addClass('top');
20439 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
20444 this.picker().addClass('bottom');
20446 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
20449 onFocus : function()
20451 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
20455 onBlur : function()
20457 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
20459 var d = this.inputEl().getValue();
20468 this.picker().show();
20469 this.picker().select('>.datepicker-months', true).first().show();
20473 this.fireEvent('show', this, this.date);
20478 if(this.isInline) {
20481 this.picker().hide();
20482 this.fireEvent('hide', this, this.date);
20486 onMousedown: function(e)
20488 e.stopPropagation();
20489 e.preventDefault();
20494 Roo.bootstrap.MonthField.superclass.keyup.call(this);
20498 fireKey: function(e)
20500 if (!this.picker().isVisible()){
20501 if (e.keyCode == 27) {// allow escape to hide and re-show picker
20512 e.preventDefault();
20516 dir = e.keyCode == 37 ? -1 : 1;
20518 this.vIndex = this.vIndex + dir;
20520 if(this.vIndex < 0){
20524 if(this.vIndex > 11){
20528 if(isNaN(this.vIndex)){
20532 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20538 dir = e.keyCode == 38 ? -1 : 1;
20540 this.vIndex = this.vIndex + dir * 4;
20542 if(this.vIndex < 0){
20546 if(this.vIndex > 11){
20550 if(isNaN(this.vIndex)){
20554 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20559 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20560 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20564 e.preventDefault();
20567 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20568 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20584 this.picker().remove();
20589 Roo.apply(Roo.bootstrap.MonthField, {
20608 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
20609 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
20614 Roo.apply(Roo.bootstrap.MonthField, {
20618 cls: 'datepicker dropdown-menu roo-dynamic',
20622 cls: 'datepicker-months',
20626 cls: 'table-condensed',
20628 Roo.bootstrap.DateField.content
20648 * @class Roo.bootstrap.CheckBox
20649 * @extends Roo.bootstrap.Input
20650 * Bootstrap CheckBox class
20652 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
20653 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
20654 * @cfg {String} boxLabel The text that appears beside the checkbox
20655 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
20656 * @cfg {Boolean} checked initnal the element
20657 * @cfg {Boolean} inline inline the element (default false)
20658 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
20659 * @cfg {String} tooltip label tooltip
20662 * Create a new CheckBox
20663 * @param {Object} config The config object
20666 Roo.bootstrap.CheckBox = function(config){
20667 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
20672 * Fires when the element is checked or unchecked.
20673 * @param {Roo.bootstrap.CheckBox} this This input
20674 * @param {Boolean} checked The new checked value
20679 * Fires when the element is click.
20680 * @param {Roo.bootstrap.CheckBox} this This input
20687 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
20689 inputType: 'checkbox',
20698 getAutoCreate : function()
20700 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20706 cfg.cls = 'form-group ' + this.inputType; //input-group
20709 cfg.cls += ' ' + this.inputType + '-inline';
20715 type : this.inputType,
20716 value : this.inputValue,
20717 cls : 'roo-' + this.inputType, //'form-box',
20718 placeholder : this.placeholder || ''
20722 if(this.inputType != 'radio'){
20726 cls : 'roo-hidden-value',
20727 value : this.checked ? this.inputValue : this.valueOff
20732 if (this.weight) { // Validity check?
20733 cfg.cls += " " + this.inputType + "-" + this.weight;
20736 if (this.disabled) {
20737 input.disabled=true;
20741 input.checked = this.checked;
20746 input.name = this.name;
20748 if(this.inputType != 'radio'){
20749 hidden.name = this.name;
20750 input.name = '_hidden_' + this.name;
20755 input.cls += ' input-' + this.size;
20760 ['xs','sm','md','lg'].map(function(size){
20761 if (settings[size]) {
20762 cfg.cls += ' col-' + size + '-' + settings[size];
20766 var inputblock = input;
20768 if (this.before || this.after) {
20771 cls : 'input-group',
20776 inputblock.cn.push({
20778 cls : 'input-group-addon',
20783 inputblock.cn.push(input);
20785 if(this.inputType != 'radio'){
20786 inputblock.cn.push(hidden);
20790 inputblock.cn.push({
20792 cls : 'input-group-addon',
20799 if (align ==='left' && this.fieldLabel.length) {
20800 // Roo.log("left and has label");
20805 cls : 'control-label',
20806 html : this.fieldLabel
20816 if(this.labelWidth > 12){
20817 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
20820 if(this.labelWidth < 13 && this.labelmd == 0){
20821 this.labelmd = this.labelWidth;
20824 if(this.labellg > 0){
20825 cfg.cn[0].cls += ' col-lg-' + this.labellg;
20826 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
20829 if(this.labelmd > 0){
20830 cfg.cn[0].cls += ' col-md-' + this.labelmd;
20831 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
20834 if(this.labelsm > 0){
20835 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
20836 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
20839 if(this.labelxs > 0){
20840 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
20841 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
20844 } else if ( this.fieldLabel.length) {
20845 // Roo.log(" label");
20849 tag: this.boxLabel ? 'span' : 'label',
20851 cls: 'control-label box-input-label',
20852 //cls : 'input-group-addon',
20853 html : this.fieldLabel
20862 // Roo.log(" no label && no align");
20863 cfg.cn = [ inputblock ] ;
20869 var boxLabelCfg = {
20871 //'for': id, // box label is handled by onclick - so no for...
20873 html: this.boxLabel
20877 boxLabelCfg.tooltip = this.tooltip;
20880 cfg.cn.push(boxLabelCfg);
20883 if(this.inputType != 'radio'){
20884 cfg.cn.push(hidden);
20892 * return the real input element.
20894 inputEl: function ()
20896 return this.el.select('input.roo-' + this.inputType,true).first();
20898 hiddenEl: function ()
20900 return this.el.select('input.roo-hidden-value',true).first();
20903 labelEl: function()
20905 return this.el.select('label.control-label',true).first();
20907 /* depricated... */
20911 return this.labelEl();
20914 boxLabelEl: function()
20916 return this.el.select('label.box-label',true).first();
20919 initEvents : function()
20921 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
20923 this.inputEl().on('click', this.onClick, this);
20925 if (this.boxLabel) {
20926 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
20929 this.startValue = this.getValue();
20932 Roo.bootstrap.CheckBox.register(this);
20936 onClick : function(e)
20938 if(this.fireEvent('click', this, e) !== false){
20939 this.setChecked(!this.checked);
20944 setChecked : function(state,suppressEvent)
20946 this.startValue = this.getValue();
20948 if(this.inputType == 'radio'){
20950 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20951 e.dom.checked = false;
20954 this.inputEl().dom.checked = true;
20956 this.inputEl().dom.value = this.inputValue;
20958 if(suppressEvent !== true){
20959 this.fireEvent('check', this, true);
20967 this.checked = state;
20969 this.inputEl().dom.checked = state;
20972 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
20974 if(suppressEvent !== true){
20975 this.fireEvent('check', this, state);
20981 getValue : function()
20983 if(this.inputType == 'radio'){
20984 return this.getGroupValue();
20987 return this.hiddenEl().dom.value;
20991 getGroupValue : function()
20993 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
20997 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
21000 setValue : function(v,suppressEvent)
21002 if(this.inputType == 'radio'){
21003 this.setGroupValue(v, suppressEvent);
21007 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
21012 setGroupValue : function(v, suppressEvent)
21014 this.startValue = this.getValue();
21016 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21017 e.dom.checked = false;
21019 if(e.dom.value == v){
21020 e.dom.checked = true;
21024 if(suppressEvent !== true){
21025 this.fireEvent('check', this, true);
21033 validate : function()
21035 if(this.getVisibilityEl().hasClass('hidden')){
21041 (this.inputType == 'radio' && this.validateRadio()) ||
21042 (this.inputType == 'checkbox' && this.validateCheckbox())
21048 this.markInvalid();
21052 validateRadio : function()
21054 if(this.getVisibilityEl().hasClass('hidden')){
21058 if(this.allowBlank){
21064 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21065 if(!e.dom.checked){
21077 validateCheckbox : function()
21080 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
21081 //return (this.getValue() == this.inputValue) ? true : false;
21084 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21092 for(var i in group){
21093 if(group[i].el.isVisible(true)){
21101 for(var i in group){
21106 r = (group[i].getValue() == group[i].inputValue) ? true : false;
21113 * Mark this field as valid
21115 markValid : function()
21119 this.fireEvent('valid', this);
21121 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21124 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
21131 if(this.inputType == 'radio'){
21132 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21133 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
21134 e.findParent('.form-group', false, true).addClass(_this.validClass);
21141 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21142 this.el.findParent('.form-group', false, true).addClass(this.validClass);
21146 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21152 for(var i in group){
21153 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21154 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
21159 * Mark this field as invalid
21160 * @param {String} msg The validation message
21162 markInvalid : function(msg)
21164 if(this.allowBlank){
21170 this.fireEvent('invalid', this, msg);
21172 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21175 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
21179 label.markInvalid();
21182 if(this.inputType == 'radio'){
21183 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21184 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
21185 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
21192 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21193 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
21197 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21203 for(var i in group){
21204 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21205 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
21210 clearInvalid : function()
21212 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
21214 // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21216 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21218 if (label && label.iconEl) {
21219 label.iconEl.removeClass(label.validClass);
21220 label.iconEl.removeClass(label.invalidClass);
21224 disable : function()
21226 if(this.inputType != 'radio'){
21227 Roo.bootstrap.CheckBox.superclass.disable.call(this);
21234 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21235 _this.getActionEl().addClass(this.disabledClass);
21236 e.dom.disabled = true;
21240 this.disabled = true;
21241 this.fireEvent("disable", this);
21245 enable : function()
21247 if(this.inputType != 'radio'){
21248 Roo.bootstrap.CheckBox.superclass.enable.call(this);
21255 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21256 _this.getActionEl().removeClass(this.disabledClass);
21257 e.dom.disabled = false;
21261 this.disabled = false;
21262 this.fireEvent("enable", this);
21266 setBoxLabel : function(v)
21271 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21277 Roo.apply(Roo.bootstrap.CheckBox, {
21282 * register a CheckBox Group
21283 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
21285 register : function(checkbox)
21287 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
21288 this.groups[checkbox.groupId] = {};
21291 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
21295 this.groups[checkbox.groupId][checkbox.name] = checkbox;
21299 * fetch a CheckBox Group based on the group ID
21300 * @param {string} the group ID
21301 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
21303 get: function(groupId) {
21304 if (typeof(this.groups[groupId]) == 'undefined') {
21308 return this.groups[groupId] ;
21321 * @class Roo.bootstrap.Radio
21322 * @extends Roo.bootstrap.Component
21323 * Bootstrap Radio class
21324 * @cfg {String} boxLabel - the label associated
21325 * @cfg {String} value - the value of radio
21328 * Create a new Radio
21329 * @param {Object} config The config object
21331 Roo.bootstrap.Radio = function(config){
21332 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
21336 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
21342 getAutoCreate : function()
21346 cls : 'form-group radio',
21351 html : this.boxLabel
21359 initEvents : function()
21361 this.parent().register(this);
21363 this.el.on('click', this.onClick, this);
21367 onClick : function(e)
21369 if(this.parent().fireEvent('click', this.parent(), this, e) !== false){
21370 this.setChecked(true);
21374 setChecked : function(state, suppressEvent)
21376 this.parent().setValue(this.value, suppressEvent);
21380 setBoxLabel : function(v)
21385 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21400 * @class Roo.bootstrap.SecurePass
21401 * @extends Roo.bootstrap.Input
21402 * Bootstrap SecurePass class
21406 * Create a new SecurePass
21407 * @param {Object} config The config object
21410 Roo.bootstrap.SecurePass = function (config) {
21411 // these go here, so the translation tool can replace them..
21413 PwdEmpty: "Please type a password, and then retype it to confirm.",
21414 PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21415 PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21416 PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21417 IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21418 FNInPwd: "Your password can't contain your first name. Please type a different password.",
21419 LNInPwd: "Your password can't contain your last name. Please type a different password.",
21420 TooWeak: "Your password is Too Weak."
21422 this.meterLabel = "Password strength:";
21423 this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
21424 this.meterClass = [
21425 "roo-password-meter-tooweak",
21426 "roo-password-meter-weak",
21427 "roo-password-meter-medium",
21428 "roo-password-meter-strong",
21429 "roo-password-meter-grey"
21434 Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
21437 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
21439 * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
21441 * PwdEmpty: "Please type a password, and then retype it to confirm.",
21442 * PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21443 * PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21444 * PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21445 * IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21446 * FNInPwd: "Your password can't contain your first name. Please type a different password.",
21447 * LNInPwd: "Your password can't contain your last name. Please type a different password."
21457 * @cfg {String/Object} Label for the strength meter (defaults to
21458 * 'Password strength:')
21463 * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
21464 * ['Weak', 'Medium', 'Strong'])
21467 pwdStrengths: false,
21480 initEvents: function ()
21482 Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
21484 if (this.el.is('input[type=password]') && Roo.isSafari) {
21485 this.el.on('keydown', this.SafariOnKeyDown, this);
21488 this.el.on('keyup', this.checkStrength, this, {buffer: 50});
21491 onRender: function (ct, position)
21493 Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
21494 this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
21495 this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
21497 this.trigger.createChild({
21502 cls: 'roo-password-meter-grey col-xs-12',
21505 //width: this.meterWidth + 'px'
21509 cls: 'roo-password-meter-text'
21515 if (this.hideTrigger) {
21516 this.trigger.setDisplayed(false);
21518 this.setSize(this.width || '', this.height || '');
21521 onDestroy: function ()
21523 if (this.trigger) {
21524 this.trigger.removeAllListeners();
21525 this.trigger.remove();
21528 this.wrap.remove();
21530 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
21533 checkStrength: function ()
21535 var pwd = this.inputEl().getValue();
21536 if (pwd == this._lastPwd) {
21541 if (this.ClientSideStrongPassword(pwd)) {
21543 } else if (this.ClientSideMediumPassword(pwd)) {
21545 } else if (this.ClientSideWeakPassword(pwd)) {
21551 Roo.log('strength1: ' + strength);
21553 //var pm = this.trigger.child('div/div/div').dom;
21554 var pm = this.trigger.child('div/div');
21555 pm.removeClass(this.meterClass);
21556 pm.addClass(this.meterClass[strength]);
21559 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21561 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21563 this._lastPwd = pwd;
21567 Roo.bootstrap.SecurePass.superclass.reset.call(this);
21569 this._lastPwd = '';
21571 var pm = this.trigger.child('div/div');
21572 pm.removeClass(this.meterClass);
21573 pm.addClass('roo-password-meter-grey');
21576 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21579 this.inputEl().dom.type='password';
21582 validateValue: function (value)
21585 if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
21588 if (value.length == 0) {
21589 if (this.allowBlank) {
21590 this.clearInvalid();
21594 this.markInvalid(this.errors.PwdEmpty);
21595 this.errorMsg = this.errors.PwdEmpty;
21603 if ('[\x21-\x7e]*'.match(value)) {
21604 this.markInvalid(this.errors.PwdBadChar);
21605 this.errorMsg = this.errors.PwdBadChar;
21608 if (value.length < 6) {
21609 this.markInvalid(this.errors.PwdShort);
21610 this.errorMsg = this.errors.PwdShort;
21613 if (value.length > 16) {
21614 this.markInvalid(this.errors.PwdLong);
21615 this.errorMsg = this.errors.PwdLong;
21619 if (this.ClientSideStrongPassword(value)) {
21621 } else if (this.ClientSideMediumPassword(value)) {
21623 } else if (this.ClientSideWeakPassword(value)) {
21630 if (strength < 2) {
21631 //this.markInvalid(this.errors.TooWeak);
21632 this.errorMsg = this.errors.TooWeak;
21637 console.log('strength2: ' + strength);
21639 //var pm = this.trigger.child('div/div/div').dom;
21641 var pm = this.trigger.child('div/div');
21642 pm.removeClass(this.meterClass);
21643 pm.addClass(this.meterClass[strength]);
21645 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21647 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21649 this.errorMsg = '';
21653 CharacterSetChecks: function (type)
21656 this.fResult = false;
21659 isctype: function (character, type)
21662 case this.kCapitalLetter:
21663 if (character >= 'A' && character <= 'Z') {
21668 case this.kSmallLetter:
21669 if (character >= 'a' && character <= 'z') {
21675 if (character >= '0' && character <= '9') {
21680 case this.kPunctuation:
21681 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
21692 IsLongEnough: function (pwd, size)
21694 return !(pwd == null || isNaN(size) || pwd.length < size);
21697 SpansEnoughCharacterSets: function (word, nb)
21699 if (!this.IsLongEnough(word, nb))
21704 var characterSetChecks = new Array(
21705 new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
21706 new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
21709 for (var index = 0; index < word.length; ++index) {
21710 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21711 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
21712 characterSetChecks[nCharSet].fResult = true;
21719 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21720 if (characterSetChecks[nCharSet].fResult) {
21725 if (nCharSets < nb) {
21731 ClientSideStrongPassword: function (pwd)
21733 return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
21736 ClientSideMediumPassword: function (pwd)
21738 return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
21741 ClientSideWeakPassword: function (pwd)
21743 return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
21746 })//<script type="text/javascript">
21749 * Based Ext JS Library 1.1.1
21750 * Copyright(c) 2006-2007, Ext JS, LLC.
21756 * @class Roo.HtmlEditorCore
21757 * @extends Roo.Component
21758 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
21760 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
21763 Roo.HtmlEditorCore = function(config){
21766 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
21771 * @event initialize
21772 * Fires when the editor is fully initialized (including the iframe)
21773 * @param {Roo.HtmlEditorCore} this
21778 * Fires when the editor is first receives the focus. Any insertion must wait
21779 * until after this event.
21780 * @param {Roo.HtmlEditorCore} this
21784 * @event beforesync
21785 * Fires before the textarea is updated with content from the editor iframe. Return false
21786 * to cancel the sync.
21787 * @param {Roo.HtmlEditorCore} this
21788 * @param {String} html
21792 * @event beforepush
21793 * Fires before the iframe editor is updated with content from the textarea. Return false
21794 * to cancel the push.
21795 * @param {Roo.HtmlEditorCore} this
21796 * @param {String} html
21801 * Fires when the textarea is updated with content from the editor iframe.
21802 * @param {Roo.HtmlEditorCore} this
21803 * @param {String} html
21808 * Fires when the iframe editor is updated with content from the textarea.
21809 * @param {Roo.HtmlEditorCore} this
21810 * @param {String} html
21815 * @event editorevent
21816 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
21817 * @param {Roo.HtmlEditorCore} this
21823 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
21825 // defaults : white / black...
21826 this.applyBlacklists();
21833 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
21837 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
21843 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
21848 * @cfg {Number} height (in pixels)
21852 * @cfg {Number} width (in pixels)
21857 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
21860 stylesheets: false,
21865 // private properties
21866 validationEvent : false,
21868 initialized : false,
21870 sourceEditMode : false,
21871 onFocus : Roo.emptyFn,
21873 hideMode:'offsets',
21877 // blacklist + whitelisted elements..
21884 * Protected method that will not generally be called directly. It
21885 * is called when the editor initializes the iframe with HTML contents. Override this method if you
21886 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
21888 getDocMarkup : function(){
21892 // inherit styels from page...??
21893 if (this.stylesheets === false) {
21895 Roo.get(document.head).select('style').each(function(node) {
21896 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21899 Roo.get(document.head).select('link').each(function(node) {
21900 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21903 } else if (!this.stylesheets.length) {
21905 st = '<style type="text/css">' +
21906 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21909 st = '<style type="text/css">' +
21914 st += '<style type="text/css">' +
21915 'IMG { cursor: pointer } ' +
21918 var cls = 'roo-htmleditor-body';
21920 if(this.bodyCls.length){
21921 cls += ' ' + this.bodyCls;
21924 return '<html><head>' + st +
21925 //<style type="text/css">' +
21926 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21928 ' </head><body class="' + cls + '"></body></html>';
21932 onRender : function(ct, position)
21935 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
21936 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
21939 this.el.dom.style.border = '0 none';
21940 this.el.dom.setAttribute('tabIndex', -1);
21941 this.el.addClass('x-hidden hide');
21945 if(Roo.isIE){ // fix IE 1px bogus margin
21946 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
21950 this.frameId = Roo.id();
21954 var iframe = this.owner.wrap.createChild({
21956 cls: 'form-control', // bootstrap..
21958 name: this.frameId,
21959 frameBorder : 'no',
21960 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
21965 this.iframe = iframe.dom;
21967 this.assignDocWin();
21969 this.doc.designMode = 'on';
21972 this.doc.write(this.getDocMarkup());
21976 var task = { // must defer to wait for browser to be ready
21978 //console.log("run task?" + this.doc.readyState);
21979 this.assignDocWin();
21980 if(this.doc.body || this.doc.readyState == 'complete'){
21982 this.doc.designMode="on";
21986 Roo.TaskMgr.stop(task);
21987 this.initEditor.defer(10, this);
21994 Roo.TaskMgr.start(task);
21999 onResize : function(w, h)
22001 Roo.log('resize: ' +w + ',' + h );
22002 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
22006 if(typeof w == 'number'){
22008 this.iframe.style.width = w + 'px';
22010 if(typeof h == 'number'){
22012 this.iframe.style.height = h + 'px';
22014 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
22021 * Toggles the editor between standard and source edit mode.
22022 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
22024 toggleSourceEdit : function(sourceEditMode){
22026 this.sourceEditMode = sourceEditMode === true;
22028 if(this.sourceEditMode){
22030 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
22033 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
22034 //this.iframe.className = '';
22037 //this.setSize(this.owner.wrap.getSize());
22038 //this.fireEvent('editmodechange', this, this.sourceEditMode);
22045 * Protected method that will not generally be called directly. If you need/want
22046 * custom HTML cleanup, this is the method you should override.
22047 * @param {String} html The HTML to be cleaned
22048 * return {String} The cleaned HTML
22050 cleanHtml : function(html){
22051 html = String(html);
22052 if(html.length > 5){
22053 if(Roo.isSafari){ // strip safari nonsense
22054 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
22057 if(html == ' '){
22064 * HTML Editor -> Textarea
22065 * Protected method that will not generally be called directly. Syncs the contents
22066 * of the editor iframe with the textarea.
22068 syncValue : function(){
22069 if(this.initialized){
22070 var bd = (this.doc.body || this.doc.documentElement);
22071 //this.cleanUpPaste(); -- this is done else where and causes havoc..
22072 var html = bd.innerHTML;
22074 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
22075 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
22077 html = '<div style="'+m[0]+'">' + html + '</div>';
22080 html = this.cleanHtml(html);
22081 // fix up the special chars.. normaly like back quotes in word...
22082 // however we do not want to do this with chinese..
22083 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
22084 var cc = b.charCodeAt();
22086 (cc >= 0x4E00 && cc < 0xA000 ) ||
22087 (cc >= 0x3400 && cc < 0x4E00 ) ||
22088 (cc >= 0xf900 && cc < 0xfb00 )
22094 if(this.owner.fireEvent('beforesync', this, html) !== false){
22095 this.el.dom.value = html;
22096 this.owner.fireEvent('sync', this, html);
22102 * Protected method that will not generally be called directly. Pushes the value of the textarea
22103 * into the iframe editor.
22105 pushValue : function(){
22106 if(this.initialized){
22107 var v = this.el.dom.value.trim();
22109 // if(v.length < 1){
22113 if(this.owner.fireEvent('beforepush', this, v) !== false){
22114 var d = (this.doc.body || this.doc.documentElement);
22116 this.cleanUpPaste();
22117 this.el.dom.value = d.innerHTML;
22118 this.owner.fireEvent('push', this, v);
22124 deferFocus : function(){
22125 this.focus.defer(10, this);
22129 focus : function(){
22130 if(this.win && !this.sourceEditMode){
22137 assignDocWin: function()
22139 var iframe = this.iframe;
22142 this.doc = iframe.contentWindow.document;
22143 this.win = iframe.contentWindow;
22145 // if (!Roo.get(this.frameId)) {
22148 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
22149 // this.win = Roo.get(this.frameId).dom.contentWindow;
22151 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
22155 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
22156 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
22161 initEditor : function(){
22162 //console.log("INIT EDITOR");
22163 this.assignDocWin();
22167 this.doc.designMode="on";
22169 this.doc.write(this.getDocMarkup());
22172 var dbody = (this.doc.body || this.doc.documentElement);
22173 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
22174 // this copies styles from the containing element into thsi one..
22175 // not sure why we need all of this..
22176 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
22178 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
22179 //ss['background-attachment'] = 'fixed'; // w3c
22180 dbody.bgProperties = 'fixed'; // ie
22181 //Roo.DomHelper.applyStyles(dbody, ss);
22182 Roo.EventManager.on(this.doc, {
22183 //'mousedown': this.onEditorEvent,
22184 'mouseup': this.onEditorEvent,
22185 'dblclick': this.onEditorEvent,
22186 'click': this.onEditorEvent,
22187 'keyup': this.onEditorEvent,
22192 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
22194 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
22195 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
22197 this.initialized = true;
22199 this.owner.fireEvent('initialize', this);
22204 onDestroy : function(){
22210 //for (var i =0; i < this.toolbars.length;i++) {
22211 // // fixme - ask toolbars for heights?
22212 // this.toolbars[i].onDestroy();
22215 //this.wrap.dom.innerHTML = '';
22216 //this.wrap.remove();
22221 onFirstFocus : function(){
22223 this.assignDocWin();
22226 this.activated = true;
22229 if(Roo.isGecko){ // prevent silly gecko errors
22231 var s = this.win.getSelection();
22232 if(!s.focusNode || s.focusNode.nodeType != 3){
22233 var r = s.getRangeAt(0);
22234 r.selectNodeContents((this.doc.body || this.doc.documentElement));
22239 this.execCmd('useCSS', true);
22240 this.execCmd('styleWithCSS', false);
22243 this.owner.fireEvent('activate', this);
22247 adjustFont: function(btn){
22248 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
22249 //if(Roo.isSafari){ // safari
22252 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
22253 if(Roo.isSafari){ // safari
22254 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
22255 v = (v < 10) ? 10 : v;
22256 v = (v > 48) ? 48 : v;
22257 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
22262 v = Math.max(1, v+adjust);
22264 this.execCmd('FontSize', v );
22267 onEditorEvent : function(e)
22269 this.owner.fireEvent('editorevent', this, e);
22270 // this.updateToolbar();
22271 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
22274 insertTag : function(tg)
22276 // could be a bit smarter... -> wrap the current selected tRoo..
22277 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
22279 range = this.createRange(this.getSelection());
22280 var wrappingNode = this.doc.createElement(tg.toLowerCase());
22281 wrappingNode.appendChild(range.extractContents());
22282 range.insertNode(wrappingNode);
22289 this.execCmd("formatblock", tg);
22293 insertText : function(txt)
22297 var range = this.createRange();
22298 range.deleteContents();
22299 //alert(Sender.getAttribute('label'));
22301 range.insertNode(this.doc.createTextNode(txt));
22307 * Executes a Midas editor command on the editor document and performs necessary focus and
22308 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
22309 * @param {String} cmd The Midas command
22310 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22312 relayCmd : function(cmd, value){
22314 this.execCmd(cmd, value);
22315 this.owner.fireEvent('editorevent', this);
22316 //this.updateToolbar();
22317 this.owner.deferFocus();
22321 * Executes a Midas editor command directly on the editor document.
22322 * For visual commands, you should use {@link #relayCmd} instead.
22323 * <b>This should only be called after the editor is initialized.</b>
22324 * @param {String} cmd The Midas command
22325 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22327 execCmd : function(cmd, value){
22328 this.doc.execCommand(cmd, false, value === undefined ? null : value);
22335 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
22337 * @param {String} text | dom node..
22339 insertAtCursor : function(text)
22342 if(!this.activated){
22348 var r = this.doc.selection.createRange();
22359 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
22363 // from jquery ui (MIT licenced)
22365 var win = this.win;
22367 if (win.getSelection && win.getSelection().getRangeAt) {
22368 range = win.getSelection().getRangeAt(0);
22369 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
22370 range.insertNode(node);
22371 } else if (win.document.selection && win.document.selection.createRange) {
22372 // no firefox support
22373 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22374 win.document.selection.createRange().pasteHTML(txt);
22376 // no firefox support
22377 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22378 this.execCmd('InsertHTML', txt);
22387 mozKeyPress : function(e){
22389 var c = e.getCharCode(), cmd;
22392 c = String.fromCharCode(c).toLowerCase();
22406 this.cleanUpPaste.defer(100, this);
22414 e.preventDefault();
22422 fixKeys : function(){ // load time branching for fastest keydown performance
22424 return function(e){
22425 var k = e.getKey(), r;
22428 r = this.doc.selection.createRange();
22431 r.pasteHTML('    ');
22438 r = this.doc.selection.createRange();
22440 var target = r.parentElement();
22441 if(!target || target.tagName.toLowerCase() != 'li'){
22443 r.pasteHTML('<br />');
22449 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22450 this.cleanUpPaste.defer(100, this);
22456 }else if(Roo.isOpera){
22457 return function(e){
22458 var k = e.getKey();
22462 this.execCmd('InsertHTML','    ');
22465 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22466 this.cleanUpPaste.defer(100, this);
22471 }else if(Roo.isSafari){
22472 return function(e){
22473 var k = e.getKey();
22477 this.execCmd('InsertText','\t');
22481 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22482 this.cleanUpPaste.defer(100, this);
22490 getAllAncestors: function()
22492 var p = this.getSelectedNode();
22495 a.push(p); // push blank onto stack..
22496 p = this.getParentElement();
22500 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
22504 a.push(this.doc.body);
22508 lastSelNode : false,
22511 getSelection : function()
22513 this.assignDocWin();
22514 return Roo.isIE ? this.doc.selection : this.win.getSelection();
22517 getSelectedNode: function()
22519 // this may only work on Gecko!!!
22521 // should we cache this!!!!
22526 var range = this.createRange(this.getSelection()).cloneRange();
22529 var parent = range.parentElement();
22531 var testRange = range.duplicate();
22532 testRange.moveToElementText(parent);
22533 if (testRange.inRange(range)) {
22536 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
22539 parent = parent.parentElement;
22544 // is ancestor a text element.
22545 var ac = range.commonAncestorContainer;
22546 if (ac.nodeType == 3) {
22547 ac = ac.parentNode;
22550 var ar = ac.childNodes;
22553 var other_nodes = [];
22554 var has_other_nodes = false;
22555 for (var i=0;i<ar.length;i++) {
22556 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
22559 // fullly contained node.
22561 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
22566 // probably selected..
22567 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
22568 other_nodes.push(ar[i]);
22572 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
22577 has_other_nodes = true;
22579 if (!nodes.length && other_nodes.length) {
22580 nodes= other_nodes;
22582 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
22588 createRange: function(sel)
22590 // this has strange effects when using with
22591 // top toolbar - not sure if it's a great idea.
22592 //this.editor.contentWindow.focus();
22593 if (typeof sel != "undefined") {
22595 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
22597 return this.doc.createRange();
22600 return this.doc.createRange();
22603 getParentElement: function()
22606 this.assignDocWin();
22607 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
22609 var range = this.createRange(sel);
22612 var p = range.commonAncestorContainer;
22613 while (p.nodeType == 3) { // text node
22624 * Range intersection.. the hard stuff...
22628 * [ -- selected range --- ]
22632 * if end is before start or hits it. fail.
22633 * if start is after end or hits it fail.
22635 * if either hits (but other is outside. - then it's not
22641 // @see http://www.thismuchiknow.co.uk/?p=64.
22642 rangeIntersectsNode : function(range, node)
22644 var nodeRange = node.ownerDocument.createRange();
22646 nodeRange.selectNode(node);
22648 nodeRange.selectNodeContents(node);
22651 var rangeStartRange = range.cloneRange();
22652 rangeStartRange.collapse(true);
22654 var rangeEndRange = range.cloneRange();
22655 rangeEndRange.collapse(false);
22657 var nodeStartRange = nodeRange.cloneRange();
22658 nodeStartRange.collapse(true);
22660 var nodeEndRange = nodeRange.cloneRange();
22661 nodeEndRange.collapse(false);
22663 return rangeStartRange.compareBoundaryPoints(
22664 Range.START_TO_START, nodeEndRange) == -1 &&
22665 rangeEndRange.compareBoundaryPoints(
22666 Range.START_TO_START, nodeStartRange) == 1;
22670 rangeCompareNode : function(range, node)
22672 var nodeRange = node.ownerDocument.createRange();
22674 nodeRange.selectNode(node);
22676 nodeRange.selectNodeContents(node);
22680 range.collapse(true);
22682 nodeRange.collapse(true);
22684 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
22685 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
22687 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
22689 var nodeIsBefore = ss == 1;
22690 var nodeIsAfter = ee == -1;
22692 if (nodeIsBefore && nodeIsAfter) {
22695 if (!nodeIsBefore && nodeIsAfter) {
22696 return 1; //right trailed.
22699 if (nodeIsBefore && !nodeIsAfter) {
22700 return 2; // left trailed.
22706 // private? - in a new class?
22707 cleanUpPaste : function()
22709 // cleans up the whole document..
22710 Roo.log('cleanuppaste');
22712 this.cleanUpChildren(this.doc.body);
22713 var clean = this.cleanWordChars(this.doc.body.innerHTML);
22714 if (clean != this.doc.body.innerHTML) {
22715 this.doc.body.innerHTML = clean;
22720 cleanWordChars : function(input) {// change the chars to hex code
22721 var he = Roo.HtmlEditorCore;
22723 var output = input;
22724 Roo.each(he.swapCodes, function(sw) {
22725 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
22727 output = output.replace(swapper, sw[1]);
22734 cleanUpChildren : function (n)
22736 if (!n.childNodes.length) {
22739 for (var i = n.childNodes.length-1; i > -1 ; i--) {
22740 this.cleanUpChild(n.childNodes[i]);
22747 cleanUpChild : function (node)
22750 //console.log(node);
22751 if (node.nodeName == "#text") {
22752 // clean up silly Windows -- stuff?
22755 if (node.nodeName == "#comment") {
22756 node.parentNode.removeChild(node);
22757 // clean up silly Windows -- stuff?
22760 var lcname = node.tagName.toLowerCase();
22761 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
22762 // whitelist of tags..
22764 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
22766 node.parentNode.removeChild(node);
22771 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
22773 // remove <a name=....> as rendering on yahoo mailer is borked with this.
22774 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
22776 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
22777 // remove_keep_children = true;
22780 if (remove_keep_children) {
22781 this.cleanUpChildren(node);
22782 // inserts everything just before this node...
22783 while (node.childNodes.length) {
22784 var cn = node.childNodes[0];
22785 node.removeChild(cn);
22786 node.parentNode.insertBefore(cn, node);
22788 node.parentNode.removeChild(node);
22792 if (!node.attributes || !node.attributes.length) {
22793 this.cleanUpChildren(node);
22797 function cleanAttr(n,v)
22800 if (v.match(/^\./) || v.match(/^\//)) {
22803 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/) || v.match(/^ftp:/)) {
22806 if (v.match(/^#/)) {
22809 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
22810 node.removeAttribute(n);
22814 var cwhite = this.cwhite;
22815 var cblack = this.cblack;
22817 function cleanStyle(n,v)
22819 if (v.match(/expression/)) { //XSS?? should we even bother..
22820 node.removeAttribute(n);
22824 var parts = v.split(/;/);
22827 Roo.each(parts, function(p) {
22828 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
22832 var l = p.split(':').shift().replace(/\s+/g,'');
22833 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
22835 if ( cwhite.length && cblack.indexOf(l) > -1) {
22836 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22837 //node.removeAttribute(n);
22841 // only allow 'c whitelisted system attributes'
22842 if ( cwhite.length && cwhite.indexOf(l) < 0) {
22843 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22844 //node.removeAttribute(n);
22854 if (clean.length) {
22855 node.setAttribute(n, clean.join(';'));
22857 node.removeAttribute(n);
22863 for (var i = node.attributes.length-1; i > -1 ; i--) {
22864 var a = node.attributes[i];
22867 if (a.name.toLowerCase().substr(0,2)=='on') {
22868 node.removeAttribute(a.name);
22871 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
22872 node.removeAttribute(a.name);
22875 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
22876 cleanAttr(a.name,a.value); // fixme..
22879 if (a.name == 'style') {
22880 cleanStyle(a.name,a.value);
22883 /// clean up MS crap..
22884 // tecnically this should be a list of valid class'es..
22887 if (a.name == 'class') {
22888 if (a.value.match(/^Mso/)) {
22889 node.className = '';
22892 if (a.value.match(/^body$/)) {
22893 node.className = '';
22904 this.cleanUpChildren(node);
22910 * Clean up MS wordisms...
22912 cleanWord : function(node)
22917 this.cleanWord(this.doc.body);
22920 if (node.nodeName == "#text") {
22921 // clean up silly Windows -- stuff?
22924 if (node.nodeName == "#comment") {
22925 node.parentNode.removeChild(node);
22926 // clean up silly Windows -- stuff?
22930 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
22931 node.parentNode.removeChild(node);
22935 // remove - but keep children..
22936 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
22937 while (node.childNodes.length) {
22938 var cn = node.childNodes[0];
22939 node.removeChild(cn);
22940 node.parentNode.insertBefore(cn, node);
22942 node.parentNode.removeChild(node);
22943 this.iterateChildren(node, this.cleanWord);
22947 if (node.className.length) {
22949 var cn = node.className.split(/\W+/);
22951 Roo.each(cn, function(cls) {
22952 if (cls.match(/Mso[a-zA-Z]+/)) {
22957 node.className = cna.length ? cna.join(' ') : '';
22959 node.removeAttribute("class");
22963 if (node.hasAttribute("lang")) {
22964 node.removeAttribute("lang");
22967 if (node.hasAttribute("style")) {
22969 var styles = node.getAttribute("style").split(";");
22971 Roo.each(styles, function(s) {
22972 if (!s.match(/:/)) {
22975 var kv = s.split(":");
22976 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
22979 // what ever is left... we allow.
22982 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
22983 if (!nstyle.length) {
22984 node.removeAttribute('style');
22987 this.iterateChildren(node, this.cleanWord);
22993 * iterateChildren of a Node, calling fn each time, using this as the scole..
22994 * @param {DomNode} node node to iterate children of.
22995 * @param {Function} fn method of this class to call on each item.
22997 iterateChildren : function(node, fn)
22999 if (!node.childNodes.length) {
23002 for (var i = node.childNodes.length-1; i > -1 ; i--) {
23003 fn.call(this, node.childNodes[i])
23009 * cleanTableWidths.
23011 * Quite often pasting from word etc.. results in tables with column and widths.
23012 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
23015 cleanTableWidths : function(node)
23020 this.cleanTableWidths(this.doc.body);
23025 if (node.nodeName == "#text" || node.nodeName == "#comment") {
23028 Roo.log(node.tagName);
23029 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
23030 this.iterateChildren(node, this.cleanTableWidths);
23033 if (node.hasAttribute('width')) {
23034 node.removeAttribute('width');
23038 if (node.hasAttribute("style")) {
23041 var styles = node.getAttribute("style").split(";");
23043 Roo.each(styles, function(s) {
23044 if (!s.match(/:/)) {
23047 var kv = s.split(":");
23048 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
23051 // what ever is left... we allow.
23054 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
23055 if (!nstyle.length) {
23056 node.removeAttribute('style');
23060 this.iterateChildren(node, this.cleanTableWidths);
23068 domToHTML : function(currentElement, depth, nopadtext) {
23070 depth = depth || 0;
23071 nopadtext = nopadtext || false;
23073 if (!currentElement) {
23074 return this.domToHTML(this.doc.body);
23077 //Roo.log(currentElement);
23079 var allText = false;
23080 var nodeName = currentElement.nodeName;
23081 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
23083 if (nodeName == '#text') {
23085 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
23090 if (nodeName != 'BODY') {
23093 // Prints the node tagName, such as <A>, <IMG>, etc
23096 for(i = 0; i < currentElement.attributes.length;i++) {
23098 var aname = currentElement.attributes.item(i).name;
23099 if (!currentElement.attributes.item(i).value.length) {
23102 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
23105 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
23114 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
23117 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
23122 // Traverse the tree
23124 var currentElementChild = currentElement.childNodes.item(i);
23125 var allText = true;
23126 var innerHTML = '';
23128 while (currentElementChild) {
23129 // Formatting code (indent the tree so it looks nice on the screen)
23130 var nopad = nopadtext;
23131 if (lastnode == 'SPAN') {
23135 if (currentElementChild.nodeName == '#text') {
23136 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
23137 toadd = nopadtext ? toadd : toadd.trim();
23138 if (!nopad && toadd.length > 80) {
23139 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
23141 innerHTML += toadd;
23144 currentElementChild = currentElement.childNodes.item(i);
23150 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
23152 // Recursively traverse the tree structure of the child node
23153 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
23154 lastnode = currentElementChild.nodeName;
23156 currentElementChild=currentElement.childNodes.item(i);
23162 // The remaining code is mostly for formatting the tree
23163 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
23168 ret+= "</"+tagName+">";
23174 applyBlacklists : function()
23176 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
23177 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
23181 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
23182 if (b.indexOf(tag) > -1) {
23185 this.white.push(tag);
23189 Roo.each(w, function(tag) {
23190 if (b.indexOf(tag) > -1) {
23193 if (this.white.indexOf(tag) > -1) {
23196 this.white.push(tag);
23201 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
23202 if (w.indexOf(tag) > -1) {
23205 this.black.push(tag);
23209 Roo.each(b, function(tag) {
23210 if (w.indexOf(tag) > -1) {
23213 if (this.black.indexOf(tag) > -1) {
23216 this.black.push(tag);
23221 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
23222 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
23226 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
23227 if (b.indexOf(tag) > -1) {
23230 this.cwhite.push(tag);
23234 Roo.each(w, function(tag) {
23235 if (b.indexOf(tag) > -1) {
23238 if (this.cwhite.indexOf(tag) > -1) {
23241 this.cwhite.push(tag);
23246 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
23247 if (w.indexOf(tag) > -1) {
23250 this.cblack.push(tag);
23254 Roo.each(b, function(tag) {
23255 if (w.indexOf(tag) > -1) {
23258 if (this.cblack.indexOf(tag) > -1) {
23261 this.cblack.push(tag);
23266 setStylesheets : function(stylesheets)
23268 if(typeof(stylesheets) == 'string'){
23269 Roo.get(this.iframe.contentDocument.head).createChild({
23271 rel : 'stylesheet',
23280 Roo.each(stylesheets, function(s) {
23285 Roo.get(_this.iframe.contentDocument.head).createChild({
23287 rel : 'stylesheet',
23296 removeStylesheets : function()
23300 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
23305 setStyle : function(style)
23307 Roo.get(this.iframe.contentDocument.head).createChild({
23316 // hide stuff that is not compatible
23330 * @event specialkey
23334 * @cfg {String} fieldClass @hide
23337 * @cfg {String} focusClass @hide
23340 * @cfg {String} autoCreate @hide
23343 * @cfg {String} inputType @hide
23346 * @cfg {String} invalidClass @hide
23349 * @cfg {String} invalidText @hide
23352 * @cfg {String} msgFx @hide
23355 * @cfg {String} validateOnBlur @hide
23359 Roo.HtmlEditorCore.white = [
23360 'area', 'br', 'img', 'input', 'hr', 'wbr',
23362 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
23363 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
23364 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
23365 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
23366 'table', 'ul', 'xmp',
23368 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
23371 'dir', 'menu', 'ol', 'ul', 'dl',
23377 Roo.HtmlEditorCore.black = [
23378 // 'embed', 'object', // enable - backend responsiblity to clean thiese
23380 'base', 'basefont', 'bgsound', 'blink', 'body',
23381 'frame', 'frameset', 'head', 'html', 'ilayer',
23382 'iframe', 'layer', 'link', 'meta', 'object',
23383 'script', 'style' ,'title', 'xml' // clean later..
23385 Roo.HtmlEditorCore.clean = [
23386 'script', 'style', 'title', 'xml'
23388 Roo.HtmlEditorCore.remove = [
23393 Roo.HtmlEditorCore.ablack = [
23397 Roo.HtmlEditorCore.aclean = [
23398 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
23402 Roo.HtmlEditorCore.pwhite= [
23403 'http', 'https', 'mailto'
23406 // white listed style attributes.
23407 Roo.HtmlEditorCore.cwhite= [
23408 // 'text-align', /// default is to allow most things..
23414 // black listed style attributes.
23415 Roo.HtmlEditorCore.cblack= [
23416 // 'font-size' -- this can be set by the project
23420 Roo.HtmlEditorCore.swapCodes =[
23439 * @class Roo.bootstrap.HtmlEditor
23440 * @extends Roo.bootstrap.TextArea
23441 * Bootstrap HtmlEditor class
23444 * Create a new HtmlEditor
23445 * @param {Object} config The config object
23448 Roo.bootstrap.HtmlEditor = function(config){
23449 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
23450 if (!this.toolbars) {
23451 this.toolbars = [];
23454 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
23457 * @event initialize
23458 * Fires when the editor is fully initialized (including the iframe)
23459 * @param {HtmlEditor} this
23464 * Fires when the editor is first receives the focus. Any insertion must wait
23465 * until after this event.
23466 * @param {HtmlEditor} this
23470 * @event beforesync
23471 * Fires before the textarea is updated with content from the editor iframe. Return false
23472 * to cancel the sync.
23473 * @param {HtmlEditor} this
23474 * @param {String} html
23478 * @event beforepush
23479 * Fires before the iframe editor is updated with content from the textarea. Return false
23480 * to cancel the push.
23481 * @param {HtmlEditor} this
23482 * @param {String} html
23487 * Fires when the textarea is updated with content from the editor iframe.
23488 * @param {HtmlEditor} this
23489 * @param {String} html
23494 * Fires when the iframe editor is updated with content from the textarea.
23495 * @param {HtmlEditor} this
23496 * @param {String} html
23500 * @event editmodechange
23501 * Fires when the editor switches edit modes
23502 * @param {HtmlEditor} this
23503 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
23505 editmodechange: true,
23507 * @event editorevent
23508 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
23509 * @param {HtmlEditor} this
23513 * @event firstfocus
23514 * Fires when on first focus - needed by toolbars..
23515 * @param {HtmlEditor} this
23520 * Auto save the htmlEditor value as a file into Events
23521 * @param {HtmlEditor} this
23525 * @event savedpreview
23526 * preview the saved version of htmlEditor
23527 * @param {HtmlEditor} this
23534 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
23538 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
23543 * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
23548 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
23553 * @cfg {Number} height (in pixels)
23557 * @cfg {Number} width (in pixels)
23562 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
23565 stylesheets: false,
23570 // private properties
23571 validationEvent : false,
23573 initialized : false,
23576 onFocus : Roo.emptyFn,
23578 hideMode:'offsets',
23580 tbContainer : false,
23584 toolbarContainer :function() {
23585 return this.wrap.select('.x-html-editor-tb',true).first();
23589 * Protected method that will not generally be called directly. It
23590 * is called when the editor creates its toolbar. Override this method if you need to
23591 * add custom toolbar buttons.
23592 * @param {HtmlEditor} editor
23594 createToolbar : function(){
23595 Roo.log('renewing');
23596 Roo.log("create toolbars");
23598 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
23599 this.toolbars[0].render(this.toolbarContainer());
23603 // if (!editor.toolbars || !editor.toolbars.length) {
23604 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
23607 // for (var i =0 ; i < editor.toolbars.length;i++) {
23608 // editor.toolbars[i] = Roo.factory(
23609 // typeof(editor.toolbars[i]) == 'string' ?
23610 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
23611 // Roo.bootstrap.HtmlEditor);
23612 // editor.toolbars[i].init(editor);
23618 onRender : function(ct, position)
23620 // Roo.log("Call onRender: " + this.xtype);
23622 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
23624 this.wrap = this.inputEl().wrap({
23625 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
23628 this.editorcore.onRender(ct, position);
23630 if (this.resizable) {
23631 this.resizeEl = new Roo.Resizable(this.wrap, {
23635 minHeight : this.height,
23636 height: this.height,
23637 handles : this.resizable,
23640 resize : function(r, w, h) {
23641 _t.onResize(w,h); // -something
23647 this.createToolbar(this);
23650 if(!this.width && this.resizable){
23651 this.setSize(this.wrap.getSize());
23653 if (this.resizeEl) {
23654 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
23655 // should trigger onReize..
23661 onResize : function(w, h)
23663 Roo.log('resize: ' +w + ',' + h );
23664 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
23668 if(this.inputEl() ){
23669 if(typeof w == 'number'){
23670 var aw = w - this.wrap.getFrameWidth('lr');
23671 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
23674 if(typeof h == 'number'){
23675 var tbh = -11; // fixme it needs to tool bar size!
23676 for (var i =0; i < this.toolbars.length;i++) {
23677 // fixme - ask toolbars for heights?
23678 tbh += this.toolbars[i].el.getHeight();
23679 //if (this.toolbars[i].footer) {
23680 // tbh += this.toolbars[i].footer.el.getHeight();
23688 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
23689 ah -= 5; // knock a few pixes off for look..
23690 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
23694 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
23695 this.editorcore.onResize(ew,eh);
23700 * Toggles the editor between standard and source edit mode.
23701 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
23703 toggleSourceEdit : function(sourceEditMode)
23705 this.editorcore.toggleSourceEdit(sourceEditMode);
23707 if(this.editorcore.sourceEditMode){
23708 Roo.log('editor - showing textarea');
23711 // Roo.log(this.syncValue());
23713 this.inputEl().removeClass(['hide', 'x-hidden']);
23714 this.inputEl().dom.removeAttribute('tabIndex');
23715 this.inputEl().focus();
23717 Roo.log('editor - hiding textarea');
23719 // Roo.log(this.pushValue());
23722 this.inputEl().addClass(['hide', 'x-hidden']);
23723 this.inputEl().dom.setAttribute('tabIndex', -1);
23724 //this.deferFocus();
23727 if(this.resizable){
23728 this.setSize(this.wrap.getSize());
23731 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
23734 // private (for BoxComponent)
23735 adjustSize : Roo.BoxComponent.prototype.adjustSize,
23737 // private (for BoxComponent)
23738 getResizeEl : function(){
23742 // private (for BoxComponent)
23743 getPositionEl : function(){
23748 initEvents : function(){
23749 this.originalValue = this.getValue();
23753 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23756 // markInvalid : Roo.emptyFn,
23758 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23761 // clearInvalid : Roo.emptyFn,
23763 setValue : function(v){
23764 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
23765 this.editorcore.pushValue();
23770 deferFocus : function(){
23771 this.focus.defer(10, this);
23775 focus : function(){
23776 this.editorcore.focus();
23782 onDestroy : function(){
23788 for (var i =0; i < this.toolbars.length;i++) {
23789 // fixme - ask toolbars for heights?
23790 this.toolbars[i].onDestroy();
23793 this.wrap.dom.innerHTML = '';
23794 this.wrap.remove();
23799 onFirstFocus : function(){
23800 //Roo.log("onFirstFocus");
23801 this.editorcore.onFirstFocus();
23802 for (var i =0; i < this.toolbars.length;i++) {
23803 this.toolbars[i].onFirstFocus();
23809 syncValue : function()
23811 this.editorcore.syncValue();
23814 pushValue : function()
23816 this.editorcore.pushValue();
23820 // hide stuff that is not compatible
23834 * @event specialkey
23838 * @cfg {String} fieldClass @hide
23841 * @cfg {String} focusClass @hide
23844 * @cfg {String} autoCreate @hide
23847 * @cfg {String} inputType @hide
23850 * @cfg {String} invalidClass @hide
23853 * @cfg {String} invalidText @hide
23856 * @cfg {String} msgFx @hide
23859 * @cfg {String} validateOnBlur @hide
23868 Roo.namespace('Roo.bootstrap.htmleditor');
23870 * @class Roo.bootstrap.HtmlEditorToolbar1
23875 new Roo.bootstrap.HtmlEditor({
23878 new Roo.bootstrap.HtmlEditorToolbar1({
23879 disable : { fonts: 1 , format: 1, ..., ... , ...],
23885 * @cfg {Object} disable List of elements to disable..
23886 * @cfg {Array} btns List of additional buttons.
23890 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
23893 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
23896 Roo.apply(this, config);
23898 // default disabled, based on 'good practice'..
23899 this.disable = this.disable || {};
23900 Roo.applyIf(this.disable, {
23903 specialElements : true
23905 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
23907 this.editor = config.editor;
23908 this.editorcore = config.editor.editorcore;
23910 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
23912 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
23913 // dont call parent... till later.
23915 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
23920 editorcore : false,
23925 "h1","h2","h3","h4","h5","h6",
23927 "abbr", "acronym", "address", "cite", "samp", "var",
23931 onRender : function(ct, position)
23933 // Roo.log("Call onRender: " + this.xtype);
23935 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
23937 this.el.dom.style.marginBottom = '0';
23939 var editorcore = this.editorcore;
23940 var editor= this.editor;
23943 var btn = function(id,cmd , toggle, handler, html){
23945 var event = toggle ? 'toggle' : 'click';
23950 xns: Roo.bootstrap,
23953 enableToggle:toggle !== false,
23955 pressed : toggle ? false : null,
23958 a.listeners[toggle ? 'toggle' : 'click'] = function() {
23959 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
23965 // var cb_box = function...
23970 xns: Roo.bootstrap,
23971 glyphicon : 'font',
23975 xns: Roo.bootstrap,
23979 Roo.each(this.formats, function(f) {
23980 style.menu.items.push({
23982 xns: Roo.bootstrap,
23983 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
23988 editorcore.insertTag(this.tagname);
23995 children.push(style);
23997 btn('bold',false,true);
23998 btn('italic',false,true);
23999 btn('align-left', 'justifyleft',true);
24000 btn('align-center', 'justifycenter',true);
24001 btn('align-right' , 'justifyright',true);
24002 btn('link', false, false, function(btn) {
24003 //Roo.log("create link?");
24004 var url = prompt(this.createLinkText, this.defaultLinkValue);
24005 if(url && url != 'http:/'+'/'){
24006 this.editorcore.relayCmd('createlink', url);
24009 btn('list','insertunorderedlist',true);
24010 btn('pencil', false,true, function(btn){
24012 this.toggleSourceEdit(btn.pressed);
24015 if (this.editor.btns.length > 0) {
24016 for (var i = 0; i<this.editor.btns.length; i++) {
24017 children.push(this.editor.btns[i]);
24025 xns: Roo.bootstrap,
24030 xns: Roo.bootstrap,
24035 cog.menu.items.push({
24037 xns: Roo.bootstrap,
24038 html : Clean styles,
24043 editorcore.insertTag(this.tagname);
24052 this.xtype = 'NavSimplebar';
24054 for(var i=0;i< children.length;i++) {
24056 this.buttons.add(this.addxtypeChild(children[i]));
24060 editor.on('editorevent', this.updateToolbar, this);
24062 onBtnClick : function(id)
24064 this.editorcore.relayCmd(id);
24065 this.editorcore.focus();
24069 * Protected method that will not generally be called directly. It triggers
24070 * a toolbar update by reading the markup state of the current selection in the editor.
24072 updateToolbar: function(){
24074 if(!this.editorcore.activated){
24075 this.editor.onFirstFocus(); // is this neeed?
24079 var btns = this.buttons;
24080 var doc = this.editorcore.doc;
24081 btns.get('bold').setActive(doc.queryCommandState('bold'));
24082 btns.get('italic').setActive(doc.queryCommandState('italic'));
24083 //btns.get('underline').setActive(doc.queryCommandState('underline'));
24085 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
24086 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
24087 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
24089 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
24090 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
24093 var ans = this.editorcore.getAllAncestors();
24094 if (this.formatCombo) {
24097 var store = this.formatCombo.store;
24098 this.formatCombo.setValue("");
24099 for (var i =0; i < ans.length;i++) {
24100 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
24102 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
24110 // hides menus... - so this cant be on a menu...
24111 Roo.bootstrap.MenuMgr.hideAll();
24113 Roo.bootstrap.MenuMgr.hideAll();
24114 //this.editorsyncValue();
24116 onFirstFocus: function() {
24117 this.buttons.each(function(item){
24121 toggleSourceEdit : function(sourceEditMode){
24124 if(sourceEditMode){
24125 Roo.log("disabling buttons");
24126 this.buttons.each( function(item){
24127 if(item.cmd != 'pencil'){
24133 Roo.log("enabling buttons");
24134 if(this.editorcore.initialized){
24135 this.buttons.each( function(item){
24141 Roo.log("calling toggole on editor");
24142 // tell the editor that it's been pressed..
24143 this.editor.toggleSourceEdit(sourceEditMode);
24153 * @class Roo.bootstrap.Table.AbstractSelectionModel
24154 * @extends Roo.util.Observable
24155 * Abstract base class for grid SelectionModels. It provides the interface that should be
24156 * implemented by descendant classes. This class should not be directly instantiated.
24159 Roo.bootstrap.Table.AbstractSelectionModel = function(){
24160 this.locked = false;
24161 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
24165 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
24166 /** @ignore Called by the grid automatically. Do not call directly. */
24167 init : function(grid){
24173 * Locks the selections.
24176 this.locked = true;
24180 * Unlocks the selections.
24182 unlock : function(){
24183 this.locked = false;
24187 * Returns true if the selections are locked.
24188 * @return {Boolean}
24190 isLocked : function(){
24191 return this.locked;
24195 * @extends Roo.bootstrap.Table.AbstractSelectionModel
24196 * @class Roo.bootstrap.Table.RowSelectionModel
24197 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
24198 * It supports multiple selections and keyboard selection/navigation.
24200 * @param {Object} config
24203 Roo.bootstrap.Table.RowSelectionModel = function(config){
24204 Roo.apply(this, config);
24205 this.selections = new Roo.util.MixedCollection(false, function(o){
24210 this.lastActive = false;
24214 * @event selectionchange
24215 * Fires when the selection changes
24216 * @param {SelectionModel} this
24218 "selectionchange" : true,
24220 * @event afterselectionchange
24221 * Fires after the selection changes (eg. by key press or clicking)
24222 * @param {SelectionModel} this
24224 "afterselectionchange" : true,
24226 * @event beforerowselect
24227 * Fires when a row is selected being selected, return false to cancel.
24228 * @param {SelectionModel} this
24229 * @param {Number} rowIndex The selected index
24230 * @param {Boolean} keepExisting False if other selections will be cleared
24232 "beforerowselect" : true,
24235 * Fires when a row is selected.
24236 * @param {SelectionModel} this
24237 * @param {Number} rowIndex The selected index
24238 * @param {Roo.data.Record} r The record
24240 "rowselect" : true,
24242 * @event rowdeselect
24243 * Fires when a row is deselected.
24244 * @param {SelectionModel} this
24245 * @param {Number} rowIndex The selected index
24247 "rowdeselect" : true
24249 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
24250 this.locked = false;
24253 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
24255 * @cfg {Boolean} singleSelect
24256 * True to allow selection of only one row at a time (defaults to false)
24258 singleSelect : false,
24261 initEvents : function()
24264 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
24265 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
24266 //}else{ // allow click to work like normal
24267 // this.grid.on("rowclick", this.handleDragableRowClick, this);
24269 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
24270 this.grid.on("rowclick", this.handleMouseDown, this);
24272 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
24273 "up" : function(e){
24275 this.selectPrevious(e.shiftKey);
24276 }else if(this.last !== false && this.lastActive !== false){
24277 var last = this.last;
24278 this.selectRange(this.last, this.lastActive-1);
24279 this.grid.getView().focusRow(this.lastActive);
24280 if(last !== false){
24284 this.selectFirstRow();
24286 this.fireEvent("afterselectionchange", this);
24288 "down" : function(e){
24290 this.selectNext(e.shiftKey);
24291 }else if(this.last !== false && this.lastActive !== false){
24292 var last = this.last;
24293 this.selectRange(this.last, this.lastActive+1);
24294 this.grid.getView().focusRow(this.lastActive);
24295 if(last !== false){
24299 this.selectFirstRow();
24301 this.fireEvent("afterselectionchange", this);
24305 this.grid.store.on('load', function(){
24306 this.selections.clear();
24309 var view = this.grid.view;
24310 view.on("refresh", this.onRefresh, this);
24311 view.on("rowupdated", this.onRowUpdated, this);
24312 view.on("rowremoved", this.onRemove, this);
24317 onRefresh : function()
24319 var ds = this.grid.store, i, v = this.grid.view;
24320 var s = this.selections;
24321 s.each(function(r){
24322 if((i = ds.indexOfId(r.id)) != -1){
24331 onRemove : function(v, index, r){
24332 this.selections.remove(r);
24336 onRowUpdated : function(v, index, r){
24337 if(this.isSelected(r)){
24338 v.onRowSelect(index);
24344 * @param {Array} records The records to select
24345 * @param {Boolean} keepExisting (optional) True to keep existing selections
24347 selectRecords : function(records, keepExisting)
24350 this.clearSelections();
24352 var ds = this.grid.store;
24353 for(var i = 0, len = records.length; i < len; i++){
24354 this.selectRow(ds.indexOf(records[i]), true);
24359 * Gets the number of selected rows.
24362 getCount : function(){
24363 return this.selections.length;
24367 * Selects the first row in the grid.
24369 selectFirstRow : function(){
24374 * Select the last row.
24375 * @param {Boolean} keepExisting (optional) True to keep existing selections
24377 selectLastRow : function(keepExisting){
24378 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
24379 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
24383 * Selects the row immediately following the last selected row.
24384 * @param {Boolean} keepExisting (optional) True to keep existing selections
24386 selectNext : function(keepExisting)
24388 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
24389 this.selectRow(this.last+1, keepExisting);
24390 this.grid.getView().focusRow(this.last);
24395 * Selects the row that precedes the last selected row.
24396 * @param {Boolean} keepExisting (optional) True to keep existing selections
24398 selectPrevious : function(keepExisting){
24400 this.selectRow(this.last-1, keepExisting);
24401 this.grid.getView().focusRow(this.last);
24406 * Returns the selected records
24407 * @return {Array} Array of selected records
24409 getSelections : function(){
24410 return [].concat(this.selections.items);
24414 * Returns the first selected record.
24417 getSelected : function(){
24418 return this.selections.itemAt(0);
24423 * Clears all selections.
24425 clearSelections : function(fast)
24431 var ds = this.grid.store;
24432 var s = this.selections;
24433 s.each(function(r){
24434 this.deselectRow(ds.indexOfId(r.id));
24438 this.selections.clear();
24445 * Selects all rows.
24447 selectAll : function(){
24451 this.selections.clear();
24452 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
24453 this.selectRow(i, true);
24458 * Returns True if there is a selection.
24459 * @return {Boolean}
24461 hasSelection : function(){
24462 return this.selections.length > 0;
24466 * Returns True if the specified row is selected.
24467 * @param {Number/Record} record The record or index of the record to check
24468 * @return {Boolean}
24470 isSelected : function(index){
24471 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
24472 return (r && this.selections.key(r.id) ? true : false);
24476 * Returns True if the specified record id is selected.
24477 * @param {String} id The id of record to check
24478 * @return {Boolean}
24480 isIdSelected : function(id){
24481 return (this.selections.key(id) ? true : false);
24486 handleMouseDBClick : function(e, t){
24490 handleMouseDown : function(e, t)
24492 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
24493 if(this.isLocked() || rowIndex < 0 ){
24496 if(e.shiftKey && this.last !== false){
24497 var last = this.last;
24498 this.selectRange(last, rowIndex, e.ctrlKey);
24499 this.last = last; // reset the last
24503 var isSelected = this.isSelected(rowIndex);
24504 //Roo.log("select row:" + rowIndex);
24506 this.deselectRow(rowIndex);
24508 this.selectRow(rowIndex, true);
24512 if(e.button !== 0 && isSelected){
24513 alert('rowIndex 2: ' + rowIndex);
24514 view.focusRow(rowIndex);
24515 }else if(e.ctrlKey && isSelected){
24516 this.deselectRow(rowIndex);
24517 }else if(!isSelected){
24518 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
24519 view.focusRow(rowIndex);
24523 this.fireEvent("afterselectionchange", this);
24526 handleDragableRowClick : function(grid, rowIndex, e)
24528 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
24529 this.selectRow(rowIndex, false);
24530 grid.view.focusRow(rowIndex);
24531 this.fireEvent("afterselectionchange", this);
24536 * Selects multiple rows.
24537 * @param {Array} rows Array of the indexes of the row to select
24538 * @param {Boolean} keepExisting (optional) True to keep existing selections
24540 selectRows : function(rows, keepExisting){
24542 this.clearSelections();
24544 for(var i = 0, len = rows.length; i < len; i++){
24545 this.selectRow(rows[i], true);
24550 * Selects a range of rows. All rows in between startRow and endRow are also selected.
24551 * @param {Number} startRow The index of the first row in the range
24552 * @param {Number} endRow The index of the last row in the range
24553 * @param {Boolean} keepExisting (optional) True to retain existing selections
24555 selectRange : function(startRow, endRow, keepExisting){
24560 this.clearSelections();
24562 if(startRow <= endRow){
24563 for(var i = startRow; i <= endRow; i++){
24564 this.selectRow(i, true);
24567 for(var i = startRow; i >= endRow; i--){
24568 this.selectRow(i, true);
24574 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
24575 * @param {Number} startRow The index of the first row in the range
24576 * @param {Number} endRow The index of the last row in the range
24578 deselectRange : function(startRow, endRow, preventViewNotify){
24582 for(var i = startRow; i <= endRow; i++){
24583 this.deselectRow(i, preventViewNotify);
24589 * @param {Number} row The index of the row to select
24590 * @param {Boolean} keepExisting (optional) True to keep existing selections
24592 selectRow : function(index, keepExisting, preventViewNotify)
24594 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
24597 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
24598 if(!keepExisting || this.singleSelect){
24599 this.clearSelections();
24602 var r = this.grid.store.getAt(index);
24603 //console.log('selectRow - record id :' + r.id);
24605 this.selections.add(r);
24606 this.last = this.lastActive = index;
24607 if(!preventViewNotify){
24608 var proxy = new Roo.Element(
24609 this.grid.getRowDom(index)
24611 proxy.addClass('bg-info info');
24613 this.fireEvent("rowselect", this, index, r);
24614 this.fireEvent("selectionchange", this);
24620 * @param {Number} row The index of the row to deselect
24622 deselectRow : function(index, preventViewNotify)
24627 if(this.last == index){
24630 if(this.lastActive == index){
24631 this.lastActive = false;
24634 var r = this.grid.store.getAt(index);
24639 this.selections.remove(r);
24640 //.console.log('deselectRow - record id :' + r.id);
24641 if(!preventViewNotify){
24643 var proxy = new Roo.Element(
24644 this.grid.getRowDom(index)
24646 proxy.removeClass('bg-info info');
24648 this.fireEvent("rowdeselect", this, index);
24649 this.fireEvent("selectionchange", this);
24653 restoreLast : function(){
24655 this.last = this._last;
24660 acceptsNav : function(row, col, cm){
24661 return !cm.isHidden(col) && cm.isCellEditable(col, row);
24665 onEditorKey : function(field, e){
24666 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
24671 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
24673 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
24675 }else if(k == e.ENTER && !e.ctrlKey){
24679 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
24681 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
24683 }else if(k == e.ESC){
24687 g.startEditing(newCell[0], newCell[1]);
24693 * Ext JS Library 1.1.1
24694 * Copyright(c) 2006-2007, Ext JS, LLC.
24696 * Originally Released Under LGPL - original licence link has changed is not relivant.
24699 * <script type="text/javascript">
24703 * @class Roo.bootstrap.PagingToolbar
24704 * @extends Roo.bootstrap.NavSimplebar
24705 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
24707 * Create a new PagingToolbar
24708 * @param {Object} config The config object
24709 * @param {Roo.data.Store} store
24711 Roo.bootstrap.PagingToolbar = function(config)
24713 // old args format still supported... - xtype is prefered..
24714 // created from xtype...
24716 this.ds = config.dataSource;
24718 if (config.store && !this.ds) {
24719 this.store= Roo.factory(config.store, Roo.data);
24720 this.ds = this.store;
24721 this.ds.xmodule = this.xmodule || false;
24724 this.toolbarItems = [];
24725 if (config.items) {
24726 this.toolbarItems = config.items;
24729 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
24734 this.bind(this.ds);
24737 if (Roo.bootstrap.version == 4) {
24738 this.navgroup = new Roo.bootstrap.ButtonGroup({ cls: 'pagination' });
24740 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
24745 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
24747 * @cfg {Roo.data.Store} dataSource
24748 * The underlying data store providing the paged data
24751 * @cfg {String/HTMLElement/Element} container
24752 * container The id or element that will contain the toolbar
24755 * @cfg {Boolean} displayInfo
24756 * True to display the displayMsg (defaults to false)
24759 * @cfg {Number} pageSize
24760 * The number of records to display per page (defaults to 20)
24764 * @cfg {String} displayMsg
24765 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
24767 displayMsg : 'Displaying {0} - {1} of {2}',
24769 * @cfg {String} emptyMsg
24770 * The message to display when no records are found (defaults to "No data to display")
24772 emptyMsg : 'No data to display',
24774 * Customizable piece of the default paging text (defaults to "Page")
24777 beforePageText : "Page",
24779 * Customizable piece of the default paging text (defaults to "of %0")
24782 afterPageText : "of {0}",
24784 * Customizable piece of the default paging text (defaults to "First Page")
24787 firstText : "First Page",
24789 * Customizable piece of the default paging text (defaults to "Previous Page")
24792 prevText : "Previous Page",
24794 * Customizable piece of the default paging text (defaults to "Next Page")
24797 nextText : "Next Page",
24799 * Customizable piece of the default paging text (defaults to "Last Page")
24802 lastText : "Last Page",
24804 * Customizable piece of the default paging text (defaults to "Refresh")
24807 refreshText : "Refresh",
24811 onRender : function(ct, position)
24813 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
24814 this.navgroup.parentId = this.id;
24815 this.navgroup.onRender(this.el, null);
24816 // add the buttons to the navgroup
24818 if(this.displayInfo){
24819 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
24820 this.displayEl = this.el.select('.x-paging-info', true).first();
24821 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
24822 // this.displayEl = navel.el.select('span',true).first();
24828 Roo.each(_this.buttons, function(e){ // this might need to use render????
24829 Roo.factory(e).render(_this.el);
24833 Roo.each(_this.toolbarItems, function(e) {
24834 _this.navgroup.addItem(e);
24838 this.first = this.navgroup.addItem({
24839 tooltip: this.firstText,
24840 cls: "prev btn-outline-secondary",
24841 html : ' <i class="fa fa-step-backward"></i>',
24843 preventDefault: true,
24844 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
24847 this.prev = this.navgroup.addItem({
24848 tooltip: this.prevText,
24849 cls: "prev btn-outline-secondary",
24850 html : ' <i class="fa fa-backward"></i>',
24852 preventDefault: true,
24853 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
24855 //this.addSeparator();
24858 var field = this.navgroup.addItem( {
24860 cls : 'x-paging-position btn-outline-secondary',
24862 html : this.beforePageText +
24863 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
24864 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
24867 this.field = field.el.select('input', true).first();
24868 this.field.on("keydown", this.onPagingKeydown, this);
24869 this.field.on("focus", function(){this.dom.select();});
24872 this.afterTextEl = field.el.select('.x-paging-after',true).first();
24873 //this.field.setHeight(18);
24874 //this.addSeparator();
24875 this.next = this.navgroup.addItem({
24876 tooltip: this.nextText,
24877 cls: "next btn-outline-secondary",
24878 html : ' <i class="fa fa-forward"></i>',
24880 preventDefault: true,
24881 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
24883 this.last = this.navgroup.addItem({
24884 tooltip: this.lastText,
24885 html : ' <i class="fa fa-step-forward"></i>',
24886 cls: "next btn-outline-secondary",
24888 preventDefault: true,
24889 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
24891 //this.addSeparator();
24892 this.loading = this.navgroup.addItem({
24893 tooltip: this.refreshText,
24894 cls: "btn-outline-secondary",
24895 html : ' <i class="fa fa-refresh"></i>',
24896 preventDefault: true,
24897 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
24903 updateInfo : function(){
24904 if(this.displayEl){
24905 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
24906 var msg = count == 0 ?
24910 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
24912 this.displayEl.update(msg);
24917 onLoad : function(ds, r, o)
24919 this.cursor = o.params.start ? o.params.start : 0;
24921 var d = this.getPageData(),
24926 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
24927 this.field.dom.value = ap;
24928 this.first.setDisabled(ap == 1);
24929 this.prev.setDisabled(ap == 1);
24930 this.next.setDisabled(ap == ps);
24931 this.last.setDisabled(ap == ps);
24932 this.loading.enable();
24937 getPageData : function(){
24938 var total = this.ds.getTotalCount();
24941 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
24942 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
24947 onLoadError : function(){
24948 this.loading.enable();
24952 onPagingKeydown : function(e){
24953 var k = e.getKey();
24954 var d = this.getPageData();
24956 var v = this.field.dom.value, pageNum;
24957 if(!v || isNaN(pageNum = parseInt(v, 10))){
24958 this.field.dom.value = d.activePage;
24961 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
24962 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24965 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))
24967 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
24968 this.field.dom.value = pageNum;
24969 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
24972 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
24974 var v = this.field.dom.value, pageNum;
24975 var increment = (e.shiftKey) ? 10 : 1;
24976 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
24979 if(!v || isNaN(pageNum = parseInt(v, 10))) {
24980 this.field.dom.value = d.activePage;
24983 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
24985 this.field.dom.value = parseInt(v, 10) + increment;
24986 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
24987 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
24994 beforeLoad : function(){
24996 this.loading.disable();
25001 onClick : function(which){
25010 ds.load({params:{start: 0, limit: this.pageSize}});
25013 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
25016 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
25019 var total = ds.getTotalCount();
25020 var extra = total % this.pageSize;
25021 var lastStart = extra ? (total - extra) : total-this.pageSize;
25022 ds.load({params:{start: lastStart, limit: this.pageSize}});
25025 ds.load({params:{start: this.cursor, limit: this.pageSize}});
25031 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
25032 * @param {Roo.data.Store} store The data store to unbind
25034 unbind : function(ds){
25035 ds.un("beforeload", this.beforeLoad, this);
25036 ds.un("load", this.onLoad, this);
25037 ds.un("loadexception", this.onLoadError, this);
25038 ds.un("remove", this.updateInfo, this);
25039 ds.un("add", this.updateInfo, this);
25040 this.ds = undefined;
25044 * Binds the paging toolbar to the specified {@link Roo.data.Store}
25045 * @param {Roo.data.Store} store The data store to bind
25047 bind : function(ds){
25048 ds.on("beforeload", this.beforeLoad, this);
25049 ds.on("load", this.onLoad, this);
25050 ds.on("loadexception", this.onLoadError, this);
25051 ds.on("remove", this.updateInfo, this);
25052 ds.on("add", this.updateInfo, this);
25063 * @class Roo.bootstrap.MessageBar
25064 * @extends Roo.bootstrap.Component
25065 * Bootstrap MessageBar class
25066 * @cfg {String} html contents of the MessageBar
25067 * @cfg {String} weight (info | success | warning | danger) default info
25068 * @cfg {String} beforeClass insert the bar before the given class
25069 * @cfg {Boolean} closable (true | false) default false
25070 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
25073 * Create a new Element
25074 * @param {Object} config The config object
25077 Roo.bootstrap.MessageBar = function(config){
25078 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
25081 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
25087 beforeClass: 'bootstrap-sticky-wrap',
25089 getAutoCreate : function(){
25093 cls: 'alert alert-dismissable alert-' + this.weight,
25098 html: this.html || ''
25104 cfg.cls += ' alert-messages-fixed';
25118 onRender : function(ct, position)
25120 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
25123 var cfg = Roo.apply({}, this.getAutoCreate());
25127 cfg.cls += ' ' + this.cls;
25130 cfg.style = this.style;
25132 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
25134 this.el.setVisibilityMode(Roo.Element.DISPLAY);
25137 this.el.select('>button.close').on('click', this.hide, this);
25143 if (!this.rendered) {
25149 this.fireEvent('show', this);
25155 if (!this.rendered) {
25161 this.fireEvent('hide', this);
25164 update : function()
25166 // var e = this.el.dom.firstChild;
25168 // if(this.closable){
25169 // e = e.nextSibling;
25172 // e.data = this.html || '';
25174 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
25190 * @class Roo.bootstrap.Graph
25191 * @extends Roo.bootstrap.Component
25192 * Bootstrap Graph class
25196 @cfg {String} graphtype bar | vbar | pie
25197 @cfg {number} g_x coodinator | centre x (pie)
25198 @cfg {number} g_y coodinator | centre y (pie)
25199 @cfg {number} g_r radius (pie)
25200 @cfg {number} g_height height of the chart (respected by all elements in the set)
25201 @cfg {number} g_width width of the chart (respected by all elements in the set)
25202 @cfg {Object} title The title of the chart
25205 -opts (object) options for the chart
25207 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
25208 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
25210 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.
25211 o stacked (boolean) whether or not to tread values as in a stacked bar chart
25213 o stretch (boolean)
25215 -opts (object) options for the pie
25218 o startAngle (number)
25219 o endAngle (number)
25223 * Create a new Input
25224 * @param {Object} config The config object
25227 Roo.bootstrap.Graph = function(config){
25228 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
25234 * The img click event for the img.
25235 * @param {Roo.EventObject} e
25241 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
25252 //g_colors: this.colors,
25259 getAutoCreate : function(){
25270 onRender : function(ct,position){
25273 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
25275 if (typeof(Raphael) == 'undefined') {
25276 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
25280 this.raphael = Raphael(this.el.dom);
25282 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25283 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25284 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25285 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
25287 r.text(160, 10, "Single Series Chart").attr(txtattr);
25288 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
25289 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
25290 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
25292 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
25293 r.barchart(330, 10, 300, 220, data1);
25294 r.barchart(10, 250, 300, 220, data2, {stacked: true});
25295 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
25298 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25299 // r.barchart(30, 30, 560, 250, xdata, {
25300 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
25301 // axis : "0 0 1 1",
25302 // axisxlabels : xdata
25303 // //yvalues : cols,
25306 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25308 // this.load(null,xdata,{
25309 // axis : "0 0 1 1",
25310 // axisxlabels : xdata
25315 load : function(graphtype,xdata,opts)
25317 this.raphael.clear();
25319 graphtype = this.graphtype;
25324 var r = this.raphael,
25325 fin = function () {
25326 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
25328 fout = function () {
25329 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
25331 pfin = function() {
25332 this.sector.stop();
25333 this.sector.scale(1.1, 1.1, this.cx, this.cy);
25336 this.label[0].stop();
25337 this.label[0].attr({ r: 7.5 });
25338 this.label[1].attr({ "font-weight": 800 });
25341 pfout = function() {
25342 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
25345 this.label[0].animate({ r: 5 }, 500, "bounce");
25346 this.label[1].attr({ "font-weight": 400 });
25352 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25355 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25358 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
25359 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
25361 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
25368 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
25373 setTitle: function(o)
25378 initEvents: function() {
25381 this.el.on('click', this.onClick, this);
25385 onClick : function(e)
25387 Roo.log('img onclick');
25388 this.fireEvent('click', this, e);
25400 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25403 * @class Roo.bootstrap.dash.NumberBox
25404 * @extends Roo.bootstrap.Component
25405 * Bootstrap NumberBox class
25406 * @cfg {String} headline Box headline
25407 * @cfg {String} content Box content
25408 * @cfg {String} icon Box icon
25409 * @cfg {String} footer Footer text
25410 * @cfg {String} fhref Footer href
25413 * Create a new NumberBox
25414 * @param {Object} config The config object
25418 Roo.bootstrap.dash.NumberBox = function(config){
25419 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
25423 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
25432 getAutoCreate : function(){
25436 cls : 'small-box ',
25444 cls : 'roo-headline',
25445 html : this.headline
25449 cls : 'roo-content',
25450 html : this.content
25464 cls : 'ion ' + this.icon
25473 cls : 'small-box-footer',
25474 href : this.fhref || '#',
25478 cfg.cn.push(footer);
25485 onRender : function(ct,position){
25486 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
25493 setHeadline: function (value)
25495 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
25498 setFooter: function (value, href)
25500 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
25503 this.el.select('a.small-box-footer',true).first().attr('href', href);
25508 setContent: function (value)
25510 this.el.select('.roo-content',true).first().dom.innerHTML = value;
25513 initEvents: function()
25527 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25530 * @class Roo.bootstrap.dash.TabBox
25531 * @extends Roo.bootstrap.Component
25532 * Bootstrap TabBox class
25533 * @cfg {String} title Title of the TabBox
25534 * @cfg {String} icon Icon of the TabBox
25535 * @cfg {Boolean} showtabs (true|false) show the tabs default true
25536 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
25539 * Create a new TabBox
25540 * @param {Object} config The config object
25544 Roo.bootstrap.dash.TabBox = function(config){
25545 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
25550 * When a pane is added
25551 * @param {Roo.bootstrap.dash.TabPane} pane
25555 * @event activatepane
25556 * When a pane is activated
25557 * @param {Roo.bootstrap.dash.TabPane} pane
25559 "activatepane" : true
25567 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
25572 tabScrollable : false,
25574 getChildContainer : function()
25576 return this.el.select('.tab-content', true).first();
25579 getAutoCreate : function(){
25583 cls: 'pull-left header',
25591 cls: 'fa ' + this.icon
25597 cls: 'nav nav-tabs pull-right',
25603 if(this.tabScrollable){
25610 cls: 'nav nav-tabs pull-right',
25621 cls: 'nav-tabs-custom',
25626 cls: 'tab-content no-padding',
25634 initEvents : function()
25636 //Roo.log('add add pane handler');
25637 this.on('addpane', this.onAddPane, this);
25640 * Updates the box title
25641 * @param {String} html to set the title to.
25643 setTitle : function(value)
25645 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
25647 onAddPane : function(pane)
25649 this.panes.push(pane);
25650 //Roo.log('addpane');
25652 // tabs are rendere left to right..
25653 if(!this.showtabs){
25657 var ctr = this.el.select('.nav-tabs', true).first();
25660 var existing = ctr.select('.nav-tab',true);
25661 var qty = existing.getCount();;
25664 var tab = ctr.createChild({
25666 cls : 'nav-tab' + (qty ? '' : ' active'),
25674 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
25677 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
25679 pane.el.addClass('active');
25684 onTabClick : function(ev,un,ob,pane)
25686 //Roo.log('tab - prev default');
25687 ev.preventDefault();
25690 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
25691 pane.tab.addClass('active');
25692 //Roo.log(pane.title);
25693 this.getChildContainer().select('.tab-pane',true).removeClass('active');
25694 // technically we should have a deactivate event.. but maybe add later.
25695 // and it should not de-activate the selected tab...
25696 this.fireEvent('activatepane', pane);
25697 pane.el.addClass('active');
25698 pane.fireEvent('activate');
25703 getActivePane : function()
25706 Roo.each(this.panes, function(p) {
25707 if(p.el.hasClass('active')){
25728 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25730 * @class Roo.bootstrap.TabPane
25731 * @extends Roo.bootstrap.Component
25732 * Bootstrap TabPane class
25733 * @cfg {Boolean} active (false | true) Default false
25734 * @cfg {String} title title of panel
25738 * Create a new TabPane
25739 * @param {Object} config The config object
25742 Roo.bootstrap.dash.TabPane = function(config){
25743 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
25749 * When a pane is activated
25750 * @param {Roo.bootstrap.dash.TabPane} pane
25757 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
25762 // the tabBox that this is attached to.
25765 getAutoCreate : function()
25773 cfg.cls += ' active';
25778 initEvents : function()
25780 //Roo.log('trigger add pane handler');
25781 this.parent().fireEvent('addpane', this)
25785 * Updates the tab title
25786 * @param {String} html to set the title to.
25788 setTitle: function(str)
25794 this.tab.select('a', true).first().dom.innerHTML = str;
25811 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25814 * @class Roo.bootstrap.menu.Menu
25815 * @extends Roo.bootstrap.Component
25816 * Bootstrap Menu class - container for Menu
25817 * @cfg {String} html Text of the menu
25818 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
25819 * @cfg {String} icon Font awesome icon
25820 * @cfg {String} pos Menu align to (top | bottom) default bottom
25824 * Create a new Menu
25825 * @param {Object} config The config object
25829 Roo.bootstrap.menu.Menu = function(config){
25830 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
25834 * @event beforeshow
25835 * Fires before this menu is displayed
25836 * @param {Roo.bootstrap.menu.Menu} this
25840 * @event beforehide
25841 * Fires before this menu is hidden
25842 * @param {Roo.bootstrap.menu.Menu} this
25847 * Fires after this menu is displayed
25848 * @param {Roo.bootstrap.menu.Menu} this
25853 * Fires after this menu is hidden
25854 * @param {Roo.bootstrap.menu.Menu} this
25859 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
25860 * @param {Roo.bootstrap.menu.Menu} this
25861 * @param {Roo.EventObject} e
25868 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
25872 weight : 'default',
25877 getChildContainer : function() {
25878 if(this.isSubMenu){
25882 return this.el.select('ul.dropdown-menu', true).first();
25885 getAutoCreate : function()
25890 cls : 'roo-menu-text',
25898 cls : 'fa ' + this.icon
25909 cls : 'dropdown-button btn btn-' + this.weight,
25914 cls : 'dropdown-toggle btn btn-' + this.weight,
25924 cls : 'dropdown-menu'
25930 if(this.pos == 'top'){
25931 cfg.cls += ' dropup';
25934 if(this.isSubMenu){
25937 cls : 'dropdown-menu'
25944 onRender : function(ct, position)
25946 this.isSubMenu = ct.hasClass('dropdown-submenu');
25948 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
25951 initEvents : function()
25953 if(this.isSubMenu){
25957 this.hidden = true;
25959 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
25960 this.triggerEl.on('click', this.onTriggerPress, this);
25962 this.buttonEl = this.el.select('button.dropdown-button', true).first();
25963 this.buttonEl.on('click', this.onClick, this);
25969 if(this.isSubMenu){
25973 return this.el.select('ul.dropdown-menu', true).first();
25976 onClick : function(e)
25978 this.fireEvent("click", this, e);
25981 onTriggerPress : function(e)
25983 if (this.isVisible()) {
25990 isVisible : function(){
25991 return !this.hidden;
25996 this.fireEvent("beforeshow", this);
25998 this.hidden = false;
25999 this.el.addClass('open');
26001 Roo.get(document).on("mouseup", this.onMouseUp, this);
26003 this.fireEvent("show", this);
26010 this.fireEvent("beforehide", this);
26012 this.hidden = true;
26013 this.el.removeClass('open');
26015 Roo.get(document).un("mouseup", this.onMouseUp);
26017 this.fireEvent("hide", this);
26020 onMouseUp : function()
26034 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
26037 * @class Roo.bootstrap.menu.Item
26038 * @extends Roo.bootstrap.Component
26039 * Bootstrap MenuItem class
26040 * @cfg {Boolean} submenu (true | false) default false
26041 * @cfg {String} html text of the item
26042 * @cfg {String} href the link
26043 * @cfg {Boolean} disable (true | false) default false
26044 * @cfg {Boolean} preventDefault (true | false) default true
26045 * @cfg {String} icon Font awesome icon
26046 * @cfg {String} pos Submenu align to (left | right) default right
26050 * Create a new Item
26051 * @param {Object} config The config object
26055 Roo.bootstrap.menu.Item = function(config){
26056 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
26060 * Fires when the mouse is hovering over this menu
26061 * @param {Roo.bootstrap.menu.Item} this
26062 * @param {Roo.EventObject} e
26067 * Fires when the mouse exits this menu
26068 * @param {Roo.bootstrap.menu.Item} this
26069 * @param {Roo.EventObject} e
26075 * The raw click event for the entire grid.
26076 * @param {Roo.EventObject} e
26082 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
26087 preventDefault: true,
26092 getAutoCreate : function()
26097 cls : 'roo-menu-item-text',
26105 cls : 'fa ' + this.icon
26114 href : this.href || '#',
26121 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
26125 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
26127 if(this.pos == 'left'){
26128 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
26135 initEvents : function()
26137 this.el.on('mouseover', this.onMouseOver, this);
26138 this.el.on('mouseout', this.onMouseOut, this);
26140 this.el.select('a', true).first().on('click', this.onClick, this);
26144 onClick : function(e)
26146 if(this.preventDefault){
26147 e.preventDefault();
26150 this.fireEvent("click", this, e);
26153 onMouseOver : function(e)
26155 if(this.submenu && this.pos == 'left'){
26156 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
26159 this.fireEvent("mouseover", this, e);
26162 onMouseOut : function(e)
26164 this.fireEvent("mouseout", this, e);
26176 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
26179 * @class Roo.bootstrap.menu.Separator
26180 * @extends Roo.bootstrap.Component
26181 * Bootstrap Separator class
26184 * Create a new Separator
26185 * @param {Object} config The config object
26189 Roo.bootstrap.menu.Separator = function(config){
26190 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
26193 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
26195 getAutoCreate : function(){
26216 * @class Roo.bootstrap.Tooltip
26217 * Bootstrap Tooltip class
26218 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
26219 * to determine which dom element triggers the tooltip.
26221 * It needs to add support for additional attributes like tooltip-position
26224 * Create a new Toolti
26225 * @param {Object} config The config object
26228 Roo.bootstrap.Tooltip = function(config){
26229 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
26231 this.alignment = Roo.bootstrap.Tooltip.alignment;
26233 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
26234 this.alignment = config.alignment;
26239 Roo.apply(Roo.bootstrap.Tooltip, {
26241 * @function init initialize tooltip monitoring.
26245 currentTip : false,
26246 currentRegion : false,
26252 Roo.get(document).on('mouseover', this.enter ,this);
26253 Roo.get(document).on('mouseout', this.leave, this);
26256 this.currentTip = new Roo.bootstrap.Tooltip();
26259 enter : function(ev)
26261 var dom = ev.getTarget();
26263 //Roo.log(['enter',dom]);
26264 var el = Roo.fly(dom);
26265 if (this.currentEl) {
26267 //Roo.log(this.currentEl);
26268 //Roo.log(this.currentEl.contains(dom));
26269 if (this.currentEl == el) {
26272 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
26278 if (this.currentTip.el) {
26279 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
26283 if(!el || el.dom == document){
26289 // you can not look for children, as if el is the body.. then everythign is the child..
26290 if (!el.attr('tooltip')) { //
26291 if (!el.select("[tooltip]").elements.length) {
26294 // is the mouse over this child...?
26295 bindEl = el.select("[tooltip]").first();
26296 var xy = ev.getXY();
26297 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
26298 //Roo.log("not in region.");
26301 //Roo.log("child element over..");
26304 this.currentEl = bindEl;
26305 this.currentTip.bind(bindEl);
26306 this.currentRegion = Roo.lib.Region.getRegion(dom);
26307 this.currentTip.enter();
26310 leave : function(ev)
26312 var dom = ev.getTarget();
26313 //Roo.log(['leave',dom]);
26314 if (!this.currentEl) {
26319 if (dom != this.currentEl.dom) {
26322 var xy = ev.getXY();
26323 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
26326 // only activate leave if mouse cursor is outside... bounding box..
26331 if (this.currentTip) {
26332 this.currentTip.leave();
26334 //Roo.log('clear currentEl');
26335 this.currentEl = false;
26340 'left' : ['r-l', [-2,0], 'right'],
26341 'right' : ['l-r', [2,0], 'left'],
26342 'bottom' : ['t-b', [0,2], 'top'],
26343 'top' : [ 'b-t', [0,-2], 'bottom']
26349 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
26354 delay : null, // can be { show : 300 , hide: 500}
26358 hoverState : null, //???
26360 placement : 'bottom',
26364 getAutoCreate : function(){
26371 cls : 'tooltip-arrow'
26374 cls : 'tooltip-inner'
26381 bind : function(el)
26387 enter : function () {
26389 if (this.timeout != null) {
26390 clearTimeout(this.timeout);
26393 this.hoverState = 'in';
26394 //Roo.log("enter - show");
26395 if (!this.delay || !this.delay.show) {
26400 this.timeout = setTimeout(function () {
26401 if (_t.hoverState == 'in') {
26404 }, this.delay.show);
26408 clearTimeout(this.timeout);
26410 this.hoverState = 'out';
26411 if (!this.delay || !this.delay.hide) {
26417 this.timeout = setTimeout(function () {
26418 //Roo.log("leave - timeout");
26420 if (_t.hoverState == 'out') {
26422 Roo.bootstrap.Tooltip.currentEl = false;
26427 show : function (msg)
26430 this.render(document.body);
26433 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
26435 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
26437 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
26439 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
26441 var placement = typeof this.placement == 'function' ?
26442 this.placement.call(this, this.el, on_el) :
26445 var autoToken = /\s?auto?\s?/i;
26446 var autoPlace = autoToken.test(placement);
26448 placement = placement.replace(autoToken, '') || 'top';
26452 //this.el.setXY([0,0]);
26454 //this.el.dom.style.display='block';
26456 //this.el.appendTo(on_el);
26458 var p = this.getPosition();
26459 var box = this.el.getBox();
26465 var align = this.alignment[placement];
26467 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
26469 if(placement == 'top' || placement == 'bottom'){
26471 placement = 'right';
26474 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
26475 placement = 'left';
26478 var scroll = Roo.select('body', true).first().getScroll();
26480 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
26484 align = this.alignment[placement];
26487 this.el.alignTo(this.bindEl, align[0],align[1]);
26488 //var arrow = this.el.select('.arrow',true).first();
26489 //arrow.set(align[2],
26491 this.el.addClass(placement);
26493 this.el.addClass('in fade');
26495 this.hoverState = null;
26497 if (this.el.hasClass('fade')) {
26508 //this.el.setXY([0,0]);
26509 this.el.removeClass('in');
26525 * @class Roo.bootstrap.LocationPicker
26526 * @extends Roo.bootstrap.Component
26527 * Bootstrap LocationPicker class
26528 * @cfg {Number} latitude Position when init default 0
26529 * @cfg {Number} longitude Position when init default 0
26530 * @cfg {Number} zoom default 15
26531 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
26532 * @cfg {Boolean} mapTypeControl default false
26533 * @cfg {Boolean} disableDoubleClickZoom default false
26534 * @cfg {Boolean} scrollwheel default true
26535 * @cfg {Boolean} streetViewControl default false
26536 * @cfg {Number} radius default 0
26537 * @cfg {String} locationName
26538 * @cfg {Boolean} draggable default true
26539 * @cfg {Boolean} enableAutocomplete default false
26540 * @cfg {Boolean} enableReverseGeocode default true
26541 * @cfg {String} markerTitle
26544 * Create a new LocationPicker
26545 * @param {Object} config The config object
26549 Roo.bootstrap.LocationPicker = function(config){
26551 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
26556 * Fires when the picker initialized.
26557 * @param {Roo.bootstrap.LocationPicker} this
26558 * @param {Google Location} location
26562 * @event positionchanged
26563 * Fires when the picker position changed.
26564 * @param {Roo.bootstrap.LocationPicker} this
26565 * @param {Google Location} location
26567 positionchanged : true,
26570 * Fires when the map resize.
26571 * @param {Roo.bootstrap.LocationPicker} this
26576 * Fires when the map show.
26577 * @param {Roo.bootstrap.LocationPicker} this
26582 * Fires when the map hide.
26583 * @param {Roo.bootstrap.LocationPicker} this
26588 * Fires when click the map.
26589 * @param {Roo.bootstrap.LocationPicker} this
26590 * @param {Map event} e
26594 * @event mapRightClick
26595 * Fires when right click the map.
26596 * @param {Roo.bootstrap.LocationPicker} this
26597 * @param {Map event} e
26599 mapRightClick : true,
26601 * @event markerClick
26602 * Fires when click the marker.
26603 * @param {Roo.bootstrap.LocationPicker} this
26604 * @param {Map event} e
26606 markerClick : true,
26608 * @event markerRightClick
26609 * Fires when right click the marker.
26610 * @param {Roo.bootstrap.LocationPicker} this
26611 * @param {Map event} e
26613 markerRightClick : true,
26615 * @event OverlayViewDraw
26616 * Fires when OverlayView Draw
26617 * @param {Roo.bootstrap.LocationPicker} this
26619 OverlayViewDraw : true,
26621 * @event OverlayViewOnAdd
26622 * Fires when OverlayView Draw
26623 * @param {Roo.bootstrap.LocationPicker} this
26625 OverlayViewOnAdd : true,
26627 * @event OverlayViewOnRemove
26628 * Fires when OverlayView Draw
26629 * @param {Roo.bootstrap.LocationPicker} this
26631 OverlayViewOnRemove : true,
26633 * @event OverlayViewShow
26634 * Fires when OverlayView Draw
26635 * @param {Roo.bootstrap.LocationPicker} this
26636 * @param {Pixel} cpx
26638 OverlayViewShow : true,
26640 * @event OverlayViewHide
26641 * Fires when OverlayView Draw
26642 * @param {Roo.bootstrap.LocationPicker} this
26644 OverlayViewHide : true,
26646 * @event loadexception
26647 * Fires when load google lib failed.
26648 * @param {Roo.bootstrap.LocationPicker} this
26650 loadexception : true
26655 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
26657 gMapContext: false,
26663 mapTypeControl: false,
26664 disableDoubleClickZoom: false,
26666 streetViewControl: false,
26670 enableAutocomplete: false,
26671 enableReverseGeocode: true,
26674 getAutoCreate: function()
26679 cls: 'roo-location-picker'
26685 initEvents: function(ct, position)
26687 if(!this.el.getWidth() || this.isApplied()){
26691 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26696 initial: function()
26698 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
26699 this.fireEvent('loadexception', this);
26703 if(!this.mapTypeId){
26704 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
26707 this.gMapContext = this.GMapContext();
26709 this.initOverlayView();
26711 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
26715 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
26716 _this.setPosition(_this.gMapContext.marker.position);
26719 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
26720 _this.fireEvent('mapClick', this, event);
26724 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
26725 _this.fireEvent('mapRightClick', this, event);
26729 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
26730 _this.fireEvent('markerClick', this, event);
26734 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
26735 _this.fireEvent('markerRightClick', this, event);
26739 this.setPosition(this.gMapContext.location);
26741 this.fireEvent('initial', this, this.gMapContext.location);
26744 initOverlayView: function()
26748 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
26752 _this.fireEvent('OverlayViewDraw', _this);
26757 _this.fireEvent('OverlayViewOnAdd', _this);
26760 onRemove: function()
26762 _this.fireEvent('OverlayViewOnRemove', _this);
26765 show: function(cpx)
26767 _this.fireEvent('OverlayViewShow', _this, cpx);
26772 _this.fireEvent('OverlayViewHide', _this);
26778 fromLatLngToContainerPixel: function(event)
26780 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
26783 isApplied: function()
26785 return this.getGmapContext() == false ? false : true;
26788 getGmapContext: function()
26790 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
26793 GMapContext: function()
26795 var position = new google.maps.LatLng(this.latitude, this.longitude);
26797 var _map = new google.maps.Map(this.el.dom, {
26800 mapTypeId: this.mapTypeId,
26801 mapTypeControl: this.mapTypeControl,
26802 disableDoubleClickZoom: this.disableDoubleClickZoom,
26803 scrollwheel: this.scrollwheel,
26804 streetViewControl: this.streetViewControl,
26805 locationName: this.locationName,
26806 draggable: this.draggable,
26807 enableAutocomplete: this.enableAutocomplete,
26808 enableReverseGeocode: this.enableReverseGeocode
26811 var _marker = new google.maps.Marker({
26812 position: position,
26814 title: this.markerTitle,
26815 draggable: this.draggable
26822 location: position,
26823 radius: this.radius,
26824 locationName: this.locationName,
26825 addressComponents: {
26826 formatted_address: null,
26827 addressLine1: null,
26828 addressLine2: null,
26830 streetNumber: null,
26834 stateOrProvince: null
26837 domContainer: this.el.dom,
26838 geodecoder: new google.maps.Geocoder()
26842 drawCircle: function(center, radius, options)
26844 if (this.gMapContext.circle != null) {
26845 this.gMapContext.circle.setMap(null);
26849 options = Roo.apply({}, options, {
26850 strokeColor: "#0000FF",
26851 strokeOpacity: .35,
26853 fillColor: "#0000FF",
26857 options.map = this.gMapContext.map;
26858 options.radius = radius;
26859 options.center = center;
26860 this.gMapContext.circle = new google.maps.Circle(options);
26861 return this.gMapContext.circle;
26867 setPosition: function(location)
26869 this.gMapContext.location = location;
26870 this.gMapContext.marker.setPosition(location);
26871 this.gMapContext.map.panTo(location);
26872 this.drawCircle(location, this.gMapContext.radius, {});
26876 if (this.gMapContext.settings.enableReverseGeocode) {
26877 this.gMapContext.geodecoder.geocode({
26878 latLng: this.gMapContext.location
26879 }, function(results, status) {
26881 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
26882 _this.gMapContext.locationName = results[0].formatted_address;
26883 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
26885 _this.fireEvent('positionchanged', this, location);
26892 this.fireEvent('positionchanged', this, location);
26897 google.maps.event.trigger(this.gMapContext.map, "resize");
26899 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
26901 this.fireEvent('resize', this);
26904 setPositionByLatLng: function(latitude, longitude)
26906 this.setPosition(new google.maps.LatLng(latitude, longitude));
26909 getCurrentPosition: function()
26912 latitude: this.gMapContext.location.lat(),
26913 longitude: this.gMapContext.location.lng()
26917 getAddressName: function()
26919 return this.gMapContext.locationName;
26922 getAddressComponents: function()
26924 return this.gMapContext.addressComponents;
26927 address_component_from_google_geocode: function(address_components)
26931 for (var i = 0; i < address_components.length; i++) {
26932 var component = address_components[i];
26933 if (component.types.indexOf("postal_code") >= 0) {
26934 result.postalCode = component.short_name;
26935 } else if (component.types.indexOf("street_number") >= 0) {
26936 result.streetNumber = component.short_name;
26937 } else if (component.types.indexOf("route") >= 0) {
26938 result.streetName = component.short_name;
26939 } else if (component.types.indexOf("neighborhood") >= 0) {
26940 result.city = component.short_name;
26941 } else if (component.types.indexOf("locality") >= 0) {
26942 result.city = component.short_name;
26943 } else if (component.types.indexOf("sublocality") >= 0) {
26944 result.district = component.short_name;
26945 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
26946 result.stateOrProvince = component.short_name;
26947 } else if (component.types.indexOf("country") >= 0) {
26948 result.country = component.short_name;
26952 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
26953 result.addressLine2 = "";
26957 setZoomLevel: function(zoom)
26959 this.gMapContext.map.setZoom(zoom);
26972 this.fireEvent('show', this);
26983 this.fireEvent('hide', this);
26988 Roo.apply(Roo.bootstrap.LocationPicker, {
26990 OverlayView : function(map, options)
26992 options = options || {};
27006 * @class Roo.bootstrap.Alert
27007 * @extends Roo.bootstrap.Component
27008 * Bootstrap Alert class
27009 * @cfg {String} title The title of alert
27010 * @cfg {String} html The content of alert
27011 * @cfg {String} weight ( success | info | warning | danger )
27012 * @cfg {String} faicon font-awesomeicon
27015 * Create a new alert
27016 * @param {Object} config The config object
27020 Roo.bootstrap.Alert = function(config){
27021 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
27025 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
27032 getAutoCreate : function()
27041 cls : 'roo-alert-icon'
27046 cls : 'roo-alert-title',
27051 cls : 'roo-alert-text',
27058 cfg.cn[0].cls += ' fa ' + this.faicon;
27062 cfg.cls += ' alert-' + this.weight;
27068 initEvents: function()
27070 this.el.setVisibilityMode(Roo.Element.DISPLAY);
27073 setTitle : function(str)
27075 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
27078 setText : function(str)
27080 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
27083 setWeight : function(weight)
27086 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
27089 this.weight = weight;
27091 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
27094 setIcon : function(icon)
27097 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
27100 this.faicon = icon;
27102 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
27123 * @class Roo.bootstrap.UploadCropbox
27124 * @extends Roo.bootstrap.Component
27125 * Bootstrap UploadCropbox class
27126 * @cfg {String} emptyText show when image has been loaded
27127 * @cfg {String} rotateNotify show when image too small to rotate
27128 * @cfg {Number} errorTimeout default 3000
27129 * @cfg {Number} minWidth default 300
27130 * @cfg {Number} minHeight default 300
27131 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
27132 * @cfg {Boolean} isDocument (true|false) default false
27133 * @cfg {String} url action url
27134 * @cfg {String} paramName default 'imageUpload'
27135 * @cfg {String} method default POST
27136 * @cfg {Boolean} loadMask (true|false) default true
27137 * @cfg {Boolean} loadingText default 'Loading...'
27140 * Create a new UploadCropbox
27141 * @param {Object} config The config object
27144 Roo.bootstrap.UploadCropbox = function(config){
27145 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
27149 * @event beforeselectfile
27150 * Fire before select file
27151 * @param {Roo.bootstrap.UploadCropbox} this
27153 "beforeselectfile" : true,
27156 * Fire after initEvent
27157 * @param {Roo.bootstrap.UploadCropbox} this
27162 * Fire after initEvent
27163 * @param {Roo.bootstrap.UploadCropbox} this
27164 * @param {String} data
27169 * Fire when preparing the file data
27170 * @param {Roo.bootstrap.UploadCropbox} this
27171 * @param {Object} file
27176 * Fire when get exception
27177 * @param {Roo.bootstrap.UploadCropbox} this
27178 * @param {XMLHttpRequest} xhr
27180 "exception" : true,
27182 * @event beforeloadcanvas
27183 * Fire before load the canvas
27184 * @param {Roo.bootstrap.UploadCropbox} this
27185 * @param {String} src
27187 "beforeloadcanvas" : true,
27190 * Fire when trash image
27191 * @param {Roo.bootstrap.UploadCropbox} this
27196 * Fire when download the image
27197 * @param {Roo.bootstrap.UploadCropbox} this
27201 * @event footerbuttonclick
27202 * Fire when footerbuttonclick
27203 * @param {Roo.bootstrap.UploadCropbox} this
27204 * @param {String} type
27206 "footerbuttonclick" : true,
27210 * @param {Roo.bootstrap.UploadCropbox} this
27215 * Fire when rotate the image
27216 * @param {Roo.bootstrap.UploadCropbox} this
27217 * @param {String} pos
27222 * Fire when inspect the file
27223 * @param {Roo.bootstrap.UploadCropbox} this
27224 * @param {Object} file
27229 * Fire when xhr upload the file
27230 * @param {Roo.bootstrap.UploadCropbox} this
27231 * @param {Object} data
27236 * Fire when arrange the file data
27237 * @param {Roo.bootstrap.UploadCropbox} this
27238 * @param {Object} formData
27243 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
27246 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
27248 emptyText : 'Click to upload image',
27249 rotateNotify : 'Image is too small to rotate',
27250 errorTimeout : 3000,
27264 cropType : 'image/jpeg',
27266 canvasLoaded : false,
27267 isDocument : false,
27269 paramName : 'imageUpload',
27271 loadingText : 'Loading...',
27274 getAutoCreate : function()
27278 cls : 'roo-upload-cropbox',
27282 cls : 'roo-upload-cropbox-selector',
27287 cls : 'roo-upload-cropbox-body',
27288 style : 'cursor:pointer',
27292 cls : 'roo-upload-cropbox-preview'
27296 cls : 'roo-upload-cropbox-thumb'
27300 cls : 'roo-upload-cropbox-empty-notify',
27301 html : this.emptyText
27305 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
27306 html : this.rotateNotify
27312 cls : 'roo-upload-cropbox-footer',
27315 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
27325 onRender : function(ct, position)
27327 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
27329 if (this.buttons.length) {
27331 Roo.each(this.buttons, function(bb) {
27333 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
27335 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
27341 this.maskEl = this.el;
27345 initEvents : function()
27347 this.urlAPI = (window.createObjectURL && window) ||
27348 (window.URL && URL.revokeObjectURL && URL) ||
27349 (window.webkitURL && webkitURL);
27351 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
27352 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27354 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
27355 this.selectorEl.hide();
27357 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
27358 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27360 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
27361 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27362 this.thumbEl.hide();
27364 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
27365 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27367 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
27368 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27369 this.errorEl.hide();
27371 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
27372 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27373 this.footerEl.hide();
27375 this.setThumbBoxSize();
27381 this.fireEvent('initial', this);
27388 window.addEventListener("resize", function() { _this.resize(); } );
27390 this.bodyEl.on('click', this.beforeSelectFile, this);
27393 this.bodyEl.on('touchstart', this.onTouchStart, this);
27394 this.bodyEl.on('touchmove', this.onTouchMove, this);
27395 this.bodyEl.on('touchend', this.onTouchEnd, this);
27399 this.bodyEl.on('mousedown', this.onMouseDown, this);
27400 this.bodyEl.on('mousemove', this.onMouseMove, this);
27401 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
27402 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
27403 Roo.get(document).on('mouseup', this.onMouseUp, this);
27406 this.selectorEl.on('change', this.onFileSelected, this);
27412 this.baseScale = 1;
27414 this.baseRotate = 1;
27415 this.dragable = false;
27416 this.pinching = false;
27419 this.cropData = false;
27420 this.notifyEl.dom.innerHTML = this.emptyText;
27422 this.selectorEl.dom.value = '';
27426 resize : function()
27428 if(this.fireEvent('resize', this) != false){
27429 this.setThumbBoxPosition();
27430 this.setCanvasPosition();
27434 onFooterButtonClick : function(e, el, o, type)
27437 case 'rotate-left' :
27438 this.onRotateLeft(e);
27440 case 'rotate-right' :
27441 this.onRotateRight(e);
27444 this.beforeSelectFile(e);
27459 this.fireEvent('footerbuttonclick', this, type);
27462 beforeSelectFile : function(e)
27464 e.preventDefault();
27466 if(this.fireEvent('beforeselectfile', this) != false){
27467 this.selectorEl.dom.click();
27471 onFileSelected : function(e)
27473 e.preventDefault();
27475 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
27479 var file = this.selectorEl.dom.files[0];
27481 if(this.fireEvent('inspect', this, file) != false){
27482 this.prepare(file);
27487 trash : function(e)
27489 this.fireEvent('trash', this);
27492 download : function(e)
27494 this.fireEvent('download', this);
27497 loadCanvas : function(src)
27499 if(this.fireEvent('beforeloadcanvas', this, src) != false){
27503 this.imageEl = document.createElement('img');
27507 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
27509 this.imageEl.src = src;
27513 onLoadCanvas : function()
27515 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
27516 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
27518 this.bodyEl.un('click', this.beforeSelectFile, this);
27520 this.notifyEl.hide();
27521 this.thumbEl.show();
27522 this.footerEl.show();
27524 this.baseRotateLevel();
27526 if(this.isDocument){
27527 this.setThumbBoxSize();
27530 this.setThumbBoxPosition();
27532 this.baseScaleLevel();
27538 this.canvasLoaded = true;
27541 this.maskEl.unmask();
27546 setCanvasPosition : function()
27548 if(!this.canvasEl){
27552 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
27553 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
27555 this.previewEl.setLeft(pw);
27556 this.previewEl.setTop(ph);
27560 onMouseDown : function(e)
27564 this.dragable = true;
27565 this.pinching = false;
27567 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
27568 this.dragable = false;
27572 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27573 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27577 onMouseMove : function(e)
27581 if(!this.canvasLoaded){
27585 if (!this.dragable){
27589 var minX = Math.ceil(this.thumbEl.getLeft(true));
27590 var minY = Math.ceil(this.thumbEl.getTop(true));
27592 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
27593 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
27595 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27596 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27598 x = x - this.mouseX;
27599 y = y - this.mouseY;
27601 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
27602 var bgY = Math.ceil(y + this.previewEl.getTop(true));
27604 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
27605 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
27607 this.previewEl.setLeft(bgX);
27608 this.previewEl.setTop(bgY);
27610 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27611 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27614 onMouseUp : function(e)
27618 this.dragable = false;
27621 onMouseWheel : function(e)
27625 this.startScale = this.scale;
27627 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
27629 if(!this.zoomable()){
27630 this.scale = this.startScale;
27639 zoomable : function()
27641 var minScale = this.thumbEl.getWidth() / this.minWidth;
27643 if(this.minWidth < this.minHeight){
27644 minScale = this.thumbEl.getHeight() / this.minHeight;
27647 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
27648 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
27652 (this.rotate == 0 || this.rotate == 180) &&
27654 width > this.imageEl.OriginWidth ||
27655 height > this.imageEl.OriginHeight ||
27656 (width < this.minWidth && height < this.minHeight)
27664 (this.rotate == 90 || this.rotate == 270) &&
27666 width > this.imageEl.OriginWidth ||
27667 height > this.imageEl.OriginHeight ||
27668 (width < this.minHeight && height < this.minWidth)
27675 !this.isDocument &&
27676 (this.rotate == 0 || this.rotate == 180) &&
27678 width < this.minWidth ||
27679 width > this.imageEl.OriginWidth ||
27680 height < this.minHeight ||
27681 height > this.imageEl.OriginHeight
27688 !this.isDocument &&
27689 (this.rotate == 90 || this.rotate == 270) &&
27691 width < this.minHeight ||
27692 width > this.imageEl.OriginWidth ||
27693 height < this.minWidth ||
27694 height > this.imageEl.OriginHeight
27704 onRotateLeft : function(e)
27706 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27708 var minScale = this.thumbEl.getWidth() / this.minWidth;
27710 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27711 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27713 this.startScale = this.scale;
27715 while (this.getScaleLevel() < minScale){
27717 this.scale = this.scale + 1;
27719 if(!this.zoomable()){
27724 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27725 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27730 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27737 this.scale = this.startScale;
27739 this.onRotateFail();
27744 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27746 if(this.isDocument){
27747 this.setThumbBoxSize();
27748 this.setThumbBoxPosition();
27749 this.setCanvasPosition();
27754 this.fireEvent('rotate', this, 'left');
27758 onRotateRight : function(e)
27760 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27762 var minScale = this.thumbEl.getWidth() / this.minWidth;
27764 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27765 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27767 this.startScale = this.scale;
27769 while (this.getScaleLevel() < minScale){
27771 this.scale = this.scale + 1;
27773 if(!this.zoomable()){
27778 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27779 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27784 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27791 this.scale = this.startScale;
27793 this.onRotateFail();
27798 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27800 if(this.isDocument){
27801 this.setThumbBoxSize();
27802 this.setThumbBoxPosition();
27803 this.setCanvasPosition();
27808 this.fireEvent('rotate', this, 'right');
27811 onRotateFail : function()
27813 this.errorEl.show(true);
27817 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
27822 this.previewEl.dom.innerHTML = '';
27824 var canvasEl = document.createElement("canvas");
27826 var contextEl = canvasEl.getContext("2d");
27828 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27829 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27830 var center = this.imageEl.OriginWidth / 2;
27832 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
27833 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27834 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27835 center = this.imageEl.OriginHeight / 2;
27838 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
27840 contextEl.translate(center, center);
27841 contextEl.rotate(this.rotate * Math.PI / 180);
27843 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27845 this.canvasEl = document.createElement("canvas");
27847 this.contextEl = this.canvasEl.getContext("2d");
27849 switch (this.rotate) {
27852 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27853 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27855 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27860 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27861 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27863 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27864 this.contextEl.drawImage(canvasEl, Math.abs(this.canvasEl.width - this.canvasEl.height), 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27868 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27873 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27874 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27876 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27877 this.contextEl.drawImage(canvasEl, 0, Math.abs(this.canvasEl.width - this.canvasEl.height), this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27881 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);
27886 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27887 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27889 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27890 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27894 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);
27901 this.previewEl.appendChild(this.canvasEl);
27903 this.setCanvasPosition();
27908 if(!this.canvasLoaded){
27912 var imageCanvas = document.createElement("canvas");
27914 var imageContext = imageCanvas.getContext("2d");
27916 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27917 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27919 var center = imageCanvas.width / 2;
27921 imageContext.translate(center, center);
27923 imageContext.rotate(this.rotate * Math.PI / 180);
27925 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27927 var canvas = document.createElement("canvas");
27929 var context = canvas.getContext("2d");
27931 canvas.width = this.minWidth;
27932 canvas.height = this.minHeight;
27934 switch (this.rotate) {
27937 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27938 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27940 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27941 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27943 var targetWidth = this.minWidth - 2 * x;
27944 var targetHeight = this.minHeight - 2 * y;
27948 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27949 scale = targetWidth / width;
27952 if(x > 0 && y == 0){
27953 scale = targetHeight / height;
27956 if(x > 0 && y > 0){
27957 scale = targetWidth / width;
27959 if(width < height){
27960 scale = targetHeight / height;
27964 context.scale(scale, scale);
27966 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
27967 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
27969 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
27970 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
27972 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
27977 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
27978 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
27980 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27981 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27983 var targetWidth = this.minWidth - 2 * x;
27984 var targetHeight = this.minHeight - 2 * y;
27988 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27989 scale = targetWidth / width;
27992 if(x > 0 && y == 0){
27993 scale = targetHeight / height;
27996 if(x > 0 && y > 0){
27997 scale = targetWidth / width;
27999 if(width < height){
28000 scale = targetHeight / height;
28004 context.scale(scale, scale);
28006 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28007 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28009 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28010 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28012 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
28014 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28019 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
28020 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
28022 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28023 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28025 var targetWidth = this.minWidth - 2 * x;
28026 var targetHeight = this.minHeight - 2 * y;
28030 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28031 scale = targetWidth / width;
28034 if(x > 0 && y == 0){
28035 scale = targetHeight / height;
28038 if(x > 0 && y > 0){
28039 scale = targetWidth / width;
28041 if(width < height){
28042 scale = targetHeight / height;
28046 context.scale(scale, scale);
28048 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28049 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28051 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28052 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28054 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
28055 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
28057 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28062 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
28063 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
28065 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28066 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28068 var targetWidth = this.minWidth - 2 * x;
28069 var targetHeight = this.minHeight - 2 * y;
28073 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28074 scale = targetWidth / width;
28077 if(x > 0 && y == 0){
28078 scale = targetHeight / height;
28081 if(x > 0 && y > 0){
28082 scale = targetWidth / width;
28084 if(width < height){
28085 scale = targetHeight / height;
28089 context.scale(scale, scale);
28091 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28092 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28094 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28095 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28097 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
28099 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28106 this.cropData = canvas.toDataURL(this.cropType);
28108 if(this.fireEvent('crop', this, this.cropData) !== false){
28109 this.process(this.file, this.cropData);
28116 setThumbBoxSize : function()
28120 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
28121 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
28122 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
28124 this.minWidth = width;
28125 this.minHeight = height;
28127 if(this.rotate == 90 || this.rotate == 270){
28128 this.minWidth = height;
28129 this.minHeight = width;
28134 width = Math.ceil(this.minWidth * height / this.minHeight);
28136 if(this.minWidth > this.minHeight){
28138 height = Math.ceil(this.minHeight * width / this.minWidth);
28141 this.thumbEl.setStyle({
28142 width : width + 'px',
28143 height : height + 'px'
28150 setThumbBoxPosition : function()
28152 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
28153 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
28155 this.thumbEl.setLeft(x);
28156 this.thumbEl.setTop(y);
28160 baseRotateLevel : function()
28162 this.baseRotate = 1;
28165 typeof(this.exif) != 'undefined' &&
28166 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
28167 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
28169 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
28172 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
28176 baseScaleLevel : function()
28180 if(this.isDocument){
28182 if(this.baseRotate == 6 || this.baseRotate == 8){
28184 height = this.thumbEl.getHeight();
28185 this.baseScale = height / this.imageEl.OriginWidth;
28187 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
28188 width = this.thumbEl.getWidth();
28189 this.baseScale = width / this.imageEl.OriginHeight;
28195 height = this.thumbEl.getHeight();
28196 this.baseScale = height / this.imageEl.OriginHeight;
28198 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
28199 width = this.thumbEl.getWidth();
28200 this.baseScale = width / this.imageEl.OriginWidth;
28206 if(this.baseRotate == 6 || this.baseRotate == 8){
28208 width = this.thumbEl.getHeight();
28209 this.baseScale = width / this.imageEl.OriginHeight;
28211 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
28212 height = this.thumbEl.getWidth();
28213 this.baseScale = height / this.imageEl.OriginHeight;
28216 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28217 height = this.thumbEl.getWidth();
28218 this.baseScale = height / this.imageEl.OriginHeight;
28220 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
28221 width = this.thumbEl.getHeight();
28222 this.baseScale = width / this.imageEl.OriginWidth;
28229 width = this.thumbEl.getWidth();
28230 this.baseScale = width / this.imageEl.OriginWidth;
28232 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
28233 height = this.thumbEl.getHeight();
28234 this.baseScale = height / this.imageEl.OriginHeight;
28237 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28239 height = this.thumbEl.getHeight();
28240 this.baseScale = height / this.imageEl.OriginHeight;
28242 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
28243 width = this.thumbEl.getWidth();
28244 this.baseScale = width / this.imageEl.OriginWidth;
28252 getScaleLevel : function()
28254 return this.baseScale * Math.pow(1.1, this.scale);
28257 onTouchStart : function(e)
28259 if(!this.canvasLoaded){
28260 this.beforeSelectFile(e);
28264 var touches = e.browserEvent.touches;
28270 if(touches.length == 1){
28271 this.onMouseDown(e);
28275 if(touches.length != 2){
28281 for(var i = 0, finger; finger = touches[i]; i++){
28282 coords.push(finger.pageX, finger.pageY);
28285 var x = Math.pow(coords[0] - coords[2], 2);
28286 var y = Math.pow(coords[1] - coords[3], 2);
28288 this.startDistance = Math.sqrt(x + y);
28290 this.startScale = this.scale;
28292 this.pinching = true;
28293 this.dragable = false;
28297 onTouchMove : function(e)
28299 if(!this.pinching && !this.dragable){
28303 var touches = e.browserEvent.touches;
28310 this.onMouseMove(e);
28316 for(var i = 0, finger; finger = touches[i]; i++){
28317 coords.push(finger.pageX, finger.pageY);
28320 var x = Math.pow(coords[0] - coords[2], 2);
28321 var y = Math.pow(coords[1] - coords[3], 2);
28323 this.endDistance = Math.sqrt(x + y);
28325 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
28327 if(!this.zoomable()){
28328 this.scale = this.startScale;
28336 onTouchEnd : function(e)
28338 this.pinching = false;
28339 this.dragable = false;
28343 process : function(file, crop)
28346 this.maskEl.mask(this.loadingText);
28349 this.xhr = new XMLHttpRequest();
28351 file.xhr = this.xhr;
28353 this.xhr.open(this.method, this.url, true);
28356 "Accept": "application/json",
28357 "Cache-Control": "no-cache",
28358 "X-Requested-With": "XMLHttpRequest"
28361 for (var headerName in headers) {
28362 var headerValue = headers[headerName];
28364 this.xhr.setRequestHeader(headerName, headerValue);
28370 this.xhr.onload = function()
28372 _this.xhrOnLoad(_this.xhr);
28375 this.xhr.onerror = function()
28377 _this.xhrOnError(_this.xhr);
28380 var formData = new FormData();
28382 formData.append('returnHTML', 'NO');
28385 formData.append('crop', crop);
28388 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
28389 formData.append(this.paramName, file, file.name);
28392 if(typeof(file.filename) != 'undefined'){
28393 formData.append('filename', file.filename);
28396 if(typeof(file.mimetype) != 'undefined'){
28397 formData.append('mimetype', file.mimetype);
28400 if(this.fireEvent('arrange', this, formData) != false){
28401 this.xhr.send(formData);
28405 xhrOnLoad : function(xhr)
28408 this.maskEl.unmask();
28411 if (xhr.readyState !== 4) {
28412 this.fireEvent('exception', this, xhr);
28416 var response = Roo.decode(xhr.responseText);
28418 if(!response.success){
28419 this.fireEvent('exception', this, xhr);
28423 var response = Roo.decode(xhr.responseText);
28425 this.fireEvent('upload', this, response);
28429 xhrOnError : function()
28432 this.maskEl.unmask();
28435 Roo.log('xhr on error');
28437 var response = Roo.decode(xhr.responseText);
28443 prepare : function(file)
28446 this.maskEl.mask(this.loadingText);
28452 if(typeof(file) === 'string'){
28453 this.loadCanvas(file);
28457 if(!file || !this.urlAPI){
28462 this.cropType = file.type;
28466 if(this.fireEvent('prepare', this, this.file) != false){
28468 var reader = new FileReader();
28470 reader.onload = function (e) {
28471 if (e.target.error) {
28472 Roo.log(e.target.error);
28476 var buffer = e.target.result,
28477 dataView = new DataView(buffer),
28479 maxOffset = dataView.byteLength - 4,
28483 if (dataView.getUint16(0) === 0xffd8) {
28484 while (offset < maxOffset) {
28485 markerBytes = dataView.getUint16(offset);
28487 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
28488 markerLength = dataView.getUint16(offset + 2) + 2;
28489 if (offset + markerLength > dataView.byteLength) {
28490 Roo.log('Invalid meta data: Invalid segment size.');
28494 if(markerBytes == 0xffe1){
28495 _this.parseExifData(
28502 offset += markerLength;
28512 var url = _this.urlAPI.createObjectURL(_this.file);
28514 _this.loadCanvas(url);
28519 reader.readAsArrayBuffer(this.file);
28525 parseExifData : function(dataView, offset, length)
28527 var tiffOffset = offset + 10,
28531 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28532 // No Exif data, might be XMP data instead
28536 // Check for the ASCII code for "Exif" (0x45786966):
28537 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28538 // No Exif data, might be XMP data instead
28541 if (tiffOffset + 8 > dataView.byteLength) {
28542 Roo.log('Invalid Exif data: Invalid segment size.');
28545 // Check for the two null bytes:
28546 if (dataView.getUint16(offset + 8) !== 0x0000) {
28547 Roo.log('Invalid Exif data: Missing byte alignment offset.');
28550 // Check the byte alignment:
28551 switch (dataView.getUint16(tiffOffset)) {
28553 littleEndian = true;
28556 littleEndian = false;
28559 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
28562 // Check for the TIFF tag marker (0x002A):
28563 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
28564 Roo.log('Invalid Exif data: Missing TIFF marker.');
28567 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
28568 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
28570 this.parseExifTags(
28573 tiffOffset + dirOffset,
28578 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
28583 if (dirOffset + 6 > dataView.byteLength) {
28584 Roo.log('Invalid Exif data: Invalid directory offset.');
28587 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
28588 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
28589 if (dirEndOffset + 4 > dataView.byteLength) {
28590 Roo.log('Invalid Exif data: Invalid directory size.');
28593 for (i = 0; i < tagsNumber; i += 1) {
28597 dirOffset + 2 + 12 * i, // tag offset
28601 // Return the offset to the next directory:
28602 return dataView.getUint32(dirEndOffset, littleEndian);
28605 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
28607 var tag = dataView.getUint16(offset, littleEndian);
28609 this.exif[tag] = this.getExifValue(
28613 dataView.getUint16(offset + 2, littleEndian), // tag type
28614 dataView.getUint32(offset + 4, littleEndian), // tag length
28619 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
28621 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
28630 Roo.log('Invalid Exif data: Invalid tag type.');
28634 tagSize = tagType.size * length;
28635 // Determine if the value is contained in the dataOffset bytes,
28636 // or if the value at the dataOffset is a pointer to the actual data:
28637 dataOffset = tagSize > 4 ?
28638 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
28639 if (dataOffset + tagSize > dataView.byteLength) {
28640 Roo.log('Invalid Exif data: Invalid data offset.');
28643 if (length === 1) {
28644 return tagType.getValue(dataView, dataOffset, littleEndian);
28647 for (i = 0; i < length; i += 1) {
28648 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
28651 if (tagType.ascii) {
28653 // Concatenate the chars:
28654 for (i = 0; i < values.length; i += 1) {
28656 // Ignore the terminating NULL byte(s):
28657 if (c === '\u0000') {
28669 Roo.apply(Roo.bootstrap.UploadCropbox, {
28671 'Orientation': 0x0112
28675 1: 0, //'top-left',
28677 3: 180, //'bottom-right',
28678 // 4: 'bottom-left',
28680 6: 90, //'right-top',
28681 // 7: 'right-bottom',
28682 8: 270 //'left-bottom'
28686 // byte, 8-bit unsigned int:
28688 getValue: function (dataView, dataOffset) {
28689 return dataView.getUint8(dataOffset);
28693 // ascii, 8-bit byte:
28695 getValue: function (dataView, dataOffset) {
28696 return String.fromCharCode(dataView.getUint8(dataOffset));
28701 // short, 16 bit int:
28703 getValue: function (dataView, dataOffset, littleEndian) {
28704 return dataView.getUint16(dataOffset, littleEndian);
28708 // long, 32 bit int:
28710 getValue: function (dataView, dataOffset, littleEndian) {
28711 return dataView.getUint32(dataOffset, littleEndian);
28715 // rational = two long values, first is numerator, second is denominator:
28717 getValue: function (dataView, dataOffset, littleEndian) {
28718 return dataView.getUint32(dataOffset, littleEndian) /
28719 dataView.getUint32(dataOffset + 4, littleEndian);
28723 // slong, 32 bit signed int:
28725 getValue: function (dataView, dataOffset, littleEndian) {
28726 return dataView.getInt32(dataOffset, littleEndian);
28730 // srational, two slongs, first is numerator, second is denominator:
28732 getValue: function (dataView, dataOffset, littleEndian) {
28733 return dataView.getInt32(dataOffset, littleEndian) /
28734 dataView.getInt32(dataOffset + 4, littleEndian);
28744 cls : 'btn-group roo-upload-cropbox-rotate-left',
28745 action : 'rotate-left',
28749 cls : 'btn btn-default',
28750 html : '<i class="fa fa-undo"></i>'
28756 cls : 'btn-group roo-upload-cropbox-picture',
28757 action : 'picture',
28761 cls : 'btn btn-default',
28762 html : '<i class="fa fa-picture-o"></i>'
28768 cls : 'btn-group roo-upload-cropbox-rotate-right',
28769 action : 'rotate-right',
28773 cls : 'btn btn-default',
28774 html : '<i class="fa fa-repeat"></i>'
28782 cls : 'btn-group roo-upload-cropbox-rotate-left',
28783 action : 'rotate-left',
28787 cls : 'btn btn-default',
28788 html : '<i class="fa fa-undo"></i>'
28794 cls : 'btn-group roo-upload-cropbox-download',
28795 action : 'download',
28799 cls : 'btn btn-default',
28800 html : '<i class="fa fa-download"></i>'
28806 cls : 'btn-group roo-upload-cropbox-crop',
28811 cls : 'btn btn-default',
28812 html : '<i class="fa fa-crop"></i>'
28818 cls : 'btn-group roo-upload-cropbox-trash',
28823 cls : 'btn btn-default',
28824 html : '<i class="fa fa-trash"></i>'
28830 cls : 'btn-group roo-upload-cropbox-rotate-right',
28831 action : 'rotate-right',
28835 cls : 'btn btn-default',
28836 html : '<i class="fa fa-repeat"></i>'
28844 cls : 'btn-group roo-upload-cropbox-rotate-left',
28845 action : 'rotate-left',
28849 cls : 'btn btn-default',
28850 html : '<i class="fa fa-undo"></i>'
28856 cls : 'btn-group roo-upload-cropbox-rotate-right',
28857 action : 'rotate-right',
28861 cls : 'btn btn-default',
28862 html : '<i class="fa fa-repeat"></i>'
28875 * @class Roo.bootstrap.DocumentManager
28876 * @extends Roo.bootstrap.Component
28877 * Bootstrap DocumentManager class
28878 * @cfg {String} paramName default 'imageUpload'
28879 * @cfg {String} toolTipName default 'filename'
28880 * @cfg {String} method default POST
28881 * @cfg {String} url action url
28882 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
28883 * @cfg {Boolean} multiple multiple upload default true
28884 * @cfg {Number} thumbSize default 300
28885 * @cfg {String} fieldLabel
28886 * @cfg {Number} labelWidth default 4
28887 * @cfg {String} labelAlign (left|top) default left
28888 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
28889 * @cfg {Number} labellg set the width of label (1-12)
28890 * @cfg {Number} labelmd set the width of label (1-12)
28891 * @cfg {Number} labelsm set the width of label (1-12)
28892 * @cfg {Number} labelxs set the width of label (1-12)
28895 * Create a new DocumentManager
28896 * @param {Object} config The config object
28899 Roo.bootstrap.DocumentManager = function(config){
28900 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
28903 this.delegates = [];
28908 * Fire when initial the DocumentManager
28909 * @param {Roo.bootstrap.DocumentManager} this
28914 * inspect selected file
28915 * @param {Roo.bootstrap.DocumentManager} this
28916 * @param {File} file
28921 * Fire when xhr load exception
28922 * @param {Roo.bootstrap.DocumentManager} this
28923 * @param {XMLHttpRequest} xhr
28925 "exception" : true,
28927 * @event afterupload
28928 * Fire when xhr load exception
28929 * @param {Roo.bootstrap.DocumentManager} this
28930 * @param {XMLHttpRequest} xhr
28932 "afterupload" : true,
28935 * prepare the form data
28936 * @param {Roo.bootstrap.DocumentManager} this
28937 * @param {Object} formData
28942 * Fire when remove the file
28943 * @param {Roo.bootstrap.DocumentManager} this
28944 * @param {Object} file
28949 * Fire after refresh the file
28950 * @param {Roo.bootstrap.DocumentManager} this
28955 * Fire after click the image
28956 * @param {Roo.bootstrap.DocumentManager} this
28957 * @param {Object} file
28962 * Fire when upload a image and editable set to true
28963 * @param {Roo.bootstrap.DocumentManager} this
28964 * @param {Object} file
28968 * @event beforeselectfile
28969 * Fire before select file
28970 * @param {Roo.bootstrap.DocumentManager} this
28972 "beforeselectfile" : true,
28975 * Fire before process file
28976 * @param {Roo.bootstrap.DocumentManager} this
28977 * @param {Object} file
28981 * @event previewrendered
28982 * Fire when preview rendered
28983 * @param {Roo.bootstrap.DocumentManager} this
28984 * @param {Object} file
28986 "previewrendered" : true,
28989 "previewResize" : true
28994 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
29003 paramName : 'imageUpload',
29004 toolTipName : 'filename',
29007 labelAlign : 'left',
29017 getAutoCreate : function()
29019 var managerWidget = {
29021 cls : 'roo-document-manager',
29025 cls : 'roo-document-manager-selector',
29030 cls : 'roo-document-manager-uploader',
29034 cls : 'roo-document-manager-upload-btn',
29035 html : '<i class="fa fa-plus"></i>'
29046 cls : 'column col-md-12',
29051 if(this.fieldLabel.length){
29056 cls : 'column col-md-12',
29057 html : this.fieldLabel
29061 cls : 'column col-md-12',
29066 if(this.labelAlign == 'left'){
29071 html : this.fieldLabel
29080 if(this.labelWidth > 12){
29081 content[0].style = "width: " + this.labelWidth + 'px';
29084 if(this.labelWidth < 13 && this.labelmd == 0){
29085 this.labelmd = this.labelWidth;
29088 if(this.labellg > 0){
29089 content[0].cls += ' col-lg-' + this.labellg;
29090 content[1].cls += ' col-lg-' + (12 - this.labellg);
29093 if(this.labelmd > 0){
29094 content[0].cls += ' col-md-' + this.labelmd;
29095 content[1].cls += ' col-md-' + (12 - this.labelmd);
29098 if(this.labelsm > 0){
29099 content[0].cls += ' col-sm-' + this.labelsm;
29100 content[1].cls += ' col-sm-' + (12 - this.labelsm);
29103 if(this.labelxs > 0){
29104 content[0].cls += ' col-xs-' + this.labelxs;
29105 content[1].cls += ' col-xs-' + (12 - this.labelxs);
29113 cls : 'row clearfix',
29121 initEvents : function()
29123 this.managerEl = this.el.select('.roo-document-manager', true).first();
29124 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29126 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
29127 this.selectorEl.hide();
29130 this.selectorEl.attr('multiple', 'multiple');
29133 this.selectorEl.on('change', this.onFileSelected, this);
29135 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
29136 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29138 this.uploader.on('click', this.onUploaderClick, this);
29140 this.renderProgressDialog();
29144 window.addEventListener("resize", function() { _this.refresh(); } );
29146 this.fireEvent('initial', this);
29149 renderProgressDialog : function()
29153 this.progressDialog = new Roo.bootstrap.Modal({
29154 cls : 'roo-document-manager-progress-dialog',
29155 allow_close : false,
29165 btnclick : function() {
29166 _this.uploadCancel();
29172 this.progressDialog.render(Roo.get(document.body));
29174 this.progress = new Roo.bootstrap.Progress({
29175 cls : 'roo-document-manager-progress',
29180 this.progress.render(this.progressDialog.getChildContainer());
29182 this.progressBar = new Roo.bootstrap.ProgressBar({
29183 cls : 'roo-document-manager-progress-bar',
29186 aria_valuemax : 12,
29190 this.progressBar.render(this.progress.getChildContainer());
29193 onUploaderClick : function(e)
29195 e.preventDefault();
29197 if(this.fireEvent('beforeselectfile', this) != false){
29198 this.selectorEl.dom.click();
29203 onFileSelected : function(e)
29205 e.preventDefault();
29207 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
29211 Roo.each(this.selectorEl.dom.files, function(file){
29212 if(this.fireEvent('inspect', this, file) != false){
29213 this.files.push(file);
29223 this.selectorEl.dom.value = '';
29225 if(!this.files || !this.files.length){
29229 if(this.boxes > 0 && this.files.length > this.boxes){
29230 this.files = this.files.slice(0, this.boxes);
29233 this.uploader.show();
29235 if(this.boxes > 0 && this.files.length > this.boxes - 1){
29236 this.uploader.hide();
29245 Roo.each(this.files, function(file){
29247 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29248 var f = this.renderPreview(file);
29253 if(file.type.indexOf('image') != -1){
29254 this.delegates.push(
29256 _this.process(file);
29257 }).createDelegate(this)
29265 _this.process(file);
29266 }).createDelegate(this)
29271 this.files = files;
29273 this.delegates = this.delegates.concat(docs);
29275 if(!this.delegates.length){
29280 this.progressBar.aria_valuemax = this.delegates.length;
29287 arrange : function()
29289 if(!this.delegates.length){
29290 this.progressDialog.hide();
29295 var delegate = this.delegates.shift();
29297 this.progressDialog.show();
29299 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
29301 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
29306 refresh : function()
29308 this.uploader.show();
29310 if(this.boxes > 0 && this.files.length > this.boxes - 1){
29311 this.uploader.hide();
29314 Roo.isTouch ? this.closable(false) : this.closable(true);
29316 this.fireEvent('refresh', this);
29319 onRemove : function(e, el, o)
29321 e.preventDefault();
29323 this.fireEvent('remove', this, o);
29327 remove : function(o)
29331 Roo.each(this.files, function(file){
29332 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
29341 this.files = files;
29348 Roo.each(this.files, function(file){
29353 file.target.remove();
29362 onClick : function(e, el, o)
29364 e.preventDefault();
29366 this.fireEvent('click', this, o);
29370 closable : function(closable)
29372 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
29374 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29386 xhrOnLoad : function(xhr)
29388 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29392 if (xhr.readyState !== 4) {
29394 this.fireEvent('exception', this, xhr);
29398 var response = Roo.decode(xhr.responseText);
29400 if(!response.success){
29402 this.fireEvent('exception', this, xhr);
29406 var file = this.renderPreview(response.data);
29408 this.files.push(file);
29412 this.fireEvent('afterupload', this, xhr);
29416 xhrOnError : function(xhr)
29418 Roo.log('xhr on error');
29420 var response = Roo.decode(xhr.responseText);
29427 process : function(file)
29429 if(this.fireEvent('process', this, file) !== false){
29430 if(this.editable && file.type.indexOf('image') != -1){
29431 this.fireEvent('edit', this, file);
29435 this.uploadStart(file, false);
29442 uploadStart : function(file, crop)
29444 this.xhr = new XMLHttpRequest();
29446 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29451 file.xhr = this.xhr;
29453 this.managerEl.createChild({
29455 cls : 'roo-document-manager-loading',
29459 tooltip : file.name,
29460 cls : 'roo-document-manager-thumb',
29461 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29467 this.xhr.open(this.method, this.url, true);
29470 "Accept": "application/json",
29471 "Cache-Control": "no-cache",
29472 "X-Requested-With": "XMLHttpRequest"
29475 for (var headerName in headers) {
29476 var headerValue = headers[headerName];
29478 this.xhr.setRequestHeader(headerName, headerValue);
29484 this.xhr.onload = function()
29486 _this.xhrOnLoad(_this.xhr);
29489 this.xhr.onerror = function()
29491 _this.xhrOnError(_this.xhr);
29494 var formData = new FormData();
29496 formData.append('returnHTML', 'NO');
29499 formData.append('crop', crop);
29502 formData.append(this.paramName, file, file.name);
29509 if(this.fireEvent('prepare', this, formData, options) != false){
29511 if(options.manually){
29515 this.xhr.send(formData);
29519 this.uploadCancel();
29522 uploadCancel : function()
29528 this.delegates = [];
29530 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29537 renderPreview : function(file)
29539 if(typeof(file.target) != 'undefined' && file.target){
29543 var img_src = encodeURI(baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename);
29545 var previewEl = this.managerEl.createChild({
29547 cls : 'roo-document-manager-preview',
29551 tooltip : file[this.toolTipName],
29552 cls : 'roo-document-manager-thumb',
29553 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + img_src + '">'
29558 html : '<i class="fa fa-times-circle"></i>'
29563 var close = previewEl.select('button.close', true).first();
29565 close.on('click', this.onRemove, this, file);
29567 file.target = previewEl;
29569 var image = previewEl.select('img', true).first();
29573 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
29575 image.on('click', this.onClick, this, file);
29577 this.fireEvent('previewrendered', this, file);
29583 onPreviewLoad : function(file, image)
29585 if(typeof(file.target) == 'undefined' || !file.target){
29589 var width = image.dom.naturalWidth || image.dom.width;
29590 var height = image.dom.naturalHeight || image.dom.height;
29592 if(!this.previewResize) {
29596 if(width > height){
29597 file.target.addClass('wide');
29601 file.target.addClass('tall');
29606 uploadFromSource : function(file, crop)
29608 this.xhr = new XMLHttpRequest();
29610 this.managerEl.createChild({
29612 cls : 'roo-document-manager-loading',
29616 tooltip : file.name,
29617 cls : 'roo-document-manager-thumb',
29618 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29624 this.xhr.open(this.method, this.url, true);
29627 "Accept": "application/json",
29628 "Cache-Control": "no-cache",
29629 "X-Requested-With": "XMLHttpRequest"
29632 for (var headerName in headers) {
29633 var headerValue = headers[headerName];
29635 this.xhr.setRequestHeader(headerName, headerValue);
29641 this.xhr.onload = function()
29643 _this.xhrOnLoad(_this.xhr);
29646 this.xhr.onerror = function()
29648 _this.xhrOnError(_this.xhr);
29651 var formData = new FormData();
29653 formData.append('returnHTML', 'NO');
29655 formData.append('crop', crop);
29657 if(typeof(file.filename) != 'undefined'){
29658 formData.append('filename', file.filename);
29661 if(typeof(file.mimetype) != 'undefined'){
29662 formData.append('mimetype', file.mimetype);
29667 if(this.fireEvent('prepare', this, formData) != false){
29668 this.xhr.send(formData);
29678 * @class Roo.bootstrap.DocumentViewer
29679 * @extends Roo.bootstrap.Component
29680 * Bootstrap DocumentViewer class
29681 * @cfg {Boolean} showDownload (true|false) show download button (default true)
29682 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
29685 * Create a new DocumentViewer
29686 * @param {Object} config The config object
29689 Roo.bootstrap.DocumentViewer = function(config){
29690 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
29695 * Fire after initEvent
29696 * @param {Roo.bootstrap.DocumentViewer} this
29702 * @param {Roo.bootstrap.DocumentViewer} this
29707 * Fire after download button
29708 * @param {Roo.bootstrap.DocumentViewer} this
29713 * Fire after trash button
29714 * @param {Roo.bootstrap.DocumentViewer} this
29721 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
29723 showDownload : true,
29727 getAutoCreate : function()
29731 cls : 'roo-document-viewer',
29735 cls : 'roo-document-viewer-body',
29739 cls : 'roo-document-viewer-thumb',
29743 cls : 'roo-document-viewer-image'
29751 cls : 'roo-document-viewer-footer',
29754 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
29758 cls : 'btn-group roo-document-viewer-download',
29762 cls : 'btn btn-default',
29763 html : '<i class="fa fa-download"></i>'
29769 cls : 'btn-group roo-document-viewer-trash',
29773 cls : 'btn btn-default',
29774 html : '<i class="fa fa-trash"></i>'
29787 initEvents : function()
29789 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
29790 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
29792 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
29793 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
29795 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
29796 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
29798 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
29799 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
29801 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
29802 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
29804 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
29805 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
29807 this.bodyEl.on('click', this.onClick, this);
29808 this.downloadBtn.on('click', this.onDownload, this);
29809 this.trashBtn.on('click', this.onTrash, this);
29811 this.downloadBtn.hide();
29812 this.trashBtn.hide();
29814 if(this.showDownload){
29815 this.downloadBtn.show();
29818 if(this.showTrash){
29819 this.trashBtn.show();
29822 if(!this.showDownload && !this.showTrash) {
29823 this.footerEl.hide();
29828 initial : function()
29830 this.fireEvent('initial', this);
29834 onClick : function(e)
29836 e.preventDefault();
29838 this.fireEvent('click', this);
29841 onDownload : function(e)
29843 e.preventDefault();
29845 this.fireEvent('download', this);
29848 onTrash : function(e)
29850 e.preventDefault();
29852 this.fireEvent('trash', this);
29864 * @class Roo.bootstrap.NavProgressBar
29865 * @extends Roo.bootstrap.Component
29866 * Bootstrap NavProgressBar class
29869 * Create a new nav progress bar
29870 * @param {Object} config The config object
29873 Roo.bootstrap.NavProgressBar = function(config){
29874 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
29876 this.bullets = this.bullets || [];
29878 // Roo.bootstrap.NavProgressBar.register(this);
29882 * Fires when the active item changes
29883 * @param {Roo.bootstrap.NavProgressBar} this
29884 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
29885 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
29892 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
29897 getAutoCreate : function()
29899 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
29903 cls : 'roo-navigation-bar-group',
29907 cls : 'roo-navigation-top-bar'
29911 cls : 'roo-navigation-bullets-bar',
29915 cls : 'roo-navigation-bar'
29922 cls : 'roo-navigation-bottom-bar'
29932 initEvents: function()
29937 onRender : function(ct, position)
29939 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
29941 if(this.bullets.length){
29942 Roo.each(this.bullets, function(b){
29951 addItem : function(cfg)
29953 var item = new Roo.bootstrap.NavProgressItem(cfg);
29955 item.parentId = this.id;
29956 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
29959 var top = new Roo.bootstrap.Element({
29961 cls : 'roo-navigation-bar-text'
29964 var bottom = new Roo.bootstrap.Element({
29966 cls : 'roo-navigation-bar-text'
29969 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
29970 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
29972 var topText = new Roo.bootstrap.Element({
29974 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
29977 var bottomText = new Roo.bootstrap.Element({
29979 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
29982 topText.onRender(top.el, null);
29983 bottomText.onRender(bottom.el, null);
29986 item.bottomEl = bottom;
29989 this.barItems.push(item);
29994 getActive : function()
29996 var active = false;
29998 Roo.each(this.barItems, function(v){
30000 if (!v.isActive()) {
30012 setActiveItem : function(item)
30016 Roo.each(this.barItems, function(v){
30017 if (v.rid == item.rid) {
30021 if (v.isActive()) {
30022 v.setActive(false);
30027 item.setActive(true);
30029 this.fireEvent('changed', this, item, prev);
30032 getBarItem: function(rid)
30036 Roo.each(this.barItems, function(e) {
30037 if (e.rid != rid) {
30048 indexOfItem : function(item)
30052 Roo.each(this.barItems, function(v, i){
30054 if (v.rid != item.rid) {
30065 setActiveNext : function()
30067 var i = this.indexOfItem(this.getActive());
30069 if (i > this.barItems.length) {
30073 this.setActiveItem(this.barItems[i+1]);
30076 setActivePrev : function()
30078 var i = this.indexOfItem(this.getActive());
30084 this.setActiveItem(this.barItems[i-1]);
30087 format : function()
30089 if(!this.barItems.length){
30093 var width = 100 / this.barItems.length;
30095 Roo.each(this.barItems, function(i){
30096 i.el.setStyle('width', width + '%');
30097 i.topEl.el.setStyle('width', width + '%');
30098 i.bottomEl.el.setStyle('width', width + '%');
30107 * Nav Progress Item
30112 * @class Roo.bootstrap.NavProgressItem
30113 * @extends Roo.bootstrap.Component
30114 * Bootstrap NavProgressItem class
30115 * @cfg {String} rid the reference id
30116 * @cfg {Boolean} active (true|false) Is item active default false
30117 * @cfg {Boolean} disabled (true|false) Is item active default false
30118 * @cfg {String} html
30119 * @cfg {String} position (top|bottom) text position default bottom
30120 * @cfg {String} icon show icon instead of number
30123 * Create a new NavProgressItem
30124 * @param {Object} config The config object
30126 Roo.bootstrap.NavProgressItem = function(config){
30127 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
30132 * The raw click event for the entire grid.
30133 * @param {Roo.bootstrap.NavProgressItem} this
30134 * @param {Roo.EventObject} e
30141 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
30147 position : 'bottom',
30150 getAutoCreate : function()
30152 var iconCls = 'roo-navigation-bar-item-icon';
30154 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
30158 cls: 'roo-navigation-bar-item',
30168 cfg.cls += ' active';
30171 cfg.cls += ' disabled';
30177 disable : function()
30179 this.setDisabled(true);
30182 enable : function()
30184 this.setDisabled(false);
30187 initEvents: function()
30189 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
30191 this.iconEl.on('click', this.onClick, this);
30194 onClick : function(e)
30196 e.preventDefault();
30202 if(this.fireEvent('click', this, e) === false){
30206 this.parent().setActiveItem(this);
30209 isActive: function ()
30211 return this.active;
30214 setActive : function(state)
30216 if(this.active == state){
30220 this.active = state;
30223 this.el.addClass('active');
30227 this.el.removeClass('active');
30232 setDisabled : function(state)
30234 if(this.disabled == state){
30238 this.disabled = state;
30241 this.el.addClass('disabled');
30245 this.el.removeClass('disabled');
30248 tooltipEl : function()
30250 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
30263 * @class Roo.bootstrap.FieldLabel
30264 * @extends Roo.bootstrap.Component
30265 * Bootstrap FieldLabel class
30266 * @cfg {String} html contents of the element
30267 * @cfg {String} tag tag of the element default label
30268 * @cfg {String} cls class of the element
30269 * @cfg {String} target label target
30270 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
30271 * @cfg {String} invalidClass default "text-warning"
30272 * @cfg {String} validClass default "text-success"
30273 * @cfg {String} iconTooltip default "This field is required"
30274 * @cfg {String} indicatorpos (left|right) default left
30277 * Create a new FieldLabel
30278 * @param {Object} config The config object
30281 Roo.bootstrap.FieldLabel = function(config){
30282 Roo.bootstrap.Element.superclass.constructor.call(this, config);
30287 * Fires after the field has been marked as invalid.
30288 * @param {Roo.form.FieldLabel} this
30289 * @param {String} msg The validation message
30294 * Fires after the field has been validated with no errors.
30295 * @param {Roo.form.FieldLabel} this
30301 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
30308 invalidClass : 'has-warning',
30309 validClass : 'has-success',
30310 iconTooltip : 'This field is required',
30311 indicatorpos : 'left',
30313 getAutoCreate : function(){
30316 if (!this.allowBlank) {
30322 cls : 'roo-bootstrap-field-label ' + this.cls,
30327 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star ' + cls,
30328 tooltip : this.iconTooltip
30337 if(this.indicatorpos == 'right'){
30340 cls : 'roo-bootstrap-field-label ' + this.cls,
30349 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star '+ cls,
30350 tooltip : this.iconTooltip
30359 initEvents: function()
30361 Roo.bootstrap.Element.superclass.initEvents.call(this);
30363 this.indicator = this.indicatorEl();
30365 if(this.indicator){
30366 this.indicator.removeClass('visible');
30367 this.indicator.addClass('invisible');
30370 Roo.bootstrap.FieldLabel.register(this);
30373 indicatorEl : function()
30375 var indicator = this.el.select('i.roo-required-indicator',true).first();
30386 * Mark this field as valid
30388 markValid : function()
30390 if(this.indicator){
30391 this.indicator.removeClass('visible');
30392 this.indicator.addClass('invisible');
30395 this.el.removeClass(this.invalidClass);
30397 this.el.addClass(this.validClass);
30399 this.fireEvent('valid', this);
30403 * Mark this field as invalid
30404 * @param {String} msg The validation message
30406 markInvalid : function(msg)
30408 if(this.indicator){
30409 this.indicator.removeClass('invisible');
30410 this.indicator.addClass('visible');
30413 this.el.removeClass(this.validClass);
30415 this.el.addClass(this.invalidClass);
30417 this.fireEvent('invalid', this, msg);
30423 Roo.apply(Roo.bootstrap.FieldLabel, {
30428 * register a FieldLabel Group
30429 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
30431 register : function(label)
30433 if(this.groups.hasOwnProperty(label.target)){
30437 this.groups[label.target] = label;
30441 * fetch a FieldLabel Group based on the target
30442 * @param {string} target
30443 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
30445 get: function(target) {
30446 if (typeof(this.groups[target]) == 'undefined') {
30450 return this.groups[target] ;
30459 * page DateSplitField.
30465 * @class Roo.bootstrap.DateSplitField
30466 * @extends Roo.bootstrap.Component
30467 * Bootstrap DateSplitField class
30468 * @cfg {string} fieldLabel - the label associated
30469 * @cfg {Number} labelWidth set the width of label (0-12)
30470 * @cfg {String} labelAlign (top|left)
30471 * @cfg {Boolean} dayAllowBlank (true|false) default false
30472 * @cfg {Boolean} monthAllowBlank (true|false) default false
30473 * @cfg {Boolean} yearAllowBlank (true|false) default false
30474 * @cfg {string} dayPlaceholder
30475 * @cfg {string} monthPlaceholder
30476 * @cfg {string} yearPlaceholder
30477 * @cfg {string} dayFormat default 'd'
30478 * @cfg {string} monthFormat default 'm'
30479 * @cfg {string} yearFormat default 'Y'
30480 * @cfg {Number} labellg set the width of label (1-12)
30481 * @cfg {Number} labelmd set the width of label (1-12)
30482 * @cfg {Number} labelsm set the width of label (1-12)
30483 * @cfg {Number} labelxs set the width of label (1-12)
30487 * Create a new DateSplitField
30488 * @param {Object} config The config object
30491 Roo.bootstrap.DateSplitField = function(config){
30492 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
30498 * getting the data of years
30499 * @param {Roo.bootstrap.DateSplitField} this
30500 * @param {Object} years
30505 * getting the data of days
30506 * @param {Roo.bootstrap.DateSplitField} this
30507 * @param {Object} days
30512 * Fires after the field has been marked as invalid.
30513 * @param {Roo.form.Field} this
30514 * @param {String} msg The validation message
30519 * Fires after the field has been validated with no errors.
30520 * @param {Roo.form.Field} this
30526 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
30529 labelAlign : 'top',
30531 dayAllowBlank : false,
30532 monthAllowBlank : false,
30533 yearAllowBlank : false,
30534 dayPlaceholder : '',
30535 monthPlaceholder : '',
30536 yearPlaceholder : '',
30540 isFormField : true,
30546 getAutoCreate : function()
30550 cls : 'row roo-date-split-field-group',
30555 cls : 'form-hidden-field roo-date-split-field-group-value',
30561 var labelCls = 'col-md-12';
30562 var contentCls = 'col-md-4';
30564 if(this.fieldLabel){
30568 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
30572 html : this.fieldLabel
30577 if(this.labelAlign == 'left'){
30579 if(this.labelWidth > 12){
30580 label.style = "width: " + this.labelWidth + 'px';
30583 if(this.labelWidth < 13 && this.labelmd == 0){
30584 this.labelmd = this.labelWidth;
30587 if(this.labellg > 0){
30588 labelCls = ' col-lg-' + this.labellg;
30589 contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
30592 if(this.labelmd > 0){
30593 labelCls = ' col-md-' + this.labelmd;
30594 contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
30597 if(this.labelsm > 0){
30598 labelCls = ' col-sm-' + this.labelsm;
30599 contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
30602 if(this.labelxs > 0){
30603 labelCls = ' col-xs-' + this.labelxs;
30604 contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
30608 label.cls += ' ' + labelCls;
30610 cfg.cn.push(label);
30613 Roo.each(['day', 'month', 'year'], function(t){
30616 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
30623 inputEl: function ()
30625 return this.el.select('.roo-date-split-field-group-value', true).first();
30628 onRender : function(ct, position)
30632 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30634 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
30636 this.dayField = new Roo.bootstrap.ComboBox({
30637 allowBlank : this.dayAllowBlank,
30638 alwaysQuery : true,
30639 displayField : 'value',
30642 forceSelection : true,
30644 placeholder : this.dayPlaceholder,
30645 selectOnFocus : true,
30646 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30647 triggerAction : 'all',
30649 valueField : 'value',
30650 store : new Roo.data.SimpleStore({
30651 data : (function() {
30653 _this.fireEvent('days', _this, days);
30656 fields : [ 'value' ]
30659 select : function (_self, record, index)
30661 _this.setValue(_this.getValue());
30666 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
30668 this.monthField = new Roo.bootstrap.MonthField({
30669 after : '<i class=\"fa fa-calendar\"></i>',
30670 allowBlank : this.monthAllowBlank,
30671 placeholder : this.monthPlaceholder,
30674 render : function (_self)
30676 this.el.select('span.input-group-addon', true).first().on('click', function(e){
30677 e.preventDefault();
30681 select : function (_self, oldvalue, newvalue)
30683 _this.setValue(_this.getValue());
30688 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
30690 this.yearField = new Roo.bootstrap.ComboBox({
30691 allowBlank : this.yearAllowBlank,
30692 alwaysQuery : true,
30693 displayField : 'value',
30696 forceSelection : true,
30698 placeholder : this.yearPlaceholder,
30699 selectOnFocus : true,
30700 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30701 triggerAction : 'all',
30703 valueField : 'value',
30704 store : new Roo.data.SimpleStore({
30705 data : (function() {
30707 _this.fireEvent('years', _this, years);
30710 fields : [ 'value' ]
30713 select : function (_self, record, index)
30715 _this.setValue(_this.getValue());
30720 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
30723 setValue : function(v, format)
30725 this.inputEl.dom.value = v;
30727 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
30729 var d = Date.parseDate(v, f);
30736 this.setDay(d.format(this.dayFormat));
30737 this.setMonth(d.format(this.monthFormat));
30738 this.setYear(d.format(this.yearFormat));
30745 setDay : function(v)
30747 this.dayField.setValue(v);
30748 this.inputEl.dom.value = this.getValue();
30753 setMonth : function(v)
30755 this.monthField.setValue(v, true);
30756 this.inputEl.dom.value = this.getValue();
30761 setYear : function(v)
30763 this.yearField.setValue(v);
30764 this.inputEl.dom.value = this.getValue();
30769 getDay : function()
30771 return this.dayField.getValue();
30774 getMonth : function()
30776 return this.monthField.getValue();
30779 getYear : function()
30781 return this.yearField.getValue();
30784 getValue : function()
30786 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
30788 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
30798 this.inputEl.dom.value = '';
30803 validate : function()
30805 var d = this.dayField.validate();
30806 var m = this.monthField.validate();
30807 var y = this.yearField.validate();
30812 (!this.dayAllowBlank && !d) ||
30813 (!this.monthAllowBlank && !m) ||
30814 (!this.yearAllowBlank && !y)
30819 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
30828 this.markInvalid();
30833 markValid : function()
30836 var label = this.el.select('label', true).first();
30837 var icon = this.el.select('i.fa-star', true).first();
30843 this.fireEvent('valid', this);
30847 * Mark this field as invalid
30848 * @param {String} msg The validation message
30850 markInvalid : function(msg)
30853 var label = this.el.select('label', true).first();
30854 var icon = this.el.select('i.fa-star', true).first();
30856 if(label && !icon){
30857 this.el.select('.roo-date-split-field-label', true).createChild({
30859 cls : 'text-danger fa fa-lg fa-star',
30860 tooltip : 'This field is required',
30861 style : 'margin-right:5px;'
30865 this.fireEvent('invalid', this, msg);
30868 clearInvalid : function()
30870 var label = this.el.select('label', true).first();
30871 var icon = this.el.select('i.fa-star', true).first();
30877 this.fireEvent('valid', this);
30880 getName: function()
30890 * http://masonry.desandro.com
30892 * The idea is to render all the bricks based on vertical width...
30894 * The original code extends 'outlayer' - we might need to use that....
30900 * @class Roo.bootstrap.LayoutMasonry
30901 * @extends Roo.bootstrap.Component
30902 * Bootstrap Layout Masonry class
30905 * Create a new Element
30906 * @param {Object} config The config object
30909 Roo.bootstrap.LayoutMasonry = function(config){
30911 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
30915 Roo.bootstrap.LayoutMasonry.register(this);
30921 * Fire after layout the items
30922 * @param {Roo.bootstrap.LayoutMasonry} this
30923 * @param {Roo.EventObject} e
30930 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
30933 * @cfg {Boolean} isLayoutInstant = no animation?
30935 isLayoutInstant : false, // needed?
30938 * @cfg {Number} boxWidth width of the columns
30943 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
30948 * @cfg {Number} padWidth padding below box..
30953 * @cfg {Number} gutter gutter width..
30958 * @cfg {Number} maxCols maximum number of columns
30964 * @cfg {Boolean} isAutoInitial defalut true
30966 isAutoInitial : true,
30971 * @cfg {Boolean} isHorizontal defalut false
30973 isHorizontal : false,
30975 currentSize : null,
30981 bricks: null, //CompositeElement
30985 _isLayoutInited : false,
30987 // isAlternative : false, // only use for vertical layout...
30990 * @cfg {Number} alternativePadWidth padding below box..
30992 alternativePadWidth : 50,
30994 selectedBrick : [],
30996 getAutoCreate : function(){
30998 var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
31002 cls: 'blog-masonary-wrapper ' + this.cls,
31004 cls : 'mas-boxes masonary'
31011 getChildContainer: function( )
31013 if (this.boxesEl) {
31014 return this.boxesEl;
31017 this.boxesEl = this.el.select('.mas-boxes').first();
31019 return this.boxesEl;
31023 initEvents : function()
31027 if(this.isAutoInitial){
31028 Roo.log('hook children rendered');
31029 this.on('childrenrendered', function() {
31030 Roo.log('children rendered');
31036 initial : function()
31038 this.selectedBrick = [];
31040 this.currentSize = this.el.getBox(true);
31042 Roo.EventManager.onWindowResize(this.resize, this);
31044 if(!this.isAutoInitial){
31052 //this.layout.defer(500,this);
31056 resize : function()
31058 var cs = this.el.getBox(true);
31061 this.currentSize.width == cs.width &&
31062 this.currentSize.x == cs.x &&
31063 this.currentSize.height == cs.height &&
31064 this.currentSize.y == cs.y
31066 Roo.log("no change in with or X or Y");
31070 this.currentSize = cs;
31076 layout : function()
31078 this._resetLayout();
31080 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
31082 this.layoutItems( isInstant );
31084 this._isLayoutInited = true;
31086 this.fireEvent('layout', this);
31090 _resetLayout : function()
31092 if(this.isHorizontal){
31093 this.horizontalMeasureColumns();
31097 this.verticalMeasureColumns();
31101 verticalMeasureColumns : function()
31103 this.getContainerWidth();
31105 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
31106 // this.colWidth = Math.floor(this.containerWidth * 0.8);
31110 var boxWidth = this.boxWidth + this.padWidth;
31112 if(this.containerWidth < this.boxWidth){
31113 boxWidth = this.containerWidth
31116 var containerWidth = this.containerWidth;
31118 var cols = Math.floor(containerWidth / boxWidth);
31120 this.cols = Math.max( cols, 1 );
31122 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
31124 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
31126 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
31128 this.colWidth = boxWidth + avail - this.padWidth;
31130 this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
31131 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
31134 horizontalMeasureColumns : function()
31136 this.getContainerWidth();
31138 var boxWidth = this.boxWidth;
31140 if(this.containerWidth < boxWidth){
31141 boxWidth = this.containerWidth;
31144 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
31146 this.el.setHeight(boxWidth);
31150 getContainerWidth : function()
31152 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
31155 layoutItems : function( isInstant )
31157 Roo.log(this.bricks);
31159 var items = Roo.apply([], this.bricks);
31161 if(this.isHorizontal){
31162 this._horizontalLayoutItems( items , isInstant );
31166 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
31167 // this._verticalAlternativeLayoutItems( items , isInstant );
31171 this._verticalLayoutItems( items , isInstant );
31175 _verticalLayoutItems : function ( items , isInstant)
31177 if ( !items || !items.length ) {
31182 ['xs', 'xs', 'xs', 'tall'],
31183 ['xs', 'xs', 'tall'],
31184 ['xs', 'xs', 'sm'],
31185 ['xs', 'xs', 'xs'],
31191 ['sm', 'xs', 'xs'],
31195 ['tall', 'xs', 'xs', 'xs'],
31196 ['tall', 'xs', 'xs'],
31208 Roo.each(items, function(item, k){
31210 switch (item.size) {
31211 // these layouts take up a full box,
31222 boxes.push([item]);
31245 var filterPattern = function(box, length)
31253 var pattern = box.slice(0, length);
31257 Roo.each(pattern, function(i){
31258 format.push(i.size);
31261 Roo.each(standard, function(s){
31263 if(String(s) != String(format)){
31272 if(!match && length == 1){
31277 filterPattern(box, length - 1);
31281 queue.push(pattern);
31283 box = box.slice(length, box.length);
31285 filterPattern(box, 4);
31291 Roo.each(boxes, function(box, k){
31297 if(box.length == 1){
31302 filterPattern(box, 4);
31306 this._processVerticalLayoutQueue( queue, isInstant );
31310 // _verticalAlternativeLayoutItems : function( items , isInstant )
31312 // if ( !items || !items.length ) {
31316 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
31320 _horizontalLayoutItems : function ( items , isInstant)
31322 if ( !items || !items.length || items.length < 3) {
31328 var eItems = items.slice(0, 3);
31330 items = items.slice(3, items.length);
31333 ['xs', 'xs', 'xs', 'wide'],
31334 ['xs', 'xs', 'wide'],
31335 ['xs', 'xs', 'sm'],
31336 ['xs', 'xs', 'xs'],
31342 ['sm', 'xs', 'xs'],
31346 ['wide', 'xs', 'xs', 'xs'],
31347 ['wide', 'xs', 'xs'],
31360 Roo.each(items, function(item, k){
31362 switch (item.size) {
31373 boxes.push([item]);
31397 var filterPattern = function(box, length)
31405 var pattern = box.slice(0, length);
31409 Roo.each(pattern, function(i){
31410 format.push(i.size);
31413 Roo.each(standard, function(s){
31415 if(String(s) != String(format)){
31424 if(!match && length == 1){
31429 filterPattern(box, length - 1);
31433 queue.push(pattern);
31435 box = box.slice(length, box.length);
31437 filterPattern(box, 4);
31443 Roo.each(boxes, function(box, k){
31449 if(box.length == 1){
31454 filterPattern(box, 4);
31461 var pos = this.el.getBox(true);
31465 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31467 var hit_end = false;
31469 Roo.each(queue, function(box){
31473 Roo.each(box, function(b){
31475 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31485 Roo.each(box, function(b){
31487 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31490 mx = Math.max(mx, b.x);
31494 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
31498 Roo.each(box, function(b){
31500 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31514 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
31517 /** Sets position of item in DOM
31518 * @param {Element} item
31519 * @param {Number} x - horizontal position
31520 * @param {Number} y - vertical position
31521 * @param {Boolean} isInstant - disables transitions
31523 _processVerticalLayoutQueue : function( queue, isInstant )
31525 var pos = this.el.getBox(true);
31530 for (var i = 0; i < this.cols; i++){
31534 Roo.each(queue, function(box, k){
31536 var col = k % this.cols;
31538 Roo.each(box, function(b,kk){
31540 b.el.position('absolute');
31542 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31543 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31545 if(b.size == 'md-left' || b.size == 'md-right'){
31546 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31547 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31550 b.el.setWidth(width);
31551 b.el.setHeight(height);
31553 b.el.select('iframe',true).setSize(width,height);
31557 for (var i = 0; i < this.cols; i++){
31559 if(maxY[i] < maxY[col]){
31564 col = Math.min(col, i);
31568 x = pos.x + col * (this.colWidth + this.padWidth);
31572 var positions = [];
31574 switch (box.length){
31576 positions = this.getVerticalOneBoxColPositions(x, y, box);
31579 positions = this.getVerticalTwoBoxColPositions(x, y, box);
31582 positions = this.getVerticalThreeBoxColPositions(x, y, box);
31585 positions = this.getVerticalFourBoxColPositions(x, y, box);
31591 Roo.each(box, function(b,kk){
31593 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31595 var sz = b.el.getSize();
31597 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
31605 for (var i = 0; i < this.cols; i++){
31606 mY = Math.max(mY, maxY[i]);
31609 this.el.setHeight(mY - pos.y);
31613 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
31615 // var pos = this.el.getBox(true);
31618 // var maxX = pos.right;
31620 // var maxHeight = 0;
31622 // Roo.each(items, function(item, k){
31626 // item.el.position('absolute');
31628 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
31630 // item.el.setWidth(width);
31632 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
31634 // item.el.setHeight(height);
31637 // item.el.setXY([x, y], isInstant ? false : true);
31639 // item.el.setXY([maxX - width, y], isInstant ? false : true);
31642 // y = y + height + this.alternativePadWidth;
31644 // maxHeight = maxHeight + height + this.alternativePadWidth;
31648 // this.el.setHeight(maxHeight);
31652 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
31654 var pos = this.el.getBox(true);
31659 var maxX = pos.right;
31661 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
31663 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31665 Roo.each(queue, function(box, k){
31667 Roo.each(box, function(b, kk){
31669 b.el.position('absolute');
31671 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31672 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31674 if(b.size == 'md-left' || b.size == 'md-right'){
31675 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31676 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31679 b.el.setWidth(width);
31680 b.el.setHeight(height);
31688 var positions = [];
31690 switch (box.length){
31692 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
31695 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
31698 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
31701 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
31707 Roo.each(box, function(b,kk){
31709 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31711 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
31719 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
31721 Roo.each(eItems, function(b,k){
31723 b.size = (k == 0) ? 'sm' : 'xs';
31724 b.x = (k == 0) ? 2 : 1;
31725 b.y = (k == 0) ? 2 : 1;
31727 b.el.position('absolute');
31729 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31731 b.el.setWidth(width);
31733 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31735 b.el.setHeight(height);
31739 var positions = [];
31742 x : maxX - this.unitWidth * 2 - this.gutter,
31747 x : maxX - this.unitWidth,
31748 y : minY + (this.unitWidth + this.gutter) * 2
31752 x : maxX - this.unitWidth * 3 - this.gutter * 2,
31756 Roo.each(eItems, function(b,k){
31758 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
31764 getVerticalOneBoxColPositions : function(x, y, box)
31768 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
31770 if(box[0].size == 'md-left'){
31774 if(box[0].size == 'md-right'){
31779 x : x + (this.unitWidth + this.gutter) * rand,
31786 getVerticalTwoBoxColPositions : function(x, y, box)
31790 if(box[0].size == 'xs'){
31794 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
31798 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
31812 x : x + (this.unitWidth + this.gutter) * 2,
31813 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
31820 getVerticalThreeBoxColPositions : function(x, y, box)
31824 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31832 x : x + (this.unitWidth + this.gutter) * 1,
31837 x : x + (this.unitWidth + this.gutter) * 2,
31845 if(box[0].size == 'xs' && box[1].size == 'xs'){
31854 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
31858 x : x + (this.unitWidth + this.gutter) * 1,
31872 x : x + (this.unitWidth + this.gutter) * 2,
31877 x : x + (this.unitWidth + this.gutter) * 2,
31878 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
31885 getVerticalFourBoxColPositions : function(x, y, box)
31889 if(box[0].size == 'xs'){
31898 y : y + (this.unitHeight + this.gutter) * 1
31903 y : y + (this.unitHeight + this.gutter) * 2
31907 x : x + (this.unitWidth + this.gutter) * 1,
31921 x : x + (this.unitWidth + this.gutter) * 2,
31926 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
31927 y : y + (this.unitHeight + this.gutter) * 1
31931 x : x + (this.unitWidth + this.gutter) * 2,
31932 y : y + (this.unitWidth + this.gutter) * 2
31939 getHorizontalOneBoxColPositions : function(maxX, minY, box)
31943 if(box[0].size == 'md-left'){
31945 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31952 if(box[0].size == 'md-right'){
31954 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31955 y : minY + (this.unitWidth + this.gutter) * 1
31961 var rand = Math.floor(Math.random() * (4 - box[0].y));
31964 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31965 y : minY + (this.unitWidth + this.gutter) * rand
31972 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
31976 if(box[0].size == 'xs'){
31979 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31984 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31985 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
31993 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
31998 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
31999 y : minY + (this.unitWidth + this.gutter) * 2
32006 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
32010 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
32013 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32018 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32019 y : minY + (this.unitWidth + this.gutter) * 1
32023 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32024 y : minY + (this.unitWidth + this.gutter) * 2
32031 if(box[0].size == 'xs' && box[1].size == 'xs'){
32034 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32039 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32044 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32045 y : minY + (this.unitWidth + this.gutter) * 1
32053 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32058 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32059 y : minY + (this.unitWidth + this.gutter) * 2
32063 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32064 y : minY + (this.unitWidth + this.gutter) * 2
32071 getHorizontalFourBoxColPositions : function(maxX, minY, box)
32075 if(box[0].size == 'xs'){
32078 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32083 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32088 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),
32093 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
32094 y : minY + (this.unitWidth + this.gutter) * 1
32102 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32107 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32108 y : minY + (this.unitWidth + this.gutter) * 2
32112 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32113 y : minY + (this.unitWidth + this.gutter) * 2
32117 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),
32118 y : minY + (this.unitWidth + this.gutter) * 2
32126 * remove a Masonry Brick
32127 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
32129 removeBrick : function(brick_id)
32135 for (var i = 0; i<this.bricks.length; i++) {
32136 if (this.bricks[i].id == brick_id) {
32137 this.bricks.splice(i,1);
32138 this.el.dom.removeChild(Roo.get(brick_id).dom);
32145 * adds a Masonry Brick
32146 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32148 addBrick : function(cfg)
32150 var cn = new Roo.bootstrap.MasonryBrick(cfg);
32151 //this.register(cn);
32152 cn.parentId = this.id;
32153 cn.render(this.el);
32158 * register a Masonry Brick
32159 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32162 register : function(brick)
32164 this.bricks.push(brick);
32165 brick.masonryId = this.id;
32169 * clear all the Masonry Brick
32171 clearAll : function()
32174 //this.getChildContainer().dom.innerHTML = "";
32175 this.el.dom.innerHTML = '';
32178 getSelected : function()
32180 if (!this.selectedBrick) {
32184 return this.selectedBrick;
32188 Roo.apply(Roo.bootstrap.LayoutMasonry, {
32192 * register a Masonry Layout
32193 * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
32196 register : function(layout)
32198 this.groups[layout.id] = layout;
32201 * fetch a Masonry Layout based on the masonry layout ID
32202 * @param {string} the masonry layout to add
32203 * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
32206 get: function(layout_id) {
32207 if (typeof(this.groups[layout_id]) == 'undefined') {
32210 return this.groups[layout_id] ;
32222 * http://masonry.desandro.com
32224 * The idea is to render all the bricks based on vertical width...
32226 * The original code extends 'outlayer' - we might need to use that....
32232 * @class Roo.bootstrap.LayoutMasonryAuto
32233 * @extends Roo.bootstrap.Component
32234 * Bootstrap Layout Masonry class
32237 * Create a new Element
32238 * @param {Object} config The config object
32241 Roo.bootstrap.LayoutMasonryAuto = function(config){
32242 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
32245 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
32248 * @cfg {Boolean} isFitWidth - resize the width..
32250 isFitWidth : false, // options..
32252 * @cfg {Boolean} isOriginLeft = left align?
32254 isOriginLeft : true,
32256 * @cfg {Boolean} isOriginTop = top align?
32258 isOriginTop : false,
32260 * @cfg {Boolean} isLayoutInstant = no animation?
32262 isLayoutInstant : false, // needed?
32264 * @cfg {Boolean} isResizingContainer = not sure if this is used..
32266 isResizingContainer : true,
32268 * @cfg {Number} columnWidth width of the columns
32274 * @cfg {Number} maxCols maximum number of columns
32279 * @cfg {Number} padHeight padding below box..
32285 * @cfg {Boolean} isAutoInitial defalut true
32288 isAutoInitial : true,
32294 initialColumnWidth : 0,
32295 currentSize : null,
32297 colYs : null, // array.
32304 bricks: null, //CompositeElement
32305 cols : 0, // array?
32306 // element : null, // wrapped now this.el
32307 _isLayoutInited : null,
32310 getAutoCreate : function(){
32314 cls: 'blog-masonary-wrapper ' + this.cls,
32316 cls : 'mas-boxes masonary'
32323 getChildContainer: function( )
32325 if (this.boxesEl) {
32326 return this.boxesEl;
32329 this.boxesEl = this.el.select('.mas-boxes').first();
32331 return this.boxesEl;
32335 initEvents : function()
32339 if(this.isAutoInitial){
32340 Roo.log('hook children rendered');
32341 this.on('childrenrendered', function() {
32342 Roo.log('children rendered');
32349 initial : function()
32351 this.reloadItems();
32353 this.currentSize = this.el.getBox(true);
32355 /// was window resize... - let's see if this works..
32356 Roo.EventManager.onWindowResize(this.resize, this);
32358 if(!this.isAutoInitial){
32363 this.layout.defer(500,this);
32366 reloadItems: function()
32368 this.bricks = this.el.select('.masonry-brick', true);
32370 this.bricks.each(function(b) {
32371 //Roo.log(b.getSize());
32372 if (!b.attr('originalwidth')) {
32373 b.attr('originalwidth', b.getSize().width);
32378 Roo.log(this.bricks.elements.length);
32381 resize : function()
32384 var cs = this.el.getBox(true);
32386 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
32387 Roo.log("no change in with or X");
32390 this.currentSize = cs;
32394 layout : function()
32397 this._resetLayout();
32398 //this._manageStamps();
32400 // don't animate first layout
32401 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
32402 this.layoutItems( isInstant );
32404 // flag for initalized
32405 this._isLayoutInited = true;
32408 layoutItems : function( isInstant )
32410 //var items = this._getItemsForLayout( this.items );
32411 // original code supports filtering layout items.. we just ignore it..
32413 this._layoutItems( this.bricks , isInstant );
32415 this._postLayout();
32417 _layoutItems : function ( items , isInstant)
32419 //this.fireEvent( 'layout', this, items );
32422 if ( !items || !items.elements.length ) {
32423 // no items, emit event with empty array
32428 items.each(function(item) {
32429 Roo.log("layout item");
32431 // get x/y object from method
32432 var position = this._getItemLayoutPosition( item );
32434 position.item = item;
32435 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
32436 queue.push( position );
32439 this._processLayoutQueue( queue );
32441 /** Sets position of item in DOM
32442 * @param {Element} item
32443 * @param {Number} x - horizontal position
32444 * @param {Number} y - vertical position
32445 * @param {Boolean} isInstant - disables transitions
32447 _processLayoutQueue : function( queue )
32449 for ( var i=0, len = queue.length; i < len; i++ ) {
32450 var obj = queue[i];
32451 obj.item.position('absolute');
32452 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
32458 * Any logic you want to do after each layout,
32459 * i.e. size the container
32461 _postLayout : function()
32463 this.resizeContainer();
32466 resizeContainer : function()
32468 if ( !this.isResizingContainer ) {
32471 var size = this._getContainerSize();
32473 this.el.setSize(size.width,size.height);
32474 this.boxesEl.setSize(size.width,size.height);
32480 _resetLayout : function()
32482 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
32483 this.colWidth = this.el.getWidth();
32484 //this.gutter = this.el.getWidth();
32486 this.measureColumns();
32492 this.colYs.push( 0 );
32498 measureColumns : function()
32500 this.getContainerWidth();
32501 // if columnWidth is 0, default to outerWidth of first item
32502 if ( !this.columnWidth ) {
32503 var firstItem = this.bricks.first();
32504 Roo.log(firstItem);
32505 this.columnWidth = this.containerWidth;
32506 if (firstItem && firstItem.attr('originalwidth') ) {
32507 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
32509 // columnWidth fall back to item of first element
32510 Roo.log("set column width?");
32511 this.initialColumnWidth = this.columnWidth ;
32513 // if first elem has no width, default to size of container
32518 if (this.initialColumnWidth) {
32519 this.columnWidth = this.initialColumnWidth;
32524 // column width is fixed at the top - however if container width get's smaller we should
32527 // this bit calcs how man columns..
32529 var columnWidth = this.columnWidth += this.gutter;
32531 // calculate columns
32532 var containerWidth = this.containerWidth + this.gutter;
32534 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
32535 // fix rounding errors, typically with gutters
32536 var excess = columnWidth - containerWidth % columnWidth;
32539 // if overshoot is less than a pixel, round up, otherwise floor it
32540 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
32541 cols = Math[ mathMethod ]( cols );
32542 this.cols = Math.max( cols, 1 );
32543 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
32545 // padding positioning..
32546 var totalColWidth = this.cols * this.columnWidth;
32547 var padavail = this.containerWidth - totalColWidth;
32548 // so for 2 columns - we need 3 'pads'
32550 var padNeeded = (1+this.cols) * this.padWidth;
32552 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
32554 this.columnWidth += padExtra
32555 //this.padWidth = Math.floor(padavail / ( this.cols));
32557 // adjust colum width so that padding is fixed??
32559 // we have 3 columns ... total = width * 3
32560 // we have X left over... that should be used by
32562 //if (this.expandC) {
32570 getContainerWidth : function()
32572 /* // container is parent if fit width
32573 var container = this.isFitWidth ? this.element.parentNode : this.element;
32574 // check that this.size and size are there
32575 // IE8 triggers resize on body size change, so they might not be
32577 var size = getSize( container ); //FIXME
32578 this.containerWidth = size && size.innerWidth; //FIXME
32581 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
32585 _getItemLayoutPosition : function( item ) // what is item?
32587 // we resize the item to our columnWidth..
32589 item.setWidth(this.columnWidth);
32590 item.autoBoxAdjust = false;
32592 var sz = item.getSize();
32594 // how many columns does this brick span
32595 var remainder = this.containerWidth % this.columnWidth;
32597 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
32598 // round if off by 1 pixel, otherwise use ceil
32599 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
32600 colSpan = Math.min( colSpan, this.cols );
32602 // normally this should be '1' as we dont' currently allow multi width columns..
32604 var colGroup = this._getColGroup( colSpan );
32605 // get the minimum Y value from the columns
32606 var minimumY = Math.min.apply( Math, colGroup );
32607 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32609 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
32611 // position the brick
32613 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
32614 y: this.currentSize.y + minimumY + this.padHeight
32618 // apply setHeight to necessary columns
32619 var setHeight = minimumY + sz.height + this.padHeight;
32620 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32622 var setSpan = this.cols + 1 - colGroup.length;
32623 for ( var i = 0; i < setSpan; i++ ) {
32624 this.colYs[ shortColIndex + i ] = setHeight ;
32631 * @param {Number} colSpan - number of columns the element spans
32632 * @returns {Array} colGroup
32634 _getColGroup : function( colSpan )
32636 if ( colSpan < 2 ) {
32637 // if brick spans only one column, use all the column Ys
32642 // how many different places could this brick fit horizontally
32643 var groupCount = this.cols + 1 - colSpan;
32644 // for each group potential horizontal position
32645 for ( var i = 0; i < groupCount; i++ ) {
32646 // make an array of colY values for that one group
32647 var groupColYs = this.colYs.slice( i, i + colSpan );
32648 // and get the max value of the array
32649 colGroup[i] = Math.max.apply( Math, groupColYs );
32654 _manageStamp : function( stamp )
32656 var stampSize = stamp.getSize();
32657 var offset = stamp.getBox();
32658 // get the columns that this stamp affects
32659 var firstX = this.isOriginLeft ? offset.x : offset.right;
32660 var lastX = firstX + stampSize.width;
32661 var firstCol = Math.floor( firstX / this.columnWidth );
32662 firstCol = Math.max( 0, firstCol );
32664 var lastCol = Math.floor( lastX / this.columnWidth );
32665 // lastCol should not go over if multiple of columnWidth #425
32666 lastCol -= lastX % this.columnWidth ? 0 : 1;
32667 lastCol = Math.min( this.cols - 1, lastCol );
32669 // set colYs to bottom of the stamp
32670 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
32673 for ( var i = firstCol; i <= lastCol; i++ ) {
32674 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
32679 _getContainerSize : function()
32681 this.maxY = Math.max.apply( Math, this.colYs );
32686 if ( this.isFitWidth ) {
32687 size.width = this._getContainerFitWidth();
32693 _getContainerFitWidth : function()
32695 var unusedCols = 0;
32696 // count unused columns
32699 if ( this.colYs[i] !== 0 ) {
32704 // fit container to columns that have been used
32705 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
32708 needsResizeLayout : function()
32710 var previousWidth = this.containerWidth;
32711 this.getContainerWidth();
32712 return previousWidth !== this.containerWidth;
32727 * @class Roo.bootstrap.MasonryBrick
32728 * @extends Roo.bootstrap.Component
32729 * Bootstrap MasonryBrick class
32732 * Create a new MasonryBrick
32733 * @param {Object} config The config object
32736 Roo.bootstrap.MasonryBrick = function(config){
32738 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
32740 Roo.bootstrap.MasonryBrick.register(this);
32746 * When a MasonryBrick is clcik
32747 * @param {Roo.bootstrap.MasonryBrick} this
32748 * @param {Roo.EventObject} e
32754 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
32757 * @cfg {String} title
32761 * @cfg {String} html
32765 * @cfg {String} bgimage
32769 * @cfg {String} videourl
32773 * @cfg {String} cls
32777 * @cfg {String} href
32781 * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
32786 * @cfg {String} placetitle (center|bottom)
32791 * @cfg {Boolean} isFitContainer defalut true
32793 isFitContainer : true,
32796 * @cfg {Boolean} preventDefault defalut false
32798 preventDefault : false,
32801 * @cfg {Boolean} inverse defalut false
32803 maskInverse : false,
32805 getAutoCreate : function()
32807 if(!this.isFitContainer){
32808 return this.getSplitAutoCreate();
32811 var cls = 'masonry-brick masonry-brick-full';
32813 if(this.href.length){
32814 cls += ' masonry-brick-link';
32817 if(this.bgimage.length){
32818 cls += ' masonry-brick-image';
32821 if(this.maskInverse){
32822 cls += ' mask-inverse';
32825 if(!this.html.length && !this.maskInverse && !this.videourl.length){
32826 cls += ' enable-mask';
32830 cls += ' masonry-' + this.size + '-brick';
32833 if(this.placetitle.length){
32835 switch (this.placetitle) {
32837 cls += ' masonry-center-title';
32840 cls += ' masonry-bottom-title';
32847 if(!this.html.length && !this.bgimage.length){
32848 cls += ' masonry-center-title';
32851 if(!this.html.length && this.bgimage.length){
32852 cls += ' masonry-bottom-title';
32857 cls += ' ' + this.cls;
32861 tag: (this.href.length) ? 'a' : 'div',
32866 cls: 'masonry-brick-mask'
32870 cls: 'masonry-brick-paragraph',
32876 if(this.href.length){
32877 cfg.href = this.href;
32880 var cn = cfg.cn[1].cn;
32882 if(this.title.length){
32885 cls: 'masonry-brick-title',
32890 if(this.html.length){
32893 cls: 'masonry-brick-text',
32898 if (!this.title.length && !this.html.length) {
32899 cfg.cn[1].cls += ' hide';
32902 if(this.bgimage.length){
32905 cls: 'masonry-brick-image-view',
32910 if(this.videourl.length){
32911 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32912 // youtube support only?
32915 cls: 'masonry-brick-image-view',
32918 allowfullscreen : true
32926 getSplitAutoCreate : function()
32928 var cls = 'masonry-brick masonry-brick-split';
32930 if(this.href.length){
32931 cls += ' masonry-brick-link';
32934 if(this.bgimage.length){
32935 cls += ' masonry-brick-image';
32939 cls += ' masonry-' + this.size + '-brick';
32942 switch (this.placetitle) {
32944 cls += ' masonry-center-title';
32947 cls += ' masonry-bottom-title';
32950 if(!this.bgimage.length){
32951 cls += ' masonry-center-title';
32954 if(this.bgimage.length){
32955 cls += ' masonry-bottom-title';
32961 cls += ' ' + this.cls;
32965 tag: (this.href.length) ? 'a' : 'div',
32970 cls: 'masonry-brick-split-head',
32974 cls: 'masonry-brick-paragraph',
32981 cls: 'masonry-brick-split-body',
32987 if(this.href.length){
32988 cfg.href = this.href;
32991 if(this.title.length){
32992 cfg.cn[0].cn[0].cn.push({
32994 cls: 'masonry-brick-title',
32999 if(this.html.length){
33000 cfg.cn[1].cn.push({
33002 cls: 'masonry-brick-text',
33007 if(this.bgimage.length){
33008 cfg.cn[0].cn.push({
33010 cls: 'masonry-brick-image-view',
33015 if(this.videourl.length){
33016 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
33017 // youtube support only?
33018 cfg.cn[0].cn.cn.push({
33020 cls: 'masonry-brick-image-view',
33023 allowfullscreen : true
33030 initEvents: function()
33032 switch (this.size) {
33065 this.el.on('touchstart', this.onTouchStart, this);
33066 this.el.on('touchmove', this.onTouchMove, this);
33067 this.el.on('touchend', this.onTouchEnd, this);
33068 this.el.on('contextmenu', this.onContextMenu, this);
33070 this.el.on('mouseenter' ,this.enter, this);
33071 this.el.on('mouseleave', this.leave, this);
33072 this.el.on('click', this.onClick, this);
33075 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
33076 this.parent().bricks.push(this);
33081 onClick: function(e, el)
33083 var time = this.endTimer - this.startTimer;
33084 // Roo.log(e.preventDefault());
33087 e.preventDefault();
33092 if(!this.preventDefault){
33096 e.preventDefault();
33098 if (this.activeClass != '') {
33099 this.selectBrick();
33102 this.fireEvent('click', this, e);
33105 enter: function(e, el)
33107 e.preventDefault();
33109 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
33113 if(this.bgimage.length && this.html.length){
33114 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
33118 leave: function(e, el)
33120 e.preventDefault();
33122 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
33126 if(this.bgimage.length && this.html.length){
33127 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
33131 onTouchStart: function(e, el)
33133 // e.preventDefault();
33135 this.touchmoved = false;
33137 if(!this.isFitContainer){
33141 if(!this.bgimage.length || !this.html.length){
33145 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
33147 this.timer = new Date().getTime();
33151 onTouchMove: function(e, el)
33153 this.touchmoved = true;
33156 onContextMenu : function(e,el)
33158 e.preventDefault();
33159 e.stopPropagation();
33163 onTouchEnd: function(e, el)
33165 // e.preventDefault();
33167 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
33174 if(!this.bgimage.length || !this.html.length){
33176 if(this.href.length){
33177 window.location.href = this.href;
33183 if(!this.isFitContainer){
33187 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
33189 window.location.href = this.href;
33192 //selection on single brick only
33193 selectBrick : function() {
33195 if (!this.parentId) {
33199 var m = Roo.bootstrap.LayoutMasonry.get(this.parentId);
33200 var index = m.selectedBrick.indexOf(this.id);
33203 m.selectedBrick.splice(index,1);
33204 this.el.removeClass(this.activeClass);
33208 for(var i = 0; i < m.selectedBrick.length; i++) {
33209 var b = Roo.bootstrap.MasonryBrick.get(m.selectedBrick[i]);
33210 b.el.removeClass(b.activeClass);
33213 m.selectedBrick = [];
33215 m.selectedBrick.push(this.id);
33216 this.el.addClass(this.activeClass);
33220 isSelected : function(){
33221 return this.el.hasClass(this.activeClass);
33226 Roo.apply(Roo.bootstrap.MasonryBrick, {
33229 groups : new Roo.util.MixedCollection(false, function(o) { return o.el.id; }),
33231 * register a Masonry Brick
33232 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
33235 register : function(brick)
33237 //this.groups[brick.id] = brick;
33238 this.groups.add(brick.id, brick);
33241 * fetch a masonry brick based on the masonry brick ID
33242 * @param {string} the masonry brick to add
33243 * @returns {Roo.bootstrap.MasonryBrick} the masonry brick
33246 get: function(brick_id)
33248 // if (typeof(this.groups[brick_id]) == 'undefined') {
33251 // return this.groups[brick_id] ;
33253 if(this.groups.key(brick_id)) {
33254 return this.groups.key(brick_id);
33272 * @class Roo.bootstrap.Brick
33273 * @extends Roo.bootstrap.Component
33274 * Bootstrap Brick class
33277 * Create a new Brick
33278 * @param {Object} config The config object
33281 Roo.bootstrap.Brick = function(config){
33282 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
33288 * When a Brick is click
33289 * @param {Roo.bootstrap.Brick} this
33290 * @param {Roo.EventObject} e
33296 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
33299 * @cfg {String} title
33303 * @cfg {String} html
33307 * @cfg {String} bgimage
33311 * @cfg {String} cls
33315 * @cfg {String} href
33319 * @cfg {String} video
33323 * @cfg {Boolean} square
33327 getAutoCreate : function()
33329 var cls = 'roo-brick';
33331 if(this.href.length){
33332 cls += ' roo-brick-link';
33335 if(this.bgimage.length){
33336 cls += ' roo-brick-image';
33339 if(!this.html.length && !this.bgimage.length){
33340 cls += ' roo-brick-center-title';
33343 if(!this.html.length && this.bgimage.length){
33344 cls += ' roo-brick-bottom-title';
33348 cls += ' ' + this.cls;
33352 tag: (this.href.length) ? 'a' : 'div',
33357 cls: 'roo-brick-paragraph',
33363 if(this.href.length){
33364 cfg.href = this.href;
33367 var cn = cfg.cn[0].cn;
33369 if(this.title.length){
33372 cls: 'roo-brick-title',
33377 if(this.html.length){
33380 cls: 'roo-brick-text',
33387 if(this.bgimage.length){
33390 cls: 'roo-brick-image-view',
33398 initEvents: function()
33400 if(this.title.length || this.html.length){
33401 this.el.on('mouseenter' ,this.enter, this);
33402 this.el.on('mouseleave', this.leave, this);
33405 Roo.EventManager.onWindowResize(this.resize, this);
33407 if(this.bgimage.length){
33408 this.imageEl = this.el.select('.roo-brick-image-view', true).first();
33409 this.imageEl.on('load', this.onImageLoad, this);
33416 onImageLoad : function()
33421 resize : function()
33423 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
33425 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
33427 if(this.bgimage.length){
33428 var image = this.el.select('.roo-brick-image-view', true).first();
33430 image.setWidth(paragraph.getWidth());
33433 image.setHeight(paragraph.getWidth());
33436 this.el.setHeight(image.getHeight());
33437 paragraph.setHeight(image.getHeight());
33443 enter: function(e, el)
33445 e.preventDefault();
33447 if(this.bgimage.length){
33448 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
33449 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
33453 leave: function(e, el)
33455 e.preventDefault();
33457 if(this.bgimage.length){
33458 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
33459 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
33474 * @class Roo.bootstrap.NumberField
33475 * @extends Roo.bootstrap.Input
33476 * Bootstrap NumberField class
33482 * Create a new NumberField
33483 * @param {Object} config The config object
33486 Roo.bootstrap.NumberField = function(config){
33487 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
33490 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
33493 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
33495 allowDecimals : true,
33497 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
33499 decimalSeparator : ".",
33501 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
33503 decimalPrecision : 2,
33505 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
33507 allowNegative : true,
33510 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
33514 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
33516 minValue : Number.NEGATIVE_INFINITY,
33518 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
33520 maxValue : Number.MAX_VALUE,
33522 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
33524 minText : "The minimum value for this field is {0}",
33526 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
33528 maxText : "The maximum value for this field is {0}",
33530 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
33531 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
33533 nanText : "{0} is not a valid number",
33535 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
33537 thousandsDelimiter : false,
33539 * @cfg {String} valueAlign alignment of value
33541 valueAlign : "left",
33543 getAutoCreate : function()
33545 var hiddenInput = {
33549 cls: 'hidden-number-input'
33553 hiddenInput.name = this.name;
33558 var cfg = Roo.bootstrap.NumberField.superclass.getAutoCreate.call(this);
33560 this.name = hiddenInput.name;
33562 if(cfg.cn.length > 0) {
33563 cfg.cn.push(hiddenInput);
33570 initEvents : function()
33572 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
33574 var allowed = "0123456789";
33576 if(this.allowDecimals){
33577 allowed += this.decimalSeparator;
33580 if(this.allowNegative){
33584 if(this.thousandsDelimiter) {
33588 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
33590 var keyPress = function(e){
33592 var k = e.getKey();
33594 var c = e.getCharCode();
33597 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
33598 allowed.indexOf(String.fromCharCode(c)) === -1
33604 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
33608 if(allowed.indexOf(String.fromCharCode(c)) === -1){
33613 this.el.on("keypress", keyPress, this);
33616 validateValue : function(value)
33619 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
33623 var num = this.parseValue(value);
33626 this.markInvalid(String.format(this.nanText, value));
33630 if(num < this.minValue){
33631 this.markInvalid(String.format(this.minText, this.minValue));
33635 if(num > this.maxValue){
33636 this.markInvalid(String.format(this.maxText, this.maxValue));
33643 getValue : function()
33645 var v = this.hiddenEl().getValue();
33647 return this.fixPrecision(this.parseValue(v));
33650 parseValue : function(value)
33652 if(this.thousandsDelimiter) {
33654 r = new RegExp(",", "g");
33655 value = value.replace(r, "");
33658 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
33659 return isNaN(value) ? '' : value;
33662 fixPrecision : function(value)
33664 if(this.thousandsDelimiter) {
33666 r = new RegExp(",", "g");
33667 value = value.replace(r, "");
33670 var nan = isNaN(value);
33672 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
33673 return nan ? '' : value;
33675 return parseFloat(value).toFixed(this.decimalPrecision);
33678 setValue : function(v)
33680 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
33686 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
33688 this.inputEl().dom.value = (v == '') ? '' :
33689 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
33691 if(!this.allowZero && v === '0') {
33692 this.hiddenEl().dom.value = '';
33693 this.inputEl().dom.value = '';
33700 decimalPrecisionFcn : function(v)
33702 return Math.floor(v);
33705 beforeBlur : function()
33707 var v = this.parseValue(this.getRawValue());
33709 if(v || v === 0 || v === ''){
33714 hiddenEl : function()
33716 return this.el.select('input.hidden-number-input',true).first();
33728 * @class Roo.bootstrap.DocumentSlider
33729 * @extends Roo.bootstrap.Component
33730 * Bootstrap DocumentSlider class
33733 * Create a new DocumentViewer
33734 * @param {Object} config The config object
33737 Roo.bootstrap.DocumentSlider = function(config){
33738 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
33745 * Fire after initEvent
33746 * @param {Roo.bootstrap.DocumentSlider} this
33751 * Fire after update
33752 * @param {Roo.bootstrap.DocumentSlider} this
33758 * @param {Roo.bootstrap.DocumentSlider} this
33764 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
33770 getAutoCreate : function()
33774 cls : 'roo-document-slider',
33778 cls : 'roo-document-slider-header',
33782 cls : 'roo-document-slider-header-title'
33788 cls : 'roo-document-slider-body',
33792 cls : 'roo-document-slider-prev',
33796 cls : 'fa fa-chevron-left'
33802 cls : 'roo-document-slider-thumb',
33806 cls : 'roo-document-slider-image'
33812 cls : 'roo-document-slider-next',
33816 cls : 'fa fa-chevron-right'
33828 initEvents : function()
33830 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
33831 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
33833 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
33834 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
33836 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
33837 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
33839 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
33840 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
33842 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
33843 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
33845 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
33846 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33848 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
33849 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33851 this.thumbEl.on('click', this.onClick, this);
33853 this.prevIndicator.on('click', this.prev, this);
33855 this.nextIndicator.on('click', this.next, this);
33859 initial : function()
33861 if(this.files.length){
33862 this.indicator = 1;
33866 this.fireEvent('initial', this);
33869 update : function()
33871 this.imageEl.attr('src', this.files[this.indicator - 1]);
33873 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
33875 this.prevIndicator.show();
33877 if(this.indicator == 1){
33878 this.prevIndicator.hide();
33881 this.nextIndicator.show();
33883 if(this.indicator == this.files.length){
33884 this.nextIndicator.hide();
33887 this.thumbEl.scrollTo('top');
33889 this.fireEvent('update', this);
33892 onClick : function(e)
33894 e.preventDefault();
33896 this.fireEvent('click', this);
33901 e.preventDefault();
33903 this.indicator = Math.max(1, this.indicator - 1);
33910 e.preventDefault();
33912 this.indicator = Math.min(this.files.length, this.indicator + 1);
33926 * @class Roo.bootstrap.RadioSet
33927 * @extends Roo.bootstrap.Input
33928 * Bootstrap RadioSet class
33929 * @cfg {String} indicatorpos (left|right) default left
33930 * @cfg {Boolean} inline (true|false) inline the element (default true)
33931 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
33933 * Create a new RadioSet
33934 * @param {Object} config The config object
33937 Roo.bootstrap.RadioSet = function(config){
33939 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
33943 Roo.bootstrap.RadioSet.register(this);
33948 * Fires when the element is checked or unchecked.
33949 * @param {Roo.bootstrap.RadioSet} this This radio
33950 * @param {Roo.bootstrap.Radio} item The checked item
33955 * Fires when the element is click.
33956 * @param {Roo.bootstrap.RadioSet} this This radio set
33957 * @param {Roo.bootstrap.Radio} item The checked item
33958 * @param {Roo.EventObject} e The event object
33965 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
33973 indicatorpos : 'left',
33975 getAutoCreate : function()
33979 cls : 'roo-radio-set-label',
33983 html : this.fieldLabel
33988 if(this.indicatorpos == 'left'){
33991 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
33992 tooltip : 'This field is required'
33997 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
33998 tooltip : 'This field is required'
34004 cls : 'roo-radio-set-items'
34007 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
34009 if (align === 'left' && this.fieldLabel.length) {
34012 cls : "roo-radio-set-right",
34018 if(this.labelWidth > 12){
34019 label.style = "width: " + this.labelWidth + 'px';
34022 if(this.labelWidth < 13 && this.labelmd == 0){
34023 this.labelmd = this.labelWidth;
34026 if(this.labellg > 0){
34027 label.cls += ' col-lg-' + this.labellg;
34028 items.cls += ' col-lg-' + (12 - this.labellg);
34031 if(this.labelmd > 0){
34032 label.cls += ' col-md-' + this.labelmd;
34033 items.cls += ' col-md-' + (12 - this.labelmd);
34036 if(this.labelsm > 0){
34037 label.cls += ' col-sm-' + this.labelsm;
34038 items.cls += ' col-sm-' + (12 - this.labelsm);
34041 if(this.labelxs > 0){
34042 label.cls += ' col-xs-' + this.labelxs;
34043 items.cls += ' col-xs-' + (12 - this.labelxs);
34049 cls : 'roo-radio-set',
34053 cls : 'roo-radio-set-input',
34056 value : this.value ? this.value : ''
34063 if(this.weight.length){
34064 cfg.cls += ' roo-radio-' + this.weight;
34068 cfg.cls += ' roo-radio-set-inline';
34072 ['xs','sm','md','lg'].map(function(size){
34073 if (settings[size]) {
34074 cfg.cls += ' col-' + size + '-' + settings[size];
34082 initEvents : function()
34084 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
34085 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
34087 if(!this.fieldLabel.length){
34088 this.labelEl.hide();
34091 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
34092 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
34094 this.indicator = this.indicatorEl();
34096 if(this.indicator){
34097 this.indicator.addClass('invisible');
34100 this.originalValue = this.getValue();
34104 inputEl: function ()
34106 return this.el.select('.roo-radio-set-input', true).first();
34109 getChildContainer : function()
34111 return this.itemsEl;
34114 register : function(item)
34116 this.radioes.push(item);
34120 validate : function()
34122 if(this.getVisibilityEl().hasClass('hidden')){
34128 Roo.each(this.radioes, function(i){
34137 if(this.allowBlank) {
34141 if(this.disabled || valid){
34146 this.markInvalid();
34151 markValid : function()
34153 if(this.labelEl.isVisible(true)){
34154 this.indicatorEl().removeClass('visible');
34155 this.indicatorEl().addClass('invisible');
34158 this.el.removeClass([this.invalidClass, this.validClass]);
34159 this.el.addClass(this.validClass);
34161 this.fireEvent('valid', this);
34164 markInvalid : function(msg)
34166 if(this.allowBlank || this.disabled){
34170 if(this.labelEl.isVisible(true)){
34171 this.indicatorEl().removeClass('invisible');
34172 this.indicatorEl().addClass('visible');
34175 this.el.removeClass([this.invalidClass, this.validClass]);
34176 this.el.addClass(this.invalidClass);
34178 this.fireEvent('invalid', this, msg);
34182 setValue : function(v, suppressEvent)
34184 if(this.value === v){
34191 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
34194 Roo.each(this.radioes, function(i){
34196 i.el.removeClass('checked');
34199 Roo.each(this.radioes, function(i){
34201 if(i.value === v || i.value.toString() === v.toString()){
34203 i.el.addClass('checked');
34205 if(suppressEvent !== true){
34206 this.fireEvent('check', this, i);
34217 clearInvalid : function(){
34219 if(!this.el || this.preventMark){
34223 this.el.removeClass([this.invalidClass]);
34225 this.fireEvent('valid', this);
34230 Roo.apply(Roo.bootstrap.RadioSet, {
34234 register : function(set)
34236 this.groups[set.name] = set;
34239 get: function(name)
34241 if (typeof(this.groups[name]) == 'undefined') {
34245 return this.groups[name] ;
34251 * Ext JS Library 1.1.1
34252 * Copyright(c) 2006-2007, Ext JS, LLC.
34254 * Originally Released Under LGPL - original licence link has changed is not relivant.
34257 * <script type="text/javascript">
34262 * @class Roo.bootstrap.SplitBar
34263 * @extends Roo.util.Observable
34264 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
34268 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
34269 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
34270 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
34271 split.minSize = 100;
34272 split.maxSize = 600;
34273 split.animate = true;
34274 split.on('moved', splitterMoved);
34277 * Create a new SplitBar
34278 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
34279 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
34280 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34281 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
34282 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
34283 position of the SplitBar).
34285 Roo.bootstrap.SplitBar = function(cfg){
34290 // dragElement : elm
34291 // resizingElement: el,
34293 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
34294 // placement : Roo.bootstrap.SplitBar.LEFT ,
34295 // existingProxy ???
34298 this.el = Roo.get(cfg.dragElement, true);
34299 this.el.dom.unselectable = "on";
34301 this.resizingEl = Roo.get(cfg.resizingElement, true);
34305 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34306 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
34309 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
34312 * The minimum size of the resizing element. (Defaults to 0)
34318 * The maximum size of the resizing element. (Defaults to 2000)
34321 this.maxSize = 2000;
34324 * Whether to animate the transition to the new size
34327 this.animate = false;
34330 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
34333 this.useShim = false;
34338 if(!cfg.existingProxy){
34340 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
34342 this.proxy = Roo.get(cfg.existingProxy).dom;
34345 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
34348 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
34351 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
34354 this.dragSpecs = {};
34357 * @private The adapter to use to positon and resize elements
34359 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34360 this.adapter.init(this);
34362 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34364 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
34365 this.el.addClass("roo-splitbar-h");
34368 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
34369 this.el.addClass("roo-splitbar-v");
34375 * Fires when the splitter is moved (alias for {@link #event-moved})
34376 * @param {Roo.bootstrap.SplitBar} this
34377 * @param {Number} newSize the new width or height
34382 * Fires when the splitter is moved
34383 * @param {Roo.bootstrap.SplitBar} this
34384 * @param {Number} newSize the new width or height
34388 * @event beforeresize
34389 * Fires before the splitter is dragged
34390 * @param {Roo.bootstrap.SplitBar} this
34392 "beforeresize" : true,
34394 "beforeapply" : true
34397 Roo.util.Observable.call(this);
34400 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
34401 onStartProxyDrag : function(x, y){
34402 this.fireEvent("beforeresize", this);
34404 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
34406 o.enableDisplayMode("block");
34407 // all splitbars share the same overlay
34408 Roo.bootstrap.SplitBar.prototype.overlay = o;
34410 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
34411 this.overlay.show();
34412 Roo.get(this.proxy).setDisplayed("block");
34413 var size = this.adapter.getElementSize(this);
34414 this.activeMinSize = this.getMinimumSize();;
34415 this.activeMaxSize = this.getMaximumSize();;
34416 var c1 = size - this.activeMinSize;
34417 var c2 = Math.max(this.activeMaxSize - size, 0);
34418 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34419 this.dd.resetConstraints();
34420 this.dd.setXConstraint(
34421 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
34422 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
34424 this.dd.setYConstraint(0, 0);
34426 this.dd.resetConstraints();
34427 this.dd.setXConstraint(0, 0);
34428 this.dd.setYConstraint(
34429 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
34430 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
34433 this.dragSpecs.startSize = size;
34434 this.dragSpecs.startPoint = [x, y];
34435 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
34439 * @private Called after the drag operation by the DDProxy
34441 onEndProxyDrag : function(e){
34442 Roo.get(this.proxy).setDisplayed(false);
34443 var endPoint = Roo.lib.Event.getXY(e);
34445 this.overlay.hide();
34448 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34449 newSize = this.dragSpecs.startSize +
34450 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
34451 endPoint[0] - this.dragSpecs.startPoint[0] :
34452 this.dragSpecs.startPoint[0] - endPoint[0]
34455 newSize = this.dragSpecs.startSize +
34456 (this.placement == Roo.bootstrap.SplitBar.TOP ?
34457 endPoint[1] - this.dragSpecs.startPoint[1] :
34458 this.dragSpecs.startPoint[1] - endPoint[1]
34461 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
34462 if(newSize != this.dragSpecs.startSize){
34463 if(this.fireEvent('beforeapply', this, newSize) !== false){
34464 this.adapter.setElementSize(this, newSize);
34465 this.fireEvent("moved", this, newSize);
34466 this.fireEvent("resize", this, newSize);
34472 * Get the adapter this SplitBar uses
34473 * @return The adapter object
34475 getAdapter : function(){
34476 return this.adapter;
34480 * Set the adapter this SplitBar uses
34481 * @param {Object} adapter A SplitBar adapter object
34483 setAdapter : function(adapter){
34484 this.adapter = adapter;
34485 this.adapter.init(this);
34489 * Gets the minimum size for the resizing element
34490 * @return {Number} The minimum size
34492 getMinimumSize : function(){
34493 return this.minSize;
34497 * Sets the minimum size for the resizing element
34498 * @param {Number} minSize The minimum size
34500 setMinimumSize : function(minSize){
34501 this.minSize = minSize;
34505 * Gets the maximum size for the resizing element
34506 * @return {Number} The maximum size
34508 getMaximumSize : function(){
34509 return this.maxSize;
34513 * Sets the maximum size for the resizing element
34514 * @param {Number} maxSize The maximum size
34516 setMaximumSize : function(maxSize){
34517 this.maxSize = maxSize;
34521 * Sets the initialize size for the resizing element
34522 * @param {Number} size The initial size
34524 setCurrentSize : function(size){
34525 var oldAnimate = this.animate;
34526 this.animate = false;
34527 this.adapter.setElementSize(this, size);
34528 this.animate = oldAnimate;
34532 * Destroy this splitbar.
34533 * @param {Boolean} removeEl True to remove the element
34535 destroy : function(removeEl){
34537 this.shim.remove();
34540 this.proxy.parentNode.removeChild(this.proxy);
34548 * @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.
34550 Roo.bootstrap.SplitBar.createProxy = function(dir){
34551 var proxy = new Roo.Element(document.createElement("div"));
34552 proxy.unselectable();
34553 var cls = 'roo-splitbar-proxy';
34554 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
34555 document.body.appendChild(proxy.dom);
34560 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
34561 * Default Adapter. It assumes the splitter and resizing element are not positioned
34562 * elements and only gets/sets the width of the element. Generally used for table based layouts.
34564 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
34567 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
34568 // do nothing for now
34569 init : function(s){
34573 * Called before drag operations to get the current size of the resizing element.
34574 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34576 getElementSize : function(s){
34577 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34578 return s.resizingEl.getWidth();
34580 return s.resizingEl.getHeight();
34585 * Called after drag operations to set the size of the resizing element.
34586 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34587 * @param {Number} newSize The new size to set
34588 * @param {Function} onComplete A function to be invoked when resizing is complete
34590 setElementSize : function(s, newSize, onComplete){
34591 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34593 s.resizingEl.setWidth(newSize);
34595 onComplete(s, newSize);
34598 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
34603 s.resizingEl.setHeight(newSize);
34605 onComplete(s, newSize);
34608 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
34615 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
34616 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
34617 * Adapter that moves the splitter element to align with the resized sizing element.
34618 * Used with an absolute positioned SplitBar.
34619 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
34620 * document.body, make sure you assign an id to the body element.
34622 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
34623 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34624 this.container = Roo.get(container);
34627 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
34628 init : function(s){
34629 this.basic.init(s);
34632 getElementSize : function(s){
34633 return this.basic.getElementSize(s);
34636 setElementSize : function(s, newSize, onComplete){
34637 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
34640 moveSplitter : function(s){
34641 var yes = Roo.bootstrap.SplitBar;
34642 switch(s.placement){
34644 s.el.setX(s.resizingEl.getRight());
34647 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
34650 s.el.setY(s.resizingEl.getBottom());
34653 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
34660 * Orientation constant - Create a vertical SplitBar
34664 Roo.bootstrap.SplitBar.VERTICAL = 1;
34667 * Orientation constant - Create a horizontal SplitBar
34671 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
34674 * Placement constant - The resizing element is to the left of the splitter element
34678 Roo.bootstrap.SplitBar.LEFT = 1;
34681 * Placement constant - The resizing element is to the right of the splitter element
34685 Roo.bootstrap.SplitBar.RIGHT = 2;
34688 * Placement constant - The resizing element is positioned above the splitter element
34692 Roo.bootstrap.SplitBar.TOP = 3;
34695 * Placement constant - The resizing element is positioned under splitter element
34699 Roo.bootstrap.SplitBar.BOTTOM = 4;
34700 Roo.namespace("Roo.bootstrap.layout");/*
34702 * Ext JS Library 1.1.1
34703 * Copyright(c) 2006-2007, Ext JS, LLC.
34705 * Originally Released Under LGPL - original licence link has changed is not relivant.
34708 * <script type="text/javascript">
34712 * @class Roo.bootstrap.layout.Manager
34713 * @extends Roo.bootstrap.Component
34714 * Base class for layout managers.
34716 Roo.bootstrap.layout.Manager = function(config)
34718 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
34724 /** false to disable window resize monitoring @type Boolean */
34725 this.monitorWindowResize = true;
34730 * Fires when a layout is performed.
34731 * @param {Roo.LayoutManager} this
34735 * @event regionresized
34736 * Fires when the user resizes a region.
34737 * @param {Roo.LayoutRegion} region The resized region
34738 * @param {Number} newSize The new size (width for east/west, height for north/south)
34740 "regionresized" : true,
34742 * @event regioncollapsed
34743 * Fires when a region is collapsed.
34744 * @param {Roo.LayoutRegion} region The collapsed region
34746 "regioncollapsed" : true,
34748 * @event regionexpanded
34749 * Fires when a region is expanded.
34750 * @param {Roo.LayoutRegion} region The expanded region
34752 "regionexpanded" : true
34754 this.updating = false;
34757 this.el = Roo.get(config.el);
34763 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
34768 monitorWindowResize : true,
34774 onRender : function(ct, position)
34777 this.el = Roo.get(ct);
34780 //this.fireEvent('render',this);
34784 initEvents: function()
34788 // ie scrollbar fix
34789 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
34790 document.body.scroll = "no";
34791 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
34792 this.el.position('relative');
34794 this.id = this.el.id;
34795 this.el.addClass("roo-layout-container");
34796 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
34797 if(this.el.dom != document.body ) {
34798 this.el.on('resize', this.layout,this);
34799 this.el.on('show', this.layout,this);
34805 * Returns true if this layout is currently being updated
34806 * @return {Boolean}
34808 isUpdating : function(){
34809 return this.updating;
34813 * Suspend the LayoutManager from doing auto-layouts while
34814 * making multiple add or remove calls
34816 beginUpdate : function(){
34817 this.updating = true;
34821 * Restore auto-layouts and optionally disable the manager from performing a layout
34822 * @param {Boolean} noLayout true to disable a layout update
34824 endUpdate : function(noLayout){
34825 this.updating = false;
34831 layout: function(){
34835 onRegionResized : function(region, newSize){
34836 this.fireEvent("regionresized", region, newSize);
34840 onRegionCollapsed : function(region){
34841 this.fireEvent("regioncollapsed", region);
34844 onRegionExpanded : function(region){
34845 this.fireEvent("regionexpanded", region);
34849 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
34850 * performs box-model adjustments.
34851 * @return {Object} The size as an object {width: (the width), height: (the height)}
34853 getViewSize : function()
34856 if(this.el.dom != document.body){
34857 size = this.el.getSize();
34859 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
34861 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
34862 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
34867 * Returns the Element this layout is bound to.
34868 * @return {Roo.Element}
34870 getEl : function(){
34875 * Returns the specified region.
34876 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
34877 * @return {Roo.LayoutRegion}
34879 getRegion : function(target){
34880 return this.regions[target.toLowerCase()];
34883 onWindowResize : function(){
34884 if(this.monitorWindowResize){
34891 * Ext JS Library 1.1.1
34892 * Copyright(c) 2006-2007, Ext JS, LLC.
34894 * Originally Released Under LGPL - original licence link has changed is not relivant.
34897 * <script type="text/javascript">
34900 * @class Roo.bootstrap.layout.Border
34901 * @extends Roo.bootstrap.layout.Manager
34902 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
34903 * please see: examples/bootstrap/nested.html<br><br>
34905 <b>The container the layout is rendered into can be either the body element or any other element.
34906 If it is not the body element, the container needs to either be an absolute positioned element,
34907 or you will need to add "position:relative" to the css of the container. You will also need to specify
34908 the container size if it is not the body element.</b>
34911 * Create a new Border
34912 * @param {Object} config Configuration options
34914 Roo.bootstrap.layout.Border = function(config){
34915 config = config || {};
34916 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
34920 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34921 if(config[region]){
34922 config[region].region = region;
34923 this.addRegion(config[region]);
34929 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
34931 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
34933 * Creates and adds a new region if it doesn't already exist.
34934 * @param {String} target The target region key (north, south, east, west or center).
34935 * @param {Object} config The regions config object
34936 * @return {BorderLayoutRegion} The new region
34938 addRegion : function(config)
34940 if(!this.regions[config.region]){
34941 var r = this.factory(config);
34942 this.bindRegion(r);
34944 return this.regions[config.region];
34948 bindRegion : function(r){
34949 this.regions[r.config.region] = r;
34951 r.on("visibilitychange", this.layout, this);
34952 r.on("paneladded", this.layout, this);
34953 r.on("panelremoved", this.layout, this);
34954 r.on("invalidated", this.layout, this);
34955 r.on("resized", this.onRegionResized, this);
34956 r.on("collapsed", this.onRegionCollapsed, this);
34957 r.on("expanded", this.onRegionExpanded, this);
34961 * Performs a layout update.
34963 layout : function()
34965 if(this.updating) {
34969 // render all the rebions if they have not been done alreayd?
34970 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34971 if(this.regions[region] && !this.regions[region].bodyEl){
34972 this.regions[region].onRender(this.el)
34976 var size = this.getViewSize();
34977 var w = size.width;
34978 var h = size.height;
34983 //var x = 0, y = 0;
34985 var rs = this.regions;
34986 var north = rs["north"];
34987 var south = rs["south"];
34988 var west = rs["west"];
34989 var east = rs["east"];
34990 var center = rs["center"];
34991 //if(this.hideOnLayout){ // not supported anymore
34992 //c.el.setStyle("display", "none");
34994 if(north && north.isVisible()){
34995 var b = north.getBox();
34996 var m = north.getMargins();
34997 b.width = w - (m.left+m.right);
35000 centerY = b.height + b.y + m.bottom;
35001 centerH -= centerY;
35002 north.updateBox(this.safeBox(b));
35004 if(south && south.isVisible()){
35005 var b = south.getBox();
35006 var m = south.getMargins();
35007 b.width = w - (m.left+m.right);
35009 var totalHeight = (b.height + m.top + m.bottom);
35010 b.y = h - totalHeight + m.top;
35011 centerH -= totalHeight;
35012 south.updateBox(this.safeBox(b));
35014 if(west && west.isVisible()){
35015 var b = west.getBox();
35016 var m = west.getMargins();
35017 b.height = centerH - (m.top+m.bottom);
35019 b.y = centerY + m.top;
35020 var totalWidth = (b.width + m.left + m.right);
35021 centerX += totalWidth;
35022 centerW -= totalWidth;
35023 west.updateBox(this.safeBox(b));
35025 if(east && east.isVisible()){
35026 var b = east.getBox();
35027 var m = east.getMargins();
35028 b.height = centerH - (m.top+m.bottom);
35029 var totalWidth = (b.width + m.left + m.right);
35030 b.x = w - totalWidth + m.left;
35031 b.y = centerY + m.top;
35032 centerW -= totalWidth;
35033 east.updateBox(this.safeBox(b));
35036 var m = center.getMargins();
35038 x: centerX + m.left,
35039 y: centerY + m.top,
35040 width: centerW - (m.left+m.right),
35041 height: centerH - (m.top+m.bottom)
35043 //if(this.hideOnLayout){
35044 //center.el.setStyle("display", "block");
35046 center.updateBox(this.safeBox(centerBox));
35049 this.fireEvent("layout", this);
35053 safeBox : function(box){
35054 box.width = Math.max(0, box.width);
35055 box.height = Math.max(0, box.height);
35060 * Adds a ContentPanel (or subclass) to this layout.
35061 * @param {String} target The target region key (north, south, east, west or center).
35062 * @param {Roo.ContentPanel} panel The panel to add
35063 * @return {Roo.ContentPanel} The added panel
35065 add : function(target, panel){
35067 target = target.toLowerCase();
35068 return this.regions[target].add(panel);
35072 * Remove a ContentPanel (or subclass) to this layout.
35073 * @param {String} target The target region key (north, south, east, west or center).
35074 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
35075 * @return {Roo.ContentPanel} The removed panel
35077 remove : function(target, panel){
35078 target = target.toLowerCase();
35079 return this.regions[target].remove(panel);
35083 * Searches all regions for a panel with the specified id
35084 * @param {String} panelId
35085 * @return {Roo.ContentPanel} The panel or null if it wasn't found
35087 findPanel : function(panelId){
35088 var rs = this.regions;
35089 for(var target in rs){
35090 if(typeof rs[target] != "function"){
35091 var p = rs[target].getPanel(panelId);
35101 * Searches all regions for a panel with the specified id and activates (shows) it.
35102 * @param {String/ContentPanel} panelId The panels id or the panel itself
35103 * @return {Roo.ContentPanel} The shown panel or null
35105 showPanel : function(panelId) {
35106 var rs = this.regions;
35107 for(var target in rs){
35108 var r = rs[target];
35109 if(typeof r != "function"){
35110 if(r.hasPanel(panelId)){
35111 return r.showPanel(panelId);
35119 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
35120 * @param {Roo.state.Provider} provider (optional) An alternate state provider
35123 restoreState : function(provider){
35125 provider = Roo.state.Manager;
35127 var sm = new Roo.LayoutStateManager();
35128 sm.init(this, provider);
35134 * Adds a xtype elements to the layout.
35138 xtype : 'ContentPanel',
35145 xtype : 'NestedLayoutPanel',
35151 items : [ ... list of content panels or nested layout panels.. ]
35155 * @param {Object} cfg Xtype definition of item to add.
35157 addxtype : function(cfg)
35159 // basically accepts a pannel...
35160 // can accept a layout region..!?!?
35161 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
35164 // theory? children can only be panels??
35166 //if (!cfg.xtype.match(/Panel$/)) {
35171 if (typeof(cfg.region) == 'undefined') {
35172 Roo.log("Failed to add Panel, region was not set");
35176 var region = cfg.region;
35182 xitems = cfg.items;
35189 case 'Content': // ContentPanel (el, cfg)
35190 case 'Scroll': // ContentPanel (el, cfg)
35192 cfg.autoCreate = true;
35193 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35195 // var el = this.el.createChild();
35196 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
35199 this.add(region, ret);
35203 case 'TreePanel': // our new panel!
35204 cfg.el = this.el.createChild();
35205 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
35206 this.add(region, ret);
35211 // create a new Layout (which is a Border Layout...
35213 var clayout = cfg.layout;
35214 clayout.el = this.el.createChild();
35215 clayout.items = clayout.items || [];
35219 // replace this exitems with the clayout ones..
35220 xitems = clayout.items;
35222 // force background off if it's in center...
35223 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
35224 cfg.background = false;
35226 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
35229 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35230 //console.log('adding nested layout panel ' + cfg.toSource());
35231 this.add(region, ret);
35232 nb = {}; /// find first...
35237 // needs grid and region
35239 //var el = this.getRegion(region).el.createChild();
35241 *var el = this.el.createChild();
35242 // create the grid first...
35243 cfg.grid.container = el;
35244 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
35247 if (region == 'center' && this.active ) {
35248 cfg.background = false;
35251 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35253 this.add(region, ret);
35255 if (cfg.background) {
35256 // render grid on panel activation (if panel background)
35257 ret.on('activate', function(gp) {
35258 if (!gp.grid.rendered) {
35259 // gp.grid.render(el);
35263 // cfg.grid.render(el);
35269 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
35270 // it was the old xcomponent building that caused this before.
35271 // espeically if border is the top element in the tree.
35281 if (typeof(Roo[cfg.xtype]) != 'undefined') {
35283 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
35284 this.add(region, ret);
35288 throw "Can not add '" + cfg.xtype + "' to Border";
35294 this.beginUpdate();
35298 Roo.each(xitems, function(i) {
35299 region = nb && i.region ? i.region : false;
35301 var add = ret.addxtype(i);
35304 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
35305 if (!i.background) {
35306 abn[region] = nb[region] ;
35313 // make the last non-background panel active..
35314 //if (nb) { Roo.log(abn); }
35317 for(var r in abn) {
35318 region = this.getRegion(r);
35320 // tried using nb[r], but it does not work..
35322 region.showPanel(abn[r]);
35333 factory : function(cfg)
35336 var validRegions = Roo.bootstrap.layout.Border.regions;
35338 var target = cfg.region;
35341 var r = Roo.bootstrap.layout;
35345 return new r.North(cfg);
35347 return new r.South(cfg);
35349 return new r.East(cfg);
35351 return new r.West(cfg);
35353 return new r.Center(cfg);
35355 throw 'Layout region "'+target+'" not supported.';
35362 * Ext JS Library 1.1.1
35363 * Copyright(c) 2006-2007, Ext JS, LLC.
35365 * Originally Released Under LGPL - original licence link has changed is not relivant.
35368 * <script type="text/javascript">
35372 * @class Roo.bootstrap.layout.Basic
35373 * @extends Roo.util.Observable
35374 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
35375 * and does not have a titlebar, tabs or any other features. All it does is size and position
35376 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
35377 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35378 * @cfg {string} region the region that it inhabits..
35379 * @cfg {bool} skipConfig skip config?
35383 Roo.bootstrap.layout.Basic = function(config){
35385 this.mgr = config.mgr;
35387 this.position = config.region;
35389 var skipConfig = config.skipConfig;
35393 * @scope Roo.BasicLayoutRegion
35397 * @event beforeremove
35398 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
35399 * @param {Roo.LayoutRegion} this
35400 * @param {Roo.ContentPanel} panel The panel
35401 * @param {Object} e The cancel event object
35403 "beforeremove" : true,
35405 * @event invalidated
35406 * Fires when the layout for this region is changed.
35407 * @param {Roo.LayoutRegion} this
35409 "invalidated" : true,
35411 * @event visibilitychange
35412 * Fires when this region is shown or hidden
35413 * @param {Roo.LayoutRegion} this
35414 * @param {Boolean} visibility true or false
35416 "visibilitychange" : true,
35418 * @event paneladded
35419 * Fires when a panel is added.
35420 * @param {Roo.LayoutRegion} this
35421 * @param {Roo.ContentPanel} panel The panel
35423 "paneladded" : true,
35425 * @event panelremoved
35426 * Fires when a panel is removed.
35427 * @param {Roo.LayoutRegion} this
35428 * @param {Roo.ContentPanel} panel The panel
35430 "panelremoved" : true,
35432 * @event beforecollapse
35433 * Fires when this region before collapse.
35434 * @param {Roo.LayoutRegion} this
35436 "beforecollapse" : true,
35439 * Fires when this region is collapsed.
35440 * @param {Roo.LayoutRegion} this
35442 "collapsed" : true,
35445 * Fires when this region is expanded.
35446 * @param {Roo.LayoutRegion} this
35451 * Fires when this region is slid into view.
35452 * @param {Roo.LayoutRegion} this
35454 "slideshow" : true,
35457 * Fires when this region slides out of view.
35458 * @param {Roo.LayoutRegion} this
35460 "slidehide" : true,
35462 * @event panelactivated
35463 * Fires when a panel is activated.
35464 * @param {Roo.LayoutRegion} this
35465 * @param {Roo.ContentPanel} panel The activated panel
35467 "panelactivated" : true,
35470 * Fires when the user resizes this region.
35471 * @param {Roo.LayoutRegion} this
35472 * @param {Number} newSize The new size (width for east/west, height for north/south)
35476 /** A collection of panels in this region. @type Roo.util.MixedCollection */
35477 this.panels = new Roo.util.MixedCollection();
35478 this.panels.getKey = this.getPanelId.createDelegate(this);
35480 this.activePanel = null;
35481 // ensure listeners are added...
35483 if (config.listeners || config.events) {
35484 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
35485 listeners : config.listeners || {},
35486 events : config.events || {}
35490 if(skipConfig !== true){
35491 this.applyConfig(config);
35495 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
35497 getPanelId : function(p){
35501 applyConfig : function(config){
35502 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35503 this.config = config;
35508 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
35509 * the width, for horizontal (north, south) the height.
35510 * @param {Number} newSize The new width or height
35512 resizeTo : function(newSize){
35513 var el = this.el ? this.el :
35514 (this.activePanel ? this.activePanel.getEl() : null);
35516 switch(this.position){
35519 el.setWidth(newSize);
35520 this.fireEvent("resized", this, newSize);
35524 el.setHeight(newSize);
35525 this.fireEvent("resized", this, newSize);
35531 getBox : function(){
35532 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
35535 getMargins : function(){
35536 return this.margins;
35539 updateBox : function(box){
35541 var el = this.activePanel.getEl();
35542 el.dom.style.left = box.x + "px";
35543 el.dom.style.top = box.y + "px";
35544 this.activePanel.setSize(box.width, box.height);
35548 * Returns the container element for this region.
35549 * @return {Roo.Element}
35551 getEl : function(){
35552 return this.activePanel;
35556 * Returns true if this region is currently visible.
35557 * @return {Boolean}
35559 isVisible : function(){
35560 return this.activePanel ? true : false;
35563 setActivePanel : function(panel){
35564 panel = this.getPanel(panel);
35565 if(this.activePanel && this.activePanel != panel){
35566 this.activePanel.setActiveState(false);
35567 this.activePanel.getEl().setLeftTop(-10000,-10000);
35569 this.activePanel = panel;
35570 panel.setActiveState(true);
35572 panel.setSize(this.box.width, this.box.height);
35574 this.fireEvent("panelactivated", this, panel);
35575 this.fireEvent("invalidated");
35579 * Show the specified panel.
35580 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
35581 * @return {Roo.ContentPanel} The shown panel or null
35583 showPanel : function(panel){
35584 panel = this.getPanel(panel);
35586 this.setActivePanel(panel);
35592 * Get the active panel for this region.
35593 * @return {Roo.ContentPanel} The active panel or null
35595 getActivePanel : function(){
35596 return this.activePanel;
35600 * Add the passed ContentPanel(s)
35601 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35602 * @return {Roo.ContentPanel} The panel added (if only one was added)
35604 add : function(panel){
35605 if(arguments.length > 1){
35606 for(var i = 0, len = arguments.length; i < len; i++) {
35607 this.add(arguments[i]);
35611 if(this.hasPanel(panel)){
35612 this.showPanel(panel);
35615 var el = panel.getEl();
35616 if(el.dom.parentNode != this.mgr.el.dom){
35617 this.mgr.el.dom.appendChild(el.dom);
35619 if(panel.setRegion){
35620 panel.setRegion(this);
35622 this.panels.add(panel);
35623 el.setStyle("position", "absolute");
35624 if(!panel.background){
35625 this.setActivePanel(panel);
35626 if(this.config.initialSize && this.panels.getCount()==1){
35627 this.resizeTo(this.config.initialSize);
35630 this.fireEvent("paneladded", this, panel);
35635 * Returns true if the panel is in this region.
35636 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35637 * @return {Boolean}
35639 hasPanel : function(panel){
35640 if(typeof panel == "object"){ // must be panel obj
35641 panel = panel.getId();
35643 return this.getPanel(panel) ? true : false;
35647 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35648 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35649 * @param {Boolean} preservePanel Overrides the config preservePanel option
35650 * @return {Roo.ContentPanel} The panel that was removed
35652 remove : function(panel, preservePanel){
35653 panel = this.getPanel(panel);
35658 this.fireEvent("beforeremove", this, panel, e);
35659 if(e.cancel === true){
35662 var panelId = panel.getId();
35663 this.panels.removeKey(panelId);
35668 * Returns the panel specified or null if it's not in this region.
35669 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35670 * @return {Roo.ContentPanel}
35672 getPanel : function(id){
35673 if(typeof id == "object"){ // must be panel obj
35676 return this.panels.get(id);
35680 * Returns this regions position (north/south/east/west/center).
35683 getPosition: function(){
35684 return this.position;
35688 * Ext JS Library 1.1.1
35689 * Copyright(c) 2006-2007, Ext JS, LLC.
35691 * Originally Released Under LGPL - original licence link has changed is not relivant.
35694 * <script type="text/javascript">
35698 * @class Roo.bootstrap.layout.Region
35699 * @extends Roo.bootstrap.layout.Basic
35700 * This class represents a region in a layout manager.
35702 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
35703 * @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})
35704 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
35705 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
35706 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
35707 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
35708 * @cfg {String} title The title for the region (overrides panel titles)
35709 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
35710 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
35711 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
35712 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
35713 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
35714 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
35715 * the space available, similar to FireFox 1.5 tabs (defaults to false)
35716 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
35717 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
35718 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
35720 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
35721 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
35722 * @cfg {Boolean} disableTabTips True to disable tab tooltips
35723 * @cfg {Number} width For East/West panels
35724 * @cfg {Number} height For North/South panels
35725 * @cfg {Boolean} split To show the splitter
35726 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
35728 * @cfg {string} cls Extra CSS classes to add to region
35730 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35731 * @cfg {string} region the region that it inhabits..
35734 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
35735 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
35737 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
35738 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
35739 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
35741 Roo.bootstrap.layout.Region = function(config)
35743 this.applyConfig(config);
35745 var mgr = config.mgr;
35746 var pos = config.region;
35747 config.skipConfig = true;
35748 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
35751 this.onRender(mgr.el);
35754 this.visible = true;
35755 this.collapsed = false;
35756 this.unrendered_panels = [];
35759 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
35761 position: '', // set by wrapper (eg. north/south etc..)
35762 unrendered_panels : null, // unrendered panels.
35763 createBody : function(){
35764 /** This region's body element
35765 * @type Roo.Element */
35766 this.bodyEl = this.el.createChild({
35768 cls: "roo-layout-panel-body tab-content" // bootstrap added...
35772 onRender: function(ctr, pos)
35774 var dh = Roo.DomHelper;
35775 /** This region's container element
35776 * @type Roo.Element */
35777 this.el = dh.append(ctr.dom, {
35779 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
35781 /** This region's title element
35782 * @type Roo.Element */
35784 this.titleEl = dh.append(this.el.dom,
35787 unselectable: "on",
35788 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
35790 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
35791 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
35794 this.titleEl.enableDisplayMode();
35795 /** This region's title text element
35796 * @type HTMLElement */
35797 this.titleTextEl = this.titleEl.dom.firstChild;
35798 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
35800 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
35801 this.closeBtn.enableDisplayMode();
35802 this.closeBtn.on("click", this.closeClicked, this);
35803 this.closeBtn.hide();
35805 this.createBody(this.config);
35806 if(this.config.hideWhenEmpty){
35808 this.on("paneladded", this.validateVisibility, this);
35809 this.on("panelremoved", this.validateVisibility, this);
35811 if(this.autoScroll){
35812 this.bodyEl.setStyle("overflow", "auto");
35814 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
35816 //if(c.titlebar !== false){
35817 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
35818 this.titleEl.hide();
35820 this.titleEl.show();
35821 if(this.config.title){
35822 this.titleTextEl.innerHTML = this.config.title;
35826 if(this.config.collapsed){
35827 this.collapse(true);
35829 if(this.config.hidden){
35833 if (this.unrendered_panels && this.unrendered_panels.length) {
35834 for (var i =0;i< this.unrendered_panels.length; i++) {
35835 this.add(this.unrendered_panels[i]);
35837 this.unrendered_panels = null;
35843 applyConfig : function(c)
35846 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
35847 var dh = Roo.DomHelper;
35848 if(c.titlebar !== false){
35849 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
35850 this.collapseBtn.on("click", this.collapse, this);
35851 this.collapseBtn.enableDisplayMode();
35853 if(c.showPin === true || this.showPin){
35854 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
35855 this.stickBtn.enableDisplayMode();
35856 this.stickBtn.on("click", this.expand, this);
35857 this.stickBtn.hide();
35862 /** This region's collapsed element
35863 * @type Roo.Element */
35866 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
35867 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
35870 if(c.floatable !== false){
35871 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
35872 this.collapsedEl.on("click", this.collapseClick, this);
35875 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
35876 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
35877 id: "message", unselectable: "on", style:{"float":"left"}});
35878 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
35880 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
35881 this.expandBtn.on("click", this.expand, this);
35885 if(this.collapseBtn){
35886 this.collapseBtn.setVisible(c.collapsible == true);
35889 this.cmargins = c.cmargins || this.cmargins ||
35890 (this.position == "west" || this.position == "east" ?
35891 {top: 0, left: 2, right:2, bottom: 0} :
35892 {top: 2, left: 0, right:0, bottom: 2});
35894 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35897 this.bottomTabs = c.tabPosition != "top";
35899 this.autoScroll = c.autoScroll || false;
35904 this.duration = c.duration || .30;
35905 this.slideDuration = c.slideDuration || .45;
35910 * Returns true if this region is currently visible.
35911 * @return {Boolean}
35913 isVisible : function(){
35914 return this.visible;
35918 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
35919 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
35921 //setCollapsedTitle : function(title){
35922 // title = title || " ";
35923 // if(this.collapsedTitleTextEl){
35924 // this.collapsedTitleTextEl.innerHTML = title;
35928 getBox : function(){
35930 // if(!this.collapsed){
35931 b = this.el.getBox(false, true);
35933 // b = this.collapsedEl.getBox(false, true);
35938 getMargins : function(){
35939 return this.margins;
35940 //return this.collapsed ? this.cmargins : this.margins;
35943 highlight : function(){
35944 this.el.addClass("x-layout-panel-dragover");
35947 unhighlight : function(){
35948 this.el.removeClass("x-layout-panel-dragover");
35951 updateBox : function(box)
35953 if (!this.bodyEl) {
35954 return; // not rendered yet..
35958 if(!this.collapsed){
35959 this.el.dom.style.left = box.x + "px";
35960 this.el.dom.style.top = box.y + "px";
35961 this.updateBody(box.width, box.height);
35963 this.collapsedEl.dom.style.left = box.x + "px";
35964 this.collapsedEl.dom.style.top = box.y + "px";
35965 this.collapsedEl.setSize(box.width, box.height);
35968 this.tabs.autoSizeTabs();
35972 updateBody : function(w, h)
35975 this.el.setWidth(w);
35976 w -= this.el.getBorderWidth("rl");
35977 if(this.config.adjustments){
35978 w += this.config.adjustments[0];
35981 if(h !== null && h > 0){
35982 this.el.setHeight(h);
35983 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
35984 h -= this.el.getBorderWidth("tb");
35985 if(this.config.adjustments){
35986 h += this.config.adjustments[1];
35988 this.bodyEl.setHeight(h);
35990 h = this.tabs.syncHeight(h);
35993 if(this.panelSize){
35994 w = w !== null ? w : this.panelSize.width;
35995 h = h !== null ? h : this.panelSize.height;
35997 if(this.activePanel){
35998 var el = this.activePanel.getEl();
35999 w = w !== null ? w : el.getWidth();
36000 h = h !== null ? h : el.getHeight();
36001 this.panelSize = {width: w, height: h};
36002 this.activePanel.setSize(w, h);
36004 if(Roo.isIE && this.tabs){
36005 this.tabs.el.repaint();
36010 * Returns the container element for this region.
36011 * @return {Roo.Element}
36013 getEl : function(){
36018 * Hides this region.
36021 //if(!this.collapsed){
36022 this.el.dom.style.left = "-2000px";
36025 // this.collapsedEl.dom.style.left = "-2000px";
36026 // this.collapsedEl.hide();
36028 this.visible = false;
36029 this.fireEvent("visibilitychange", this, false);
36033 * Shows this region if it was previously hidden.
36036 //if(!this.collapsed){
36039 // this.collapsedEl.show();
36041 this.visible = true;
36042 this.fireEvent("visibilitychange", this, true);
36045 closeClicked : function(){
36046 if(this.activePanel){
36047 this.remove(this.activePanel);
36051 collapseClick : function(e){
36053 e.stopPropagation();
36056 e.stopPropagation();
36062 * Collapses this region.
36063 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
36066 collapse : function(skipAnim, skipCheck = false){
36067 if(this.collapsed) {
36071 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
36073 this.collapsed = true;
36075 this.split.el.hide();
36077 if(this.config.animate && skipAnim !== true){
36078 this.fireEvent("invalidated", this);
36079 this.animateCollapse();
36081 this.el.setLocation(-20000,-20000);
36083 this.collapsedEl.show();
36084 this.fireEvent("collapsed", this);
36085 this.fireEvent("invalidated", this);
36091 animateCollapse : function(){
36096 * Expands this region if it was previously collapsed.
36097 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
36098 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
36101 expand : function(e, skipAnim){
36103 e.stopPropagation();
36105 if(!this.collapsed || this.el.hasActiveFx()) {
36109 this.afterSlideIn();
36112 this.collapsed = false;
36113 if(this.config.animate && skipAnim !== true){
36114 this.animateExpand();
36118 this.split.el.show();
36120 this.collapsedEl.setLocation(-2000,-2000);
36121 this.collapsedEl.hide();
36122 this.fireEvent("invalidated", this);
36123 this.fireEvent("expanded", this);
36127 animateExpand : function(){
36131 initTabs : function()
36133 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
36135 var ts = new Roo.bootstrap.panel.Tabs({
36136 el: this.bodyEl.dom,
36137 tabPosition: this.bottomTabs ? 'bottom' : 'top',
36138 disableTooltips: this.config.disableTabTips,
36139 toolbar : this.config.toolbar
36142 if(this.config.hideTabs){
36143 ts.stripWrap.setDisplayed(false);
36146 ts.resizeTabs = this.config.resizeTabs === true;
36147 ts.minTabWidth = this.config.minTabWidth || 40;
36148 ts.maxTabWidth = this.config.maxTabWidth || 250;
36149 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
36150 ts.monitorResize = false;
36151 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
36152 ts.bodyEl.addClass('roo-layout-tabs-body');
36153 this.panels.each(this.initPanelAsTab, this);
36156 initPanelAsTab : function(panel){
36157 var ti = this.tabs.addTab(
36161 this.config.closeOnTab && panel.isClosable(),
36164 if(panel.tabTip !== undefined){
36165 ti.setTooltip(panel.tabTip);
36167 ti.on("activate", function(){
36168 this.setActivePanel(panel);
36171 if(this.config.closeOnTab){
36172 ti.on("beforeclose", function(t, e){
36174 this.remove(panel);
36178 panel.tabItem = ti;
36183 updatePanelTitle : function(panel, title)
36185 if(this.activePanel == panel){
36186 this.updateTitle(title);
36189 var ti = this.tabs.getTab(panel.getEl().id);
36191 if(panel.tabTip !== undefined){
36192 ti.setTooltip(panel.tabTip);
36197 updateTitle : function(title){
36198 if(this.titleTextEl && !this.config.title){
36199 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
36203 setActivePanel : function(panel)
36205 panel = this.getPanel(panel);
36206 if(this.activePanel && this.activePanel != panel){
36207 if(this.activePanel.setActiveState(false) === false){
36211 this.activePanel = panel;
36212 panel.setActiveState(true);
36213 if(this.panelSize){
36214 panel.setSize(this.panelSize.width, this.panelSize.height);
36217 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
36219 this.updateTitle(panel.getTitle());
36221 this.fireEvent("invalidated", this);
36223 this.fireEvent("panelactivated", this, panel);
36227 * Shows the specified panel.
36228 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
36229 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
36231 showPanel : function(panel)
36233 panel = this.getPanel(panel);
36236 var tab = this.tabs.getTab(panel.getEl().id);
36237 if(tab.isHidden()){
36238 this.tabs.unhideTab(tab.id);
36242 this.setActivePanel(panel);
36249 * Get the active panel for this region.
36250 * @return {Roo.ContentPanel} The active panel or null
36252 getActivePanel : function(){
36253 return this.activePanel;
36256 validateVisibility : function(){
36257 if(this.panels.getCount() < 1){
36258 this.updateTitle(" ");
36259 this.closeBtn.hide();
36262 if(!this.isVisible()){
36269 * Adds the passed ContentPanel(s) to this region.
36270 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
36271 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
36273 add : function(panel)
36275 if(arguments.length > 1){
36276 for(var i = 0, len = arguments.length; i < len; i++) {
36277 this.add(arguments[i]);
36282 // if we have not been rendered yet, then we can not really do much of this..
36283 if (!this.bodyEl) {
36284 this.unrendered_panels.push(panel);
36291 if(this.hasPanel(panel)){
36292 this.showPanel(panel);
36295 panel.setRegion(this);
36296 this.panels.add(panel);
36297 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
36298 // sinle panel - no tab...?? would it not be better to render it with the tabs,
36299 // and hide them... ???
36300 this.bodyEl.dom.appendChild(panel.getEl().dom);
36301 if(panel.background !== true){
36302 this.setActivePanel(panel);
36304 this.fireEvent("paneladded", this, panel);
36311 this.initPanelAsTab(panel);
36315 if(panel.background !== true){
36316 this.tabs.activate(panel.getEl().id);
36318 this.fireEvent("paneladded", this, panel);
36323 * Hides the tab for the specified panel.
36324 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36326 hidePanel : function(panel){
36327 if(this.tabs && (panel = this.getPanel(panel))){
36328 this.tabs.hideTab(panel.getEl().id);
36333 * Unhides the tab for a previously hidden panel.
36334 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36336 unhidePanel : function(panel){
36337 if(this.tabs && (panel = this.getPanel(panel))){
36338 this.tabs.unhideTab(panel.getEl().id);
36342 clearPanels : function(){
36343 while(this.panels.getCount() > 0){
36344 this.remove(this.panels.first());
36349 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
36350 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36351 * @param {Boolean} preservePanel Overrides the config preservePanel option
36352 * @return {Roo.ContentPanel} The panel that was removed
36354 remove : function(panel, preservePanel)
36356 panel = this.getPanel(panel);
36361 this.fireEvent("beforeremove", this, panel, e);
36362 if(e.cancel === true){
36365 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
36366 var panelId = panel.getId();
36367 this.panels.removeKey(panelId);
36369 document.body.appendChild(panel.getEl().dom);
36372 this.tabs.removeTab(panel.getEl().id);
36373 }else if (!preservePanel){
36374 this.bodyEl.dom.removeChild(panel.getEl().dom);
36376 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
36377 var p = this.panels.first();
36378 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
36379 tempEl.appendChild(p.getEl().dom);
36380 this.bodyEl.update("");
36381 this.bodyEl.dom.appendChild(p.getEl().dom);
36383 this.updateTitle(p.getTitle());
36385 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
36386 this.setActivePanel(p);
36388 panel.setRegion(null);
36389 if(this.activePanel == panel){
36390 this.activePanel = null;
36392 if(this.config.autoDestroy !== false && preservePanel !== true){
36393 try{panel.destroy();}catch(e){}
36395 this.fireEvent("panelremoved", this, panel);
36400 * Returns the TabPanel component used by this region
36401 * @return {Roo.TabPanel}
36403 getTabs : function(){
36407 createTool : function(parentEl, className){
36408 var btn = Roo.DomHelper.append(parentEl, {
36410 cls: "x-layout-tools-button",
36413 cls: "roo-layout-tools-button-inner " + className,
36417 btn.addClassOnOver("roo-layout-tools-button-over");
36422 * Ext JS Library 1.1.1
36423 * Copyright(c) 2006-2007, Ext JS, LLC.
36425 * Originally Released Under LGPL - original licence link has changed is not relivant.
36428 * <script type="text/javascript">
36434 * @class Roo.SplitLayoutRegion
36435 * @extends Roo.LayoutRegion
36436 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
36438 Roo.bootstrap.layout.Split = function(config){
36439 this.cursor = config.cursor;
36440 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
36443 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
36445 splitTip : "Drag to resize.",
36446 collapsibleSplitTip : "Drag to resize. Double click to hide.",
36447 useSplitTips : false,
36449 applyConfig : function(config){
36450 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
36453 onRender : function(ctr,pos) {
36455 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
36456 if(!this.config.split){
36461 var splitEl = Roo.DomHelper.append(ctr.dom, {
36463 id: this.el.id + "-split",
36464 cls: "roo-layout-split roo-layout-split-"+this.position,
36467 /** The SplitBar for this region
36468 * @type Roo.SplitBar */
36469 // does not exist yet...
36470 Roo.log([this.position, this.orientation]);
36472 this.split = new Roo.bootstrap.SplitBar({
36473 dragElement : splitEl,
36474 resizingElement: this.el,
36475 orientation : this.orientation
36478 this.split.on("moved", this.onSplitMove, this);
36479 this.split.useShim = this.config.useShim === true;
36480 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
36481 if(this.useSplitTips){
36482 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
36484 //if(config.collapsible){
36485 // this.split.el.on("dblclick", this.collapse, this);
36488 if(typeof this.config.minSize != "undefined"){
36489 this.split.minSize = this.config.minSize;
36491 if(typeof this.config.maxSize != "undefined"){
36492 this.split.maxSize = this.config.maxSize;
36494 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
36495 this.hideSplitter();
36500 getHMaxSize : function(){
36501 var cmax = this.config.maxSize || 10000;
36502 var center = this.mgr.getRegion("center");
36503 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
36506 getVMaxSize : function(){
36507 var cmax = this.config.maxSize || 10000;
36508 var center = this.mgr.getRegion("center");
36509 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
36512 onSplitMove : function(split, newSize){
36513 this.fireEvent("resized", this, newSize);
36517 * Returns the {@link Roo.SplitBar} for this region.
36518 * @return {Roo.SplitBar}
36520 getSplitBar : function(){
36525 this.hideSplitter();
36526 Roo.bootstrap.layout.Split.superclass.hide.call(this);
36529 hideSplitter : function(){
36531 this.split.el.setLocation(-2000,-2000);
36532 this.split.el.hide();
36538 this.split.el.show();
36540 Roo.bootstrap.layout.Split.superclass.show.call(this);
36543 beforeSlide: function(){
36544 if(Roo.isGecko){// firefox overflow auto bug workaround
36545 this.bodyEl.clip();
36547 this.tabs.bodyEl.clip();
36549 if(this.activePanel){
36550 this.activePanel.getEl().clip();
36552 if(this.activePanel.beforeSlide){
36553 this.activePanel.beforeSlide();
36559 afterSlide : function(){
36560 if(Roo.isGecko){// firefox overflow auto bug workaround
36561 this.bodyEl.unclip();
36563 this.tabs.bodyEl.unclip();
36565 if(this.activePanel){
36566 this.activePanel.getEl().unclip();
36567 if(this.activePanel.afterSlide){
36568 this.activePanel.afterSlide();
36574 initAutoHide : function(){
36575 if(this.autoHide !== false){
36576 if(!this.autoHideHd){
36577 var st = new Roo.util.DelayedTask(this.slideIn, this);
36578 this.autoHideHd = {
36579 "mouseout": function(e){
36580 if(!e.within(this.el, true)){
36584 "mouseover" : function(e){
36590 this.el.on(this.autoHideHd);
36594 clearAutoHide : function(){
36595 if(this.autoHide !== false){
36596 this.el.un("mouseout", this.autoHideHd.mouseout);
36597 this.el.un("mouseover", this.autoHideHd.mouseover);
36601 clearMonitor : function(){
36602 Roo.get(document).un("click", this.slideInIf, this);
36605 // these names are backwards but not changed for compat
36606 slideOut : function(){
36607 if(this.isSlid || this.el.hasActiveFx()){
36610 this.isSlid = true;
36611 if(this.collapseBtn){
36612 this.collapseBtn.hide();
36614 this.closeBtnState = this.closeBtn.getStyle('display');
36615 this.closeBtn.hide();
36617 this.stickBtn.show();
36620 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
36621 this.beforeSlide();
36622 this.el.setStyle("z-index", 10001);
36623 this.el.slideIn(this.getSlideAnchor(), {
36624 callback: function(){
36626 this.initAutoHide();
36627 Roo.get(document).on("click", this.slideInIf, this);
36628 this.fireEvent("slideshow", this);
36635 afterSlideIn : function(){
36636 this.clearAutoHide();
36637 this.isSlid = false;
36638 this.clearMonitor();
36639 this.el.setStyle("z-index", "");
36640 if(this.collapseBtn){
36641 this.collapseBtn.show();
36643 this.closeBtn.setStyle('display', this.closeBtnState);
36645 this.stickBtn.hide();
36647 this.fireEvent("slidehide", this);
36650 slideIn : function(cb){
36651 if(!this.isSlid || this.el.hasActiveFx()){
36655 this.isSlid = false;
36656 this.beforeSlide();
36657 this.el.slideOut(this.getSlideAnchor(), {
36658 callback: function(){
36659 this.el.setLeftTop(-10000, -10000);
36661 this.afterSlideIn();
36669 slideInIf : function(e){
36670 if(!e.within(this.el)){
36675 animateCollapse : function(){
36676 this.beforeSlide();
36677 this.el.setStyle("z-index", 20000);
36678 var anchor = this.getSlideAnchor();
36679 this.el.slideOut(anchor, {
36680 callback : function(){
36681 this.el.setStyle("z-index", "");
36682 this.collapsedEl.slideIn(anchor, {duration:.3});
36684 this.el.setLocation(-10000,-10000);
36686 this.fireEvent("collapsed", this);
36693 animateExpand : function(){
36694 this.beforeSlide();
36695 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
36696 this.el.setStyle("z-index", 20000);
36697 this.collapsedEl.hide({
36700 this.el.slideIn(this.getSlideAnchor(), {
36701 callback : function(){
36702 this.el.setStyle("z-index", "");
36705 this.split.el.show();
36707 this.fireEvent("invalidated", this);
36708 this.fireEvent("expanded", this);
36736 getAnchor : function(){
36737 return this.anchors[this.position];
36740 getCollapseAnchor : function(){
36741 return this.canchors[this.position];
36744 getSlideAnchor : function(){
36745 return this.sanchors[this.position];
36748 getAlignAdj : function(){
36749 var cm = this.cmargins;
36750 switch(this.position){
36766 getExpandAdj : function(){
36767 var c = this.collapsedEl, cm = this.cmargins;
36768 switch(this.position){
36770 return [-(cm.right+c.getWidth()+cm.left), 0];
36773 return [cm.right+c.getWidth()+cm.left, 0];
36776 return [0, -(cm.top+cm.bottom+c.getHeight())];
36779 return [0, cm.top+cm.bottom+c.getHeight()];
36785 * Ext JS Library 1.1.1
36786 * Copyright(c) 2006-2007, Ext JS, LLC.
36788 * Originally Released Under LGPL - original licence link has changed is not relivant.
36791 * <script type="text/javascript">
36794 * These classes are private internal classes
36796 Roo.bootstrap.layout.Center = function(config){
36797 config.region = "center";
36798 Roo.bootstrap.layout.Region.call(this, config);
36799 this.visible = true;
36800 this.minWidth = config.minWidth || 20;
36801 this.minHeight = config.minHeight || 20;
36804 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
36806 // center panel can't be hidden
36810 // center panel can't be hidden
36813 getMinWidth: function(){
36814 return this.minWidth;
36817 getMinHeight: function(){
36818 return this.minHeight;
36831 Roo.bootstrap.layout.North = function(config)
36833 config.region = 'north';
36834 config.cursor = 'n-resize';
36836 Roo.bootstrap.layout.Split.call(this, config);
36840 this.split.placement = Roo.bootstrap.SplitBar.TOP;
36841 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36842 this.split.el.addClass("roo-layout-split-v");
36844 var size = config.initialSize || config.height;
36845 if(typeof size != "undefined"){
36846 this.el.setHeight(size);
36849 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
36851 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36855 getBox : function(){
36856 if(this.collapsed){
36857 return this.collapsedEl.getBox();
36859 var box = this.el.getBox();
36861 box.height += this.split.el.getHeight();
36866 updateBox : function(box){
36867 if(this.split && !this.collapsed){
36868 box.height -= this.split.el.getHeight();
36869 this.split.el.setLeft(box.x);
36870 this.split.el.setTop(box.y+box.height);
36871 this.split.el.setWidth(box.width);
36873 if(this.collapsed){
36874 this.updateBody(box.width, null);
36876 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36884 Roo.bootstrap.layout.South = function(config){
36885 config.region = 'south';
36886 config.cursor = 's-resize';
36887 Roo.bootstrap.layout.Split.call(this, config);
36889 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
36890 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36891 this.split.el.addClass("roo-layout-split-v");
36893 var size = config.initialSize || config.height;
36894 if(typeof size != "undefined"){
36895 this.el.setHeight(size);
36899 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
36900 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36901 getBox : function(){
36902 if(this.collapsed){
36903 return this.collapsedEl.getBox();
36905 var box = this.el.getBox();
36907 var sh = this.split.el.getHeight();
36914 updateBox : function(box){
36915 if(this.split && !this.collapsed){
36916 var sh = this.split.el.getHeight();
36919 this.split.el.setLeft(box.x);
36920 this.split.el.setTop(box.y-sh);
36921 this.split.el.setWidth(box.width);
36923 if(this.collapsed){
36924 this.updateBody(box.width, null);
36926 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36930 Roo.bootstrap.layout.East = function(config){
36931 config.region = "east";
36932 config.cursor = "e-resize";
36933 Roo.bootstrap.layout.Split.call(this, config);
36935 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
36936 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36937 this.split.el.addClass("roo-layout-split-h");
36939 var size = config.initialSize || config.width;
36940 if(typeof size != "undefined"){
36941 this.el.setWidth(size);
36944 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
36945 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36946 getBox : function(){
36947 if(this.collapsed){
36948 return this.collapsedEl.getBox();
36950 var box = this.el.getBox();
36952 var sw = this.split.el.getWidth();
36959 updateBox : function(box){
36960 if(this.split && !this.collapsed){
36961 var sw = this.split.el.getWidth();
36963 this.split.el.setLeft(box.x);
36964 this.split.el.setTop(box.y);
36965 this.split.el.setHeight(box.height);
36968 if(this.collapsed){
36969 this.updateBody(null, box.height);
36971 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36975 Roo.bootstrap.layout.West = function(config){
36976 config.region = "west";
36977 config.cursor = "w-resize";
36979 Roo.bootstrap.layout.Split.call(this, config);
36981 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
36982 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36983 this.split.el.addClass("roo-layout-split-h");
36987 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
36988 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36990 onRender: function(ctr, pos)
36992 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
36993 var size = this.config.initialSize || this.config.width;
36994 if(typeof size != "undefined"){
36995 this.el.setWidth(size);
36999 getBox : function(){
37000 if(this.collapsed){
37001 return this.collapsedEl.getBox();
37003 var box = this.el.getBox();
37005 box.width += this.split.el.getWidth();
37010 updateBox : function(box){
37011 if(this.split && !this.collapsed){
37012 var sw = this.split.el.getWidth();
37014 this.split.el.setLeft(box.x+box.width);
37015 this.split.el.setTop(box.y);
37016 this.split.el.setHeight(box.height);
37018 if(this.collapsed){
37019 this.updateBody(null, box.height);
37021 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37024 Roo.namespace("Roo.bootstrap.panel");/*
37026 * Ext JS Library 1.1.1
37027 * Copyright(c) 2006-2007, Ext JS, LLC.
37029 * Originally Released Under LGPL - original licence link has changed is not relivant.
37032 * <script type="text/javascript">
37035 * @class Roo.ContentPanel
37036 * @extends Roo.util.Observable
37037 * A basic ContentPanel element.
37038 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
37039 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
37040 * @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
37041 * @cfg {Boolean} closable True if the panel can be closed/removed
37042 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
37043 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
37044 * @cfg {Toolbar} toolbar A toolbar for this panel
37045 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
37046 * @cfg {String} title The title for this panel
37047 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
37048 * @cfg {String} url Calls {@link #setUrl} with this value
37049 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
37050 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
37051 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
37052 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
37053 * @cfg {Boolean} badges render the badges
37056 * Create a new ContentPanel.
37057 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
37058 * @param {String/Object} config A string to set only the title or a config object
37059 * @param {String} content (optional) Set the HTML content for this panel
37060 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
37062 Roo.bootstrap.panel.Content = function( config){
37064 this.tpl = config.tpl || false;
37066 var el = config.el;
37067 var content = config.content;
37069 if(config.autoCreate){ // xtype is available if this is called from factory
37072 this.el = Roo.get(el);
37073 if(!this.el && config && config.autoCreate){
37074 if(typeof config.autoCreate == "object"){
37075 if(!config.autoCreate.id){
37076 config.autoCreate.id = config.id||el;
37078 this.el = Roo.DomHelper.append(document.body,
37079 config.autoCreate, true);
37081 var elcfg = { tag: "div",
37082 cls: "roo-layout-inactive-content",
37086 elcfg.html = config.html;
37090 this.el = Roo.DomHelper.append(document.body, elcfg , true);
37093 this.closable = false;
37094 this.loaded = false;
37095 this.active = false;
37098 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
37100 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
37102 this.wrapEl = this.el; //this.el.wrap();
37104 if (config.toolbar.items) {
37105 ti = config.toolbar.items ;
37106 delete config.toolbar.items ;
37110 this.toolbar.render(this.wrapEl, 'before');
37111 for(var i =0;i < ti.length;i++) {
37112 // Roo.log(['add child', items[i]]);
37113 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37115 this.toolbar.items = nitems;
37116 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
37117 delete config.toolbar;
37121 // xtype created footer. - not sure if will work as we normally have to render first..
37122 if (this.footer && !this.footer.el && this.footer.xtype) {
37123 if (!this.wrapEl) {
37124 this.wrapEl = this.el.wrap();
37127 this.footer.container = this.wrapEl.createChild();
37129 this.footer = Roo.factory(this.footer, Roo);
37134 if(typeof config == "string"){
37135 this.title = config;
37137 Roo.apply(this, config);
37141 this.resizeEl = Roo.get(this.resizeEl, true);
37143 this.resizeEl = this.el;
37145 // handle view.xtype
37153 * Fires when this panel is activated.
37154 * @param {Roo.ContentPanel} this
37158 * @event deactivate
37159 * Fires when this panel is activated.
37160 * @param {Roo.ContentPanel} this
37162 "deactivate" : true,
37166 * Fires when this panel is resized if fitToFrame is true.
37167 * @param {Roo.ContentPanel} this
37168 * @param {Number} width The width after any component adjustments
37169 * @param {Number} height The height after any component adjustments
37175 * Fires when this tab is created
37176 * @param {Roo.ContentPanel} this
37187 if(this.autoScroll){
37188 this.resizeEl.setStyle("overflow", "auto");
37190 // fix randome scrolling
37191 //this.el.on('scroll', function() {
37192 // Roo.log('fix random scolling');
37193 // this.scrollTo('top',0);
37196 content = content || this.content;
37198 this.setContent(content);
37200 if(config && config.url){
37201 this.setUrl(this.url, this.params, this.loadOnce);
37206 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
37208 if (this.view && typeof(this.view.xtype) != 'undefined') {
37209 this.view.el = this.el.appendChild(document.createElement("div"));
37210 this.view = Roo.factory(this.view);
37211 this.view.render && this.view.render(false, '');
37215 this.fireEvent('render', this);
37218 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
37222 setRegion : function(region){
37223 this.region = region;
37224 this.setActiveClass(region && !this.background);
37228 setActiveClass: function(state)
37231 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
37232 this.el.setStyle('position','relative');
37234 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
37235 this.el.setStyle('position', 'absolute');
37240 * Returns the toolbar for this Panel if one was configured.
37241 * @return {Roo.Toolbar}
37243 getToolbar : function(){
37244 return this.toolbar;
37247 setActiveState : function(active)
37249 this.active = active;
37250 this.setActiveClass(active);
37252 if(this.fireEvent("deactivate", this) === false){
37257 this.fireEvent("activate", this);
37261 * Updates this panel's element
37262 * @param {String} content The new content
37263 * @param {Boolean} loadScripts (optional) true to look for and process scripts
37265 setContent : function(content, loadScripts){
37266 this.el.update(content, loadScripts);
37269 ignoreResize : function(w, h){
37270 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
37273 this.lastSize = {width: w, height: h};
37278 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
37279 * @return {Roo.UpdateManager} The UpdateManager
37281 getUpdateManager : function(){
37282 return this.el.getUpdateManager();
37285 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
37286 * @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:
37289 url: "your-url.php",
37290 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
37291 callback: yourFunction,
37292 scope: yourObject, //(optional scope)
37295 text: "Loading...",
37300 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
37301 * 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.
37302 * @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}
37303 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
37304 * @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.
37305 * @return {Roo.ContentPanel} this
37308 var um = this.el.getUpdateManager();
37309 um.update.apply(um, arguments);
37315 * 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.
37316 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
37317 * @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)
37318 * @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)
37319 * @return {Roo.UpdateManager} The UpdateManager
37321 setUrl : function(url, params, loadOnce){
37322 if(this.refreshDelegate){
37323 this.removeListener("activate", this.refreshDelegate);
37325 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
37326 this.on("activate", this.refreshDelegate);
37327 return this.el.getUpdateManager();
37330 _handleRefresh : function(url, params, loadOnce){
37331 if(!loadOnce || !this.loaded){
37332 var updater = this.el.getUpdateManager();
37333 updater.update(url, params, this._setLoaded.createDelegate(this));
37337 _setLoaded : function(){
37338 this.loaded = true;
37342 * Returns this panel's id
37345 getId : function(){
37350 * Returns this panel's element - used by regiosn to add.
37351 * @return {Roo.Element}
37353 getEl : function(){
37354 return this.wrapEl || this.el;
37359 adjustForComponents : function(width, height)
37361 //Roo.log('adjustForComponents ');
37362 if(this.resizeEl != this.el){
37363 width -= this.el.getFrameWidth('lr');
37364 height -= this.el.getFrameWidth('tb');
37367 var te = this.toolbar.getEl();
37368 te.setWidth(width);
37369 height -= te.getHeight();
37372 var te = this.footer.getEl();
37373 te.setWidth(width);
37374 height -= te.getHeight();
37378 if(this.adjustments){
37379 width += this.adjustments[0];
37380 height += this.adjustments[1];
37382 return {"width": width, "height": height};
37385 setSize : function(width, height){
37386 if(this.fitToFrame && !this.ignoreResize(width, height)){
37387 if(this.fitContainer && this.resizeEl != this.el){
37388 this.el.setSize(width, height);
37390 var size = this.adjustForComponents(width, height);
37391 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
37392 this.fireEvent('resize', this, size.width, size.height);
37397 * Returns this panel's title
37400 getTitle : function(){
37402 if (typeof(this.title) != 'object') {
37407 for (var k in this.title) {
37408 if (!this.title.hasOwnProperty(k)) {
37412 if (k.indexOf('-') >= 0) {
37413 var s = k.split('-');
37414 for (var i = 0; i<s.length; i++) {
37415 t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
37418 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
37425 * Set this panel's title
37426 * @param {String} title
37428 setTitle : function(title){
37429 this.title = title;
37431 this.region.updatePanelTitle(this, title);
37436 * Returns true is this panel was configured to be closable
37437 * @return {Boolean}
37439 isClosable : function(){
37440 return this.closable;
37443 beforeSlide : function(){
37445 this.resizeEl.clip();
37448 afterSlide : function(){
37450 this.resizeEl.unclip();
37454 * Force a content refresh from the URL specified in the {@link #setUrl} method.
37455 * Will fail silently if the {@link #setUrl} method has not been called.
37456 * This does not activate the panel, just updates its content.
37458 refresh : function(){
37459 if(this.refreshDelegate){
37460 this.loaded = false;
37461 this.refreshDelegate();
37466 * Destroys this panel
37468 destroy : function(){
37469 this.el.removeAllListeners();
37470 var tempEl = document.createElement("span");
37471 tempEl.appendChild(this.el.dom);
37472 tempEl.innerHTML = "";
37478 * form - if the content panel contains a form - this is a reference to it.
37479 * @type {Roo.form.Form}
37483 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
37484 * This contains a reference to it.
37490 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
37500 * @param {Object} cfg Xtype definition of item to add.
37504 getChildContainer: function () {
37505 return this.getEl();
37510 var ret = new Roo.factory(cfg);
37515 if (cfg.xtype.match(/^Form$/)) {
37518 //if (this.footer) {
37519 // el = this.footer.container.insertSibling(false, 'before');
37521 el = this.el.createChild();
37524 this.form = new Roo.form.Form(cfg);
37527 if ( this.form.allItems.length) {
37528 this.form.render(el.dom);
37532 // should only have one of theses..
37533 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
37534 // views.. should not be just added - used named prop 'view''
37536 cfg.el = this.el.appendChild(document.createElement("div"));
37539 var ret = new Roo.factory(cfg);
37541 ret.render && ret.render(false, ''); // render blank..
37551 * @class Roo.bootstrap.panel.Grid
37552 * @extends Roo.bootstrap.panel.Content
37554 * Create a new GridPanel.
37555 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
37556 * @param {Object} config A the config object
37562 Roo.bootstrap.panel.Grid = function(config)
37566 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
37567 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
37569 config.el = this.wrapper;
37570 //this.el = this.wrapper;
37572 if (config.container) {
37573 // ctor'ed from a Border/panel.grid
37576 this.wrapper.setStyle("overflow", "hidden");
37577 this.wrapper.addClass('roo-grid-container');
37582 if(config.toolbar){
37583 var tool_el = this.wrapper.createChild();
37584 this.toolbar = Roo.factory(config.toolbar);
37586 if (config.toolbar.items) {
37587 ti = config.toolbar.items ;
37588 delete config.toolbar.items ;
37592 this.toolbar.render(tool_el);
37593 for(var i =0;i < ti.length;i++) {
37594 // Roo.log(['add child', items[i]]);
37595 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37597 this.toolbar.items = nitems;
37599 delete config.toolbar;
37602 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
37603 config.grid.scrollBody = true;;
37604 config.grid.monitorWindowResize = false; // turn off autosizing
37605 config.grid.autoHeight = false;
37606 config.grid.autoWidth = false;
37608 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
37610 if (config.background) {
37611 // render grid on panel activation (if panel background)
37612 this.on('activate', function(gp) {
37613 if (!gp.grid.rendered) {
37614 gp.grid.render(this.wrapper);
37615 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37620 this.grid.render(this.wrapper);
37621 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37624 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
37625 // ??? needed ??? config.el = this.wrapper;
37630 // xtype created footer. - not sure if will work as we normally have to render first..
37631 if (this.footer && !this.footer.el && this.footer.xtype) {
37633 var ctr = this.grid.getView().getFooterPanel(true);
37634 this.footer.dataSource = this.grid.dataSource;
37635 this.footer = Roo.factory(this.footer, Roo);
37636 this.footer.render(ctr);
37646 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
37647 getId : function(){
37648 return this.grid.id;
37652 * Returns the grid for this panel
37653 * @return {Roo.bootstrap.Table}
37655 getGrid : function(){
37659 setSize : function(width, height){
37660 if(!this.ignoreResize(width, height)){
37661 var grid = this.grid;
37662 var size = this.adjustForComponents(width, height);
37663 var gridel = grid.getGridEl();
37664 gridel.setSize(size.width, size.height);
37666 var thd = grid.getGridEl().select('thead',true).first();
37667 var tbd = grid.getGridEl().select('tbody', true).first();
37669 tbd.setSize(width, height - thd.getHeight());
37678 beforeSlide : function(){
37679 this.grid.getView().scroller.clip();
37682 afterSlide : function(){
37683 this.grid.getView().scroller.unclip();
37686 destroy : function(){
37687 this.grid.destroy();
37689 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
37694 * @class Roo.bootstrap.panel.Nest
37695 * @extends Roo.bootstrap.panel.Content
37697 * Create a new Panel, that can contain a layout.Border.
37700 * @param {Roo.BorderLayout} layout The layout for this panel
37701 * @param {String/Object} config A string to set only the title or a config object
37703 Roo.bootstrap.panel.Nest = function(config)
37705 // construct with only one argument..
37706 /* FIXME - implement nicer consturctors
37707 if (layout.layout) {
37709 layout = config.layout;
37710 delete config.layout;
37712 if (layout.xtype && !layout.getEl) {
37713 // then layout needs constructing..
37714 layout = Roo.factory(layout, Roo);
37718 config.el = config.layout.getEl();
37720 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
37722 config.layout.monitorWindowResize = false; // turn off autosizing
37723 this.layout = config.layout;
37724 this.layout.getEl().addClass("roo-layout-nested-layout");
37731 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
37733 setSize : function(width, height){
37734 if(!this.ignoreResize(width, height)){
37735 var size = this.adjustForComponents(width, height);
37736 var el = this.layout.getEl();
37737 if (size.height < 1) {
37738 el.setWidth(size.width);
37740 el.setSize(size.width, size.height);
37742 var touch = el.dom.offsetWidth;
37743 this.layout.layout();
37744 // ie requires a double layout on the first pass
37745 if(Roo.isIE && !this.initialized){
37746 this.initialized = true;
37747 this.layout.layout();
37752 // activate all subpanels if not currently active..
37754 setActiveState : function(active){
37755 this.active = active;
37756 this.setActiveClass(active);
37759 this.fireEvent("deactivate", this);
37763 this.fireEvent("activate", this);
37764 // not sure if this should happen before or after..
37765 if (!this.layout) {
37766 return; // should not happen..
37769 for (var r in this.layout.regions) {
37770 reg = this.layout.getRegion(r);
37771 if (reg.getActivePanel()) {
37772 //reg.showPanel(reg.getActivePanel()); // force it to activate..
37773 reg.setActivePanel(reg.getActivePanel());
37776 if (!reg.panels.length) {
37779 reg.showPanel(reg.getPanel(0));
37788 * Returns the nested BorderLayout for this panel
37789 * @return {Roo.BorderLayout}
37791 getLayout : function(){
37792 return this.layout;
37796 * Adds a xtype elements to the layout of the nested panel
37800 xtype : 'ContentPanel',
37807 xtype : 'NestedLayoutPanel',
37813 items : [ ... list of content panels or nested layout panels.. ]
37817 * @param {Object} cfg Xtype definition of item to add.
37819 addxtype : function(cfg) {
37820 return this.layout.addxtype(cfg);
37825 * Ext JS Library 1.1.1
37826 * Copyright(c) 2006-2007, Ext JS, LLC.
37828 * Originally Released Under LGPL - original licence link has changed is not relivant.
37831 * <script type="text/javascript">
37834 * @class Roo.TabPanel
37835 * @extends Roo.util.Observable
37836 * A lightweight tab container.
37840 // basic tabs 1, built from existing content
37841 var tabs = new Roo.TabPanel("tabs1");
37842 tabs.addTab("script", "View Script");
37843 tabs.addTab("markup", "View Markup");
37844 tabs.activate("script");
37846 // more advanced tabs, built from javascript
37847 var jtabs = new Roo.TabPanel("jtabs");
37848 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
37850 // set up the UpdateManager
37851 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
37852 var updater = tab2.getUpdateManager();
37853 updater.setDefaultUrl("ajax1.htm");
37854 tab2.on('activate', updater.refresh, updater, true);
37856 // Use setUrl for Ajax loading
37857 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
37858 tab3.setUrl("ajax2.htm", null, true);
37861 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
37864 jtabs.activate("jtabs-1");
37867 * Create a new TabPanel.
37868 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
37869 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
37871 Roo.bootstrap.panel.Tabs = function(config){
37873 * The container element for this TabPanel.
37874 * @type Roo.Element
37876 this.el = Roo.get(config.el);
37879 if(typeof config == "boolean"){
37880 this.tabPosition = config ? "bottom" : "top";
37882 Roo.apply(this, config);
37886 if(this.tabPosition == "bottom"){
37887 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37888 this.el.addClass("roo-tabs-bottom");
37890 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
37891 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
37892 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
37894 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
37896 if(this.tabPosition != "bottom"){
37897 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
37898 * @type Roo.Element
37900 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37901 this.el.addClass("roo-tabs-top");
37905 this.bodyEl.setStyle("position", "relative");
37907 this.active = null;
37908 this.activateDelegate = this.activate.createDelegate(this);
37913 * Fires when the active tab changes
37914 * @param {Roo.TabPanel} this
37915 * @param {Roo.TabPanelItem} activePanel The new active tab
37919 * @event beforetabchange
37920 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
37921 * @param {Roo.TabPanel} this
37922 * @param {Object} e Set cancel to true on this object to cancel the tab change
37923 * @param {Roo.TabPanelItem} tab The tab being changed to
37925 "beforetabchange" : true
37928 Roo.EventManager.onWindowResize(this.onResize, this);
37929 this.cpad = this.el.getPadding("lr");
37930 this.hiddenCount = 0;
37933 // toolbar on the tabbar support...
37934 if (this.toolbar) {
37935 alert("no toolbar support yet");
37936 this.toolbar = false;
37938 var tcfg = this.toolbar;
37939 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
37940 this.toolbar = new Roo.Toolbar(tcfg);
37941 if (Roo.isSafari) {
37942 var tbl = tcfg.container.child('table', true);
37943 tbl.setAttribute('width', '100%');
37951 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
37954 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
37956 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
37958 tabPosition : "top",
37960 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
37962 currentTabWidth : 0,
37964 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
37968 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
37972 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
37974 preferredTabWidth : 175,
37976 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
37978 resizeTabs : false,
37980 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
37982 monitorResize : true,
37984 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
37989 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
37990 * @param {String} id The id of the div to use <b>or create</b>
37991 * @param {String} text The text for the tab
37992 * @param {String} content (optional) Content to put in the TabPanelItem body
37993 * @param {Boolean} closable (optional) True to create a close icon on the tab
37994 * @return {Roo.TabPanelItem} The created TabPanelItem
37996 addTab : function(id, text, content, closable, tpl)
37998 var item = new Roo.bootstrap.panel.TabItem({
38002 closable : closable,
38005 this.addTabItem(item);
38007 item.setContent(content);
38013 * Returns the {@link Roo.TabPanelItem} with the specified id/index
38014 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
38015 * @return {Roo.TabPanelItem}
38017 getTab : function(id){
38018 return this.items[id];
38022 * Hides the {@link Roo.TabPanelItem} with the specified id/index
38023 * @param {String/Number} id The id or index of the TabPanelItem to hide.
38025 hideTab : function(id){
38026 var t = this.items[id];
38029 this.hiddenCount++;
38030 this.autoSizeTabs();
38035 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
38036 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
38038 unhideTab : function(id){
38039 var t = this.items[id];
38041 t.setHidden(false);
38042 this.hiddenCount--;
38043 this.autoSizeTabs();
38048 * Adds an existing {@link Roo.TabPanelItem}.
38049 * @param {Roo.TabPanelItem} item The TabPanelItem to add
38051 addTabItem : function(item){
38052 this.items[item.id] = item;
38053 this.items.push(item);
38054 // if(this.resizeTabs){
38055 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
38056 // this.autoSizeTabs();
38058 // item.autoSize();
38063 * Removes a {@link Roo.TabPanelItem}.
38064 * @param {String/Number} id The id or index of the TabPanelItem to remove.
38066 removeTab : function(id){
38067 var items = this.items;
38068 var tab = items[id];
38069 if(!tab) { return; }
38070 var index = items.indexOf(tab);
38071 if(this.active == tab && items.length > 1){
38072 var newTab = this.getNextAvailable(index);
38077 this.stripEl.dom.removeChild(tab.pnode.dom);
38078 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
38079 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
38081 items.splice(index, 1);
38082 delete this.items[tab.id];
38083 tab.fireEvent("close", tab);
38084 tab.purgeListeners();
38085 this.autoSizeTabs();
38088 getNextAvailable : function(start){
38089 var items = this.items;
38091 // look for a next tab that will slide over to
38092 // replace the one being removed
38093 while(index < items.length){
38094 var item = items[++index];
38095 if(item && !item.isHidden()){
38099 // if one isn't found select the previous tab (on the left)
38102 var item = items[--index];
38103 if(item && !item.isHidden()){
38111 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
38112 * @param {String/Number} id The id or index of the TabPanelItem to disable.
38114 disableTab : function(id){
38115 var tab = this.items[id];
38116 if(tab && this.active != tab){
38122 * Enables a {@link Roo.TabPanelItem} that is disabled.
38123 * @param {String/Number} id The id or index of the TabPanelItem to enable.
38125 enableTab : function(id){
38126 var tab = this.items[id];
38131 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
38132 * @param {String/Number} id The id or index of the TabPanelItem to activate.
38133 * @return {Roo.TabPanelItem} The TabPanelItem.
38135 activate : function(id){
38136 var tab = this.items[id];
38140 if(tab == this.active || tab.disabled){
38144 this.fireEvent("beforetabchange", this, e, tab);
38145 if(e.cancel !== true && !tab.disabled){
38147 this.active.hide();
38149 this.active = this.items[id];
38150 this.active.show();
38151 this.fireEvent("tabchange", this, this.active);
38157 * Gets the active {@link Roo.TabPanelItem}.
38158 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
38160 getActiveTab : function(){
38161 return this.active;
38165 * Updates the tab body element to fit the height of the container element
38166 * for overflow scrolling
38167 * @param {Number} targetHeight (optional) Override the starting height from the elements height
38169 syncHeight : function(targetHeight){
38170 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
38171 var bm = this.bodyEl.getMargins();
38172 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
38173 this.bodyEl.setHeight(newHeight);
38177 onResize : function(){
38178 if(this.monitorResize){
38179 this.autoSizeTabs();
38184 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
38186 beginUpdate : function(){
38187 this.updating = true;
38191 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
38193 endUpdate : function(){
38194 this.updating = false;
38195 this.autoSizeTabs();
38199 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
38201 autoSizeTabs : function(){
38202 var count = this.items.length;
38203 var vcount = count - this.hiddenCount;
38204 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
38207 var w = Math.max(this.el.getWidth() - this.cpad, 10);
38208 var availWidth = Math.floor(w / vcount);
38209 var b = this.stripBody;
38210 if(b.getWidth() > w){
38211 var tabs = this.items;
38212 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
38213 if(availWidth < this.minTabWidth){
38214 /*if(!this.sleft){ // incomplete scrolling code
38215 this.createScrollButtons();
38218 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
38221 if(this.currentTabWidth < this.preferredTabWidth){
38222 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
38228 * Returns the number of tabs in this TabPanel.
38231 getCount : function(){
38232 return this.items.length;
38236 * Resizes all the tabs to the passed width
38237 * @param {Number} The new width
38239 setTabWidth : function(width){
38240 this.currentTabWidth = width;
38241 for(var i = 0, len = this.items.length; i < len; i++) {
38242 if(!this.items[i].isHidden()) {
38243 this.items[i].setWidth(width);
38249 * Destroys this TabPanel
38250 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
38252 destroy : function(removeEl){
38253 Roo.EventManager.removeResizeListener(this.onResize, this);
38254 for(var i = 0, len = this.items.length; i < len; i++){
38255 this.items[i].purgeListeners();
38257 if(removeEl === true){
38258 this.el.update("");
38263 createStrip : function(container)
38265 var strip = document.createElement("nav");
38266 strip.className = "navbar navbar-default"; //"x-tabs-wrap";
38267 container.appendChild(strip);
38271 createStripList : function(strip)
38273 // div wrapper for retard IE
38274 // returns the "tr" element.
38275 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
38276 //'<div class="x-tabs-strip-wrap">'+
38277 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
38278 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
38279 return strip.firstChild; //.firstChild.firstChild.firstChild;
38281 createBody : function(container)
38283 var body = document.createElement("div");
38284 Roo.id(body, "tab-body");
38285 //Roo.fly(body).addClass("x-tabs-body");
38286 Roo.fly(body).addClass("tab-content");
38287 container.appendChild(body);
38290 createItemBody :function(bodyEl, id){
38291 var body = Roo.getDom(id);
38293 body = document.createElement("div");
38296 //Roo.fly(body).addClass("x-tabs-item-body");
38297 Roo.fly(body).addClass("tab-pane");
38298 bodyEl.insertBefore(body, bodyEl.firstChild);
38302 createStripElements : function(stripEl, text, closable, tpl)
38304 var td = document.createElement("li"); // was td..
38307 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
38310 stripEl.appendChild(td);
38312 td.className = "x-tabs-closable";
38313 if(!this.closeTpl){
38314 this.closeTpl = new Roo.Template(
38315 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38316 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
38317 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
38320 var el = this.closeTpl.overwrite(td, {"text": text});
38321 var close = el.getElementsByTagName("div")[0];
38322 var inner = el.getElementsByTagName("em")[0];
38323 return {"el": el, "close": close, "inner": inner};
38326 // not sure what this is..
38327 // if(!this.tabTpl){
38328 //this.tabTpl = new Roo.Template(
38329 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38330 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
38332 // this.tabTpl = new Roo.Template(
38333 // '<a href="#">' +
38334 // '<span unselectable="on"' +
38335 // (this.disableTooltips ? '' : ' title="{text}"') +
38336 // ' >{text}</span></a>'
38342 var template = tpl || this.tabTpl || false;
38346 template = new Roo.Template(
38348 '<span unselectable="on"' +
38349 (this.disableTooltips ? '' : ' title="{text}"') +
38350 ' >{text}</span></a>'
38354 switch (typeof(template)) {
38358 template = new Roo.Template(template);
38364 var el = template.overwrite(td, {"text": text});
38366 var inner = el.getElementsByTagName("span")[0];
38368 return {"el": el, "inner": inner};
38376 * @class Roo.TabPanelItem
38377 * @extends Roo.util.Observable
38378 * Represents an individual item (tab plus body) in a TabPanel.
38379 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
38380 * @param {String} id The id of this TabPanelItem
38381 * @param {String} text The text for the tab of this TabPanelItem
38382 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
38384 Roo.bootstrap.panel.TabItem = function(config){
38386 * The {@link Roo.TabPanel} this TabPanelItem belongs to
38387 * @type Roo.TabPanel
38389 this.tabPanel = config.panel;
38391 * The id for this TabPanelItem
38394 this.id = config.id;
38396 this.disabled = false;
38398 this.text = config.text;
38400 this.loaded = false;
38401 this.closable = config.closable;
38404 * The body element for this TabPanelItem.
38405 * @type Roo.Element
38407 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
38408 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
38409 this.bodyEl.setStyle("display", "block");
38410 this.bodyEl.setStyle("zoom", "1");
38411 //this.hideAction();
38413 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
38415 this.el = Roo.get(els.el);
38416 this.inner = Roo.get(els.inner, true);
38417 this.textEl = Roo.get(this.el.dom.firstChild, true);
38418 this.pnode = Roo.get(els.el.parentNode, true);
38419 // this.el.on("mousedown", this.onTabMouseDown, this);
38420 this.el.on("click", this.onTabClick, this);
38422 if(config.closable){
38423 var c = Roo.get(els.close, true);
38424 c.dom.title = this.closeText;
38425 c.addClassOnOver("close-over");
38426 c.on("click", this.closeClick, this);
38432 * Fires when this tab becomes the active tab.
38433 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38434 * @param {Roo.TabPanelItem} this
38438 * @event beforeclose
38439 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
38440 * @param {Roo.TabPanelItem} this
38441 * @param {Object} e Set cancel to true on this object to cancel the close.
38443 "beforeclose": true,
38446 * Fires when this tab is closed.
38447 * @param {Roo.TabPanelItem} this
38451 * @event deactivate
38452 * Fires when this tab is no longer the active tab.
38453 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38454 * @param {Roo.TabPanelItem} this
38456 "deactivate" : true
38458 this.hidden = false;
38460 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
38463 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
38465 purgeListeners : function(){
38466 Roo.util.Observable.prototype.purgeListeners.call(this);
38467 this.el.removeAllListeners();
38470 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
38473 this.pnode.addClass("active");
38476 this.tabPanel.stripWrap.repaint();
38478 this.fireEvent("activate", this.tabPanel, this);
38482 * Returns true if this tab is the active tab.
38483 * @return {Boolean}
38485 isActive : function(){
38486 return this.tabPanel.getActiveTab() == this;
38490 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
38493 this.pnode.removeClass("active");
38495 this.fireEvent("deactivate", this.tabPanel, this);
38498 hideAction : function(){
38499 this.bodyEl.hide();
38500 this.bodyEl.setStyle("position", "absolute");
38501 this.bodyEl.setLeft("-20000px");
38502 this.bodyEl.setTop("-20000px");
38505 showAction : function(){
38506 this.bodyEl.setStyle("position", "relative");
38507 this.bodyEl.setTop("");
38508 this.bodyEl.setLeft("");
38509 this.bodyEl.show();
38513 * Set the tooltip for the tab.
38514 * @param {String} tooltip The tab's tooltip
38516 setTooltip : function(text){
38517 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
38518 this.textEl.dom.qtip = text;
38519 this.textEl.dom.removeAttribute('title');
38521 this.textEl.dom.title = text;
38525 onTabClick : function(e){
38526 e.preventDefault();
38527 this.tabPanel.activate(this.id);
38530 onTabMouseDown : function(e){
38531 e.preventDefault();
38532 this.tabPanel.activate(this.id);
38535 getWidth : function(){
38536 return this.inner.getWidth();
38539 setWidth : function(width){
38540 var iwidth = width - this.pnode.getPadding("lr");
38541 this.inner.setWidth(iwidth);
38542 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
38543 this.pnode.setWidth(width);
38547 * Show or hide the tab
38548 * @param {Boolean} hidden True to hide or false to show.
38550 setHidden : function(hidden){
38551 this.hidden = hidden;
38552 this.pnode.setStyle("display", hidden ? "none" : "");
38556 * Returns true if this tab is "hidden"
38557 * @return {Boolean}
38559 isHidden : function(){
38560 return this.hidden;
38564 * Returns the text for this tab
38567 getText : function(){
38571 autoSize : function(){
38572 //this.el.beginMeasure();
38573 this.textEl.setWidth(1);
38575 * #2804 [new] Tabs in Roojs
38576 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
38578 //this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
38579 //this.el.endMeasure();
38583 * Sets the text for the tab (Note: this also sets the tooltip text)
38584 * @param {String} text The tab's text and tooltip
38586 setText : function(text){
38588 this.textEl.update(text);
38589 this.setTooltip(text);
38590 //if(!this.tabPanel.resizeTabs){
38591 // this.autoSize();
38595 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
38597 activate : function(){
38598 this.tabPanel.activate(this.id);
38602 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
38604 disable : function(){
38605 if(this.tabPanel.active != this){
38606 this.disabled = true;
38607 this.pnode.addClass("disabled");
38612 * Enables this TabPanelItem if it was previously disabled.
38614 enable : function(){
38615 this.disabled = false;
38616 this.pnode.removeClass("disabled");
38620 * Sets the content for this TabPanelItem.
38621 * @param {String} content The content
38622 * @param {Boolean} loadScripts true to look for and load scripts
38624 setContent : function(content, loadScripts){
38625 this.bodyEl.update(content, loadScripts);
38629 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
38630 * @return {Roo.UpdateManager} The UpdateManager
38632 getUpdateManager : function(){
38633 return this.bodyEl.getUpdateManager();
38637 * Set a URL to be used to load the content for this TabPanelItem.
38638 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
38639 * @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)
38640 * @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)
38641 * @return {Roo.UpdateManager} The UpdateManager
38643 setUrl : function(url, params, loadOnce){
38644 if(this.refreshDelegate){
38645 this.un('activate', this.refreshDelegate);
38647 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
38648 this.on("activate", this.refreshDelegate);
38649 return this.bodyEl.getUpdateManager();
38653 _handleRefresh : function(url, params, loadOnce){
38654 if(!loadOnce || !this.loaded){
38655 var updater = this.bodyEl.getUpdateManager();
38656 updater.update(url, params, this._setLoaded.createDelegate(this));
38661 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
38662 * Will fail silently if the setUrl method has not been called.
38663 * This does not activate the panel, just updates its content.
38665 refresh : function(){
38666 if(this.refreshDelegate){
38667 this.loaded = false;
38668 this.refreshDelegate();
38673 _setLoaded : function(){
38674 this.loaded = true;
38678 closeClick : function(e){
38681 this.fireEvent("beforeclose", this, o);
38682 if(o.cancel !== true){
38683 this.tabPanel.removeTab(this.id);
38687 * The text displayed in the tooltip for the close icon.
38690 closeText : "Close this tab"
38693 * This script refer to:
38694 * Title: International Telephone Input
38695 * Author: Jack O'Connor
38696 * Code version: v12.1.12
38697 * Availability: https://github.com/jackocnr/intl-tel-input.git
38700 Roo.bootstrap.PhoneInputData = function() {
38703 "Afghanistan (افغانستان)",
38708 "Albania (Shqipëri)",
38713 "Algeria (الجزائر)",
38738 "Antigua and Barbuda",
38748 "Armenia (Հայաստան)",
38764 "Austria (Österreich)",
38769 "Azerbaijan (Azərbaycan)",
38779 "Bahrain (البحرين)",
38784 "Bangladesh (বাংলাদেশ)",
38794 "Belarus (Беларусь)",
38799 "Belgium (België)",
38829 "Bosnia and Herzegovina (Босна и Херцеговина)",
38844 "British Indian Ocean Territory",
38849 "British Virgin Islands",
38859 "Bulgaria (България)",
38869 "Burundi (Uburundi)",
38874 "Cambodia (កម្ពុជា)",
38879 "Cameroon (Cameroun)",
38888 ["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"]
38891 "Cape Verde (Kabu Verdi)",
38896 "Caribbean Netherlands",
38907 "Central African Republic (République centrafricaine)",
38927 "Christmas Island",
38933 "Cocos (Keeling) Islands",
38944 "Comoros (جزر القمر)",
38949 "Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)",
38954 "Congo (Republic) (Congo-Brazzaville)",
38974 "Croatia (Hrvatska)",
38995 "Czech Republic (Česká republika)",
39000 "Denmark (Danmark)",
39015 "Dominican Republic (República Dominicana)",
39019 ["809", "829", "849"]
39037 "Equatorial Guinea (Guinea Ecuatorial)",
39057 "Falkland Islands (Islas Malvinas)",
39062 "Faroe Islands (Føroyar)",
39083 "French Guiana (Guyane française)",
39088 "French Polynesia (Polynésie française)",
39103 "Georgia (საქართველო)",
39108 "Germany (Deutschland)",
39128 "Greenland (Kalaallit Nunaat)",
39165 "Guinea-Bissau (Guiné Bissau)",
39190 "Hungary (Magyarország)",
39195 "Iceland (Ísland)",
39215 "Iraq (العراق)",
39231 "Israel (ישראל)",
39258 "Jordan (الأردن)",
39263 "Kazakhstan (Казахстан)",
39284 "Kuwait (الكويت)",
39289 "Kyrgyzstan (Кыргызстан)",
39299 "Latvia (Latvija)",
39304 "Lebanon (لبنان)",
39319 "Libya (ليبيا)",
39329 "Lithuania (Lietuva)",
39344 "Macedonia (FYROM) (Македонија)",
39349 "Madagascar (Madagasikara)",
39379 "Marshall Islands",
39389 "Mauritania (موريتانيا)",
39394 "Mauritius (Moris)",
39415 "Moldova (Republica Moldova)",
39425 "Mongolia (Монгол)",
39430 "Montenegro (Crna Gora)",
39440 "Morocco (المغرب)",
39446 "Mozambique (Moçambique)",
39451 "Myanmar (Burma) (မြန်မာ)",
39456 "Namibia (Namibië)",
39471 "Netherlands (Nederland)",
39476 "New Caledonia (Nouvelle-Calédonie)",
39511 "North Korea (조선 민주주의 인민 공화국)",
39516 "Northern Mariana Islands",
39532 "Pakistan (پاکستان)",
39542 "Palestine (فلسطين)",
39552 "Papua New Guinea",
39594 "Réunion (La Réunion)",
39600 "Romania (România)",
39616 "Saint Barthélemy",
39627 "Saint Kitts and Nevis",
39637 "Saint Martin (Saint-Martin (partie française))",
39643 "Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)",
39648 "Saint Vincent and the Grenadines",
39663 "São Tomé and Príncipe (São Tomé e Príncipe)",
39668 "Saudi Arabia (المملكة العربية السعودية)",
39673 "Senegal (Sénégal)",
39703 "Slovakia (Slovensko)",
39708 "Slovenia (Slovenija)",
39718 "Somalia (Soomaaliya)",
39728 "South Korea (대한민국)",
39733 "South Sudan (جنوب السودان)",
39743 "Sri Lanka (ශ්රී ලංකාව)",
39748 "Sudan (السودان)",
39758 "Svalbard and Jan Mayen",
39769 "Sweden (Sverige)",
39774 "Switzerland (Schweiz)",
39779 "Syria (سوريا)",
39824 "Trinidad and Tobago",
39829 "Tunisia (تونس)",
39834 "Turkey (Türkiye)",
39844 "Turks and Caicos Islands",
39854 "U.S. Virgin Islands",
39864 "Ukraine (Україна)",
39869 "United Arab Emirates (الإمارات العربية المتحدة)",
39891 "Uzbekistan (Oʻzbekiston)",
39901 "Vatican City (Città del Vaticano)",
39912 "Vietnam (Việt Nam)",
39917 "Wallis and Futuna (Wallis-et-Futuna)",
39922 "Western Sahara (الصحراء الغربية)",
39928 "Yemen (اليمن)",
39952 * This script refer to:
39953 * Title: International Telephone Input
39954 * Author: Jack O'Connor
39955 * Code version: v12.1.12
39956 * Availability: https://github.com/jackocnr/intl-tel-input.git
39960 * @class Roo.bootstrap.PhoneInput
39961 * @extends Roo.bootstrap.TriggerField
39962 * An input with International dial-code selection
39964 * @cfg {String} defaultDialCode default '+852'
39965 * @cfg {Array} preferedCountries default []
39968 * Create a new PhoneInput.
39969 * @param {Object} config Configuration options
39972 Roo.bootstrap.PhoneInput = function(config) {
39973 Roo.bootstrap.PhoneInput.superclass.constructor.call(this, config);
39976 Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
39978 listWidth: undefined,
39980 selectedClass: 'active',
39982 invalidClass : "has-warning",
39984 validClass: 'has-success',
39986 allowed: '0123456789',
39991 * @cfg {String} defaultDialCode The default dial code when initializing the input
39993 defaultDialCode: '+852',
39996 * @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
39998 preferedCountries: false,
40000 getAutoCreate : function()
40002 var data = Roo.bootstrap.PhoneInputData();
40003 var align = this.labelAlign || this.parentLabelAlign();
40006 this.allCountries = [];
40007 this.dialCodeMapping = [];
40009 for (var i = 0; i < data.length; i++) {
40011 this.allCountries[i] = {
40015 priority: c[3] || 0,
40016 areaCodes: c[4] || null
40018 this.dialCodeMapping[c[2]] = {
40021 priority: c[3] || 0,
40022 areaCodes: c[4] || null
40034 // type: 'number', -- do not use number - we get the flaky up/down arrows.
40035 maxlength: this.max_length,
40036 cls : 'form-control tel-input',
40037 autocomplete: 'new-password'
40040 var hiddenInput = {
40043 cls: 'hidden-tel-input'
40047 hiddenInput.name = this.name;
40050 if (this.disabled) {
40051 input.disabled = true;
40054 var flag_container = {
40071 cls: this.hasFeedback ? 'has-feedback' : '',
40077 cls: 'dial-code-holder',
40084 cls: 'roo-select2-container input-group',
40091 if (this.fieldLabel.length) {
40094 tooltip: 'This field is required'
40100 cls: 'control-label',
40106 html: this.fieldLabel
40109 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40115 if(this.indicatorpos == 'right') {
40116 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40123 if(align == 'left') {
40131 if(this.labelWidth > 12){
40132 label.style = "width: " + this.labelWidth + 'px';
40134 if(this.labelWidth < 13 && this.labelmd == 0){
40135 this.labelmd = this.labelWidth;
40137 if(this.labellg > 0){
40138 label.cls += ' col-lg-' + this.labellg;
40139 input.cls += ' col-lg-' + (12 - this.labellg);
40141 if(this.labelmd > 0){
40142 label.cls += ' col-md-' + this.labelmd;
40143 container.cls += ' col-md-' + (12 - this.labelmd);
40145 if(this.labelsm > 0){
40146 label.cls += ' col-sm-' + this.labelsm;
40147 container.cls += ' col-sm-' + (12 - this.labelsm);
40149 if(this.labelxs > 0){
40150 label.cls += ' col-xs-' + this.labelxs;
40151 container.cls += ' col-xs-' + (12 - this.labelxs);
40161 var settings = this;
40163 ['xs','sm','md','lg'].map(function(size){
40164 if (settings[size]) {
40165 cfg.cls += ' col-' + size + '-' + settings[size];
40169 this.store = new Roo.data.Store({
40170 proxy : new Roo.data.MemoryProxy({}),
40171 reader : new Roo.data.JsonReader({
40182 'name' : 'dialCode',
40186 'name' : 'priority',
40190 'name' : 'areaCodes',
40197 if(!this.preferedCountries) {
40198 this.preferedCountries = [
40205 var p = this.preferedCountries.reverse();
40208 for (var i = 0; i < p.length; i++) {
40209 for (var j = 0; j < this.allCountries.length; j++) {
40210 if(this.allCountries[j].iso2 == p[i]) {
40211 var t = this.allCountries[j];
40212 this.allCountries.splice(j,1);
40213 this.allCountries.unshift(t);
40219 this.store.proxy.data = {
40221 data: this.allCountries
40227 initEvents : function()
40230 Roo.bootstrap.PhoneInput.superclass.initEvents.call(this);
40232 this.indicator = this.indicatorEl();
40233 this.flag = this.flagEl();
40234 this.dialCodeHolder = this.dialCodeHolderEl();
40236 this.trigger = this.el.select('div.flag-box',true).first();
40237 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
40242 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40243 _this.list.setWidth(lw);
40246 this.list.on('mouseover', this.onViewOver, this);
40247 this.list.on('mousemove', this.onViewMove, this);
40248 this.inputEl().on("keyup", this.onKeyUp, this);
40249 this.inputEl().on("keypress", this.onKeyPress, this);
40251 this.tpl = '<li><a href="#"><div class="flag {iso2}"></div>{name} <span class="dial-code">+{dialCode}</span></a></li>';
40253 this.view = new Roo.View(this.list, this.tpl, {
40254 singleSelect:true, store: this.store, selectedClass: this.selectedClass
40257 this.view.on('click', this.onViewClick, this);
40258 this.setValue(this.defaultDialCode);
40261 onTriggerClick : function(e)
40263 Roo.log('trigger click');
40268 if(this.isExpanded()){
40270 this.hasFocus = false;
40272 this.store.load({});
40273 this.hasFocus = true;
40278 isExpanded : function()
40280 return this.list.isVisible();
40283 collapse : function()
40285 if(!this.isExpanded()){
40289 Roo.get(document).un('mousedown', this.collapseIf, this);
40290 Roo.get(document).un('mousewheel', this.collapseIf, this);
40291 this.fireEvent('collapse', this);
40295 expand : function()
40299 if(this.isExpanded() || !this.hasFocus){
40303 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
40304 this.list.setWidth(lw);
40307 this.restrictHeight();
40309 Roo.get(document).on('mousedown', this.collapseIf, this);
40310 Roo.get(document).on('mousewheel', this.collapseIf, this);
40312 this.fireEvent('expand', this);
40315 restrictHeight : function()
40317 this.list.alignTo(this.inputEl(), this.listAlign);
40318 this.list.alignTo(this.inputEl(), this.listAlign);
40321 onViewOver : function(e, t)
40323 if(this.inKeyMode){
40326 var item = this.view.findItemFromChild(t);
40329 var index = this.view.indexOf(item);
40330 this.select(index, false);
40335 onViewClick : function(view, doFocus, el, e)
40337 var index = this.view.getSelectedIndexes()[0];
40339 var r = this.store.getAt(index);
40342 this.onSelect(r, index);
40344 if(doFocus !== false && !this.blockFocus){
40345 this.inputEl().focus();
40349 onViewMove : function(e, t)
40351 this.inKeyMode = false;
40354 select : function(index, scrollIntoView)
40356 this.selectedIndex = index;
40357 this.view.select(index);
40358 if(scrollIntoView !== false){
40359 var el = this.view.getNode(index);
40361 this.list.scrollChildIntoView(el, false);
40366 createList : function()
40368 this.list = Roo.get(document.body).createChild({
40370 cls: 'typeahead typeahead-long dropdown-menu tel-list',
40371 style: 'display:none'
40374 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
40377 collapseIf : function(e)
40379 var in_combo = e.within(this.el);
40380 var in_list = e.within(this.list);
40381 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
40383 if (in_combo || in_list || is_list) {
40389 onSelect : function(record, index)
40391 if(this.fireEvent('beforeselect', this, record, index) !== false){
40393 this.setFlagClass(record.data.iso2);
40394 this.setDialCode(record.data.dialCode);
40395 this.hasFocus = false;
40397 this.fireEvent('select', this, record, index);
40401 flagEl : function()
40403 var flag = this.el.select('div.flag',true).first();
40410 dialCodeHolderEl : function()
40412 var d = this.el.select('input.dial-code-holder',true).first();
40419 setDialCode : function(v)
40421 this.dialCodeHolder.dom.value = '+'+v;
40424 setFlagClass : function(n)
40426 this.flag.dom.className = 'flag '+n;
40429 getValue : function()
40431 var v = this.inputEl().getValue();
40432 if(this.dialCodeHolder) {
40433 v = this.dialCodeHolder.dom.value+this.inputEl().getValue();
40438 setValue : function(v)
40440 var d = this.getDialCode(v);
40442 //invalid dial code
40443 if(v.length == 0 || !d || d.length == 0) {
40445 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
40446 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
40452 this.setFlagClass(this.dialCodeMapping[d].iso2);
40453 this.setDialCode(d);
40454 this.inputEl().dom.value = v.replace('+'+d,'');
40455 this.hiddenEl().dom.value = this.getValue();
40460 getDialCode : function(v)
40464 if (v.length == 0) {
40465 return this.dialCodeHolder.dom.value;
40469 if (v.charAt(0) != "+") {
40472 var numericChars = "";
40473 for (var i = 1; i < v.length; i++) {
40474 var c = v.charAt(i);
40477 if (this.dialCodeMapping[numericChars]) {
40478 dialCode = v.substr(1, i);
40480 if (numericChars.length == 4) {
40490 this.setValue(this.defaultDialCode);
40494 hiddenEl : function()
40496 return this.el.select('input.hidden-tel-input',true).first();
40499 // after setting val
40500 onKeyUp : function(e){
40501 this.setValue(this.getValue());
40504 onKeyPress : function(e){
40505 if(this.allowed.indexOf(String.fromCharCode(e.getCharCode())) === -1){
40512 * @class Roo.bootstrap.MoneyField
40513 * @extends Roo.bootstrap.ComboBox
40514 * Bootstrap MoneyField class
40517 * Create a new MoneyField.
40518 * @param {Object} config Configuration options
40521 Roo.bootstrap.MoneyField = function(config) {
40523 Roo.bootstrap.MoneyField.superclass.constructor.call(this, config);
40527 Roo.extend(Roo.bootstrap.MoneyField, Roo.bootstrap.ComboBox, {
40530 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
40532 allowDecimals : true,
40534 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
40536 decimalSeparator : ".",
40538 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
40540 decimalPrecision : 0,
40542 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
40544 allowNegative : true,
40546 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
40550 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
40552 minValue : Number.NEGATIVE_INFINITY,
40554 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
40556 maxValue : Number.MAX_VALUE,
40558 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
40560 minText : "The minimum value for this field is {0}",
40562 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
40564 maxText : "The maximum value for this field is {0}",
40566 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
40567 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
40569 nanText : "{0} is not a valid number",
40571 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
40575 * @cfg {String} defaults currency of the MoneyField
40576 * value should be in lkey
40578 defaultCurrency : false,
40580 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
40582 thousandsDelimiter : false,
40584 * @cfg {Number} max_length Maximum input field length allowed (defaults to Number.MAX_VALUE)
40595 getAutoCreate : function()
40597 var align = this.labelAlign || this.parentLabelAlign();
40609 cls : 'form-control roo-money-amount-input',
40610 autocomplete: 'new-password'
40613 var hiddenInput = {
40617 cls: 'hidden-number-input'
40620 if(this.max_length) {
40621 input.maxlength = this.max_length;
40625 hiddenInput.name = this.name;
40628 if (this.disabled) {
40629 input.disabled = true;
40632 var clg = 12 - this.inputlg;
40633 var cmd = 12 - this.inputmd;
40634 var csm = 12 - this.inputsm;
40635 var cxs = 12 - this.inputxs;
40639 cls : 'row roo-money-field',
40643 cls : 'roo-money-currency column col-lg-' + clg + ' col-md-' + cmd + ' col-sm-' + csm + ' col-xs-' + cxs,
40647 cls: 'roo-select2-container input-group',
40651 cls : 'form-control roo-money-currency-input',
40652 autocomplete: 'new-password',
40654 name : this.currencyName
40658 cls : 'input-group-addon',
40672 cls : 'roo-money-amount column col-lg-' + this.inputlg + ' col-md-' + this.inputmd + ' col-sm-' + this.inputsm + ' col-xs-' + this.inputxs,
40676 cls: this.hasFeedback ? 'has-feedback' : '',
40687 if (this.fieldLabel.length) {
40690 tooltip: 'This field is required'
40696 cls: 'control-label',
40702 html: this.fieldLabel
40705 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40711 if(this.indicatorpos == 'right') {
40712 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40719 if(align == 'left') {
40727 if(this.labelWidth > 12){
40728 label.style = "width: " + this.labelWidth + 'px';
40730 if(this.labelWidth < 13 && this.labelmd == 0){
40731 this.labelmd = this.labelWidth;
40733 if(this.labellg > 0){
40734 label.cls += ' col-lg-' + this.labellg;
40735 input.cls += ' col-lg-' + (12 - this.labellg);
40737 if(this.labelmd > 0){
40738 label.cls += ' col-md-' + this.labelmd;
40739 container.cls += ' col-md-' + (12 - this.labelmd);
40741 if(this.labelsm > 0){
40742 label.cls += ' col-sm-' + this.labelsm;
40743 container.cls += ' col-sm-' + (12 - this.labelsm);
40745 if(this.labelxs > 0){
40746 label.cls += ' col-xs-' + this.labelxs;
40747 container.cls += ' col-xs-' + (12 - this.labelxs);
40758 var settings = this;
40760 ['xs','sm','md','lg'].map(function(size){
40761 if (settings[size]) {
40762 cfg.cls += ' col-' + size + '-' + settings[size];
40769 initEvents : function()
40771 this.indicator = this.indicatorEl();
40773 this.initCurrencyEvent();
40775 this.initNumberEvent();
40778 initCurrencyEvent : function()
40781 throw "can not find store for combo";
40784 this.store = Roo.factory(this.store, Roo.data);
40785 this.store.parent = this;
40789 this.triggerEl = this.el.select('.input-group-addon', true).first();
40791 this.triggerEl.on("click", this.onTriggerClick, this, { preventDefault : true });
40796 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40797 _this.list.setWidth(lw);
40800 this.list.on('mouseover', this.onViewOver, this);
40801 this.list.on('mousemove', this.onViewMove, this);
40802 this.list.on('scroll', this.onViewScroll, this);
40805 this.tpl = '<li><a href="#">{' + this.currencyField + '}</a></li>';
40808 this.view = new Roo.View(this.list, this.tpl, {
40809 singleSelect:true, store: this.store, selectedClass: this.selectedClass
40812 this.view.on('click', this.onViewClick, this);
40814 this.store.on('beforeload', this.onBeforeLoad, this);
40815 this.store.on('load', this.onLoad, this);
40816 this.store.on('loadexception', this.onLoadException, this);
40818 this.keyNav = new Roo.KeyNav(this.currencyEl(), {
40819 "up" : function(e){
40820 this.inKeyMode = true;
40824 "down" : function(e){
40825 if(!this.isExpanded()){
40826 this.onTriggerClick();
40828 this.inKeyMode = true;
40833 "enter" : function(e){
40836 if(this.fireEvent("specialkey", this, e)){
40837 this.onViewClick(false);
40843 "esc" : function(e){
40847 "tab" : function(e){
40850 if(this.fireEvent("specialkey", this, e)){
40851 this.onViewClick(false);
40859 doRelay : function(foo, bar, hname){
40860 if(hname == 'down' || this.scope.isExpanded()){
40861 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
40869 this.currencyEl().on("click", this.onTriggerClick, this, { preventDefault : true });
40873 initNumberEvent : function(e)
40875 this.inputEl().on("keydown" , this.fireKey, this);
40876 this.inputEl().on("focus", this.onFocus, this);
40877 this.inputEl().on("blur", this.onBlur, this);
40879 this.inputEl().relayEvent('keyup', this);
40881 if(this.indicator){
40882 this.indicator.addClass('invisible');
40885 this.originalValue = this.getValue();
40887 if(this.validationEvent == 'keyup'){
40888 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
40889 this.inputEl().on('keyup', this.filterValidation, this);
40891 else if(this.validationEvent !== false){
40892 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
40895 if(this.selectOnFocus){
40896 this.on("focus", this.preFocus, this);
40899 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
40900 this.inputEl().on("keypress", this.filterKeys, this);
40902 this.inputEl().relayEvent('keypress', this);
40905 var allowed = "0123456789";
40907 if(this.allowDecimals){
40908 allowed += this.decimalSeparator;
40911 if(this.allowNegative){
40915 if(this.thousandsDelimiter) {
40919 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
40921 var keyPress = function(e){
40923 var k = e.getKey();
40925 var c = e.getCharCode();
40928 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
40929 allowed.indexOf(String.fromCharCode(c)) === -1
40935 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
40939 if(allowed.indexOf(String.fromCharCode(c)) === -1){
40944 this.inputEl().on("keypress", keyPress, this);
40948 onTriggerClick : function(e)
40955 this.loadNext = false;
40957 if(this.isExpanded()){
40962 this.hasFocus = true;
40964 if(this.triggerAction == 'all') {
40965 this.doQuery(this.allQuery, true);
40969 this.doQuery(this.getRawValue());
40972 getCurrency : function()
40974 var v = this.currencyEl().getValue();
40979 restrictHeight : function()
40981 this.list.alignTo(this.currencyEl(), this.listAlign);
40982 this.list.alignTo(this.currencyEl(), this.listAlign);
40985 onViewClick : function(view, doFocus, el, e)
40987 var index = this.view.getSelectedIndexes()[0];
40989 var r = this.store.getAt(index);
40992 this.onSelect(r, index);
40996 onSelect : function(record, index){
40998 if(this.fireEvent('beforeselect', this, record, index) !== false){
41000 this.setFromCurrencyData(index > -1 ? record.data : false);
41004 this.fireEvent('select', this, record, index);
41008 setFromCurrencyData : function(o)
41012 this.lastCurrency = o;
41014 if (this.currencyField) {
41015 currency = !o || typeof(o[this.currencyField]) == 'undefined' ? '' : o[this.currencyField];
41017 Roo.log('no currencyField value set for '+ (this.name ? this.name : this.id));
41020 this.lastSelectionText = currency;
41022 //setting default currency
41023 if(o[this.currencyField] * 1 == 0 && this.defaultCurrency) {
41024 this.setCurrency(this.defaultCurrency);
41028 this.setCurrency(currency);
41031 setFromData : function(o)
41035 c[this.currencyField] = !o || typeof(o[this.currencyName]) == 'undefined' ? '' : o[this.currencyName];
41037 this.setFromCurrencyData(c);
41042 value = !o || typeof(o[this.name]) == 'undefined' ? '' : o[this.name];
41044 Roo.log('no value set for '+ (this.name ? this.name : this.id));
41047 this.setValue(value);
41051 setCurrency : function(v)
41053 this.currencyValue = v;
41056 this.currencyEl().dom.value = (v === null || v === undefined ? '' : v);
41061 setValue : function(v)
41063 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
41069 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
41071 this.inputEl().dom.value = (v == '') ? '' :
41072 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
41074 if(!this.allowZero && v === '0') {
41075 this.hiddenEl().dom.value = '';
41076 this.inputEl().dom.value = '';
41083 getRawValue : function()
41085 var v = this.inputEl().getValue();
41090 getValue : function()
41092 return this.fixPrecision(this.parseValue(this.getRawValue()));
41095 parseValue : function(value)
41097 if(this.thousandsDelimiter) {
41099 r = new RegExp(",", "g");
41100 value = value.replace(r, "");
41103 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
41104 return isNaN(value) ? '' : value;
41108 fixPrecision : function(value)
41110 if(this.thousandsDelimiter) {
41112 r = new RegExp(",", "g");
41113 value = value.replace(r, "");
41116 var nan = isNaN(value);
41118 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
41119 return nan ? '' : value;
41121 return parseFloat(value).toFixed(this.decimalPrecision);
41124 decimalPrecisionFcn : function(v)
41126 return Math.floor(v);
41129 validateValue : function(value)
41131 if(!Roo.bootstrap.MoneyField.superclass.validateValue.call(this, value)){
41135 var num = this.parseValue(value);
41138 this.markInvalid(String.format(this.nanText, value));
41142 if(num < this.minValue){
41143 this.markInvalid(String.format(this.minText, this.minValue));
41147 if(num > this.maxValue){
41148 this.markInvalid(String.format(this.maxText, this.maxValue));
41155 validate : function()
41157 if(this.disabled || this.allowBlank){
41162 var currency = this.getCurrency();
41164 if(this.validateValue(this.getRawValue()) && currency.length){
41169 this.markInvalid();
41173 getName: function()
41178 beforeBlur : function()
41184 var v = this.parseValue(this.getRawValue());
41191 onBlur : function()
41195 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
41196 //this.el.removeClass(this.focusClass);
41199 this.hasFocus = false;
41201 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
41205 var v = this.getValue();
41207 if(String(v) !== String(this.startValue)){
41208 this.fireEvent('change', this, v, this.startValue);
41211 this.fireEvent("blur", this);
41214 inputEl : function()
41216 return this.el.select('.roo-money-amount-input', true).first();
41219 currencyEl : function()
41221 return this.el.select('.roo-money-currency-input', true).first();
41224 hiddenEl : function()
41226 return this.el.select('input.hidden-number-input',true).first();