2 * set the version of bootstrap based on the stylesheet...
6 Roo.bootstrap.version = (
9 Roo.each(document.styleSheets, 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 * This is really a wrapper for addxtypeChild
176 * it handles stuff relating to flexy:foreach / flexy:if
177 * = some of our projects use a flat rendering of the output, and try and overlay it with dynamic data.
178 * -- this is a bit of a nightmare... and is even more confusing to debug..
183 addxtype : function(tree,cntr)
187 cn = Roo.factory(tree);
188 //Roo.log(['addxtype', cn]);
190 cn.parentType = this.xtype; //??
191 cn.parentId = this.id;
193 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
194 if (typeof(cn.container_method) == 'string') {
195 cntr = cn.container_method;
199 var has_flexy_each = (typeof(tree['flexy:foreach']) != 'undefined');
201 var has_flexy_if = (typeof(tree['flexy:if']) != 'undefined');
203 var build_from_html = Roo.XComponent.build_from_html;
205 var is_body = (tree.xtype == 'Body') ;
207 var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
209 var self_cntr_el = Roo.get(this[cntr](false));
211 // do not try and build conditional elements
212 if ((has_flexy_each || has_flexy_if || this.can_build_overlaid == false ) && build_from_html) {
216 if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
217 if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
218 return this.addxtypeChild(tree,cntr, is_body);
221 var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
224 return this.addxtypeChild(Roo.apply({}, tree),cntr);
227 Roo.log('skipping render');
233 if (!build_from_html) {
237 // this i think handles overlaying multiple children of the same type
238 // with the sam eelement.. - which might be buggy..
240 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
246 if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
250 ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
256 * add a child to this element
257 * - turn the child.cfg into a child_instance
258 * - call child_instance.render( this { getContainerMethod()} )
259 * - loop through the children, and call addxtype.. (reall this) on newly created child.
263 addxtypeChild : function (tree, cntr, is_body)
265 Roo.debug && Roo.log('addxtypeChild:' + cntr);
267 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
270 var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
271 (typeof(tree['flexy:foreach']) != 'undefined');
275 skip_children = false;
276 // render the element if it's not BODY.
279 // if parent was disabled, then do not try and create the children..
280 if(!this[cntr](true)){
285 cn = Roo.factory(tree);
287 cn.parentType = this.xtype; //??
288 cn.parentId = this.id;
290 var build_from_html = Roo.XComponent.build_from_html;
293 // does the container contain child eleemnts with 'xtype' attributes.
294 // that match this xtype..
295 // note - when we render we create these as well..
296 // so we should check to see if body has xtype set.
297 if (build_from_html && Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
299 var self_cntr_el = Roo.get(this[cntr](false));
300 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
302 //Roo.log(Roo.XComponent.build_from_html);
303 //Roo.log("got echild:");
306 // there is a scenario where some of the child elements are flexy:if (and all of the same type)
307 // and are not displayed -this causes this to use up the wrong element when matching.
308 // at present the only work around for this is to nest flexy:if elements in another element that is always rendered.
311 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
312 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
318 //echild.dom.removeAttribute('xtype');
320 Roo.debug && Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
321 Roo.debug && Roo.log(self_cntr_el);
322 Roo.debug && Roo.log(echild);
323 Roo.debug && Roo.log(cn);
329 // if object has flexy:if - then it may or may not be rendered.
330 if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) {
331 // skip a flexy if element.
332 Roo.debug && Roo.log('skipping render');
333 Roo.debug && Roo.log(tree);
335 Roo.debug && Roo.log('skipping all children');
336 skip_children = true;
341 // actually if flexy:foreach is found, we really want to create
342 // multiple copies here...
344 //Roo.log(this[cntr]());
345 // some elements do not have render methods.. like the layouts...
347 if(this[cntr](true) === false){
352 cn.render && cn.render(this[cntr](true));
355 // then add the element..
362 if (typeof (tree.menu) != 'undefined') {
363 tree.menu.parentType = cn.xtype;
364 tree.menu.triggerEl = cn.el;
365 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
369 if (!tree.items || !tree.items.length) {
371 //Roo.log(["no children", this]);
376 var items = tree.items;
379 //Roo.log(items.length);
381 if (!skip_children) {
382 for(var i =0;i < items.length;i++) {
383 // Roo.log(['add child', items[i]]);
384 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
390 //Roo.log("fire childrenrendered");
392 cn.fireEvent('childrenrendered', this);
398 addxtypeChildren: function(child_array)
401 if (!child_array || !child_array.length) {
405 for(var i =0;i < child_array.length;i++) {
406 // Roo.log(['add child', items[i]]);
407 nitems.push(this.addxtype(Roo.apply({}, child_array[i])));
416 * Set the element that will be used to show or hide
418 setVisibilityEl : function(el)
420 this.visibilityEl = el;
424 * Get the element that will be used to show or hide
426 getVisibilityEl : function()
428 if (typeof(this.visibilityEl) == 'object') {
429 return this.visibilityEl;
432 if (typeof(this.visibilityEl) == 'string') {
433 return this.visibilityEl == 'parent' ? this.parent().getEl() : this.getEl();
440 * Show a component - removes 'hidden' class
444 if(!this.getVisibilityEl()){
448 this.getVisibilityEl().removeClass(['hidden','d-none']);
450 this.fireEvent('show', this);
455 * Hide a component - adds 'hidden' class
459 if(!this.getVisibilityEl()){
463 this.getVisibilityEl().addClass(['hidden','d-none']);
465 this.fireEvent('hide', this);
478 * @class Roo.bootstrap.Body
479 * @extends Roo.bootstrap.Component
480 * Bootstrap Body class
484 * @param {Object} config The config object
487 Roo.bootstrap.Body = function(config){
489 config = config || {};
491 Roo.bootstrap.Body.superclass.constructor.call(this, config);
492 this.el = Roo.get(config.el ? config.el : document.body );
493 if (this.cls && this.cls.length) {
494 Roo.get(document.body).addClass(this.cls);
498 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
500 is_body : true,// just to make sure it's constructed?
505 onRender : function(ct, position)
507 /* Roo.log("Roo.bootstrap.Body - onRender");
508 if (this.cls && this.cls.length) {
509 Roo.get(document.body).addClass(this.cls);
528 * @class Roo.bootstrap.ButtonGroup
529 * @extends Roo.bootstrap.Component
530 * Bootstrap ButtonGroup class
531 * @cfg {String} size lg | sm | xs (default empty normal)
532 * @cfg {String} align vertical | justified (default none)
533 * @cfg {String} direction up | down (default down)
534 * @cfg {Boolean} toolbar false | true
535 * @cfg {Boolean} btn true | false
540 * @param {Object} config The config object
543 Roo.bootstrap.ButtonGroup = function(config){
544 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
547 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
555 getAutoCreate : function(){
561 cfg.html = this.html || cfg.html;
572 if (['vertical','justified'].indexOf(this.align)!==-1) {
573 cfg.cls = 'btn-group-' + this.align;
575 if (this.align == 'justified') {
576 console.log(this.items);
580 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
581 cfg.cls += ' btn-group-' + this.size;
584 if (this.direction == 'up') {
585 cfg.cls += ' dropup' ;
591 * Add a button to the group (similar to NavItem API.)
593 addItem : function(cfg)
595 var cn = new Roo.bootstrap.Button(cfg);
597 cn.parentId = this.id;
598 cn.onRender(this.el, null);
612 * @class Roo.bootstrap.Button
613 * @extends Roo.bootstrap.Component
614 * Bootstrap Button class
615 * @cfg {String} html The button content
616 * @cfg {String} weight (default | primary | secondary | success | info | warning | danger | link ) default
617 * @cfg {String} badge_weight (default | primary | secondary | success | info | warning | danger | link ) default (same as button)
618 * @cfg {Boolean} outline default false (except for weight=default which emulates old behaveiour with an outline)
619 * @cfg {String} size ( lg | sm | xs)
620 * @cfg {String} tag ( a | input | submit)
621 * @cfg {String} href empty or href
622 * @cfg {Boolean} disabled default false;
623 * @cfg {Boolean} isClose default false;
624 * @cfg {String} glyphicon depricated - use fa
625 * @cfg {String} fa fontawesome icon - eg. 'comment' - without the fa/fas etc..
626 * @cfg {String} badge text for badge
627 * @cfg {String} theme (default|glow)
628 * @cfg {Boolean} inverse dark themed version
629 * @cfg {Boolean} toggle is it a slidy toggle button
630 * @cfg {Boolean} pressed (true|false) default null - if the button ahs active state
631 * @cfg {String} ontext text for on slidy toggle state
632 * @cfg {String} offtext text for off slidy toggle state
633 * @cfg {Boolean} preventDefault default true (stop click event triggering the URL if it's a link.)
634 * @cfg {Boolean} removeClass remove the standard class..
635 * @cfg {String} target target for a href. (_self|_blank|_parent|_top| other)
638 * Create a new button
639 * @param {Object} config The config object
643 Roo.bootstrap.Button = function(config){
644 Roo.bootstrap.Button.superclass.constructor.call(this, config);
645 this.weightClass = ["btn-default btn-outline-secondary",
657 * When a butotn is pressed
658 * @param {Roo.bootstrap.Button} btn
659 * @param {Roo.EventObject} e
664 * After the button has been toggles
665 * @param {Roo.bootstrap.Button} btn
666 * @param {Roo.EventObject} e
667 * @param {boolean} pressed (also available as button.pressed)
673 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
694 preventDefault: true,
702 getAutoCreate : function(){
710 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
711 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
716 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
718 if (this.toggle == true) {
721 cls: 'slider-frame roo-button',
726 'data-off-text':'OFF',
727 cls: 'slider-button',
733 if (['default', 'secondary' , 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
734 cfg.cls += ' '+this.weight;
743 cfg["aria-hidden"] = true;
745 cfg.html = "×";
751 if (this.theme==='default') {
752 cfg.cls = 'btn roo-button';
754 //if (this.parentType != 'Navbar') {
755 this.weight = this.weight.length ? this.weight : 'default';
757 if (['default', 'primary', 'secondary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
759 var outline = this.outline || this.weight == 'default' ? 'outline-' : '';
760 var weight = this.weight == 'default' ? 'secondary' : this.weight;
761 cfg.cls += ' btn-' + outline + weight;
762 if (this.weight == 'default') {
764 cfg.cls += ' btn-' + this.weight;
767 } else if (this.theme==='glow') {
770 cfg.cls = 'btn-glow roo-button';
772 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
774 cfg.cls += ' ' + this.weight;
780 this.cls += ' inverse';
784 if (this.active || this.pressed === true) {
785 cfg.cls += ' active';
789 cfg.disabled = 'disabled';
793 Roo.log('changing to ul' );
795 this.glyphicon = 'caret';
796 if (Roo.bootstrap.version == 4) {
797 this.fa = 'caret-down';
802 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
804 //gsRoo.log(this.parentType);
805 if (this.parentType === 'Navbar' && !this.parent().bar) {
806 Roo.log('changing to li?');
815 href : this.href || '#'
818 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
819 cfg.cls += ' dropdown';
826 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
828 if (this.glyphicon) {
829 cfg.html = ' ' + cfg.html;
834 cls: 'glyphicon glyphicon-' + this.glyphicon
839 cfg.html = ' ' + cfg.html;
844 cls: 'fa fas fa-' + this.fa
854 // cfg.cls='btn roo-button';
858 var value = cfg.html;
863 cls: 'glyphicon glyphicon-' + this.glyphicon,
870 cls: 'fa fas fa-' + this.fa,
875 var bw = this.badge_weight.length ? this.badge_weight :
876 (this.weight.length ? this.weight : 'secondary');
877 bw = bw == 'default' ? 'secondary' : bw;
883 cls: 'badge badge-' + bw,
892 cfg.cls += ' dropdown';
893 cfg.html = typeof(cfg.html) != 'undefined' ?
894 cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
897 if (cfg.tag !== 'a' && this.href !== '') {
898 throw "Tag must be a to set href.";
899 } else if (this.href.length > 0) {
900 cfg.href = this.href;
903 if(this.removeClass){
908 cfg.target = this.target;
913 initEvents: function() {
914 // Roo.log('init events?');
915 // Roo.log(this.el.dom);
918 if (typeof (this.menu) != 'undefined') {
919 this.menu.parentType = this.xtype;
920 this.menu.triggerEl = this.el;
921 this.addxtype(Roo.apply({}, this.menu));
925 if (this.el.hasClass('roo-button')) {
926 this.el.on('click', this.onClick, this);
928 this.el.select('.roo-button').on('click', this.onClick, this);
931 if(this.removeClass){
932 this.el.on('click', this.onClick, this);
935 this.el.enableDisplayMode();
938 onClick : function(e)
944 Roo.log('button on click ');
945 if(this.preventDefault){
949 if (this.pressed === true || this.pressed === false) {
950 this.toggleActive(e);
954 this.fireEvent('click', this, e);
958 * Enables this button
962 this.disabled = false;
963 this.el.removeClass('disabled');
967 * Disable this button
971 this.disabled = true;
972 this.el.addClass('disabled');
975 * sets the active state on/off,
976 * @param {Boolean} state (optional) Force a particular state
978 setActive : function(v) {
980 this.el[v ? 'addClass' : 'removeClass']('active');
984 * toggles the current active state
986 toggleActive : function(e)
988 this.setActive(!this.pressed);
989 this.fireEvent('toggle', this, e, !this.pressed);
992 * get the current active state
993 * @return {boolean} true if it's active
995 isActive : function()
997 return this.el.hasClass('active');
1000 * set the text of the first selected button
1002 setText : function(str)
1004 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
1007 * get the text of the first selected button
1009 getText : function()
1011 return this.el.select('.roo-button-text',true).first().dom.innerHTML;
1014 setWeight : function(str)
1016 this.el.removeClass(this.weightClass);
1018 var outline = this.outline ? 'outline-' : '';
1019 if (str == 'default') {
1020 this.el.addClass('btn-default btn-outline-secondary');
1023 this.el.addClass('btn-' + outline + str);
1037 * @class Roo.bootstrap.Column
1038 * @extends Roo.bootstrap.Component
1039 * Bootstrap Column class
1040 * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
1041 * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
1042 * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
1043 * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
1044 * @cfg {Number} xsoff colspan offset out of 12 for mobile-sized screens or 0 for hidden
1045 * @cfg {Number} smoff colspan offset out of 12 for tablet-sized screens or 0 for hidden
1046 * @cfg {Number} mdoff colspan offset out of 12 for computer-sized screens or 0 for hidden
1047 * @cfg {Number} lgoff colspan offset out of 12 for large computer-sized screens or 0 for hidden
1050 * @cfg {Boolean} hidden (true|false) hide the element
1051 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
1052 * @cfg {String} fa (ban|check|...) font awesome icon
1053 * @cfg {Number} fasize (1|2|....) font awsome size
1055 * @cfg {String} icon (info-sign|check|...) glyphicon name
1057 * @cfg {String} html content of column.
1060 * Create a new Column
1061 * @param {Object} config The config object
1064 Roo.bootstrap.Column = function(config){
1065 Roo.bootstrap.Column.superclass.constructor.call(this, config);
1068 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
1086 getAutoCreate : function(){
1087 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
1095 ['xs','sm','md','lg'].map(function(size){
1096 //Roo.log( size + ':' + settings[size]);
1098 if (settings[size+'off'] !== false) {
1099 cfg.cls += ' col-' + size + '-offset-' + settings[size+'off'] ;
1102 if (settings[size] === false) {
1106 if (!settings[size]) { // 0 = hidden
1107 cfg.cls += ' hidden-' + size + ' hidden' + size + '-down';;
1110 cfg.cls += ' col-' + size + '-' + settings[size] + (
1111 size == 'xs' ? (' col-' + settings[size] ) : '' // bs4 col-{num} replaces col-xs
1117 cfg.cls += ' hidden';
1120 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1121 cfg.cls +=' alert alert-' + this.alert;
1125 if (this.html.length) {
1126 cfg.html = this.html;
1130 if (this.fasize > 1) {
1131 fasize = ' fa-' + this.fasize + 'x';
1133 cfg.html = '<i class="fa fa-'+this.fa + fasize + '"></i>' + (cfg.html || '');
1138 cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + (cfg.html || '');
1157 * @class Roo.bootstrap.Container
1158 * @extends Roo.bootstrap.Component
1159 * Bootstrap Container class
1160 * @cfg {Boolean} jumbotron is it a jumbotron element
1161 * @cfg {String} html content of element
1162 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
1163 * @cfg {String} panel (default|primary|success|info|warning|danger) render as panel - type - primary/success.....
1164 * @cfg {String} header content of header (for panel)
1165 * @cfg {String} footer content of footer (for panel)
1166 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
1167 * @cfg {String} tag (header|aside|section) type of HTML tag.
1168 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
1169 * @cfg {String} fa font awesome icon
1170 * @cfg {String} icon (info-sign|check|...) glyphicon name
1171 * @cfg {Boolean} hidden (true|false) hide the element
1172 * @cfg {Boolean} expandable (true|false) default false
1173 * @cfg {Boolean} expanded (true|false) default true
1174 * @cfg {String} rheader contet on the right of header
1175 * @cfg {Boolean} clickable (true|false) default false
1179 * Create a new Container
1180 * @param {Object} config The config object
1183 Roo.bootstrap.Container = function(config){
1184 Roo.bootstrap.Container.superclass.constructor.call(this, config);
1190 * After the panel has been expand
1192 * @param {Roo.bootstrap.Container} this
1197 * After the panel has been collapsed
1199 * @param {Roo.bootstrap.Container} this
1204 * When a element is chick
1205 * @param {Roo.bootstrap.Container} this
1206 * @param {Roo.EventObject} e
1212 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
1230 getChildContainer : function() {
1236 if (this.panel.length) {
1237 return this.el.select('.panel-body',true).first();
1244 getAutoCreate : function(){
1247 tag : this.tag || 'div',
1251 if (this.jumbotron) {
1252 cfg.cls = 'jumbotron';
1257 // - this is applied by the parent..
1259 // cfg.cls = this.cls + '';
1262 if (this.sticky.length) {
1264 var bd = Roo.get(document.body);
1265 if (!bd.hasClass('bootstrap-sticky')) {
1266 bd.addClass('bootstrap-sticky');
1267 Roo.select('html',true).setStyle('height', '100%');
1270 cfg.cls += 'bootstrap-sticky-' + this.sticky;
1274 if (this.well.length) {
1275 switch (this.well) {
1278 cfg.cls +=' well well-' +this.well;
1287 cfg.cls += ' hidden';
1291 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1292 cfg.cls +=' alert alert-' + this.alert;
1297 if (this.panel.length) {
1298 cfg.cls += ' panel panel-' + this.panel;
1300 if (this.header.length) {
1304 if(this.expandable){
1306 cfg.cls = cfg.cls + ' expandable';
1310 cls: (this.expanded ? 'fa fa-minus' : 'fa fa-plus')
1318 cls : 'panel-title',
1319 html : (this.expandable ? ' ' : '') + this.header
1323 cls: 'panel-header-right',
1329 cls : 'panel-heading',
1330 style : this.expandable ? 'cursor: pointer' : '',
1338 cls : 'panel-body' + (this.expanded ? '' : ' hide'),
1343 if (this.footer.length) {
1345 cls : 'panel-footer',
1354 body.html = this.html || cfg.html;
1355 // prefix with the icons..
1357 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1360 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1365 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1366 cfg.cls = 'container';
1372 initEvents: function()
1374 if(this.expandable){
1375 var headerEl = this.headerEl();
1378 headerEl.on('click', this.onToggleClick, this);
1383 this.el.on('click', this.onClick, this);
1388 onToggleClick : function()
1390 var headerEl = this.headerEl();
1406 if(this.fireEvent('expand', this)) {
1408 this.expanded = true;
1410 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).show();
1412 this.el.select('.panel-body',true).first().removeClass('hide');
1414 var toggleEl = this.toggleEl();
1420 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-minus']);
1425 collapse : function()
1427 if(this.fireEvent('collapse', this)) {
1429 this.expanded = false;
1431 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).hide();
1432 this.el.select('.panel-body',true).first().addClass('hide');
1434 var toggleEl = this.toggleEl();
1440 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-plus']);
1444 toggleEl : function()
1446 if(!this.el || !this.panel.length || !this.header.length || !this.expandable){
1450 return this.el.select('.panel-heading .fa',true).first();
1453 headerEl : function()
1455 if(!this.el || !this.panel.length || !this.header.length){
1459 return this.el.select('.panel-heading',true).first()
1464 if(!this.el || !this.panel.length){
1468 return this.el.select('.panel-body',true).first()
1471 titleEl : function()
1473 if(!this.el || !this.panel.length || !this.header.length){
1477 return this.el.select('.panel-title',true).first();
1480 setTitle : function(v)
1482 var titleEl = this.titleEl();
1488 titleEl.dom.innerHTML = v;
1491 getTitle : function()
1494 var titleEl = this.titleEl();
1500 return titleEl.dom.innerHTML;
1503 setRightTitle : function(v)
1505 var t = this.el.select('.panel-header-right',true).first();
1511 t.dom.innerHTML = v;
1514 onClick : function(e)
1518 this.fireEvent('click', this, e);
1531 * @class Roo.bootstrap.Img
1532 * @extends Roo.bootstrap.Component
1533 * Bootstrap Img class
1534 * @cfg {Boolean} imgResponsive false | true
1535 * @cfg {String} border rounded | circle | thumbnail
1536 * @cfg {String} src image source
1537 * @cfg {String} alt image alternative text
1538 * @cfg {String} href a tag href
1539 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1540 * @cfg {String} xsUrl xs image source
1541 * @cfg {String} smUrl sm image source
1542 * @cfg {String} mdUrl md image source
1543 * @cfg {String} lgUrl lg image source
1546 * Create a new Input
1547 * @param {Object} config The config object
1550 Roo.bootstrap.Img = function(config){
1551 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1557 * The img click event for the img.
1558 * @param {Roo.EventObject} e
1564 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1566 imgResponsive: true,
1576 getAutoCreate : function()
1578 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1579 return this.createSingleImg();
1584 cls: 'roo-image-responsive-group',
1589 Roo.each(['xs', 'sm', 'md', 'lg'], function(size){
1591 if(!_this[size + 'Url']){
1597 cls: (_this.imgResponsive) ? 'img-responsive' : '',
1598 html: _this.html || cfg.html,
1599 src: _this[size + 'Url']
1602 img.cls += ' roo-image-responsive-' + size;
1604 var s = ['xs', 'sm', 'md', 'lg'];
1606 s.splice(s.indexOf(size), 1);
1608 Roo.each(s, function(ss){
1609 img.cls += ' hidden-' + ss;
1612 if (['rounded','circle','thumbnail'].indexOf(_this.border)>-1) {
1613 cfg.cls += ' img-' + _this.border;
1617 cfg.alt = _this.alt;
1630 a.target = _this.target;
1634 cfg.cn.push((_this.href) ? a : img);
1641 createSingleImg : function()
1645 cls: (this.imgResponsive) ? 'img-responsive' : '',
1647 src : 'about:blank' // just incase src get's set to undefined?!?
1650 cfg.html = this.html || cfg.html;
1652 cfg.src = this.src || cfg.src;
1654 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1655 cfg.cls += ' img-' + this.border;
1672 a.target = this.target;
1677 return (this.href) ? a : cfg;
1680 initEvents: function()
1683 this.el.on('click', this.onClick, this);
1688 onClick : function(e)
1690 Roo.log('img onclick');
1691 this.fireEvent('click', this, e);
1694 * Sets the url of the image - used to update it
1695 * @param {String} url the url of the image
1698 setSrc : function(url)
1702 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1703 this.el.dom.src = url;
1707 this.el.select('img', true).first().dom.src = url;
1723 * @class Roo.bootstrap.Link
1724 * @extends Roo.bootstrap.Component
1725 * Bootstrap Link Class
1726 * @cfg {String} alt image alternative text
1727 * @cfg {String} href a tag href
1728 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1729 * @cfg {String} html the content of the link.
1730 * @cfg {String} anchor name for the anchor link
1731 * @cfg {String} fa - favicon
1733 * @cfg {Boolean} preventDefault (true | false) default false
1737 * Create a new Input
1738 * @param {Object} config The config object
1741 Roo.bootstrap.Link = function(config){
1742 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1748 * The img click event for the img.
1749 * @param {Roo.EventObject} e
1755 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1759 preventDefault: false,
1765 getAutoCreate : function()
1767 var html = this.html || '';
1769 if (this.fa !== false) {
1770 html = '<i class="fa fa-' + this.fa + '"></i>';
1775 // anchor's do not require html/href...
1776 if (this.anchor === false) {
1778 cfg.href = this.href || '#';
1780 cfg.name = this.anchor;
1781 if (this.html !== false || this.fa !== false) {
1784 if (this.href !== false) {
1785 cfg.href = this.href;
1789 if(this.alt !== false){
1794 if(this.target !== false) {
1795 cfg.target = this.target;
1801 initEvents: function() {
1803 if(!this.href || this.preventDefault){
1804 this.el.on('click', this.onClick, this);
1808 onClick : function(e)
1810 if(this.preventDefault){
1813 //Roo.log('img onclick');
1814 this.fireEvent('click', this, e);
1827 * @class Roo.bootstrap.Header
1828 * @extends Roo.bootstrap.Component
1829 * Bootstrap Header class
1830 * @cfg {String} html content of header
1831 * @cfg {Number} level (1|2|3|4|5|6) default 1
1834 * Create a new Header
1835 * @param {Object} config The config object
1839 Roo.bootstrap.Header = function(config){
1840 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1843 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1851 getAutoCreate : function(){
1856 tag: 'h' + (1 *this.level),
1857 html: this.html || ''
1869 * Ext JS Library 1.1.1
1870 * Copyright(c) 2006-2007, Ext JS, LLC.
1872 * Originally Released Under LGPL - original licence link has changed is not relivant.
1875 * <script type="text/javascript">
1879 * @class Roo.bootstrap.MenuMgr
1880 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1883 Roo.bootstrap.MenuMgr = function(){
1884 var menus, active, groups = {}, attached = false, lastShow = new Date();
1886 // private - called when first menu is created
1889 active = new Roo.util.MixedCollection();
1890 Roo.get(document).addKeyListener(27, function(){
1891 if(active.length > 0){
1899 if(active && active.length > 0){
1900 var c = active.clone();
1910 if(active.length < 1){
1911 Roo.get(document).un("mouseup", onMouseDown);
1919 var last = active.last();
1920 lastShow = new Date();
1923 Roo.get(document).on("mouseup", onMouseDown);
1928 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1929 m.parentMenu.activeChild = m;
1930 }else if(last && last.isVisible()){
1931 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1936 function onBeforeHide(m){
1938 m.activeChild.hide();
1940 if(m.autoHideTimer){
1941 clearTimeout(m.autoHideTimer);
1942 delete m.autoHideTimer;
1947 function onBeforeShow(m){
1948 var pm = m.parentMenu;
1949 if(!pm && !m.allowOtherMenus){
1951 }else if(pm && pm.activeChild && active != m){
1952 pm.activeChild.hide();
1956 // private this should really trigger on mouseup..
1957 function onMouseDown(e){
1958 Roo.log("on Mouse Up");
1960 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".dropdown-menu") && !e.getTarget('.user-menu')){
1961 Roo.log("MenuManager hideAll");
1970 function onBeforeCheck(mi, state){
1972 var g = groups[mi.group];
1973 for(var i = 0, l = g.length; i < l; i++){
1975 g[i].setChecked(false);
1984 * Hides all menus that are currently visible
1986 hideAll : function(){
1991 register : function(menu){
1995 menus[menu.id] = menu;
1996 menu.on("beforehide", onBeforeHide);
1997 menu.on("hide", onHide);
1998 menu.on("beforeshow", onBeforeShow);
1999 menu.on("show", onShow);
2001 if(g && menu.events["checkchange"]){
2005 groups[g].push(menu);
2006 menu.on("checkchange", onCheck);
2011 * Returns a {@link Roo.menu.Menu} object
2012 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
2013 * be used to generate and return a new Menu instance.
2015 get : function(menu){
2016 if(typeof menu == "string"){ // menu id
2018 }else if(menu.events){ // menu instance
2021 /*else if(typeof menu.length == 'number'){ // array of menu items?
2022 return new Roo.bootstrap.Menu({items:menu});
2023 }else{ // otherwise, must be a config
2024 return new Roo.bootstrap.Menu(menu);
2031 unregister : function(menu){
2032 delete menus[menu.id];
2033 menu.un("beforehide", onBeforeHide);
2034 menu.un("hide", onHide);
2035 menu.un("beforeshow", onBeforeShow);
2036 menu.un("show", onShow);
2038 if(g && menu.events["checkchange"]){
2039 groups[g].remove(menu);
2040 menu.un("checkchange", onCheck);
2045 registerCheckable : function(menuItem){
2046 var g = menuItem.group;
2051 groups[g].push(menuItem);
2052 menuItem.on("beforecheckchange", onBeforeCheck);
2057 unregisterCheckable : function(menuItem){
2058 var g = menuItem.group;
2060 groups[g].remove(menuItem);
2061 menuItem.un("beforecheckchange", onBeforeCheck);
2073 * @class Roo.bootstrap.Menu
2074 * @extends Roo.bootstrap.Component
2075 * Bootstrap Menu class - container for MenuItems
2076 * @cfg {String} type (dropdown|treeview|submenu) type of menu
2077 * @cfg {bool} hidden if the menu should be hidden when rendered.
2078 * @cfg {bool} stopEvent (true|false) Stop event after trigger press (default true)
2079 * @cfg {bool} isLink (true|false) the menu has link disable auto expand and collaspe (default false)
2083 * @param {Object} config The config object
2087 Roo.bootstrap.Menu = function(config){
2088 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
2089 if (this.registerMenu && this.type != 'treeview') {
2090 Roo.bootstrap.MenuMgr.register(this);
2097 * Fires before this menu is displayed (return false to block)
2098 * @param {Roo.menu.Menu} this
2103 * Fires before this menu is hidden (return false to block)
2104 * @param {Roo.menu.Menu} this
2109 * Fires after this menu is displayed
2110 * @param {Roo.menu.Menu} this
2115 * Fires after this menu is hidden
2116 * @param {Roo.menu.Menu} this
2121 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
2122 * @param {Roo.menu.Menu} this
2123 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2124 * @param {Roo.EventObject} e
2129 * Fires when the mouse is hovering over this menu
2130 * @param {Roo.menu.Menu} this
2131 * @param {Roo.EventObject} e
2132 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2137 * Fires when the mouse exits this menu
2138 * @param {Roo.menu.Menu} this
2139 * @param {Roo.EventObject} e
2140 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2145 * Fires when a menu item contained in this menu is clicked
2146 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
2147 * @param {Roo.EventObject} e
2151 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
2154 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
2158 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
2161 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
2163 registerMenu : true,
2165 menuItems :false, // stores the menu items..
2175 getChildContainer : function() {
2179 getAutoCreate : function(){
2181 //if (['right'].indexOf(this.align)!==-1) {
2182 // cfg.cn[1].cls += ' pull-right'
2188 cls : 'dropdown-menu' ,
2189 style : 'z-index:1000'
2193 if (this.type === 'submenu') {
2194 cfg.cls = 'submenu active';
2196 if (this.type === 'treeview') {
2197 cfg.cls = 'treeview-menu';
2202 initEvents : function() {
2204 // Roo.log("ADD event");
2205 // Roo.log(this.triggerEl.dom);
2207 this.triggerEl.on('click', this.onTriggerClick, this);
2209 this.triggerEl.on(Roo.isTouch ? 'touchstart' : 'mouseup', this.onTriggerPress, this);
2212 if (this.triggerEl.hasClass('nav-item')) {
2213 // dropdown toggle on the 'a' in BS4?
2214 this.triggerEl.select('.nav-link',true).first().addClass('dropdown-toggle');
2216 this.triggerEl.addClass('dropdown-toggle');
2219 this.el.on('touchstart' , this.onTouch, this);
2221 this.el.on('click' , this.onClick, this);
2223 this.el.on("mouseover", this.onMouseOver, this);
2224 this.el.on("mouseout", this.onMouseOut, this);
2228 findTargetItem : function(e)
2230 var t = e.getTarget(".dropdown-menu-item", this.el, true);
2234 //Roo.log(t); Roo.log(t.id);
2236 //Roo.log(this.menuitems);
2237 return this.menuitems.get(t.id);
2239 //return this.items.get(t.menuItemId);
2245 onTouch : function(e)
2247 Roo.log("menu.onTouch");
2248 //e.stopEvent(); this make the user popdown broken
2252 onClick : function(e)
2254 Roo.log("menu.onClick");
2256 var t = this.findTargetItem(e);
2257 if(!t || t.isContainer){
2262 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
2263 if(t == this.activeItem && t.shouldDeactivate(e)){
2264 this.activeItem.deactivate();
2265 delete this.activeItem;
2269 this.setActiveItem(t, true);
2277 Roo.log('pass click event');
2281 this.fireEvent("click", this, t, e);
2285 if(!t.href.length || t.href == '#'){
2286 (function() { _this.hide(); }).defer(100);
2291 onMouseOver : function(e){
2292 var t = this.findTargetItem(e);
2295 // if(t.canActivate && !t.disabled){
2296 // this.setActiveItem(t, true);
2300 this.fireEvent("mouseover", this, e, t);
2302 isVisible : function(){
2303 return !this.hidden;
2305 onMouseOut : function(e){
2306 var t = this.findTargetItem(e);
2309 // if(t == this.activeItem && t.shouldDeactivate(e)){
2310 // this.activeItem.deactivate();
2311 // delete this.activeItem;
2314 this.fireEvent("mouseout", this, e, t);
2319 * Displays this menu relative to another element
2320 * @param {String/HTMLElement/Roo.Element} element The element to align to
2321 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
2322 * the element (defaults to this.defaultAlign)
2323 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2325 show : function(el, pos, parentMenu)
2327 if (false === this.fireEvent("beforeshow", this)) {
2328 Roo.log("show canceled");
2331 this.parentMenu = parentMenu;
2336 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
2339 * Displays this menu at a specific xy position
2340 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
2341 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2343 showAt : function(xy, parentMenu, /* private: */_e){
2344 this.parentMenu = parentMenu;
2349 this.fireEvent("beforeshow", this);
2350 //xy = this.el.adjustForConstraints(xy);
2354 this.hideMenuItems();
2355 this.hidden = false;
2356 this.triggerEl.addClass('open');
2357 this.el.addClass('show');
2359 // reassign x when hitting right
2360 if(this.el.getWidth() + xy[0] >= Roo.lib.Dom.getViewWidth()){
2361 xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
2364 // reassign y when hitting bottom
2365 if(this.el.getHeight() + xy[1] >= Roo.lib.Dom.getViewHeight()){
2366 xy[1] = xy[1] - this.el.getHeight() - this.triggerEl.getHeight();
2369 // but the list may align on trigger left or trigger top... should it be a properity?
2371 if(this.el.getStyle('top') != 'auto' && this.el.getStyle('top').slice(-1) != "%"){
2376 this.fireEvent("show", this);
2382 this.doFocus.defer(50, this);
2386 doFocus : function(){
2388 this.focusEl.focus();
2393 * Hides this menu and optionally all parent menus
2394 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
2396 hide : function(deep)
2398 if (false === this.fireEvent("beforehide", this)) {
2399 Roo.log("hide canceled");
2402 this.hideMenuItems();
2403 if(this.el && this.isVisible()){
2405 if(this.activeItem){
2406 this.activeItem.deactivate();
2407 this.activeItem = null;
2409 this.triggerEl.removeClass('open');;
2410 this.el.removeClass('show');
2412 this.fireEvent("hide", this);
2414 if(deep === true && this.parentMenu){
2415 this.parentMenu.hide(true);
2419 onTriggerClick : function(e)
2421 Roo.log('trigger click');
2423 var target = e.getTarget();
2425 Roo.log(target.nodeName.toLowerCase());
2427 if(target.nodeName.toLowerCase() === 'i'){
2433 onTriggerPress : function(e)
2435 Roo.log('trigger press');
2436 //Roo.log(e.getTarget());
2437 // Roo.log(this.triggerEl.dom);
2439 // trigger only occurs on normal menu's -- if it's a treeview or dropdown... do not hide/show..
2440 var pel = Roo.get(e.getTarget());
2441 if (pel.findParent('.dropdown-menu') || pel.findParent('.treeview-menu') ) {
2442 Roo.log('is treeview or dropdown?');
2446 if(e.getTarget().nodeName.toLowerCase() !== 'i' && this.isLink){
2450 if (this.isVisible()) {
2455 this.show(this.triggerEl, '?', false);
2458 if(this.stopEvent || e.getTarget().nodeName.toLowerCase() === 'i'){
2465 hideMenuItems : function()
2467 Roo.log("hide Menu Items");
2472 this.el.select('.open',true).each(function(aa) {
2474 aa.removeClass('open');
2478 addxtypeChild : function (tree, cntr) {
2479 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
2481 this.menuitems.add(comp);
2493 this.getEl().dom.innerHTML = '';
2494 this.menuitems.clear();
2508 * @class Roo.bootstrap.MenuItem
2509 * @extends Roo.bootstrap.Component
2510 * Bootstrap MenuItem class
2511 * @cfg {String} html the menu label
2512 * @cfg {String} href the link
2513 * @cfg {Boolean} preventDefault do not trigger A href on clicks (default false).
2514 * @cfg {Boolean} isContainer is it a container - just returns a drop down item..
2515 * @cfg {Boolean} active used on sidebars to highlight active itesm
2516 * @cfg {String} fa favicon to show on left of menu item.
2517 * @cfg {Roo.bootsrap.Menu} menu the child menu.
2521 * Create a new MenuItem
2522 * @param {Object} config The config object
2526 Roo.bootstrap.MenuItem = function(config){
2527 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
2532 * The raw click event for the entire grid.
2533 * @param {Roo.bootstrap.MenuItem} this
2534 * @param {Roo.EventObject} e
2540 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
2544 preventDefault: false,
2545 isContainer : false,
2549 getAutoCreate : function(){
2551 if(this.isContainer){
2554 cls: 'dropdown-menu-item '
2564 cls : 'dropdown-item',
2569 if (this.fa !== false) {
2572 cls : 'fa fa-' + this.fa
2581 cls: 'dropdown-menu-item',
2584 if (this.parent().type == 'treeview') {
2585 cfg.cls = 'treeview-menu';
2588 cfg.cls += ' active';
2593 anc.href = this.href || cfg.cn[0].href ;
2594 ctag.html = this.html || cfg.cn[0].html ;
2598 initEvents: function()
2600 if (this.parent().type == 'treeview') {
2601 this.el.select('a').on('click', this.onClick, this);
2605 this.menu.parentType = this.xtype;
2606 this.menu.triggerEl = this.el;
2607 this.menu = this.addxtype(Roo.apply({}, this.menu));
2611 onClick : function(e)
2613 Roo.log('item on click ');
2615 if(this.preventDefault){
2618 //this.parent().hideMenuItems();
2620 this.fireEvent('click', this, e);
2639 * @class Roo.bootstrap.MenuSeparator
2640 * @extends Roo.bootstrap.Component
2641 * Bootstrap MenuSeparator class
2644 * Create a new MenuItem
2645 * @param {Object} config The config object
2649 Roo.bootstrap.MenuSeparator = function(config){
2650 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2653 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2655 getAutoCreate : function(){
2674 * @class Roo.bootstrap.Modal
2675 * @extends Roo.bootstrap.Component
2676 * Bootstrap Modal class
2677 * @cfg {String} title Title of dialog
2678 * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2679 * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method adn
2680 * @cfg {Boolean} specificTitle default false
2681 * @cfg {Array} buttons Array of buttons or standard button set..
2682 * @cfg {String} buttonPosition (left|right|center) default right (DEPRICATED) - use mr-auto on buttons to put them on the left
2683 * @cfg {Boolean} animate default true
2684 * @cfg {Boolean} allow_close default true
2685 * @cfg {Boolean} fitwindow default false
2686 * @cfg {String} size (sm|lg) default empty
2687 * @cfg {Number} max_width set the max width of modal
2691 * Create a new Modal Dialog
2692 * @param {Object} config The config object
2695 Roo.bootstrap.Modal = function(config){
2696 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2701 * The raw btnclick event for the button
2702 * @param {Roo.EventObject} e
2707 * Fire when dialog resize
2708 * @param {Roo.bootstrap.Modal} this
2709 * @param {Roo.EventObject} e
2713 this.buttons = this.buttons || [];
2716 this.tmpl = Roo.factory(this.tmpl);
2721 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2723 title : 'test dialog',
2733 specificTitle: false,
2735 buttonPosition: 'right',
2758 onRender : function(ct, position)
2760 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2763 var cfg = Roo.apply({}, this.getAutoCreate());
2766 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2768 //if (!cfg.name.length) {
2772 cfg.cls += ' ' + this.cls;
2775 cfg.style = this.style;
2777 this.el = Roo.get(document.body).createChild(cfg, position);
2779 //var type = this.el.dom.type;
2782 if(this.tabIndex !== undefined){
2783 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2786 this.dialogEl = this.el.select('.modal-dialog',true).first();
2787 this.bodyEl = this.el.select('.modal-body',true).first();
2788 this.closeEl = this.el.select('.modal-header .close', true).first();
2789 this.headerEl = this.el.select('.modal-header',true).first();
2790 this.titleEl = this.el.select('.modal-title',true).first();
2791 this.footerEl = this.el.select('.modal-footer',true).first();
2793 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2795 //this.el.addClass("x-dlg-modal");
2797 if (this.buttons.length) {
2798 Roo.each(this.buttons, function(bb) {
2799 var b = Roo.apply({}, bb);
2800 b.xns = b.xns || Roo.bootstrap;
2801 b.xtype = b.xtype || 'Button';
2802 if (typeof(b.listeners) == 'undefined') {
2803 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2806 var btn = Roo.factory(b);
2808 btn.render(this.getButtonContainer());
2812 // render the children.
2815 if(typeof(this.items) != 'undefined'){
2816 var items = this.items;
2819 for(var i =0;i < items.length;i++) {
2820 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2824 this.items = nitems;
2826 // where are these used - they used to be body/close/footer
2830 //this.el.addClass([this.fieldClass, this.cls]);
2834 getAutoCreate : function()
2838 html : this.html || ''
2843 cls : 'modal-title',
2847 if(this.specificTitle){
2853 if (this.allow_close && Roo.bootstrap.version == 3) {
2863 if (this.allow_close && Roo.bootstrap.version == 4) {
2873 if(this.size.length){
2874 size = 'modal-' + this.size;
2877 var footer = Roo.bootstrap.version == 3 ?
2879 cls : 'modal-footer',
2883 cls: 'btn-' + this.buttonPosition
2888 { // BS4 uses mr-auto on left buttons....
2889 cls : 'modal-footer'
2900 cls: "modal-dialog " + size,
2903 cls : "modal-content",
2906 cls : 'modal-header',
2921 modal.cls += ' fade';
2927 getChildContainer : function() {
2932 getButtonContainer : function() {
2934 return Roo.bootstrap.version == 4 ?
2935 this.el.select('.modal-footer',true).first()
2936 : this.el.select('.modal-footer div',true).first();
2939 initEvents : function()
2941 if (this.allow_close) {
2942 this.closeEl.on('click', this.hide, this);
2944 Roo.EventManager.onWindowResize(this.resize, this, true);
2952 this.maskEl.setSize(
2953 Roo.lib.Dom.getViewWidth(true),
2954 Roo.lib.Dom.getViewHeight(true)
2957 if (this.fitwindow) {
2961 this.width || Roo.lib.Dom.getViewportWidth(true) - 30,
2962 this.height || Roo.lib.Dom.getViewportHeight(true) // catering margin-top 30 margin-bottom 30
2967 if(this.max_width !== 0) {
2969 var w = Math.min(this.max_width, Roo.lib.Dom.getViewportWidth(true) - 30);
2972 this.setSize(w, this.height);
2976 if(this.max_height) {
2977 this.setSize(w,Math.min(
2979 Roo.lib.Dom.getViewportHeight(true) - 60
2985 if(!this.fit_content) {
2986 this.setSize(w, Roo.lib.Dom.getViewportHeight(true) - 60);
2990 this.setSize(w, Math.min(
2992 this.headerEl.getHeight() +
2993 this.footerEl.getHeight() +
2994 this.getChildHeight(this.bodyEl.dom.childNodes),
2995 Roo.lib.Dom.getViewportHeight(true) - 60)
3001 setSize : function(w,h)
3012 if (!this.rendered) {
3016 //this.el.setStyle('display', 'block');
3017 this.el.removeClass('hideing');
3018 this.el.dom.style.display='block';
3020 Roo.get(document.body).addClass('modal-open');
3022 if(this.animate){ // element has 'fade' - so stuff happens after .3s ?- not sure why the delay?
3025 this.el.addClass('show');
3026 this.el.addClass('in');
3029 this.el.addClass('show');
3030 this.el.addClass('in');
3033 // not sure how we can show data in here..
3035 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
3038 Roo.get(document.body).addClass("x-body-masked");
3040 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
3041 this.maskEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
3042 this.maskEl.dom.style.display = 'block';
3043 this.maskEl.addClass('show');
3048 this.fireEvent('show', this);
3050 // set zindex here - otherwise it appears to be ignored...
3051 this.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
3054 this.items.forEach( function(e) {
3055 e.layout ? e.layout() : false;
3063 if(this.fireEvent("beforehide", this) !== false){
3065 this.maskEl.removeClass('show');
3067 this.maskEl.dom.style.display = '';
3068 Roo.get(document.body).removeClass("x-body-masked");
3069 this.el.removeClass('in');
3070 this.el.select('.modal-dialog', true).first().setStyle('transform','');
3072 if(this.animate){ // why
3073 this.el.addClass('hideing');
3074 this.el.removeClass('show');
3076 if (!this.el.hasClass('hideing')) {
3077 return; // it's been shown again...
3080 this.el.dom.style.display='';
3082 Roo.get(document.body).removeClass('modal-open');
3083 this.el.removeClass('hideing');
3087 this.el.removeClass('show');
3088 this.el.dom.style.display='';
3089 Roo.get(document.body).removeClass('modal-open');
3092 this.fireEvent('hide', this);
3095 isVisible : function()
3098 return this.el.hasClass('show') && !this.el.hasClass('hideing');
3102 addButton : function(str, cb)
3106 var b = Roo.apply({}, { html : str } );
3107 b.xns = b.xns || Roo.bootstrap;
3108 b.xtype = b.xtype || 'Button';
3109 if (typeof(b.listeners) == 'undefined') {
3110 b.listeners = { click : cb.createDelegate(this) };
3113 var btn = Roo.factory(b);
3115 btn.render(this.getButtonContainer());
3121 setDefaultButton : function(btn)
3123 //this.el.select('.modal-footer').()
3126 resizeTo: function(w,h)
3128 this.dialogEl.setWidth(w);
3130 var diff = this.headerEl.getHeight() + this.footerEl.getHeight() + 60; // dialog margin-bottom: 30
3132 this.bodyEl.setHeight(h - diff);
3134 this.fireEvent('resize', this);
3137 setContentSize : function(w, h)
3141 onButtonClick: function(btn,e)
3144 this.fireEvent('btnclick', btn.name, e);
3147 * Set the title of the Dialog
3148 * @param {String} str new Title
3150 setTitle: function(str) {
3151 this.titleEl.dom.innerHTML = str;
3154 * Set the body of the Dialog
3155 * @param {String} str new Title
3157 setBody: function(str) {
3158 this.bodyEl.dom.innerHTML = str;
3161 * Set the body of the Dialog using the template
3162 * @param {Obj} data - apply this data to the template and replace the body contents.
3164 applyBody: function(obj)
3167 Roo.log("Error - using apply Body without a template");
3170 this.tmpl.overwrite(this.bodyEl, obj);
3173 getChildHeight : function(child_nodes)
3177 child_nodes.length == 0
3182 var child_height = 0;
3184 for(var i = 0; i < child_nodes.length; i++) {
3187 * for modal with tabs...
3188 if(child_nodes[i].classList.contains('roo-layout-panel')) {
3190 var layout_childs = child_nodes[i].childNodes;
3192 for(var j = 0; j < layout_childs.length; j++) {
3194 if(layout_childs[j].classList.contains('roo-layout-panel-body')) {
3196 var layout_body_childs = layout_childs[j].childNodes;
3198 for(var k = 0; k < layout_body_childs.length; k++) {
3200 if(layout_body_childs[k].classList.contains('navbar')) {
3201 child_height += layout_body_childs[k].offsetHeight;
3205 if(layout_body_childs[k].classList.contains('roo-layout-tabs-body')) {
3207 var layout_body_tab_childs = layout_body_childs[k].childNodes;
3209 for(var m = 0; m < layout_body_tab_childs.length; m++) {
3211 if(layout_body_tab_childs[m].classList.contains('roo-layout-active-content')) {
3212 child_height += this.getChildHeight(layout_body_tab_childs[m].childNodes);
3227 child_height += child_nodes[i].offsetHeight;
3228 // Roo.log(child_nodes[i].offsetHeight);
3231 return child_height;
3237 Roo.apply(Roo.bootstrap.Modal, {
3239 * Button config that displays a single OK button
3248 * Button config that displays Yes and No buttons
3264 * Button config that displays OK and Cancel buttons
3279 * Button config that displays Yes, No and Cancel buttons
3303 * messagebox - can be used as a replace
3307 * @class Roo.MessageBox
3308 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
3312 Roo.Msg.alert('Status', 'Changes saved successfully.');
3314 // Prompt for user data:
3315 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
3317 // process text value...
3321 // Show a dialog using config options:
3323 title:'Save Changes?',
3324 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
3325 buttons: Roo.Msg.YESNOCANCEL,
3332 Roo.bootstrap.MessageBox = function(){
3333 var dlg, opt, mask, waitTimer;
3334 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
3335 var buttons, activeTextEl, bwidth;
3339 var handleButton = function(button){
3341 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
3345 var handleHide = function(){
3347 dlg.el.removeClass(opt.cls);
3350 // Roo.TaskMgr.stop(waitTimer);
3351 // waitTimer = null;
3356 var updateButtons = function(b){
3359 buttons["ok"].hide();
3360 buttons["cancel"].hide();
3361 buttons["yes"].hide();
3362 buttons["no"].hide();
3363 dlg.footerEl.hide();
3367 dlg.footerEl.show();
3368 for(var k in buttons){
3369 if(typeof buttons[k] != "function"){
3372 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
3373 width += buttons[k].el.getWidth()+15;
3383 var handleEsc = function(d, k, e){
3384 if(opt && opt.closable !== false){
3394 * Returns a reference to the underlying {@link Roo.BasicDialog} element
3395 * @return {Roo.BasicDialog} The BasicDialog element
3397 getDialog : function(){
3399 dlg = new Roo.bootstrap.Modal( {
3402 //constraintoviewport:false,
3404 //collapsible : false,
3409 //buttonAlign:"center",
3410 closeClick : function(){
3411 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
3414 handleButton("cancel");
3419 dlg.on("hide", handleHide);
3421 //dlg.addKeyListener(27, handleEsc);
3423 this.buttons = buttons;
3424 var bt = this.buttonText;
3425 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
3426 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
3427 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
3428 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
3430 bodyEl = dlg.bodyEl.createChild({
3432 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
3433 '<textarea class="roo-mb-textarea"></textarea>' +
3434 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
3436 msgEl = bodyEl.dom.firstChild;
3437 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
3438 textboxEl.enableDisplayMode();
3439 textboxEl.addKeyListener([10,13], function(){
3440 if(dlg.isVisible() && opt && opt.buttons){
3443 }else if(opt.buttons.yes){
3444 handleButton("yes");
3448 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
3449 textareaEl.enableDisplayMode();
3450 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
3451 progressEl.enableDisplayMode();
3453 // This is supposed to be the progessElement.. but I think it's controlling the height of everything..
3454 var pf = progressEl.dom.firstChild;
3456 pp = Roo.get(pf.firstChild);
3457 pp.setHeight(pf.offsetHeight);
3465 * Updates the message box body text
3466 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
3467 * the XHTML-compliant non-breaking space character '&#160;')
3468 * @return {Roo.MessageBox} This message box
3470 updateText : function(text)
3472 if(!dlg.isVisible() && !opt.width){
3473 dlg.dialogEl.setStyle({ 'max-width' : this.maxWidth});
3474 // dlg.resizeTo(this.maxWidth, 100); // forcing the height breaks long alerts()
3476 msgEl.innerHTML = text || ' ';
3478 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
3479 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
3481 Math.min(opt.width || cw , this.maxWidth),
3482 Math.max(opt.minWidth || this.minWidth, bwidth)
3485 activeTextEl.setWidth(w);
3487 if(dlg.isVisible()){
3488 dlg.fixedcenter = false;
3490 // to big, make it scroll. = But as usual stupid IE does not support
3493 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
3494 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
3495 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
3497 bodyEl.dom.style.height = '';
3498 bodyEl.dom.style.overflowY = '';
3501 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
3503 bodyEl.dom.style.overflowX = '';
3506 dlg.setContentSize(w, bodyEl.getHeight());
3507 if(dlg.isVisible()){
3508 dlg.fixedcenter = true;
3514 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
3515 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
3516 * @param {Number} value Any number between 0 and 1 (e.g., .5)
3517 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
3518 * @return {Roo.MessageBox} This message box
3520 updateProgress : function(value, text){
3522 this.updateText(text);
3525 if (pp) { // weird bug on my firefox - for some reason this is not defined
3526 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
3527 pp.setHeight(Math.floor(progressEl.dom.firstChild.offsetHeight));
3533 * Returns true if the message box is currently displayed
3534 * @return {Boolean} True if the message box is visible, else false
3536 isVisible : function(){
3537 return dlg && dlg.isVisible();
3541 * Hides the message box if it is displayed
3544 if(this.isVisible()){
3550 * Displays a new message box, or reinitializes an existing message box, based on the config options
3551 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
3552 * The following config object properties are supported:
3554 Property Type Description
3555 ---------- --------------- ------------------------------------------------------------------------------------
3556 animEl String/Element An id or Element from which the message box should animate as it opens and
3557 closes (defaults to undefined)
3558 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
3559 cancel:'Bar'}), or false to not show any buttons (defaults to false)
3560 closable Boolean False to hide the top-right close button (defaults to true). Note that
3561 progress and wait dialogs will ignore this property and always hide the
3562 close button as they can only be closed programmatically.
3563 cls String A custom CSS class to apply to the message box element
3564 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
3565 displayed (defaults to 75)
3566 fn Function A callback function to execute after closing the dialog. The arguments to the
3567 function will be btn (the name of the button that was clicked, if applicable,
3568 e.g. "ok"), and text (the value of the active text field, if applicable).
3569 Progress and wait dialogs will ignore this option since they do not respond to
3570 user actions and can only be closed programmatically, so any required function
3571 should be called by the same code after it closes the dialog.
3572 icon String A CSS class that provides a background image to be used as an icon for
3573 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
3574 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
3575 minWidth Number The minimum width in pixels of the message box (defaults to 100)
3576 modal Boolean False to allow user interaction with the page while the message box is
3577 displayed (defaults to true)
3578 msg String A string that will replace the existing message box body text (defaults
3579 to the XHTML-compliant non-breaking space character ' ')
3580 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
3581 progress Boolean True to display a progress bar (defaults to false)
3582 progressText String The text to display inside the progress bar if progress = true (defaults to '')
3583 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
3584 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
3585 title String The title text
3586 value String The string value to set into the active textbox element if displayed
3587 wait Boolean True to display a progress bar (defaults to false)
3588 width Number The width of the dialog in pixels
3595 msg: 'Please enter your address:',
3597 buttons: Roo.MessageBox.OKCANCEL,
3600 animEl: 'addAddressBtn'
3603 * @param {Object} config Configuration options
3604 * @return {Roo.MessageBox} This message box
3606 show : function(options)
3609 // this causes nightmares if you show one dialog after another
3610 // especially on callbacks..
3612 if(this.isVisible()){
3615 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
3616 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
3617 Roo.log("New Dialog Message:" + options.msg )
3618 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
3619 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
3622 var d = this.getDialog();
3624 d.setTitle(opt.title || " ");
3625 d.closeEl.setDisplayed(opt.closable !== false);
3626 activeTextEl = textboxEl;
3627 opt.prompt = opt.prompt || (opt.multiline ? true : false);
3632 textareaEl.setHeight(typeof opt.multiline == "number" ?
3633 opt.multiline : this.defaultTextHeight);
3634 activeTextEl = textareaEl;
3643 progressEl.setDisplayed(opt.progress === true);
3645 d.animate = false; // do not animate progress, as it may not have finished animating before we close it..
3647 this.updateProgress(0);
3648 activeTextEl.dom.value = opt.value || "";
3650 dlg.setDefaultButton(activeTextEl);
3652 var bs = opt.buttons;
3656 }else if(bs && bs.yes){
3657 db = buttons["yes"];
3659 dlg.setDefaultButton(db);
3661 bwidth = updateButtons(opt.buttons);
3662 this.updateText(opt.msg);
3664 d.el.addClass(opt.cls);
3666 d.proxyDrag = opt.proxyDrag === true;
3667 d.modal = opt.modal !== false;
3668 d.mask = opt.modal !== false ? mask : false;
3670 // force it to the end of the z-index stack so it gets a cursor in FF
3671 document.body.appendChild(dlg.el.dom);
3672 d.animateTarget = null;
3673 d.show(options.animEl);
3679 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
3680 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
3681 * and closing the message box when the process is complete.
3682 * @param {String} title The title bar text
3683 * @param {String} msg The message box body text
3684 * @return {Roo.MessageBox} This message box
3686 progress : function(title, msg){
3693 minWidth: this.minProgressWidth,
3700 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
3701 * If a callback function is passed it will be called after the user clicks the button, and the
3702 * id of the button that was clicked will be passed as the only parameter to the callback
3703 * (could also be the top-right close button).
3704 * @param {String} title The title bar text
3705 * @param {String} msg The message box body text
3706 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3707 * @param {Object} scope (optional) The scope of the callback function
3708 * @return {Roo.MessageBox} This message box
3710 alert : function(title, msg, fn, scope)
3725 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
3726 * interaction while waiting for a long-running process to complete that does not have defined intervals.
3727 * You are responsible for closing the message box when the process is complete.
3728 * @param {String} msg The message box body text
3729 * @param {String} title (optional) The title bar text
3730 * @return {Roo.MessageBox} This message box
3732 wait : function(msg, title){
3743 waitTimer = Roo.TaskMgr.start({
3745 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
3753 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
3754 * If a callback function is passed it will be called after the user clicks either button, and the id of the
3755 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
3756 * @param {String} title The title bar text
3757 * @param {String} msg The message box body text
3758 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3759 * @param {Object} scope (optional) The scope of the callback function
3760 * @return {Roo.MessageBox} This message box
3762 confirm : function(title, msg, fn, scope){
3766 buttons: this.YESNO,
3775 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
3776 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
3777 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
3778 * (could also be the top-right close button) and the text that was entered will be passed as the two
3779 * parameters to the callback.
3780 * @param {String} title The title bar text
3781 * @param {String} msg The message box body text
3782 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3783 * @param {Object} scope (optional) The scope of the callback function
3784 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
3785 * property, or the height in pixels to create the textbox (defaults to false / single-line)
3786 * @return {Roo.MessageBox} This message box
3788 prompt : function(title, msg, fn, scope, multiline){
3792 buttons: this.OKCANCEL,
3797 multiline: multiline,
3804 * Button config that displays a single OK button
3809 * Button config that displays Yes and No buttons
3812 YESNO : {yes:true, no:true},
3814 * Button config that displays OK and Cancel buttons
3817 OKCANCEL : {ok:true, cancel:true},
3819 * Button config that displays Yes, No and Cancel buttons
3822 YESNOCANCEL : {yes:true, no:true, cancel:true},
3825 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3828 defaultTextHeight : 75,
3830 * The maximum width in pixels of the message box (defaults to 600)
3835 * The minimum width in pixels of the message box (defaults to 100)
3840 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3841 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3844 minProgressWidth : 250,
3846 * An object containing the default button text strings that can be overriden for localized language support.
3847 * Supported properties are: ok, cancel, yes and no.
3848 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3861 * Shorthand for {@link Roo.MessageBox}
3863 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3864 Roo.Msg = Roo.Msg || Roo.MessageBox;
3873 * @class Roo.bootstrap.Navbar
3874 * @extends Roo.bootstrap.Component
3875 * Bootstrap Navbar class
3878 * Create a new Navbar
3879 * @param {Object} config The config object
3883 Roo.bootstrap.Navbar = function(config){
3884 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3888 * @event beforetoggle
3889 * Fire before toggle the menu
3890 * @param {Roo.EventObject} e
3892 "beforetoggle" : true
3896 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3905 getAutoCreate : function(){
3908 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3912 initEvents :function ()
3914 //Roo.log(this.el.select('.navbar-toggle',true));
3915 this.el.select('.navbar-toggle',true).on('click', this.onToggle , this);
3922 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3924 var size = this.el.getSize();
3925 this.maskEl.setSize(size.width, size.height);
3926 this.maskEl.enableDisplayMode("block");
3935 getChildContainer : function()
3937 if (this.el && this.el.select('.collapse').getCount()) {
3938 return this.el.select('.collapse',true).first();
3953 onToggle : function()
3956 if(this.fireEvent('beforetoggle', this) === false){
3959 var ce = this.el.select('.navbar-collapse',true).first();
3961 if (!ce.hasClass('show')) {
3971 * Expand the navbar pulldown
3973 expand : function ()
3976 var ce = this.el.select('.navbar-collapse',true).first();
3977 if (ce.hasClass('collapsing')) {
3980 ce.dom.style.height = '';
3982 ce.addClass('in'); // old...
3983 ce.removeClass('collapse');
3984 ce.addClass('show');
3985 var h = ce.getHeight();
3987 ce.removeClass('show');
3988 // at this point we should be able to see it..
3989 ce.addClass('collapsing');
3991 ce.setHeight(0); // resize it ...
3992 ce.on('transitionend', function() {
3993 //Roo.log('done transition');
3994 ce.removeClass('collapsing');
3995 ce.addClass('show');
3996 ce.removeClass('collapse');
3998 ce.dom.style.height = '';
3999 }, this, { single: true} );
4001 ce.dom.scrollTop = 0;
4004 * Collapse the navbar pulldown
4006 collapse : function()
4008 var ce = this.el.select('.navbar-collapse',true).first();
4010 if (ce.hasClass('collapsing') || ce.hasClass('collapse') ) {
4011 // it's collapsed or collapsing..
4014 ce.removeClass('in'); // old...
4015 ce.setHeight(ce.getHeight());
4016 ce.removeClass('show');
4017 ce.addClass('collapsing');
4019 ce.on('transitionend', function() {
4020 ce.dom.style.height = '';
4021 ce.removeClass('collapsing');
4022 ce.addClass('collapse');
4023 }, this, { single: true} );
4043 * @class Roo.bootstrap.NavSimplebar
4044 * @extends Roo.bootstrap.Navbar
4045 * Bootstrap Sidebar class
4047 * @cfg {Boolean} inverse is inverted color
4049 * @cfg {String} type (nav | pills | tabs)
4050 * @cfg {Boolean} arrangement stacked | justified
4051 * @cfg {String} align (left | right) alignment
4053 * @cfg {Boolean} main (true|false) main nav bar? default false
4054 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
4056 * @cfg {String} tag (header|footer|nav|div) default is nav
4058 * @cfg {String} weight (light|primary|secondary|success|danger|warning|info|dark|white) default is light.
4062 * Create a new Sidebar
4063 * @param {Object} config The config object
4067 Roo.bootstrap.NavSimplebar = function(config){
4068 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
4071 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
4087 getAutoCreate : function(){
4091 tag : this.tag || 'div',
4092 cls : 'navbar roo-navbar-simple' //navbar-expand-lg ??
4094 if (['light','white'].indexOf(this.weight) > -1) {
4095 cfg.cls += ['light','white'].indexOf(this.weight) > -1 ? ' navbar-light' : ' navbar-dark';
4097 cfg.cls += ' bg-' + this.weight;
4100 cfg.cls += ' navbar-inverse';
4104 // i'm not actually sure these are really used - normally we add a navGroup to a navbar
4106 if (Roo.bootstrap.version == 4 && this.xtype == 'NavSimplebar') {
4115 cls: 'nav nav-' + this.xtype,
4121 this.type = this.type || 'nav';
4122 if (['tabs','pills'].indexOf(this.type) != -1) {
4123 cfg.cn[0].cls += ' nav-' + this.type
4127 if (this.type!=='nav') {
4128 Roo.log('nav type must be nav/tabs/pills')
4130 cfg.cn[0].cls += ' navbar-nav'
4136 if (['stacked','justified'].indexOf(this.arrangement) != -1) {
4137 cfg.cn[0].cls += ' nav-' + this.arrangement;
4141 if (this.align === 'right') {
4142 cfg.cn[0].cls += ' navbar-right';
4167 * navbar-expand-md fixed-top
4171 * @class Roo.bootstrap.NavHeaderbar
4172 * @extends Roo.bootstrap.NavSimplebar
4173 * Bootstrap Sidebar class
4175 * @cfg {String} brand what is brand
4176 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
4177 * @cfg {String} brand_href href of the brand
4178 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
4179 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
4180 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
4181 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
4184 * Create a new Sidebar
4185 * @param {Object} config The config object
4189 Roo.bootstrap.NavHeaderbar = function(config){
4190 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
4194 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
4201 desktopCenter : false,
4204 getAutoCreate : function(){
4207 tag: this.nav || 'nav',
4208 cls: 'navbar navbar-expand-md',
4214 if (this.desktopCenter) {
4215 cn.push({cls : 'container', cn : []});
4223 cls: 'navbar-toggle navbar-toggler',
4224 'data-toggle': 'collapse',
4229 html: 'Toggle navigation'
4233 cls: 'icon-bar navbar-toggler-icon'
4246 cn.push( Roo.bootstrap.version == 4 ? btn : {
4248 cls: 'navbar-header',
4257 cls: Roo.bootstrap.version == 4 ? 'nav flex-row roo-navbar-collapse' : 'collapse navbar-collapse roo-navbar-collapse',
4261 cfg.cls += this.inverse ? ' navbar-inverse navbar-dark bg-dark' : ' navbar-default';
4263 if (['light','white'].indexOf(this.weight) > -1) {
4264 cfg.cls += ['light','white'].indexOf(this.weight) > -1 ? ' navbar-light' : ' navbar-dark';
4266 cfg.cls += ' bg-' + this.weight;
4269 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
4270 cfg.cls += ' navbar-' + this.position + ' ' + this.position ;
4272 // tag can override this..
4274 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
4277 if (this.brand !== '') {
4278 var cp = Roo.bootstrap.version == 4 ? cn : cn[0].cn;
4279 cp.unshift({ // changed from push ?? BS4 needs it at the start? - does this break or exsiting?
4281 href: this.brand_href ? this.brand_href : '#',
4282 cls: 'navbar-brand',
4290 cfg.cls += ' main-nav';
4298 getHeaderChildContainer : function()
4300 if (this.srButton && this.el.select('.navbar-header').getCount()) {
4301 return this.el.select('.navbar-header',true).first();
4304 return this.getChildContainer();
4308 initEvents : function()
4310 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
4312 if (this.autohide) {
4317 Roo.get(document).on('scroll',function(e) {
4318 var ns = Roo.get(document).getScroll().top;
4319 var os = prevScroll;
4323 ft.removeClass('slideDown');
4324 ft.addClass('slideUp');
4327 ft.removeClass('slideUp');
4328 ft.addClass('slideDown');
4349 * @class Roo.bootstrap.NavSidebar
4350 * @extends Roo.bootstrap.Navbar
4351 * Bootstrap Sidebar class
4354 * Create a new Sidebar
4355 * @param {Object} config The config object
4359 Roo.bootstrap.NavSidebar = function(config){
4360 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
4363 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
4365 sidebar : true, // used by Navbar Item and NavbarGroup at present...
4367 getAutoCreate : function(){
4372 cls: 'sidebar sidebar-nav'
4394 * @class Roo.bootstrap.NavGroup
4395 * @extends Roo.bootstrap.Component
4396 * Bootstrap NavGroup class
4397 * @cfg {String} align (left|right)
4398 * @cfg {Boolean} inverse
4399 * @cfg {String} type (nav|pills|tab) default nav
4400 * @cfg {String} navId - reference Id for navbar.
4404 * Create a new nav group
4405 * @param {Object} config The config object
4408 Roo.bootstrap.NavGroup = function(config){
4409 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
4412 Roo.bootstrap.NavGroup.register(this);
4416 * Fires when the active item changes
4417 * @param {Roo.bootstrap.NavGroup} this
4418 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
4419 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
4426 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
4437 getAutoCreate : function()
4439 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
4445 if (Roo.bootstrap.version == 4) {
4446 if (['tabs','pills'].indexOf(this.type) != -1) {
4447 cfg.cls += ' nav-' + this.type;
4449 // trying to remove so header bar can right align top?
4450 if (this.parent() && this.parent().xtype != 'NavHeaderbar') {
4451 // do not use on header bar...
4452 cfg.cls += ' navbar-nav';
4457 if (['tabs','pills'].indexOf(this.type) != -1) {
4458 cfg.cls += ' nav-' + this.type
4460 if (this.type !== 'nav') {
4461 Roo.log('nav type must be nav/tabs/pills')
4463 cfg.cls += ' navbar-nav'
4467 if (this.parent() && this.parent().sidebar) {
4470 cls: 'dashboard-menu sidebar-menu'
4476 if (this.form === true) {
4479 cls: 'navbar-form form-inline'
4481 //nav navbar-right ml-md-auto
4482 if (this.align === 'right') {
4483 cfg.cls += ' navbar-right ml-md-auto';
4485 cfg.cls += ' navbar-left';
4489 if (this.align === 'right') {
4490 cfg.cls += ' navbar-right ml-md-auto';
4492 cfg.cls += ' mr-auto';
4496 cfg.cls += ' navbar-inverse';
4504 * sets the active Navigation item
4505 * @param {Roo.bootstrap.NavItem} the new current navitem
4507 setActiveItem : function(item)
4510 Roo.each(this.navItems, function(v){
4515 v.setActive(false, true);
4522 item.setActive(true, true);
4523 this.fireEvent('changed', this, item, prev);
4528 * gets the active Navigation item
4529 * @return {Roo.bootstrap.NavItem} the current navitem
4531 getActive : function()
4535 Roo.each(this.navItems, function(v){
4546 indexOfNav : function()
4550 Roo.each(this.navItems, function(v,i){
4561 * adds a Navigation item
4562 * @param {Roo.bootstrap.NavItem} the navitem to add
4564 addItem : function(cfg)
4566 if (this.form && Roo.bootstrap.version == 4) {
4569 var cn = new Roo.bootstrap.NavItem(cfg);
4571 cn.parentId = this.id;
4572 cn.onRender(this.el, null);
4576 * register a Navigation item
4577 * @param {Roo.bootstrap.NavItem} the navitem to add
4579 register : function(item)
4581 this.navItems.push( item);
4582 item.navId = this.navId;
4587 * clear all the Navigation item
4590 clearAll : function()
4593 this.el.dom.innerHTML = '';
4596 getNavItem: function(tabId)
4599 Roo.each(this.navItems, function(e) {
4600 if (e.tabId == tabId) {
4610 setActiveNext : function()
4612 var i = this.indexOfNav(this.getActive());
4613 if (i > this.navItems.length) {
4616 this.setActiveItem(this.navItems[i+1]);
4618 setActivePrev : function()
4620 var i = this.indexOfNav(this.getActive());
4624 this.setActiveItem(this.navItems[i-1]);
4626 clearWasActive : function(except) {
4627 Roo.each(this.navItems, function(e) {
4628 if (e.tabId != except.tabId && e.was_active) {
4629 e.was_active = false;
4636 getWasActive : function ()
4639 Roo.each(this.navItems, function(e) {
4654 Roo.apply(Roo.bootstrap.NavGroup, {
4658 * register a Navigation Group
4659 * @param {Roo.bootstrap.NavGroup} the navgroup to add
4661 register : function(navgrp)
4663 this.groups[navgrp.navId] = navgrp;
4667 * fetch a Navigation Group based on the navigation ID
4668 * @param {string} the navgroup to add
4669 * @returns {Roo.bootstrap.NavGroup} the navgroup
4671 get: function(navId) {
4672 if (typeof(this.groups[navId]) == 'undefined') {
4674 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
4676 return this.groups[navId] ;
4691 * @class Roo.bootstrap.NavItem
4692 * @extends Roo.bootstrap.Component
4693 * Bootstrap Navbar.NavItem class
4694 * @cfg {String} href link to
4695 * @cfg {String} button_weight (default | primary | secondary | success | info | warning | danger | link ) default none
4697 * @cfg {String} html content of button
4698 * @cfg {String} badge text inside badge
4699 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
4700 * @cfg {String} glyphicon DEPRICATED - use fa
4701 * @cfg {String} icon DEPRICATED - use fa
4702 * @cfg {String} fa - Fontawsome icon name (can add stuff to it like fa-2x)
4703 * @cfg {Boolean} active Is item active
4704 * @cfg {Boolean} disabled Is item disabled
4706 * @cfg {Boolean} preventDefault (true | false) default false
4707 * @cfg {String} tabId the tab that this item activates.
4708 * @cfg {String} tagtype (a|span) render as a href or span?
4709 * @cfg {Boolean} animateRef (true|false) link to element default false
4712 * Create a new Navbar Item
4713 * @param {Object} config The config object
4715 Roo.bootstrap.NavItem = function(config){
4716 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
4721 * The raw click event for the entire grid.
4722 * @param {Roo.EventObject} e
4727 * Fires when the active item active state changes
4728 * @param {Roo.bootstrap.NavItem} this
4729 * @param {boolean} state the new state
4735 * Fires when scroll to element
4736 * @param {Roo.bootstrap.NavItem} this
4737 * @param {Object} options
4738 * @param {Roo.EventObject} e
4746 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
4755 preventDefault : false,
4763 button_outline : false,
4767 getAutoCreate : function(){
4775 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
4777 if (this.disabled) {
4778 cfg.cls += ' disabled';
4782 if (this.button_weight.length) {
4783 cfg.tag = this.href ? 'a' : 'button';
4784 cfg.html = this.html || '';
4785 cfg.cls += ' btn btn' + (this.button_outline ? '-outline' : '') + '-' + this.button_weight;
4787 cfg.href = this.href;
4790 cfg.html = '<i class="fa fas fa-'+this.fa+'"></i> <span>' + this.html + '</span>';
4793 // menu .. should add dropdown-menu class - so no need for carat..
4795 if (this.badge !== '') {
4797 cfg.html += ' <span class="badge badge-secondary">' + this.badge + '</span>';
4802 if (this.href || this.html || this.glyphicon || this.icon || this.fa) {
4806 href : this.href || "#",
4807 html: this.html || ''
4810 if (this.tagtype == 'a') {
4811 cfg.cn[0].cls = 'nav-link';
4814 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>';
4817 cfg.cn[0].html = '<i class="fa fas fa-'+this.fa+'"></i> <span>' + cfg.cn[0].html + '</span>';
4819 if(this.glyphicon) {
4820 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
4825 cfg.cn[0].html += " <span class='caret'></span>";
4829 if (this.badge !== '') {
4831 cfg.cn[0].html += ' <span class="badge badge-secondary">' + this.badge + '</span>';
4839 onRender : function(ct, position)
4841 // Roo.log("Call onRender: " + this.xtype);
4842 if (Roo.bootstrap.version == 4 && ct.dom.type != 'ul') {
4846 var ret = Roo.bootstrap.NavItem.superclass.onRender.call(this, ct, position);
4847 this.navLink = this.el.select('.nav-link',true).first();
4852 initEvents: function()
4854 if (typeof (this.menu) != 'undefined') {
4855 this.menu.parentType = this.xtype;
4856 this.menu.triggerEl = this.el;
4857 this.menu = this.addxtype(Roo.apply({}, this.menu));
4860 this.el.select('a',true).on('click', this.onClick, this);
4862 if(this.tagtype == 'span'){
4863 this.el.select('span',true).on('click', this.onClick, this);
4866 // at this point parent should be available..
4867 this.parent().register(this);
4870 onClick : function(e)
4872 if (e.getTarget('.dropdown-menu-item')) {
4873 // did you click on a menu itemm.... - then don't trigger onclick..
4878 this.preventDefault ||
4881 Roo.log("NavItem - prevent Default?");
4885 if (this.disabled) {
4889 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4890 if (tg && tg.transition) {
4891 Roo.log("waiting for the transitionend");
4897 //Roo.log("fire event clicked");
4898 if(this.fireEvent('click', this, e) === false){
4902 if(this.tagtype == 'span'){
4906 //Roo.log(this.href);
4907 var ael = this.el.select('a',true).first();
4910 if(ael && this.animateRef && this.href.indexOf('#') > -1){
4911 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4912 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4913 return; // ignore... - it's a 'hash' to another page.
4915 Roo.log("NavItem - prevent Default?");
4917 this.scrollToElement(e);
4921 var p = this.parent();
4923 if (['tabs','pills'].indexOf(p.type)!==-1) {
4924 if (typeof(p.setActiveItem) !== 'undefined') {
4925 p.setActiveItem(this);
4929 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4930 if (p.parentType == 'NavHeaderbar' && !this.menu) {
4931 // remove the collapsed menu expand...
4932 p.parent().el.select('.roo-navbar-collapse',true).removeClass('in');
4936 isActive: function () {
4939 setActive : function(state, fire, is_was_active)
4941 if (this.active && !state && this.navId) {
4942 this.was_active = true;
4943 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4945 nv.clearWasActive(this);
4949 this.active = state;
4952 this.el.removeClass('active');
4953 this.navLink ? this.navLink.removeClass('active') : false;
4954 } else if (!this.el.hasClass('active')) {
4956 this.el.addClass('active');
4957 if (Roo.bootstrap.version == 4 && this.navLink ) {
4958 this.navLink.addClass('active');
4963 this.fireEvent('changed', this, state);
4966 // show a panel if it's registered and related..
4968 if (!this.navId || !this.tabId || !state || is_was_active) {
4972 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4976 var pan = tg.getPanelByName(this.tabId);
4980 // if we can not flip to new panel - go back to old nav highlight..
4981 if (false == tg.showPanel(pan)) {
4982 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4984 var onav = nv.getWasActive();
4986 onav.setActive(true, false, true);
4995 // this should not be here...
4996 setDisabled : function(state)
4998 this.disabled = state;
5000 this.el.removeClass('disabled');
5001 } else if (!this.el.hasClass('disabled')) {
5002 this.el.addClass('disabled');
5008 * Fetch the element to display the tooltip on.
5009 * @return {Roo.Element} defaults to this.el
5011 tooltipEl : function()
5013 return this.el.select('' + this.tagtype + '', true).first();
5016 scrollToElement : function(e)
5018 var c = document.body;
5021 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
5023 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
5024 c = document.documentElement;
5027 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
5033 var o = target.calcOffsetsTo(c);
5040 this.fireEvent('scrollto', this, options, e);
5042 Roo.get(c).scrollTo('top', options.value, true);
5055 * <span> icon </span>
5056 * <span> text </span>
5057 * <span>badge </span>
5061 * @class Roo.bootstrap.NavSidebarItem
5062 * @extends Roo.bootstrap.NavItem
5063 * Bootstrap Navbar.NavSidebarItem class
5064 * {String} badgeWeight (default|primary|success|info|warning|danger)the extra classes for the badge
5065 * {Boolean} open is the menu open
5066 * {Boolean} buttonView use button as the tigger el rather that a (default false)
5067 * {String} buttonWeight (default|primary|success|info|warning|danger)the extra classes for the button
5068 * {String} buttonSize (sm|md|lg)the extra classes for the button
5069 * {Boolean} showArrow show arrow next to the text (default true)
5071 * Create a new Navbar Button
5072 * @param {Object} config The config object
5074 Roo.bootstrap.NavSidebarItem = function(config){
5075 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
5080 * The raw click event for the entire grid.
5081 * @param {Roo.EventObject} e
5086 * Fires when the active item active state changes
5087 * @param {Roo.bootstrap.NavSidebarItem} this
5088 * @param {boolean} state the new state
5096 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
5098 badgeWeight : 'default',
5104 buttonWeight : 'default',
5110 getAutoCreate : function(){
5115 href : this.href || '#',
5121 if(this.buttonView){
5124 href : this.href || '#',
5125 cls: 'btn btn-' + this.buttonWeight + ' btn-' + this.buttonSize + 'roo-button-dropdown-toggle',
5138 cfg.cls += ' active';
5141 if (this.disabled) {
5142 cfg.cls += ' disabled';
5145 cfg.cls += ' open x-open';
5148 if (this.glyphicon || this.icon) {
5149 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
5150 a.cn.push({ tag : 'i', cls : c }) ;
5153 if(!this.buttonView){
5156 html : this.html || ''
5163 if (this.badge !== '') {
5164 a.cn.push({ tag: 'span', cls : 'badge pull-right badge-' + this.badgeWeight, html: this.badge });
5170 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
5173 a.cls += ' dropdown-toggle treeview' ;
5179 initEvents : function()
5181 if (typeof (this.menu) != 'undefined') {
5182 this.menu.parentType = this.xtype;
5183 this.menu.triggerEl = this.el;
5184 this.menu = this.addxtype(Roo.apply({}, this.menu));
5187 this.el.on('click', this.onClick, this);
5189 if(this.badge !== ''){
5190 this.badgeEl = this.el.select('.badge', true).first().setVisibilityMode(Roo.Element.DISPLAY);
5195 onClick : function(e)
5202 if(this.preventDefault){
5206 this.fireEvent('click', this, e);
5209 disable : function()
5211 this.setDisabled(true);
5216 this.setDisabled(false);
5219 setDisabled : function(state)
5221 if(this.disabled == state){
5225 this.disabled = state;
5228 this.el.addClass('disabled');
5232 this.el.removeClass('disabled');
5237 setActive : function(state)
5239 if(this.active == state){
5243 this.active = state;
5246 this.el.addClass('active');
5250 this.el.removeClass('active');
5255 isActive: function ()
5260 setBadge : function(str)
5266 this.badgeEl.dom.innerHTML = str;
5283 * @class Roo.bootstrap.Row
5284 * @extends Roo.bootstrap.Component
5285 * Bootstrap Row class (contains columns...)
5289 * @param {Object} config The config object
5292 Roo.bootstrap.Row = function(config){
5293 Roo.bootstrap.Row.superclass.constructor.call(this, config);
5296 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
5298 getAutoCreate : function(){
5317 * @class Roo.bootstrap.Element
5318 * @extends Roo.bootstrap.Component
5319 * Bootstrap Element class
5320 * @cfg {String} html contents of the element
5321 * @cfg {String} tag tag of the element
5322 * @cfg {String} cls class of the element
5323 * @cfg {Boolean} preventDefault (true|false) default false
5324 * @cfg {Boolean} clickable (true|false) default false
5327 * Create a new Element
5328 * @param {Object} config The config object
5331 Roo.bootstrap.Element = function(config){
5332 Roo.bootstrap.Element.superclass.constructor.call(this, config);
5338 * When a element is chick
5339 * @param {Roo.bootstrap.Element} this
5340 * @param {Roo.EventObject} e
5346 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
5351 preventDefault: false,
5354 getAutoCreate : function(){
5358 // cls: this.cls, double assign in parent class Component.js :: onRender
5365 initEvents: function()
5367 Roo.bootstrap.Element.superclass.initEvents.call(this);
5370 this.el.on('click', this.onClick, this);
5375 onClick : function(e)
5377 if(this.preventDefault){
5381 this.fireEvent('click', this, e);
5384 getValue : function()
5386 return this.el.dom.innerHTML;
5389 setValue : function(value)
5391 this.el.dom.innerHTML = value;
5406 * @class Roo.bootstrap.Pagination
5407 * @extends Roo.bootstrap.Component
5408 * Bootstrap Pagination class
5409 * @cfg {String} size xs | sm | md | lg
5410 * @cfg {Boolean} inverse false | true
5413 * Create a new Pagination
5414 * @param {Object} config The config object
5417 Roo.bootstrap.Pagination = function(config){
5418 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
5421 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
5427 getAutoCreate : function(){
5433 cfg.cls += ' inverse';
5439 cfg.cls += " " + this.cls;
5457 * @class Roo.bootstrap.PaginationItem
5458 * @extends Roo.bootstrap.Component
5459 * Bootstrap PaginationItem class
5460 * @cfg {String} html text
5461 * @cfg {String} href the link
5462 * @cfg {Boolean} preventDefault (true | false) default true
5463 * @cfg {Boolean} active (true | false) default false
5464 * @cfg {Boolean} disabled default false
5468 * Create a new PaginationItem
5469 * @param {Object} config The config object
5473 Roo.bootstrap.PaginationItem = function(config){
5474 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
5479 * The raw click event for the entire grid.
5480 * @param {Roo.EventObject} e
5486 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
5490 preventDefault: true,
5495 getAutoCreate : function(){
5501 href : this.href ? this.href : '#',
5502 html : this.html ? this.html : ''
5512 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
5516 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
5522 initEvents: function() {
5524 this.el.on('click', this.onClick, this);
5527 onClick : function(e)
5529 Roo.log('PaginationItem on click ');
5530 if(this.preventDefault){
5538 this.fireEvent('click', this, e);
5554 * @class Roo.bootstrap.Slider
5555 * @extends Roo.bootstrap.Component
5556 * Bootstrap Slider class
5559 * Create a new Slider
5560 * @param {Object} config The config object
5563 Roo.bootstrap.Slider = function(config){
5564 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
5567 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
5569 getAutoCreate : function(){
5573 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
5577 cls: 'ui-slider-handle ui-state-default ui-corner-all'
5589 * Ext JS Library 1.1.1
5590 * Copyright(c) 2006-2007, Ext JS, LLC.
5592 * Originally Released Under LGPL - original licence link has changed is not relivant.
5595 * <script type="text/javascript">
5600 * @class Roo.grid.ColumnModel
5601 * @extends Roo.util.Observable
5602 * This is the default implementation of a ColumnModel used by the Grid. It defines
5603 * the columns in the grid.
5606 var colModel = new Roo.grid.ColumnModel([
5607 {header: "Ticker", width: 60, sortable: true, locked: true},
5608 {header: "Company Name", width: 150, sortable: true},
5609 {header: "Market Cap.", width: 100, sortable: true},
5610 {header: "$ Sales", width: 100, sortable: true, renderer: money},
5611 {header: "Employees", width: 100, sortable: true, resizable: false}
5616 * The config options listed for this class are options which may appear in each
5617 * individual column definition.
5618 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
5620 * @param {Object} config An Array of column config objects. See this class's
5621 * config objects for details.
5623 Roo.grid.ColumnModel = function(config){
5625 * The config passed into the constructor
5627 this.config = config;
5630 // if no id, create one
5631 // if the column does not have a dataIndex mapping,
5632 // map it to the order it is in the config
5633 for(var i = 0, len = config.length; i < len; i++){
5635 if(typeof c.dataIndex == "undefined"){
5638 if(typeof c.renderer == "string"){
5639 c.renderer = Roo.util.Format[c.renderer];
5641 if(typeof c.id == "undefined"){
5644 if(c.editor && c.editor.xtype){
5645 c.editor = Roo.factory(c.editor, Roo.grid);
5647 if(c.editor && c.editor.isFormField){
5648 c.editor = new Roo.grid.GridEditor(c.editor);
5650 this.lookup[c.id] = c;
5654 * The width of columns which have no width specified (defaults to 100)
5657 this.defaultWidth = 100;
5660 * Default sortable of columns which have no sortable specified (defaults to false)
5663 this.defaultSortable = false;
5667 * @event widthchange
5668 * Fires when the width of a column changes.
5669 * @param {ColumnModel} this
5670 * @param {Number} columnIndex The column index
5671 * @param {Number} newWidth The new width
5673 "widthchange": true,
5675 * @event headerchange
5676 * Fires when the text of a header changes.
5677 * @param {ColumnModel} this
5678 * @param {Number} columnIndex The column index
5679 * @param {Number} newText The new header text
5681 "headerchange": true,
5683 * @event hiddenchange
5684 * Fires when a column is hidden or "unhidden".
5685 * @param {ColumnModel} this
5686 * @param {Number} columnIndex The column index
5687 * @param {Boolean} hidden true if hidden, false otherwise
5689 "hiddenchange": true,
5691 * @event columnmoved
5692 * Fires when a column is moved.
5693 * @param {ColumnModel} this
5694 * @param {Number} oldIndex
5695 * @param {Number} newIndex
5697 "columnmoved" : true,
5699 * @event columlockchange
5700 * Fires when a column's locked state is changed
5701 * @param {ColumnModel} this
5702 * @param {Number} colIndex
5703 * @param {Boolean} locked true if locked
5705 "columnlockchange" : true
5707 Roo.grid.ColumnModel.superclass.constructor.call(this);
5709 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
5711 * @cfg {String} header The header text to display in the Grid view.
5714 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
5715 * {@link Roo.data.Record} definition from which to draw the column's value. If not
5716 * specified, the column's index is used as an index into the Record's data Array.
5719 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
5720 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
5723 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
5724 * Defaults to the value of the {@link #defaultSortable} property.
5725 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
5728 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
5731 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
5734 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
5737 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
5740 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
5741 * given the cell's data value. See {@link #setRenderer}. If not specified, the
5742 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
5743 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
5746 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
5749 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
5752 * @cfg {String} valign (Optional) Set the CSS vertical-align property of the column (eg. middle, top, bottom etc). Defaults to undefined.
5755 * @cfg {String} cursor (Optional)
5758 * @cfg {String} tooltip (Optional)
5761 * @cfg {Number} xs (Optional)
5764 * @cfg {Number} sm (Optional)
5767 * @cfg {Number} md (Optional)
5770 * @cfg {Number} lg (Optional)
5773 * Returns the id of the column at the specified index.
5774 * @param {Number} index The column index
5775 * @return {String} the id
5777 getColumnId : function(index){
5778 return this.config[index].id;
5782 * Returns the column for a specified id.
5783 * @param {String} id The column id
5784 * @return {Object} the column
5786 getColumnById : function(id){
5787 return this.lookup[id];
5792 * Returns the column for a specified dataIndex.
5793 * @param {String} dataIndex The column dataIndex
5794 * @return {Object|Boolean} the column or false if not found
5796 getColumnByDataIndex: function(dataIndex){
5797 var index = this.findColumnIndex(dataIndex);
5798 return index > -1 ? this.config[index] : false;
5802 * Returns the index for a specified column id.
5803 * @param {String} id The column id
5804 * @return {Number} the index, or -1 if not found
5806 getIndexById : function(id){
5807 for(var i = 0, len = this.config.length; i < len; i++){
5808 if(this.config[i].id == id){
5816 * Returns the index for a specified column dataIndex.
5817 * @param {String} dataIndex The column dataIndex
5818 * @return {Number} the index, or -1 if not found
5821 findColumnIndex : function(dataIndex){
5822 for(var i = 0, len = this.config.length; i < len; i++){
5823 if(this.config[i].dataIndex == dataIndex){
5831 moveColumn : function(oldIndex, newIndex){
5832 var c = this.config[oldIndex];
5833 this.config.splice(oldIndex, 1);
5834 this.config.splice(newIndex, 0, c);
5835 this.dataMap = null;
5836 this.fireEvent("columnmoved", this, oldIndex, newIndex);
5839 isLocked : function(colIndex){
5840 return this.config[colIndex].locked === true;
5843 setLocked : function(colIndex, value, suppressEvent){
5844 if(this.isLocked(colIndex) == value){
5847 this.config[colIndex].locked = value;
5849 this.fireEvent("columnlockchange", this, colIndex, value);
5853 getTotalLockedWidth : function(){
5855 for(var i = 0; i < this.config.length; i++){
5856 if(this.isLocked(i) && !this.isHidden(i)){
5857 this.totalWidth += this.getColumnWidth(i);
5863 getLockedCount : function(){
5864 for(var i = 0, len = this.config.length; i < len; i++){
5865 if(!this.isLocked(i)){
5870 return this.config.length;
5874 * Returns the number of columns.
5877 getColumnCount : function(visibleOnly){
5878 if(visibleOnly === true){
5880 for(var i = 0, len = this.config.length; i < len; i++){
5881 if(!this.isHidden(i)){
5887 return this.config.length;
5891 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
5892 * @param {Function} fn
5893 * @param {Object} scope (optional)
5894 * @return {Array} result
5896 getColumnsBy : function(fn, scope){
5898 for(var i = 0, len = this.config.length; i < len; i++){
5899 var c = this.config[i];
5900 if(fn.call(scope||this, c, i) === true){
5908 * Returns true if the specified column is sortable.
5909 * @param {Number} col The column index
5912 isSortable : function(col){
5913 if(typeof this.config[col].sortable == "undefined"){
5914 return this.defaultSortable;
5916 return this.config[col].sortable;
5920 * Returns the rendering (formatting) function defined for the column.
5921 * @param {Number} col The column index.
5922 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
5924 getRenderer : function(col){
5925 if(!this.config[col].renderer){
5926 return Roo.grid.ColumnModel.defaultRenderer;
5928 return this.config[col].renderer;
5932 * Sets the rendering (formatting) function for a column.
5933 * @param {Number} col The column index
5934 * @param {Function} fn The function to use to process the cell's raw data
5935 * to return HTML markup for the grid view. The render function is called with
5936 * the following parameters:<ul>
5937 * <li>Data value.</li>
5938 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
5939 * <li>css A CSS style string to apply to the table cell.</li>
5940 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
5941 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
5942 * <li>Row index</li>
5943 * <li>Column index</li>
5944 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
5946 setRenderer : function(col, fn){
5947 this.config[col].renderer = fn;
5951 * Returns the width for the specified column.
5952 * @param {Number} col The column index
5955 getColumnWidth : function(col){
5956 return this.config[col].width * 1 || this.defaultWidth;
5960 * Sets the width for a column.
5961 * @param {Number} col The column index
5962 * @param {Number} width The new width
5964 setColumnWidth : function(col, width, suppressEvent){
5965 this.config[col].width = width;
5966 this.totalWidth = null;
5968 this.fireEvent("widthchange", this, col, width);
5973 * Returns the total width of all columns.
5974 * @param {Boolean} includeHidden True to include hidden column widths
5977 getTotalWidth : function(includeHidden){
5978 if(!this.totalWidth){
5979 this.totalWidth = 0;
5980 for(var i = 0, len = this.config.length; i < len; i++){
5981 if(includeHidden || !this.isHidden(i)){
5982 this.totalWidth += this.getColumnWidth(i);
5986 return this.totalWidth;
5990 * Returns the header for the specified column.
5991 * @param {Number} col The column index
5994 getColumnHeader : function(col){
5995 return this.config[col].header;
5999 * Sets the header for a column.
6000 * @param {Number} col The column index
6001 * @param {String} header The new header
6003 setColumnHeader : function(col, header){
6004 this.config[col].header = header;
6005 this.fireEvent("headerchange", this, col, header);
6009 * Returns the tooltip for the specified column.
6010 * @param {Number} col The column index
6013 getColumnTooltip : function(col){
6014 return this.config[col].tooltip;
6017 * Sets the tooltip for a column.
6018 * @param {Number} col The column index
6019 * @param {String} tooltip The new tooltip
6021 setColumnTooltip : function(col, tooltip){
6022 this.config[col].tooltip = tooltip;
6026 * Returns the dataIndex for the specified column.
6027 * @param {Number} col The column index
6030 getDataIndex : function(col){
6031 return this.config[col].dataIndex;
6035 * Sets the dataIndex for a column.
6036 * @param {Number} col The column index
6037 * @param {Number} dataIndex The new dataIndex
6039 setDataIndex : function(col, dataIndex){
6040 this.config[col].dataIndex = dataIndex;
6046 * Returns true if the cell is editable.
6047 * @param {Number} colIndex The column index
6048 * @param {Number} rowIndex The row index - this is nto actually used..?
6051 isCellEditable : function(colIndex, rowIndex){
6052 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
6056 * Returns the editor defined for the cell/column.
6057 * return false or null to disable editing.
6058 * @param {Number} colIndex The column index
6059 * @param {Number} rowIndex The row index
6062 getCellEditor : function(colIndex, rowIndex){
6063 return this.config[colIndex].editor;
6067 * Sets if a column is editable.
6068 * @param {Number} col The column index
6069 * @param {Boolean} editable True if the column is editable
6071 setEditable : function(col, editable){
6072 this.config[col].editable = editable;
6077 * Returns true if the column is hidden.
6078 * @param {Number} colIndex The column index
6081 isHidden : function(colIndex){
6082 return this.config[colIndex].hidden;
6087 * Returns true if the column width cannot be changed
6089 isFixed : function(colIndex){
6090 return this.config[colIndex].fixed;
6094 * Returns true if the column can be resized
6097 isResizable : function(colIndex){
6098 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
6101 * Sets if a column is hidden.
6102 * @param {Number} colIndex The column index
6103 * @param {Boolean} hidden True if the column is hidden
6105 setHidden : function(colIndex, hidden){
6106 this.config[colIndex].hidden = hidden;
6107 this.totalWidth = null;
6108 this.fireEvent("hiddenchange", this, colIndex, hidden);
6112 * Sets the editor for a column.
6113 * @param {Number} col The column index
6114 * @param {Object} editor The editor object
6116 setEditor : function(col, editor){
6117 this.config[col].editor = editor;
6121 Roo.grid.ColumnModel.defaultRenderer = function(value)
6123 if(typeof value == "object") {
6126 if(typeof value == "string" && value.length < 1){
6130 return String.format("{0}", value);
6133 // Alias for backwards compatibility
6134 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
6137 * Ext JS Library 1.1.1
6138 * Copyright(c) 2006-2007, Ext JS, LLC.
6140 * Originally Released Under LGPL - original licence link has changed is not relivant.
6143 * <script type="text/javascript">
6147 * @class Roo.LoadMask
6148 * A simple utility class for generically masking elements while loading data. If the element being masked has
6149 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
6150 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
6151 * element's UpdateManager load indicator and will be destroyed after the initial load.
6153 * Create a new LoadMask
6154 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
6155 * @param {Object} config The config object
6157 Roo.LoadMask = function(el, config){
6158 this.el = Roo.get(el);
6159 Roo.apply(this, config);
6161 this.store.on('beforeload', this.onBeforeLoad, this);
6162 this.store.on('load', this.onLoad, this);
6163 this.store.on('loadexception', this.onLoadException, this);
6164 this.removeMask = false;
6166 var um = this.el.getUpdateManager();
6167 um.showLoadIndicator = false; // disable the default indicator
6168 um.on('beforeupdate', this.onBeforeLoad, this);
6169 um.on('update', this.onLoad, this);
6170 um.on('failure', this.onLoad, this);
6171 this.removeMask = true;
6175 Roo.LoadMask.prototype = {
6177 * @cfg {Boolean} removeMask
6178 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
6179 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
6183 * The text to display in a centered loading message box (defaults to 'Loading...')
6187 * @cfg {String} msgCls
6188 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
6190 msgCls : 'x-mask-loading',
6193 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
6199 * Disables the mask to prevent it from being displayed
6201 disable : function(){
6202 this.disabled = true;
6206 * Enables the mask so that it can be displayed
6208 enable : function(){
6209 this.disabled = false;
6212 onLoadException : function()
6216 if (typeof(arguments[3]) != 'undefined') {
6217 Roo.MessageBox.alert("Error loading",arguments[3]);
6221 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
6222 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
6229 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
6234 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
6238 onBeforeLoad : function(){
6240 (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
6245 destroy : function(){
6247 this.store.un('beforeload', this.onBeforeLoad, this);
6248 this.store.un('load', this.onLoad, this);
6249 this.store.un('loadexception', this.onLoadException, this);
6251 var um = this.el.getUpdateManager();
6252 um.un('beforeupdate', this.onBeforeLoad, this);
6253 um.un('update', this.onLoad, this);
6254 um.un('failure', this.onLoad, this);
6265 * @class Roo.bootstrap.Table
6266 * @extends Roo.bootstrap.Component
6267 * Bootstrap Table class
6268 * @cfg {String} cls table class
6269 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
6270 * @cfg {String} bgcolor Specifies the background color for a table
6271 * @cfg {Number} border Specifies whether the table cells should have borders or not
6272 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
6273 * @cfg {Number} cellspacing Specifies the space between cells
6274 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
6275 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
6276 * @cfg {String} sortable Specifies that the table should be sortable
6277 * @cfg {String} summary Specifies a summary of the content of a table
6278 * @cfg {Number} width Specifies the width of a table
6279 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
6281 * @cfg {boolean} striped Should the rows be alternative striped
6282 * @cfg {boolean} bordered Add borders to the table
6283 * @cfg {boolean} hover Add hover highlighting
6284 * @cfg {boolean} condensed Format condensed
6285 * @cfg {boolean} responsive Format condensed
6286 * @cfg {Boolean} loadMask (true|false) default false
6287 * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
6288 * @cfg {Boolean} headerShow (true|false) generate thead, default true
6289 * @cfg {Boolean} rowSelection (true|false) default false
6290 * @cfg {Boolean} cellSelection (true|false) default false
6291 * @cfg {Boolean} scrollBody (true|false) default false - body scrolled / fixed header
6292 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
6293 * @cfg {Boolean} lazyLoad auto load data while scrolling to the end (default false)
6294 * @cfg {Boolean} auto_hide_footer auto hide footer if only one page (default false)
6298 * Create a new Table
6299 * @param {Object} config The config object
6302 Roo.bootstrap.Table = function(config){
6303 Roo.bootstrap.Table.superclass.constructor.call(this, config);
6308 this.rowSelection = (typeof(config.rowSelection) != 'undefined') ? config.rowSelection : this.rowSelection;
6309 this.cellSelection = (typeof(config.cellSelection) != 'undefined') ? config.cellSelection : this.cellSelection;
6310 this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
6311 this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
6313 this.sm = this.sm || {xtype: 'RowSelectionModel'};
6315 this.sm.grid = this;
6316 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
6317 this.sm = this.selModel;
6318 this.sm.xmodule = this.xmodule || false;
6321 if (this.cm && typeof(this.cm.config) == 'undefined') {
6322 this.colModel = new Roo.grid.ColumnModel(this.cm);
6323 this.cm = this.colModel;
6324 this.cm.xmodule = this.xmodule || false;
6327 this.store= Roo.factory(this.store, Roo.data);
6328 this.ds = this.store;
6329 this.ds.xmodule = this.xmodule || false;
6332 if (this.footer && this.store) {
6333 this.footer.dataSource = this.ds;
6334 this.footer = Roo.factory(this.footer);
6341 * Fires when a cell is clicked
6342 * @param {Roo.bootstrap.Table} this
6343 * @param {Roo.Element} el
6344 * @param {Number} rowIndex
6345 * @param {Number} columnIndex
6346 * @param {Roo.EventObject} e
6350 * @event celldblclick
6351 * Fires when a cell is double clicked
6352 * @param {Roo.bootstrap.Table} this
6353 * @param {Roo.Element} el
6354 * @param {Number} rowIndex
6355 * @param {Number} columnIndex
6356 * @param {Roo.EventObject} e
6358 "celldblclick" : true,
6361 * Fires when a row is clicked
6362 * @param {Roo.bootstrap.Table} this
6363 * @param {Roo.Element} el
6364 * @param {Number} rowIndex
6365 * @param {Roo.EventObject} e
6369 * @event rowdblclick
6370 * Fires when a row is double clicked
6371 * @param {Roo.bootstrap.Table} this
6372 * @param {Roo.Element} el
6373 * @param {Number} rowIndex
6374 * @param {Roo.EventObject} e
6376 "rowdblclick" : true,
6379 * Fires when a mouseover occur
6380 * @param {Roo.bootstrap.Table} this
6381 * @param {Roo.Element} el
6382 * @param {Number} rowIndex
6383 * @param {Number} columnIndex
6384 * @param {Roo.EventObject} e
6389 * Fires when a mouseout occur
6390 * @param {Roo.bootstrap.Table} this
6391 * @param {Roo.Element} el
6392 * @param {Number} rowIndex
6393 * @param {Number} columnIndex
6394 * @param {Roo.EventObject} e
6399 * Fires when a row is rendered, so you can change add a style to it.
6400 * @param {Roo.bootstrap.Table} this
6401 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
6405 * @event rowsrendered
6406 * Fires when all the rows have been rendered
6407 * @param {Roo.bootstrap.Table} this
6409 'rowsrendered' : true,
6411 * @event contextmenu
6412 * The raw contextmenu event for the entire grid.
6413 * @param {Roo.EventObject} e
6415 "contextmenu" : true,
6417 * @event rowcontextmenu
6418 * Fires when a row is right clicked
6419 * @param {Roo.bootstrap.Table} this
6420 * @param {Number} rowIndex
6421 * @param {Roo.EventObject} e
6423 "rowcontextmenu" : true,
6425 * @event cellcontextmenu
6426 * Fires when a cell is right clicked
6427 * @param {Roo.bootstrap.Table} this
6428 * @param {Number} rowIndex
6429 * @param {Number} cellIndex
6430 * @param {Roo.EventObject} e
6432 "cellcontextmenu" : true,
6434 * @event headercontextmenu
6435 * Fires when a header is right clicked
6436 * @param {Roo.bootstrap.Table} this
6437 * @param {Number} columnIndex
6438 * @param {Roo.EventObject} e
6440 "headercontextmenu" : true
6444 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
6470 rowSelection : false,
6471 cellSelection : false,
6474 // Roo.Element - the tbody
6476 // Roo.Element - thead element
6479 container: false, // used by gridpanel...
6485 auto_hide_footer : false,
6487 getAutoCreate : function()
6489 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
6496 if (this.scrollBody) {
6497 cfg.cls += ' table-body-fixed';
6500 cfg.cls += ' table-striped';
6504 cfg.cls += ' table-hover';
6506 if (this.bordered) {
6507 cfg.cls += ' table-bordered';
6509 if (this.condensed) {
6510 cfg.cls += ' table-condensed';
6512 if (this.responsive) {
6513 cfg.cls += ' table-responsive';
6517 cfg.cls+= ' ' +this.cls;
6520 // this lot should be simplifed...
6533 ].forEach(function(k) {
6541 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
6544 if(this.store || this.cm){
6545 if(this.headerShow){
6546 cfg.cn.push(this.renderHeader());
6549 cfg.cn.push(this.renderBody());
6551 if(this.footerShow){
6552 cfg.cn.push(this.renderFooter());
6554 // where does this come from?
6555 //cfg.cls+= ' TableGrid';
6558 return { cn : [ cfg ] };
6561 initEvents : function()
6563 if(!this.store || !this.cm){
6566 if (this.selModel) {
6567 this.selModel.initEvents();
6571 //Roo.log('initEvents with ds!!!!');
6573 this.mainBody = this.el.select('tbody', true).first();
6574 this.mainHead = this.el.select('thead', true).first();
6575 this.mainFoot = this.el.select('tfoot', true).first();
6581 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6582 e.on('click', _this.sort, _this);
6585 this.mainBody.on("click", this.onClick, this);
6586 this.mainBody.on("dblclick", this.onDblClick, this);
6588 // why is this done????? = it breaks dialogs??
6589 //this.parent().el.setStyle('position', 'relative');
6593 this.footer.parentId = this.id;
6594 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
6597 this.el.select('tfoot tr td').first().addClass('hide');
6602 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
6605 this.store.on('load', this.onLoad, this);
6606 this.store.on('beforeload', this.onBeforeLoad, this);
6607 this.store.on('update', this.onUpdate, this);
6608 this.store.on('add', this.onAdd, this);
6609 this.store.on("clear", this.clear, this);
6611 this.el.on("contextmenu", this.onContextMenu, this);
6613 this.mainBody.on('scroll', this.onBodyScroll, this);
6615 this.cm.on("headerchange", this.onHeaderChange, this);
6617 this.cm.on("hiddenchange", this.onHiddenChange, this, arguments);
6621 onContextMenu : function(e, t)
6623 this.processEvent("contextmenu", e);
6626 processEvent : function(name, e)
6628 if (name != 'touchstart' ) {
6629 this.fireEvent(name, e);
6632 var t = e.getTarget();
6634 var cell = Roo.get(t);
6640 if(cell.findParent('tfoot', false, true)){
6644 if(cell.findParent('thead', false, true)){
6646 if(e.getTarget().nodeName.toLowerCase() != 'th'){
6647 cell = Roo.get(t).findParent('th', false, true);
6649 Roo.log("failed to find th in thead?");
6650 Roo.log(e.getTarget());
6655 var cellIndex = cell.dom.cellIndex;
6657 var ename = name == 'touchstart' ? 'click' : name;
6658 this.fireEvent("header" + ename, this, cellIndex, e);
6663 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6664 cell = Roo.get(t).findParent('td', false, true);
6666 Roo.log("failed to find th in tbody?");
6667 Roo.log(e.getTarget());
6672 var row = cell.findParent('tr', false, true);
6673 var cellIndex = cell.dom.cellIndex;
6674 var rowIndex = row.dom.rowIndex - 1;
6678 this.fireEvent("row" + name, this, rowIndex, e);
6682 this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
6688 onMouseover : function(e, el)
6690 var cell = Roo.get(el);
6696 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6697 cell = cell.findParent('td', false, true);
6700 var row = cell.findParent('tr', false, true);
6701 var cellIndex = cell.dom.cellIndex;
6702 var rowIndex = row.dom.rowIndex - 1; // start from 0
6704 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
6708 onMouseout : function(e, el)
6710 var cell = Roo.get(el);
6716 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6717 cell = cell.findParent('td', false, true);
6720 var row = cell.findParent('tr', false, true);
6721 var cellIndex = cell.dom.cellIndex;
6722 var rowIndex = row.dom.rowIndex - 1; // start from 0
6724 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
6728 onClick : function(e, el)
6730 var cell = Roo.get(el);
6732 if(!cell || (!this.cellSelection && !this.rowSelection)){
6736 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6737 cell = cell.findParent('td', false, true);
6740 if(!cell || typeof(cell) == 'undefined'){
6744 var row = cell.findParent('tr', false, true);
6746 if(!row || typeof(row) == 'undefined'){
6750 var cellIndex = cell.dom.cellIndex;
6751 var rowIndex = this.getRowIndex(row);
6753 // why??? - should these not be based on SelectionModel?
6754 if(this.cellSelection){
6755 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
6758 if(this.rowSelection){
6759 this.fireEvent('rowclick', this, row, rowIndex, e);
6765 onDblClick : function(e,el)
6767 var cell = Roo.get(el);
6769 if(!cell || (!this.cellSelection && !this.rowSelection)){
6773 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6774 cell = cell.findParent('td', false, true);
6777 if(!cell || typeof(cell) == 'undefined'){
6781 var row = cell.findParent('tr', false, true);
6783 if(!row || typeof(row) == 'undefined'){
6787 var cellIndex = cell.dom.cellIndex;
6788 var rowIndex = this.getRowIndex(row);
6790 if(this.cellSelection){
6791 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
6794 if(this.rowSelection){
6795 this.fireEvent('rowdblclick', this, row, rowIndex, e);
6799 sort : function(e,el)
6801 var col = Roo.get(el);
6803 if(!col.hasClass('sortable')){
6807 var sort = col.attr('sort');
6810 if(col.select('i', true).first().hasClass('glyphicon-arrow-up')){
6814 this.store.sortInfo = {field : sort, direction : dir};
6817 Roo.log("calling footer first");
6818 this.footer.onClick('first');
6821 this.store.load({ params : { start : 0 } });
6825 renderHeader : function()
6833 this.totalWidth = 0;
6835 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6837 var config = cm.config[i];
6841 cls : 'x-hcol-' + i,
6843 html: cm.getColumnHeader(i)
6848 if(typeof(config.sortable) != 'undefined' && config.sortable){
6850 c.html = '<i class="glyphicon"></i>' + c.html;
6853 // could use BS4 hidden-..-down
6855 if(typeof(config.lgHeader) != 'undefined'){
6856 hh += '<span class="hidden-xs hidden-sm hidden-md ">' + config.lgHeader + '</span>';
6859 if(typeof(config.mdHeader) != 'undefined'){
6860 hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
6863 if(typeof(config.smHeader) != 'undefined'){
6864 hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
6867 if(typeof(config.xsHeader) != 'undefined'){
6868 hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
6875 if(typeof(config.tooltip) != 'undefined'){
6876 c.tooltip = config.tooltip;
6879 if(typeof(config.colspan) != 'undefined'){
6880 c.colspan = config.colspan;
6883 if(typeof(config.hidden) != 'undefined' && config.hidden){
6884 c.style += ' display:none;';
6887 if(typeof(config.dataIndex) != 'undefined'){
6888 c.sort = config.dataIndex;
6893 if(typeof(config.align) != 'undefined' && config.align.length){
6894 c.style += ' text-align:' + config.align + ';';
6897 if(typeof(config.width) != 'undefined'){
6898 c.style += ' width:' + config.width + 'px;';
6899 this.totalWidth += config.width;
6901 this.totalWidth += 100; // assume minimum of 100 per column?
6904 if(typeof(config.cls) != 'undefined'){
6905 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
6908 ['xs','sm','md','lg'].map(function(size){
6910 if(typeof(config[size]) == 'undefined'){
6914 if (!config[size]) { // 0 = hidden
6915 // BS 4 '0' is treated as hide that column and below.
6916 c.cls += ' hidden-' + size + ' hidden' + size + '-down';
6920 c.cls += ' col-' + size + '-' + config[size] + (
6921 size == 'xs' ? (' col-' + config[size] ) : '' // bs4 col-{num} replaces col-xs
6933 renderBody : function()
6943 colspan : this.cm.getColumnCount()
6953 renderFooter : function()
6963 colspan : this.cm.getColumnCount()
6977 // Roo.log('ds onload');
6982 var ds = this.store;
6984 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6985 e.select('i', true).removeClass(['glyphicon-arrow-up', 'glyphicon-arrow-down']);
6986 if (_this.store.sortInfo) {
6988 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
6989 e.select('i', true).addClass(['glyphicon-arrow-up']);
6992 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
6993 e.select('i', true).addClass(['glyphicon-arrow-down']);
6998 var tbody = this.mainBody;
7000 if(ds.getCount() > 0){
7001 ds.data.each(function(d,rowIndex){
7002 var row = this.renderRow(cm, ds, rowIndex);
7004 tbody.createChild(row);
7008 if(row.cellObjects.length){
7009 Roo.each(row.cellObjects, function(r){
7010 _this.renderCellObject(r);
7017 var tfoot = this.el.select('tfoot', true).first();
7019 if(this.footerShow && this.auto_hide_footer && this.mainFoot){
7021 this.mainFoot.setVisibilityMode(Roo.Element.DISPLAY).hide();
7023 var total = this.ds.getTotalCount();
7025 if(this.footer.pageSize < total){
7026 this.mainFoot.show();
7030 Roo.each(this.el.select('tbody td', true).elements, function(e){
7031 e.on('mouseover', _this.onMouseover, _this);
7034 Roo.each(this.el.select('tbody td', true).elements, function(e){
7035 e.on('mouseout', _this.onMouseout, _this);
7037 this.fireEvent('rowsrendered', this);
7043 onUpdate : function(ds,record)
7045 this.refreshRow(record);
7049 onRemove : function(ds, record, index, isUpdate){
7050 if(isUpdate !== true){
7051 this.fireEvent("beforerowremoved", this, index, record);
7053 var bt = this.mainBody.dom;
7055 var rows = this.el.select('tbody > tr', true).elements;
7057 if(typeof(rows[index]) != 'undefined'){
7058 bt.removeChild(rows[index].dom);
7061 // if(bt.rows[index]){
7062 // bt.removeChild(bt.rows[index]);
7065 if(isUpdate !== true){
7066 //this.stripeRows(index);
7067 //this.syncRowHeights(index, index);
7069 this.fireEvent("rowremoved", this, index, record);
7073 onAdd : function(ds, records, rowIndex)
7075 //Roo.log('on Add called');
7076 // - note this does not handle multiple adding very well..
7077 var bt = this.mainBody.dom;
7078 for (var i =0 ; i < records.length;i++) {
7079 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
7080 //Roo.log(records[i]);
7081 //Roo.log(this.store.getAt(rowIndex+i));
7082 this.insertRow(this.store, rowIndex + i, false);
7089 refreshRow : function(record){
7090 var ds = this.store, index;
7091 if(typeof record == 'number'){
7093 record = ds.getAt(index);
7095 index = ds.indexOf(record);
7097 this.insertRow(ds, index, true);
7099 this.onRemove(ds, record, index+1, true);
7101 //this.syncRowHeights(index, index);
7103 this.fireEvent("rowupdated", this, index, record);
7106 insertRow : function(dm, rowIndex, isUpdate){
7109 this.fireEvent("beforerowsinserted", this, rowIndex);
7111 //var s = this.getScrollState();
7112 var row = this.renderRow(this.cm, this.store, rowIndex);
7113 // insert before rowIndex..
7114 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
7118 if(row.cellObjects.length){
7119 Roo.each(row.cellObjects, function(r){
7120 _this.renderCellObject(r);
7125 this.fireEvent("rowsinserted", this, rowIndex);
7126 //this.syncRowHeights(firstRow, lastRow);
7127 //this.stripeRows(firstRow);
7134 getRowDom : function(rowIndex)
7136 var rows = this.el.select('tbody > tr', true).elements;
7138 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
7141 // returns the object tree for a tr..
7144 renderRow : function(cm, ds, rowIndex)
7146 var d = ds.getAt(rowIndex);
7150 cls : 'x-row-' + rowIndex,
7154 var cellObjects = [];
7156 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
7157 var config = cm.config[i];
7159 var renderer = cm.getRenderer(i);
7163 if(typeof(renderer) !== 'undefined'){
7164 value = renderer(d.data[cm.getDataIndex(i)], false, d);
7166 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
7167 // and are rendered into the cells after the row is rendered - using the id for the element.
7169 if(typeof(value) === 'object'){
7179 rowIndex : rowIndex,
7184 this.fireEvent('rowclass', this, rowcfg);
7188 cls : rowcfg.rowClass + ' x-col-' + i,
7190 html: (typeof(value) === 'object') ? '' : value
7197 if(typeof(config.colspan) != 'undefined'){
7198 td.colspan = config.colspan;
7201 if(typeof(config.hidden) != 'undefined' && config.hidden){
7202 td.style += ' display:none;';
7205 if(typeof(config.align) != 'undefined' && config.align.length){
7206 td.style += ' text-align:' + config.align + ';';
7208 if(typeof(config.valign) != 'undefined' && config.valign.length){
7209 td.style += ' vertical-align:' + config.valign + ';';
7212 if(typeof(config.width) != 'undefined'){
7213 td.style += ' width:' + config.width + 'px;';
7216 if(typeof(config.cursor) != 'undefined'){
7217 td.style += ' cursor:' + config.cursor + ';';
7220 if(typeof(config.cls) != 'undefined'){
7221 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
7224 ['xs','sm','md','lg'].map(function(size){
7226 if(typeof(config[size]) == 'undefined'){
7232 if (!config[size]) { // 0 = hidden
7233 // BS 4 '0' is treated as hide that column and below.
7234 td.cls += ' hidden-' + size + ' hidden' + size + '-down';
7238 td.cls += ' col-' + size + '-' + config[size] + (
7239 size == 'xs' ? (' col-' + config[size] ) : '' // bs4 col-{num} replaces col-xs
7249 row.cellObjects = cellObjects;
7257 onBeforeLoad : function()
7266 this.el.select('tbody', true).first().dom.innerHTML = '';
7269 * Show or hide a row.
7270 * @param {Number} rowIndex to show or hide
7271 * @param {Boolean} state hide
7273 setRowVisibility : function(rowIndex, state)
7275 var bt = this.mainBody.dom;
7277 var rows = this.el.select('tbody > tr', true).elements;
7279 if(typeof(rows[rowIndex]) == 'undefined'){
7282 rows[rowIndex].dom.style.display = state ? '' : 'none';
7286 getSelectionModel : function(){
7288 this.selModel = new Roo.bootstrap.Table.RowSelectionModel({grid: this});
7290 return this.selModel;
7293 * Render the Roo.bootstrap object from renderder
7295 renderCellObject : function(r)
7299 r.cfg.parentId = (typeof(r.container) == 'string') ? r.container : r.container.id;
7301 var t = r.cfg.render(r.container);
7304 Roo.each(r.cfg.cn, function(c){
7306 container: t.getChildContainer(),
7309 _this.renderCellObject(child);
7314 getRowIndex : function(row)
7318 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
7329 * Returns the grid's underlying element = used by panel.Grid
7330 * @return {Element} The element
7332 getGridEl : function(){
7336 * Forces a resize - used by panel.Grid
7337 * @return {Element} The element
7339 autoSize : function()
7341 //var ctr = Roo.get(this.container.dom.parentElement);
7342 var ctr = Roo.get(this.el.dom);
7344 var thd = this.getGridEl().select('thead',true).first();
7345 var tbd = this.getGridEl().select('tbody', true).first();
7346 var tfd = this.getGridEl().select('tfoot', true).first();
7348 var cw = ctr.getWidth();
7352 tbd.setSize(ctr.getWidth(),
7353 ctr.getHeight() - ((thd ? thd.getHeight() : 0) + (tfd ? tfd.getHeight() : 0))
7355 var barsize = (tbd.dom.offsetWidth - tbd.dom.clientWidth);
7358 cw = Math.max(cw, this.totalWidth);
7359 this.getGridEl().select('tr',true).setWidth(cw);
7360 // resize 'expandable coloumn?
7362 return; // we doe not have a view in this design..
7365 onBodyScroll: function()
7367 //Roo.log("body scrolled');" + this.mainBody.dom.scrollLeft);
7369 this.mainHead.setStyle({
7370 'position' : 'relative',
7371 'left': (-1* this.mainBody.dom.scrollLeft) + 'px'
7377 var scrollHeight = this.mainBody.dom.scrollHeight;
7379 var scrollTop = Math.ceil(this.mainBody.getScroll().top);
7381 var height = this.mainBody.getHeight();
7383 if(scrollHeight - height == scrollTop) {
7385 var total = this.ds.getTotalCount();
7387 if(this.footer.cursor + this.footer.pageSize < total){
7389 this.footer.ds.load({
7391 start : this.footer.cursor + this.footer.pageSize,
7392 limit : this.footer.pageSize
7402 onHeaderChange : function()
7404 var header = this.renderHeader();
7405 var table = this.el.select('table', true).first();
7407 this.mainHead.remove();
7408 this.mainHead = table.createChild(header, this.mainBody, false);
7411 onHiddenChange : function(colModel, colIndex, hidden)
7413 var thSelector = '#' + this.id + ' .x-hcol-' + colIndex;
7414 var tdSelector = '#' + this.id + ' .x-col-' + colIndex;
7416 this.CSS.updateRule(thSelector, "display", "");
7417 this.CSS.updateRule(tdSelector, "display", "");
7420 this.CSS.updateRule(thSelector, "display", "none");
7421 this.CSS.updateRule(tdSelector, "display", "none");
7424 this.onHeaderChange();
7428 setColumnWidth: function(col_index, width)
7430 // width = "md-2 xs-2..."
7431 if(!this.colModel.config[col_index]) {
7435 var w = width.split(" ");
7437 var rows = this.el.dom.getElementsByClassName("x-col-"+col_index);
7439 var h_row = this.el.dom.getElementsByClassName("x-hcol-"+col_index);
7442 for(var j = 0; j < w.length; j++) {
7448 var size_cls = w[j].split("-");
7450 if(!Number.isInteger(size_cls[1] * 1)) {
7454 if(!this.colModel.config[col_index][size_cls[0]]) {
7458 if(!h_row[0].classList.contains("col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]])) {
7462 h_row[0].classList.replace(
7463 "col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]],
7464 "col-"+size_cls[0]+"-"+size_cls[1]
7467 for(var i = 0; i < rows.length; i++) {
7469 var size_cls = w[j].split("-");
7471 if(!Number.isInteger(size_cls[1] * 1)) {
7475 if(!this.colModel.config[col_index][size_cls[0]]) {
7479 if(!rows[i].classList.contains("col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]])) {
7483 rows[i].classList.replace(
7484 "col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]],
7485 "col-"+size_cls[0]+"-"+size_cls[1]
7489 this.colModel.config[col_index][size_cls[0]] = size_cls[1];
7504 * @class Roo.bootstrap.TableCell
7505 * @extends Roo.bootstrap.Component
7506 * Bootstrap TableCell class
7507 * @cfg {String} html cell contain text
7508 * @cfg {String} cls cell class
7509 * @cfg {String} tag cell tag (td|th) default td
7510 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
7511 * @cfg {String} align Aligns the content in a cell
7512 * @cfg {String} axis Categorizes cells
7513 * @cfg {String} bgcolor Specifies the background color of a cell
7514 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7515 * @cfg {Number} colspan Specifies the number of columns a cell should span
7516 * @cfg {String} headers Specifies one or more header cells a cell is related to
7517 * @cfg {Number} height Sets the height of a cell
7518 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
7519 * @cfg {Number} rowspan Sets the number of rows a cell should span
7520 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
7521 * @cfg {String} valign Vertical aligns the content in a cell
7522 * @cfg {Number} width Specifies the width of a cell
7525 * Create a new TableCell
7526 * @param {Object} config The config object
7529 Roo.bootstrap.TableCell = function(config){
7530 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
7533 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
7553 getAutoCreate : function(){
7554 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
7574 cfg.align=this.align
7580 cfg.bgcolor=this.bgcolor
7583 cfg.charoff=this.charoff
7586 cfg.colspan=this.colspan
7589 cfg.headers=this.headers
7592 cfg.height=this.height
7595 cfg.nowrap=this.nowrap
7598 cfg.rowspan=this.rowspan
7601 cfg.scope=this.scope
7604 cfg.valign=this.valign
7607 cfg.width=this.width
7626 * @class Roo.bootstrap.TableRow
7627 * @extends Roo.bootstrap.Component
7628 * Bootstrap TableRow class
7629 * @cfg {String} cls row class
7630 * @cfg {String} align Aligns the content in a table row
7631 * @cfg {String} bgcolor Specifies a background color for a table row
7632 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7633 * @cfg {String} valign Vertical aligns the content in a table row
7636 * Create a new TableRow
7637 * @param {Object} config The config object
7640 Roo.bootstrap.TableRow = function(config){
7641 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
7644 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
7652 getAutoCreate : function(){
7653 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
7663 cfg.align = this.align;
7666 cfg.bgcolor = this.bgcolor;
7669 cfg.charoff = this.charoff;
7672 cfg.valign = this.valign;
7690 * @class Roo.bootstrap.TableBody
7691 * @extends Roo.bootstrap.Component
7692 * Bootstrap TableBody class
7693 * @cfg {String} cls element class
7694 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
7695 * @cfg {String} align Aligns the content inside the element
7696 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
7697 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
7700 * Create a new TableBody
7701 * @param {Object} config The config object
7704 Roo.bootstrap.TableBody = function(config){
7705 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
7708 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
7716 getAutoCreate : function(){
7717 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
7731 cfg.align = this.align;
7734 cfg.charoff = this.charoff;
7737 cfg.valign = this.valign;
7744 // initEvents : function()
7751 // this.store = Roo.factory(this.store, Roo.data);
7752 // this.store.on('load', this.onLoad, this);
7754 // this.store.load();
7758 // onLoad: function ()
7760 // this.fireEvent('load', this);
7770 * Ext JS Library 1.1.1
7771 * Copyright(c) 2006-2007, Ext JS, LLC.
7773 * Originally Released Under LGPL - original licence link has changed is not relivant.
7776 * <script type="text/javascript">
7779 // as we use this in bootstrap.
7780 Roo.namespace('Roo.form');
7782 * @class Roo.form.Action
7783 * Internal Class used to handle form actions
7785 * @param {Roo.form.BasicForm} el The form element or its id
7786 * @param {Object} config Configuration options
7791 // define the action interface
7792 Roo.form.Action = function(form, options){
7794 this.options = options || {};
7797 * Client Validation Failed
7800 Roo.form.Action.CLIENT_INVALID = 'client';
7802 * Server Validation Failed
7805 Roo.form.Action.SERVER_INVALID = 'server';
7807 * Connect to Server Failed
7810 Roo.form.Action.CONNECT_FAILURE = 'connect';
7812 * Reading Data from Server Failed
7815 Roo.form.Action.LOAD_FAILURE = 'load';
7817 Roo.form.Action.prototype = {
7819 failureType : undefined,
7820 response : undefined,
7824 run : function(options){
7829 success : function(response){
7834 handleResponse : function(response){
7838 // default connection failure
7839 failure : function(response){
7841 this.response = response;
7842 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7843 this.form.afterAction(this, false);
7846 processResponse : function(response){
7847 this.response = response;
7848 if(!response.responseText){
7851 this.result = this.handleResponse(response);
7855 // utility functions used internally
7856 getUrl : function(appendParams){
7857 var url = this.options.url || this.form.url || this.form.el.dom.action;
7859 var p = this.getParams();
7861 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
7867 getMethod : function(){
7868 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
7871 getParams : function(){
7872 var bp = this.form.baseParams;
7873 var p = this.options.params;
7875 if(typeof p == "object"){
7876 p = Roo.urlEncode(Roo.applyIf(p, bp));
7877 }else if(typeof p == 'string' && bp){
7878 p += '&' + Roo.urlEncode(bp);
7881 p = Roo.urlEncode(bp);
7886 createCallback : function(){
7888 success: this.success,
7889 failure: this.failure,
7891 timeout: (this.form.timeout*1000),
7892 upload: this.form.fileUpload ? this.success : undefined
7897 Roo.form.Action.Submit = function(form, options){
7898 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
7901 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
7904 haveProgress : false,
7905 uploadComplete : false,
7907 // uploadProgress indicator.
7908 uploadProgress : function()
7910 if (!this.form.progressUrl) {
7914 if (!this.haveProgress) {
7915 Roo.MessageBox.progress("Uploading", "Uploading");
7917 if (this.uploadComplete) {
7918 Roo.MessageBox.hide();
7922 this.haveProgress = true;
7924 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
7926 var c = new Roo.data.Connection();
7928 url : this.form.progressUrl,
7933 success : function(req){
7934 //console.log(data);
7938 rdata = Roo.decode(req.responseText)
7940 Roo.log("Invalid data from server..");
7944 if (!rdata || !rdata.success) {
7946 Roo.MessageBox.alert(Roo.encode(rdata));
7949 var data = rdata.data;
7951 if (this.uploadComplete) {
7952 Roo.MessageBox.hide();
7957 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
7958 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
7961 this.uploadProgress.defer(2000,this);
7964 failure: function(data) {
7965 Roo.log('progress url failed ');
7976 // run get Values on the form, so it syncs any secondary forms.
7977 this.form.getValues();
7979 var o = this.options;
7980 var method = this.getMethod();
7981 var isPost = method == 'POST';
7982 if(o.clientValidation === false || this.form.isValid()){
7984 if (this.form.progressUrl) {
7985 this.form.findField('UPLOAD_IDENTIFIER').setValue(
7986 (new Date() * 1) + '' + Math.random());
7991 Roo.Ajax.request(Roo.apply(this.createCallback(), {
7992 form:this.form.el.dom,
7993 url:this.getUrl(!isPost),
7995 params:isPost ? this.getParams() : null,
7996 isUpload: this.form.fileUpload,
7997 formData : this.form.formData
8000 this.uploadProgress();
8002 }else if (o.clientValidation !== false){ // client validation failed
8003 this.failureType = Roo.form.Action.CLIENT_INVALID;
8004 this.form.afterAction(this, false);
8008 success : function(response)
8010 this.uploadComplete= true;
8011 if (this.haveProgress) {
8012 Roo.MessageBox.hide();
8016 var result = this.processResponse(response);
8017 if(result === true || result.success){
8018 this.form.afterAction(this, true);
8022 this.form.markInvalid(result.errors);
8023 this.failureType = Roo.form.Action.SERVER_INVALID;
8025 this.form.afterAction(this, false);
8027 failure : function(response)
8029 this.uploadComplete= true;
8030 if (this.haveProgress) {
8031 Roo.MessageBox.hide();
8034 this.response = response;
8035 this.failureType = Roo.form.Action.CONNECT_FAILURE;
8036 this.form.afterAction(this, false);
8039 handleResponse : function(response){
8040 if(this.form.errorReader){
8041 var rs = this.form.errorReader.read(response);
8044 for(var i = 0, len = rs.records.length; i < len; i++) {
8045 var r = rs.records[i];
8049 if(errors.length < 1){
8053 success : rs.success,
8059 ret = Roo.decode(response.responseText);
8063 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
8073 Roo.form.Action.Load = function(form, options){
8074 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
8075 this.reader = this.form.reader;
8078 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
8083 Roo.Ajax.request(Roo.apply(
8084 this.createCallback(), {
8085 method:this.getMethod(),
8086 url:this.getUrl(false),
8087 params:this.getParams()
8091 success : function(response){
8093 var result = this.processResponse(response);
8094 if(result === true || !result.success || !result.data){
8095 this.failureType = Roo.form.Action.LOAD_FAILURE;
8096 this.form.afterAction(this, false);
8099 this.form.clearInvalid();
8100 this.form.setValues(result.data);
8101 this.form.afterAction(this, true);
8104 handleResponse : function(response){
8105 if(this.form.reader){
8106 var rs = this.form.reader.read(response);
8107 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
8109 success : rs.success,
8113 return Roo.decode(response.responseText);
8117 Roo.form.Action.ACTION_TYPES = {
8118 'load' : Roo.form.Action.Load,
8119 'submit' : Roo.form.Action.Submit
8128 * @class Roo.bootstrap.Form
8129 * @extends Roo.bootstrap.Component
8130 * Bootstrap Form class
8131 * @cfg {String} method GET | POST (default POST)
8132 * @cfg {String} labelAlign top | left (default top)
8133 * @cfg {String} align left | right - for navbars
8134 * @cfg {Boolean} loadMask load mask when submit (default true)
8139 * @param {Object} config The config object
8143 Roo.bootstrap.Form = function(config){
8145 Roo.bootstrap.Form.superclass.constructor.call(this, config);
8147 Roo.bootstrap.Form.popover.apply();
8151 * @event clientvalidation
8152 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
8153 * @param {Form} this
8154 * @param {Boolean} valid true if the form has passed client-side validation
8156 clientvalidation: true,
8158 * @event beforeaction
8159 * Fires before any action is performed. Return false to cancel the action.
8160 * @param {Form} this
8161 * @param {Action} action The action to be performed
8165 * @event actionfailed
8166 * Fires when an action fails.
8167 * @param {Form} this
8168 * @param {Action} action The action that failed
8170 actionfailed : true,
8172 * @event actioncomplete
8173 * Fires when an action is completed.
8174 * @param {Form} this
8175 * @param {Action} action The action that completed
8177 actioncomplete : true
8181 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
8184 * @cfg {String} method
8185 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
8190 * The URL to use for form actions if one isn't supplied in the action options.
8193 * @cfg {Boolean} fileUpload
8194 * Set to true if this form is a file upload.
8198 * @cfg {Object} baseParams
8199 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
8203 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
8207 * @cfg {Sting} align (left|right) for navbar forms
8212 activeAction : null,
8215 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
8216 * element by passing it or its id or mask the form itself by passing in true.
8219 waitMsgTarget : false,
8224 * @cfg {Boolean} errorMask (true|false) default false
8229 * @cfg {Number} maskOffset Default 100
8234 * @cfg {Boolean} maskBody
8238 getAutoCreate : function(){
8242 method : this.method || 'POST',
8243 id : this.id || Roo.id(),
8246 if (this.parent().xtype.match(/^Nav/)) {
8247 cfg.cls = 'navbar-form form-inline navbar-' + this.align;
8251 if (this.labelAlign == 'left' ) {
8252 cfg.cls += ' form-horizontal';
8258 initEvents : function()
8260 this.el.on('submit', this.onSubmit, this);
8261 // this was added as random key presses on the form where triggering form submit.
8262 this.el.on('keypress', function(e) {
8263 if (e.getCharCode() != 13) {
8266 // we might need to allow it for textareas.. and some other items.
8267 // check e.getTarget().
8269 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
8273 Roo.log("keypress blocked");
8281 onSubmit : function(e){
8286 * Returns true if client-side validation on the form is successful.
8289 isValid : function(){
8290 var items = this.getItems();
8294 items.each(function(f){
8300 Roo.log('invalid field: ' + f.name);
8304 if(!target && f.el.isVisible(true)){
8310 if(this.errorMask && !valid){
8311 Roo.bootstrap.Form.popover.mask(this, target);
8318 * Returns true if any fields in this form have changed since their original load.
8321 isDirty : function(){
8323 var items = this.getItems();
8324 items.each(function(f){
8334 * Performs a predefined action (submit or load) or custom actions you define on this form.
8335 * @param {String} actionName The name of the action type
8336 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
8337 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
8338 * accept other config options):
8340 Property Type Description
8341 ---------------- --------------- ----------------------------------------------------------------------------------
8342 url String The url for the action (defaults to the form's url)
8343 method String The form method to use (defaults to the form's method, or POST if not defined)
8344 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
8345 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
8346 validate the form on the client (defaults to false)
8348 * @return {BasicForm} this
8350 doAction : function(action, options){
8351 if(typeof action == 'string'){
8352 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
8354 if(this.fireEvent('beforeaction', this, action) !== false){
8355 this.beforeAction(action);
8356 action.run.defer(100, action);
8362 beforeAction : function(action){
8363 var o = action.options;
8368 Roo.get(document.body).mask(o.waitMsg || "Sending", 'x-mask-loading')
8370 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
8373 // not really supported yet.. ??
8375 //if(this.waitMsgTarget === true){
8376 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
8377 //}else if(this.waitMsgTarget){
8378 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
8379 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
8381 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
8387 afterAction : function(action, success){
8388 this.activeAction = null;
8389 var o = action.options;
8394 Roo.get(document.body).unmask();
8400 //if(this.waitMsgTarget === true){
8401 // this.el.unmask();
8402 //}else if(this.waitMsgTarget){
8403 // this.waitMsgTarget.unmask();
8405 // Roo.MessageBox.updateProgress(1);
8406 // Roo.MessageBox.hide();
8413 Roo.callback(o.success, o.scope, [this, action]);
8414 this.fireEvent('actioncomplete', this, action);
8418 // failure condition..
8419 // we have a scenario where updates need confirming.
8420 // eg. if a locking scenario exists..
8421 // we look for { errors : { needs_confirm : true }} in the response.
8423 (typeof(action.result) != 'undefined') &&
8424 (typeof(action.result.errors) != 'undefined') &&
8425 (typeof(action.result.errors.needs_confirm) != 'undefined')
8428 Roo.log("not supported yet");
8431 Roo.MessageBox.confirm(
8432 "Change requires confirmation",
8433 action.result.errorMsg,
8438 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
8448 Roo.callback(o.failure, o.scope, [this, action]);
8449 // show an error message if no failed handler is set..
8450 if (!this.hasListener('actionfailed')) {
8451 Roo.log("need to add dialog support");
8453 Roo.MessageBox.alert("Error",
8454 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
8455 action.result.errorMsg :
8456 "Saving Failed, please check your entries or try again"
8461 this.fireEvent('actionfailed', this, action);
8466 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
8467 * @param {String} id The value to search for
8470 findField : function(id){
8471 var items = this.getItems();
8472 var field = items.get(id);
8474 items.each(function(f){
8475 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
8482 return field || null;
8485 * Mark fields in this form invalid in bulk.
8486 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
8487 * @return {BasicForm} this
8489 markInvalid : function(errors){
8490 if(errors instanceof Array){
8491 for(var i = 0, len = errors.length; i < len; i++){
8492 var fieldError = errors[i];
8493 var f = this.findField(fieldError.id);
8495 f.markInvalid(fieldError.msg);
8501 if(typeof errors[id] != 'function' && (field = this.findField(id))){
8502 field.markInvalid(errors[id]);
8506 //Roo.each(this.childForms || [], function (f) {
8507 // f.markInvalid(errors);
8514 * Set values for fields in this form in bulk.
8515 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
8516 * @return {BasicForm} this
8518 setValues : function(values){
8519 if(values instanceof Array){ // array of objects
8520 for(var i = 0, len = values.length; i < len; i++){
8522 var f = this.findField(v.id);
8524 f.setValue(v.value);
8525 if(this.trackResetOnLoad){
8526 f.originalValue = f.getValue();
8530 }else{ // object hash
8533 if(typeof values[id] != 'function' && (field = this.findField(id))){
8535 if (field.setFromData &&
8537 field.displayField &&
8538 // combos' with local stores can
8539 // be queried via setValue()
8540 // to set their value..
8541 (field.store && !field.store.isLocal)
8545 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
8546 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
8547 field.setFromData(sd);
8549 } else if(field.setFromData && (field.store && !field.store.isLocal)) {
8551 field.setFromData(values);
8554 field.setValue(values[id]);
8558 if(this.trackResetOnLoad){
8559 field.originalValue = field.getValue();
8565 //Roo.each(this.childForms || [], function (f) {
8566 // f.setValues(values);
8573 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
8574 * they are returned as an array.
8575 * @param {Boolean} asString
8578 getValues : function(asString){
8579 //if (this.childForms) {
8580 // copy values from the child forms
8581 // Roo.each(this.childForms, function (f) {
8582 // this.setValues(f.getValues());
8588 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
8589 if(asString === true){
8592 return Roo.urlDecode(fs);
8596 * Returns the fields in this form as an object with key/value pairs.
8597 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
8600 getFieldValues : function(with_hidden)
8602 var items = this.getItems();
8604 items.each(function(f){
8610 var v = f.getValue();
8612 if (f.inputType =='radio') {
8613 if (typeof(ret[f.getName()]) == 'undefined') {
8614 ret[f.getName()] = ''; // empty..
8617 if (!f.el.dom.checked) {
8625 if(f.xtype == 'MoneyField'){
8626 ret[f.currencyName] = f.getCurrency();
8629 // not sure if this supported any more..
8630 if ((typeof(v) == 'object') && f.getRawValue) {
8631 v = f.getRawValue() ; // dates..
8633 // combo boxes where name != hiddenName...
8634 if (f.name !== false && f.name != '' && f.name != f.getName()) {
8635 ret[f.name] = f.getRawValue();
8637 ret[f.getName()] = v;
8644 * Clears all invalid messages in this form.
8645 * @return {BasicForm} this
8647 clearInvalid : function(){
8648 var items = this.getItems();
8650 items.each(function(f){
8659 * @return {BasicForm} this
8662 var items = this.getItems();
8663 items.each(function(f){
8667 Roo.each(this.childForms || [], function (f) {
8675 getItems : function()
8677 var r=new Roo.util.MixedCollection(false, function(o){
8678 return o.id || (o.id = Roo.id());
8680 var iter = function(el) {
8687 Roo.each(el.items,function(e) {
8696 hideFields : function(items)
8698 Roo.each(items, function(i){
8700 var f = this.findField(i);
8711 showFields : function(items)
8713 Roo.each(items, function(i){
8715 var f = this.findField(i);
8728 Roo.apply(Roo.bootstrap.Form, {
8755 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
8756 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
8757 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
8758 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
8761 this.maskEl.top.enableDisplayMode("block");
8762 this.maskEl.left.enableDisplayMode("block");
8763 this.maskEl.bottom.enableDisplayMode("block");
8764 this.maskEl.right.enableDisplayMode("block");
8766 this.toolTip = new Roo.bootstrap.Tooltip({
8767 cls : 'roo-form-error-popover',
8769 'left' : ['r-l', [-2,0], 'right'],
8770 'right' : ['l-r', [2,0], 'left'],
8771 'bottom' : ['tl-bl', [0,2], 'top'],
8772 'top' : [ 'bl-tl', [0,-2], 'bottom']
8776 this.toolTip.render(Roo.get(document.body));
8778 this.toolTip.el.enableDisplayMode("block");
8780 Roo.get(document.body).on('click', function(){
8784 Roo.get(document.body).on('touchstart', function(){
8788 this.isApplied = true
8791 mask : function(form, target)
8795 this.target = target;
8797 if(!this.form.errorMask || !target.el){
8801 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.modal', 100, true) || Roo.get(document.body);
8803 Roo.log(scrollable);
8805 var ot = this.target.el.calcOffsetsTo(scrollable);
8807 var scrollTo = ot[1] - this.form.maskOffset;
8809 scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
8811 scrollable.scrollTo('top', scrollTo);
8813 var box = this.target.el.getBox();
8815 var zIndex = Roo.bootstrap.Modal.zIndex++;
8818 this.maskEl.top.setStyle('position', 'absolute');
8819 this.maskEl.top.setStyle('z-index', zIndex);
8820 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
8821 this.maskEl.top.setLeft(0);
8822 this.maskEl.top.setTop(0);
8823 this.maskEl.top.show();
8825 this.maskEl.left.setStyle('position', 'absolute');
8826 this.maskEl.left.setStyle('z-index', zIndex);
8827 this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
8828 this.maskEl.left.setLeft(0);
8829 this.maskEl.left.setTop(box.y - this.padding);
8830 this.maskEl.left.show();
8832 this.maskEl.bottom.setStyle('position', 'absolute');
8833 this.maskEl.bottom.setStyle('z-index', zIndex);
8834 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
8835 this.maskEl.bottom.setLeft(0);
8836 this.maskEl.bottom.setTop(box.bottom + this.padding);
8837 this.maskEl.bottom.show();
8839 this.maskEl.right.setStyle('position', 'absolute');
8840 this.maskEl.right.setStyle('z-index', zIndex);
8841 this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
8842 this.maskEl.right.setLeft(box.right + this.padding);
8843 this.maskEl.right.setTop(box.y - this.padding);
8844 this.maskEl.right.show();
8846 this.toolTip.bindEl = this.target.el;
8848 this.toolTip.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
8850 var tip = this.target.blankText;
8852 if(this.target.getValue() !== '' ) {
8854 if (this.target.invalidText.length) {
8855 tip = this.target.invalidText;
8856 } else if (this.target.regexText.length){
8857 tip = this.target.regexText;
8861 this.toolTip.show(tip);
8863 this.intervalID = window.setInterval(function() {
8864 Roo.bootstrap.Form.popover.unmask();
8867 window.onwheel = function(){ return false;};
8869 (function(){ this.isMasked = true; }).defer(500, this);
8875 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
8879 this.maskEl.top.setStyle('position', 'absolute');
8880 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
8881 this.maskEl.top.hide();
8883 this.maskEl.left.setStyle('position', 'absolute');
8884 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
8885 this.maskEl.left.hide();
8887 this.maskEl.bottom.setStyle('position', 'absolute');
8888 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
8889 this.maskEl.bottom.hide();
8891 this.maskEl.right.setStyle('position', 'absolute');
8892 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
8893 this.maskEl.right.hide();
8895 this.toolTip.hide();
8897 this.toolTip.el.hide();
8899 window.onwheel = function(){ return true;};
8901 if(this.intervalID){
8902 window.clearInterval(this.intervalID);
8903 this.intervalID = false;
8906 this.isMasked = false;
8916 * Ext JS Library 1.1.1
8917 * Copyright(c) 2006-2007, Ext JS, LLC.
8919 * Originally Released Under LGPL - original licence link has changed is not relivant.
8922 * <script type="text/javascript">
8925 * @class Roo.form.VTypes
8926 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
8929 Roo.form.VTypes = function(){
8930 // closure these in so they are only created once.
8931 var alpha = /^[a-zA-Z_]+$/;
8932 var alphanum = /^[a-zA-Z0-9_]+$/;
8933 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
8934 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
8936 // All these messages and functions are configurable
8939 * The function used to validate email addresses
8940 * @param {String} value The email address
8942 'email' : function(v){
8943 return email.test(v);
8946 * The error text to display when the email validation function returns false
8949 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
8951 * The keystroke filter mask to be applied on email input
8954 'emailMask' : /[a-z0-9_\.\-@]/i,
8957 * The function used to validate URLs
8958 * @param {String} value The URL
8960 'url' : function(v){
8964 * The error text to display when the url validation function returns false
8967 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
8970 * The function used to validate alpha values
8971 * @param {String} value The value
8973 'alpha' : function(v){
8974 return alpha.test(v);
8977 * The error text to display when the alpha validation function returns false
8980 'alphaText' : 'This field should only contain letters and _',
8982 * The keystroke filter mask to be applied on alpha input
8985 'alphaMask' : /[a-z_]/i,
8988 * The function used to validate alphanumeric values
8989 * @param {String} value The value
8991 'alphanum' : function(v){
8992 return alphanum.test(v);
8995 * The error text to display when the alphanumeric validation function returns false
8998 'alphanumText' : 'This field should only contain letters, numbers and _',
9000 * The keystroke filter mask to be applied on alphanumeric input
9003 'alphanumMask' : /[a-z0-9_]/i
9013 * @class Roo.bootstrap.Input
9014 * @extends Roo.bootstrap.Component
9015 * Bootstrap Input class
9016 * @cfg {Boolean} disabled is it disabled
9017 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
9018 * @cfg {String} name name of the input
9019 * @cfg {string} fieldLabel - the label associated
9020 * @cfg {string} placeholder - placeholder to put in text.
9021 * @cfg {string} before - input group add on before
9022 * @cfg {string} after - input group add on after
9023 * @cfg {string} size - (lg|sm) or leave empty..
9024 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
9025 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
9026 * @cfg {Number} md colspan out of 12 for computer-sized screens
9027 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
9028 * @cfg {string} value default value of the input
9029 * @cfg {Number} labelWidth set the width of label
9030 * @cfg {Number} labellg set the width of label (1-12)
9031 * @cfg {Number} labelmd set the width of label (1-12)
9032 * @cfg {Number} labelsm set the width of label (1-12)
9033 * @cfg {Number} labelxs set the width of label (1-12)
9034 * @cfg {String} labelAlign (top|left)
9035 * @cfg {Boolean} readOnly Specifies that the field should be read-only
9036 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
9037 * @cfg {String} indicatorpos (left|right) default left
9038 * @cfg {String} capture (user|camera) use for file input only. (default empty)
9039 * @cfg {String} accept (image|video|audio) use for file input only. (default empty)
9041 * @cfg {String} align (left|center|right) Default left
9042 * @cfg {Boolean} forceFeedback (true|false) Default false
9045 * Create a new Input
9046 * @param {Object} config The config object
9049 Roo.bootstrap.Input = function(config){
9051 Roo.bootstrap.Input.superclass.constructor.call(this, config);
9056 * Fires when this field receives input focus.
9057 * @param {Roo.form.Field} this
9062 * Fires when this field loses input focus.
9063 * @param {Roo.form.Field} this
9068 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
9069 * {@link Roo.EventObject#getKey} to determine which key was pressed.
9070 * @param {Roo.form.Field} this
9071 * @param {Roo.EventObject} e The event object
9076 * Fires just before the field blurs if the field value has changed.
9077 * @param {Roo.form.Field} this
9078 * @param {Mixed} newValue The new value
9079 * @param {Mixed} oldValue The original value
9084 * Fires after the field has been marked as invalid.
9085 * @param {Roo.form.Field} this
9086 * @param {String} msg The validation message
9091 * Fires after the field has been validated with no errors.
9092 * @param {Roo.form.Field} this
9097 * Fires after the key up
9098 * @param {Roo.form.Field} this
9099 * @param {Roo.EventObject} e The event Object
9105 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
9107 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
9108 automatic validation (defaults to "keyup").
9110 validationEvent : "keyup",
9112 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
9114 validateOnBlur : true,
9116 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
9118 validationDelay : 250,
9120 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
9122 focusClass : "x-form-focus", // not needed???
9126 * @cfg {String} invalidClass DEPRICATED - code uses BS4 - is-valid / is-invalid
9128 invalidClass : "has-warning",
9131 * @cfg {String} validClass DEPRICATED - code uses BS4 - is-valid / is-invalid
9133 validClass : "has-success",
9136 * @cfg {Boolean} hasFeedback (true|false) default true
9141 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
9143 invalidFeedbackClass : "glyphicon-warning-sign",
9146 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
9148 validFeedbackClass : "glyphicon-ok",
9151 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
9153 selectOnFocus : false,
9156 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
9160 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
9165 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
9167 disableKeyFilter : false,
9170 * @cfg {Boolean} disabled True to disable the field (defaults to false).
9174 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
9178 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
9180 blankText : "Please complete this mandatory field",
9183 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
9187 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
9189 maxLength : Number.MAX_VALUE,
9191 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
9193 minLengthText : "The minimum length for this field is {0}",
9195 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
9197 maxLengthText : "The maximum length for this field is {0}",
9201 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
9202 * If available, this function will be called only after the basic validators all return true, and will be passed the
9203 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
9207 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
9208 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
9209 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
9213 * @cfg {String} regexText -- Depricated - use Invalid Text
9218 * @cfg {String} invalidText The error text to display if {@link #validator} test fails during validation (defaults to "")
9224 autocomplete: false,
9243 formatedValue : false,
9244 forceFeedback : false,
9246 indicatorpos : 'left',
9256 parentLabelAlign : function()
9259 while (parent.parent()) {
9260 parent = parent.parent();
9261 if (typeof(parent.labelAlign) !='undefined') {
9262 return parent.labelAlign;
9269 getAutoCreate : function()
9271 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9277 if(this.inputType != 'hidden'){
9278 cfg.cls = 'form-group' //input-group
9284 type : this.inputType,
9286 cls : 'form-control',
9287 placeholder : this.placeholder || '',
9288 autocomplete : this.autocomplete || 'new-password'
9291 if(this.capture.length){
9292 input.capture = this.capture;
9295 if(this.accept.length){
9296 input.accept = this.accept + "/*";
9300 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
9303 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9304 input.maxLength = this.maxLength;
9307 if (this.disabled) {
9308 input.disabled=true;
9311 if (this.readOnly) {
9312 input.readonly=true;
9316 input.name = this.name;
9320 input.cls += ' input-' + this.size;
9324 ['xs','sm','md','lg'].map(function(size){
9325 if (settings[size]) {
9326 cfg.cls += ' col-' + size + '-' + settings[size];
9330 var inputblock = input;
9334 cls: 'glyphicon form-control-feedback'
9337 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9340 cls : 'has-feedback',
9348 if (this.before || this.after) {
9351 cls : 'input-group',
9355 if (this.before && typeof(this.before) == 'string') {
9357 inputblock.cn.push({
9359 cls : 'roo-input-before input-group-addon input-group-prepend input-group-text',
9363 if (this.before && typeof(this.before) == 'object') {
9364 this.before = Roo.factory(this.before);
9366 inputblock.cn.push({
9368 cls : 'roo-input-before input-group-prepend input-group-text input-group-' +
9369 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
9373 inputblock.cn.push(input);
9375 if (this.after && typeof(this.after) == 'string') {
9376 inputblock.cn.push({
9378 cls : 'roo-input-after input-group-append input-group-text input-group-addon',
9382 if (this.after && typeof(this.after) == 'object') {
9383 this.after = Roo.factory(this.after);
9385 inputblock.cn.push({
9387 cls : 'roo-input-after input-group-append input-group-text input-group-' +
9388 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
9392 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9393 inputblock.cls += ' has-feedback';
9394 inputblock.cn.push(feedback);
9399 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
9400 tooltip : 'This field is required'
9402 if (Roo.bootstrap.version == 4) {
9405 style : 'display-none'
9408 if (align ==='left' && this.fieldLabel.length) {
9410 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
9417 cls : 'control-label col-form-label',
9418 html : this.fieldLabel
9429 var labelCfg = cfg.cn[1];
9430 var contentCfg = cfg.cn[2];
9432 if(this.indicatorpos == 'right'){
9437 cls : 'control-label col-form-label',
9441 html : this.fieldLabel
9455 labelCfg = cfg.cn[0];
9456 contentCfg = cfg.cn[1];
9460 if(this.labelWidth > 12){
9461 labelCfg.style = "width: " + this.labelWidth + 'px';
9464 if(this.labelWidth < 13 && this.labelmd == 0){
9465 this.labelmd = this.labelWidth;
9468 if(this.labellg > 0){
9469 labelCfg.cls += ' col-lg-' + this.labellg;
9470 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
9473 if(this.labelmd > 0){
9474 labelCfg.cls += ' col-md-' + this.labelmd;
9475 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
9478 if(this.labelsm > 0){
9479 labelCfg.cls += ' col-sm-' + this.labelsm;
9480 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
9483 if(this.labelxs > 0){
9484 labelCfg.cls += ' col-xs-' + this.labelxs;
9485 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
9489 } else if ( this.fieldLabel.length) {
9494 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
9495 tooltip : 'This field is required'
9499 //cls : 'input-group-addon',
9500 html : this.fieldLabel
9508 if(this.indicatorpos == 'right'){
9513 //cls : 'input-group-addon',
9514 html : this.fieldLabel
9519 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9520 tooltip : 'This field is required'
9540 if (this.parentType === 'Navbar' && this.parent().bar) {
9541 cfg.cls += ' navbar-form';
9544 if (this.parentType === 'NavGroup' && !(Roo.bootstrap.version == 4 && this.parent().form)) {
9545 // on BS4 we do this only if not form
9546 cfg.cls += ' navbar-form';
9554 * return the real input element.
9556 inputEl: function ()
9558 return this.el.select('input.form-control',true).first();
9561 tooltipEl : function()
9563 return this.inputEl();
9566 indicatorEl : function()
9568 if (Roo.bootstrap.version == 4) {
9569 return false; // not enabled in v4 yet.
9572 var indicator = this.el.select('i.roo-required-indicator',true).first();
9582 setDisabled : function(v)
9584 var i = this.inputEl().dom;
9586 i.removeAttribute('disabled');
9590 i.setAttribute('disabled','true');
9592 initEvents : function()
9595 this.inputEl().on("keydown" , this.fireKey, this);
9596 this.inputEl().on("focus", this.onFocus, this);
9597 this.inputEl().on("blur", this.onBlur, this);
9599 this.inputEl().relayEvent('keyup', this);
9601 this.indicator = this.indicatorEl();
9604 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible'); // changed from invisible??? -
9607 // reference to original value for reset
9608 this.originalValue = this.getValue();
9609 //Roo.form.TextField.superclass.initEvents.call(this);
9610 if(this.validationEvent == 'keyup'){
9611 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
9612 this.inputEl().on('keyup', this.filterValidation, this);
9614 else if(this.validationEvent !== false){
9615 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
9618 if(this.selectOnFocus){
9619 this.on("focus", this.preFocus, this);
9622 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
9623 this.inputEl().on("keypress", this.filterKeys, this);
9625 this.inputEl().relayEvent('keypress', this);
9628 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
9629 this.el.on("click", this.autoSize, this);
9632 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
9633 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
9636 if (typeof(this.before) == 'object') {
9637 this.before.render(this.el.select('.roo-input-before',true).first());
9639 if (typeof(this.after) == 'object') {
9640 this.after.render(this.el.select('.roo-input-after',true).first());
9643 this.inputEl().on('change', this.onChange, this);
9646 filterValidation : function(e){
9647 if(!e.isNavKeyPress()){
9648 this.validationTask.delay(this.validationDelay);
9652 * Validates the field value
9653 * @return {Boolean} True if the value is valid, else false
9655 validate : function(){
9656 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
9657 if(this.disabled || this.validateValue(this.getRawValue())){
9668 * Validates a value according to the field's validation rules and marks the field as invalid
9669 * if the validation fails
9670 * @param {Mixed} value The value to validate
9671 * @return {Boolean} True if the value is valid, else false
9673 validateValue : function(value)
9675 if(this.getVisibilityEl().hasClass('hidden')){
9679 if(value.length < 1) { // if it's blank
9680 if(this.allowBlank){
9686 if(value.length < this.minLength){
9689 if(value.length > this.maxLength){
9693 var vt = Roo.form.VTypes;
9694 if(!vt[this.vtype](value, this)){
9698 if(typeof this.validator == "function"){
9699 var msg = this.validator(value);
9703 if (typeof(msg) == 'string') {
9704 this.invalidText = msg;
9708 if(this.regex && !this.regex.test(value)){
9716 fireKey : function(e){
9717 //Roo.log('field ' + e.getKey());
9718 if(e.isNavKeyPress()){
9719 this.fireEvent("specialkey", this, e);
9722 focus : function (selectText){
9724 this.inputEl().focus();
9725 if(selectText === true){
9726 this.inputEl().dom.select();
9732 onFocus : function(){
9733 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9734 // this.el.addClass(this.focusClass);
9737 this.hasFocus = true;
9738 this.startValue = this.getValue();
9739 this.fireEvent("focus", this);
9743 beforeBlur : Roo.emptyFn,
9747 onBlur : function(){
9749 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9750 //this.el.removeClass(this.focusClass);
9752 this.hasFocus = false;
9753 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
9756 var v = this.getValue();
9757 if(String(v) !== String(this.startValue)){
9758 this.fireEvent('change', this, v, this.startValue);
9760 this.fireEvent("blur", this);
9763 onChange : function(e)
9765 var v = this.getValue();
9766 if(String(v) !== String(this.startValue)){
9767 this.fireEvent('change', this, v, this.startValue);
9773 * Resets the current field value to the originally loaded value and clears any validation messages
9776 this.setValue(this.originalValue);
9780 * Returns the name of the field
9781 * @return {Mixed} name The name field
9783 getName: function(){
9787 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
9788 * @return {Mixed} value The field value
9790 getValue : function(){
9792 var v = this.inputEl().getValue();
9797 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
9798 * @return {Mixed} value The field value
9800 getRawValue : function(){
9801 var v = this.inputEl().getValue();
9807 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
9808 * @param {Mixed} value The value to set
9810 setRawValue : function(v){
9811 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9814 selectText : function(start, end){
9815 var v = this.getRawValue();
9817 start = start === undefined ? 0 : start;
9818 end = end === undefined ? v.length : end;
9819 var d = this.inputEl().dom;
9820 if(d.setSelectionRange){
9821 d.setSelectionRange(start, end);
9822 }else if(d.createTextRange){
9823 var range = d.createTextRange();
9824 range.moveStart("character", start);
9825 range.moveEnd("character", v.length-end);
9832 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
9833 * @param {Mixed} value The value to set
9835 setValue : function(v){
9838 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9844 processValue : function(value){
9845 if(this.stripCharsRe){
9846 var newValue = value.replace(this.stripCharsRe, '');
9847 if(newValue !== value){
9848 this.setRawValue(newValue);
9855 preFocus : function(){
9857 if(this.selectOnFocus){
9858 this.inputEl().dom.select();
9861 filterKeys : function(e){
9863 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
9866 var c = e.getCharCode(), cc = String.fromCharCode(c);
9867 if(Roo.isIE && (e.isSpecialKey() || !cc)){
9870 if(!this.maskRe.test(cc)){
9875 * Clear any invalid styles/messages for this field
9877 clearInvalid : function(){
9879 if(!this.el || this.preventMark){ // not rendered
9884 this.el.removeClass([this.invalidClass, 'is-invalid']);
9886 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9888 var feedback = this.el.select('.form-control-feedback', true).first();
9891 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9897 this.indicator.removeClass('visible');
9898 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9901 this.fireEvent('valid', this);
9905 * Mark this field as valid
9907 markValid : function()
9909 if(!this.el || this.preventMark){ // not rendered...
9913 this.el.removeClass([this.invalidClass, this.validClass]);
9914 this.inputEl().removeClass(['is-valid', 'is-invalid']);
9916 var feedback = this.el.select('.form-control-feedback', true).first();
9919 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9923 this.indicator.removeClass('visible');
9924 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9931 if(this.allowBlank && !this.getRawValue().length){
9934 if (Roo.bootstrap.version == 3) {
9935 this.el.addClass(this.validClass);
9937 this.inputEl().addClass('is-valid');
9940 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9942 var feedback = this.el.select('.form-control-feedback', true).first();
9945 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9946 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9951 this.fireEvent('valid', this);
9955 * Mark this field as invalid
9956 * @param {String} msg The validation message
9958 markInvalid : function(msg)
9960 if(!this.el || this.preventMark){ // not rendered
9964 this.el.removeClass([this.invalidClass, this.validClass]);
9965 this.inputEl().removeClass(['is-valid', 'is-invalid']);
9967 var feedback = this.el.select('.form-control-feedback', true).first();
9970 this.el.select('.form-control-feedback', true).first().removeClass(
9971 [this.invalidFeedbackClass, this.validFeedbackClass]);
9978 if(this.allowBlank && !this.getRawValue().length){
9983 this.indicator.removeClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9984 this.indicator.addClass('visible');
9986 if (Roo.bootstrap.version == 3) {
9987 this.el.addClass(this.invalidClass);
9989 this.inputEl().addClass('is-invalid');
9994 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9996 var feedback = this.el.select('.form-control-feedback', true).first();
9999 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10001 if(this.getValue().length || this.forceFeedback){
10002 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
10009 this.fireEvent('invalid', this, msg);
10012 SafariOnKeyDown : function(event)
10014 // this is a workaround for a password hang bug on chrome/ webkit.
10015 if (this.inputEl().dom.type != 'password') {
10019 var isSelectAll = false;
10021 if(this.inputEl().dom.selectionEnd > 0){
10022 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
10024 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
10025 event.preventDefault();
10030 if(isSelectAll && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
10032 event.preventDefault();
10033 // this is very hacky as keydown always get's upper case.
10035 var cc = String.fromCharCode(event.getCharCode());
10036 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
10040 adjustWidth : function(tag, w){
10041 tag = tag.toLowerCase();
10042 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
10043 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
10044 if(tag == 'input'){
10047 if(tag == 'textarea'){
10050 }else if(Roo.isOpera){
10051 if(tag == 'input'){
10054 if(tag == 'textarea'){
10062 setFieldLabel : function(v)
10064 if(!this.rendered){
10068 if(this.indicatorEl()){
10069 var ar = this.el.select('label > span',true);
10071 if (ar.elements.length) {
10072 this.el.select('label > span',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
10073 this.fieldLabel = v;
10077 var br = this.el.select('label',true);
10079 if(br.elements.length) {
10080 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
10081 this.fieldLabel = v;
10085 Roo.log('Cannot Found any of label > span || label in input');
10089 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
10090 this.fieldLabel = v;
10105 * @class Roo.bootstrap.TextArea
10106 * @extends Roo.bootstrap.Input
10107 * Bootstrap TextArea class
10108 * @cfg {Number} cols Specifies the visible width of a text area
10109 * @cfg {Number} rows Specifies the visible number of lines in a text area
10110 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
10111 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
10112 * @cfg {string} html text
10115 * Create a new TextArea
10116 * @param {Object} config The config object
10119 Roo.bootstrap.TextArea = function(config){
10120 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
10124 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
10134 getAutoCreate : function(){
10136 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
10142 if(this.inputType != 'hidden'){
10143 cfg.cls = 'form-group' //input-group
10151 value : this.value || '',
10152 html: this.html || '',
10153 cls : 'form-control',
10154 placeholder : this.placeholder || ''
10158 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
10159 input.maxLength = this.maxLength;
10163 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
10167 input.cols = this.cols;
10170 if (this.readOnly) {
10171 input.readonly = true;
10175 input.name = this.name;
10179 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
10183 ['xs','sm','md','lg'].map(function(size){
10184 if (settings[size]) {
10185 cfg.cls += ' col-' + size + '-' + settings[size];
10189 var inputblock = input;
10191 if(this.hasFeedback && !this.allowBlank){
10195 cls: 'glyphicon form-control-feedback'
10199 cls : 'has-feedback',
10208 if (this.before || this.after) {
10211 cls : 'input-group',
10215 inputblock.cn.push({
10217 cls : 'input-group-addon',
10222 inputblock.cn.push(input);
10224 if(this.hasFeedback && !this.allowBlank){
10225 inputblock.cls += ' has-feedback';
10226 inputblock.cn.push(feedback);
10230 inputblock.cn.push({
10232 cls : 'input-group-addon',
10239 if (align ==='left' && this.fieldLabel.length) {
10244 cls : 'control-label',
10245 html : this.fieldLabel
10256 if(this.labelWidth > 12){
10257 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
10260 if(this.labelWidth < 13 && this.labelmd == 0){
10261 this.labelmd = this.labelWidth;
10264 if(this.labellg > 0){
10265 cfg.cn[0].cls += ' col-lg-' + this.labellg;
10266 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
10269 if(this.labelmd > 0){
10270 cfg.cn[0].cls += ' col-md-' + this.labelmd;
10271 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
10274 if(this.labelsm > 0){
10275 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
10276 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
10279 if(this.labelxs > 0){
10280 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
10281 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
10284 } else if ( this.fieldLabel.length) {
10289 //cls : 'input-group-addon',
10290 html : this.fieldLabel
10308 if (this.disabled) {
10309 input.disabled=true;
10316 * return the real textarea element.
10318 inputEl: function ()
10320 return this.el.select('textarea.form-control',true).first();
10324 * Clear any invalid styles/messages for this field
10326 clearInvalid : function()
10329 if(!this.el || this.preventMark){ // not rendered
10333 var label = this.el.select('label', true).first();
10334 var icon = this.el.select('i.fa-star', true).first();
10339 this.el.removeClass( this.validClass);
10340 this.inputEl().removeClass('is-invalid');
10342 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10344 var feedback = this.el.select('.form-control-feedback', true).first();
10347 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
10352 this.fireEvent('valid', this);
10356 * Mark this field as valid
10358 markValid : function()
10360 if(!this.el || this.preventMark){ // not rendered
10364 this.el.removeClass([this.invalidClass, this.validClass]);
10365 this.inputEl().removeClass(['is-valid', 'is-invalid']);
10367 var feedback = this.el.select('.form-control-feedback', true).first();
10370 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10373 if(this.disabled || this.allowBlank){
10377 var label = this.el.select('label', true).first();
10378 var icon = this.el.select('i.fa-star', true).first();
10383 if (Roo.bootstrap.version == 3) {
10384 this.el.addClass(this.validClass);
10386 this.inputEl().addClass('is-valid');
10390 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
10392 var feedback = this.el.select('.form-control-feedback', true).first();
10395 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10396 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
10401 this.fireEvent('valid', this);
10405 * Mark this field as invalid
10406 * @param {String} msg The validation message
10408 markInvalid : function(msg)
10410 if(!this.el || this.preventMark){ // not rendered
10414 this.el.removeClass([this.invalidClass, this.validClass]);
10415 this.inputEl().removeClass(['is-valid', 'is-invalid']);
10417 var feedback = this.el.select('.form-control-feedback', true).first();
10420 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10423 if(this.disabled || this.allowBlank){
10427 var label = this.el.select('label', true).first();
10428 var icon = this.el.select('i.fa-star', true).first();
10430 if(!this.getValue().length && label && !icon){
10431 this.el.createChild({
10433 cls : 'text-danger fa fa-lg fa-star',
10434 tooltip : 'This field is required',
10435 style : 'margin-right:5px;'
10439 if (Roo.bootstrap.version == 3) {
10440 this.el.addClass(this.invalidClass);
10442 this.inputEl().addClass('is-invalid');
10445 // fixme ... this may be depricated need to test..
10446 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10448 var feedback = this.el.select('.form-control-feedback', true).first();
10451 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10453 if(this.getValue().length || this.forceFeedback){
10454 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
10461 this.fireEvent('invalid', this, msg);
10469 * trigger field - base class for combo..
10474 * @class Roo.bootstrap.TriggerField
10475 * @extends Roo.bootstrap.Input
10476 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
10477 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
10478 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
10479 * for which you can provide a custom implementation. For example:
10481 var trigger = new Roo.bootstrap.TriggerField();
10482 trigger.onTriggerClick = myTriggerFn;
10483 trigger.applyTo('my-field');
10486 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
10487 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
10488 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
10489 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
10490 * @cfg {String} caret (search|calendar) BS3 only - carat fa name
10493 * Create a new TriggerField.
10494 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
10495 * to the base TextField)
10497 Roo.bootstrap.TriggerField = function(config){
10498 this.mimicing = false;
10499 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
10502 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
10504 * @cfg {String} triggerClass A CSS class to apply to the trigger
10507 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
10512 * @cfg {Boolean} removable (true|false) special filter default false
10516 /** @cfg {Boolean} grow @hide */
10517 /** @cfg {Number} growMin @hide */
10518 /** @cfg {Number} growMax @hide */
10524 autoSize: Roo.emptyFn,
10528 deferHeight : true,
10531 actionMode : 'wrap',
10536 getAutoCreate : function(){
10538 var align = this.labelAlign || this.parentLabelAlign();
10543 cls: 'form-group' //input-group
10550 type : this.inputType,
10551 cls : 'form-control',
10552 autocomplete: 'new-password',
10553 placeholder : this.placeholder || ''
10557 input.name = this.name;
10560 input.cls += ' input-' + this.size;
10563 if (this.disabled) {
10564 input.disabled=true;
10567 var inputblock = input;
10569 if(this.hasFeedback && !this.allowBlank){
10573 cls: 'glyphicon form-control-feedback'
10576 if(this.removable && !this.editable && !this.tickable){
10578 cls : 'has-feedback',
10584 cls : 'roo-combo-removable-btn close'
10591 cls : 'has-feedback',
10600 if(this.removable && !this.editable && !this.tickable){
10602 cls : 'roo-removable',
10608 cls : 'roo-combo-removable-btn close'
10615 if (this.before || this.after) {
10618 cls : 'input-group',
10622 inputblock.cn.push({
10624 cls : 'input-group-addon input-group-prepend input-group-text',
10629 inputblock.cn.push(input);
10631 if(this.hasFeedback && !this.allowBlank){
10632 inputblock.cls += ' has-feedback';
10633 inputblock.cn.push(feedback);
10637 inputblock.cn.push({
10639 cls : 'input-group-addon input-group-append input-group-text',
10648 var ibwrap = inputblock;
10653 cls: 'roo-select2-choices',
10657 cls: 'roo-select2-search-field',
10669 cls: 'roo-select2-container input-group',
10674 cls: 'form-hidden-field'
10680 if(!this.multiple && this.showToggleBtn){
10686 if (this.caret != false) {
10689 cls: 'fa fa-' + this.caret
10696 cls : 'input-group-addon input-group-append input-group-text btn dropdown-toggle',
10698 Roo.bootstrap.version == 3 ? caret : '',
10701 cls: 'combobox-clear',
10715 combobox.cls += ' roo-select2-container-multi';
10719 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
10720 tooltip : 'This field is required'
10722 if (Roo.bootstrap.version == 4) {
10725 style : 'display:none'
10730 if (align ==='left' && this.fieldLabel.length) {
10732 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
10739 cls : 'control-label',
10740 html : this.fieldLabel
10752 var labelCfg = cfg.cn[1];
10753 var contentCfg = cfg.cn[2];
10755 if(this.indicatorpos == 'right'){
10760 cls : 'control-label',
10764 html : this.fieldLabel
10778 labelCfg = cfg.cn[0];
10779 contentCfg = cfg.cn[1];
10782 if(this.labelWidth > 12){
10783 labelCfg.style = "width: " + this.labelWidth + 'px';
10786 if(this.labelWidth < 13 && this.labelmd == 0){
10787 this.labelmd = this.labelWidth;
10790 if(this.labellg > 0){
10791 labelCfg.cls += ' col-lg-' + this.labellg;
10792 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
10795 if(this.labelmd > 0){
10796 labelCfg.cls += ' col-md-' + this.labelmd;
10797 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
10800 if(this.labelsm > 0){
10801 labelCfg.cls += ' col-sm-' + this.labelsm;
10802 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
10805 if(this.labelxs > 0){
10806 labelCfg.cls += ' col-xs-' + this.labelxs;
10807 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
10810 } else if ( this.fieldLabel.length) {
10811 // Roo.log(" label");
10816 //cls : 'input-group-addon',
10817 html : this.fieldLabel
10825 if(this.indicatorpos == 'right'){
10833 html : this.fieldLabel
10847 // Roo.log(" no label && no align");
10854 ['xs','sm','md','lg'].map(function(size){
10855 if (settings[size]) {
10856 cfg.cls += ' col-' + size + '-' + settings[size];
10867 onResize : function(w, h){
10868 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
10869 // if(typeof w == 'number'){
10870 // var x = w - this.trigger.getWidth();
10871 // this.inputEl().setWidth(this.adjustWidth('input', x));
10872 // this.trigger.setStyle('left', x+'px');
10877 adjustSize : Roo.BoxComponent.prototype.adjustSize,
10880 getResizeEl : function(){
10881 return this.inputEl();
10885 getPositionEl : function(){
10886 return this.inputEl();
10890 alignErrorIcon : function(){
10891 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
10895 initEvents : function(){
10899 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
10900 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
10901 if(!this.multiple && this.showToggleBtn){
10902 this.trigger = this.el.select('span.dropdown-toggle',true).first();
10903 if(this.hideTrigger){
10904 this.trigger.setDisplayed(false);
10906 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10910 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
10913 if(this.removable && !this.editable && !this.tickable){
10914 var close = this.closeTriggerEl();
10917 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
10918 close.on('click', this.removeBtnClick, this, close);
10922 //this.trigger.addClassOnOver('x-form-trigger-over');
10923 //this.trigger.addClassOnClick('x-form-trigger-click');
10926 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
10930 closeTriggerEl : function()
10932 var close = this.el.select('.roo-combo-removable-btn', true).first();
10933 return close ? close : false;
10936 removeBtnClick : function(e, h, el)
10938 e.preventDefault();
10940 if(this.fireEvent("remove", this) !== false){
10942 this.fireEvent("afterremove", this)
10946 createList : function()
10948 this.list = Roo.get(document.body).createChild({
10949 tag: Roo.bootstrap.version == 4 ? 'div' : 'ul',
10950 cls: 'typeahead typeahead-long dropdown-menu',
10951 style: 'display:none'
10954 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
10959 initTrigger : function(){
10964 onDestroy : function(){
10966 this.trigger.removeAllListeners();
10967 // this.trigger.remove();
10970 // this.wrap.remove();
10972 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
10976 onFocus : function(){
10977 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
10979 if(!this.mimicing){
10980 this.wrap.addClass('x-trigger-wrap-focus');
10981 this.mimicing = true;
10982 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
10983 if(this.monitorTab){
10984 this.el.on("keydown", this.checkTab, this);
10991 checkTab : function(e){
10992 if(e.getKey() == e.TAB){
10993 this.triggerBlur();
10998 onBlur : function(){
11003 mimicBlur : function(e, t){
11005 if(!this.wrap.contains(t) && this.validateBlur()){
11006 this.triggerBlur();
11012 triggerBlur : function(){
11013 this.mimicing = false;
11014 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
11015 if(this.monitorTab){
11016 this.el.un("keydown", this.checkTab, this);
11018 //this.wrap.removeClass('x-trigger-wrap-focus');
11019 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
11023 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
11024 validateBlur : function(e, t){
11029 onDisable : function(){
11030 this.inputEl().dom.disabled = true;
11031 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
11033 // this.wrap.addClass('x-item-disabled');
11038 onEnable : function(){
11039 this.inputEl().dom.disabled = false;
11040 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
11042 // this.el.removeClass('x-item-disabled');
11047 onShow : function(){
11048 var ae = this.getActionEl();
11051 ae.dom.style.display = '';
11052 ae.dom.style.visibility = 'visible';
11058 onHide : function(){
11059 var ae = this.getActionEl();
11060 ae.dom.style.display = 'none';
11064 * The function that should handle the trigger's click event. This method does nothing by default until overridden
11065 * by an implementing function.
11067 * @param {EventObject} e
11069 onTriggerClick : Roo.emptyFn
11073 * Ext JS Library 1.1.1
11074 * Copyright(c) 2006-2007, Ext JS, LLC.
11076 * Originally Released Under LGPL - original licence link has changed is not relivant.
11079 * <script type="text/javascript">
11084 * @class Roo.data.SortTypes
11086 * Defines the default sorting (casting?) comparison functions used when sorting data.
11088 Roo.data.SortTypes = {
11090 * Default sort that does nothing
11091 * @param {Mixed} s The value being converted
11092 * @return {Mixed} The comparison value
11094 none : function(s){
11099 * The regular expression used to strip tags
11103 stripTagsRE : /<\/?[^>]+>/gi,
11106 * Strips all HTML tags to sort on text only
11107 * @param {Mixed} s The value being converted
11108 * @return {String} The comparison value
11110 asText : function(s){
11111 return String(s).replace(this.stripTagsRE, "");
11115 * Strips all HTML tags to sort on text only - Case insensitive
11116 * @param {Mixed} s The value being converted
11117 * @return {String} The comparison value
11119 asUCText : function(s){
11120 return String(s).toUpperCase().replace(this.stripTagsRE, "");
11124 * Case insensitive string
11125 * @param {Mixed} s The value being converted
11126 * @return {String} The comparison value
11128 asUCString : function(s) {
11129 return String(s).toUpperCase();
11134 * @param {Mixed} s The value being converted
11135 * @return {Number} The comparison value
11137 asDate : function(s) {
11141 if(s instanceof Date){
11142 return s.getTime();
11144 return Date.parse(String(s));
11149 * @param {Mixed} s The value being converted
11150 * @return {Float} The comparison value
11152 asFloat : function(s) {
11153 var val = parseFloat(String(s).replace(/,/g, ""));
11162 * @param {Mixed} s The value being converted
11163 * @return {Number} The comparison value
11165 asInt : function(s) {
11166 var val = parseInt(String(s).replace(/,/g, ""));
11174 * Ext JS Library 1.1.1
11175 * Copyright(c) 2006-2007, Ext JS, LLC.
11177 * Originally Released Under LGPL - original licence link has changed is not relivant.
11180 * <script type="text/javascript">
11184 * @class Roo.data.Record
11185 * Instances of this class encapsulate both record <em>definition</em> information, and record
11186 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
11187 * to access Records cached in an {@link Roo.data.Store} object.<br>
11189 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
11190 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
11193 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
11195 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
11196 * {@link #create}. The parameters are the same.
11197 * @param {Array} data An associative Array of data values keyed by the field name.
11198 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
11199 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
11200 * not specified an integer id is generated.
11202 Roo.data.Record = function(data, id){
11203 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
11208 * Generate a constructor for a specific record layout.
11209 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
11210 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
11211 * Each field definition object may contain the following properties: <ul>
11212 * <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,
11213 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
11214 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
11215 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
11216 * is being used, then this is a string containing the javascript expression to reference the data relative to
11217 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
11218 * to the data item relative to the record element. If the mapping expression is the same as the field name,
11219 * this may be omitted.</p></li>
11220 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
11221 * <ul><li>auto (Default, implies no conversion)</li>
11226 * <li>date</li></ul></p></li>
11227 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
11228 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
11229 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
11230 * by the Reader into an object that will be stored in the Record. It is passed the
11231 * following parameters:<ul>
11232 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
11234 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
11236 * <br>usage:<br><pre><code>
11237 var TopicRecord = Roo.data.Record.create(
11238 {name: 'title', mapping: 'topic_title'},
11239 {name: 'author', mapping: 'username'},
11240 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
11241 {name: 'lastPost', mapping: 'post_time', type: 'date'},
11242 {name: 'lastPoster', mapping: 'user2'},
11243 {name: 'excerpt', mapping: 'post_text'}
11246 var myNewRecord = new TopicRecord({
11247 title: 'Do my job please',
11250 lastPost: new Date(),
11251 lastPoster: 'Animal',
11252 excerpt: 'No way dude!'
11254 myStore.add(myNewRecord);
11259 Roo.data.Record.create = function(o){
11260 var f = function(){
11261 f.superclass.constructor.apply(this, arguments);
11263 Roo.extend(f, Roo.data.Record);
11264 var p = f.prototype;
11265 p.fields = new Roo.util.MixedCollection(false, function(field){
11268 for(var i = 0, len = o.length; i < len; i++){
11269 p.fields.add(new Roo.data.Field(o[i]));
11271 f.getField = function(name){
11272 return p.fields.get(name);
11277 Roo.data.Record.AUTO_ID = 1000;
11278 Roo.data.Record.EDIT = 'edit';
11279 Roo.data.Record.REJECT = 'reject';
11280 Roo.data.Record.COMMIT = 'commit';
11282 Roo.data.Record.prototype = {
11284 * Readonly flag - true if this record has been modified.
11293 join : function(store){
11294 this.store = store;
11298 * Set the named field to the specified value.
11299 * @param {String} name The name of the field to set.
11300 * @param {Object} value The value to set the field to.
11302 set : function(name, value){
11303 if(this.data[name] == value){
11307 if(!this.modified){
11308 this.modified = {};
11310 if(typeof this.modified[name] == 'undefined'){
11311 this.modified[name] = this.data[name];
11313 this.data[name] = value;
11314 if(!this.editing && this.store){
11315 this.store.afterEdit(this);
11320 * Get the value of the named field.
11321 * @param {String} name The name of the field to get the value of.
11322 * @return {Object} The value of the field.
11324 get : function(name){
11325 return this.data[name];
11329 beginEdit : function(){
11330 this.editing = true;
11331 this.modified = {};
11335 cancelEdit : function(){
11336 this.editing = false;
11337 delete this.modified;
11341 endEdit : function(){
11342 this.editing = false;
11343 if(this.dirty && this.store){
11344 this.store.afterEdit(this);
11349 * Usually called by the {@link Roo.data.Store} which owns the Record.
11350 * Rejects all changes made to the Record since either creation, or the last commit operation.
11351 * Modified fields are reverted to their original values.
11353 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
11354 * of reject operations.
11356 reject : function(){
11357 var m = this.modified;
11359 if(typeof m[n] != "function"){
11360 this.data[n] = m[n];
11363 this.dirty = false;
11364 delete this.modified;
11365 this.editing = false;
11367 this.store.afterReject(this);
11372 * Usually called by the {@link Roo.data.Store} which owns the Record.
11373 * Commits all changes made to the Record since either creation, or the last commit operation.
11375 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
11376 * of commit operations.
11378 commit : function(){
11379 this.dirty = false;
11380 delete this.modified;
11381 this.editing = false;
11383 this.store.afterCommit(this);
11388 hasError : function(){
11389 return this.error != null;
11393 clearError : function(){
11398 * Creates a copy of this record.
11399 * @param {String} id (optional) A new record id if you don't want to use this record's id
11402 copy : function(newId) {
11403 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
11407 * Ext JS Library 1.1.1
11408 * Copyright(c) 2006-2007, Ext JS, LLC.
11410 * Originally Released Under LGPL - original licence link has changed is not relivant.
11413 * <script type="text/javascript">
11419 * @class Roo.data.Store
11420 * @extends Roo.util.Observable
11421 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
11422 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
11424 * 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
11425 * has no knowledge of the format of the data returned by the Proxy.<br>
11427 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
11428 * instances from the data object. These records are cached and made available through accessor functions.
11430 * Creates a new Store.
11431 * @param {Object} config A config object containing the objects needed for the Store to access data,
11432 * and read the data into Records.
11434 Roo.data.Store = function(config){
11435 this.data = new Roo.util.MixedCollection(false);
11436 this.data.getKey = function(o){
11439 this.baseParams = {};
11441 this.paramNames = {
11446 "multisort" : "_multisort"
11449 if(config && config.data){
11450 this.inlineData = config.data;
11451 delete config.data;
11454 Roo.apply(this, config);
11456 if(this.reader){ // reader passed
11457 this.reader = Roo.factory(this.reader, Roo.data);
11458 this.reader.xmodule = this.xmodule || false;
11459 if(!this.recordType){
11460 this.recordType = this.reader.recordType;
11462 if(this.reader.onMetaChange){
11463 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
11467 if(this.recordType){
11468 this.fields = this.recordType.prototype.fields;
11470 this.modified = [];
11474 * @event datachanged
11475 * Fires when the data cache has changed, and a widget which is using this Store
11476 * as a Record cache should refresh its view.
11477 * @param {Store} this
11479 datachanged : true,
11481 * @event metachange
11482 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
11483 * @param {Store} this
11484 * @param {Object} meta The JSON metadata
11489 * Fires when Records have been added to the Store
11490 * @param {Store} this
11491 * @param {Roo.data.Record[]} records The array of Records added
11492 * @param {Number} index The index at which the record(s) were added
11497 * Fires when a Record has been removed from the Store
11498 * @param {Store} this
11499 * @param {Roo.data.Record} record The Record that was removed
11500 * @param {Number} index The index at which the record was removed
11505 * Fires when a Record has been updated
11506 * @param {Store} this
11507 * @param {Roo.data.Record} record The Record that was updated
11508 * @param {String} operation The update operation being performed. Value may be one of:
11510 Roo.data.Record.EDIT
11511 Roo.data.Record.REJECT
11512 Roo.data.Record.COMMIT
11518 * Fires when the data cache has been cleared.
11519 * @param {Store} this
11523 * @event beforeload
11524 * Fires before a request is made for a new data object. If the beforeload handler returns false
11525 * the load action will be canceled.
11526 * @param {Store} this
11527 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11531 * @event beforeloadadd
11532 * Fires after a new set of Records has been loaded.
11533 * @param {Store} this
11534 * @param {Roo.data.Record[]} records The Records that were loaded
11535 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11537 beforeloadadd : true,
11540 * Fires after a new set of Records has been loaded, before they are added to the store.
11541 * @param {Store} this
11542 * @param {Roo.data.Record[]} records The Records that were loaded
11543 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11544 * @params {Object} return from reader
11548 * @event loadexception
11549 * Fires if an exception occurs in the Proxy during loading.
11550 * Called with the signature of the Proxy's "loadexception" event.
11551 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
11554 * @param {Object} return from JsonData.reader() - success, totalRecords, records
11555 * @param {Object} load options
11556 * @param {Object} jsonData from your request (normally this contains the Exception)
11558 loadexception : true
11562 this.proxy = Roo.factory(this.proxy, Roo.data);
11563 this.proxy.xmodule = this.xmodule || false;
11564 this.relayEvents(this.proxy, ["loadexception"]);
11566 this.sortToggle = {};
11567 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
11569 Roo.data.Store.superclass.constructor.call(this);
11571 if(this.inlineData){
11572 this.loadData(this.inlineData);
11573 delete this.inlineData;
11577 Roo.extend(Roo.data.Store, Roo.util.Observable, {
11579 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
11580 * without a remote query - used by combo/forms at present.
11584 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
11587 * @cfg {Array} data Inline data to be loaded when the store is initialized.
11590 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
11591 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
11594 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
11595 * on any HTTP request
11598 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
11601 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
11605 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
11606 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
11608 remoteSort : false,
11611 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
11612 * loaded or when a record is removed. (defaults to false).
11614 pruneModifiedRecords : false,
11617 lastOptions : null,
11620 * Add Records to the Store and fires the add event.
11621 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11623 add : function(records){
11624 records = [].concat(records);
11625 for(var i = 0, len = records.length; i < len; i++){
11626 records[i].join(this);
11628 var index = this.data.length;
11629 this.data.addAll(records);
11630 this.fireEvent("add", this, records, index);
11634 * Remove a Record from the Store and fires the remove event.
11635 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
11637 remove : function(record){
11638 var index = this.data.indexOf(record);
11639 this.data.removeAt(index);
11641 if(this.pruneModifiedRecords){
11642 this.modified.remove(record);
11644 this.fireEvent("remove", this, record, index);
11648 * Remove all Records from the Store and fires the clear event.
11650 removeAll : function(){
11652 if(this.pruneModifiedRecords){
11653 this.modified = [];
11655 this.fireEvent("clear", this);
11659 * Inserts Records to the Store at the given index and fires the add event.
11660 * @param {Number} index The start index at which to insert the passed Records.
11661 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11663 insert : function(index, records){
11664 records = [].concat(records);
11665 for(var i = 0, len = records.length; i < len; i++){
11666 this.data.insert(index, records[i]);
11667 records[i].join(this);
11669 this.fireEvent("add", this, records, index);
11673 * Get the index within the cache of the passed Record.
11674 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
11675 * @return {Number} The index of the passed Record. Returns -1 if not found.
11677 indexOf : function(record){
11678 return this.data.indexOf(record);
11682 * Get the index within the cache of the Record with the passed id.
11683 * @param {String} id The id of the Record to find.
11684 * @return {Number} The index of the Record. Returns -1 if not found.
11686 indexOfId : function(id){
11687 return this.data.indexOfKey(id);
11691 * Get the Record with the specified id.
11692 * @param {String} id The id of the Record to find.
11693 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
11695 getById : function(id){
11696 return this.data.key(id);
11700 * Get the Record at the specified index.
11701 * @param {Number} index The index of the Record to find.
11702 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
11704 getAt : function(index){
11705 return this.data.itemAt(index);
11709 * Returns a range of Records between specified indices.
11710 * @param {Number} startIndex (optional) The starting index (defaults to 0)
11711 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
11712 * @return {Roo.data.Record[]} An array of Records
11714 getRange : function(start, end){
11715 return this.data.getRange(start, end);
11719 storeOptions : function(o){
11720 o = Roo.apply({}, o);
11723 this.lastOptions = o;
11727 * Loads the Record cache from the configured Proxy using the configured Reader.
11729 * If using remote paging, then the first load call must specify the <em>start</em>
11730 * and <em>limit</em> properties in the options.params property to establish the initial
11731 * position within the dataset, and the number of Records to cache on each read from the Proxy.
11733 * <strong>It is important to note that for remote data sources, loading is asynchronous,
11734 * and this call will return before the new data has been loaded. Perform any post-processing
11735 * in a callback function, or in a "load" event handler.</strong>
11737 * @param {Object} options An object containing properties which control loading options:<ul>
11738 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
11739 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
11740 * passed the following arguments:<ul>
11741 * <li>r : Roo.data.Record[]</li>
11742 * <li>options: Options object from the load call</li>
11743 * <li>success: Boolean success indicator</li></ul></li>
11744 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
11745 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
11748 load : function(options){
11749 options = options || {};
11750 if(this.fireEvent("beforeload", this, options) !== false){
11751 this.storeOptions(options);
11752 var p = Roo.apply(options.params || {}, this.baseParams);
11753 // if meta was not loaded from remote source.. try requesting it.
11754 if (!this.reader.metaFromRemote) {
11755 p._requestMeta = 1;
11757 if(this.sortInfo && this.remoteSort){
11758 var pn = this.paramNames;
11759 p[pn["sort"]] = this.sortInfo.field;
11760 p[pn["dir"]] = this.sortInfo.direction;
11762 if (this.multiSort) {
11763 var pn = this.paramNames;
11764 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
11767 this.proxy.load(p, this.reader, this.loadRecords, this, options);
11772 * Reloads the Record cache from the configured Proxy using the configured Reader and
11773 * the options from the last load operation performed.
11774 * @param {Object} options (optional) An object containing properties which may override the options
11775 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
11776 * the most recently used options are reused).
11778 reload : function(options){
11779 this.load(Roo.applyIf(options||{}, this.lastOptions));
11783 // Called as a callback by the Reader during a load operation.
11784 loadRecords : function(o, options, success){
11785 if(!o || success === false){
11786 if(success !== false){
11787 this.fireEvent("load", this, [], options, o);
11789 if(options.callback){
11790 options.callback.call(options.scope || this, [], options, false);
11794 // if data returned failure - throw an exception.
11795 if (o.success === false) {
11796 // show a message if no listener is registered.
11797 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
11798 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
11800 // loadmask wil be hooked into this..
11801 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
11804 var r = o.records, t = o.totalRecords || r.length;
11806 this.fireEvent("beforeloadadd", this, r, options, o);
11808 if(!options || options.add !== true){
11809 if(this.pruneModifiedRecords){
11810 this.modified = [];
11812 for(var i = 0, len = r.length; i < len; i++){
11816 this.data = this.snapshot;
11817 delete this.snapshot;
11820 this.data.addAll(r);
11821 this.totalLength = t;
11823 this.fireEvent("datachanged", this);
11825 this.totalLength = Math.max(t, this.data.length+r.length);
11829 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
11831 var e = new Roo.data.Record({});
11833 e.set(this.parent.displayField, this.parent.emptyTitle);
11834 e.set(this.parent.valueField, '');
11839 this.fireEvent("load", this, r, options, o);
11840 if(options.callback){
11841 options.callback.call(options.scope || this, r, options, true);
11847 * Loads data from a passed data block. A Reader which understands the format of the data
11848 * must have been configured in the constructor.
11849 * @param {Object} data The data block from which to read the Records. The format of the data expected
11850 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
11851 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
11853 loadData : function(o, append){
11854 var r = this.reader.readRecords(o);
11855 this.loadRecords(r, {add: append}, true);
11859 * Gets the number of cached records.
11861 * <em>If using paging, this may not be the total size of the dataset. If the data object
11862 * used by the Reader contains the dataset size, then the getTotalCount() function returns
11863 * the data set size</em>
11865 getCount : function(){
11866 return this.data.length || 0;
11870 * Gets the total number of records in the dataset as returned by the server.
11872 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
11873 * the dataset size</em>
11875 getTotalCount : function(){
11876 return this.totalLength || 0;
11880 * Returns the sort state of the Store as an object with two properties:
11882 field {String} The name of the field by which the Records are sorted
11883 direction {String} The sort order, "ASC" or "DESC"
11886 getSortState : function(){
11887 return this.sortInfo;
11891 applySort : function(){
11892 if(this.sortInfo && !this.remoteSort){
11893 var s = this.sortInfo, f = s.field;
11894 var st = this.fields.get(f).sortType;
11895 var fn = function(r1, r2){
11896 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
11897 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
11899 this.data.sort(s.direction, fn);
11900 if(this.snapshot && this.snapshot != this.data){
11901 this.snapshot.sort(s.direction, fn);
11907 * Sets the default sort column and order to be used by the next load operation.
11908 * @param {String} fieldName The name of the field to sort by.
11909 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11911 setDefaultSort : function(field, dir){
11912 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
11916 * Sort the Records.
11917 * If remote sorting is used, the sort is performed on the server, and the cache is
11918 * reloaded. If local sorting is used, the cache is sorted internally.
11919 * @param {String} fieldName The name of the field to sort by.
11920 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11922 sort : function(fieldName, dir){
11923 var f = this.fields.get(fieldName);
11925 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
11927 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
11928 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
11933 this.sortToggle[f.name] = dir;
11934 this.sortInfo = {field: f.name, direction: dir};
11935 if(!this.remoteSort){
11937 this.fireEvent("datachanged", this);
11939 this.load(this.lastOptions);
11944 * Calls the specified function for each of the Records in the cache.
11945 * @param {Function} fn The function to call. The Record is passed as the first parameter.
11946 * Returning <em>false</em> aborts and exits the iteration.
11947 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
11949 each : function(fn, scope){
11950 this.data.each(fn, scope);
11954 * Gets all records modified since the last commit. Modified records are persisted across load operations
11955 * (e.g., during paging).
11956 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
11958 getModifiedRecords : function(){
11959 return this.modified;
11963 createFilterFn : function(property, value, anyMatch){
11964 if(!value.exec){ // not a regex
11965 value = String(value);
11966 if(value.length == 0){
11969 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
11971 return function(r){
11972 return value.test(r.data[property]);
11977 * Sums the value of <i>property</i> for each record between start and end and returns the result.
11978 * @param {String} property A field on your records
11979 * @param {Number} start The record index to start at (defaults to 0)
11980 * @param {Number} end The last record index to include (defaults to length - 1)
11981 * @return {Number} The sum
11983 sum : function(property, start, end){
11984 var rs = this.data.items, v = 0;
11985 start = start || 0;
11986 end = (end || end === 0) ? end : rs.length-1;
11988 for(var i = start; i <= end; i++){
11989 v += (rs[i].data[property] || 0);
11995 * Filter the records by a specified property.
11996 * @param {String} field A field on your records
11997 * @param {String/RegExp} value Either a string that the field
11998 * should start with or a RegExp to test against the field
11999 * @param {Boolean} anyMatch True to match any part not just the beginning
12001 filter : function(property, value, anyMatch){
12002 var fn = this.createFilterFn(property, value, anyMatch);
12003 return fn ? this.filterBy(fn) : this.clearFilter();
12007 * Filter by a function. The specified function will be called with each
12008 * record in this data source. If the function returns true the record is included,
12009 * otherwise it is filtered.
12010 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
12011 * @param {Object} scope (optional) The scope of the function (defaults to this)
12013 filterBy : function(fn, scope){
12014 this.snapshot = this.snapshot || this.data;
12015 this.data = this.queryBy(fn, scope||this);
12016 this.fireEvent("datachanged", this);
12020 * Query the records by a specified property.
12021 * @param {String} field A field on your records
12022 * @param {String/RegExp} value Either a string that the field
12023 * should start with or a RegExp to test against the field
12024 * @param {Boolean} anyMatch True to match any part not just the beginning
12025 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
12027 query : function(property, value, anyMatch){
12028 var fn = this.createFilterFn(property, value, anyMatch);
12029 return fn ? this.queryBy(fn) : this.data.clone();
12033 * Query by a function. The specified function will be called with each
12034 * record in this data source. If the function returns true the record is included
12036 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
12037 * @param {Object} scope (optional) The scope of the function (defaults to this)
12038 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
12040 queryBy : function(fn, scope){
12041 var data = this.snapshot || this.data;
12042 return data.filterBy(fn, scope||this);
12046 * Collects unique values for a particular dataIndex from this store.
12047 * @param {String} dataIndex The property to collect
12048 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
12049 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
12050 * @return {Array} An array of the unique values
12052 collect : function(dataIndex, allowNull, bypassFilter){
12053 var d = (bypassFilter === true && this.snapshot) ?
12054 this.snapshot.items : this.data.items;
12055 var v, sv, r = [], l = {};
12056 for(var i = 0, len = d.length; i < len; i++){
12057 v = d[i].data[dataIndex];
12059 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
12068 * Revert to a view of the Record cache with no filtering applied.
12069 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
12071 clearFilter : function(suppressEvent){
12072 if(this.snapshot && this.snapshot != this.data){
12073 this.data = this.snapshot;
12074 delete this.snapshot;
12075 if(suppressEvent !== true){
12076 this.fireEvent("datachanged", this);
12082 afterEdit : function(record){
12083 if(this.modified.indexOf(record) == -1){
12084 this.modified.push(record);
12086 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
12090 afterReject : function(record){
12091 this.modified.remove(record);
12092 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
12096 afterCommit : function(record){
12097 this.modified.remove(record);
12098 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
12102 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
12103 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
12105 commitChanges : function(){
12106 var m = this.modified.slice(0);
12107 this.modified = [];
12108 for(var i = 0, len = m.length; i < len; i++){
12114 * Cancel outstanding changes on all changed records.
12116 rejectChanges : function(){
12117 var m = this.modified.slice(0);
12118 this.modified = [];
12119 for(var i = 0, len = m.length; i < len; i++){
12124 onMetaChange : function(meta, rtype, o){
12125 this.recordType = rtype;
12126 this.fields = rtype.prototype.fields;
12127 delete this.snapshot;
12128 this.sortInfo = meta.sortInfo || this.sortInfo;
12129 this.modified = [];
12130 this.fireEvent('metachange', this, this.reader.meta);
12133 moveIndex : function(data, type)
12135 var index = this.indexOf(data);
12137 var newIndex = index + type;
12141 this.insert(newIndex, data);
12146 * Ext JS Library 1.1.1
12147 * Copyright(c) 2006-2007, Ext JS, LLC.
12149 * Originally Released Under LGPL - original licence link has changed is not relivant.
12152 * <script type="text/javascript">
12156 * @class Roo.data.SimpleStore
12157 * @extends Roo.data.Store
12158 * Small helper class to make creating Stores from Array data easier.
12159 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
12160 * @cfg {Array} fields An array of field definition objects, or field name strings.
12161 * @cfg {Array} data The multi-dimensional array of data
12163 * @param {Object} config
12165 Roo.data.SimpleStore = function(config){
12166 Roo.data.SimpleStore.superclass.constructor.call(this, {
12168 reader: new Roo.data.ArrayReader({
12171 Roo.data.Record.create(config.fields)
12173 proxy : new Roo.data.MemoryProxy(config.data)
12177 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
12179 * Ext JS Library 1.1.1
12180 * Copyright(c) 2006-2007, Ext JS, LLC.
12182 * Originally Released Under LGPL - original licence link has changed is not relivant.
12185 * <script type="text/javascript">
12190 * @extends Roo.data.Store
12191 * @class Roo.data.JsonStore
12192 * Small helper class to make creating Stores for JSON data easier. <br/>
12194 var store = new Roo.data.JsonStore({
12195 url: 'get-images.php',
12197 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
12200 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
12201 * JsonReader and HttpProxy (unless inline data is provided).</b>
12202 * @cfg {Array} fields An array of field definition objects, or field name strings.
12204 * @param {Object} config
12206 Roo.data.JsonStore = function(c){
12207 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
12208 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
12209 reader: new Roo.data.JsonReader(c, c.fields)
12212 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
12214 * Ext JS Library 1.1.1
12215 * Copyright(c) 2006-2007, Ext JS, LLC.
12217 * Originally Released Under LGPL - original licence link has changed is not relivant.
12220 * <script type="text/javascript">
12224 Roo.data.Field = function(config){
12225 if(typeof config == "string"){
12226 config = {name: config};
12228 Roo.apply(this, config);
12231 this.type = "auto";
12234 var st = Roo.data.SortTypes;
12235 // named sortTypes are supported, here we look them up
12236 if(typeof this.sortType == "string"){
12237 this.sortType = st[this.sortType];
12240 // set default sortType for strings and dates
12241 if(!this.sortType){
12244 this.sortType = st.asUCString;
12247 this.sortType = st.asDate;
12250 this.sortType = st.none;
12255 var stripRe = /[\$,%]/g;
12257 // prebuilt conversion function for this field, instead of
12258 // switching every time we're reading a value
12260 var cv, dateFormat = this.dateFormat;
12265 cv = function(v){ return v; };
12268 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
12272 return v !== undefined && v !== null && v !== '' ?
12273 parseInt(String(v).replace(stripRe, ""), 10) : '';
12278 return v !== undefined && v !== null && v !== '' ?
12279 parseFloat(String(v).replace(stripRe, ""), 10) : '';
12284 cv = function(v){ return v === true || v === "true" || v == 1; };
12291 if(v instanceof Date){
12295 if(dateFormat == "timestamp"){
12296 return new Date(v*1000);
12298 return Date.parseDate(v, dateFormat);
12300 var parsed = Date.parse(v);
12301 return parsed ? new Date(parsed) : null;
12310 Roo.data.Field.prototype = {
12318 * Ext JS Library 1.1.1
12319 * Copyright(c) 2006-2007, Ext JS, LLC.
12321 * Originally Released Under LGPL - original licence link has changed is not relivant.
12324 * <script type="text/javascript">
12327 // Base class for reading structured data from a data source. This class is intended to be
12328 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
12331 * @class Roo.data.DataReader
12332 * Base class for reading structured data from a data source. This class is intended to be
12333 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
12336 Roo.data.DataReader = function(meta, recordType){
12340 this.recordType = recordType instanceof Array ?
12341 Roo.data.Record.create(recordType) : recordType;
12344 Roo.data.DataReader.prototype = {
12346 * Create an empty record
12347 * @param {Object} data (optional) - overlay some values
12348 * @return {Roo.data.Record} record created.
12350 newRow : function(d) {
12352 this.recordType.prototype.fields.each(function(c) {
12354 case 'int' : da[c.name] = 0; break;
12355 case 'date' : da[c.name] = new Date(); break;
12356 case 'float' : da[c.name] = 0.0; break;
12357 case 'boolean' : da[c.name] = false; break;
12358 default : da[c.name] = ""; break;
12362 return new this.recordType(Roo.apply(da, d));
12367 * Ext JS Library 1.1.1
12368 * Copyright(c) 2006-2007, Ext JS, LLC.
12370 * Originally Released Under LGPL - original licence link has changed is not relivant.
12373 * <script type="text/javascript">
12377 * @class Roo.data.DataProxy
12378 * @extends Roo.data.Observable
12379 * This class is an abstract base class for implementations which provide retrieval of
12380 * unformatted data objects.<br>
12382 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
12383 * (of the appropriate type which knows how to parse the data object) to provide a block of
12384 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
12386 * Custom implementations must implement the load method as described in
12387 * {@link Roo.data.HttpProxy#load}.
12389 Roo.data.DataProxy = function(){
12392 * @event beforeload
12393 * Fires before a network request is made to retrieve a data object.
12394 * @param {Object} This DataProxy object.
12395 * @param {Object} params The params parameter to the load function.
12400 * Fires before the load method's callback is called.
12401 * @param {Object} This DataProxy object.
12402 * @param {Object} o The data object.
12403 * @param {Object} arg The callback argument object passed to the load function.
12407 * @event loadexception
12408 * Fires if an Exception occurs during data retrieval.
12409 * @param {Object} This DataProxy object.
12410 * @param {Object} o The data object.
12411 * @param {Object} arg The callback argument object passed to the load function.
12412 * @param {Object} e The Exception.
12414 loadexception : true
12416 Roo.data.DataProxy.superclass.constructor.call(this);
12419 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
12422 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
12426 * Ext JS Library 1.1.1
12427 * Copyright(c) 2006-2007, Ext JS, LLC.
12429 * Originally Released Under LGPL - original licence link has changed is not relivant.
12432 * <script type="text/javascript">
12435 * @class Roo.data.MemoryProxy
12436 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
12437 * to the Reader when its load method is called.
12439 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
12441 Roo.data.MemoryProxy = function(data){
12445 Roo.data.MemoryProxy.superclass.constructor.call(this);
12449 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
12452 * Load data from the requested source (in this case an in-memory
12453 * data object passed to the constructor), read the data object into
12454 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12455 * process that block using the passed callback.
12456 * @param {Object} params This parameter is not used by the MemoryProxy class.
12457 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12458 * object into a block of Roo.data.Records.
12459 * @param {Function} callback The function into which to pass the block of Roo.data.records.
12460 * The function must be passed <ul>
12461 * <li>The Record block object</li>
12462 * <li>The "arg" argument from the load function</li>
12463 * <li>A boolean success indicator</li>
12465 * @param {Object} scope The scope in which to call the callback
12466 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12468 load : function(params, reader, callback, scope, arg){
12469 params = params || {};
12472 result = reader.readRecords(params.data ? params.data :this.data);
12474 this.fireEvent("loadexception", this, arg, null, e);
12475 callback.call(scope, null, arg, false);
12478 callback.call(scope, result, arg, true);
12482 update : function(params, records){
12487 * Ext JS Library 1.1.1
12488 * Copyright(c) 2006-2007, Ext JS, LLC.
12490 * Originally Released Under LGPL - original licence link has changed is not relivant.
12493 * <script type="text/javascript">
12496 * @class Roo.data.HttpProxy
12497 * @extends Roo.data.DataProxy
12498 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
12499 * configured to reference a certain URL.<br><br>
12501 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
12502 * from which the running page was served.<br><br>
12504 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
12506 * Be aware that to enable the browser to parse an XML document, the server must set
12507 * the Content-Type header in the HTTP response to "text/xml".
12509 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
12510 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
12511 * will be used to make the request.
12513 Roo.data.HttpProxy = function(conn){
12514 Roo.data.HttpProxy.superclass.constructor.call(this);
12515 // is conn a conn config or a real conn?
12517 this.useAjax = !conn || !conn.events;
12521 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
12522 // thse are take from connection...
12525 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
12528 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
12529 * extra parameters to each request made by this object. (defaults to undefined)
12532 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
12533 * to each request made by this object. (defaults to undefined)
12536 * @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)
12539 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
12542 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
12548 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
12552 * Return the {@link Roo.data.Connection} object being used by this Proxy.
12553 * @return {Connection} The Connection object. This object may be used to subscribe to events on
12554 * a finer-grained basis than the DataProxy events.
12556 getConnection : function(){
12557 return this.useAjax ? Roo.Ajax : this.conn;
12561 * Load data from the configured {@link Roo.data.Connection}, read the data object into
12562 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
12563 * process that block using the passed callback.
12564 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12565 * for the request to the remote server.
12566 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12567 * object into a block of Roo.data.Records.
12568 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12569 * The function must be passed <ul>
12570 * <li>The Record block object</li>
12571 * <li>The "arg" argument from the load function</li>
12572 * <li>A boolean success indicator</li>
12574 * @param {Object} scope The scope in which to call the callback
12575 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12577 load : function(params, reader, callback, scope, arg){
12578 if(this.fireEvent("beforeload", this, params) !== false){
12580 params : params || {},
12582 callback : callback,
12587 callback : this.loadResponse,
12591 Roo.applyIf(o, this.conn);
12592 if(this.activeRequest){
12593 Roo.Ajax.abort(this.activeRequest);
12595 this.activeRequest = Roo.Ajax.request(o);
12597 this.conn.request(o);
12600 callback.call(scope||this, null, arg, false);
12605 loadResponse : function(o, success, response){
12606 delete this.activeRequest;
12608 this.fireEvent("loadexception", this, o, response);
12609 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12614 result = o.reader.read(response);
12616 this.fireEvent("loadexception", this, o, response, e);
12617 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12621 this.fireEvent("load", this, o, o.request.arg);
12622 o.request.callback.call(o.request.scope, result, o.request.arg, true);
12626 update : function(dataSet){
12631 updateResponse : function(dataSet){
12636 * Ext JS Library 1.1.1
12637 * Copyright(c) 2006-2007, Ext JS, LLC.
12639 * Originally Released Under LGPL - original licence link has changed is not relivant.
12642 * <script type="text/javascript">
12646 * @class Roo.data.ScriptTagProxy
12647 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
12648 * other than the originating domain of the running page.<br><br>
12650 * <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
12651 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
12653 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
12654 * source code that is used as the source inside a <script> tag.<br><br>
12656 * In order for the browser to process the returned data, the server must wrap the data object
12657 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
12658 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
12659 * depending on whether the callback name was passed:
12662 boolean scriptTag = false;
12663 String cb = request.getParameter("callback");
12666 response.setContentType("text/javascript");
12668 response.setContentType("application/x-json");
12670 Writer out = response.getWriter();
12672 out.write(cb + "(");
12674 out.print(dataBlock.toJsonString());
12681 * @param {Object} config A configuration object.
12683 Roo.data.ScriptTagProxy = function(config){
12684 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
12685 Roo.apply(this, config);
12686 this.head = document.getElementsByTagName("head")[0];
12689 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
12691 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
12693 * @cfg {String} url The URL from which to request the data object.
12696 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
12700 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
12701 * the server the name of the callback function set up by the load call to process the returned data object.
12702 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
12703 * javascript output which calls this named function passing the data object as its only parameter.
12705 callbackParam : "callback",
12707 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
12708 * name to the request.
12713 * Load data from the configured URL, read the data object into
12714 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12715 * process that block using the passed callback.
12716 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12717 * for the request to the remote server.
12718 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12719 * object into a block of Roo.data.Records.
12720 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12721 * The function must be passed <ul>
12722 * <li>The Record block object</li>
12723 * <li>The "arg" argument from the load function</li>
12724 * <li>A boolean success indicator</li>
12726 * @param {Object} scope The scope in which to call the callback
12727 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12729 load : function(params, reader, callback, scope, arg){
12730 if(this.fireEvent("beforeload", this, params) !== false){
12732 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
12734 var url = this.url;
12735 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
12737 url += "&_dc=" + (new Date().getTime());
12739 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
12742 cb : "stcCallback"+transId,
12743 scriptId : "stcScript"+transId,
12747 callback : callback,
12753 window[trans.cb] = function(o){
12754 conn.handleResponse(o, trans);
12757 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
12759 if(this.autoAbort !== false){
12763 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
12765 var script = document.createElement("script");
12766 script.setAttribute("src", url);
12767 script.setAttribute("type", "text/javascript");
12768 script.setAttribute("id", trans.scriptId);
12769 this.head.appendChild(script);
12771 this.trans = trans;
12773 callback.call(scope||this, null, arg, false);
12778 isLoading : function(){
12779 return this.trans ? true : false;
12783 * Abort the current server request.
12785 abort : function(){
12786 if(this.isLoading()){
12787 this.destroyTrans(this.trans);
12792 destroyTrans : function(trans, isLoaded){
12793 this.head.removeChild(document.getElementById(trans.scriptId));
12794 clearTimeout(trans.timeoutId);
12796 window[trans.cb] = undefined;
12798 delete window[trans.cb];
12801 // if hasn't been loaded, wait for load to remove it to prevent script error
12802 window[trans.cb] = function(){
12803 window[trans.cb] = undefined;
12805 delete window[trans.cb];
12812 handleResponse : function(o, trans){
12813 this.trans = false;
12814 this.destroyTrans(trans, true);
12817 result = trans.reader.readRecords(o);
12819 this.fireEvent("loadexception", this, o, trans.arg, e);
12820 trans.callback.call(trans.scope||window, null, trans.arg, false);
12823 this.fireEvent("load", this, o, trans.arg);
12824 trans.callback.call(trans.scope||window, result, trans.arg, true);
12828 handleFailure : function(trans){
12829 this.trans = false;
12830 this.destroyTrans(trans, false);
12831 this.fireEvent("loadexception", this, null, trans.arg);
12832 trans.callback.call(trans.scope||window, null, trans.arg, false);
12836 * Ext JS Library 1.1.1
12837 * Copyright(c) 2006-2007, Ext JS, LLC.
12839 * Originally Released Under LGPL - original licence link has changed is not relivant.
12842 * <script type="text/javascript">
12846 * @class Roo.data.JsonReader
12847 * @extends Roo.data.DataReader
12848 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
12849 * based on mappings in a provided Roo.data.Record constructor.
12851 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
12852 * in the reply previously.
12857 var RecordDef = Roo.data.Record.create([
12858 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
12859 {name: 'occupation'} // This field will use "occupation" as the mapping.
12861 var myReader = new Roo.data.JsonReader({
12862 totalProperty: "results", // The property which contains the total dataset size (optional)
12863 root: "rows", // The property which contains an Array of row objects
12864 id: "id" // The property within each row object that provides an ID for the record (optional)
12868 * This would consume a JSON file like this:
12870 { 'results': 2, 'rows': [
12871 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
12872 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
12875 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
12876 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
12877 * paged from the remote server.
12878 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
12879 * @cfg {String} root name of the property which contains the Array of row objects.
12880 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
12881 * @cfg {Array} fields Array of field definition objects
12883 * Create a new JsonReader
12884 * @param {Object} meta Metadata configuration options
12885 * @param {Object} recordType Either an Array of field definition objects,
12886 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
12888 Roo.data.JsonReader = function(meta, recordType){
12891 // set some defaults:
12892 Roo.applyIf(meta, {
12893 totalProperty: 'total',
12894 successProperty : 'success',
12899 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
12901 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
12904 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
12905 * Used by Store query builder to append _requestMeta to params.
12908 metaFromRemote : false,
12910 * This method is only used by a DataProxy which has retrieved data from a remote server.
12911 * @param {Object} response The XHR object which contains the JSON data in its responseText.
12912 * @return {Object} data A data block which is used by an Roo.data.Store object as
12913 * a cache of Roo.data.Records.
12915 read : function(response){
12916 var json = response.responseText;
12918 var o = /* eval:var:o */ eval("("+json+")");
12920 throw {message: "JsonReader.read: Json object not found"};
12926 this.metaFromRemote = true;
12927 this.meta = o.metaData;
12928 this.recordType = Roo.data.Record.create(o.metaData.fields);
12929 this.onMetaChange(this.meta, this.recordType, o);
12931 return this.readRecords(o);
12934 // private function a store will implement
12935 onMetaChange : function(meta, recordType, o){
12942 simpleAccess: function(obj, subsc) {
12949 getJsonAccessor: function(){
12951 return function(expr) {
12953 return(re.test(expr))
12954 ? new Function("obj", "return obj." + expr)
12959 return Roo.emptyFn;
12964 * Create a data block containing Roo.data.Records from an XML document.
12965 * @param {Object} o An object which contains an Array of row objects in the property specified
12966 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
12967 * which contains the total size of the dataset.
12968 * @return {Object} data A data block which is used by an Roo.data.Store object as
12969 * a cache of Roo.data.Records.
12971 readRecords : function(o){
12973 * After any data loads, the raw JSON data is available for further custom processing.
12977 var s = this.meta, Record = this.recordType,
12978 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
12980 // Generate extraction functions for the totalProperty, the root, the id, and for each field
12982 if(s.totalProperty) {
12983 this.getTotal = this.getJsonAccessor(s.totalProperty);
12985 if(s.successProperty) {
12986 this.getSuccess = this.getJsonAccessor(s.successProperty);
12988 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
12990 var g = this.getJsonAccessor(s.id);
12991 this.getId = function(rec) {
12993 return (r === undefined || r === "") ? null : r;
12996 this.getId = function(){return null;};
12999 for(var jj = 0; jj < fl; jj++){
13001 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
13002 this.ef[jj] = this.getJsonAccessor(map);
13006 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
13007 if(s.totalProperty){
13008 var vt = parseInt(this.getTotal(o), 10);
13013 if(s.successProperty){
13014 var vs = this.getSuccess(o);
13015 if(vs === false || vs === 'false'){
13020 for(var i = 0; i < c; i++){
13023 var id = this.getId(n);
13024 for(var j = 0; j < fl; j++){
13026 var v = this.ef[j](n);
13028 Roo.log('missing convert for ' + f.name);
13032 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
13034 var record = new Record(values, id);
13036 records[i] = record;
13042 totalRecords : totalRecords
13047 * Ext JS Library 1.1.1
13048 * Copyright(c) 2006-2007, Ext JS, LLC.
13050 * Originally Released Under LGPL - original licence link has changed is not relivant.
13053 * <script type="text/javascript">
13057 * @class Roo.data.ArrayReader
13058 * @extends Roo.data.DataReader
13059 * Data reader class to create an Array of Roo.data.Record objects from an Array.
13060 * Each element of that Array represents a row of data fields. The
13061 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
13062 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
13066 var RecordDef = Roo.data.Record.create([
13067 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
13068 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
13070 var myReader = new Roo.data.ArrayReader({
13071 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
13075 * This would consume an Array like this:
13077 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
13081 * Create a new JsonReader
13082 * @param {Object} meta Metadata configuration options.
13083 * @param {Object|Array} recordType Either an Array of field definition objects
13085 * @cfg {Array} fields Array of field definition objects
13086 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
13087 * as specified to {@link Roo.data.Record#create},
13088 * or an {@link Roo.data.Record} object
13091 * created using {@link Roo.data.Record#create}.
13093 Roo.data.ArrayReader = function(meta, recordType){
13096 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType||meta.fields);
13099 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
13101 * Create a data block containing Roo.data.Records from an XML document.
13102 * @param {Object} o An Array of row objects which represents the dataset.
13103 * @return {Object} A data block which is used by an {@link Roo.data.Store} object as
13104 * a cache of Roo.data.Records.
13106 readRecords : function(o){
13107 var sid = this.meta ? this.meta.id : null;
13108 var recordType = this.recordType, fields = recordType.prototype.fields;
13111 for(var i = 0; i < root.length; i++){
13114 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
13115 for(var j = 0, jlen = fields.length; j < jlen; j++){
13116 var f = fields.items[j];
13117 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
13118 var v = n[k] !== undefined ? n[k] : f.defaultValue;
13120 values[f.name] = v;
13122 var record = new recordType(values, id);
13124 records[records.length] = record;
13128 totalRecords : records.length
13137 * @class Roo.bootstrap.ComboBox
13138 * @extends Roo.bootstrap.TriggerField
13139 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
13140 * @cfg {Boolean} append (true|false) default false
13141 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
13142 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
13143 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
13144 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
13145 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
13146 * @cfg {Boolean} animate default true
13147 * @cfg {Boolean} emptyResultText only for touch device
13148 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
13149 * @cfg {String} emptyTitle default ''
13151 * Create a new ComboBox.
13152 * @param {Object} config Configuration options
13154 Roo.bootstrap.ComboBox = function(config){
13155 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
13159 * Fires when the dropdown list is expanded
13160 * @param {Roo.bootstrap.ComboBox} combo This combo box
13165 * Fires when the dropdown list is collapsed
13166 * @param {Roo.bootstrap.ComboBox} combo This combo box
13170 * @event beforeselect
13171 * Fires before a list item is selected. Return false to cancel the selection.
13172 * @param {Roo.bootstrap.ComboBox} combo This combo box
13173 * @param {Roo.data.Record} record The data record returned from the underlying store
13174 * @param {Number} index The index of the selected item in the dropdown list
13176 'beforeselect' : true,
13179 * Fires when a list item is selected
13180 * @param {Roo.bootstrap.ComboBox} combo This combo box
13181 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
13182 * @param {Number} index The index of the selected item in the dropdown list
13186 * @event beforequery
13187 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
13188 * The event object passed has these properties:
13189 * @param {Roo.bootstrap.ComboBox} combo This combo box
13190 * @param {String} query The query
13191 * @param {Boolean} forceAll true to force "all" query
13192 * @param {Boolean} cancel true to cancel the query
13193 * @param {Object} e The query event object
13195 'beforequery': true,
13198 * Fires when the 'add' icon is pressed (add a listener to enable add button)
13199 * @param {Roo.bootstrap.ComboBox} combo This combo box
13204 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
13205 * @param {Roo.bootstrap.ComboBox} combo This combo box
13206 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
13211 * Fires when the remove value from the combobox array
13212 * @param {Roo.bootstrap.ComboBox} combo This combo box
13216 * @event afterremove
13217 * Fires when the remove value from the combobox array
13218 * @param {Roo.bootstrap.ComboBox} combo This combo box
13220 'afterremove' : true,
13222 * @event specialfilter
13223 * Fires when specialfilter
13224 * @param {Roo.bootstrap.ComboBox} combo This combo box
13226 'specialfilter' : true,
13229 * Fires when tick the element
13230 * @param {Roo.bootstrap.ComboBox} combo This combo box
13234 * @event touchviewdisplay
13235 * Fires when touch view require special display (default is using displayField)
13236 * @param {Roo.bootstrap.ComboBox} combo This combo box
13237 * @param {Object} cfg set html .
13239 'touchviewdisplay' : true
13244 this.tickItems = [];
13246 this.selectedIndex = -1;
13247 if(this.mode == 'local'){
13248 if(config.queryDelay === undefined){
13249 this.queryDelay = 10;
13251 if(config.minChars === undefined){
13257 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
13260 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
13261 * rendering into an Roo.Editor, defaults to false)
13264 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
13265 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
13268 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
13271 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
13272 * the dropdown list (defaults to undefined, with no header element)
13276 * @cfg {String/Roo.Template} tpl The template to use to render the output
13280 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
13282 listWidth: undefined,
13284 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
13285 * mode = 'remote' or 'text' if mode = 'local')
13287 displayField: undefined,
13290 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
13291 * mode = 'remote' or 'value' if mode = 'local').
13292 * Note: use of a valueField requires the user make a selection
13293 * in order for a value to be mapped.
13295 valueField: undefined,
13297 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
13302 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
13303 * field's data value (defaults to the underlying DOM element's name)
13305 hiddenName: undefined,
13307 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
13311 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
13313 selectedClass: 'active',
13316 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
13320 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
13321 * anchor positions (defaults to 'tl-bl')
13323 listAlign: 'tl-bl?',
13325 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
13329 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
13330 * query specified by the allQuery config option (defaults to 'query')
13332 triggerAction: 'query',
13334 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
13335 * (defaults to 4, does not apply if editable = false)
13339 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
13340 * delay (typeAheadDelay) if it matches a known value (defaults to false)
13344 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
13345 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
13349 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
13350 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
13354 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
13355 * when editable = true (defaults to false)
13357 selectOnFocus:false,
13359 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
13361 queryParam: 'query',
13363 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
13364 * when mode = 'remote' (defaults to 'Loading...')
13366 loadingText: 'Loading...',
13368 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
13372 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
13376 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
13377 * traditional select (defaults to true)
13381 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
13385 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
13389 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
13390 * listWidth has a higher value)
13394 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
13395 * allow the user to set arbitrary text into the field (defaults to false)
13397 forceSelection:false,
13399 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
13400 * if typeAhead = true (defaults to 250)
13402 typeAheadDelay : 250,
13404 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
13405 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
13407 valueNotFoundText : undefined,
13409 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
13411 blockFocus : false,
13414 * @cfg {Boolean} disableClear Disable showing of clear button.
13416 disableClear : false,
13418 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
13420 alwaysQuery : false,
13423 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
13428 * @cfg {String} invalidClass DEPRICATED - uses BS4 is-valid now
13430 invalidClass : "has-warning",
13433 * @cfg {String} validClass DEPRICATED - uses BS4 is-valid now
13435 validClass : "has-success",
13438 * @cfg {Boolean} specialFilter (true|false) special filter default false
13440 specialFilter : false,
13443 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
13445 mobileTouchView : true,
13448 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
13450 useNativeIOS : false,
13453 * @cfg {Boolean} mobile_restrict_height (true|false) restrict height for touch view
13455 mobile_restrict_height : false,
13457 ios_options : false,
13469 btnPosition : 'right',
13470 triggerList : true,
13471 showToggleBtn : true,
13473 emptyResultText: 'Empty',
13474 triggerText : 'Select',
13477 // element that contains real text value.. (when hidden is used..)
13479 getAutoCreate : function()
13484 * Render classic select for iso
13487 if(Roo.isIOS && this.useNativeIOS){
13488 cfg = this.getAutoCreateNativeIOS();
13496 if(Roo.isTouch && this.mobileTouchView){
13497 cfg = this.getAutoCreateTouchView();
13504 if(!this.tickable){
13505 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
13510 * ComboBox with tickable selections
13513 var align = this.labelAlign || this.parentLabelAlign();
13516 cls : 'form-group roo-combobox-tickable' //input-group
13519 var btn_text_select = '';
13520 var btn_text_done = '';
13521 var btn_text_cancel = '';
13523 if (this.btn_text_show) {
13524 btn_text_select = 'Select';
13525 btn_text_done = 'Done';
13526 btn_text_cancel = 'Cancel';
13531 cls : 'tickable-buttons',
13536 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
13537 //html : this.triggerText
13538 html: btn_text_select
13544 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
13546 html: btn_text_done
13552 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
13554 html: btn_text_cancel
13560 buttons.cn.unshift({
13562 cls: 'roo-select2-search-field-input'
13568 Roo.each(buttons.cn, function(c){
13570 c.cls += ' btn-' + _this.size;
13573 if (_this.disabled) {
13580 style : 'display: contents',
13585 cls: 'form-hidden-field'
13589 cls: 'roo-select2-choices',
13593 cls: 'roo-select2-search-field',
13604 cls: 'roo-select2-container input-group roo-select2-container-multi',
13610 // cls: 'typeahead typeahead-long dropdown-menu',
13611 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
13616 if(this.hasFeedback && !this.allowBlank){
13620 cls: 'glyphicon form-control-feedback'
13623 combobox.cn.push(feedback);
13628 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
13629 tooltip : 'This field is required'
13631 if (Roo.bootstrap.version == 4) {
13634 style : 'display:none'
13637 if (align ==='left' && this.fieldLabel.length) {
13639 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
13646 cls : 'control-label col-form-label',
13647 html : this.fieldLabel
13659 var labelCfg = cfg.cn[1];
13660 var contentCfg = cfg.cn[2];
13663 if(this.indicatorpos == 'right'){
13669 cls : 'control-label col-form-label',
13673 html : this.fieldLabel
13689 labelCfg = cfg.cn[0];
13690 contentCfg = cfg.cn[1];
13694 if(this.labelWidth > 12){
13695 labelCfg.style = "width: " + this.labelWidth + 'px';
13698 if(this.labelWidth < 13 && this.labelmd == 0){
13699 this.labelmd = this.labelWidth;
13702 if(this.labellg > 0){
13703 labelCfg.cls += ' col-lg-' + this.labellg;
13704 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
13707 if(this.labelmd > 0){
13708 labelCfg.cls += ' col-md-' + this.labelmd;
13709 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
13712 if(this.labelsm > 0){
13713 labelCfg.cls += ' col-sm-' + this.labelsm;
13714 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
13717 if(this.labelxs > 0){
13718 labelCfg.cls += ' col-xs-' + this.labelxs;
13719 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
13723 } else if ( this.fieldLabel.length) {
13724 // Roo.log(" label");
13729 //cls : 'input-group-addon',
13730 html : this.fieldLabel
13735 if(this.indicatorpos == 'right'){
13739 //cls : 'input-group-addon',
13740 html : this.fieldLabel
13750 // Roo.log(" no label && no align");
13757 ['xs','sm','md','lg'].map(function(size){
13758 if (settings[size]) {
13759 cfg.cls += ' col-' + size + '-' + settings[size];
13767 _initEventsCalled : false,
13770 initEvents: function()
13772 if (this._initEventsCalled) { // as we call render... prevent looping...
13775 this._initEventsCalled = true;
13778 throw "can not find store for combo";
13781 this.indicator = this.indicatorEl();
13783 this.store = Roo.factory(this.store, Roo.data);
13784 this.store.parent = this;
13786 // if we are building from html. then this element is so complex, that we can not really
13787 // use the rendered HTML.
13788 // so we have to trash and replace the previous code.
13789 if (Roo.XComponent.build_from_html) {
13790 // remove this element....
13791 var e = this.el.dom, k=0;
13792 while (e ) { e = e.previousSibling; ++k;}
13797 this.rendered = false;
13799 this.render(this.parent().getChildContainer(true), k);
13802 if(Roo.isIOS && this.useNativeIOS){
13803 this.initIOSView();
13811 if(Roo.isTouch && this.mobileTouchView){
13812 this.initTouchView();
13817 this.initTickableEvents();
13821 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
13823 if(this.hiddenName){
13825 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13827 this.hiddenField.dom.value =
13828 this.hiddenValue !== undefined ? this.hiddenValue :
13829 this.value !== undefined ? this.value : '';
13831 // prevent input submission
13832 this.el.dom.removeAttribute('name');
13833 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13838 // this.el.dom.setAttribute('autocomplete', 'off');
13841 var cls = 'x-combo-list';
13843 //this.list = new Roo.Layer({
13844 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
13850 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13851 _this.list.setWidth(lw);
13854 this.list.on('mouseover', this.onViewOver, this);
13855 this.list.on('mousemove', this.onViewMove, this);
13856 this.list.on('scroll', this.onViewScroll, this);
13859 this.list.swallowEvent('mousewheel');
13860 this.assetHeight = 0;
13863 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
13864 this.assetHeight += this.header.getHeight();
13867 this.innerList = this.list.createChild({cls:cls+'-inner'});
13868 this.innerList.on('mouseover', this.onViewOver, this);
13869 this.innerList.on('mousemove', this.onViewMove, this);
13870 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13872 if(this.allowBlank && !this.pageSize && !this.disableClear){
13873 this.footer = this.list.createChild({cls:cls+'-ft'});
13874 this.pageTb = new Roo.Toolbar(this.footer);
13878 this.footer = this.list.createChild({cls:cls+'-ft'});
13879 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
13880 {pageSize: this.pageSize});
13884 if (this.pageTb && this.allowBlank && !this.disableClear) {
13886 this.pageTb.add(new Roo.Toolbar.Fill(), {
13887 cls: 'x-btn-icon x-btn-clear',
13889 handler: function()
13892 _this.clearValue();
13893 _this.onSelect(false, -1);
13898 this.assetHeight += this.footer.getHeight();
13903 this.tpl = Roo.bootstrap.version == 4 ?
13904 '<a class="dropdown-item" href="#">{' + this.displayField + '}</a>' : // 4 does not need <li> and it get's really confisued.
13905 '<li><a class="dropdown-item" href="#">{' + this.displayField + '}</a></li>';
13908 this.view = new Roo.View(this.list, this.tpl, {
13909 singleSelect:true, store: this.store, selectedClass: this.selectedClass
13911 //this.view.wrapEl.setDisplayed(false);
13912 this.view.on('click', this.onViewClick, this);
13915 this.store.on('beforeload', this.onBeforeLoad, this);
13916 this.store.on('load', this.onLoad, this);
13917 this.store.on('loadexception', this.onLoadException, this);
13919 if(this.resizable){
13920 this.resizer = new Roo.Resizable(this.list, {
13921 pinned:true, handles:'se'
13923 this.resizer.on('resize', function(r, w, h){
13924 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
13925 this.listWidth = w;
13926 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
13927 this.restrictHeight();
13929 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
13932 if(!this.editable){
13933 this.editable = true;
13934 this.setEditable(false);
13939 if (typeof(this.events.add.listeners) != 'undefined') {
13941 this.addicon = this.wrap.createChild(
13942 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
13944 this.addicon.on('click', function(e) {
13945 this.fireEvent('add', this);
13948 if (typeof(this.events.edit.listeners) != 'undefined') {
13950 this.editicon = this.wrap.createChild(
13951 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
13952 if (this.addicon) {
13953 this.editicon.setStyle('margin-left', '40px');
13955 this.editicon.on('click', function(e) {
13957 // we fire even if inothing is selected..
13958 this.fireEvent('edit', this, this.lastData );
13964 this.keyNav = new Roo.KeyNav(this.inputEl(), {
13965 "up" : function(e){
13966 this.inKeyMode = true;
13970 "down" : function(e){
13971 if(!this.isExpanded()){
13972 this.onTriggerClick();
13974 this.inKeyMode = true;
13979 "enter" : function(e){
13980 // this.onViewClick();
13984 if(this.fireEvent("specialkey", this, e)){
13985 this.onViewClick(false);
13991 "esc" : function(e){
13995 "tab" : function(e){
13998 if(this.fireEvent("specialkey", this, e)){
13999 this.onViewClick(false);
14007 doRelay : function(foo, bar, hname){
14008 if(hname == 'down' || this.scope.isExpanded()){
14009 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
14018 this.queryDelay = Math.max(this.queryDelay || 10,
14019 this.mode == 'local' ? 10 : 250);
14022 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
14024 if(this.typeAhead){
14025 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
14027 if(this.editable !== false){
14028 this.inputEl().on("keyup", this.onKeyUp, this);
14030 if(this.forceSelection){
14031 this.inputEl().on('blur', this.doForce, this);
14035 this.choices = this.el.select('ul.roo-select2-choices', true).first();
14036 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
14040 initTickableEvents: function()
14044 if(this.hiddenName){
14046 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
14048 this.hiddenField.dom.value =
14049 this.hiddenValue !== undefined ? this.hiddenValue :
14050 this.value !== undefined ? this.value : '';
14052 // prevent input submission
14053 this.el.dom.removeAttribute('name');
14054 this.hiddenField.dom.setAttribute('name', this.hiddenName);
14059 // this.list = this.el.select('ul.dropdown-menu',true).first();
14061 this.choices = this.el.select('ul.roo-select2-choices', true).first();
14062 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
14063 if(this.triggerList){
14064 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
14067 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
14068 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
14070 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
14071 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
14073 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
14074 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
14076 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
14077 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
14078 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
14081 this.cancelBtn.hide();
14086 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
14087 _this.list.setWidth(lw);
14090 this.list.on('mouseover', this.onViewOver, this);
14091 this.list.on('mousemove', this.onViewMove, this);
14093 this.list.on('scroll', this.onViewScroll, this);
14096 this.tpl = '<li class="roo-select2-result"><div class="checkbox"><input id="{roo-id}"' +
14097 'type="checkbox" {roo-data-checked}><label for="{roo-id}"><b>{' + this.displayField + '}</b></label></div></li>';
14100 this.view = new Roo.View(this.list, this.tpl, {
14105 selectedClass: this.selectedClass
14108 //this.view.wrapEl.setDisplayed(false);
14109 this.view.on('click', this.onViewClick, this);
14113 this.store.on('beforeload', this.onBeforeLoad, this);
14114 this.store.on('load', this.onLoad, this);
14115 this.store.on('loadexception', this.onLoadException, this);
14118 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
14119 "up" : function(e){
14120 this.inKeyMode = true;
14124 "down" : function(e){
14125 this.inKeyMode = true;
14129 "enter" : function(e){
14130 if(this.fireEvent("specialkey", this, e)){
14131 this.onViewClick(false);
14137 "esc" : function(e){
14138 this.onTickableFooterButtonClick(e, false, false);
14141 "tab" : function(e){
14142 this.fireEvent("specialkey", this, e);
14144 this.onTickableFooterButtonClick(e, false, false);
14151 doRelay : function(e, fn, key){
14152 if(this.scope.isExpanded()){
14153 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
14162 this.queryDelay = Math.max(this.queryDelay || 10,
14163 this.mode == 'local' ? 10 : 250);
14166 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
14168 if(this.typeAhead){
14169 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
14172 if(this.editable !== false){
14173 this.tickableInputEl().on("keyup", this.onKeyUp, this);
14176 this.indicator = this.indicatorEl();
14178 if(this.indicator){
14179 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
14180 this.indicator.hide();
14185 onDestroy : function(){
14187 this.view.setStore(null);
14188 this.view.el.removeAllListeners();
14189 this.view.el.remove();
14190 this.view.purgeListeners();
14193 this.list.dom.innerHTML = '';
14197 this.store.un('beforeload', this.onBeforeLoad, this);
14198 this.store.un('load', this.onLoad, this);
14199 this.store.un('loadexception', this.onLoadException, this);
14201 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
14205 fireKey : function(e){
14206 if(e.isNavKeyPress() && !this.list.isVisible()){
14207 this.fireEvent("specialkey", this, e);
14212 onResize: function(w, h){
14213 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
14215 // if(typeof w != 'number'){
14216 // // we do not handle it!?!?
14219 // var tw = this.trigger.getWidth();
14220 // // tw += this.addicon ? this.addicon.getWidth() : 0;
14221 // // tw += this.editicon ? this.editicon.getWidth() : 0;
14223 // this.inputEl().setWidth( this.adjustWidth('input', x));
14225 // //this.trigger.setStyle('left', x+'px');
14227 // if(this.list && this.listWidth === undefined){
14228 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
14229 // this.list.setWidth(lw);
14230 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
14238 * Allow or prevent the user from directly editing the field text. If false is passed,
14239 * the user will only be able to select from the items defined in the dropdown list. This method
14240 * is the runtime equivalent of setting the 'editable' config option at config time.
14241 * @param {Boolean} value True to allow the user to directly edit the field text
14243 setEditable : function(value){
14244 if(value == this.editable){
14247 this.editable = value;
14249 this.inputEl().dom.setAttribute('readOnly', true);
14250 this.inputEl().on('mousedown', this.onTriggerClick, this);
14251 this.inputEl().addClass('x-combo-noedit');
14253 this.inputEl().dom.setAttribute('readOnly', false);
14254 this.inputEl().un('mousedown', this.onTriggerClick, this);
14255 this.inputEl().removeClass('x-combo-noedit');
14261 onBeforeLoad : function(combo,opts){
14262 if(!this.hasFocus){
14266 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
14268 this.restrictHeight();
14269 this.selectedIndex = -1;
14273 onLoad : function(){
14275 this.hasQuery = false;
14277 if(!this.hasFocus){
14281 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
14282 this.loading.hide();
14285 if(this.store.getCount() > 0){
14288 this.restrictHeight();
14289 if(this.lastQuery == this.allQuery){
14290 if(this.editable && !this.tickable){
14291 this.inputEl().dom.select();
14295 !this.selectByValue(this.value, true) &&
14298 !this.store.lastOptions ||
14299 typeof(this.store.lastOptions.add) == 'undefined' ||
14300 this.store.lastOptions.add != true
14303 this.select(0, true);
14306 if(this.autoFocus){
14309 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
14310 this.taTask.delay(this.typeAheadDelay);
14314 this.onEmptyResults();
14320 onLoadException : function()
14322 this.hasQuery = false;
14324 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
14325 this.loading.hide();
14328 if(this.tickable && this.editable){
14333 // only causes errors at present
14334 //Roo.log(this.store.reader.jsonData);
14335 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
14337 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
14343 onTypeAhead : function(){
14344 if(this.store.getCount() > 0){
14345 var r = this.store.getAt(0);
14346 var newValue = r.data[this.displayField];
14347 var len = newValue.length;
14348 var selStart = this.getRawValue().length;
14350 if(selStart != len){
14351 this.setRawValue(newValue);
14352 this.selectText(selStart, newValue.length);
14358 onSelect : function(record, index){
14360 if(this.fireEvent('beforeselect', this, record, index) !== false){
14362 this.setFromData(index > -1 ? record.data : false);
14365 this.fireEvent('select', this, record, index);
14370 * Returns the currently selected field value or empty string if no value is set.
14371 * @return {String} value The selected value
14373 getValue : function()
14375 if(Roo.isIOS && this.useNativeIOS){
14376 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
14380 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
14383 if(this.valueField){
14384 return typeof this.value != 'undefined' ? this.value : '';
14386 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
14390 getRawValue : function()
14392 if(Roo.isIOS && this.useNativeIOS){
14393 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
14396 var v = this.inputEl().getValue();
14402 * Clears any text/value currently set in the field
14404 clearValue : function(){
14406 if(this.hiddenField){
14407 this.hiddenField.dom.value = '';
14410 this.setRawValue('');
14411 this.lastSelectionText = '';
14412 this.lastData = false;
14414 var close = this.closeTriggerEl();
14425 * Sets the specified value into the field. If the value finds a match, the corresponding record text
14426 * will be displayed in the field. If the value does not match the data value of an existing item,
14427 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
14428 * Otherwise the field will be blank (although the value will still be set).
14429 * @param {String} value The value to match
14431 setValue : function(v)
14433 if(Roo.isIOS && this.useNativeIOS){
14434 this.setIOSValue(v);
14444 if(this.valueField){
14445 var r = this.findRecord(this.valueField, v);
14447 text = r.data[this.displayField];
14448 }else if(this.valueNotFoundText !== undefined){
14449 text = this.valueNotFoundText;
14452 this.lastSelectionText = text;
14453 if(this.hiddenField){
14454 this.hiddenField.dom.value = v;
14456 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
14459 var close = this.closeTriggerEl();
14462 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
14468 * @property {Object} the last set data for the element
14473 * Sets the value of the field based on a object which is related to the record format for the store.
14474 * @param {Object} value the value to set as. or false on reset?
14476 setFromData : function(o){
14483 var dv = ''; // display value
14484 var vv = ''; // value value..
14486 if (this.displayField) {
14487 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14489 // this is an error condition!!!
14490 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14493 if(this.valueField){
14494 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
14497 var close = this.closeTriggerEl();
14500 if(dv.length || vv * 1 > 0){
14502 this.blockFocus=true;
14508 if(this.hiddenField){
14509 this.hiddenField.dom.value = vv;
14511 this.lastSelectionText = dv;
14512 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14516 // no hidden field.. - we store the value in 'value', but still display
14517 // display field!!!!
14518 this.lastSelectionText = dv;
14519 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14526 reset : function(){
14527 // overridden so that last data is reset..
14534 this.setValue(this.originalValue);
14535 //this.clearInvalid();
14536 this.lastData = false;
14538 this.view.clearSelections();
14544 findRecord : function(prop, value){
14546 if(this.store.getCount() > 0){
14547 this.store.each(function(r){
14548 if(r.data[prop] == value){
14558 getName: function()
14560 // returns hidden if it's set..
14561 if (!this.rendered) {return ''};
14562 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
14566 onViewMove : function(e, t){
14567 this.inKeyMode = false;
14571 onViewOver : function(e, t){
14572 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
14575 var item = this.view.findItemFromChild(t);
14578 var index = this.view.indexOf(item);
14579 this.select(index, false);
14584 onViewClick : function(view, doFocus, el, e)
14586 var index = this.view.getSelectedIndexes()[0];
14588 var r = this.store.getAt(index);
14592 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
14599 Roo.each(this.tickItems, function(v,k){
14601 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
14603 _this.tickItems.splice(k, 1);
14605 if(typeof(e) == 'undefined' && view == false){
14606 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
14618 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
14619 this.tickItems.push(r.data);
14622 if(typeof(e) == 'undefined' && view == false){
14623 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
14630 this.onSelect(r, index);
14632 if(doFocus !== false && !this.blockFocus){
14633 this.inputEl().focus();
14638 restrictHeight : function(){
14639 //this.innerList.dom.style.height = '';
14640 //var inner = this.innerList.dom;
14641 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
14642 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
14643 //this.list.beginUpdate();
14644 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
14645 this.list.alignTo(this.inputEl(), this.listAlign);
14646 this.list.alignTo(this.inputEl(), this.listAlign);
14647 //this.list.endUpdate();
14651 onEmptyResults : function(){
14653 if(this.tickable && this.editable){
14654 this.hasFocus = false;
14655 this.restrictHeight();
14663 * Returns true if the dropdown list is expanded, else false.
14665 isExpanded : function(){
14666 return this.list.isVisible();
14670 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
14671 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14672 * @param {String} value The data value of the item to select
14673 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14674 * selected item if it is not currently in view (defaults to true)
14675 * @return {Boolean} True if the value matched an item in the list, else false
14677 selectByValue : function(v, scrollIntoView){
14678 if(v !== undefined && v !== null){
14679 var r = this.findRecord(this.valueField || this.displayField, v);
14681 this.select(this.store.indexOf(r), scrollIntoView);
14689 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
14690 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14691 * @param {Number} index The zero-based index of the list item to select
14692 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14693 * selected item if it is not currently in view (defaults to true)
14695 select : function(index, scrollIntoView){
14696 this.selectedIndex = index;
14697 this.view.select(index);
14698 if(scrollIntoView !== false){
14699 var el = this.view.getNode(index);
14701 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
14704 this.list.scrollChildIntoView(el, false);
14710 selectNext : function(){
14711 var ct = this.store.getCount();
14713 if(this.selectedIndex == -1){
14715 }else if(this.selectedIndex < ct-1){
14716 this.select(this.selectedIndex+1);
14722 selectPrev : function(){
14723 var ct = this.store.getCount();
14725 if(this.selectedIndex == -1){
14727 }else if(this.selectedIndex != 0){
14728 this.select(this.selectedIndex-1);
14734 onKeyUp : function(e){
14735 if(this.editable !== false && !e.isSpecialKey()){
14736 this.lastKey = e.getKey();
14737 this.dqTask.delay(this.queryDelay);
14742 validateBlur : function(){
14743 return !this.list || !this.list.isVisible();
14747 initQuery : function(){
14749 var v = this.getRawValue();
14751 if(this.tickable && this.editable){
14752 v = this.tickableInputEl().getValue();
14759 doForce : function(){
14760 if(this.inputEl().dom.value.length > 0){
14761 this.inputEl().dom.value =
14762 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
14768 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
14769 * query allowing the query action to be canceled if needed.
14770 * @param {String} query The SQL query to execute
14771 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
14772 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
14773 * saved in the current store (defaults to false)
14775 doQuery : function(q, forceAll){
14777 if(q === undefined || q === null){
14782 forceAll: forceAll,
14786 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
14791 forceAll = qe.forceAll;
14792 if(forceAll === true || (q.length >= this.minChars)){
14794 this.hasQuery = true;
14796 if(this.lastQuery != q || this.alwaysQuery){
14797 this.lastQuery = q;
14798 if(this.mode == 'local'){
14799 this.selectedIndex = -1;
14801 this.store.clearFilter();
14804 if(this.specialFilter){
14805 this.fireEvent('specialfilter', this);
14810 this.store.filter(this.displayField, q);
14813 this.store.fireEvent("datachanged", this.store);
14820 this.store.baseParams[this.queryParam] = q;
14822 var options = {params : this.getParams(q)};
14825 options.add = true;
14826 options.params.start = this.page * this.pageSize;
14829 this.store.load(options);
14832 * this code will make the page width larger, at the beginning, the list not align correctly,
14833 * we should expand the list on onLoad
14834 * so command out it
14839 this.selectedIndex = -1;
14844 this.loadNext = false;
14848 getParams : function(q){
14850 //p[this.queryParam] = q;
14854 p.limit = this.pageSize;
14860 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
14862 collapse : function(){
14863 if(!this.isExpanded()){
14869 this.hasFocus = false;
14873 this.cancelBtn.hide();
14874 this.trigger.show();
14877 this.tickableInputEl().dom.value = '';
14878 this.tickableInputEl().blur();
14883 Roo.get(document).un('mousedown', this.collapseIf, this);
14884 Roo.get(document).un('mousewheel', this.collapseIf, this);
14885 if (!this.editable) {
14886 Roo.get(document).un('keydown', this.listKeyPress, this);
14888 this.fireEvent('collapse', this);
14894 collapseIf : function(e){
14895 var in_combo = e.within(this.el);
14896 var in_list = e.within(this.list);
14897 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
14899 if (in_combo || in_list || is_list) {
14900 //e.stopPropagation();
14905 this.onTickableFooterButtonClick(e, false, false);
14913 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
14915 expand : function(){
14917 if(this.isExpanded() || !this.hasFocus){
14921 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
14922 this.list.setWidth(lw);
14928 this.restrictHeight();
14932 this.tickItems = Roo.apply([], this.item);
14935 this.cancelBtn.show();
14936 this.trigger.hide();
14939 this.tickableInputEl().focus();
14944 Roo.get(document).on('mousedown', this.collapseIf, this);
14945 Roo.get(document).on('mousewheel', this.collapseIf, this);
14946 if (!this.editable) {
14947 Roo.get(document).on('keydown', this.listKeyPress, this);
14950 this.fireEvent('expand', this);
14954 // Implements the default empty TriggerField.onTriggerClick function
14955 onTriggerClick : function(e)
14957 Roo.log('trigger click');
14959 if(this.disabled || !this.triggerList){
14964 this.loadNext = false;
14966 if(this.isExpanded()){
14968 if (!this.blockFocus) {
14969 this.inputEl().focus();
14973 this.hasFocus = true;
14974 if(this.triggerAction == 'all') {
14975 this.doQuery(this.allQuery, true);
14977 this.doQuery(this.getRawValue());
14979 if (!this.blockFocus) {
14980 this.inputEl().focus();
14985 onTickableTriggerClick : function(e)
14992 this.loadNext = false;
14993 this.hasFocus = true;
14995 if(this.triggerAction == 'all') {
14996 this.doQuery(this.allQuery, true);
14998 this.doQuery(this.getRawValue());
15002 onSearchFieldClick : function(e)
15004 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
15005 this.onTickableFooterButtonClick(e, false, false);
15009 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
15014 this.loadNext = false;
15015 this.hasFocus = true;
15017 if(this.triggerAction == 'all') {
15018 this.doQuery(this.allQuery, true);
15020 this.doQuery(this.getRawValue());
15024 listKeyPress : function(e)
15026 //Roo.log('listkeypress');
15027 // scroll to first matching element based on key pres..
15028 if (e.isSpecialKey()) {
15031 var k = String.fromCharCode(e.getKey()).toUpperCase();
15034 var csel = this.view.getSelectedNodes();
15035 var cselitem = false;
15037 var ix = this.view.indexOf(csel[0]);
15038 cselitem = this.store.getAt(ix);
15039 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
15045 this.store.each(function(v) {
15047 // start at existing selection.
15048 if (cselitem.id == v.id) {
15054 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
15055 match = this.store.indexOf(v);
15061 if (match === false) {
15062 return true; // no more action?
15065 this.view.select(match);
15066 var sn = Roo.get(this.view.getSelectedNodes()[0]);
15067 sn.scrollIntoView(sn.dom.parentNode, false);
15070 onViewScroll : function(e, t){
15072 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){
15076 this.hasQuery = true;
15078 this.loading = this.list.select('.loading', true).first();
15080 if(this.loading === null){
15081 this.list.createChild({
15083 cls: 'loading roo-select2-more-results roo-select2-active',
15084 html: 'Loading more results...'
15087 this.loading = this.list.select('.loading', true).first();
15089 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
15091 this.loading.hide();
15094 this.loading.show();
15099 this.loadNext = true;
15101 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
15106 addItem : function(o)
15108 var dv = ''; // display value
15110 if (this.displayField) {
15111 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
15113 // this is an error condition!!!
15114 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
15121 var choice = this.choices.createChild({
15123 cls: 'roo-select2-search-choice',
15132 cls: 'roo-select2-search-choice-close fa fa-times',
15137 }, this.searchField);
15139 var close = choice.select('a.roo-select2-search-choice-close', true).first();
15141 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
15149 this.inputEl().dom.value = '';
15154 onRemoveItem : function(e, _self, o)
15156 e.preventDefault();
15158 this.lastItem = Roo.apply([], this.item);
15160 var index = this.item.indexOf(o.data) * 1;
15163 Roo.log('not this item?!');
15167 this.item.splice(index, 1);
15172 this.fireEvent('remove', this, e);
15178 syncValue : function()
15180 if(!this.item.length){
15187 Roo.each(this.item, function(i){
15188 if(_this.valueField){
15189 value.push(i[_this.valueField]);
15196 this.value = value.join(',');
15198 if(this.hiddenField){
15199 this.hiddenField.dom.value = this.value;
15202 this.store.fireEvent("datachanged", this.store);
15207 clearItem : function()
15209 if(!this.multiple){
15215 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
15223 if(this.tickable && !Roo.isTouch){
15224 this.view.refresh();
15228 inputEl: function ()
15230 if(Roo.isIOS && this.useNativeIOS){
15231 return this.el.select('select.roo-ios-select', true).first();
15234 if(Roo.isTouch && this.mobileTouchView){
15235 return this.el.select('input.form-control',true).first();
15239 return this.searchField;
15242 return this.el.select('input.form-control',true).first();
15245 onTickableFooterButtonClick : function(e, btn, el)
15247 e.preventDefault();
15249 this.lastItem = Roo.apply([], this.item);
15251 if(btn && btn.name == 'cancel'){
15252 this.tickItems = Roo.apply([], this.item);
15261 Roo.each(this.tickItems, function(o){
15269 validate : function()
15271 if(this.getVisibilityEl().hasClass('hidden')){
15275 var v = this.getRawValue();
15278 v = this.getValue();
15281 if(this.disabled || this.allowBlank || v.length){
15286 this.markInvalid();
15290 tickableInputEl : function()
15292 if(!this.tickable || !this.editable){
15293 return this.inputEl();
15296 return this.inputEl().select('.roo-select2-search-field-input', true).first();
15300 getAutoCreateTouchView : function()
15305 cls: 'form-group' //input-group
15311 type : this.inputType,
15312 cls : 'form-control x-combo-noedit',
15313 autocomplete: 'new-password',
15314 placeholder : this.placeholder || '',
15319 input.name = this.name;
15323 input.cls += ' input-' + this.size;
15326 if (this.disabled) {
15327 input.disabled = true;
15338 inputblock.cls += ' input-group';
15340 inputblock.cn.unshift({
15342 cls : 'input-group-addon input-group-prepend input-group-text',
15347 if(this.removable && !this.multiple){
15348 inputblock.cls += ' roo-removable';
15350 inputblock.cn.push({
15353 cls : 'roo-combo-removable-btn close'
15357 if(this.hasFeedback && !this.allowBlank){
15359 inputblock.cls += ' has-feedback';
15361 inputblock.cn.push({
15363 cls: 'glyphicon form-control-feedback'
15370 inputblock.cls += (this.before) ? '' : ' input-group';
15372 inputblock.cn.push({
15374 cls : 'input-group-addon input-group-append input-group-text',
15380 var ibwrap = inputblock;
15385 cls: 'roo-select2-choices',
15389 cls: 'roo-select2-search-field',
15402 cls: 'roo-select2-container input-group roo-touchview-combobox ',
15407 cls: 'form-hidden-field'
15413 if(!this.multiple && this.showToggleBtn){
15419 if (this.caret != false) {
15422 cls: 'fa fa-' + this.caret
15429 cls : 'input-group-addon input-group-append input-group-text btn dropdown-toggle',
15431 Roo.bootstrap.version == 3 ? caret : '',
15434 cls: 'combobox-clear',
15448 combobox.cls += ' roo-select2-container-multi';
15451 var align = this.labelAlign || this.parentLabelAlign();
15453 if (align ==='left' && this.fieldLabel.length) {
15458 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15459 tooltip : 'This field is required'
15463 cls : 'control-label col-form-label',
15464 html : this.fieldLabel
15475 var labelCfg = cfg.cn[1];
15476 var contentCfg = cfg.cn[2];
15479 if(this.indicatorpos == 'right'){
15484 cls : 'control-label col-form-label',
15488 html : this.fieldLabel
15492 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15493 tooltip : 'This field is required'
15506 labelCfg = cfg.cn[0];
15507 contentCfg = cfg.cn[1];
15512 if(this.labelWidth > 12){
15513 labelCfg.style = "width: " + this.labelWidth + 'px';
15516 if(this.labelWidth < 13 && this.labelmd == 0){
15517 this.labelmd = this.labelWidth;
15520 if(this.labellg > 0){
15521 labelCfg.cls += ' col-lg-' + this.labellg;
15522 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
15525 if(this.labelmd > 0){
15526 labelCfg.cls += ' col-md-' + this.labelmd;
15527 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
15530 if(this.labelsm > 0){
15531 labelCfg.cls += ' col-sm-' + this.labelsm;
15532 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
15535 if(this.labelxs > 0){
15536 labelCfg.cls += ' col-xs-' + this.labelxs;
15537 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
15541 } else if ( this.fieldLabel.length) {
15545 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15546 tooltip : 'This field is required'
15550 cls : 'control-label',
15551 html : this.fieldLabel
15562 if(this.indicatorpos == 'right'){
15566 cls : 'control-label',
15567 html : this.fieldLabel,
15571 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15572 tooltip : 'This field is required'
15589 var settings = this;
15591 ['xs','sm','md','lg'].map(function(size){
15592 if (settings[size]) {
15593 cfg.cls += ' col-' + size + '-' + settings[size];
15600 initTouchView : function()
15602 this.renderTouchView();
15604 this.touchViewEl.on('scroll', function(){
15605 this.el.dom.scrollTop = 0;
15608 this.originalValue = this.getValue();
15610 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
15612 this.inputEl().on("click", this.showTouchView, this);
15613 if (this.triggerEl) {
15614 this.triggerEl.on("click", this.showTouchView, this);
15618 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
15619 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
15621 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
15623 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
15624 this.store.on('load', this.onTouchViewLoad, this);
15625 this.store.on('loadexception', this.onTouchViewLoadException, this);
15627 if(this.hiddenName){
15629 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
15631 this.hiddenField.dom.value =
15632 this.hiddenValue !== undefined ? this.hiddenValue :
15633 this.value !== undefined ? this.value : '';
15635 this.el.dom.removeAttribute('name');
15636 this.hiddenField.dom.setAttribute('name', this.hiddenName);
15640 this.choices = this.el.select('ul.roo-select2-choices', true).first();
15641 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
15644 if(this.removable && !this.multiple){
15645 var close = this.closeTriggerEl();
15647 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
15648 close.on('click', this.removeBtnClick, this, close);
15652 * fix the bug in Safari iOS8
15654 this.inputEl().on("focus", function(e){
15655 document.activeElement.blur();
15658 this._touchViewMask = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
15665 renderTouchView : function()
15667 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
15668 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15670 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
15671 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15673 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
15674 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15675 this.touchViewBodyEl.setStyle('overflow', 'auto');
15677 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
15678 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15680 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
15681 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15685 showTouchView : function()
15691 this.touchViewHeaderEl.hide();
15693 if(this.modalTitle.length){
15694 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
15695 this.touchViewHeaderEl.show();
15698 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
15699 this.touchViewEl.show();
15701 this.touchViewEl.select('.modal-dialog', true).first().setStyle({ margin : '0px', width : '100%'});
15703 //this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
15704 // Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15706 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15708 if(this.modalTitle.length){
15709 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15712 this.touchViewBodyEl.setHeight(bodyHeight);
15716 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
15718 this.touchViewEl.addClass('in');
15721 if(this._touchViewMask){
15722 Roo.get(document.body).addClass("x-body-masked");
15723 this._touchViewMask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15724 this._touchViewMask.setStyle('z-index', 10000);
15725 this._touchViewMask.addClass('show');
15728 this.doTouchViewQuery();
15732 hideTouchView : function()
15734 this.touchViewEl.removeClass('in');
15738 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
15740 this.touchViewEl.setStyle('display', 'none');
15743 if(this._touchViewMask){
15744 this._touchViewMask.removeClass('show');
15745 Roo.get(document.body).removeClass("x-body-masked");
15749 setTouchViewValue : function()
15756 Roo.each(this.tickItems, function(o){
15761 this.hideTouchView();
15764 doTouchViewQuery : function()
15773 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
15777 if(!this.alwaysQuery || this.mode == 'local'){
15778 this.onTouchViewLoad();
15785 onTouchViewBeforeLoad : function(combo,opts)
15791 onTouchViewLoad : function()
15793 if(this.store.getCount() < 1){
15794 this.onTouchViewEmptyResults();
15798 this.clearTouchView();
15800 var rawValue = this.getRawValue();
15802 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
15804 this.tickItems = [];
15806 this.store.data.each(function(d, rowIndex){
15807 var row = this.touchViewListGroup.createChild(template);
15809 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
15810 row.addClass(d.data.cls);
15813 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15816 html : d.data[this.displayField]
15819 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
15820 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
15823 row.removeClass('selected');
15824 if(!this.multiple && this.valueField &&
15825 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
15828 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15829 row.addClass('selected');
15832 if(this.multiple && this.valueField &&
15833 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
15837 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15838 this.tickItems.push(d.data);
15841 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
15845 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
15847 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15849 if(this.modalTitle.length){
15850 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15853 var listHeight = this.touchViewListGroup.getHeight() + this.touchViewBodyEl.getPadding('tb') * 2;
15855 if(this.mobile_restrict_height && listHeight < bodyHeight){
15856 this.touchViewBodyEl.setHeight(listHeight);
15861 if(firstChecked && listHeight > bodyHeight){
15862 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
15867 onTouchViewLoadException : function()
15869 this.hideTouchView();
15872 onTouchViewEmptyResults : function()
15874 this.clearTouchView();
15876 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
15878 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
15882 clearTouchView : function()
15884 this.touchViewListGroup.dom.innerHTML = '';
15887 onTouchViewClick : function(e, el, o)
15889 e.preventDefault();
15892 var rowIndex = o.rowIndex;
15894 var r = this.store.getAt(rowIndex);
15896 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
15898 if(!this.multiple){
15899 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
15900 c.dom.removeAttribute('checked');
15903 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15905 this.setFromData(r.data);
15907 var close = this.closeTriggerEl();
15913 this.hideTouchView();
15915 this.fireEvent('select', this, r, rowIndex);
15920 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
15921 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
15922 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
15926 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15927 this.addItem(r.data);
15928 this.tickItems.push(r.data);
15932 getAutoCreateNativeIOS : function()
15935 cls: 'form-group' //input-group,
15940 cls : 'roo-ios-select'
15944 combobox.name = this.name;
15947 if (this.disabled) {
15948 combobox.disabled = true;
15951 var settings = this;
15953 ['xs','sm','md','lg'].map(function(size){
15954 if (settings[size]) {
15955 cfg.cls += ' col-' + size + '-' + settings[size];
15965 initIOSView : function()
15967 this.store.on('load', this.onIOSViewLoad, this);
15972 onIOSViewLoad : function()
15974 if(this.store.getCount() < 1){
15978 this.clearIOSView();
15980 if(this.allowBlank) {
15982 var default_text = '-- SELECT --';
15984 if(this.placeholder.length){
15985 default_text = this.placeholder;
15988 if(this.emptyTitle.length){
15989 default_text += ' - ' + this.emptyTitle + ' -';
15992 var opt = this.inputEl().createChild({
15995 html : default_text
15999 o[this.valueField] = 0;
16000 o[this.displayField] = default_text;
16002 this.ios_options.push({
16009 this.store.data.each(function(d, rowIndex){
16013 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
16014 html = d.data[this.displayField];
16019 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
16020 value = d.data[this.valueField];
16029 if(this.value == d.data[this.valueField]){
16030 option['selected'] = true;
16033 var opt = this.inputEl().createChild(option);
16035 this.ios_options.push({
16042 this.inputEl().on('change', function(){
16043 this.fireEvent('select', this);
16048 clearIOSView: function()
16050 this.inputEl().dom.innerHTML = '';
16052 this.ios_options = [];
16055 setIOSValue: function(v)
16059 if(!this.ios_options){
16063 Roo.each(this.ios_options, function(opts){
16065 opts.el.dom.removeAttribute('selected');
16067 if(opts.data[this.valueField] != v){
16071 opts.el.dom.setAttribute('selected', true);
16077 * @cfg {Boolean} grow
16081 * @cfg {Number} growMin
16085 * @cfg {Number} growMax
16094 Roo.apply(Roo.bootstrap.ComboBox, {
16098 cls: 'modal-header',
16120 cls: 'list-group-item',
16124 cls: 'roo-combobox-list-group-item-value'
16128 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
16142 listItemCheckbox : {
16144 cls: 'list-group-item',
16148 cls: 'roo-combobox-list-group-item-value'
16152 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
16168 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
16173 cls: 'modal-footer',
16181 cls: 'col-xs-6 text-left',
16184 cls: 'btn btn-danger roo-touch-view-cancel',
16190 cls: 'col-xs-6 text-right',
16193 cls: 'btn btn-success roo-touch-view-ok',
16204 Roo.apply(Roo.bootstrap.ComboBox, {
16206 touchViewTemplate : {
16208 cls: 'modal fade roo-combobox-touch-view',
16212 cls: 'modal-dialog',
16213 style : 'position:fixed', // we have to fix position....
16217 cls: 'modal-content',
16219 Roo.bootstrap.ComboBox.header,
16220 Roo.bootstrap.ComboBox.body,
16221 Roo.bootstrap.ComboBox.footer
16230 * Ext JS Library 1.1.1
16231 * Copyright(c) 2006-2007, Ext JS, LLC.
16233 * Originally Released Under LGPL - original licence link has changed is not relivant.
16236 * <script type="text/javascript">
16241 * @extends Roo.util.Observable
16242 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
16243 * This class also supports single and multi selection modes. <br>
16244 * Create a data model bound view:
16246 var store = new Roo.data.Store(...);
16248 var view = new Roo.View({
16250 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
16252 singleSelect: true,
16253 selectedClass: "ydataview-selected",
16257 // listen for node click?
16258 view.on("click", function(vw, index, node, e){
16259 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
16263 dataModel.load("foobar.xml");
16265 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
16267 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
16268 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
16270 * Note: old style constructor is still suported (container, template, config)
16273 * Create a new View
16274 * @param {Object} config The config object
16277 Roo.View = function(config, depreciated_tpl, depreciated_config){
16279 this.parent = false;
16281 if (typeof(depreciated_tpl) == 'undefined') {
16282 // new way.. - universal constructor.
16283 Roo.apply(this, config);
16284 this.el = Roo.get(this.el);
16287 this.el = Roo.get(config);
16288 this.tpl = depreciated_tpl;
16289 Roo.apply(this, depreciated_config);
16291 this.wrapEl = this.el.wrap().wrap();
16292 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
16295 if(typeof(this.tpl) == "string"){
16296 this.tpl = new Roo.Template(this.tpl);
16298 // support xtype ctors..
16299 this.tpl = new Roo.factory(this.tpl, Roo);
16303 this.tpl.compile();
16308 * @event beforeclick
16309 * Fires before a click is processed. Returns false to cancel the default action.
16310 * @param {Roo.View} this
16311 * @param {Number} index The index of the target node
16312 * @param {HTMLElement} node The target node
16313 * @param {Roo.EventObject} e The raw event object
16315 "beforeclick" : true,
16318 * Fires when a template node is clicked.
16319 * @param {Roo.View} this
16320 * @param {Number} index The index of the target node
16321 * @param {HTMLElement} node The target node
16322 * @param {Roo.EventObject} e The raw event object
16327 * Fires when a template node is double clicked.
16328 * @param {Roo.View} this
16329 * @param {Number} index The index of the target node
16330 * @param {HTMLElement} node The target node
16331 * @param {Roo.EventObject} e The raw event object
16335 * @event contextmenu
16336 * Fires when a template node is right clicked.
16337 * @param {Roo.View} this
16338 * @param {Number} index The index of the target node
16339 * @param {HTMLElement} node The target node
16340 * @param {Roo.EventObject} e The raw event object
16342 "contextmenu" : true,
16344 * @event selectionchange
16345 * Fires when the selected nodes change.
16346 * @param {Roo.View} this
16347 * @param {Array} selections Array of the selected nodes
16349 "selectionchange" : true,
16352 * @event beforeselect
16353 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
16354 * @param {Roo.View} this
16355 * @param {HTMLElement} node The node to be selected
16356 * @param {Array} selections Array of currently selected nodes
16358 "beforeselect" : true,
16360 * @event preparedata
16361 * Fires on every row to render, to allow you to change the data.
16362 * @param {Roo.View} this
16363 * @param {Object} data to be rendered (change this)
16365 "preparedata" : true
16373 "click": this.onClick,
16374 "dblclick": this.onDblClick,
16375 "contextmenu": this.onContextMenu,
16379 this.selections = [];
16381 this.cmp = new Roo.CompositeElementLite([]);
16383 this.store = Roo.factory(this.store, Roo.data);
16384 this.setStore(this.store, true);
16387 if ( this.footer && this.footer.xtype) {
16389 var fctr = this.wrapEl.appendChild(document.createElement("div"));
16391 this.footer.dataSource = this.store;
16392 this.footer.container = fctr;
16393 this.footer = Roo.factory(this.footer, Roo);
16394 fctr.insertFirst(this.el);
16396 // this is a bit insane - as the paging toolbar seems to detach the el..
16397 // dom.parentNode.parentNode.parentNode
16398 // they get detached?
16402 Roo.View.superclass.constructor.call(this);
16407 Roo.extend(Roo.View, Roo.util.Observable, {
16410 * @cfg {Roo.data.Store} store Data store to load data from.
16415 * @cfg {String|Roo.Element} el The container element.
16420 * @cfg {String|Roo.Template} tpl The template used by this View
16424 * @cfg {String} dataName the named area of the template to use as the data area
16425 * Works with domtemplates roo-name="name"
16429 * @cfg {String} selectedClass The css class to add to selected nodes
16431 selectedClass : "x-view-selected",
16433 * @cfg {String} emptyText The empty text to show when nothing is loaded.
16438 * @cfg {String} text to display on mask (default Loading)
16442 * @cfg {Boolean} multiSelect Allow multiple selection
16444 multiSelect : false,
16446 * @cfg {Boolean} singleSelect Allow single selection
16448 singleSelect: false,
16451 * @cfg {Boolean} toggleSelect - selecting
16453 toggleSelect : false,
16456 * @cfg {Boolean} tickable - selecting
16461 * Returns the element this view is bound to.
16462 * @return {Roo.Element}
16464 getEl : function(){
16465 return this.wrapEl;
16471 * Refreshes the view. - called by datachanged on the store. - do not call directly.
16473 refresh : function(){
16474 //Roo.log('refresh');
16477 // if we are using something like 'domtemplate', then
16478 // the what gets used is:
16479 // t.applySubtemplate(NAME, data, wrapping data..)
16480 // the outer template then get' applied with
16481 // the store 'extra data'
16482 // and the body get's added to the
16483 // roo-name="data" node?
16484 // <span class='roo-tpl-{name}'></span> ?????
16488 this.clearSelections();
16489 this.el.update("");
16491 var records = this.store.getRange();
16492 if(records.length < 1) {
16494 // is this valid?? = should it render a template??
16496 this.el.update(this.emptyText);
16500 if (this.dataName) {
16501 this.el.update(t.apply(this.store.meta)); //????
16502 el = this.el.child('.roo-tpl-' + this.dataName);
16505 for(var i = 0, len = records.length; i < len; i++){
16506 var data = this.prepareData(records[i].data, i, records[i]);
16507 this.fireEvent("preparedata", this, data, i, records[i]);
16509 var d = Roo.apply({}, data);
16512 Roo.apply(d, {'roo-id' : Roo.id()});
16516 Roo.each(this.parent.item, function(item){
16517 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
16520 Roo.apply(d, {'roo-data-checked' : 'checked'});
16524 html[html.length] = Roo.util.Format.trim(
16526 t.applySubtemplate(this.dataName, d, this.store.meta) :
16533 el.update(html.join(""));
16534 this.nodes = el.dom.childNodes;
16535 this.updateIndexes(0);
16540 * Function to override to reformat the data that is sent to
16541 * the template for each node.
16542 * DEPRICATED - use the preparedata event handler.
16543 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
16544 * a JSON object for an UpdateManager bound view).
16546 prepareData : function(data, index, record)
16548 this.fireEvent("preparedata", this, data, index, record);
16552 onUpdate : function(ds, record){
16553 // Roo.log('on update');
16554 this.clearSelections();
16555 var index = this.store.indexOf(record);
16556 var n = this.nodes[index];
16557 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
16558 n.parentNode.removeChild(n);
16559 this.updateIndexes(index, index);
16565 onAdd : function(ds, records, index)
16567 //Roo.log(['on Add', ds, records, index] );
16568 this.clearSelections();
16569 if(this.nodes.length == 0){
16573 var n = this.nodes[index];
16574 for(var i = 0, len = records.length; i < len; i++){
16575 var d = this.prepareData(records[i].data, i, records[i]);
16577 this.tpl.insertBefore(n, d);
16580 this.tpl.append(this.el, d);
16583 this.updateIndexes(index);
16586 onRemove : function(ds, record, index){
16587 // Roo.log('onRemove');
16588 this.clearSelections();
16589 var el = this.dataName ?
16590 this.el.child('.roo-tpl-' + this.dataName) :
16593 el.dom.removeChild(this.nodes[index]);
16594 this.updateIndexes(index);
16598 * Refresh an individual node.
16599 * @param {Number} index
16601 refreshNode : function(index){
16602 this.onUpdate(this.store, this.store.getAt(index));
16605 updateIndexes : function(startIndex, endIndex){
16606 var ns = this.nodes;
16607 startIndex = startIndex || 0;
16608 endIndex = endIndex || ns.length - 1;
16609 for(var i = startIndex; i <= endIndex; i++){
16610 ns[i].nodeIndex = i;
16615 * Changes the data store this view uses and refresh the view.
16616 * @param {Store} store
16618 setStore : function(store, initial){
16619 if(!initial && this.store){
16620 this.store.un("datachanged", this.refresh);
16621 this.store.un("add", this.onAdd);
16622 this.store.un("remove", this.onRemove);
16623 this.store.un("update", this.onUpdate);
16624 this.store.un("clear", this.refresh);
16625 this.store.un("beforeload", this.onBeforeLoad);
16626 this.store.un("load", this.onLoad);
16627 this.store.un("loadexception", this.onLoad);
16631 store.on("datachanged", this.refresh, this);
16632 store.on("add", this.onAdd, this);
16633 store.on("remove", this.onRemove, this);
16634 store.on("update", this.onUpdate, this);
16635 store.on("clear", this.refresh, this);
16636 store.on("beforeload", this.onBeforeLoad, this);
16637 store.on("load", this.onLoad, this);
16638 store.on("loadexception", this.onLoad, this);
16646 * onbeforeLoad - masks the loading area.
16649 onBeforeLoad : function(store,opts)
16651 //Roo.log('onBeforeLoad');
16653 this.el.update("");
16655 this.el.mask(this.mask ? this.mask : "Loading" );
16657 onLoad : function ()
16664 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
16665 * @param {HTMLElement} node
16666 * @return {HTMLElement} The template node
16668 findItemFromChild : function(node){
16669 var el = this.dataName ?
16670 this.el.child('.roo-tpl-' + this.dataName,true) :
16673 if(!node || node.parentNode == el){
16676 var p = node.parentNode;
16677 while(p && p != el){
16678 if(p.parentNode == el){
16687 onClick : function(e){
16688 var item = this.findItemFromChild(e.getTarget());
16690 var index = this.indexOf(item);
16691 if(this.onItemClick(item, index, e) !== false){
16692 this.fireEvent("click", this, index, item, e);
16695 this.clearSelections();
16700 onContextMenu : function(e){
16701 var item = this.findItemFromChild(e.getTarget());
16703 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
16708 onDblClick : function(e){
16709 var item = this.findItemFromChild(e.getTarget());
16711 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
16715 onItemClick : function(item, index, e)
16717 if(this.fireEvent("beforeclick", this, index, item, e) === false){
16720 if (this.toggleSelect) {
16721 var m = this.isSelected(item) ? 'unselect' : 'select';
16724 _t[m](item, true, false);
16727 if(this.multiSelect || this.singleSelect){
16728 if(this.multiSelect && e.shiftKey && this.lastSelection){
16729 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
16731 this.select(item, this.multiSelect && e.ctrlKey);
16732 this.lastSelection = item;
16735 if(!this.tickable){
16736 e.preventDefault();
16744 * Get the number of selected nodes.
16747 getSelectionCount : function(){
16748 return this.selections.length;
16752 * Get the currently selected nodes.
16753 * @return {Array} An array of HTMLElements
16755 getSelectedNodes : function(){
16756 return this.selections;
16760 * Get the indexes of the selected nodes.
16763 getSelectedIndexes : function(){
16764 var indexes = [], s = this.selections;
16765 for(var i = 0, len = s.length; i < len; i++){
16766 indexes.push(s[i].nodeIndex);
16772 * Clear all selections
16773 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
16775 clearSelections : function(suppressEvent){
16776 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
16777 this.cmp.elements = this.selections;
16778 this.cmp.removeClass(this.selectedClass);
16779 this.selections = [];
16780 if(!suppressEvent){
16781 this.fireEvent("selectionchange", this, this.selections);
16787 * Returns true if the passed node is selected
16788 * @param {HTMLElement/Number} node The node or node index
16789 * @return {Boolean}
16791 isSelected : function(node){
16792 var s = this.selections;
16796 node = this.getNode(node);
16797 return s.indexOf(node) !== -1;
16802 * @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
16803 * @param {Boolean} keepExisting (optional) true to keep existing selections
16804 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16806 select : function(nodeInfo, keepExisting, suppressEvent){
16807 if(nodeInfo instanceof Array){
16809 this.clearSelections(true);
16811 for(var i = 0, len = nodeInfo.length; i < len; i++){
16812 this.select(nodeInfo[i], true, true);
16816 var node = this.getNode(nodeInfo);
16817 if(!node || this.isSelected(node)){
16818 return; // already selected.
16821 this.clearSelections(true);
16824 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
16825 Roo.fly(node).addClass(this.selectedClass);
16826 this.selections.push(node);
16827 if(!suppressEvent){
16828 this.fireEvent("selectionchange", this, this.selections);
16836 * @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
16837 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
16838 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16840 unselect : function(nodeInfo, keepExisting, suppressEvent)
16842 if(nodeInfo instanceof Array){
16843 Roo.each(this.selections, function(s) {
16844 this.unselect(s, nodeInfo);
16848 var node = this.getNode(nodeInfo);
16849 if(!node || !this.isSelected(node)){
16850 //Roo.log("not selected");
16851 return; // not selected.
16855 Roo.each(this.selections, function(s) {
16857 Roo.fly(node).removeClass(this.selectedClass);
16864 this.selections= ns;
16865 this.fireEvent("selectionchange", this, this.selections);
16869 * Gets a template node.
16870 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16871 * @return {HTMLElement} The node or null if it wasn't found
16873 getNode : function(nodeInfo){
16874 if(typeof nodeInfo == "string"){
16875 return document.getElementById(nodeInfo);
16876 }else if(typeof nodeInfo == "number"){
16877 return this.nodes[nodeInfo];
16883 * Gets a range template nodes.
16884 * @param {Number} startIndex
16885 * @param {Number} endIndex
16886 * @return {Array} An array of nodes
16888 getNodes : function(start, end){
16889 var ns = this.nodes;
16890 start = start || 0;
16891 end = typeof end == "undefined" ? ns.length - 1 : end;
16894 for(var i = start; i <= end; i++){
16898 for(var i = start; i >= end; i--){
16906 * Finds the index of the passed node
16907 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16908 * @return {Number} The index of the node or -1
16910 indexOf : function(node){
16911 node = this.getNode(node);
16912 if(typeof node.nodeIndex == "number"){
16913 return node.nodeIndex;
16915 var ns = this.nodes;
16916 for(var i = 0, len = ns.length; i < len; i++){
16927 * based on jquery fullcalendar
16931 Roo.bootstrap = Roo.bootstrap || {};
16933 * @class Roo.bootstrap.Calendar
16934 * @extends Roo.bootstrap.Component
16935 * Bootstrap Calendar class
16936 * @cfg {Boolean} loadMask (true|false) default false
16937 * @cfg {Object} header generate the user specific header of the calendar, default false
16940 * Create a new Container
16941 * @param {Object} config The config object
16946 Roo.bootstrap.Calendar = function(config){
16947 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
16951 * Fires when a date is selected
16952 * @param {DatePicker} this
16953 * @param {Date} date The selected date
16957 * @event monthchange
16958 * Fires when the displayed month changes
16959 * @param {DatePicker} this
16960 * @param {Date} date The selected month
16962 'monthchange': true,
16964 * @event evententer
16965 * Fires when mouse over an event
16966 * @param {Calendar} this
16967 * @param {event} Event
16969 'evententer': true,
16971 * @event eventleave
16972 * Fires when the mouse leaves an
16973 * @param {Calendar} this
16976 'eventleave': true,
16978 * @event eventclick
16979 * Fires when the mouse click an
16980 * @param {Calendar} this
16989 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
16992 * @cfg {Number} startDay
16993 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
17001 getAutoCreate : function(){
17004 var fc_button = function(name, corner, style, content ) {
17005 return Roo.apply({},{
17007 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
17009 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
17012 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
17023 style : 'width:100%',
17030 cls : 'fc-header-left',
17032 fc_button('prev', 'left', 'arrow', '‹' ),
17033 fc_button('next', 'right', 'arrow', '›' ),
17034 { tag: 'span', cls: 'fc-header-space' },
17035 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
17043 cls : 'fc-header-center',
17047 cls: 'fc-header-title',
17050 html : 'month / year'
17058 cls : 'fc-header-right',
17060 /* fc_button('month', 'left', '', 'month' ),
17061 fc_button('week', '', '', 'week' ),
17062 fc_button('day', 'right', '', 'day' )
17074 header = this.header;
17077 var cal_heads = function() {
17079 // fixme - handle this.
17081 for (var i =0; i < Date.dayNames.length; i++) {
17082 var d = Date.dayNames[i];
17085 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
17086 html : d.substring(0,3)
17090 ret[0].cls += ' fc-first';
17091 ret[6].cls += ' fc-last';
17094 var cal_cell = function(n) {
17097 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
17102 cls: 'fc-day-number',
17106 cls: 'fc-day-content',
17110 style: 'position: relative;' // height: 17px;
17122 var cal_rows = function() {
17125 for (var r = 0; r < 6; r++) {
17132 for (var i =0; i < Date.dayNames.length; i++) {
17133 var d = Date.dayNames[i];
17134 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
17137 row.cn[0].cls+=' fc-first';
17138 row.cn[0].cn[0].style = 'min-height:90px';
17139 row.cn[6].cls+=' fc-last';
17143 ret[0].cls += ' fc-first';
17144 ret[4].cls += ' fc-prev-last';
17145 ret[5].cls += ' fc-last';
17152 cls: 'fc-border-separate',
17153 style : 'width:100%',
17161 cls : 'fc-first fc-last',
17179 cls : 'fc-content',
17180 style : "position: relative;",
17183 cls : 'fc-view fc-view-month fc-grid',
17184 style : 'position: relative',
17185 unselectable : 'on',
17188 cls : 'fc-event-container',
17189 style : 'position:absolute;z-index:8;top:0;left:0;'
17207 initEvents : function()
17210 throw "can not find store for calendar";
17216 style: "text-align:center",
17220 style: "background-color:white;width:50%;margin:250 auto",
17224 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
17235 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
17237 var size = this.el.select('.fc-content', true).first().getSize();
17238 this.maskEl.setSize(size.width, size.height);
17239 this.maskEl.enableDisplayMode("block");
17240 if(!this.loadMask){
17241 this.maskEl.hide();
17244 this.store = Roo.factory(this.store, Roo.data);
17245 this.store.on('load', this.onLoad, this);
17246 this.store.on('beforeload', this.onBeforeLoad, this);
17250 this.cells = this.el.select('.fc-day',true);
17251 //Roo.log(this.cells);
17252 this.textNodes = this.el.query('.fc-day-number');
17253 this.cells.addClassOnOver('fc-state-hover');
17255 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
17256 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
17257 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
17258 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
17260 this.on('monthchange', this.onMonthChange, this);
17262 this.update(new Date().clearTime());
17265 resize : function() {
17266 var sz = this.el.getSize();
17268 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
17269 this.el.select('.fc-day-content div',true).setHeight(34);
17274 showPrevMonth : function(e){
17275 this.update(this.activeDate.add("mo", -1));
17277 showToday : function(e){
17278 this.update(new Date().clearTime());
17281 showNextMonth : function(e){
17282 this.update(this.activeDate.add("mo", 1));
17286 showPrevYear : function(){
17287 this.update(this.activeDate.add("y", -1));
17291 showNextYear : function(){
17292 this.update(this.activeDate.add("y", 1));
17297 update : function(date)
17299 var vd = this.activeDate;
17300 this.activeDate = date;
17301 // if(vd && this.el){
17302 // var t = date.getTime();
17303 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
17304 // Roo.log('using add remove');
17306 // this.fireEvent('monthchange', this, date);
17308 // this.cells.removeClass("fc-state-highlight");
17309 // this.cells.each(function(c){
17310 // if(c.dateValue == t){
17311 // c.addClass("fc-state-highlight");
17312 // setTimeout(function(){
17313 // try{c.dom.firstChild.focus();}catch(e){}
17323 var days = date.getDaysInMonth();
17325 var firstOfMonth = date.getFirstDateOfMonth();
17326 var startingPos = firstOfMonth.getDay()-this.startDay;
17328 if(startingPos < this.startDay){
17332 var pm = date.add(Date.MONTH, -1);
17333 var prevStart = pm.getDaysInMonth()-startingPos;
17335 this.cells = this.el.select('.fc-day',true);
17336 this.textNodes = this.el.query('.fc-day-number');
17337 this.cells.addClassOnOver('fc-state-hover');
17339 var cells = this.cells.elements;
17340 var textEls = this.textNodes;
17342 Roo.each(cells, function(cell){
17343 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
17346 days += startingPos;
17348 // convert everything to numbers so it's fast
17349 var day = 86400000;
17350 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
17353 //Roo.log(prevStart);
17355 var today = new Date().clearTime().getTime();
17356 var sel = date.clearTime().getTime();
17357 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
17358 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
17359 var ddMatch = this.disabledDatesRE;
17360 var ddText = this.disabledDatesText;
17361 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
17362 var ddaysText = this.disabledDaysText;
17363 var format = this.format;
17365 var setCellClass = function(cal, cell){
17369 //Roo.log('set Cell Class');
17371 var t = d.getTime();
17375 cell.dateValue = t;
17377 cell.className += " fc-today";
17378 cell.className += " fc-state-highlight";
17379 cell.title = cal.todayText;
17382 // disable highlight in other month..
17383 //cell.className += " fc-state-highlight";
17388 cell.className = " fc-state-disabled";
17389 cell.title = cal.minText;
17393 cell.className = " fc-state-disabled";
17394 cell.title = cal.maxText;
17398 if(ddays.indexOf(d.getDay()) != -1){
17399 cell.title = ddaysText;
17400 cell.className = " fc-state-disabled";
17403 if(ddMatch && format){
17404 var fvalue = d.dateFormat(format);
17405 if(ddMatch.test(fvalue)){
17406 cell.title = ddText.replace("%0", fvalue);
17407 cell.className = " fc-state-disabled";
17411 if (!cell.initialClassName) {
17412 cell.initialClassName = cell.dom.className;
17415 cell.dom.className = cell.initialClassName + ' ' + cell.className;
17420 for(; i < startingPos; i++) {
17421 textEls[i].innerHTML = (++prevStart);
17422 d.setDate(d.getDate()+1);
17424 cells[i].className = "fc-past fc-other-month";
17425 setCellClass(this, cells[i]);
17430 for(; i < days; i++){
17431 intDay = i - startingPos + 1;
17432 textEls[i].innerHTML = (intDay);
17433 d.setDate(d.getDate()+1);
17435 cells[i].className = ''; // "x-date-active";
17436 setCellClass(this, cells[i]);
17440 for(; i < 42; i++) {
17441 textEls[i].innerHTML = (++extraDays);
17442 d.setDate(d.getDate()+1);
17444 cells[i].className = "fc-future fc-other-month";
17445 setCellClass(this, cells[i]);
17448 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
17450 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
17452 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
17453 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
17455 if(totalRows != 6){
17456 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
17457 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
17460 this.fireEvent('monthchange', this, date);
17464 if(!this.internalRender){
17465 var main = this.el.dom.firstChild;
17466 var w = main.offsetWidth;
17467 this.el.setWidth(w + this.el.getBorderWidth("lr"));
17468 Roo.fly(main).setWidth(w);
17469 this.internalRender = true;
17470 // opera does not respect the auto grow header center column
17471 // then, after it gets a width opera refuses to recalculate
17472 // without a second pass
17473 if(Roo.isOpera && !this.secondPass){
17474 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
17475 this.secondPass = true;
17476 this.update.defer(10, this, [date]);
17483 findCell : function(dt) {
17484 dt = dt.clearTime().getTime();
17486 this.cells.each(function(c){
17487 //Roo.log("check " +c.dateValue + '?=' + dt);
17488 if(c.dateValue == dt){
17498 findCells : function(ev) {
17499 var s = ev.start.clone().clearTime().getTime();
17501 var e= ev.end.clone().clearTime().getTime();
17504 this.cells.each(function(c){
17505 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
17507 if(c.dateValue > e){
17510 if(c.dateValue < s){
17519 // findBestRow: function(cells)
17523 // for (var i =0 ; i < cells.length;i++) {
17524 // ret = Math.max(cells[i].rows || 0,ret);
17531 addItem : function(ev)
17533 // look for vertical location slot in
17534 var cells = this.findCells(ev);
17536 // ev.row = this.findBestRow(cells);
17538 // work out the location.
17542 for(var i =0; i < cells.length; i++) {
17544 cells[i].row = cells[0].row;
17547 cells[i].row = cells[i].row + 1;
17557 if (crow.start.getY() == cells[i].getY()) {
17559 crow.end = cells[i];
17576 cells[0].events.push(ev);
17578 this.calevents.push(ev);
17581 clearEvents: function() {
17583 if(!this.calevents){
17587 Roo.each(this.cells.elements, function(c){
17593 Roo.each(this.calevents, function(e) {
17594 Roo.each(e.els, function(el) {
17595 el.un('mouseenter' ,this.onEventEnter, this);
17596 el.un('mouseleave' ,this.onEventLeave, this);
17601 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
17607 renderEvents: function()
17611 this.cells.each(function(c) {
17620 if(c.row != c.events.length){
17621 r = 4 - (4 - (c.row - c.events.length));
17624 c.events = ev.slice(0, r);
17625 c.more = ev.slice(r);
17627 if(c.more.length && c.more.length == 1){
17628 c.events.push(c.more.pop());
17631 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
17635 this.cells.each(function(c) {
17637 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
17640 for (var e = 0; e < c.events.length; e++){
17641 var ev = c.events[e];
17642 var rows = ev.rows;
17644 for(var i = 0; i < rows.length; i++) {
17646 // how many rows should it span..
17649 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
17650 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
17652 unselectable : "on",
17655 cls: 'fc-event-inner',
17659 // cls: 'fc-event-time',
17660 // html : cells.length > 1 ? '' : ev.time
17664 cls: 'fc-event-title',
17665 html : String.format('{0}', ev.title)
17672 cls: 'ui-resizable-handle ui-resizable-e',
17673 html : '  '
17680 cfg.cls += ' fc-event-start';
17682 if ((i+1) == rows.length) {
17683 cfg.cls += ' fc-event-end';
17686 var ctr = _this.el.select('.fc-event-container',true).first();
17687 var cg = ctr.createChild(cfg);
17689 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
17690 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
17692 var r = (c.more.length) ? 1 : 0;
17693 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
17694 cg.setWidth(ebox.right - sbox.x -2);
17696 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
17697 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
17698 cg.on('click', _this.onEventClick, _this, ev);
17709 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
17710 style : 'position: absolute',
17711 unselectable : "on",
17714 cls: 'fc-event-inner',
17718 cls: 'fc-event-title',
17726 cls: 'ui-resizable-handle ui-resizable-e',
17727 html : '  '
17733 var ctr = _this.el.select('.fc-event-container',true).first();
17734 var cg = ctr.createChild(cfg);
17736 var sbox = c.select('.fc-day-content',true).first().getBox();
17737 var ebox = c.select('.fc-day-content',true).first().getBox();
17739 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
17740 cg.setWidth(ebox.right - sbox.x -2);
17742 cg.on('click', _this.onMoreEventClick, _this, c.more);
17752 onEventEnter: function (e, el,event,d) {
17753 this.fireEvent('evententer', this, el, event);
17756 onEventLeave: function (e, el,event,d) {
17757 this.fireEvent('eventleave', this, el, event);
17760 onEventClick: function (e, el,event,d) {
17761 this.fireEvent('eventclick', this, el, event);
17764 onMonthChange: function () {
17768 onMoreEventClick: function(e, el, more)
17772 this.calpopover.placement = 'right';
17773 this.calpopover.setTitle('More');
17775 this.calpopover.setContent('');
17777 var ctr = this.calpopover.el.select('.popover-content', true).first();
17779 Roo.each(more, function(m){
17781 cls : 'fc-event-hori fc-event-draggable',
17784 var cg = ctr.createChild(cfg);
17786 cg.on('click', _this.onEventClick, _this, m);
17789 this.calpopover.show(el);
17794 onLoad: function ()
17796 this.calevents = [];
17799 if(this.store.getCount() > 0){
17800 this.store.data.each(function(d){
17803 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
17804 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
17805 time : d.data.start_time,
17806 title : d.data.title,
17807 description : d.data.description,
17808 venue : d.data.venue
17813 this.renderEvents();
17815 if(this.calevents.length && this.loadMask){
17816 this.maskEl.hide();
17820 onBeforeLoad: function()
17822 this.clearEvents();
17824 this.maskEl.show();
17838 * @class Roo.bootstrap.Popover
17839 * @extends Roo.bootstrap.Component
17840 * Bootstrap Popover class
17841 * @cfg {String} html contents of the popover (or false to use children..)
17842 * @cfg {String} title of popover (or false to hide)
17843 * @cfg {String} placement how it is placed
17844 * @cfg {String} trigger click || hover (or false to trigger manually)
17845 * @cfg {String} over what (parent or false to trigger manually.)
17846 * @cfg {Number} delay - delay before showing
17849 * Create a new Popover
17850 * @param {Object} config The config object
17853 Roo.bootstrap.Popover = function(config){
17854 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
17860 * After the popover show
17862 * @param {Roo.bootstrap.Popover} this
17867 * After the popover hide
17869 * @param {Roo.bootstrap.Popover} this
17875 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
17877 title: 'Fill in a title',
17880 placement : 'right',
17881 trigger : 'hover', // hover
17887 can_build_overlaid : false,
17889 getChildContainer : function()
17891 return this.el.select('.popover-content',true).first();
17894 getAutoCreate : function(){
17897 cls : 'popover roo-dynamic',
17898 style: 'display:block',
17904 cls : 'popover-inner',
17908 cls: 'popover-title popover-header',
17912 cls : 'popover-content popover-body',
17923 setTitle: function(str)
17926 this.el.select('.popover-title',true).first().dom.innerHTML = str;
17928 setContent: function(str)
17931 this.el.select('.popover-content',true).first().dom.innerHTML = str;
17933 // as it get's added to the bottom of the page.
17934 onRender : function(ct, position)
17936 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17938 var cfg = Roo.apply({}, this.getAutoCreate());
17942 cfg.cls += ' ' + this.cls;
17945 cfg.style = this.style;
17947 //Roo.log("adding to ");
17948 this.el = Roo.get(document.body).createChild(cfg, position);
17949 // Roo.log(this.el);
17954 initEvents : function()
17956 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
17957 this.el.enableDisplayMode('block');
17959 if (this.over === false) {
17962 if (this.triggers === false) {
17965 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17966 var triggers = this.trigger ? this.trigger.split(' ') : [];
17967 Roo.each(triggers, function(trigger) {
17969 if (trigger == 'click') {
17970 on_el.on('click', this.toggle, this);
17971 } else if (trigger != 'manual') {
17972 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
17973 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
17975 on_el.on(eventIn ,this.enter, this);
17976 on_el.on(eventOut, this.leave, this);
17987 toggle : function () {
17988 this.hoverState == 'in' ? this.leave() : this.enter();
17991 enter : function () {
17993 clearTimeout(this.timeout);
17995 this.hoverState = 'in';
17997 if (!this.delay || !this.delay.show) {
18002 this.timeout = setTimeout(function () {
18003 if (_t.hoverState == 'in') {
18006 }, this.delay.show)
18009 leave : function() {
18010 clearTimeout(this.timeout);
18012 this.hoverState = 'out';
18014 if (!this.delay || !this.delay.hide) {
18019 this.timeout = setTimeout(function () {
18020 if (_t.hoverState == 'out') {
18023 }, this.delay.hide)
18026 show : function (on_el)
18029 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
18033 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
18034 if (this.html !== false) {
18035 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
18037 this.el.removeClass([
18038 'fade','top','bottom', 'left', 'right','in',
18039 'bs-popover-top','bs-popover-bottom', 'bs-popover-left', 'bs-popover-right'
18041 if (!this.title.length) {
18042 this.el.select('.popover-title',true).hide();
18045 var placement = typeof this.placement == 'function' ?
18046 this.placement.call(this, this.el, on_el) :
18049 var autoToken = /\s?auto?\s?/i;
18050 var autoPlace = autoToken.test(placement);
18052 placement = placement.replace(autoToken, '') || 'top';
18056 //this.el.setXY([0,0]);
18058 this.el.dom.style.display='block';
18059 this.el.addClass(placement);
18061 //this.el.appendTo(on_el);
18063 var p = this.getPosition();
18064 var box = this.el.getBox();
18069 var align = Roo.bootstrap.Popover.alignment[placement];
18072 this.el.alignTo(on_el, align[0],align[1]);
18073 //var arrow = this.el.select('.arrow',true).first();
18074 //arrow.set(align[2],
18076 this.el.addClass('in');
18079 if (this.el.hasClass('fade')) {
18083 this.hoverState = 'in';
18085 this.fireEvent('show', this);
18090 this.el.setXY([0,0]);
18091 this.el.removeClass('in');
18093 this.hoverState = null;
18095 this.fireEvent('hide', this);
18100 Roo.bootstrap.Popover.alignment = {
18101 'left' : ['r-l', [-10,0], 'right bs-popover-right'],
18102 'right' : ['l-r', [10,0], 'left bs-popover-left'],
18103 'bottom' : ['t-b', [0,10], 'top bs-popover-top'],
18104 'top' : [ 'b-t', [0,-10], 'bottom bs-popover-bottom']
18115 * @class Roo.bootstrap.Progress
18116 * @extends Roo.bootstrap.Component
18117 * Bootstrap Progress class
18118 * @cfg {Boolean} striped striped of the progress bar
18119 * @cfg {Boolean} active animated of the progress bar
18123 * Create a new Progress
18124 * @param {Object} config The config object
18127 Roo.bootstrap.Progress = function(config){
18128 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
18131 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
18136 getAutoCreate : function(){
18144 cfg.cls += ' progress-striped';
18148 cfg.cls += ' active';
18167 * @class Roo.bootstrap.ProgressBar
18168 * @extends Roo.bootstrap.Component
18169 * Bootstrap ProgressBar class
18170 * @cfg {Number} aria_valuenow aria-value now
18171 * @cfg {Number} aria_valuemin aria-value min
18172 * @cfg {Number} aria_valuemax aria-value max
18173 * @cfg {String} label label for the progress bar
18174 * @cfg {String} panel (success | info | warning | danger )
18175 * @cfg {String} role role of the progress bar
18176 * @cfg {String} sr_only text
18180 * Create a new ProgressBar
18181 * @param {Object} config The config object
18184 Roo.bootstrap.ProgressBar = function(config){
18185 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
18188 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
18192 aria_valuemax : 100,
18198 getAutoCreate : function()
18203 cls: 'progress-bar',
18204 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
18216 cfg.role = this.role;
18219 if(this.aria_valuenow){
18220 cfg['aria-valuenow'] = this.aria_valuenow;
18223 if(this.aria_valuemin){
18224 cfg['aria-valuemin'] = this.aria_valuemin;
18227 if(this.aria_valuemax){
18228 cfg['aria-valuemax'] = this.aria_valuemax;
18231 if(this.label && !this.sr_only){
18232 cfg.html = this.label;
18236 cfg.cls += ' progress-bar-' + this.panel;
18242 update : function(aria_valuenow)
18244 this.aria_valuenow = aria_valuenow;
18246 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
18261 * @class Roo.bootstrap.TabGroup
18262 * @extends Roo.bootstrap.Column
18263 * Bootstrap Column class
18264 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
18265 * @cfg {Boolean} carousel true to make the group behave like a carousel
18266 * @cfg {Boolean} bullets show bullets for the panels
18267 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
18268 * @cfg {Number} timer auto slide timer .. default 0 millisecond
18269 * @cfg {Boolean} showarrow (true|false) show arrow default true
18272 * Create a new TabGroup
18273 * @param {Object} config The config object
18276 Roo.bootstrap.TabGroup = function(config){
18277 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
18279 this.navId = Roo.id();
18282 Roo.bootstrap.TabGroup.register(this);
18286 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
18289 transition : false,
18294 slideOnTouch : false,
18297 getAutoCreate : function()
18299 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
18301 cfg.cls += ' tab-content';
18303 if (this.carousel) {
18304 cfg.cls += ' carousel slide';
18307 cls : 'carousel-inner',
18311 if(this.bullets && !Roo.isTouch){
18314 cls : 'carousel-bullets',
18318 if(this.bullets_cls){
18319 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
18326 cfg.cn[0].cn.push(bullets);
18329 if(this.showarrow){
18330 cfg.cn[0].cn.push({
18332 class : 'carousel-arrow',
18336 class : 'carousel-prev',
18340 class : 'fa fa-chevron-left'
18346 class : 'carousel-next',
18350 class : 'fa fa-chevron-right'
18363 initEvents: function()
18365 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
18366 // this.el.on("touchstart", this.onTouchStart, this);
18369 if(this.autoslide){
18372 this.slideFn = window.setInterval(function() {
18373 _this.showPanelNext();
18377 if(this.showarrow){
18378 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
18379 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
18385 // onTouchStart : function(e, el, o)
18387 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
18391 // this.showPanelNext();
18395 getChildContainer : function()
18397 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
18401 * register a Navigation item
18402 * @param {Roo.bootstrap.NavItem} the navitem to add
18404 register : function(item)
18406 this.tabs.push( item);
18407 item.navId = this.navId; // not really needed..
18412 getActivePanel : function()
18415 Roo.each(this.tabs, function(t) {
18425 getPanelByName : function(n)
18428 Roo.each(this.tabs, function(t) {
18429 if (t.tabId == n) {
18437 indexOfPanel : function(p)
18440 Roo.each(this.tabs, function(t,i) {
18441 if (t.tabId == p.tabId) {
18450 * show a specific panel
18451 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
18452 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
18454 showPanel : function (pan)
18456 if(this.transition || typeof(pan) == 'undefined'){
18457 Roo.log("waiting for the transitionend");
18461 if (typeof(pan) == 'number') {
18462 pan = this.tabs[pan];
18465 if (typeof(pan) == 'string') {
18466 pan = this.getPanelByName(pan);
18469 var cur = this.getActivePanel();
18472 Roo.log('pan or acitve pan is undefined');
18476 if (pan.tabId == this.getActivePanel().tabId) {
18480 if (false === cur.fireEvent('beforedeactivate')) {
18484 if(this.bullets > 0 && !Roo.isTouch){
18485 this.setActiveBullet(this.indexOfPanel(pan));
18488 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
18490 //class="carousel-item carousel-item-next carousel-item-left"
18492 this.transition = true;
18493 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
18494 var lr = dir == 'next' ? 'left' : 'right';
18495 pan.el.addClass(dir); // or prev
18496 pan.el.addClass('carousel-item-' + dir); // or prev
18497 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
18498 cur.el.addClass(lr); // or right
18499 pan.el.addClass(lr);
18500 cur.el.addClass('carousel-item-' +lr); // or right
18501 pan.el.addClass('carousel-item-' +lr);
18505 cur.el.on('transitionend', function() {
18506 Roo.log("trans end?");
18508 pan.el.removeClass([lr,dir, 'carousel-item-' + lr, 'carousel-item-' + dir]);
18509 pan.setActive(true);
18511 cur.el.removeClass([lr, 'carousel-item-' + lr]);
18512 cur.setActive(false);
18514 _this.transition = false;
18516 }, this, { single: true } );
18521 cur.setActive(false);
18522 pan.setActive(true);
18527 showPanelNext : function()
18529 var i = this.indexOfPanel(this.getActivePanel());
18531 if (i >= this.tabs.length - 1 && !this.autoslide) {
18535 if (i >= this.tabs.length - 1 && this.autoslide) {
18539 this.showPanel(this.tabs[i+1]);
18542 showPanelPrev : function()
18544 var i = this.indexOfPanel(this.getActivePanel());
18546 if (i < 1 && !this.autoslide) {
18550 if (i < 1 && this.autoslide) {
18551 i = this.tabs.length;
18554 this.showPanel(this.tabs[i-1]);
18558 addBullet: function()
18560 if(!this.bullets || Roo.isTouch){
18563 var ctr = this.el.select('.carousel-bullets',true).first();
18564 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
18565 var bullet = ctr.createChild({
18566 cls : 'bullet bullet-' + i
18567 },ctr.dom.lastChild);
18572 bullet.on('click', (function(e, el, o, ii, t){
18574 e.preventDefault();
18576 this.showPanel(ii);
18578 if(this.autoslide && this.slideFn){
18579 clearInterval(this.slideFn);
18580 this.slideFn = window.setInterval(function() {
18581 _this.showPanelNext();
18585 }).createDelegate(this, [i, bullet], true));
18590 setActiveBullet : function(i)
18596 Roo.each(this.el.select('.bullet', true).elements, function(el){
18597 el.removeClass('selected');
18600 var bullet = this.el.select('.bullet-' + i, true).first();
18606 bullet.addClass('selected');
18617 Roo.apply(Roo.bootstrap.TabGroup, {
18621 * register a Navigation Group
18622 * @param {Roo.bootstrap.NavGroup} the navgroup to add
18624 register : function(navgrp)
18626 this.groups[navgrp.navId] = navgrp;
18630 * fetch a Navigation Group based on the navigation ID
18631 * if one does not exist , it will get created.
18632 * @param {string} the navgroup to add
18633 * @returns {Roo.bootstrap.NavGroup} the navgroup
18635 get: function(navId) {
18636 if (typeof(this.groups[navId]) == 'undefined') {
18637 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
18639 return this.groups[navId] ;
18654 * @class Roo.bootstrap.TabPanel
18655 * @extends Roo.bootstrap.Component
18656 * Bootstrap TabPanel class
18657 * @cfg {Boolean} active panel active
18658 * @cfg {String} html panel content
18659 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
18660 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
18661 * @cfg {String} href click to link..
18665 * Create a new TabPanel
18666 * @param {Object} config The config object
18669 Roo.bootstrap.TabPanel = function(config){
18670 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
18674 * Fires when the active status changes
18675 * @param {Roo.bootstrap.TabPanel} this
18676 * @param {Boolean} state the new state
18681 * @event beforedeactivate
18682 * Fires before a tab is de-activated - can be used to do validation on a form.
18683 * @param {Roo.bootstrap.TabPanel} this
18684 * @return {Boolean} false if there is an error
18687 'beforedeactivate': true
18690 this.tabId = this.tabId || Roo.id();
18694 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
18702 getAutoCreate : function(){
18707 // item is needed for carousel - not sure if it has any effect otherwise
18708 cls: 'carousel-item tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
18709 html: this.html || ''
18713 cfg.cls += ' active';
18717 cfg.tabId = this.tabId;
18725 initEvents: function()
18727 var p = this.parent();
18729 this.navId = this.navId || p.navId;
18731 if (typeof(this.navId) != 'undefined') {
18732 // not really needed.. but just in case.. parent should be a NavGroup.
18733 var tg = Roo.bootstrap.TabGroup.get(this.navId);
18737 var i = tg.tabs.length - 1;
18739 if(this.active && tg.bullets > 0 && i < tg.bullets){
18740 tg.setActiveBullet(i);
18744 this.el.on('click', this.onClick, this);
18747 this.el.on("touchstart", this.onTouchStart, this);
18748 this.el.on("touchmove", this.onTouchMove, this);
18749 this.el.on("touchend", this.onTouchEnd, this);
18754 onRender : function(ct, position)
18756 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
18759 setActive : function(state)
18761 Roo.log("panel - set active " + this.tabId + "=" + state);
18763 this.active = state;
18765 this.el.removeClass('active');
18767 } else if (!this.el.hasClass('active')) {
18768 this.el.addClass('active');
18771 this.fireEvent('changed', this, state);
18774 onClick : function(e)
18776 e.preventDefault();
18778 if(!this.href.length){
18782 window.location.href = this.href;
18791 onTouchStart : function(e)
18793 this.swiping = false;
18795 this.startX = e.browserEvent.touches[0].clientX;
18796 this.startY = e.browserEvent.touches[0].clientY;
18799 onTouchMove : function(e)
18801 this.swiping = true;
18803 this.endX = e.browserEvent.touches[0].clientX;
18804 this.endY = e.browserEvent.touches[0].clientY;
18807 onTouchEnd : function(e)
18814 var tabGroup = this.parent();
18816 if(this.endX > this.startX){ // swiping right
18817 tabGroup.showPanelPrev();
18821 if(this.startX > this.endX){ // swiping left
18822 tabGroup.showPanelNext();
18841 * @class Roo.bootstrap.DateField
18842 * @extends Roo.bootstrap.Input
18843 * Bootstrap DateField class
18844 * @cfg {Number} weekStart default 0
18845 * @cfg {String} viewMode default empty, (months|years)
18846 * @cfg {String} minViewMode default empty, (months|years)
18847 * @cfg {Number} startDate default -Infinity
18848 * @cfg {Number} endDate default Infinity
18849 * @cfg {Boolean} todayHighlight default false
18850 * @cfg {Boolean} todayBtn default false
18851 * @cfg {Boolean} calendarWeeks default false
18852 * @cfg {Object} daysOfWeekDisabled default empty
18853 * @cfg {Boolean} singleMode default false (true | false)
18855 * @cfg {Boolean} keyboardNavigation default true
18856 * @cfg {String} language default en
18859 * Create a new DateField
18860 * @param {Object} config The config object
18863 Roo.bootstrap.DateField = function(config){
18864 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
18868 * Fires when this field show.
18869 * @param {Roo.bootstrap.DateField} this
18870 * @param {Mixed} date The date value
18875 * Fires when this field hide.
18876 * @param {Roo.bootstrap.DateField} this
18877 * @param {Mixed} date The date value
18882 * Fires when select a date.
18883 * @param {Roo.bootstrap.DateField} this
18884 * @param {Mixed} date The date value
18888 * @event beforeselect
18889 * Fires when before select a date.
18890 * @param {Roo.bootstrap.DateField} this
18891 * @param {Mixed} date The date value
18893 beforeselect : true
18897 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
18900 * @cfg {String} format
18901 * The default date format string which can be overriden for localization support. The format must be
18902 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
18906 * @cfg {String} altFormats
18907 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
18908 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
18910 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
18918 todayHighlight : false,
18924 keyboardNavigation: true,
18926 calendarWeeks: false,
18928 startDate: -Infinity,
18932 daysOfWeekDisabled: [],
18936 singleMode : false,
18938 UTCDate: function()
18940 return new Date(Date.UTC.apply(Date, arguments));
18943 UTCToday: function()
18945 var today = new Date();
18946 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
18949 getDate: function() {
18950 var d = this.getUTCDate();
18951 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
18954 getUTCDate: function() {
18958 setDate: function(d) {
18959 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
18962 setUTCDate: function(d) {
18964 this.setValue(this.formatDate(this.date));
18967 onRender: function(ct, position)
18970 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
18972 this.language = this.language || 'en';
18973 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
18974 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
18976 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
18977 this.format = this.format || 'm/d/y';
18978 this.isInline = false;
18979 this.isInput = true;
18980 this.component = this.el.select('.add-on', true).first() || false;
18981 this.component = (this.component && this.component.length === 0) ? false : this.component;
18982 this.hasInput = this.component && this.inputEl().length;
18984 if (typeof(this.minViewMode === 'string')) {
18985 switch (this.minViewMode) {
18987 this.minViewMode = 1;
18990 this.minViewMode = 2;
18993 this.minViewMode = 0;
18998 if (typeof(this.viewMode === 'string')) {
18999 switch (this.viewMode) {
19012 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
19014 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
19016 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19018 this.picker().on('mousedown', this.onMousedown, this);
19019 this.picker().on('click', this.onClick, this);
19021 this.picker().addClass('datepicker-dropdown');
19023 this.startViewMode = this.viewMode;
19025 if(this.singleMode){
19026 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
19027 v.setVisibilityMode(Roo.Element.DISPLAY);
19031 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
19032 v.setStyle('width', '189px');
19036 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
19037 if(!this.calendarWeeks){
19042 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
19043 v.attr('colspan', function(i, val){
19044 return parseInt(val) + 1;
19049 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
19051 this.setStartDate(this.startDate);
19052 this.setEndDate(this.endDate);
19054 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
19061 if(this.isInline) {
19066 picker : function()
19068 return this.pickerEl;
19069 // return this.el.select('.datepicker', true).first();
19072 fillDow: function()
19074 var dowCnt = this.weekStart;
19083 if(this.calendarWeeks){
19091 while (dowCnt < this.weekStart + 7) {
19095 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
19099 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
19102 fillMonths: function()
19105 var months = this.picker().select('>.datepicker-months td', true).first();
19107 months.dom.innerHTML = '';
19113 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
19116 months.createChild(month);
19123 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;
19125 if (this.date < this.startDate) {
19126 this.viewDate = new Date(this.startDate);
19127 } else if (this.date > this.endDate) {
19128 this.viewDate = new Date(this.endDate);
19130 this.viewDate = new Date(this.date);
19138 var d = new Date(this.viewDate),
19139 year = d.getUTCFullYear(),
19140 month = d.getUTCMonth(),
19141 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
19142 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
19143 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
19144 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
19145 currentDate = this.date && this.date.valueOf(),
19146 today = this.UTCToday();
19148 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
19150 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
19152 // this.picker.select('>tfoot th.today').
19153 // .text(dates[this.language].today)
19154 // .toggle(this.todayBtn !== false);
19156 this.updateNavArrows();
19159 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
19161 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
19163 prevMonth.setUTCDate(day);
19165 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
19167 var nextMonth = new Date(prevMonth);
19169 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
19171 nextMonth = nextMonth.valueOf();
19173 var fillMonths = false;
19175 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
19177 while(prevMonth.valueOf() <= nextMonth) {
19180 if (prevMonth.getUTCDay() === this.weekStart) {
19182 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
19190 if(this.calendarWeeks){
19191 // ISO 8601: First week contains first thursday.
19192 // ISO also states week starts on Monday, but we can be more abstract here.
19194 // Start of current week: based on weekstart/current date
19195 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
19196 // Thursday of this week
19197 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
19198 // First Thursday of year, year from thursday
19199 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
19200 // Calendar week: ms between thursdays, div ms per day, div 7 days
19201 calWeek = (th - yth) / 864e5 / 7 + 1;
19203 fillMonths.cn.push({
19211 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
19213 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
19216 if (this.todayHighlight &&
19217 prevMonth.getUTCFullYear() == today.getFullYear() &&
19218 prevMonth.getUTCMonth() == today.getMonth() &&
19219 prevMonth.getUTCDate() == today.getDate()) {
19220 clsName += ' today';
19223 if (currentDate && prevMonth.valueOf() === currentDate) {
19224 clsName += ' active';
19227 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
19228 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
19229 clsName += ' disabled';
19232 fillMonths.cn.push({
19234 cls: 'day ' + clsName,
19235 html: prevMonth.getDate()
19238 prevMonth.setDate(prevMonth.getDate()+1);
19241 var currentYear = this.date && this.date.getUTCFullYear();
19242 var currentMonth = this.date && this.date.getUTCMonth();
19244 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
19246 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
19247 v.removeClass('active');
19249 if(currentYear === year && k === currentMonth){
19250 v.addClass('active');
19253 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
19254 v.addClass('disabled');
19260 year = parseInt(year/10, 10) * 10;
19262 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
19264 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
19267 for (var i = -1; i < 11; i++) {
19268 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
19270 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
19278 showMode: function(dir)
19281 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
19284 Roo.each(this.picker().select('>div',true).elements, function(v){
19285 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19288 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
19293 if(this.isInline) {
19297 this.picker().removeClass(['bottom', 'top']);
19299 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
19301 * place to the top of element!
19305 this.picker().addClass('top');
19306 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
19311 this.picker().addClass('bottom');
19313 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
19316 parseDate : function(value)
19318 if(!value || value instanceof Date){
19321 var v = Date.parseDate(value, this.format);
19322 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
19323 v = Date.parseDate(value, 'Y-m-d');
19325 if(!v && this.altFormats){
19326 if(!this.altFormatsArray){
19327 this.altFormatsArray = this.altFormats.split("|");
19329 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
19330 v = Date.parseDate(value, this.altFormatsArray[i]);
19336 formatDate : function(date, fmt)
19338 return (!date || !(date instanceof Date)) ?
19339 date : date.dateFormat(fmt || this.format);
19342 onFocus : function()
19344 Roo.bootstrap.DateField.superclass.onFocus.call(this);
19348 onBlur : function()
19350 Roo.bootstrap.DateField.superclass.onBlur.call(this);
19352 var d = this.inputEl().getValue();
19359 showPopup : function()
19361 this.picker().show();
19365 this.fireEvent('showpopup', this, this.date);
19368 hidePopup : function()
19370 if(this.isInline) {
19373 this.picker().hide();
19374 this.viewMode = this.startViewMode;
19377 this.fireEvent('hidepopup', this, this.date);
19381 onMousedown: function(e)
19383 e.stopPropagation();
19384 e.preventDefault();
19389 Roo.bootstrap.DateField.superclass.keyup.call(this);
19393 setValue: function(v)
19395 if(this.fireEvent('beforeselect', this, v) !== false){
19396 var d = new Date(this.parseDate(v) ).clearTime();
19398 if(isNaN(d.getTime())){
19399 this.date = this.viewDate = '';
19400 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
19404 v = this.formatDate(d);
19406 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
19408 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
19412 this.fireEvent('select', this, this.date);
19416 getValue: function()
19418 return this.formatDate(this.date);
19421 fireKey: function(e)
19423 if (!this.picker().isVisible()){
19424 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19430 var dateChanged = false,
19432 newDate, newViewDate;
19437 e.preventDefault();
19441 if (!this.keyboardNavigation) {
19444 dir = e.keyCode == 37 ? -1 : 1;
19447 newDate = this.moveYear(this.date, dir);
19448 newViewDate = this.moveYear(this.viewDate, dir);
19449 } else if (e.shiftKey){
19450 newDate = this.moveMonth(this.date, dir);
19451 newViewDate = this.moveMonth(this.viewDate, dir);
19453 newDate = new Date(this.date);
19454 newDate.setUTCDate(this.date.getUTCDate() + dir);
19455 newViewDate = new Date(this.viewDate);
19456 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
19458 if (this.dateWithinRange(newDate)){
19459 this.date = newDate;
19460 this.viewDate = newViewDate;
19461 this.setValue(this.formatDate(this.date));
19463 e.preventDefault();
19464 dateChanged = true;
19469 if (!this.keyboardNavigation) {
19472 dir = e.keyCode == 38 ? -1 : 1;
19474 newDate = this.moveYear(this.date, dir);
19475 newViewDate = this.moveYear(this.viewDate, dir);
19476 } else if (e.shiftKey){
19477 newDate = this.moveMonth(this.date, dir);
19478 newViewDate = this.moveMonth(this.viewDate, dir);
19480 newDate = new Date(this.date);
19481 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
19482 newViewDate = new Date(this.viewDate);
19483 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
19485 if (this.dateWithinRange(newDate)){
19486 this.date = newDate;
19487 this.viewDate = newViewDate;
19488 this.setValue(this.formatDate(this.date));
19490 e.preventDefault();
19491 dateChanged = true;
19495 this.setValue(this.formatDate(this.date));
19497 e.preventDefault();
19500 this.setValue(this.formatDate(this.date));
19514 onClick: function(e)
19516 e.stopPropagation();
19517 e.preventDefault();
19519 var target = e.getTarget();
19521 if(target.nodeName.toLowerCase() === 'i'){
19522 target = Roo.get(target).dom.parentNode;
19525 var nodeName = target.nodeName;
19526 var className = target.className;
19527 var html = target.innerHTML;
19528 //Roo.log(nodeName);
19530 switch(nodeName.toLowerCase()) {
19532 switch(className) {
19538 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
19539 switch(this.viewMode){
19541 this.viewDate = this.moveMonth(this.viewDate, dir);
19545 this.viewDate = this.moveYear(this.viewDate, dir);
19551 var date = new Date();
19552 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
19554 this.setValue(this.formatDate(this.date));
19561 if (className.indexOf('disabled') < 0) {
19562 this.viewDate.setUTCDate(1);
19563 if (className.indexOf('month') > -1) {
19564 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
19566 var year = parseInt(html, 10) || 0;
19567 this.viewDate.setUTCFullYear(year);
19571 if(this.singleMode){
19572 this.setValue(this.formatDate(this.viewDate));
19583 //Roo.log(className);
19584 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
19585 var day = parseInt(html, 10) || 1;
19586 var year = this.viewDate.getUTCFullYear(),
19587 month = this.viewDate.getUTCMonth();
19589 if (className.indexOf('old') > -1) {
19596 } else if (className.indexOf('new') > -1) {
19604 //Roo.log([year,month,day]);
19605 this.date = this.UTCDate(year, month, day,0,0,0,0);
19606 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
19608 //Roo.log(this.formatDate(this.date));
19609 this.setValue(this.formatDate(this.date));
19616 setStartDate: function(startDate)
19618 this.startDate = startDate || -Infinity;
19619 if (this.startDate !== -Infinity) {
19620 this.startDate = this.parseDate(this.startDate);
19623 this.updateNavArrows();
19626 setEndDate: function(endDate)
19628 this.endDate = endDate || Infinity;
19629 if (this.endDate !== Infinity) {
19630 this.endDate = this.parseDate(this.endDate);
19633 this.updateNavArrows();
19636 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
19638 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
19639 if (typeof(this.daysOfWeekDisabled) !== 'object') {
19640 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
19642 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
19643 return parseInt(d, 10);
19646 this.updateNavArrows();
19649 updateNavArrows: function()
19651 if(this.singleMode){
19655 var d = new Date(this.viewDate),
19656 year = d.getUTCFullYear(),
19657 month = d.getUTCMonth();
19659 Roo.each(this.picker().select('.prev', true).elements, function(v){
19661 switch (this.viewMode) {
19664 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
19670 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
19677 Roo.each(this.picker().select('.next', true).elements, function(v){
19679 switch (this.viewMode) {
19682 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
19688 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
19696 moveMonth: function(date, dir)
19701 var new_date = new Date(date.valueOf()),
19702 day = new_date.getUTCDate(),
19703 month = new_date.getUTCMonth(),
19704 mag = Math.abs(dir),
19706 dir = dir > 0 ? 1 : -1;
19709 // If going back one month, make sure month is not current month
19710 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
19712 return new_date.getUTCMonth() == month;
19714 // If going forward one month, make sure month is as expected
19715 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
19717 return new_date.getUTCMonth() != new_month;
19719 new_month = month + dir;
19720 new_date.setUTCMonth(new_month);
19721 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
19722 if (new_month < 0 || new_month > 11) {
19723 new_month = (new_month + 12) % 12;
19726 // For magnitudes >1, move one month at a time...
19727 for (var i=0; i<mag; i++) {
19728 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
19729 new_date = this.moveMonth(new_date, dir);
19731 // ...then reset the day, keeping it in the new month
19732 new_month = new_date.getUTCMonth();
19733 new_date.setUTCDate(day);
19735 return new_month != new_date.getUTCMonth();
19738 // Common date-resetting loop -- if date is beyond end of month, make it
19741 new_date.setUTCDate(--day);
19742 new_date.setUTCMonth(new_month);
19747 moveYear: function(date, dir)
19749 return this.moveMonth(date, dir*12);
19752 dateWithinRange: function(date)
19754 return date >= this.startDate && date <= this.endDate;
19760 this.picker().remove();
19763 validateValue : function(value)
19765 if(this.getVisibilityEl().hasClass('hidden')){
19769 if(value.length < 1) {
19770 if(this.allowBlank){
19776 if(value.length < this.minLength){
19779 if(value.length > this.maxLength){
19783 var vt = Roo.form.VTypes;
19784 if(!vt[this.vtype](value, this)){
19788 if(typeof this.validator == "function"){
19789 var msg = this.validator(value);
19795 if(this.regex && !this.regex.test(value)){
19799 if(typeof(this.parseDate(value)) == 'undefined'){
19803 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
19807 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
19817 this.date = this.viewDate = '';
19819 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
19824 Roo.apply(Roo.bootstrap.DateField, {
19835 html: '<i class="fa fa-arrow-left"/>'
19845 html: '<i class="fa fa-arrow-right"/>'
19887 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
19888 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
19889 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
19890 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19891 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
19904 navFnc: 'FullYear',
19909 navFnc: 'FullYear',
19914 Roo.apply(Roo.bootstrap.DateField, {
19918 cls: 'datepicker dropdown-menu roo-dynamic',
19922 cls: 'datepicker-days',
19926 cls: 'table-condensed',
19928 Roo.bootstrap.DateField.head,
19932 Roo.bootstrap.DateField.footer
19939 cls: 'datepicker-months',
19943 cls: 'table-condensed',
19945 Roo.bootstrap.DateField.head,
19946 Roo.bootstrap.DateField.content,
19947 Roo.bootstrap.DateField.footer
19954 cls: 'datepicker-years',
19958 cls: 'table-condensed',
19960 Roo.bootstrap.DateField.head,
19961 Roo.bootstrap.DateField.content,
19962 Roo.bootstrap.DateField.footer
19981 * @class Roo.bootstrap.TimeField
19982 * @extends Roo.bootstrap.Input
19983 * Bootstrap DateField class
19987 * Create a new TimeField
19988 * @param {Object} config The config object
19991 Roo.bootstrap.TimeField = function(config){
19992 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
19996 * Fires when this field show.
19997 * @param {Roo.bootstrap.DateField} thisthis
19998 * @param {Mixed} date The date value
20003 * Fires when this field hide.
20004 * @param {Roo.bootstrap.DateField} this
20005 * @param {Mixed} date The date value
20010 * Fires when select a date.
20011 * @param {Roo.bootstrap.DateField} this
20012 * @param {Mixed} date The date value
20018 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
20021 * @cfg {String} format
20022 * The default time format string which can be overriden for localization support. The format must be
20023 * valid according to {@link Date#parseDate} (defaults to 'H:i').
20027 onRender: function(ct, position)
20030 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
20032 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
20034 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
20036 this.pop = this.picker().select('>.datepicker-time',true).first();
20037 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
20039 this.picker().on('mousedown', this.onMousedown, this);
20040 this.picker().on('click', this.onClick, this);
20042 this.picker().addClass('datepicker-dropdown');
20047 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
20048 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
20049 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
20050 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
20051 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
20052 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
20056 fireKey: function(e){
20057 if (!this.picker().isVisible()){
20058 if (e.keyCode == 27) { // allow escape to hide and re-show picker
20064 e.preventDefault();
20072 this.onTogglePeriod();
20075 this.onIncrementMinutes();
20078 this.onDecrementMinutes();
20087 onClick: function(e) {
20088 e.stopPropagation();
20089 e.preventDefault();
20092 picker : function()
20094 return this.el.select('.datepicker', true).first();
20097 fillTime: function()
20099 var time = this.pop.select('tbody', true).first();
20101 time.dom.innerHTML = '';
20116 cls: 'hours-up glyphicon glyphicon-chevron-up'
20136 cls: 'minutes-up glyphicon glyphicon-chevron-up'
20157 cls: 'timepicker-hour',
20172 cls: 'timepicker-minute',
20187 cls: 'btn btn-primary period',
20209 cls: 'hours-down glyphicon glyphicon-chevron-down'
20229 cls: 'minutes-down glyphicon glyphicon-chevron-down'
20247 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
20254 var hours = this.time.getHours();
20255 var minutes = this.time.getMinutes();
20268 hours = hours - 12;
20272 hours = '0' + hours;
20276 minutes = '0' + minutes;
20279 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
20280 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
20281 this.pop.select('button', true).first().dom.innerHTML = period;
20287 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
20289 var cls = ['bottom'];
20291 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
20298 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
20303 this.picker().addClass(cls.join('-'));
20307 Roo.each(cls, function(c){
20309 _this.picker().setTop(_this.inputEl().getHeight());
20313 _this.picker().setTop(0 - _this.picker().getHeight());
20318 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
20322 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
20329 onFocus : function()
20331 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
20335 onBlur : function()
20337 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
20343 this.picker().show();
20348 this.fireEvent('show', this, this.date);
20353 this.picker().hide();
20356 this.fireEvent('hide', this, this.date);
20359 setTime : function()
20362 this.setValue(this.time.format(this.format));
20364 this.fireEvent('select', this, this.date);
20369 onMousedown: function(e){
20370 e.stopPropagation();
20371 e.preventDefault();
20374 onIncrementHours: function()
20376 Roo.log('onIncrementHours');
20377 this.time = this.time.add(Date.HOUR, 1);
20382 onDecrementHours: function()
20384 Roo.log('onDecrementHours');
20385 this.time = this.time.add(Date.HOUR, -1);
20389 onIncrementMinutes: function()
20391 Roo.log('onIncrementMinutes');
20392 this.time = this.time.add(Date.MINUTE, 1);
20396 onDecrementMinutes: function()
20398 Roo.log('onDecrementMinutes');
20399 this.time = this.time.add(Date.MINUTE, -1);
20403 onTogglePeriod: function()
20405 Roo.log('onTogglePeriod');
20406 this.time = this.time.add(Date.HOUR, 12);
20413 Roo.apply(Roo.bootstrap.TimeField, {
20443 cls: 'btn btn-info ok',
20455 Roo.apply(Roo.bootstrap.TimeField, {
20459 cls: 'datepicker dropdown-menu',
20463 cls: 'datepicker-time',
20467 cls: 'table-condensed',
20469 Roo.bootstrap.TimeField.content,
20470 Roo.bootstrap.TimeField.footer
20489 * @class Roo.bootstrap.MonthField
20490 * @extends Roo.bootstrap.Input
20491 * Bootstrap MonthField class
20493 * @cfg {String} language default en
20496 * Create a new MonthField
20497 * @param {Object} config The config object
20500 Roo.bootstrap.MonthField = function(config){
20501 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
20506 * Fires when this field show.
20507 * @param {Roo.bootstrap.MonthField} this
20508 * @param {Mixed} date The date value
20513 * Fires when this field hide.
20514 * @param {Roo.bootstrap.MonthField} this
20515 * @param {Mixed} date The date value
20520 * Fires when select a date.
20521 * @param {Roo.bootstrap.MonthField} this
20522 * @param {String} oldvalue The old value
20523 * @param {String} newvalue The new value
20529 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
20531 onRender: function(ct, position)
20534 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
20536 this.language = this.language || 'en';
20537 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
20538 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
20540 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
20541 this.isInline = false;
20542 this.isInput = true;
20543 this.component = this.el.select('.add-on', true).first() || false;
20544 this.component = (this.component && this.component.length === 0) ? false : this.component;
20545 this.hasInput = this.component && this.inputEL().length;
20547 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
20549 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
20551 this.picker().on('mousedown', this.onMousedown, this);
20552 this.picker().on('click', this.onClick, this);
20554 this.picker().addClass('datepicker-dropdown');
20556 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
20557 v.setStyle('width', '189px');
20564 if(this.isInline) {
20570 setValue: function(v, suppressEvent)
20572 var o = this.getValue();
20574 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
20578 if(suppressEvent !== true){
20579 this.fireEvent('select', this, o, v);
20584 getValue: function()
20589 onClick: function(e)
20591 e.stopPropagation();
20592 e.preventDefault();
20594 var target = e.getTarget();
20596 if(target.nodeName.toLowerCase() === 'i'){
20597 target = Roo.get(target).dom.parentNode;
20600 var nodeName = target.nodeName;
20601 var className = target.className;
20602 var html = target.innerHTML;
20604 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
20608 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
20610 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20616 picker : function()
20618 return this.pickerEl;
20621 fillMonths: function()
20624 var months = this.picker().select('>.datepicker-months td', true).first();
20626 months.dom.innerHTML = '';
20632 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
20635 months.createChild(month);
20644 if(typeof(this.vIndex) == 'undefined' && this.value.length){
20645 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
20648 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
20649 e.removeClass('active');
20651 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
20652 e.addClass('active');
20659 if(this.isInline) {
20663 this.picker().removeClass(['bottom', 'top']);
20665 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
20667 * place to the top of element!
20671 this.picker().addClass('top');
20672 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
20677 this.picker().addClass('bottom');
20679 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
20682 onFocus : function()
20684 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
20688 onBlur : function()
20690 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
20692 var d = this.inputEl().getValue();
20701 this.picker().show();
20702 this.picker().select('>.datepicker-months', true).first().show();
20706 this.fireEvent('show', this, this.date);
20711 if(this.isInline) {
20714 this.picker().hide();
20715 this.fireEvent('hide', this, this.date);
20719 onMousedown: function(e)
20721 e.stopPropagation();
20722 e.preventDefault();
20727 Roo.bootstrap.MonthField.superclass.keyup.call(this);
20731 fireKey: function(e)
20733 if (!this.picker().isVisible()){
20734 if (e.keyCode == 27) {// allow escape to hide and re-show picker
20745 e.preventDefault();
20749 dir = e.keyCode == 37 ? -1 : 1;
20751 this.vIndex = this.vIndex + dir;
20753 if(this.vIndex < 0){
20757 if(this.vIndex > 11){
20761 if(isNaN(this.vIndex)){
20765 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20771 dir = e.keyCode == 38 ? -1 : 1;
20773 this.vIndex = this.vIndex + dir * 4;
20775 if(this.vIndex < 0){
20779 if(this.vIndex > 11){
20783 if(isNaN(this.vIndex)){
20787 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20792 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20793 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20797 e.preventDefault();
20800 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20801 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20817 this.picker().remove();
20822 Roo.apply(Roo.bootstrap.MonthField, {
20841 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
20842 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
20847 Roo.apply(Roo.bootstrap.MonthField, {
20851 cls: 'datepicker dropdown-menu roo-dynamic',
20855 cls: 'datepicker-months',
20859 cls: 'table-condensed',
20861 Roo.bootstrap.DateField.content
20881 * @class Roo.bootstrap.CheckBox
20882 * @extends Roo.bootstrap.Input
20883 * Bootstrap CheckBox class
20885 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
20886 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
20887 * @cfg {String} boxLabel The text that appears beside the checkbox
20888 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
20889 * @cfg {Boolean} checked initnal the element
20890 * @cfg {Boolean} inline inline the element (default false)
20891 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
20892 * @cfg {String} tooltip label tooltip
20895 * Create a new CheckBox
20896 * @param {Object} config The config object
20899 Roo.bootstrap.CheckBox = function(config){
20900 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
20905 * Fires when the element is checked or unchecked.
20906 * @param {Roo.bootstrap.CheckBox} this This input
20907 * @param {Boolean} checked The new checked value
20912 * Fires when the element is click.
20913 * @param {Roo.bootstrap.CheckBox} this This input
20920 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
20922 inputType: 'checkbox',
20931 getAutoCreate : function()
20933 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20939 cfg.cls = 'form-group ' + this.inputType; //input-group
20942 cfg.cls += ' ' + this.inputType + '-inline';
20948 type : this.inputType,
20949 value : this.inputValue,
20950 cls : 'roo-' + this.inputType, //'form-box',
20951 placeholder : this.placeholder || ''
20955 if(this.inputType != 'radio'){
20959 cls : 'roo-hidden-value',
20960 value : this.checked ? this.inputValue : this.valueOff
20965 if (this.weight) { // Validity check?
20966 cfg.cls += " " + this.inputType + "-" + this.weight;
20969 if (this.disabled) {
20970 input.disabled=true;
20974 input.checked = this.checked;
20979 input.name = this.name;
20981 if(this.inputType != 'radio'){
20982 hidden.name = this.name;
20983 input.name = '_hidden_' + this.name;
20988 input.cls += ' input-' + this.size;
20993 ['xs','sm','md','lg'].map(function(size){
20994 if (settings[size]) {
20995 cfg.cls += ' col-' + size + '-' + settings[size];
20999 var inputblock = input;
21001 if (this.before || this.after) {
21004 cls : 'input-group',
21009 inputblock.cn.push({
21011 cls : 'input-group-addon',
21016 inputblock.cn.push(input);
21018 if(this.inputType != 'radio'){
21019 inputblock.cn.push(hidden);
21023 inputblock.cn.push({
21025 cls : 'input-group-addon',
21032 if (align ==='left' && this.fieldLabel.length) {
21033 // Roo.log("left and has label");
21038 cls : 'control-label',
21039 html : this.fieldLabel
21049 if(this.labelWidth > 12){
21050 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
21053 if(this.labelWidth < 13 && this.labelmd == 0){
21054 this.labelmd = this.labelWidth;
21057 if(this.labellg > 0){
21058 cfg.cn[0].cls += ' col-lg-' + this.labellg;
21059 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
21062 if(this.labelmd > 0){
21063 cfg.cn[0].cls += ' col-md-' + this.labelmd;
21064 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
21067 if(this.labelsm > 0){
21068 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
21069 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
21072 if(this.labelxs > 0){
21073 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
21074 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
21077 } else if ( this.fieldLabel.length) {
21078 // Roo.log(" label");
21082 tag: this.boxLabel ? 'span' : 'label',
21084 cls: 'control-label box-input-label',
21085 //cls : 'input-group-addon',
21086 html : this.fieldLabel
21095 // Roo.log(" no label && no align");
21096 cfg.cn = [ inputblock ] ;
21102 var boxLabelCfg = {
21104 //'for': id, // box label is handled by onclick - so no for...
21106 html: this.boxLabel
21110 boxLabelCfg.tooltip = this.tooltip;
21113 cfg.cn.push(boxLabelCfg);
21116 if(this.inputType != 'radio'){
21117 cfg.cn.push(hidden);
21125 * return the real input element.
21127 inputEl: function ()
21129 return this.el.select('input.roo-' + this.inputType,true).first();
21131 hiddenEl: function ()
21133 return this.el.select('input.roo-hidden-value',true).first();
21136 labelEl: function()
21138 return this.el.select('label.control-label',true).first();
21140 /* depricated... */
21144 return this.labelEl();
21147 boxLabelEl: function()
21149 return this.el.select('label.box-label',true).first();
21152 initEvents : function()
21154 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
21156 this.inputEl().on('click', this.onClick, this);
21158 if (this.boxLabel) {
21159 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
21162 this.startValue = this.getValue();
21165 Roo.bootstrap.CheckBox.register(this);
21169 onClick : function(e)
21171 if(this.fireEvent('click', this, e) !== false){
21172 this.setChecked(!this.checked);
21177 setChecked : function(state,suppressEvent)
21179 this.startValue = this.getValue();
21181 if(this.inputType == 'radio'){
21183 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21184 e.dom.checked = false;
21187 this.inputEl().dom.checked = true;
21189 this.inputEl().dom.value = this.inputValue;
21191 if(suppressEvent !== true){
21192 this.fireEvent('check', this, true);
21200 this.checked = state;
21202 this.inputEl().dom.checked = state;
21205 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
21207 if(suppressEvent !== true){
21208 this.fireEvent('check', this, state);
21214 getValue : function()
21216 if(this.inputType == 'radio'){
21217 return this.getGroupValue();
21220 return this.hiddenEl().dom.value;
21224 getGroupValue : function()
21226 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
21230 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
21233 setValue : function(v,suppressEvent)
21235 if(this.inputType == 'radio'){
21236 this.setGroupValue(v, suppressEvent);
21240 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
21245 setGroupValue : function(v, suppressEvent)
21247 this.startValue = this.getValue();
21249 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21250 e.dom.checked = false;
21252 if(e.dom.value == v){
21253 e.dom.checked = true;
21257 if(suppressEvent !== true){
21258 this.fireEvent('check', this, true);
21266 validate : function()
21268 if(this.getVisibilityEl().hasClass('hidden')){
21274 (this.inputType == 'radio' && this.validateRadio()) ||
21275 (this.inputType == 'checkbox' && this.validateCheckbox())
21281 this.markInvalid();
21285 validateRadio : function()
21287 if(this.getVisibilityEl().hasClass('hidden')){
21291 if(this.allowBlank){
21297 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21298 if(!e.dom.checked){
21310 validateCheckbox : function()
21313 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
21314 //return (this.getValue() == this.inputValue) ? true : false;
21317 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21325 for(var i in group){
21326 if(group[i].el.isVisible(true)){
21334 for(var i in group){
21339 r = (group[i].getValue() == group[i].inputValue) ? true : false;
21346 * Mark this field as valid
21348 markValid : function()
21352 this.fireEvent('valid', this);
21354 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21357 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
21364 if(this.inputType == 'radio'){
21365 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21366 var fg = e.findParent('.form-group', false, true);
21367 if (Roo.bootstrap.version == 3) {
21368 fg.removeClass([_this.invalidClass, _this.validClass]);
21369 fg.addClass(_this.validClass);
21371 fg.removeClass(['is-valid', 'is-invalid']);
21372 fg.addClass('is-valid');
21380 var fg = this.el.findParent('.form-group', false, true);
21381 if (Roo.bootstrap.version == 3) {
21382 fg.removeClass([this.invalidClass, this.validClass]);
21383 fg.addClass(this.validClass);
21385 fg.removeClass(['is-valid', 'is-invalid']);
21386 fg.addClass('is-valid');
21391 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21397 for(var i in group){
21398 var fg = group[i].el.findParent('.form-group', false, true);
21399 if (Roo.bootstrap.version == 3) {
21400 fg.removeClass([this.invalidClass, this.validClass]);
21401 fg.addClass(this.validClass);
21403 fg.removeClass(['is-valid', 'is-invalid']);
21404 fg.addClass('is-valid');
21410 * Mark this field as invalid
21411 * @param {String} msg The validation message
21413 markInvalid : function(msg)
21415 if(this.allowBlank){
21421 this.fireEvent('invalid', this, msg);
21423 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21426 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
21430 label.markInvalid();
21433 if(this.inputType == 'radio'){
21435 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21436 var fg = e.findParent('.form-group', false, true);
21437 if (Roo.bootstrap.version == 3) {
21438 fg.removeClass([_this.invalidClass, _this.validClass]);
21439 fg.addClass(_this.invalidClass);
21441 fg.removeClass(['is-invalid', 'is-valid']);
21442 fg.addClass('is-invalid');
21450 var fg = this.el.findParent('.form-group', false, true);
21451 if (Roo.bootstrap.version == 3) {
21452 fg.removeClass([_this.invalidClass, _this.validClass]);
21453 fg.addClass(_this.invalidClass);
21455 fg.removeClass(['is-invalid', 'is-valid']);
21456 fg.addClass('is-invalid');
21461 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21467 for(var i in group){
21468 var fg = group[i].el.findParent('.form-group', false, true);
21469 if (Roo.bootstrap.version == 3) {
21470 fg.removeClass([_this.invalidClass, _this.validClass]);
21471 fg.addClass(_this.invalidClass);
21473 fg.removeClass(['is-invalid', 'is-valid']);
21474 fg.addClass('is-invalid');
21480 clearInvalid : function()
21482 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
21484 // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21486 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21488 if (label && label.iconEl) {
21489 label.iconEl.removeClass([ label.validClass, label.invalidClass ]);
21490 label.iconEl.removeClass(['is-invalid', 'is-valid']);
21494 disable : function()
21496 if(this.inputType != 'radio'){
21497 Roo.bootstrap.CheckBox.superclass.disable.call(this);
21504 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21505 _this.getActionEl().addClass(this.disabledClass);
21506 e.dom.disabled = true;
21510 this.disabled = true;
21511 this.fireEvent("disable", this);
21515 enable : function()
21517 if(this.inputType != 'radio'){
21518 Roo.bootstrap.CheckBox.superclass.enable.call(this);
21525 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21526 _this.getActionEl().removeClass(this.disabledClass);
21527 e.dom.disabled = false;
21531 this.disabled = false;
21532 this.fireEvent("enable", this);
21536 setBoxLabel : function(v)
21541 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21547 Roo.apply(Roo.bootstrap.CheckBox, {
21552 * register a CheckBox Group
21553 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
21555 register : function(checkbox)
21557 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
21558 this.groups[checkbox.groupId] = {};
21561 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
21565 this.groups[checkbox.groupId][checkbox.name] = checkbox;
21569 * fetch a CheckBox Group based on the group ID
21570 * @param {string} the group ID
21571 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
21573 get: function(groupId) {
21574 if (typeof(this.groups[groupId]) == 'undefined') {
21578 return this.groups[groupId] ;
21591 * @class Roo.bootstrap.Radio
21592 * @extends Roo.bootstrap.Component
21593 * Bootstrap Radio class
21594 * @cfg {String} boxLabel - the label associated
21595 * @cfg {String} value - the value of radio
21598 * Create a new Radio
21599 * @param {Object} config The config object
21601 Roo.bootstrap.Radio = function(config){
21602 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
21606 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
21612 getAutoCreate : function()
21616 cls : 'form-group radio',
21621 html : this.boxLabel
21629 initEvents : function()
21631 this.parent().register(this);
21633 this.el.on('click', this.onClick, this);
21637 onClick : function(e)
21639 if(this.parent().fireEvent('click', this.parent(), this, e) !== false){
21640 this.setChecked(true);
21644 setChecked : function(state, suppressEvent)
21646 this.parent().setValue(this.value, suppressEvent);
21650 setBoxLabel : function(v)
21655 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21670 * @class Roo.bootstrap.SecurePass
21671 * @extends Roo.bootstrap.Input
21672 * Bootstrap SecurePass class
21676 * Create a new SecurePass
21677 * @param {Object} config The config object
21680 Roo.bootstrap.SecurePass = function (config) {
21681 // these go here, so the translation tool can replace them..
21683 PwdEmpty: "Please type a password, and then retype it to confirm.",
21684 PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21685 PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21686 PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21687 IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21688 FNInPwd: "Your password can't contain your first name. Please type a different password.",
21689 LNInPwd: "Your password can't contain your last name. Please type a different password.",
21690 TooWeak: "Your password is Too Weak."
21692 this.meterLabel = "Password strength:";
21693 this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
21694 this.meterClass = [
21695 "roo-password-meter-tooweak",
21696 "roo-password-meter-weak",
21697 "roo-password-meter-medium",
21698 "roo-password-meter-strong",
21699 "roo-password-meter-grey"
21704 Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
21707 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
21709 * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
21711 * PwdEmpty: "Please type a password, and then retype it to confirm.",
21712 * PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21713 * PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21714 * PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21715 * IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21716 * FNInPwd: "Your password can't contain your first name. Please type a different password.",
21717 * LNInPwd: "Your password can't contain your last name. Please type a different password."
21727 * @cfg {String/Object} Label for the strength meter (defaults to
21728 * 'Password strength:')
21733 * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
21734 * ['Weak', 'Medium', 'Strong'])
21737 pwdStrengths: false,
21750 initEvents: function ()
21752 Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
21754 if (this.el.is('input[type=password]') && Roo.isSafari) {
21755 this.el.on('keydown', this.SafariOnKeyDown, this);
21758 this.el.on('keyup', this.checkStrength, this, {buffer: 50});
21761 onRender: function (ct, position)
21763 Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
21764 this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
21765 this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
21767 this.trigger.createChild({
21772 cls: 'roo-password-meter-grey col-xs-12',
21775 //width: this.meterWidth + 'px'
21779 cls: 'roo-password-meter-text'
21785 if (this.hideTrigger) {
21786 this.trigger.setDisplayed(false);
21788 this.setSize(this.width || '', this.height || '');
21791 onDestroy: function ()
21793 if (this.trigger) {
21794 this.trigger.removeAllListeners();
21795 this.trigger.remove();
21798 this.wrap.remove();
21800 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
21803 checkStrength: function ()
21805 var pwd = this.inputEl().getValue();
21806 if (pwd == this._lastPwd) {
21811 if (this.ClientSideStrongPassword(pwd)) {
21813 } else if (this.ClientSideMediumPassword(pwd)) {
21815 } else if (this.ClientSideWeakPassword(pwd)) {
21821 Roo.log('strength1: ' + strength);
21823 //var pm = this.trigger.child('div/div/div').dom;
21824 var pm = this.trigger.child('div/div');
21825 pm.removeClass(this.meterClass);
21826 pm.addClass(this.meterClass[strength]);
21829 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21831 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21833 this._lastPwd = pwd;
21837 Roo.bootstrap.SecurePass.superclass.reset.call(this);
21839 this._lastPwd = '';
21841 var pm = this.trigger.child('div/div');
21842 pm.removeClass(this.meterClass);
21843 pm.addClass('roo-password-meter-grey');
21846 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21849 this.inputEl().dom.type='password';
21852 validateValue: function (value)
21855 if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
21858 if (value.length == 0) {
21859 if (this.allowBlank) {
21860 this.clearInvalid();
21864 this.markInvalid(this.errors.PwdEmpty);
21865 this.errorMsg = this.errors.PwdEmpty;
21873 if ('[\x21-\x7e]*'.match(value)) {
21874 this.markInvalid(this.errors.PwdBadChar);
21875 this.errorMsg = this.errors.PwdBadChar;
21878 if (value.length < 6) {
21879 this.markInvalid(this.errors.PwdShort);
21880 this.errorMsg = this.errors.PwdShort;
21883 if (value.length > 16) {
21884 this.markInvalid(this.errors.PwdLong);
21885 this.errorMsg = this.errors.PwdLong;
21889 if (this.ClientSideStrongPassword(value)) {
21891 } else if (this.ClientSideMediumPassword(value)) {
21893 } else if (this.ClientSideWeakPassword(value)) {
21900 if (strength < 2) {
21901 //this.markInvalid(this.errors.TooWeak);
21902 this.errorMsg = this.errors.TooWeak;
21907 console.log('strength2: ' + strength);
21909 //var pm = this.trigger.child('div/div/div').dom;
21911 var pm = this.trigger.child('div/div');
21912 pm.removeClass(this.meterClass);
21913 pm.addClass(this.meterClass[strength]);
21915 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21917 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21919 this.errorMsg = '';
21923 CharacterSetChecks: function (type)
21926 this.fResult = false;
21929 isctype: function (character, type)
21932 case this.kCapitalLetter:
21933 if (character >= 'A' && character <= 'Z') {
21938 case this.kSmallLetter:
21939 if (character >= 'a' && character <= 'z') {
21945 if (character >= '0' && character <= '9') {
21950 case this.kPunctuation:
21951 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
21962 IsLongEnough: function (pwd, size)
21964 return !(pwd == null || isNaN(size) || pwd.length < size);
21967 SpansEnoughCharacterSets: function (word, nb)
21969 if (!this.IsLongEnough(word, nb))
21974 var characterSetChecks = new Array(
21975 new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
21976 new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
21979 for (var index = 0; index < word.length; ++index) {
21980 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21981 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
21982 characterSetChecks[nCharSet].fResult = true;
21989 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21990 if (characterSetChecks[nCharSet].fResult) {
21995 if (nCharSets < nb) {
22001 ClientSideStrongPassword: function (pwd)
22003 return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
22006 ClientSideMediumPassword: function (pwd)
22008 return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
22011 ClientSideWeakPassword: function (pwd)
22013 return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
22016 })//<script type="text/javascript">
22019 * Based Ext JS Library 1.1.1
22020 * Copyright(c) 2006-2007, Ext JS, LLC.
22026 * @class Roo.HtmlEditorCore
22027 * @extends Roo.Component
22028 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
22030 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
22033 Roo.HtmlEditorCore = function(config){
22036 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
22041 * @event initialize
22042 * Fires when the editor is fully initialized (including the iframe)
22043 * @param {Roo.HtmlEditorCore} this
22048 * Fires when the editor is first receives the focus. Any insertion must wait
22049 * until after this event.
22050 * @param {Roo.HtmlEditorCore} this
22054 * @event beforesync
22055 * Fires before the textarea is updated with content from the editor iframe. Return false
22056 * to cancel the sync.
22057 * @param {Roo.HtmlEditorCore} this
22058 * @param {String} html
22062 * @event beforepush
22063 * Fires before the iframe editor is updated with content from the textarea. Return false
22064 * to cancel the push.
22065 * @param {Roo.HtmlEditorCore} this
22066 * @param {String} html
22071 * Fires when the textarea is updated with content from the editor iframe.
22072 * @param {Roo.HtmlEditorCore} this
22073 * @param {String} html
22078 * Fires when the iframe editor is updated with content from the textarea.
22079 * @param {Roo.HtmlEditorCore} this
22080 * @param {String} html
22085 * @event editorevent
22086 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
22087 * @param {Roo.HtmlEditorCore} this
22093 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
22095 // defaults : white / black...
22096 this.applyBlacklists();
22103 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
22107 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
22113 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
22118 * @cfg {Number} height (in pixels)
22122 * @cfg {Number} width (in pixels)
22127 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
22130 stylesheets: false,
22135 // private properties
22136 validationEvent : false,
22138 initialized : false,
22140 sourceEditMode : false,
22141 onFocus : Roo.emptyFn,
22143 hideMode:'offsets',
22147 // blacklist + whitelisted elements..
22154 * Protected method that will not generally be called directly. It
22155 * is called when the editor initializes the iframe with HTML contents. Override this method if you
22156 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
22158 getDocMarkup : function(){
22162 // inherit styels from page...??
22163 if (this.stylesheets === false) {
22165 Roo.get(document.head).select('style').each(function(node) {
22166 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
22169 Roo.get(document.head).select('link').each(function(node) {
22170 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
22173 } else if (!this.stylesheets.length) {
22175 st = '<style type="text/css">' +
22176 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
22179 st = '<style type="text/css">' +
22184 st += '<style type="text/css">' +
22185 'IMG { cursor: pointer } ' +
22188 var cls = 'roo-htmleditor-body';
22190 if(this.bodyCls.length){
22191 cls += ' ' + this.bodyCls;
22194 return '<html><head>' + st +
22195 //<style type="text/css">' +
22196 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
22198 ' </head><body class="' + cls + '"></body></html>';
22202 onRender : function(ct, position)
22205 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
22206 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
22209 this.el.dom.style.border = '0 none';
22210 this.el.dom.setAttribute('tabIndex', -1);
22211 this.el.addClass('x-hidden hide');
22215 if(Roo.isIE){ // fix IE 1px bogus margin
22216 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
22220 this.frameId = Roo.id();
22224 var iframe = this.owner.wrap.createChild({
22226 cls: 'form-control', // bootstrap..
22228 name: this.frameId,
22229 frameBorder : 'no',
22230 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
22235 this.iframe = iframe.dom;
22237 this.assignDocWin();
22239 this.doc.designMode = 'on';
22242 this.doc.write(this.getDocMarkup());
22246 var task = { // must defer to wait for browser to be ready
22248 //console.log("run task?" + this.doc.readyState);
22249 this.assignDocWin();
22250 if(this.doc.body || this.doc.readyState == 'complete'){
22252 this.doc.designMode="on";
22256 Roo.TaskMgr.stop(task);
22257 this.initEditor.defer(10, this);
22264 Roo.TaskMgr.start(task);
22269 onResize : function(w, h)
22271 Roo.log('resize: ' +w + ',' + h );
22272 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
22276 if(typeof w == 'number'){
22278 this.iframe.style.width = w + 'px';
22280 if(typeof h == 'number'){
22282 this.iframe.style.height = h + 'px';
22284 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
22291 * Toggles the editor between standard and source edit mode.
22292 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
22294 toggleSourceEdit : function(sourceEditMode){
22296 this.sourceEditMode = sourceEditMode === true;
22298 if(this.sourceEditMode){
22300 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
22303 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
22304 //this.iframe.className = '';
22307 //this.setSize(this.owner.wrap.getSize());
22308 //this.fireEvent('editmodechange', this, this.sourceEditMode);
22315 * Protected method that will not generally be called directly. If you need/want
22316 * custom HTML cleanup, this is the method you should override.
22317 * @param {String} html The HTML to be cleaned
22318 * return {String} The cleaned HTML
22320 cleanHtml : function(html){
22321 html = String(html);
22322 if(html.length > 5){
22323 if(Roo.isSafari){ // strip safari nonsense
22324 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
22327 if(html == ' '){
22334 * HTML Editor -> Textarea
22335 * Protected method that will not generally be called directly. Syncs the contents
22336 * of the editor iframe with the textarea.
22338 syncValue : function(){
22339 if(this.initialized){
22340 var bd = (this.doc.body || this.doc.documentElement);
22341 //this.cleanUpPaste(); -- this is done else where and causes havoc..
22342 var html = bd.innerHTML;
22344 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
22345 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
22347 html = '<div style="'+m[0]+'">' + html + '</div>';
22350 html = this.cleanHtml(html);
22351 // fix up the special chars.. normaly like back quotes in word...
22352 // however we do not want to do this with chinese..
22353 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
22354 var cc = b.charCodeAt();
22356 (cc >= 0x4E00 && cc < 0xA000 ) ||
22357 (cc >= 0x3400 && cc < 0x4E00 ) ||
22358 (cc >= 0xf900 && cc < 0xfb00 )
22364 if(this.owner.fireEvent('beforesync', this, html) !== false){
22365 this.el.dom.value = html;
22366 this.owner.fireEvent('sync', this, html);
22372 * Protected method that will not generally be called directly. Pushes the value of the textarea
22373 * into the iframe editor.
22375 pushValue : function(){
22376 if(this.initialized){
22377 var v = this.el.dom.value.trim();
22379 // if(v.length < 1){
22383 if(this.owner.fireEvent('beforepush', this, v) !== false){
22384 var d = (this.doc.body || this.doc.documentElement);
22386 this.cleanUpPaste();
22387 this.el.dom.value = d.innerHTML;
22388 this.owner.fireEvent('push', this, v);
22394 deferFocus : function(){
22395 this.focus.defer(10, this);
22399 focus : function(){
22400 if(this.win && !this.sourceEditMode){
22407 assignDocWin: function()
22409 var iframe = this.iframe;
22412 this.doc = iframe.contentWindow.document;
22413 this.win = iframe.contentWindow;
22415 // if (!Roo.get(this.frameId)) {
22418 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
22419 // this.win = Roo.get(this.frameId).dom.contentWindow;
22421 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
22425 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
22426 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
22431 initEditor : function(){
22432 //console.log("INIT EDITOR");
22433 this.assignDocWin();
22437 this.doc.designMode="on";
22439 this.doc.write(this.getDocMarkup());
22442 var dbody = (this.doc.body || this.doc.documentElement);
22443 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
22444 // this copies styles from the containing element into thsi one..
22445 // not sure why we need all of this..
22446 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
22448 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
22449 //ss['background-attachment'] = 'fixed'; // w3c
22450 dbody.bgProperties = 'fixed'; // ie
22451 //Roo.DomHelper.applyStyles(dbody, ss);
22452 Roo.EventManager.on(this.doc, {
22453 //'mousedown': this.onEditorEvent,
22454 'mouseup': this.onEditorEvent,
22455 'dblclick': this.onEditorEvent,
22456 'click': this.onEditorEvent,
22457 'keyup': this.onEditorEvent,
22462 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
22464 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
22465 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
22467 this.initialized = true;
22469 this.owner.fireEvent('initialize', this);
22474 onDestroy : function(){
22480 //for (var i =0; i < this.toolbars.length;i++) {
22481 // // fixme - ask toolbars for heights?
22482 // this.toolbars[i].onDestroy();
22485 //this.wrap.dom.innerHTML = '';
22486 //this.wrap.remove();
22491 onFirstFocus : function(){
22493 this.assignDocWin();
22496 this.activated = true;
22499 if(Roo.isGecko){ // prevent silly gecko errors
22501 var s = this.win.getSelection();
22502 if(!s.focusNode || s.focusNode.nodeType != 3){
22503 var r = s.getRangeAt(0);
22504 r.selectNodeContents((this.doc.body || this.doc.documentElement));
22509 this.execCmd('useCSS', true);
22510 this.execCmd('styleWithCSS', false);
22513 this.owner.fireEvent('activate', this);
22517 adjustFont: function(btn){
22518 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
22519 //if(Roo.isSafari){ // safari
22522 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
22523 if(Roo.isSafari){ // safari
22524 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
22525 v = (v < 10) ? 10 : v;
22526 v = (v > 48) ? 48 : v;
22527 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
22532 v = Math.max(1, v+adjust);
22534 this.execCmd('FontSize', v );
22537 onEditorEvent : function(e)
22539 this.owner.fireEvent('editorevent', this, e);
22540 // this.updateToolbar();
22541 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
22544 insertTag : function(tg)
22546 // could be a bit smarter... -> wrap the current selected tRoo..
22547 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
22549 range = this.createRange(this.getSelection());
22550 var wrappingNode = this.doc.createElement(tg.toLowerCase());
22551 wrappingNode.appendChild(range.extractContents());
22552 range.insertNode(wrappingNode);
22559 this.execCmd("formatblock", tg);
22563 insertText : function(txt)
22567 var range = this.createRange();
22568 range.deleteContents();
22569 //alert(Sender.getAttribute('label'));
22571 range.insertNode(this.doc.createTextNode(txt));
22577 * Executes a Midas editor command on the editor document and performs necessary focus and
22578 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
22579 * @param {String} cmd The Midas command
22580 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22582 relayCmd : function(cmd, value){
22584 this.execCmd(cmd, value);
22585 this.owner.fireEvent('editorevent', this);
22586 //this.updateToolbar();
22587 this.owner.deferFocus();
22591 * Executes a Midas editor command directly on the editor document.
22592 * For visual commands, you should use {@link #relayCmd} instead.
22593 * <b>This should only be called after the editor is initialized.</b>
22594 * @param {String} cmd The Midas command
22595 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22597 execCmd : function(cmd, value){
22598 this.doc.execCommand(cmd, false, value === undefined ? null : value);
22605 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
22607 * @param {String} text | dom node..
22609 insertAtCursor : function(text)
22612 if(!this.activated){
22618 var r = this.doc.selection.createRange();
22629 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
22633 // from jquery ui (MIT licenced)
22635 var win = this.win;
22637 if (win.getSelection && win.getSelection().getRangeAt) {
22638 range = win.getSelection().getRangeAt(0);
22639 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
22640 range.insertNode(node);
22641 } else if (win.document.selection && win.document.selection.createRange) {
22642 // no firefox support
22643 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22644 win.document.selection.createRange().pasteHTML(txt);
22646 // no firefox support
22647 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22648 this.execCmd('InsertHTML', txt);
22657 mozKeyPress : function(e){
22659 var c = e.getCharCode(), cmd;
22662 c = String.fromCharCode(c).toLowerCase();
22676 this.cleanUpPaste.defer(100, this);
22684 e.preventDefault();
22692 fixKeys : function(){ // load time branching for fastest keydown performance
22694 return function(e){
22695 var k = e.getKey(), r;
22698 r = this.doc.selection.createRange();
22701 r.pasteHTML('    ');
22708 r = this.doc.selection.createRange();
22710 var target = r.parentElement();
22711 if(!target || target.tagName.toLowerCase() != 'li'){
22713 r.pasteHTML('<br />');
22719 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22720 this.cleanUpPaste.defer(100, this);
22726 }else if(Roo.isOpera){
22727 return function(e){
22728 var k = e.getKey();
22732 this.execCmd('InsertHTML','    ');
22735 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22736 this.cleanUpPaste.defer(100, this);
22741 }else if(Roo.isSafari){
22742 return function(e){
22743 var k = e.getKey();
22747 this.execCmd('InsertText','\t');
22751 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22752 this.cleanUpPaste.defer(100, this);
22760 getAllAncestors: function()
22762 var p = this.getSelectedNode();
22765 a.push(p); // push blank onto stack..
22766 p = this.getParentElement();
22770 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
22774 a.push(this.doc.body);
22778 lastSelNode : false,
22781 getSelection : function()
22783 this.assignDocWin();
22784 return Roo.isIE ? this.doc.selection : this.win.getSelection();
22787 getSelectedNode: function()
22789 // this may only work on Gecko!!!
22791 // should we cache this!!!!
22796 var range = this.createRange(this.getSelection()).cloneRange();
22799 var parent = range.parentElement();
22801 var testRange = range.duplicate();
22802 testRange.moveToElementText(parent);
22803 if (testRange.inRange(range)) {
22806 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
22809 parent = parent.parentElement;
22814 // is ancestor a text element.
22815 var ac = range.commonAncestorContainer;
22816 if (ac.nodeType == 3) {
22817 ac = ac.parentNode;
22820 var ar = ac.childNodes;
22823 var other_nodes = [];
22824 var has_other_nodes = false;
22825 for (var i=0;i<ar.length;i++) {
22826 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
22829 // fullly contained node.
22831 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
22836 // probably selected..
22837 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
22838 other_nodes.push(ar[i]);
22842 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
22847 has_other_nodes = true;
22849 if (!nodes.length && other_nodes.length) {
22850 nodes= other_nodes;
22852 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
22858 createRange: function(sel)
22860 // this has strange effects when using with
22861 // top toolbar - not sure if it's a great idea.
22862 //this.editor.contentWindow.focus();
22863 if (typeof sel != "undefined") {
22865 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
22867 return this.doc.createRange();
22870 return this.doc.createRange();
22873 getParentElement: function()
22876 this.assignDocWin();
22877 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
22879 var range = this.createRange(sel);
22882 var p = range.commonAncestorContainer;
22883 while (p.nodeType == 3) { // text node
22894 * Range intersection.. the hard stuff...
22898 * [ -- selected range --- ]
22902 * if end is before start or hits it. fail.
22903 * if start is after end or hits it fail.
22905 * if either hits (but other is outside. - then it's not
22911 // @see http://www.thismuchiknow.co.uk/?p=64.
22912 rangeIntersectsNode : function(range, node)
22914 var nodeRange = node.ownerDocument.createRange();
22916 nodeRange.selectNode(node);
22918 nodeRange.selectNodeContents(node);
22921 var rangeStartRange = range.cloneRange();
22922 rangeStartRange.collapse(true);
22924 var rangeEndRange = range.cloneRange();
22925 rangeEndRange.collapse(false);
22927 var nodeStartRange = nodeRange.cloneRange();
22928 nodeStartRange.collapse(true);
22930 var nodeEndRange = nodeRange.cloneRange();
22931 nodeEndRange.collapse(false);
22933 return rangeStartRange.compareBoundaryPoints(
22934 Range.START_TO_START, nodeEndRange) == -1 &&
22935 rangeEndRange.compareBoundaryPoints(
22936 Range.START_TO_START, nodeStartRange) == 1;
22940 rangeCompareNode : function(range, node)
22942 var nodeRange = node.ownerDocument.createRange();
22944 nodeRange.selectNode(node);
22946 nodeRange.selectNodeContents(node);
22950 range.collapse(true);
22952 nodeRange.collapse(true);
22954 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
22955 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
22957 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
22959 var nodeIsBefore = ss == 1;
22960 var nodeIsAfter = ee == -1;
22962 if (nodeIsBefore && nodeIsAfter) {
22965 if (!nodeIsBefore && nodeIsAfter) {
22966 return 1; //right trailed.
22969 if (nodeIsBefore && !nodeIsAfter) {
22970 return 2; // left trailed.
22976 // private? - in a new class?
22977 cleanUpPaste : function()
22979 // cleans up the whole document..
22980 Roo.log('cleanuppaste');
22982 this.cleanUpChildren(this.doc.body);
22983 var clean = this.cleanWordChars(this.doc.body.innerHTML);
22984 if (clean != this.doc.body.innerHTML) {
22985 this.doc.body.innerHTML = clean;
22990 cleanWordChars : function(input) {// change the chars to hex code
22991 var he = Roo.HtmlEditorCore;
22993 var output = input;
22994 Roo.each(he.swapCodes, function(sw) {
22995 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
22997 output = output.replace(swapper, sw[1]);
23004 cleanUpChildren : function (n)
23006 if (!n.childNodes.length) {
23009 for (var i = n.childNodes.length-1; i > -1 ; i--) {
23010 this.cleanUpChild(n.childNodes[i]);
23017 cleanUpChild : function (node)
23020 //console.log(node);
23021 if (node.nodeName == "#text") {
23022 // clean up silly Windows -- stuff?
23025 if (node.nodeName == "#comment") {
23026 node.parentNode.removeChild(node);
23027 // clean up silly Windows -- stuff?
23030 var lcname = node.tagName.toLowerCase();
23031 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
23032 // whitelist of tags..
23034 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
23036 node.parentNode.removeChild(node);
23041 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
23043 // remove <a name=....> as rendering on yahoo mailer is borked with this.
23044 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
23046 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
23047 // remove_keep_children = true;
23050 if (remove_keep_children) {
23051 this.cleanUpChildren(node);
23052 // inserts everything just before this node...
23053 while (node.childNodes.length) {
23054 var cn = node.childNodes[0];
23055 node.removeChild(cn);
23056 node.parentNode.insertBefore(cn, node);
23058 node.parentNode.removeChild(node);
23062 if (!node.attributes || !node.attributes.length) {
23063 this.cleanUpChildren(node);
23067 function cleanAttr(n,v)
23070 if (v.match(/^\./) || v.match(/^\//)) {
23073 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/) || v.match(/^ftp:/)) {
23076 if (v.match(/^#/)) {
23079 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
23080 node.removeAttribute(n);
23084 var cwhite = this.cwhite;
23085 var cblack = this.cblack;
23087 function cleanStyle(n,v)
23089 if (v.match(/expression/)) { //XSS?? should we even bother..
23090 node.removeAttribute(n);
23094 var parts = v.split(/;/);
23097 Roo.each(parts, function(p) {
23098 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
23102 var l = p.split(':').shift().replace(/\s+/g,'');
23103 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
23105 if ( cwhite.length && cblack.indexOf(l) > -1) {
23106 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
23107 //node.removeAttribute(n);
23111 // only allow 'c whitelisted system attributes'
23112 if ( cwhite.length && cwhite.indexOf(l) < 0) {
23113 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
23114 //node.removeAttribute(n);
23124 if (clean.length) {
23125 node.setAttribute(n, clean.join(';'));
23127 node.removeAttribute(n);
23133 for (var i = node.attributes.length-1; i > -1 ; i--) {
23134 var a = node.attributes[i];
23137 if (a.name.toLowerCase().substr(0,2)=='on') {
23138 node.removeAttribute(a.name);
23141 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
23142 node.removeAttribute(a.name);
23145 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
23146 cleanAttr(a.name,a.value); // fixme..
23149 if (a.name == 'style') {
23150 cleanStyle(a.name,a.value);
23153 /// clean up MS crap..
23154 // tecnically this should be a list of valid class'es..
23157 if (a.name == 'class') {
23158 if (a.value.match(/^Mso/)) {
23159 node.className = '';
23162 if (a.value.match(/^body$/)) {
23163 node.className = '';
23174 this.cleanUpChildren(node);
23180 * Clean up MS wordisms...
23182 cleanWord : function(node)
23187 this.cleanWord(this.doc.body);
23190 if (node.nodeName == "#text") {
23191 // clean up silly Windows -- stuff?
23194 if (node.nodeName == "#comment") {
23195 node.parentNode.removeChild(node);
23196 // clean up silly Windows -- stuff?
23200 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
23201 node.parentNode.removeChild(node);
23205 // remove - but keep children..
23206 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
23207 while (node.childNodes.length) {
23208 var cn = node.childNodes[0];
23209 node.removeChild(cn);
23210 node.parentNode.insertBefore(cn, node);
23212 node.parentNode.removeChild(node);
23213 this.iterateChildren(node, this.cleanWord);
23217 if (node.className.length) {
23219 var cn = node.className.split(/\W+/);
23221 Roo.each(cn, function(cls) {
23222 if (cls.match(/Mso[a-zA-Z]+/)) {
23227 node.className = cna.length ? cna.join(' ') : '';
23229 node.removeAttribute("class");
23233 if (node.hasAttribute("lang")) {
23234 node.removeAttribute("lang");
23237 if (node.hasAttribute("style")) {
23239 var styles = node.getAttribute("style").split(";");
23241 Roo.each(styles, function(s) {
23242 if (!s.match(/:/)) {
23245 var kv = s.split(":");
23246 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
23249 // what ever is left... we allow.
23252 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
23253 if (!nstyle.length) {
23254 node.removeAttribute('style');
23257 this.iterateChildren(node, this.cleanWord);
23263 * iterateChildren of a Node, calling fn each time, using this as the scole..
23264 * @param {DomNode} node node to iterate children of.
23265 * @param {Function} fn method of this class to call on each item.
23267 iterateChildren : function(node, fn)
23269 if (!node.childNodes.length) {
23272 for (var i = node.childNodes.length-1; i > -1 ; i--) {
23273 fn.call(this, node.childNodes[i])
23279 * cleanTableWidths.
23281 * Quite often pasting from word etc.. results in tables with column and widths.
23282 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
23285 cleanTableWidths : function(node)
23290 this.cleanTableWidths(this.doc.body);
23295 if (node.nodeName == "#text" || node.nodeName == "#comment") {
23298 Roo.log(node.tagName);
23299 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
23300 this.iterateChildren(node, this.cleanTableWidths);
23303 if (node.hasAttribute('width')) {
23304 node.removeAttribute('width');
23308 if (node.hasAttribute("style")) {
23311 var styles = node.getAttribute("style").split(";");
23313 Roo.each(styles, function(s) {
23314 if (!s.match(/:/)) {
23317 var kv = s.split(":");
23318 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
23321 // what ever is left... we allow.
23324 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
23325 if (!nstyle.length) {
23326 node.removeAttribute('style');
23330 this.iterateChildren(node, this.cleanTableWidths);
23338 domToHTML : function(currentElement, depth, nopadtext) {
23340 depth = depth || 0;
23341 nopadtext = nopadtext || false;
23343 if (!currentElement) {
23344 return this.domToHTML(this.doc.body);
23347 //Roo.log(currentElement);
23349 var allText = false;
23350 var nodeName = currentElement.nodeName;
23351 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
23353 if (nodeName == '#text') {
23355 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
23360 if (nodeName != 'BODY') {
23363 // Prints the node tagName, such as <A>, <IMG>, etc
23366 for(i = 0; i < currentElement.attributes.length;i++) {
23368 var aname = currentElement.attributes.item(i).name;
23369 if (!currentElement.attributes.item(i).value.length) {
23372 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
23375 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
23384 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
23387 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
23392 // Traverse the tree
23394 var currentElementChild = currentElement.childNodes.item(i);
23395 var allText = true;
23396 var innerHTML = '';
23398 while (currentElementChild) {
23399 // Formatting code (indent the tree so it looks nice on the screen)
23400 var nopad = nopadtext;
23401 if (lastnode == 'SPAN') {
23405 if (currentElementChild.nodeName == '#text') {
23406 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
23407 toadd = nopadtext ? toadd : toadd.trim();
23408 if (!nopad && toadd.length > 80) {
23409 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
23411 innerHTML += toadd;
23414 currentElementChild = currentElement.childNodes.item(i);
23420 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
23422 // Recursively traverse the tree structure of the child node
23423 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
23424 lastnode = currentElementChild.nodeName;
23426 currentElementChild=currentElement.childNodes.item(i);
23432 // The remaining code is mostly for formatting the tree
23433 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
23438 ret+= "</"+tagName+">";
23444 applyBlacklists : function()
23446 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
23447 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
23451 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
23452 if (b.indexOf(tag) > -1) {
23455 this.white.push(tag);
23459 Roo.each(w, function(tag) {
23460 if (b.indexOf(tag) > -1) {
23463 if (this.white.indexOf(tag) > -1) {
23466 this.white.push(tag);
23471 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
23472 if (w.indexOf(tag) > -1) {
23475 this.black.push(tag);
23479 Roo.each(b, function(tag) {
23480 if (w.indexOf(tag) > -1) {
23483 if (this.black.indexOf(tag) > -1) {
23486 this.black.push(tag);
23491 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
23492 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
23496 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
23497 if (b.indexOf(tag) > -1) {
23500 this.cwhite.push(tag);
23504 Roo.each(w, function(tag) {
23505 if (b.indexOf(tag) > -1) {
23508 if (this.cwhite.indexOf(tag) > -1) {
23511 this.cwhite.push(tag);
23516 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
23517 if (w.indexOf(tag) > -1) {
23520 this.cblack.push(tag);
23524 Roo.each(b, function(tag) {
23525 if (w.indexOf(tag) > -1) {
23528 if (this.cblack.indexOf(tag) > -1) {
23531 this.cblack.push(tag);
23536 setStylesheets : function(stylesheets)
23538 if(typeof(stylesheets) == 'string'){
23539 Roo.get(this.iframe.contentDocument.head).createChild({
23541 rel : 'stylesheet',
23550 Roo.each(stylesheets, function(s) {
23555 Roo.get(_this.iframe.contentDocument.head).createChild({
23557 rel : 'stylesheet',
23566 removeStylesheets : function()
23570 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
23575 setStyle : function(style)
23577 Roo.get(this.iframe.contentDocument.head).createChild({
23586 // hide stuff that is not compatible
23600 * @event specialkey
23604 * @cfg {String} fieldClass @hide
23607 * @cfg {String} focusClass @hide
23610 * @cfg {String} autoCreate @hide
23613 * @cfg {String} inputType @hide
23616 * @cfg {String} invalidClass @hide
23619 * @cfg {String} invalidText @hide
23622 * @cfg {String} msgFx @hide
23625 * @cfg {String} validateOnBlur @hide
23629 Roo.HtmlEditorCore.white = [
23630 'area', 'br', 'img', 'input', 'hr', 'wbr',
23632 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
23633 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
23634 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
23635 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
23636 'table', 'ul', 'xmp',
23638 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
23641 'dir', 'menu', 'ol', 'ul', 'dl',
23647 Roo.HtmlEditorCore.black = [
23648 // 'embed', 'object', // enable - backend responsiblity to clean thiese
23650 'base', 'basefont', 'bgsound', 'blink', 'body',
23651 'frame', 'frameset', 'head', 'html', 'ilayer',
23652 'iframe', 'layer', 'link', 'meta', 'object',
23653 'script', 'style' ,'title', 'xml' // clean later..
23655 Roo.HtmlEditorCore.clean = [
23656 'script', 'style', 'title', 'xml'
23658 Roo.HtmlEditorCore.remove = [
23663 Roo.HtmlEditorCore.ablack = [
23667 Roo.HtmlEditorCore.aclean = [
23668 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
23672 Roo.HtmlEditorCore.pwhite= [
23673 'http', 'https', 'mailto'
23676 // white listed style attributes.
23677 Roo.HtmlEditorCore.cwhite= [
23678 // 'text-align', /// default is to allow most things..
23684 // black listed style attributes.
23685 Roo.HtmlEditorCore.cblack= [
23686 // 'font-size' -- this can be set by the project
23690 Roo.HtmlEditorCore.swapCodes =[
23709 * @class Roo.bootstrap.HtmlEditor
23710 * @extends Roo.bootstrap.TextArea
23711 * Bootstrap HtmlEditor class
23714 * Create a new HtmlEditor
23715 * @param {Object} config The config object
23718 Roo.bootstrap.HtmlEditor = function(config){
23719 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
23720 if (!this.toolbars) {
23721 this.toolbars = [];
23724 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
23727 * @event initialize
23728 * Fires when the editor is fully initialized (including the iframe)
23729 * @param {HtmlEditor} this
23734 * Fires when the editor is first receives the focus. Any insertion must wait
23735 * until after this event.
23736 * @param {HtmlEditor} this
23740 * @event beforesync
23741 * Fires before the textarea is updated with content from the editor iframe. Return false
23742 * to cancel the sync.
23743 * @param {HtmlEditor} this
23744 * @param {String} html
23748 * @event beforepush
23749 * Fires before the iframe editor is updated with content from the textarea. Return false
23750 * to cancel the push.
23751 * @param {HtmlEditor} this
23752 * @param {String} html
23757 * Fires when the textarea is updated with content from the editor iframe.
23758 * @param {HtmlEditor} this
23759 * @param {String} html
23764 * Fires when the iframe editor is updated with content from the textarea.
23765 * @param {HtmlEditor} this
23766 * @param {String} html
23770 * @event editmodechange
23771 * Fires when the editor switches edit modes
23772 * @param {HtmlEditor} this
23773 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
23775 editmodechange: true,
23777 * @event editorevent
23778 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
23779 * @param {HtmlEditor} this
23783 * @event firstfocus
23784 * Fires when on first focus - needed by toolbars..
23785 * @param {HtmlEditor} this
23790 * Auto save the htmlEditor value as a file into Events
23791 * @param {HtmlEditor} this
23795 * @event savedpreview
23796 * preview the saved version of htmlEditor
23797 * @param {HtmlEditor} this
23804 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
23808 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
23813 * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
23818 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
23823 * @cfg {Number} height (in pixels)
23827 * @cfg {Number} width (in pixels)
23832 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
23835 stylesheets: false,
23840 // private properties
23841 validationEvent : false,
23843 initialized : false,
23846 onFocus : Roo.emptyFn,
23848 hideMode:'offsets',
23850 tbContainer : false,
23854 toolbarContainer :function() {
23855 return this.wrap.select('.x-html-editor-tb',true).first();
23859 * Protected method that will not generally be called directly. It
23860 * is called when the editor creates its toolbar. Override this method if you need to
23861 * add custom toolbar buttons.
23862 * @param {HtmlEditor} editor
23864 createToolbar : function(){
23865 Roo.log('renewing');
23866 Roo.log("create toolbars");
23868 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
23869 this.toolbars[0].render(this.toolbarContainer());
23873 // if (!editor.toolbars || !editor.toolbars.length) {
23874 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
23877 // for (var i =0 ; i < editor.toolbars.length;i++) {
23878 // editor.toolbars[i] = Roo.factory(
23879 // typeof(editor.toolbars[i]) == 'string' ?
23880 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
23881 // Roo.bootstrap.HtmlEditor);
23882 // editor.toolbars[i].init(editor);
23888 onRender : function(ct, position)
23890 // Roo.log("Call onRender: " + this.xtype);
23892 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
23894 this.wrap = this.inputEl().wrap({
23895 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
23898 this.editorcore.onRender(ct, position);
23900 if (this.resizable) {
23901 this.resizeEl = new Roo.Resizable(this.wrap, {
23905 minHeight : this.height,
23906 height: this.height,
23907 handles : this.resizable,
23910 resize : function(r, w, h) {
23911 _t.onResize(w,h); // -something
23917 this.createToolbar(this);
23920 if(!this.width && this.resizable){
23921 this.setSize(this.wrap.getSize());
23923 if (this.resizeEl) {
23924 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
23925 // should trigger onReize..
23931 onResize : function(w, h)
23933 Roo.log('resize: ' +w + ',' + h );
23934 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
23938 if(this.inputEl() ){
23939 if(typeof w == 'number'){
23940 var aw = w - this.wrap.getFrameWidth('lr');
23941 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
23944 if(typeof h == 'number'){
23945 var tbh = -11; // fixme it needs to tool bar size!
23946 for (var i =0; i < this.toolbars.length;i++) {
23947 // fixme - ask toolbars for heights?
23948 tbh += this.toolbars[i].el.getHeight();
23949 //if (this.toolbars[i].footer) {
23950 // tbh += this.toolbars[i].footer.el.getHeight();
23958 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
23959 ah -= 5; // knock a few pixes off for look..
23960 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
23964 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
23965 this.editorcore.onResize(ew,eh);
23970 * Toggles the editor between standard and source edit mode.
23971 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
23973 toggleSourceEdit : function(sourceEditMode)
23975 this.editorcore.toggleSourceEdit(sourceEditMode);
23977 if(this.editorcore.sourceEditMode){
23978 Roo.log('editor - showing textarea');
23981 // Roo.log(this.syncValue());
23983 this.inputEl().removeClass(['hide', 'x-hidden']);
23984 this.inputEl().dom.removeAttribute('tabIndex');
23985 this.inputEl().focus();
23987 Roo.log('editor - hiding textarea');
23989 // Roo.log(this.pushValue());
23992 this.inputEl().addClass(['hide', 'x-hidden']);
23993 this.inputEl().dom.setAttribute('tabIndex', -1);
23994 //this.deferFocus();
23997 if(this.resizable){
23998 this.setSize(this.wrap.getSize());
24001 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
24004 // private (for BoxComponent)
24005 adjustSize : Roo.BoxComponent.prototype.adjustSize,
24007 // private (for BoxComponent)
24008 getResizeEl : function(){
24012 // private (for BoxComponent)
24013 getPositionEl : function(){
24018 initEvents : function(){
24019 this.originalValue = this.getValue();
24023 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
24026 // markInvalid : Roo.emptyFn,
24028 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
24031 // clearInvalid : Roo.emptyFn,
24033 setValue : function(v){
24034 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
24035 this.editorcore.pushValue();
24040 deferFocus : function(){
24041 this.focus.defer(10, this);
24045 focus : function(){
24046 this.editorcore.focus();
24052 onDestroy : function(){
24058 for (var i =0; i < this.toolbars.length;i++) {
24059 // fixme - ask toolbars for heights?
24060 this.toolbars[i].onDestroy();
24063 this.wrap.dom.innerHTML = '';
24064 this.wrap.remove();
24069 onFirstFocus : function(){
24070 //Roo.log("onFirstFocus");
24071 this.editorcore.onFirstFocus();
24072 for (var i =0; i < this.toolbars.length;i++) {
24073 this.toolbars[i].onFirstFocus();
24079 syncValue : function()
24081 this.editorcore.syncValue();
24084 pushValue : function()
24086 this.editorcore.pushValue();
24090 // hide stuff that is not compatible
24104 * @event specialkey
24108 * @cfg {String} fieldClass @hide
24111 * @cfg {String} focusClass @hide
24114 * @cfg {String} autoCreate @hide
24117 * @cfg {String} inputType @hide
24121 * @cfg {String} invalidText @hide
24124 * @cfg {String} msgFx @hide
24127 * @cfg {String} validateOnBlur @hide
24136 Roo.namespace('Roo.bootstrap.htmleditor');
24138 * @class Roo.bootstrap.HtmlEditorToolbar1
24144 new Roo.bootstrap.HtmlEditor({
24147 new Roo.bootstrap.HtmlEditorToolbar1({
24148 disable : { fonts: 1 , format: 1, ..., ... , ...],
24154 * @cfg {Object} disable List of elements to disable..
24155 * @cfg {Array} btns List of additional buttons.
24159 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
24162 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
24165 Roo.apply(this, config);
24167 // default disabled, based on 'good practice'..
24168 this.disable = this.disable || {};
24169 Roo.applyIf(this.disable, {
24172 specialElements : true
24174 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
24176 this.editor = config.editor;
24177 this.editorcore = config.editor.editorcore;
24179 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
24181 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
24182 // dont call parent... till later.
24184 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
24189 editorcore : false,
24194 "h1","h2","h3","h4","h5","h6",
24196 "abbr", "acronym", "address", "cite", "samp", "var",
24200 onRender : function(ct, position)
24202 // Roo.log("Call onRender: " + this.xtype);
24204 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
24206 this.el.dom.style.marginBottom = '0';
24208 var editorcore = this.editorcore;
24209 var editor= this.editor;
24212 var btn = function(id,cmd , toggle, handler, html){
24214 var event = toggle ? 'toggle' : 'click';
24219 xns: Roo.bootstrap,
24223 enableToggle:toggle !== false,
24225 pressed : toggle ? false : null,
24228 a.listeners[toggle ? 'toggle' : 'click'] = function() {
24229 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
24235 // var cb_box = function...
24240 xns: Roo.bootstrap,
24245 xns: Roo.bootstrap,
24249 Roo.each(this.formats, function(f) {
24250 style.menu.items.push({
24252 xns: Roo.bootstrap,
24253 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
24258 editorcore.insertTag(this.tagname);
24265 children.push(style);
24267 btn('bold',false,true);
24268 btn('italic',false,true);
24269 btn('align-left', 'justifyleft',true);
24270 btn('align-center', 'justifycenter',true);
24271 btn('align-right' , 'justifyright',true);
24272 btn('link', false, false, function(btn) {
24273 //Roo.log("create link?");
24274 var url = prompt(this.createLinkText, this.defaultLinkValue);
24275 if(url && url != 'http:/'+'/'){
24276 this.editorcore.relayCmd('createlink', url);
24279 btn('list','insertunorderedlist',true);
24280 btn('pencil', false,true, function(btn){
24282 this.toggleSourceEdit(btn.pressed);
24285 if (this.editor.btns.length > 0) {
24286 for (var i = 0; i<this.editor.btns.length; i++) {
24287 children.push(this.editor.btns[i]);
24295 xns: Roo.bootstrap,
24300 xns: Roo.bootstrap,
24305 cog.menu.items.push({
24307 xns: Roo.bootstrap,
24308 html : Clean styles,
24313 editorcore.insertTag(this.tagname);
24322 this.xtype = 'NavSimplebar';
24324 for(var i=0;i< children.length;i++) {
24326 this.buttons.add(this.addxtypeChild(children[i]));
24330 editor.on('editorevent', this.updateToolbar, this);
24332 onBtnClick : function(id)
24334 this.editorcore.relayCmd(id);
24335 this.editorcore.focus();
24339 * Protected method that will not generally be called directly. It triggers
24340 * a toolbar update by reading the markup state of the current selection in the editor.
24342 updateToolbar: function(){
24344 if(!this.editorcore.activated){
24345 this.editor.onFirstFocus(); // is this neeed?
24349 var btns = this.buttons;
24350 var doc = this.editorcore.doc;
24351 btns.get('bold').setActive(doc.queryCommandState('bold'));
24352 btns.get('italic').setActive(doc.queryCommandState('italic'));
24353 //btns.get('underline').setActive(doc.queryCommandState('underline'));
24355 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
24356 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
24357 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
24359 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
24360 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
24363 var ans = this.editorcore.getAllAncestors();
24364 if (this.formatCombo) {
24367 var store = this.formatCombo.store;
24368 this.formatCombo.setValue("");
24369 for (var i =0; i < ans.length;i++) {
24370 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
24372 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
24380 // hides menus... - so this cant be on a menu...
24381 Roo.bootstrap.MenuMgr.hideAll();
24383 Roo.bootstrap.MenuMgr.hideAll();
24384 //this.editorsyncValue();
24386 onFirstFocus: function() {
24387 this.buttons.each(function(item){
24391 toggleSourceEdit : function(sourceEditMode){
24394 if(sourceEditMode){
24395 Roo.log("disabling buttons");
24396 this.buttons.each( function(item){
24397 if(item.cmd != 'pencil'){
24403 Roo.log("enabling buttons");
24404 if(this.editorcore.initialized){
24405 this.buttons.each( function(item){
24411 Roo.log("calling toggole on editor");
24412 // tell the editor that it's been pressed..
24413 this.editor.toggleSourceEdit(sourceEditMode);
24423 * @class Roo.bootstrap.Table.AbstractSelectionModel
24424 * @extends Roo.util.Observable
24425 * Abstract base class for grid SelectionModels. It provides the interface that should be
24426 * implemented by descendant classes. This class should not be directly instantiated.
24429 Roo.bootstrap.Table.AbstractSelectionModel = function(){
24430 this.locked = false;
24431 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
24435 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
24436 /** @ignore Called by the grid automatically. Do not call directly. */
24437 init : function(grid){
24443 * Locks the selections.
24446 this.locked = true;
24450 * Unlocks the selections.
24452 unlock : function(){
24453 this.locked = false;
24457 * Returns true if the selections are locked.
24458 * @return {Boolean}
24460 isLocked : function(){
24461 return this.locked;
24465 * @extends Roo.bootstrap.Table.AbstractSelectionModel
24466 * @class Roo.bootstrap.Table.RowSelectionModel
24467 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
24468 * It supports multiple selections and keyboard selection/navigation.
24470 * @param {Object} config
24473 Roo.bootstrap.Table.RowSelectionModel = function(config){
24474 Roo.apply(this, config);
24475 this.selections = new Roo.util.MixedCollection(false, function(o){
24480 this.lastActive = false;
24484 * @event selectionchange
24485 * Fires when the selection changes
24486 * @param {SelectionModel} this
24488 "selectionchange" : true,
24490 * @event afterselectionchange
24491 * Fires after the selection changes (eg. by key press or clicking)
24492 * @param {SelectionModel} this
24494 "afterselectionchange" : true,
24496 * @event beforerowselect
24497 * Fires when a row is selected being selected, return false to cancel.
24498 * @param {SelectionModel} this
24499 * @param {Number} rowIndex The selected index
24500 * @param {Boolean} keepExisting False if other selections will be cleared
24502 "beforerowselect" : true,
24505 * Fires when a row is selected.
24506 * @param {SelectionModel} this
24507 * @param {Number} rowIndex The selected index
24508 * @param {Roo.data.Record} r The record
24510 "rowselect" : true,
24512 * @event rowdeselect
24513 * Fires when a row is deselected.
24514 * @param {SelectionModel} this
24515 * @param {Number} rowIndex The selected index
24517 "rowdeselect" : true
24519 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
24520 this.locked = false;
24523 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
24525 * @cfg {Boolean} singleSelect
24526 * True to allow selection of only one row at a time (defaults to false)
24528 singleSelect : false,
24531 initEvents : function()
24534 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
24535 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
24536 //}else{ // allow click to work like normal
24537 // this.grid.on("rowclick", this.handleDragableRowClick, this);
24539 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
24540 this.grid.on("rowclick", this.handleMouseDown, this);
24542 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
24543 "up" : function(e){
24545 this.selectPrevious(e.shiftKey);
24546 }else if(this.last !== false && this.lastActive !== false){
24547 var last = this.last;
24548 this.selectRange(this.last, this.lastActive-1);
24549 this.grid.getView().focusRow(this.lastActive);
24550 if(last !== false){
24554 this.selectFirstRow();
24556 this.fireEvent("afterselectionchange", this);
24558 "down" : function(e){
24560 this.selectNext(e.shiftKey);
24561 }else if(this.last !== false && this.lastActive !== false){
24562 var last = this.last;
24563 this.selectRange(this.last, this.lastActive+1);
24564 this.grid.getView().focusRow(this.lastActive);
24565 if(last !== false){
24569 this.selectFirstRow();
24571 this.fireEvent("afterselectionchange", this);
24575 this.grid.store.on('load', function(){
24576 this.selections.clear();
24579 var view = this.grid.view;
24580 view.on("refresh", this.onRefresh, this);
24581 view.on("rowupdated", this.onRowUpdated, this);
24582 view.on("rowremoved", this.onRemove, this);
24587 onRefresh : function()
24589 var ds = this.grid.store, i, v = this.grid.view;
24590 var s = this.selections;
24591 s.each(function(r){
24592 if((i = ds.indexOfId(r.id)) != -1){
24601 onRemove : function(v, index, r){
24602 this.selections.remove(r);
24606 onRowUpdated : function(v, index, r){
24607 if(this.isSelected(r)){
24608 v.onRowSelect(index);
24614 * @param {Array} records The records to select
24615 * @param {Boolean} keepExisting (optional) True to keep existing selections
24617 selectRecords : function(records, keepExisting)
24620 this.clearSelections();
24622 var ds = this.grid.store;
24623 for(var i = 0, len = records.length; i < len; i++){
24624 this.selectRow(ds.indexOf(records[i]), true);
24629 * Gets the number of selected rows.
24632 getCount : function(){
24633 return this.selections.length;
24637 * Selects the first row in the grid.
24639 selectFirstRow : function(){
24644 * Select the last row.
24645 * @param {Boolean} keepExisting (optional) True to keep existing selections
24647 selectLastRow : function(keepExisting){
24648 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
24649 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
24653 * Selects the row immediately following the last selected row.
24654 * @param {Boolean} keepExisting (optional) True to keep existing selections
24656 selectNext : function(keepExisting)
24658 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
24659 this.selectRow(this.last+1, keepExisting);
24660 this.grid.getView().focusRow(this.last);
24665 * Selects the row that precedes the last selected row.
24666 * @param {Boolean} keepExisting (optional) True to keep existing selections
24668 selectPrevious : function(keepExisting){
24670 this.selectRow(this.last-1, keepExisting);
24671 this.grid.getView().focusRow(this.last);
24676 * Returns the selected records
24677 * @return {Array} Array of selected records
24679 getSelections : function(){
24680 return [].concat(this.selections.items);
24684 * Returns the first selected record.
24687 getSelected : function(){
24688 return this.selections.itemAt(0);
24693 * Clears all selections.
24695 clearSelections : function(fast)
24701 var ds = this.grid.store;
24702 var s = this.selections;
24703 s.each(function(r){
24704 this.deselectRow(ds.indexOfId(r.id));
24708 this.selections.clear();
24715 * Selects all rows.
24717 selectAll : function(){
24721 this.selections.clear();
24722 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
24723 this.selectRow(i, true);
24728 * Returns True if there is a selection.
24729 * @return {Boolean}
24731 hasSelection : function(){
24732 return this.selections.length > 0;
24736 * Returns True if the specified row is selected.
24737 * @param {Number/Record} record The record or index of the record to check
24738 * @return {Boolean}
24740 isSelected : function(index){
24741 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
24742 return (r && this.selections.key(r.id) ? true : false);
24746 * Returns True if the specified record id is selected.
24747 * @param {String} id The id of record to check
24748 * @return {Boolean}
24750 isIdSelected : function(id){
24751 return (this.selections.key(id) ? true : false);
24756 handleMouseDBClick : function(e, t){
24760 handleMouseDown : function(e, t)
24762 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
24763 if(this.isLocked() || rowIndex < 0 ){
24766 if(e.shiftKey && this.last !== false){
24767 var last = this.last;
24768 this.selectRange(last, rowIndex, e.ctrlKey);
24769 this.last = last; // reset the last
24773 var isSelected = this.isSelected(rowIndex);
24774 //Roo.log("select row:" + rowIndex);
24776 this.deselectRow(rowIndex);
24778 this.selectRow(rowIndex, true);
24782 if(e.button !== 0 && isSelected){
24783 alert('rowIndex 2: ' + rowIndex);
24784 view.focusRow(rowIndex);
24785 }else if(e.ctrlKey && isSelected){
24786 this.deselectRow(rowIndex);
24787 }else if(!isSelected){
24788 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
24789 view.focusRow(rowIndex);
24793 this.fireEvent("afterselectionchange", this);
24796 handleDragableRowClick : function(grid, rowIndex, e)
24798 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
24799 this.selectRow(rowIndex, false);
24800 grid.view.focusRow(rowIndex);
24801 this.fireEvent("afterselectionchange", this);
24806 * Selects multiple rows.
24807 * @param {Array} rows Array of the indexes of the row to select
24808 * @param {Boolean} keepExisting (optional) True to keep existing selections
24810 selectRows : function(rows, keepExisting){
24812 this.clearSelections();
24814 for(var i = 0, len = rows.length; i < len; i++){
24815 this.selectRow(rows[i], true);
24820 * Selects a range of rows. All rows in between startRow and endRow are also selected.
24821 * @param {Number} startRow The index of the first row in the range
24822 * @param {Number} endRow The index of the last row in the range
24823 * @param {Boolean} keepExisting (optional) True to retain existing selections
24825 selectRange : function(startRow, endRow, keepExisting){
24830 this.clearSelections();
24832 if(startRow <= endRow){
24833 for(var i = startRow; i <= endRow; i++){
24834 this.selectRow(i, true);
24837 for(var i = startRow; i >= endRow; i--){
24838 this.selectRow(i, true);
24844 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
24845 * @param {Number} startRow The index of the first row in the range
24846 * @param {Number} endRow The index of the last row in the range
24848 deselectRange : function(startRow, endRow, preventViewNotify){
24852 for(var i = startRow; i <= endRow; i++){
24853 this.deselectRow(i, preventViewNotify);
24859 * @param {Number} row The index of the row to select
24860 * @param {Boolean} keepExisting (optional) True to keep existing selections
24862 selectRow : function(index, keepExisting, preventViewNotify)
24864 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
24867 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
24868 if(!keepExisting || this.singleSelect){
24869 this.clearSelections();
24872 var r = this.grid.store.getAt(index);
24873 //console.log('selectRow - record id :' + r.id);
24875 this.selections.add(r);
24876 this.last = this.lastActive = index;
24877 if(!preventViewNotify){
24878 var proxy = new Roo.Element(
24879 this.grid.getRowDom(index)
24881 proxy.addClass('bg-info info');
24883 this.fireEvent("rowselect", this, index, r);
24884 this.fireEvent("selectionchange", this);
24890 * @param {Number} row The index of the row to deselect
24892 deselectRow : function(index, preventViewNotify)
24897 if(this.last == index){
24900 if(this.lastActive == index){
24901 this.lastActive = false;
24904 var r = this.grid.store.getAt(index);
24909 this.selections.remove(r);
24910 //.console.log('deselectRow - record id :' + r.id);
24911 if(!preventViewNotify){
24913 var proxy = new Roo.Element(
24914 this.grid.getRowDom(index)
24916 proxy.removeClass('bg-info info');
24918 this.fireEvent("rowdeselect", this, index);
24919 this.fireEvent("selectionchange", this);
24923 restoreLast : function(){
24925 this.last = this._last;
24930 acceptsNav : function(row, col, cm){
24931 return !cm.isHidden(col) && cm.isCellEditable(col, row);
24935 onEditorKey : function(field, e){
24936 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
24941 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
24943 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
24945 }else if(k == e.ENTER && !e.ctrlKey){
24949 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
24951 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
24953 }else if(k == e.ESC){
24957 g.startEditing(newCell[0], newCell[1]);
24963 * Ext JS Library 1.1.1
24964 * Copyright(c) 2006-2007, Ext JS, LLC.
24966 * Originally Released Under LGPL - original licence link has changed is not relivant.
24969 * <script type="text/javascript">
24973 * @class Roo.bootstrap.PagingToolbar
24974 * @extends Roo.bootstrap.NavSimplebar
24975 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
24977 * Create a new PagingToolbar
24978 * @param {Object} config The config object
24979 * @param {Roo.data.Store} store
24981 Roo.bootstrap.PagingToolbar = function(config)
24983 // old args format still supported... - xtype is prefered..
24984 // created from xtype...
24986 this.ds = config.dataSource;
24988 if (config.store && !this.ds) {
24989 this.store= Roo.factory(config.store, Roo.data);
24990 this.ds = this.store;
24991 this.ds.xmodule = this.xmodule || false;
24994 this.toolbarItems = [];
24995 if (config.items) {
24996 this.toolbarItems = config.items;
24999 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
25004 this.bind(this.ds);
25007 if (Roo.bootstrap.version == 4) {
25008 this.navgroup = new Roo.bootstrap.ButtonGroup({ cls: 'pagination' });
25010 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
25015 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
25017 * @cfg {Roo.data.Store} dataSource
25018 * The underlying data store providing the paged data
25021 * @cfg {String/HTMLElement/Element} container
25022 * container The id or element that will contain the toolbar
25025 * @cfg {Boolean} displayInfo
25026 * True to display the displayMsg (defaults to false)
25029 * @cfg {Number} pageSize
25030 * The number of records to display per page (defaults to 20)
25034 * @cfg {String} displayMsg
25035 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
25037 displayMsg : 'Displaying {0} - {1} of {2}',
25039 * @cfg {String} emptyMsg
25040 * The message to display when no records are found (defaults to "No data to display")
25042 emptyMsg : 'No data to display',
25044 * Customizable piece of the default paging text (defaults to "Page")
25047 beforePageText : "Page",
25049 * Customizable piece of the default paging text (defaults to "of %0")
25052 afterPageText : "of {0}",
25054 * Customizable piece of the default paging text (defaults to "First Page")
25057 firstText : "First Page",
25059 * Customizable piece of the default paging text (defaults to "Previous Page")
25062 prevText : "Previous Page",
25064 * Customizable piece of the default paging text (defaults to "Next Page")
25067 nextText : "Next Page",
25069 * Customizable piece of the default paging text (defaults to "Last Page")
25072 lastText : "Last Page",
25074 * Customizable piece of the default paging text (defaults to "Refresh")
25077 refreshText : "Refresh",
25081 onRender : function(ct, position)
25083 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
25084 this.navgroup.parentId = this.id;
25085 this.navgroup.onRender(this.el, null);
25086 // add the buttons to the navgroup
25088 if(this.displayInfo){
25089 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
25090 this.displayEl = this.el.select('.x-paging-info', true).first();
25091 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
25092 // this.displayEl = navel.el.select('span',true).first();
25098 Roo.each(_this.buttons, function(e){ // this might need to use render????
25099 Roo.factory(e).render(_this.el);
25103 Roo.each(_this.toolbarItems, function(e) {
25104 _this.navgroup.addItem(e);
25108 this.first = this.navgroup.addItem({
25109 tooltip: this.firstText,
25110 cls: "prev btn-outline-secondary",
25111 html : ' <i class="fa fa-step-backward"></i>',
25113 preventDefault: true,
25114 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
25117 this.prev = this.navgroup.addItem({
25118 tooltip: this.prevText,
25119 cls: "prev btn-outline-secondary",
25120 html : ' <i class="fa fa-backward"></i>',
25122 preventDefault: true,
25123 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
25125 //this.addSeparator();
25128 var field = this.navgroup.addItem( {
25130 cls : 'x-paging-position btn-outline-secondary',
25132 html : this.beforePageText +
25133 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
25134 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
25137 this.field = field.el.select('input', true).first();
25138 this.field.on("keydown", this.onPagingKeydown, this);
25139 this.field.on("focus", function(){this.dom.select();});
25142 this.afterTextEl = field.el.select('.x-paging-after',true).first();
25143 //this.field.setHeight(18);
25144 //this.addSeparator();
25145 this.next = this.navgroup.addItem({
25146 tooltip: this.nextText,
25147 cls: "next btn-outline-secondary",
25148 html : ' <i class="fa fa-forward"></i>',
25150 preventDefault: true,
25151 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
25153 this.last = this.navgroup.addItem({
25154 tooltip: this.lastText,
25155 html : ' <i class="fa fa-step-forward"></i>',
25156 cls: "next btn-outline-secondary",
25158 preventDefault: true,
25159 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
25161 //this.addSeparator();
25162 this.loading = this.navgroup.addItem({
25163 tooltip: this.refreshText,
25164 cls: "btn-outline-secondary",
25165 html : ' <i class="fa fa-refresh"></i>',
25166 preventDefault: true,
25167 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
25173 updateInfo : function(){
25174 if(this.displayEl){
25175 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
25176 var msg = count == 0 ?
25180 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
25182 this.displayEl.update(msg);
25187 onLoad : function(ds, r, o)
25189 this.cursor = o.params.start ? o.params.start : 0;
25191 var d = this.getPageData(),
25196 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
25197 this.field.dom.value = ap;
25198 this.first.setDisabled(ap == 1);
25199 this.prev.setDisabled(ap == 1);
25200 this.next.setDisabled(ap == ps);
25201 this.last.setDisabled(ap == ps);
25202 this.loading.enable();
25207 getPageData : function(){
25208 var total = this.ds.getTotalCount();
25211 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
25212 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
25217 onLoadError : function(){
25218 this.loading.enable();
25222 onPagingKeydown : function(e){
25223 var k = e.getKey();
25224 var d = this.getPageData();
25226 var v = this.field.dom.value, pageNum;
25227 if(!v || isNaN(pageNum = parseInt(v, 10))){
25228 this.field.dom.value = d.activePage;
25231 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
25232 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
25235 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))
25237 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
25238 this.field.dom.value = pageNum;
25239 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
25242 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
25244 var v = this.field.dom.value, pageNum;
25245 var increment = (e.shiftKey) ? 10 : 1;
25246 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
25249 if(!v || isNaN(pageNum = parseInt(v, 10))) {
25250 this.field.dom.value = d.activePage;
25253 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
25255 this.field.dom.value = parseInt(v, 10) + increment;
25256 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
25257 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
25264 beforeLoad : function(){
25266 this.loading.disable();
25271 onClick : function(which){
25280 ds.load({params:{start: 0, limit: this.pageSize}});
25283 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
25286 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
25289 var total = ds.getTotalCount();
25290 var extra = total % this.pageSize;
25291 var lastStart = extra ? (total - extra) : total-this.pageSize;
25292 ds.load({params:{start: lastStart, limit: this.pageSize}});
25295 ds.load({params:{start: this.cursor, limit: this.pageSize}});
25301 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
25302 * @param {Roo.data.Store} store The data store to unbind
25304 unbind : function(ds){
25305 ds.un("beforeload", this.beforeLoad, this);
25306 ds.un("load", this.onLoad, this);
25307 ds.un("loadexception", this.onLoadError, this);
25308 ds.un("remove", this.updateInfo, this);
25309 ds.un("add", this.updateInfo, this);
25310 this.ds = undefined;
25314 * Binds the paging toolbar to the specified {@link Roo.data.Store}
25315 * @param {Roo.data.Store} store The data store to bind
25317 bind : function(ds){
25318 ds.on("beforeload", this.beforeLoad, this);
25319 ds.on("load", this.onLoad, this);
25320 ds.on("loadexception", this.onLoadError, this);
25321 ds.on("remove", this.updateInfo, this);
25322 ds.on("add", this.updateInfo, this);
25333 * @class Roo.bootstrap.MessageBar
25334 * @extends Roo.bootstrap.Component
25335 * Bootstrap MessageBar class
25336 * @cfg {String} html contents of the MessageBar
25337 * @cfg {String} weight (info | success | warning | danger) default info
25338 * @cfg {String} beforeClass insert the bar before the given class
25339 * @cfg {Boolean} closable (true | false) default false
25340 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
25343 * Create a new Element
25344 * @param {Object} config The config object
25347 Roo.bootstrap.MessageBar = function(config){
25348 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
25351 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
25357 beforeClass: 'bootstrap-sticky-wrap',
25359 getAutoCreate : function(){
25363 cls: 'alert alert-dismissable alert-' + this.weight,
25368 html: this.html || ''
25374 cfg.cls += ' alert-messages-fixed';
25388 onRender : function(ct, position)
25390 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
25393 var cfg = Roo.apply({}, this.getAutoCreate());
25397 cfg.cls += ' ' + this.cls;
25400 cfg.style = this.style;
25402 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
25404 this.el.setVisibilityMode(Roo.Element.DISPLAY);
25407 this.el.select('>button.close').on('click', this.hide, this);
25413 if (!this.rendered) {
25419 this.fireEvent('show', this);
25425 if (!this.rendered) {
25431 this.fireEvent('hide', this);
25434 update : function()
25436 // var e = this.el.dom.firstChild;
25438 // if(this.closable){
25439 // e = e.nextSibling;
25442 // e.data = this.html || '';
25444 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
25460 * @class Roo.bootstrap.Graph
25461 * @extends Roo.bootstrap.Component
25462 * Bootstrap Graph class
25466 @cfg {String} graphtype bar | vbar | pie
25467 @cfg {number} g_x coodinator | centre x (pie)
25468 @cfg {number} g_y coodinator | centre y (pie)
25469 @cfg {number} g_r radius (pie)
25470 @cfg {number} g_height height of the chart (respected by all elements in the set)
25471 @cfg {number} g_width width of the chart (respected by all elements in the set)
25472 @cfg {Object} title The title of the chart
25475 -opts (object) options for the chart
25477 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
25478 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
25480 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.
25481 o stacked (boolean) whether or not to tread values as in a stacked bar chart
25483 o stretch (boolean)
25485 -opts (object) options for the pie
25488 o startAngle (number)
25489 o endAngle (number)
25493 * Create a new Input
25494 * @param {Object} config The config object
25497 Roo.bootstrap.Graph = function(config){
25498 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
25504 * The img click event for the img.
25505 * @param {Roo.EventObject} e
25511 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
25522 //g_colors: this.colors,
25529 getAutoCreate : function(){
25540 onRender : function(ct,position){
25543 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
25545 if (typeof(Raphael) == 'undefined') {
25546 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
25550 this.raphael = Raphael(this.el.dom);
25552 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25553 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25554 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25555 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
25557 r.text(160, 10, "Single Series Chart").attr(txtattr);
25558 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
25559 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
25560 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
25562 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
25563 r.barchart(330, 10, 300, 220, data1);
25564 r.barchart(10, 250, 300, 220, data2, {stacked: true});
25565 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
25568 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25569 // r.barchart(30, 30, 560, 250, xdata, {
25570 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
25571 // axis : "0 0 1 1",
25572 // axisxlabels : xdata
25573 // //yvalues : cols,
25576 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25578 // this.load(null,xdata,{
25579 // axis : "0 0 1 1",
25580 // axisxlabels : xdata
25585 load : function(graphtype,xdata,opts)
25587 this.raphael.clear();
25589 graphtype = this.graphtype;
25594 var r = this.raphael,
25595 fin = function () {
25596 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
25598 fout = function () {
25599 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
25601 pfin = function() {
25602 this.sector.stop();
25603 this.sector.scale(1.1, 1.1, this.cx, this.cy);
25606 this.label[0].stop();
25607 this.label[0].attr({ r: 7.5 });
25608 this.label[1].attr({ "font-weight": 800 });
25611 pfout = function() {
25612 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
25615 this.label[0].animate({ r: 5 }, 500, "bounce");
25616 this.label[1].attr({ "font-weight": 400 });
25622 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25625 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25628 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
25629 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
25631 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
25638 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
25643 setTitle: function(o)
25648 initEvents: function() {
25651 this.el.on('click', this.onClick, this);
25655 onClick : function(e)
25657 Roo.log('img onclick');
25658 this.fireEvent('click', this, e);
25670 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25673 * @class Roo.bootstrap.dash.NumberBox
25674 * @extends Roo.bootstrap.Component
25675 * Bootstrap NumberBox class
25676 * @cfg {String} headline Box headline
25677 * @cfg {String} content Box content
25678 * @cfg {String} icon Box icon
25679 * @cfg {String} footer Footer text
25680 * @cfg {String} fhref Footer href
25683 * Create a new NumberBox
25684 * @param {Object} config The config object
25688 Roo.bootstrap.dash.NumberBox = function(config){
25689 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
25693 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
25702 getAutoCreate : function(){
25706 cls : 'small-box ',
25714 cls : 'roo-headline',
25715 html : this.headline
25719 cls : 'roo-content',
25720 html : this.content
25734 cls : 'ion ' + this.icon
25743 cls : 'small-box-footer',
25744 href : this.fhref || '#',
25748 cfg.cn.push(footer);
25755 onRender : function(ct,position){
25756 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
25763 setHeadline: function (value)
25765 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
25768 setFooter: function (value, href)
25770 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
25773 this.el.select('a.small-box-footer',true).first().attr('href', href);
25778 setContent: function (value)
25780 this.el.select('.roo-content',true).first().dom.innerHTML = value;
25783 initEvents: function()
25797 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25800 * @class Roo.bootstrap.dash.TabBox
25801 * @extends Roo.bootstrap.Component
25802 * Bootstrap TabBox class
25803 * @cfg {String} title Title of the TabBox
25804 * @cfg {String} icon Icon of the TabBox
25805 * @cfg {Boolean} showtabs (true|false) show the tabs default true
25806 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
25809 * Create a new TabBox
25810 * @param {Object} config The config object
25814 Roo.bootstrap.dash.TabBox = function(config){
25815 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
25820 * When a pane is added
25821 * @param {Roo.bootstrap.dash.TabPane} pane
25825 * @event activatepane
25826 * When a pane is activated
25827 * @param {Roo.bootstrap.dash.TabPane} pane
25829 "activatepane" : true
25837 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
25842 tabScrollable : false,
25844 getChildContainer : function()
25846 return this.el.select('.tab-content', true).first();
25849 getAutoCreate : function(){
25853 cls: 'pull-left header',
25861 cls: 'fa ' + this.icon
25867 cls: 'nav nav-tabs pull-right',
25873 if(this.tabScrollable){
25880 cls: 'nav nav-tabs pull-right',
25891 cls: 'nav-tabs-custom',
25896 cls: 'tab-content no-padding',
25904 initEvents : function()
25906 //Roo.log('add add pane handler');
25907 this.on('addpane', this.onAddPane, this);
25910 * Updates the box title
25911 * @param {String} html to set the title to.
25913 setTitle : function(value)
25915 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
25917 onAddPane : function(pane)
25919 this.panes.push(pane);
25920 //Roo.log('addpane');
25922 // tabs are rendere left to right..
25923 if(!this.showtabs){
25927 var ctr = this.el.select('.nav-tabs', true).first();
25930 var existing = ctr.select('.nav-tab',true);
25931 var qty = existing.getCount();;
25934 var tab = ctr.createChild({
25936 cls : 'nav-tab' + (qty ? '' : ' active'),
25944 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
25947 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
25949 pane.el.addClass('active');
25954 onTabClick : function(ev,un,ob,pane)
25956 //Roo.log('tab - prev default');
25957 ev.preventDefault();
25960 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
25961 pane.tab.addClass('active');
25962 //Roo.log(pane.title);
25963 this.getChildContainer().select('.tab-pane',true).removeClass('active');
25964 // technically we should have a deactivate event.. but maybe add later.
25965 // and it should not de-activate the selected tab...
25966 this.fireEvent('activatepane', pane);
25967 pane.el.addClass('active');
25968 pane.fireEvent('activate');
25973 getActivePane : function()
25976 Roo.each(this.panes, function(p) {
25977 if(p.el.hasClass('active')){
25998 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
26000 * @class Roo.bootstrap.TabPane
26001 * @extends Roo.bootstrap.Component
26002 * Bootstrap TabPane class
26003 * @cfg {Boolean} active (false | true) Default false
26004 * @cfg {String} title title of panel
26008 * Create a new TabPane
26009 * @param {Object} config The config object
26012 Roo.bootstrap.dash.TabPane = function(config){
26013 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
26019 * When a pane is activated
26020 * @param {Roo.bootstrap.dash.TabPane} pane
26027 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
26032 // the tabBox that this is attached to.
26035 getAutoCreate : function()
26043 cfg.cls += ' active';
26048 initEvents : function()
26050 //Roo.log('trigger add pane handler');
26051 this.parent().fireEvent('addpane', this)
26055 * Updates the tab title
26056 * @param {String} html to set the title to.
26058 setTitle: function(str)
26064 this.tab.select('a', true).first().dom.innerHTML = str;
26081 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
26084 * @class Roo.bootstrap.menu.Menu
26085 * @extends Roo.bootstrap.Component
26086 * Bootstrap Menu class - container for Menu
26087 * @cfg {String} html Text of the menu
26088 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
26089 * @cfg {String} icon Font awesome icon
26090 * @cfg {String} pos Menu align to (top | bottom) default bottom
26094 * Create a new Menu
26095 * @param {Object} config The config object
26099 Roo.bootstrap.menu.Menu = function(config){
26100 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
26104 * @event beforeshow
26105 * Fires before this menu is displayed
26106 * @param {Roo.bootstrap.menu.Menu} this
26110 * @event beforehide
26111 * Fires before this menu is hidden
26112 * @param {Roo.bootstrap.menu.Menu} this
26117 * Fires after this menu is displayed
26118 * @param {Roo.bootstrap.menu.Menu} this
26123 * Fires after this menu is hidden
26124 * @param {Roo.bootstrap.menu.Menu} this
26129 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
26130 * @param {Roo.bootstrap.menu.Menu} this
26131 * @param {Roo.EventObject} e
26138 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
26142 weight : 'default',
26147 getChildContainer : function() {
26148 if(this.isSubMenu){
26152 return this.el.select('ul.dropdown-menu', true).first();
26155 getAutoCreate : function()
26160 cls : 'roo-menu-text',
26168 cls : 'fa ' + this.icon
26179 cls : 'dropdown-button btn btn-' + this.weight,
26184 cls : 'dropdown-toggle btn btn-' + this.weight,
26194 cls : 'dropdown-menu'
26200 if(this.pos == 'top'){
26201 cfg.cls += ' dropup';
26204 if(this.isSubMenu){
26207 cls : 'dropdown-menu'
26214 onRender : function(ct, position)
26216 this.isSubMenu = ct.hasClass('dropdown-submenu');
26218 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
26221 initEvents : function()
26223 if(this.isSubMenu){
26227 this.hidden = true;
26229 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
26230 this.triggerEl.on('click', this.onTriggerPress, this);
26232 this.buttonEl = this.el.select('button.dropdown-button', true).first();
26233 this.buttonEl.on('click', this.onClick, this);
26239 if(this.isSubMenu){
26243 return this.el.select('ul.dropdown-menu', true).first();
26246 onClick : function(e)
26248 this.fireEvent("click", this, e);
26251 onTriggerPress : function(e)
26253 if (this.isVisible()) {
26260 isVisible : function(){
26261 return !this.hidden;
26266 this.fireEvent("beforeshow", this);
26268 this.hidden = false;
26269 this.el.addClass('open');
26271 Roo.get(document).on("mouseup", this.onMouseUp, this);
26273 this.fireEvent("show", this);
26280 this.fireEvent("beforehide", this);
26282 this.hidden = true;
26283 this.el.removeClass('open');
26285 Roo.get(document).un("mouseup", this.onMouseUp);
26287 this.fireEvent("hide", this);
26290 onMouseUp : function()
26304 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
26307 * @class Roo.bootstrap.menu.Item
26308 * @extends Roo.bootstrap.Component
26309 * Bootstrap MenuItem class
26310 * @cfg {Boolean} submenu (true | false) default false
26311 * @cfg {String} html text of the item
26312 * @cfg {String} href the link
26313 * @cfg {Boolean} disable (true | false) default false
26314 * @cfg {Boolean} preventDefault (true | false) default true
26315 * @cfg {String} icon Font awesome icon
26316 * @cfg {String} pos Submenu align to (left | right) default right
26320 * Create a new Item
26321 * @param {Object} config The config object
26325 Roo.bootstrap.menu.Item = function(config){
26326 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
26330 * Fires when the mouse is hovering over this menu
26331 * @param {Roo.bootstrap.menu.Item} this
26332 * @param {Roo.EventObject} e
26337 * Fires when the mouse exits this menu
26338 * @param {Roo.bootstrap.menu.Item} this
26339 * @param {Roo.EventObject} e
26345 * The raw click event for the entire grid.
26346 * @param {Roo.EventObject} e
26352 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
26357 preventDefault: true,
26362 getAutoCreate : function()
26367 cls : 'roo-menu-item-text',
26375 cls : 'fa ' + this.icon
26384 href : this.href || '#',
26391 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
26395 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
26397 if(this.pos == 'left'){
26398 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
26405 initEvents : function()
26407 this.el.on('mouseover', this.onMouseOver, this);
26408 this.el.on('mouseout', this.onMouseOut, this);
26410 this.el.select('a', true).first().on('click', this.onClick, this);
26414 onClick : function(e)
26416 if(this.preventDefault){
26417 e.preventDefault();
26420 this.fireEvent("click", this, e);
26423 onMouseOver : function(e)
26425 if(this.submenu && this.pos == 'left'){
26426 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
26429 this.fireEvent("mouseover", this, e);
26432 onMouseOut : function(e)
26434 this.fireEvent("mouseout", this, e);
26446 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
26449 * @class Roo.bootstrap.menu.Separator
26450 * @extends Roo.bootstrap.Component
26451 * Bootstrap Separator class
26454 * Create a new Separator
26455 * @param {Object} config The config object
26459 Roo.bootstrap.menu.Separator = function(config){
26460 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
26463 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
26465 getAutoCreate : function(){
26486 * @class Roo.bootstrap.Tooltip
26487 * Bootstrap Tooltip class
26488 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
26489 * to determine which dom element triggers the tooltip.
26491 * It needs to add support for additional attributes like tooltip-position
26494 * Create a new Toolti
26495 * @param {Object} config The config object
26498 Roo.bootstrap.Tooltip = function(config){
26499 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
26501 this.alignment = Roo.bootstrap.Tooltip.alignment;
26503 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
26504 this.alignment = config.alignment;
26509 Roo.apply(Roo.bootstrap.Tooltip, {
26511 * @function init initialize tooltip monitoring.
26515 currentTip : false,
26516 currentRegion : false,
26522 Roo.get(document).on('mouseover', this.enter ,this);
26523 Roo.get(document).on('mouseout', this.leave, this);
26526 this.currentTip = new Roo.bootstrap.Tooltip();
26529 enter : function(ev)
26531 var dom = ev.getTarget();
26533 //Roo.log(['enter',dom]);
26534 var el = Roo.fly(dom);
26535 if (this.currentEl) {
26537 //Roo.log(this.currentEl);
26538 //Roo.log(this.currentEl.contains(dom));
26539 if (this.currentEl == el) {
26542 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
26548 if (this.currentTip.el) {
26549 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
26553 if(!el || el.dom == document){
26559 // you can not look for children, as if el is the body.. then everythign is the child..
26560 if (!el.attr('tooltip')) { //
26561 if (!el.select("[tooltip]").elements.length) {
26564 // is the mouse over this child...?
26565 bindEl = el.select("[tooltip]").first();
26566 var xy = ev.getXY();
26567 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
26568 //Roo.log("not in region.");
26571 //Roo.log("child element over..");
26574 this.currentEl = bindEl;
26575 this.currentTip.bind(bindEl);
26576 this.currentRegion = Roo.lib.Region.getRegion(dom);
26577 this.currentTip.enter();
26580 leave : function(ev)
26582 var dom = ev.getTarget();
26583 //Roo.log(['leave',dom]);
26584 if (!this.currentEl) {
26589 if (dom != this.currentEl.dom) {
26592 var xy = ev.getXY();
26593 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
26596 // only activate leave if mouse cursor is outside... bounding box..
26601 if (this.currentTip) {
26602 this.currentTip.leave();
26604 //Roo.log('clear currentEl');
26605 this.currentEl = false;
26610 'left' : ['r-l', [-2,0], 'right'],
26611 'right' : ['l-r', [2,0], 'left'],
26612 'bottom' : ['t-b', [0,2], 'top'],
26613 'top' : [ 'b-t', [0,-2], 'bottom']
26619 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
26624 delay : null, // can be { show : 300 , hide: 500}
26628 hoverState : null, //???
26630 placement : 'bottom',
26634 getAutoCreate : function(){
26641 cls : 'tooltip-arrow'
26644 cls : 'tooltip-inner'
26651 bind : function(el)
26657 enter : function () {
26659 if (this.timeout != null) {
26660 clearTimeout(this.timeout);
26663 this.hoverState = 'in';
26664 //Roo.log("enter - show");
26665 if (!this.delay || !this.delay.show) {
26670 this.timeout = setTimeout(function () {
26671 if (_t.hoverState == 'in') {
26674 }, this.delay.show);
26678 clearTimeout(this.timeout);
26680 this.hoverState = 'out';
26681 if (!this.delay || !this.delay.hide) {
26687 this.timeout = setTimeout(function () {
26688 //Roo.log("leave - timeout");
26690 if (_t.hoverState == 'out') {
26692 Roo.bootstrap.Tooltip.currentEl = false;
26697 show : function (msg)
26700 this.render(document.body);
26703 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
26705 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
26707 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
26709 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
26711 var placement = typeof this.placement == 'function' ?
26712 this.placement.call(this, this.el, on_el) :
26715 var autoToken = /\s?auto?\s?/i;
26716 var autoPlace = autoToken.test(placement);
26718 placement = placement.replace(autoToken, '') || 'top';
26722 //this.el.setXY([0,0]);
26724 //this.el.dom.style.display='block';
26726 //this.el.appendTo(on_el);
26728 var p = this.getPosition();
26729 var box = this.el.getBox();
26735 var align = this.alignment[placement];
26737 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
26739 if(placement == 'top' || placement == 'bottom'){
26741 placement = 'right';
26744 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
26745 placement = 'left';
26748 var scroll = Roo.select('body', true).first().getScroll();
26750 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
26754 align = this.alignment[placement];
26757 this.el.alignTo(this.bindEl, align[0],align[1]);
26758 //var arrow = this.el.select('.arrow',true).first();
26759 //arrow.set(align[2],
26761 this.el.addClass(placement);
26763 this.el.addClass('in fade');
26765 this.hoverState = null;
26767 if (this.el.hasClass('fade')) {
26778 //this.el.setXY([0,0]);
26779 this.el.removeClass('in');
26795 * @class Roo.bootstrap.LocationPicker
26796 * @extends Roo.bootstrap.Component
26797 * Bootstrap LocationPicker class
26798 * @cfg {Number} latitude Position when init default 0
26799 * @cfg {Number} longitude Position when init default 0
26800 * @cfg {Number} zoom default 15
26801 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
26802 * @cfg {Boolean} mapTypeControl default false
26803 * @cfg {Boolean} disableDoubleClickZoom default false
26804 * @cfg {Boolean} scrollwheel default true
26805 * @cfg {Boolean} streetViewControl default false
26806 * @cfg {Number} radius default 0
26807 * @cfg {String} locationName
26808 * @cfg {Boolean} draggable default true
26809 * @cfg {Boolean} enableAutocomplete default false
26810 * @cfg {Boolean} enableReverseGeocode default true
26811 * @cfg {String} markerTitle
26814 * Create a new LocationPicker
26815 * @param {Object} config The config object
26819 Roo.bootstrap.LocationPicker = function(config){
26821 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
26826 * Fires when the picker initialized.
26827 * @param {Roo.bootstrap.LocationPicker} this
26828 * @param {Google Location} location
26832 * @event positionchanged
26833 * Fires when the picker position changed.
26834 * @param {Roo.bootstrap.LocationPicker} this
26835 * @param {Google Location} location
26837 positionchanged : true,
26840 * Fires when the map resize.
26841 * @param {Roo.bootstrap.LocationPicker} this
26846 * Fires when the map show.
26847 * @param {Roo.bootstrap.LocationPicker} this
26852 * Fires when the map hide.
26853 * @param {Roo.bootstrap.LocationPicker} this
26858 * Fires when click the map.
26859 * @param {Roo.bootstrap.LocationPicker} this
26860 * @param {Map event} e
26864 * @event mapRightClick
26865 * Fires when right click the map.
26866 * @param {Roo.bootstrap.LocationPicker} this
26867 * @param {Map event} e
26869 mapRightClick : true,
26871 * @event markerClick
26872 * Fires when click the marker.
26873 * @param {Roo.bootstrap.LocationPicker} this
26874 * @param {Map event} e
26876 markerClick : true,
26878 * @event markerRightClick
26879 * Fires when right click the marker.
26880 * @param {Roo.bootstrap.LocationPicker} this
26881 * @param {Map event} e
26883 markerRightClick : true,
26885 * @event OverlayViewDraw
26886 * Fires when OverlayView Draw
26887 * @param {Roo.bootstrap.LocationPicker} this
26889 OverlayViewDraw : true,
26891 * @event OverlayViewOnAdd
26892 * Fires when OverlayView Draw
26893 * @param {Roo.bootstrap.LocationPicker} this
26895 OverlayViewOnAdd : true,
26897 * @event OverlayViewOnRemove
26898 * Fires when OverlayView Draw
26899 * @param {Roo.bootstrap.LocationPicker} this
26901 OverlayViewOnRemove : true,
26903 * @event OverlayViewShow
26904 * Fires when OverlayView Draw
26905 * @param {Roo.bootstrap.LocationPicker} this
26906 * @param {Pixel} cpx
26908 OverlayViewShow : true,
26910 * @event OverlayViewHide
26911 * Fires when OverlayView Draw
26912 * @param {Roo.bootstrap.LocationPicker} this
26914 OverlayViewHide : true,
26916 * @event loadexception
26917 * Fires when load google lib failed.
26918 * @param {Roo.bootstrap.LocationPicker} this
26920 loadexception : true
26925 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
26927 gMapContext: false,
26933 mapTypeControl: false,
26934 disableDoubleClickZoom: false,
26936 streetViewControl: false,
26940 enableAutocomplete: false,
26941 enableReverseGeocode: true,
26944 getAutoCreate: function()
26949 cls: 'roo-location-picker'
26955 initEvents: function(ct, position)
26957 if(!this.el.getWidth() || this.isApplied()){
26961 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26966 initial: function()
26968 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
26969 this.fireEvent('loadexception', this);
26973 if(!this.mapTypeId){
26974 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
26977 this.gMapContext = this.GMapContext();
26979 this.initOverlayView();
26981 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
26985 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
26986 _this.setPosition(_this.gMapContext.marker.position);
26989 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
26990 _this.fireEvent('mapClick', this, event);
26994 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
26995 _this.fireEvent('mapRightClick', this, event);
26999 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
27000 _this.fireEvent('markerClick', this, event);
27004 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
27005 _this.fireEvent('markerRightClick', this, event);
27009 this.setPosition(this.gMapContext.location);
27011 this.fireEvent('initial', this, this.gMapContext.location);
27014 initOverlayView: function()
27018 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
27022 _this.fireEvent('OverlayViewDraw', _this);
27027 _this.fireEvent('OverlayViewOnAdd', _this);
27030 onRemove: function()
27032 _this.fireEvent('OverlayViewOnRemove', _this);
27035 show: function(cpx)
27037 _this.fireEvent('OverlayViewShow', _this, cpx);
27042 _this.fireEvent('OverlayViewHide', _this);
27048 fromLatLngToContainerPixel: function(event)
27050 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
27053 isApplied: function()
27055 return this.getGmapContext() == false ? false : true;
27058 getGmapContext: function()
27060 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
27063 GMapContext: function()
27065 var position = new google.maps.LatLng(this.latitude, this.longitude);
27067 var _map = new google.maps.Map(this.el.dom, {
27070 mapTypeId: this.mapTypeId,
27071 mapTypeControl: this.mapTypeControl,
27072 disableDoubleClickZoom: this.disableDoubleClickZoom,
27073 scrollwheel: this.scrollwheel,
27074 streetViewControl: this.streetViewControl,
27075 locationName: this.locationName,
27076 draggable: this.draggable,
27077 enableAutocomplete: this.enableAutocomplete,
27078 enableReverseGeocode: this.enableReverseGeocode
27081 var _marker = new google.maps.Marker({
27082 position: position,
27084 title: this.markerTitle,
27085 draggable: this.draggable
27092 location: position,
27093 radius: this.radius,
27094 locationName: this.locationName,
27095 addressComponents: {
27096 formatted_address: null,
27097 addressLine1: null,
27098 addressLine2: null,
27100 streetNumber: null,
27104 stateOrProvince: null
27107 domContainer: this.el.dom,
27108 geodecoder: new google.maps.Geocoder()
27112 drawCircle: function(center, radius, options)
27114 if (this.gMapContext.circle != null) {
27115 this.gMapContext.circle.setMap(null);
27119 options = Roo.apply({}, options, {
27120 strokeColor: "#0000FF",
27121 strokeOpacity: .35,
27123 fillColor: "#0000FF",
27127 options.map = this.gMapContext.map;
27128 options.radius = radius;
27129 options.center = center;
27130 this.gMapContext.circle = new google.maps.Circle(options);
27131 return this.gMapContext.circle;
27137 setPosition: function(location)
27139 this.gMapContext.location = location;
27140 this.gMapContext.marker.setPosition(location);
27141 this.gMapContext.map.panTo(location);
27142 this.drawCircle(location, this.gMapContext.radius, {});
27146 if (this.gMapContext.settings.enableReverseGeocode) {
27147 this.gMapContext.geodecoder.geocode({
27148 latLng: this.gMapContext.location
27149 }, function(results, status) {
27151 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
27152 _this.gMapContext.locationName = results[0].formatted_address;
27153 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
27155 _this.fireEvent('positionchanged', this, location);
27162 this.fireEvent('positionchanged', this, location);
27167 google.maps.event.trigger(this.gMapContext.map, "resize");
27169 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
27171 this.fireEvent('resize', this);
27174 setPositionByLatLng: function(latitude, longitude)
27176 this.setPosition(new google.maps.LatLng(latitude, longitude));
27179 getCurrentPosition: function()
27182 latitude: this.gMapContext.location.lat(),
27183 longitude: this.gMapContext.location.lng()
27187 getAddressName: function()
27189 return this.gMapContext.locationName;
27192 getAddressComponents: function()
27194 return this.gMapContext.addressComponents;
27197 address_component_from_google_geocode: function(address_components)
27201 for (var i = 0; i < address_components.length; i++) {
27202 var component = address_components[i];
27203 if (component.types.indexOf("postal_code") >= 0) {
27204 result.postalCode = component.short_name;
27205 } else if (component.types.indexOf("street_number") >= 0) {
27206 result.streetNumber = component.short_name;
27207 } else if (component.types.indexOf("route") >= 0) {
27208 result.streetName = component.short_name;
27209 } else if (component.types.indexOf("neighborhood") >= 0) {
27210 result.city = component.short_name;
27211 } else if (component.types.indexOf("locality") >= 0) {
27212 result.city = component.short_name;
27213 } else if (component.types.indexOf("sublocality") >= 0) {
27214 result.district = component.short_name;
27215 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
27216 result.stateOrProvince = component.short_name;
27217 } else if (component.types.indexOf("country") >= 0) {
27218 result.country = component.short_name;
27222 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
27223 result.addressLine2 = "";
27227 setZoomLevel: function(zoom)
27229 this.gMapContext.map.setZoom(zoom);
27242 this.fireEvent('show', this);
27253 this.fireEvent('hide', this);
27258 Roo.apply(Roo.bootstrap.LocationPicker, {
27260 OverlayView : function(map, options)
27262 options = options || {};
27269 * @class Roo.bootstrap.Alert
27270 * @extends Roo.bootstrap.Component
27271 * Bootstrap Alert class - shows an alert area box
27273 * <div class="alert alert-danger" role="alert"><span class="fa fa-exclamation-triangle"></span><span class="sr-only">Error:</span>
27274 Enter a valid email address
27277 * @cfg {String} title The title of alert
27278 * @cfg {String} html The content of alert
27279 * @cfg {String} weight ( success | info | warning | danger )
27280 * @cfg {String} faicon font-awesomeicon
27283 * Create a new alert
27284 * @param {Object} config The config object
27288 Roo.bootstrap.Alert = function(config){
27289 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
27293 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
27300 getAutoCreate : function()
27309 cls : 'roo-alert-icon'
27314 cls : 'roo-alert-title',
27319 cls : 'roo-alert-text',
27326 cfg.cn[0].cls += ' fa ' + this.faicon;
27330 cfg.cls += ' alert-' + this.weight;
27336 initEvents: function()
27338 this.el.setVisibilityMode(Roo.Element.DISPLAY);
27341 setTitle : function(str)
27343 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
27346 setText : function(str)
27348 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
27351 setWeight : function(weight)
27354 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
27357 this.weight = weight;
27359 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
27362 setIcon : function(icon)
27365 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
27368 this.faicon = icon;
27370 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
27391 * @class Roo.bootstrap.UploadCropbox
27392 * @extends Roo.bootstrap.Component
27393 * Bootstrap UploadCropbox class
27394 * @cfg {String} emptyText show when image has been loaded
27395 * @cfg {String} rotateNotify show when image too small to rotate
27396 * @cfg {Number} errorTimeout default 3000
27397 * @cfg {Number} minWidth default 300
27398 * @cfg {Number} minHeight default 300
27399 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
27400 * @cfg {Boolean} isDocument (true|false) default false
27401 * @cfg {String} url action url
27402 * @cfg {String} paramName default 'imageUpload'
27403 * @cfg {String} method default POST
27404 * @cfg {Boolean} loadMask (true|false) default true
27405 * @cfg {Boolean} loadingText default 'Loading...'
27408 * Create a new UploadCropbox
27409 * @param {Object} config The config object
27412 Roo.bootstrap.UploadCropbox = function(config){
27413 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
27417 * @event beforeselectfile
27418 * Fire before select file
27419 * @param {Roo.bootstrap.UploadCropbox} this
27421 "beforeselectfile" : true,
27424 * Fire after initEvent
27425 * @param {Roo.bootstrap.UploadCropbox} this
27430 * Fire after initEvent
27431 * @param {Roo.bootstrap.UploadCropbox} this
27432 * @param {String} data
27437 * Fire when preparing the file data
27438 * @param {Roo.bootstrap.UploadCropbox} this
27439 * @param {Object} file
27444 * Fire when get exception
27445 * @param {Roo.bootstrap.UploadCropbox} this
27446 * @param {XMLHttpRequest} xhr
27448 "exception" : true,
27450 * @event beforeloadcanvas
27451 * Fire before load the canvas
27452 * @param {Roo.bootstrap.UploadCropbox} this
27453 * @param {String} src
27455 "beforeloadcanvas" : true,
27458 * Fire when trash image
27459 * @param {Roo.bootstrap.UploadCropbox} this
27464 * Fire when download the image
27465 * @param {Roo.bootstrap.UploadCropbox} this
27469 * @event footerbuttonclick
27470 * Fire when footerbuttonclick
27471 * @param {Roo.bootstrap.UploadCropbox} this
27472 * @param {String} type
27474 "footerbuttonclick" : true,
27478 * @param {Roo.bootstrap.UploadCropbox} this
27483 * Fire when rotate the image
27484 * @param {Roo.bootstrap.UploadCropbox} this
27485 * @param {String} pos
27490 * Fire when inspect the file
27491 * @param {Roo.bootstrap.UploadCropbox} this
27492 * @param {Object} file
27497 * Fire when xhr upload the file
27498 * @param {Roo.bootstrap.UploadCropbox} this
27499 * @param {Object} data
27504 * Fire when arrange the file data
27505 * @param {Roo.bootstrap.UploadCropbox} this
27506 * @param {Object} formData
27511 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
27514 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
27516 emptyText : 'Click to upload image',
27517 rotateNotify : 'Image is too small to rotate',
27518 errorTimeout : 3000,
27532 cropType : 'image/jpeg',
27534 canvasLoaded : false,
27535 isDocument : false,
27537 paramName : 'imageUpload',
27539 loadingText : 'Loading...',
27542 getAutoCreate : function()
27546 cls : 'roo-upload-cropbox',
27550 cls : 'roo-upload-cropbox-selector',
27555 cls : 'roo-upload-cropbox-body',
27556 style : 'cursor:pointer',
27560 cls : 'roo-upload-cropbox-preview'
27564 cls : 'roo-upload-cropbox-thumb'
27568 cls : 'roo-upload-cropbox-empty-notify',
27569 html : this.emptyText
27573 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
27574 html : this.rotateNotify
27580 cls : 'roo-upload-cropbox-footer',
27583 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
27593 onRender : function(ct, position)
27595 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
27597 if (this.buttons.length) {
27599 Roo.each(this.buttons, function(bb) {
27601 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
27603 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
27609 this.maskEl = this.el;
27613 initEvents : function()
27615 this.urlAPI = (window.createObjectURL && window) ||
27616 (window.URL && URL.revokeObjectURL && URL) ||
27617 (window.webkitURL && webkitURL);
27619 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
27620 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27622 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
27623 this.selectorEl.hide();
27625 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
27626 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27628 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
27629 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27630 this.thumbEl.hide();
27632 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
27633 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27635 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
27636 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27637 this.errorEl.hide();
27639 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
27640 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27641 this.footerEl.hide();
27643 this.setThumbBoxSize();
27649 this.fireEvent('initial', this);
27656 window.addEventListener("resize", function() { _this.resize(); } );
27658 this.bodyEl.on('click', this.beforeSelectFile, this);
27661 this.bodyEl.on('touchstart', this.onTouchStart, this);
27662 this.bodyEl.on('touchmove', this.onTouchMove, this);
27663 this.bodyEl.on('touchend', this.onTouchEnd, this);
27667 this.bodyEl.on('mousedown', this.onMouseDown, this);
27668 this.bodyEl.on('mousemove', this.onMouseMove, this);
27669 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
27670 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
27671 Roo.get(document).on('mouseup', this.onMouseUp, this);
27674 this.selectorEl.on('change', this.onFileSelected, this);
27680 this.baseScale = 1;
27682 this.baseRotate = 1;
27683 this.dragable = false;
27684 this.pinching = false;
27687 this.cropData = false;
27688 this.notifyEl.dom.innerHTML = this.emptyText;
27690 this.selectorEl.dom.value = '';
27694 resize : function()
27696 if(this.fireEvent('resize', this) != false){
27697 this.setThumbBoxPosition();
27698 this.setCanvasPosition();
27702 onFooterButtonClick : function(e, el, o, type)
27705 case 'rotate-left' :
27706 this.onRotateLeft(e);
27708 case 'rotate-right' :
27709 this.onRotateRight(e);
27712 this.beforeSelectFile(e);
27727 this.fireEvent('footerbuttonclick', this, type);
27730 beforeSelectFile : function(e)
27732 e.preventDefault();
27734 if(this.fireEvent('beforeselectfile', this) != false){
27735 this.selectorEl.dom.click();
27739 onFileSelected : function(e)
27741 e.preventDefault();
27743 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
27747 var file = this.selectorEl.dom.files[0];
27749 if(this.fireEvent('inspect', this, file) != false){
27750 this.prepare(file);
27755 trash : function(e)
27757 this.fireEvent('trash', this);
27760 download : function(e)
27762 this.fireEvent('download', this);
27765 loadCanvas : function(src)
27767 if(this.fireEvent('beforeloadcanvas', this, src) != false){
27771 this.imageEl = document.createElement('img');
27775 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
27777 this.imageEl.src = src;
27781 onLoadCanvas : function()
27783 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
27784 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
27786 this.bodyEl.un('click', this.beforeSelectFile, this);
27788 this.notifyEl.hide();
27789 this.thumbEl.show();
27790 this.footerEl.show();
27792 this.baseRotateLevel();
27794 if(this.isDocument){
27795 this.setThumbBoxSize();
27798 this.setThumbBoxPosition();
27800 this.baseScaleLevel();
27806 this.canvasLoaded = true;
27809 this.maskEl.unmask();
27814 setCanvasPosition : function()
27816 if(!this.canvasEl){
27820 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
27821 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
27823 this.previewEl.setLeft(pw);
27824 this.previewEl.setTop(ph);
27828 onMouseDown : function(e)
27832 this.dragable = true;
27833 this.pinching = false;
27835 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
27836 this.dragable = false;
27840 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27841 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27845 onMouseMove : function(e)
27849 if(!this.canvasLoaded){
27853 if (!this.dragable){
27857 var minX = Math.ceil(this.thumbEl.getLeft(true));
27858 var minY = Math.ceil(this.thumbEl.getTop(true));
27860 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
27861 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
27863 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27864 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27866 x = x - this.mouseX;
27867 y = y - this.mouseY;
27869 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
27870 var bgY = Math.ceil(y + this.previewEl.getTop(true));
27872 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
27873 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
27875 this.previewEl.setLeft(bgX);
27876 this.previewEl.setTop(bgY);
27878 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27879 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27882 onMouseUp : function(e)
27886 this.dragable = false;
27889 onMouseWheel : function(e)
27893 this.startScale = this.scale;
27895 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
27897 if(!this.zoomable()){
27898 this.scale = this.startScale;
27907 zoomable : function()
27909 var minScale = this.thumbEl.getWidth() / this.minWidth;
27911 if(this.minWidth < this.minHeight){
27912 minScale = this.thumbEl.getHeight() / this.minHeight;
27915 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
27916 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
27920 (this.rotate == 0 || this.rotate == 180) &&
27922 width > this.imageEl.OriginWidth ||
27923 height > this.imageEl.OriginHeight ||
27924 (width < this.minWidth && height < this.minHeight)
27932 (this.rotate == 90 || this.rotate == 270) &&
27934 width > this.imageEl.OriginWidth ||
27935 height > this.imageEl.OriginHeight ||
27936 (width < this.minHeight && height < this.minWidth)
27943 !this.isDocument &&
27944 (this.rotate == 0 || this.rotate == 180) &&
27946 width < this.minWidth ||
27947 width > this.imageEl.OriginWidth ||
27948 height < this.minHeight ||
27949 height > this.imageEl.OriginHeight
27956 !this.isDocument &&
27957 (this.rotate == 90 || this.rotate == 270) &&
27959 width < this.minHeight ||
27960 width > this.imageEl.OriginWidth ||
27961 height < this.minWidth ||
27962 height > this.imageEl.OriginHeight
27972 onRotateLeft : function(e)
27974 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27976 var minScale = this.thumbEl.getWidth() / this.minWidth;
27978 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27979 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27981 this.startScale = this.scale;
27983 while (this.getScaleLevel() < minScale){
27985 this.scale = this.scale + 1;
27987 if(!this.zoomable()){
27992 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27993 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27998 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
28005 this.scale = this.startScale;
28007 this.onRotateFail();
28012 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
28014 if(this.isDocument){
28015 this.setThumbBoxSize();
28016 this.setThumbBoxPosition();
28017 this.setCanvasPosition();
28022 this.fireEvent('rotate', this, 'left');
28026 onRotateRight : function(e)
28028 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
28030 var minScale = this.thumbEl.getWidth() / this.minWidth;
28032 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
28033 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
28035 this.startScale = this.scale;
28037 while (this.getScaleLevel() < minScale){
28039 this.scale = this.scale + 1;
28041 if(!this.zoomable()){
28046 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
28047 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
28052 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
28059 this.scale = this.startScale;
28061 this.onRotateFail();
28066 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
28068 if(this.isDocument){
28069 this.setThumbBoxSize();
28070 this.setThumbBoxPosition();
28071 this.setCanvasPosition();
28076 this.fireEvent('rotate', this, 'right');
28079 onRotateFail : function()
28081 this.errorEl.show(true);
28085 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
28090 this.previewEl.dom.innerHTML = '';
28092 var canvasEl = document.createElement("canvas");
28094 var contextEl = canvasEl.getContext("2d");
28096 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
28097 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
28098 var center = this.imageEl.OriginWidth / 2;
28100 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
28101 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
28102 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
28103 center = this.imageEl.OriginHeight / 2;
28106 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
28108 contextEl.translate(center, center);
28109 contextEl.rotate(this.rotate * Math.PI / 180);
28111 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
28113 this.canvasEl = document.createElement("canvas");
28115 this.contextEl = this.canvasEl.getContext("2d");
28117 switch (this.rotate) {
28120 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
28121 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
28123 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
28128 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
28129 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
28131 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28132 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);
28136 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
28141 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
28142 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
28144 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28145 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);
28149 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);
28154 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
28155 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
28157 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28158 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
28162 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);
28169 this.previewEl.appendChild(this.canvasEl);
28171 this.setCanvasPosition();
28176 if(!this.canvasLoaded){
28180 var imageCanvas = document.createElement("canvas");
28182 var imageContext = imageCanvas.getContext("2d");
28184 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
28185 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
28187 var center = imageCanvas.width / 2;
28189 imageContext.translate(center, center);
28191 imageContext.rotate(this.rotate * Math.PI / 180);
28193 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
28195 var canvas = document.createElement("canvas");
28197 var context = canvas.getContext("2d");
28199 canvas.width = this.minWidth;
28200 canvas.height = this.minHeight;
28202 switch (this.rotate) {
28205 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
28206 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
28208 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28209 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28211 var targetWidth = this.minWidth - 2 * x;
28212 var targetHeight = this.minHeight - 2 * y;
28216 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28217 scale = targetWidth / width;
28220 if(x > 0 && y == 0){
28221 scale = targetHeight / height;
28224 if(x > 0 && y > 0){
28225 scale = targetWidth / width;
28227 if(width < height){
28228 scale = targetHeight / height;
28232 context.scale(scale, scale);
28234 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28235 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28237 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28238 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28240 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28245 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
28246 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
28248 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28249 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28251 var targetWidth = this.minWidth - 2 * x;
28252 var targetHeight = this.minHeight - 2 * y;
28256 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28257 scale = targetWidth / width;
28260 if(x > 0 && y == 0){
28261 scale = targetHeight / height;
28264 if(x > 0 && y > 0){
28265 scale = targetWidth / width;
28267 if(width < height){
28268 scale = targetHeight / height;
28272 context.scale(scale, scale);
28274 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28275 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28277 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28278 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28280 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
28282 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28287 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
28288 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
28290 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28291 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28293 var targetWidth = this.minWidth - 2 * x;
28294 var targetHeight = this.minHeight - 2 * y;
28298 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28299 scale = targetWidth / width;
28302 if(x > 0 && y == 0){
28303 scale = targetHeight / height;
28306 if(x > 0 && y > 0){
28307 scale = targetWidth / width;
28309 if(width < height){
28310 scale = targetHeight / height;
28314 context.scale(scale, scale);
28316 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28317 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28319 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28320 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28322 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
28323 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
28325 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28330 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
28331 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
28333 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28334 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28336 var targetWidth = this.minWidth - 2 * x;
28337 var targetHeight = this.minHeight - 2 * y;
28341 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28342 scale = targetWidth / width;
28345 if(x > 0 && y == 0){
28346 scale = targetHeight / height;
28349 if(x > 0 && y > 0){
28350 scale = targetWidth / width;
28352 if(width < height){
28353 scale = targetHeight / height;
28357 context.scale(scale, scale);
28359 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28360 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28362 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28363 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28365 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
28367 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28374 this.cropData = canvas.toDataURL(this.cropType);
28376 if(this.fireEvent('crop', this, this.cropData) !== false){
28377 this.process(this.file, this.cropData);
28384 setThumbBoxSize : function()
28388 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
28389 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
28390 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
28392 this.minWidth = width;
28393 this.minHeight = height;
28395 if(this.rotate == 90 || this.rotate == 270){
28396 this.minWidth = height;
28397 this.minHeight = width;
28402 width = Math.ceil(this.minWidth * height / this.minHeight);
28404 if(this.minWidth > this.minHeight){
28406 height = Math.ceil(this.minHeight * width / this.minWidth);
28409 this.thumbEl.setStyle({
28410 width : width + 'px',
28411 height : height + 'px'
28418 setThumbBoxPosition : function()
28420 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
28421 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
28423 this.thumbEl.setLeft(x);
28424 this.thumbEl.setTop(y);
28428 baseRotateLevel : function()
28430 this.baseRotate = 1;
28433 typeof(this.exif) != 'undefined' &&
28434 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
28435 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
28437 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
28440 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
28444 baseScaleLevel : function()
28448 if(this.isDocument){
28450 if(this.baseRotate == 6 || this.baseRotate == 8){
28452 height = this.thumbEl.getHeight();
28453 this.baseScale = height / this.imageEl.OriginWidth;
28455 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
28456 width = this.thumbEl.getWidth();
28457 this.baseScale = width / this.imageEl.OriginHeight;
28463 height = this.thumbEl.getHeight();
28464 this.baseScale = height / this.imageEl.OriginHeight;
28466 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
28467 width = this.thumbEl.getWidth();
28468 this.baseScale = width / this.imageEl.OriginWidth;
28474 if(this.baseRotate == 6 || this.baseRotate == 8){
28476 width = this.thumbEl.getHeight();
28477 this.baseScale = width / this.imageEl.OriginHeight;
28479 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
28480 height = this.thumbEl.getWidth();
28481 this.baseScale = height / this.imageEl.OriginHeight;
28484 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28485 height = this.thumbEl.getWidth();
28486 this.baseScale = height / this.imageEl.OriginHeight;
28488 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
28489 width = this.thumbEl.getHeight();
28490 this.baseScale = width / this.imageEl.OriginWidth;
28497 width = this.thumbEl.getWidth();
28498 this.baseScale = width / this.imageEl.OriginWidth;
28500 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
28501 height = this.thumbEl.getHeight();
28502 this.baseScale = height / this.imageEl.OriginHeight;
28505 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28507 height = this.thumbEl.getHeight();
28508 this.baseScale = height / this.imageEl.OriginHeight;
28510 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
28511 width = this.thumbEl.getWidth();
28512 this.baseScale = width / this.imageEl.OriginWidth;
28520 getScaleLevel : function()
28522 return this.baseScale * Math.pow(1.1, this.scale);
28525 onTouchStart : function(e)
28527 if(!this.canvasLoaded){
28528 this.beforeSelectFile(e);
28532 var touches = e.browserEvent.touches;
28538 if(touches.length == 1){
28539 this.onMouseDown(e);
28543 if(touches.length != 2){
28549 for(var i = 0, finger; finger = touches[i]; i++){
28550 coords.push(finger.pageX, finger.pageY);
28553 var x = Math.pow(coords[0] - coords[2], 2);
28554 var y = Math.pow(coords[1] - coords[3], 2);
28556 this.startDistance = Math.sqrt(x + y);
28558 this.startScale = this.scale;
28560 this.pinching = true;
28561 this.dragable = false;
28565 onTouchMove : function(e)
28567 if(!this.pinching && !this.dragable){
28571 var touches = e.browserEvent.touches;
28578 this.onMouseMove(e);
28584 for(var i = 0, finger; finger = touches[i]; i++){
28585 coords.push(finger.pageX, finger.pageY);
28588 var x = Math.pow(coords[0] - coords[2], 2);
28589 var y = Math.pow(coords[1] - coords[3], 2);
28591 this.endDistance = Math.sqrt(x + y);
28593 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
28595 if(!this.zoomable()){
28596 this.scale = this.startScale;
28604 onTouchEnd : function(e)
28606 this.pinching = false;
28607 this.dragable = false;
28611 process : function(file, crop)
28614 this.maskEl.mask(this.loadingText);
28617 this.xhr = new XMLHttpRequest();
28619 file.xhr = this.xhr;
28621 this.xhr.open(this.method, this.url, true);
28624 "Accept": "application/json",
28625 "Cache-Control": "no-cache",
28626 "X-Requested-With": "XMLHttpRequest"
28629 for (var headerName in headers) {
28630 var headerValue = headers[headerName];
28632 this.xhr.setRequestHeader(headerName, headerValue);
28638 this.xhr.onload = function()
28640 _this.xhrOnLoad(_this.xhr);
28643 this.xhr.onerror = function()
28645 _this.xhrOnError(_this.xhr);
28648 var formData = new FormData();
28650 formData.append('returnHTML', 'NO');
28653 formData.append('crop', crop);
28656 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
28657 formData.append(this.paramName, file, file.name);
28660 if(typeof(file.filename) != 'undefined'){
28661 formData.append('filename', file.filename);
28664 if(typeof(file.mimetype) != 'undefined'){
28665 formData.append('mimetype', file.mimetype);
28668 if(this.fireEvent('arrange', this, formData) != false){
28669 this.xhr.send(formData);
28673 xhrOnLoad : function(xhr)
28676 this.maskEl.unmask();
28679 if (xhr.readyState !== 4) {
28680 this.fireEvent('exception', this, xhr);
28684 var response = Roo.decode(xhr.responseText);
28686 if(!response.success){
28687 this.fireEvent('exception', this, xhr);
28691 var response = Roo.decode(xhr.responseText);
28693 this.fireEvent('upload', this, response);
28697 xhrOnError : function()
28700 this.maskEl.unmask();
28703 Roo.log('xhr on error');
28705 var response = Roo.decode(xhr.responseText);
28711 prepare : function(file)
28714 this.maskEl.mask(this.loadingText);
28720 if(typeof(file) === 'string'){
28721 this.loadCanvas(file);
28725 if(!file || !this.urlAPI){
28730 this.cropType = file.type;
28734 if(this.fireEvent('prepare', this, this.file) != false){
28736 var reader = new FileReader();
28738 reader.onload = function (e) {
28739 if (e.target.error) {
28740 Roo.log(e.target.error);
28744 var buffer = e.target.result,
28745 dataView = new DataView(buffer),
28747 maxOffset = dataView.byteLength - 4,
28751 if (dataView.getUint16(0) === 0xffd8) {
28752 while (offset < maxOffset) {
28753 markerBytes = dataView.getUint16(offset);
28755 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
28756 markerLength = dataView.getUint16(offset + 2) + 2;
28757 if (offset + markerLength > dataView.byteLength) {
28758 Roo.log('Invalid meta data: Invalid segment size.');
28762 if(markerBytes == 0xffe1){
28763 _this.parseExifData(
28770 offset += markerLength;
28780 var url = _this.urlAPI.createObjectURL(_this.file);
28782 _this.loadCanvas(url);
28787 reader.readAsArrayBuffer(this.file);
28793 parseExifData : function(dataView, offset, length)
28795 var tiffOffset = offset + 10,
28799 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28800 // No Exif data, might be XMP data instead
28804 // Check for the ASCII code for "Exif" (0x45786966):
28805 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28806 // No Exif data, might be XMP data instead
28809 if (tiffOffset + 8 > dataView.byteLength) {
28810 Roo.log('Invalid Exif data: Invalid segment size.');
28813 // Check for the two null bytes:
28814 if (dataView.getUint16(offset + 8) !== 0x0000) {
28815 Roo.log('Invalid Exif data: Missing byte alignment offset.');
28818 // Check the byte alignment:
28819 switch (dataView.getUint16(tiffOffset)) {
28821 littleEndian = true;
28824 littleEndian = false;
28827 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
28830 // Check for the TIFF tag marker (0x002A):
28831 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
28832 Roo.log('Invalid Exif data: Missing TIFF marker.');
28835 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
28836 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
28838 this.parseExifTags(
28841 tiffOffset + dirOffset,
28846 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
28851 if (dirOffset + 6 > dataView.byteLength) {
28852 Roo.log('Invalid Exif data: Invalid directory offset.');
28855 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
28856 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
28857 if (dirEndOffset + 4 > dataView.byteLength) {
28858 Roo.log('Invalid Exif data: Invalid directory size.');
28861 for (i = 0; i < tagsNumber; i += 1) {
28865 dirOffset + 2 + 12 * i, // tag offset
28869 // Return the offset to the next directory:
28870 return dataView.getUint32(dirEndOffset, littleEndian);
28873 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
28875 var tag = dataView.getUint16(offset, littleEndian);
28877 this.exif[tag] = this.getExifValue(
28881 dataView.getUint16(offset + 2, littleEndian), // tag type
28882 dataView.getUint32(offset + 4, littleEndian), // tag length
28887 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
28889 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
28898 Roo.log('Invalid Exif data: Invalid tag type.');
28902 tagSize = tagType.size * length;
28903 // Determine if the value is contained in the dataOffset bytes,
28904 // or if the value at the dataOffset is a pointer to the actual data:
28905 dataOffset = tagSize > 4 ?
28906 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
28907 if (dataOffset + tagSize > dataView.byteLength) {
28908 Roo.log('Invalid Exif data: Invalid data offset.');
28911 if (length === 1) {
28912 return tagType.getValue(dataView, dataOffset, littleEndian);
28915 for (i = 0; i < length; i += 1) {
28916 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
28919 if (tagType.ascii) {
28921 // Concatenate the chars:
28922 for (i = 0; i < values.length; i += 1) {
28924 // Ignore the terminating NULL byte(s):
28925 if (c === '\u0000') {
28937 Roo.apply(Roo.bootstrap.UploadCropbox, {
28939 'Orientation': 0x0112
28943 1: 0, //'top-left',
28945 3: 180, //'bottom-right',
28946 // 4: 'bottom-left',
28948 6: 90, //'right-top',
28949 // 7: 'right-bottom',
28950 8: 270 //'left-bottom'
28954 // byte, 8-bit unsigned int:
28956 getValue: function (dataView, dataOffset) {
28957 return dataView.getUint8(dataOffset);
28961 // ascii, 8-bit byte:
28963 getValue: function (dataView, dataOffset) {
28964 return String.fromCharCode(dataView.getUint8(dataOffset));
28969 // short, 16 bit int:
28971 getValue: function (dataView, dataOffset, littleEndian) {
28972 return dataView.getUint16(dataOffset, littleEndian);
28976 // long, 32 bit int:
28978 getValue: function (dataView, dataOffset, littleEndian) {
28979 return dataView.getUint32(dataOffset, littleEndian);
28983 // rational = two long values, first is numerator, second is denominator:
28985 getValue: function (dataView, dataOffset, littleEndian) {
28986 return dataView.getUint32(dataOffset, littleEndian) /
28987 dataView.getUint32(dataOffset + 4, littleEndian);
28991 // slong, 32 bit signed int:
28993 getValue: function (dataView, dataOffset, littleEndian) {
28994 return dataView.getInt32(dataOffset, littleEndian);
28998 // srational, two slongs, first is numerator, second is denominator:
29000 getValue: function (dataView, dataOffset, littleEndian) {
29001 return dataView.getInt32(dataOffset, littleEndian) /
29002 dataView.getInt32(dataOffset + 4, littleEndian);
29012 cls : 'btn-group roo-upload-cropbox-rotate-left',
29013 action : 'rotate-left',
29017 cls : 'btn btn-default',
29018 html : '<i class="fa fa-undo"></i>'
29024 cls : 'btn-group roo-upload-cropbox-picture',
29025 action : 'picture',
29029 cls : 'btn btn-default',
29030 html : '<i class="fa fa-picture-o"></i>'
29036 cls : 'btn-group roo-upload-cropbox-rotate-right',
29037 action : 'rotate-right',
29041 cls : 'btn btn-default',
29042 html : '<i class="fa fa-repeat"></i>'
29050 cls : 'btn-group roo-upload-cropbox-rotate-left',
29051 action : 'rotate-left',
29055 cls : 'btn btn-default',
29056 html : '<i class="fa fa-undo"></i>'
29062 cls : 'btn-group roo-upload-cropbox-download',
29063 action : 'download',
29067 cls : 'btn btn-default',
29068 html : '<i class="fa fa-download"></i>'
29074 cls : 'btn-group roo-upload-cropbox-crop',
29079 cls : 'btn btn-default',
29080 html : '<i class="fa fa-crop"></i>'
29086 cls : 'btn-group roo-upload-cropbox-trash',
29091 cls : 'btn btn-default',
29092 html : '<i class="fa fa-trash"></i>'
29098 cls : 'btn-group roo-upload-cropbox-rotate-right',
29099 action : 'rotate-right',
29103 cls : 'btn btn-default',
29104 html : '<i class="fa fa-repeat"></i>'
29112 cls : 'btn-group roo-upload-cropbox-rotate-left',
29113 action : 'rotate-left',
29117 cls : 'btn btn-default',
29118 html : '<i class="fa fa-undo"></i>'
29124 cls : 'btn-group roo-upload-cropbox-rotate-right',
29125 action : 'rotate-right',
29129 cls : 'btn btn-default',
29130 html : '<i class="fa fa-repeat"></i>'
29143 * @class Roo.bootstrap.DocumentManager
29144 * @extends Roo.bootstrap.Component
29145 * Bootstrap DocumentManager class
29146 * @cfg {String} paramName default 'imageUpload'
29147 * @cfg {String} toolTipName default 'filename'
29148 * @cfg {String} method default POST
29149 * @cfg {String} url action url
29150 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
29151 * @cfg {Boolean} multiple multiple upload default true
29152 * @cfg {Number} thumbSize default 300
29153 * @cfg {String} fieldLabel
29154 * @cfg {Number} labelWidth default 4
29155 * @cfg {String} labelAlign (left|top) default left
29156 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
29157 * @cfg {Number} labellg set the width of label (1-12)
29158 * @cfg {Number} labelmd set the width of label (1-12)
29159 * @cfg {Number} labelsm set the width of label (1-12)
29160 * @cfg {Number} labelxs set the width of label (1-12)
29163 * Create a new DocumentManager
29164 * @param {Object} config The config object
29167 Roo.bootstrap.DocumentManager = function(config){
29168 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
29171 this.delegates = [];
29176 * Fire when initial the DocumentManager
29177 * @param {Roo.bootstrap.DocumentManager} this
29182 * inspect selected file
29183 * @param {Roo.bootstrap.DocumentManager} this
29184 * @param {File} file
29189 * Fire when xhr load exception
29190 * @param {Roo.bootstrap.DocumentManager} this
29191 * @param {XMLHttpRequest} xhr
29193 "exception" : true,
29195 * @event afterupload
29196 * Fire when xhr load exception
29197 * @param {Roo.bootstrap.DocumentManager} this
29198 * @param {XMLHttpRequest} xhr
29200 "afterupload" : true,
29203 * prepare the form data
29204 * @param {Roo.bootstrap.DocumentManager} this
29205 * @param {Object} formData
29210 * Fire when remove the file
29211 * @param {Roo.bootstrap.DocumentManager} this
29212 * @param {Object} file
29217 * Fire after refresh the file
29218 * @param {Roo.bootstrap.DocumentManager} this
29223 * Fire after click the image
29224 * @param {Roo.bootstrap.DocumentManager} this
29225 * @param {Object} file
29230 * Fire when upload a image and editable set to true
29231 * @param {Roo.bootstrap.DocumentManager} this
29232 * @param {Object} file
29236 * @event beforeselectfile
29237 * Fire before select file
29238 * @param {Roo.bootstrap.DocumentManager} this
29240 "beforeselectfile" : true,
29243 * Fire before process file
29244 * @param {Roo.bootstrap.DocumentManager} this
29245 * @param {Object} file
29249 * @event previewrendered
29250 * Fire when preview rendered
29251 * @param {Roo.bootstrap.DocumentManager} this
29252 * @param {Object} file
29254 "previewrendered" : true,
29257 "previewResize" : true
29262 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
29271 paramName : 'imageUpload',
29272 toolTipName : 'filename',
29275 labelAlign : 'left',
29285 getAutoCreate : function()
29287 var managerWidget = {
29289 cls : 'roo-document-manager',
29293 cls : 'roo-document-manager-selector',
29298 cls : 'roo-document-manager-uploader',
29302 cls : 'roo-document-manager-upload-btn',
29303 html : '<i class="fa fa-plus"></i>'
29314 cls : 'column col-md-12',
29319 if(this.fieldLabel.length){
29324 cls : 'column col-md-12',
29325 html : this.fieldLabel
29329 cls : 'column col-md-12',
29334 if(this.labelAlign == 'left'){
29339 html : this.fieldLabel
29348 if(this.labelWidth > 12){
29349 content[0].style = "width: " + this.labelWidth + 'px';
29352 if(this.labelWidth < 13 && this.labelmd == 0){
29353 this.labelmd = this.labelWidth;
29356 if(this.labellg > 0){
29357 content[0].cls += ' col-lg-' + this.labellg;
29358 content[1].cls += ' col-lg-' + (12 - this.labellg);
29361 if(this.labelmd > 0){
29362 content[0].cls += ' col-md-' + this.labelmd;
29363 content[1].cls += ' col-md-' + (12 - this.labelmd);
29366 if(this.labelsm > 0){
29367 content[0].cls += ' col-sm-' + this.labelsm;
29368 content[1].cls += ' col-sm-' + (12 - this.labelsm);
29371 if(this.labelxs > 0){
29372 content[0].cls += ' col-xs-' + this.labelxs;
29373 content[1].cls += ' col-xs-' + (12 - this.labelxs);
29381 cls : 'row clearfix',
29389 initEvents : function()
29391 this.managerEl = this.el.select('.roo-document-manager', true).first();
29392 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29394 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
29395 this.selectorEl.hide();
29398 this.selectorEl.attr('multiple', 'multiple');
29401 this.selectorEl.on('change', this.onFileSelected, this);
29403 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
29404 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29406 this.uploader.on('click', this.onUploaderClick, this);
29408 this.renderProgressDialog();
29412 window.addEventListener("resize", function() { _this.refresh(); } );
29414 this.fireEvent('initial', this);
29417 renderProgressDialog : function()
29421 this.progressDialog = new Roo.bootstrap.Modal({
29422 cls : 'roo-document-manager-progress-dialog',
29423 allow_close : false,
29434 btnclick : function() {
29435 _this.uploadCancel();
29441 this.progressDialog.render(Roo.get(document.body));
29443 this.progress = new Roo.bootstrap.Progress({
29444 cls : 'roo-document-manager-progress',
29449 this.progress.render(this.progressDialog.getChildContainer());
29451 this.progressBar = new Roo.bootstrap.ProgressBar({
29452 cls : 'roo-document-manager-progress-bar',
29455 aria_valuemax : 12,
29459 this.progressBar.render(this.progress.getChildContainer());
29462 onUploaderClick : function(e)
29464 e.preventDefault();
29466 if(this.fireEvent('beforeselectfile', this) != false){
29467 this.selectorEl.dom.click();
29472 onFileSelected : function(e)
29474 e.preventDefault();
29476 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
29480 Roo.each(this.selectorEl.dom.files, function(file){
29481 if(this.fireEvent('inspect', this, file) != false){
29482 this.files.push(file);
29492 this.selectorEl.dom.value = '';
29494 if(!this.files || !this.files.length){
29498 if(this.boxes > 0 && this.files.length > this.boxes){
29499 this.files = this.files.slice(0, this.boxes);
29502 this.uploader.show();
29504 if(this.boxes > 0 && this.files.length > this.boxes - 1){
29505 this.uploader.hide();
29514 Roo.each(this.files, function(file){
29516 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29517 var f = this.renderPreview(file);
29522 if(file.type.indexOf('image') != -1){
29523 this.delegates.push(
29525 _this.process(file);
29526 }).createDelegate(this)
29534 _this.process(file);
29535 }).createDelegate(this)
29540 this.files = files;
29542 this.delegates = this.delegates.concat(docs);
29544 if(!this.delegates.length){
29549 this.progressBar.aria_valuemax = this.delegates.length;
29556 arrange : function()
29558 if(!this.delegates.length){
29559 this.progressDialog.hide();
29564 var delegate = this.delegates.shift();
29566 this.progressDialog.show();
29568 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
29570 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
29575 refresh : function()
29577 this.uploader.show();
29579 if(this.boxes > 0 && this.files.length > this.boxes - 1){
29580 this.uploader.hide();
29583 Roo.isTouch ? this.closable(false) : this.closable(true);
29585 this.fireEvent('refresh', this);
29588 onRemove : function(e, el, o)
29590 e.preventDefault();
29592 this.fireEvent('remove', this, o);
29596 remove : function(o)
29600 Roo.each(this.files, function(file){
29601 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
29610 this.files = files;
29617 Roo.each(this.files, function(file){
29622 file.target.remove();
29631 onClick : function(e, el, o)
29633 e.preventDefault();
29635 this.fireEvent('click', this, o);
29639 closable : function(closable)
29641 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
29643 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29655 xhrOnLoad : function(xhr)
29657 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29661 if (xhr.readyState !== 4) {
29663 this.fireEvent('exception', this, xhr);
29667 var response = Roo.decode(xhr.responseText);
29669 if(!response.success){
29671 this.fireEvent('exception', this, xhr);
29675 var file = this.renderPreview(response.data);
29677 this.files.push(file);
29681 this.fireEvent('afterupload', this, xhr);
29685 xhrOnError : function(xhr)
29687 Roo.log('xhr on error');
29689 var response = Roo.decode(xhr.responseText);
29696 process : function(file)
29698 if(this.fireEvent('process', this, file) !== false){
29699 if(this.editable && file.type.indexOf('image') != -1){
29700 this.fireEvent('edit', this, file);
29704 this.uploadStart(file, false);
29711 uploadStart : function(file, crop)
29713 this.xhr = new XMLHttpRequest();
29715 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29720 file.xhr = this.xhr;
29722 this.managerEl.createChild({
29724 cls : 'roo-document-manager-loading',
29728 tooltip : file.name,
29729 cls : 'roo-document-manager-thumb',
29730 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29736 this.xhr.open(this.method, this.url, true);
29739 "Accept": "application/json",
29740 "Cache-Control": "no-cache",
29741 "X-Requested-With": "XMLHttpRequest"
29744 for (var headerName in headers) {
29745 var headerValue = headers[headerName];
29747 this.xhr.setRequestHeader(headerName, headerValue);
29753 this.xhr.onload = function()
29755 _this.xhrOnLoad(_this.xhr);
29758 this.xhr.onerror = function()
29760 _this.xhrOnError(_this.xhr);
29763 var formData = new FormData();
29765 formData.append('returnHTML', 'NO');
29768 formData.append('crop', crop);
29771 formData.append(this.paramName, file, file.name);
29778 if(this.fireEvent('prepare', this, formData, options) != false){
29780 if(options.manually){
29784 this.xhr.send(formData);
29788 this.uploadCancel();
29791 uploadCancel : function()
29797 this.delegates = [];
29799 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29806 renderPreview : function(file)
29808 if(typeof(file.target) != 'undefined' && file.target){
29812 var img_src = encodeURI(baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename);
29814 var previewEl = this.managerEl.createChild({
29816 cls : 'roo-document-manager-preview',
29820 tooltip : file[this.toolTipName],
29821 cls : 'roo-document-manager-thumb',
29822 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + img_src + '">'
29827 html : '<i class="fa fa-times-circle"></i>'
29832 var close = previewEl.select('button.close', true).first();
29834 close.on('click', this.onRemove, this, file);
29836 file.target = previewEl;
29838 var image = previewEl.select('img', true).first();
29842 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
29844 image.on('click', this.onClick, this, file);
29846 this.fireEvent('previewrendered', this, file);
29852 onPreviewLoad : function(file, image)
29854 if(typeof(file.target) == 'undefined' || !file.target){
29858 var width = image.dom.naturalWidth || image.dom.width;
29859 var height = image.dom.naturalHeight || image.dom.height;
29861 if(!this.previewResize) {
29865 if(width > height){
29866 file.target.addClass('wide');
29870 file.target.addClass('tall');
29875 uploadFromSource : function(file, crop)
29877 this.xhr = new XMLHttpRequest();
29879 this.managerEl.createChild({
29881 cls : 'roo-document-manager-loading',
29885 tooltip : file.name,
29886 cls : 'roo-document-manager-thumb',
29887 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29893 this.xhr.open(this.method, this.url, true);
29896 "Accept": "application/json",
29897 "Cache-Control": "no-cache",
29898 "X-Requested-With": "XMLHttpRequest"
29901 for (var headerName in headers) {
29902 var headerValue = headers[headerName];
29904 this.xhr.setRequestHeader(headerName, headerValue);
29910 this.xhr.onload = function()
29912 _this.xhrOnLoad(_this.xhr);
29915 this.xhr.onerror = function()
29917 _this.xhrOnError(_this.xhr);
29920 var formData = new FormData();
29922 formData.append('returnHTML', 'NO');
29924 formData.append('crop', crop);
29926 if(typeof(file.filename) != 'undefined'){
29927 formData.append('filename', file.filename);
29930 if(typeof(file.mimetype) != 'undefined'){
29931 formData.append('mimetype', file.mimetype);
29936 if(this.fireEvent('prepare', this, formData) != false){
29937 this.xhr.send(formData);
29947 * @class Roo.bootstrap.DocumentViewer
29948 * @extends Roo.bootstrap.Component
29949 * Bootstrap DocumentViewer class
29950 * @cfg {Boolean} showDownload (true|false) show download button (default true)
29951 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
29954 * Create a new DocumentViewer
29955 * @param {Object} config The config object
29958 Roo.bootstrap.DocumentViewer = function(config){
29959 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
29964 * Fire after initEvent
29965 * @param {Roo.bootstrap.DocumentViewer} this
29971 * @param {Roo.bootstrap.DocumentViewer} this
29976 * Fire after download button
29977 * @param {Roo.bootstrap.DocumentViewer} this
29982 * Fire after trash button
29983 * @param {Roo.bootstrap.DocumentViewer} this
29990 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
29992 showDownload : true,
29996 getAutoCreate : function()
30000 cls : 'roo-document-viewer',
30004 cls : 'roo-document-viewer-body',
30008 cls : 'roo-document-viewer-thumb',
30012 cls : 'roo-document-viewer-image'
30020 cls : 'roo-document-viewer-footer',
30023 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
30027 cls : 'btn-group roo-document-viewer-download',
30031 cls : 'btn btn-default',
30032 html : '<i class="fa fa-download"></i>'
30038 cls : 'btn-group roo-document-viewer-trash',
30042 cls : 'btn btn-default',
30043 html : '<i class="fa fa-trash"></i>'
30056 initEvents : function()
30058 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
30059 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
30061 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
30062 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
30064 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
30065 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
30067 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
30068 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
30070 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
30071 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
30073 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
30074 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
30076 this.bodyEl.on('click', this.onClick, this);
30077 this.downloadBtn.on('click', this.onDownload, this);
30078 this.trashBtn.on('click', this.onTrash, this);
30080 this.downloadBtn.hide();
30081 this.trashBtn.hide();
30083 if(this.showDownload){
30084 this.downloadBtn.show();
30087 if(this.showTrash){
30088 this.trashBtn.show();
30091 if(!this.showDownload && !this.showTrash) {
30092 this.footerEl.hide();
30097 initial : function()
30099 this.fireEvent('initial', this);
30103 onClick : function(e)
30105 e.preventDefault();
30107 this.fireEvent('click', this);
30110 onDownload : function(e)
30112 e.preventDefault();
30114 this.fireEvent('download', this);
30117 onTrash : function(e)
30119 e.preventDefault();
30121 this.fireEvent('trash', this);
30133 * @class Roo.bootstrap.NavProgressBar
30134 * @extends Roo.bootstrap.Component
30135 * Bootstrap NavProgressBar class
30138 * Create a new nav progress bar
30139 * @param {Object} config The config object
30142 Roo.bootstrap.NavProgressBar = function(config){
30143 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
30145 this.bullets = this.bullets || [];
30147 // Roo.bootstrap.NavProgressBar.register(this);
30151 * Fires when the active item changes
30152 * @param {Roo.bootstrap.NavProgressBar} this
30153 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
30154 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
30161 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
30166 getAutoCreate : function()
30168 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
30172 cls : 'roo-navigation-bar-group',
30176 cls : 'roo-navigation-top-bar'
30180 cls : 'roo-navigation-bullets-bar',
30184 cls : 'roo-navigation-bar'
30191 cls : 'roo-navigation-bottom-bar'
30201 initEvents: function()
30206 onRender : function(ct, position)
30208 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30210 if(this.bullets.length){
30211 Roo.each(this.bullets, function(b){
30220 addItem : function(cfg)
30222 var item = new Roo.bootstrap.NavProgressItem(cfg);
30224 item.parentId = this.id;
30225 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
30228 var top = new Roo.bootstrap.Element({
30230 cls : 'roo-navigation-bar-text'
30233 var bottom = new Roo.bootstrap.Element({
30235 cls : 'roo-navigation-bar-text'
30238 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
30239 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
30241 var topText = new Roo.bootstrap.Element({
30243 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
30246 var bottomText = new Roo.bootstrap.Element({
30248 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
30251 topText.onRender(top.el, null);
30252 bottomText.onRender(bottom.el, null);
30255 item.bottomEl = bottom;
30258 this.barItems.push(item);
30263 getActive : function()
30265 var active = false;
30267 Roo.each(this.barItems, function(v){
30269 if (!v.isActive()) {
30281 setActiveItem : function(item)
30285 Roo.each(this.barItems, function(v){
30286 if (v.rid == item.rid) {
30290 if (v.isActive()) {
30291 v.setActive(false);
30296 item.setActive(true);
30298 this.fireEvent('changed', this, item, prev);
30301 getBarItem: function(rid)
30305 Roo.each(this.barItems, function(e) {
30306 if (e.rid != rid) {
30317 indexOfItem : function(item)
30321 Roo.each(this.barItems, function(v, i){
30323 if (v.rid != item.rid) {
30334 setActiveNext : function()
30336 var i = this.indexOfItem(this.getActive());
30338 if (i > this.barItems.length) {
30342 this.setActiveItem(this.barItems[i+1]);
30345 setActivePrev : function()
30347 var i = this.indexOfItem(this.getActive());
30353 this.setActiveItem(this.barItems[i-1]);
30356 format : function()
30358 if(!this.barItems.length){
30362 var width = 100 / this.barItems.length;
30364 Roo.each(this.barItems, function(i){
30365 i.el.setStyle('width', width + '%');
30366 i.topEl.el.setStyle('width', width + '%');
30367 i.bottomEl.el.setStyle('width', width + '%');
30376 * Nav Progress Item
30381 * @class Roo.bootstrap.NavProgressItem
30382 * @extends Roo.bootstrap.Component
30383 * Bootstrap NavProgressItem class
30384 * @cfg {String} rid the reference id
30385 * @cfg {Boolean} active (true|false) Is item active default false
30386 * @cfg {Boolean} disabled (true|false) Is item active default false
30387 * @cfg {String} html
30388 * @cfg {String} position (top|bottom) text position default bottom
30389 * @cfg {String} icon show icon instead of number
30392 * Create a new NavProgressItem
30393 * @param {Object} config The config object
30395 Roo.bootstrap.NavProgressItem = function(config){
30396 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
30401 * The raw click event for the entire grid.
30402 * @param {Roo.bootstrap.NavProgressItem} this
30403 * @param {Roo.EventObject} e
30410 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
30416 position : 'bottom',
30419 getAutoCreate : function()
30421 var iconCls = 'roo-navigation-bar-item-icon';
30423 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
30427 cls: 'roo-navigation-bar-item',
30437 cfg.cls += ' active';
30440 cfg.cls += ' disabled';
30446 disable : function()
30448 this.setDisabled(true);
30451 enable : function()
30453 this.setDisabled(false);
30456 initEvents: function()
30458 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
30460 this.iconEl.on('click', this.onClick, this);
30463 onClick : function(e)
30465 e.preventDefault();
30471 if(this.fireEvent('click', this, e) === false){
30475 this.parent().setActiveItem(this);
30478 isActive: function ()
30480 return this.active;
30483 setActive : function(state)
30485 if(this.active == state){
30489 this.active = state;
30492 this.el.addClass('active');
30496 this.el.removeClass('active');
30501 setDisabled : function(state)
30503 if(this.disabled == state){
30507 this.disabled = state;
30510 this.el.addClass('disabled');
30514 this.el.removeClass('disabled');
30517 tooltipEl : function()
30519 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
30532 * @class Roo.bootstrap.FieldLabel
30533 * @extends Roo.bootstrap.Component
30534 * Bootstrap FieldLabel class
30535 * @cfg {String} html contents of the element
30536 * @cfg {String} tag tag of the element default label
30537 * @cfg {String} cls class of the element
30538 * @cfg {String} target label target
30539 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
30540 * @cfg {String} invalidClass DEPRICATED - BS4 uses is-invalid
30541 * @cfg {String} validClass DEPRICATED - BS4 uses is-valid
30542 * @cfg {String} iconTooltip default "This field is required"
30543 * @cfg {String} indicatorpos (left|right) default left
30546 * Create a new FieldLabel
30547 * @param {Object} config The config object
30550 Roo.bootstrap.FieldLabel = function(config){
30551 Roo.bootstrap.Element.superclass.constructor.call(this, config);
30556 * Fires after the field has been marked as invalid.
30557 * @param {Roo.form.FieldLabel} this
30558 * @param {String} msg The validation message
30563 * Fires after the field has been validated with no errors.
30564 * @param {Roo.form.FieldLabel} this
30570 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
30577 invalidClass : 'has-warning',
30578 validClass : 'has-success',
30579 iconTooltip : 'This field is required',
30580 indicatorpos : 'left',
30582 getAutoCreate : function(){
30585 if (!this.allowBlank) {
30591 cls : 'roo-bootstrap-field-label ' + this.cls,
30596 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star ' + cls,
30597 tooltip : this.iconTooltip
30606 if(this.indicatorpos == 'right'){
30609 cls : 'roo-bootstrap-field-label ' + this.cls,
30618 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star '+ cls,
30619 tooltip : this.iconTooltip
30628 initEvents: function()
30630 Roo.bootstrap.Element.superclass.initEvents.call(this);
30632 this.indicator = this.indicatorEl();
30634 if(this.indicator){
30635 this.indicator.removeClass('visible');
30636 this.indicator.addClass('invisible');
30639 Roo.bootstrap.FieldLabel.register(this);
30642 indicatorEl : function()
30644 var indicator = this.el.select('i.roo-required-indicator',true).first();
30655 * Mark this field as valid
30657 markValid : function()
30659 if(this.indicator){
30660 this.indicator.removeClass('visible');
30661 this.indicator.addClass('invisible');
30663 if (Roo.bootstrap.version == 3) {
30664 this.el.removeClass(this.invalidClass);
30665 this.el.addClass(this.validClass);
30667 this.el.removeClass('is-invalid');
30668 this.el.addClass('is-valid');
30672 this.fireEvent('valid', this);
30676 * Mark this field as invalid
30677 * @param {String} msg The validation message
30679 markInvalid : function(msg)
30681 if(this.indicator){
30682 this.indicator.removeClass('invisible');
30683 this.indicator.addClass('visible');
30685 if (Roo.bootstrap.version == 3) {
30686 this.el.removeClass(this.validClass);
30687 this.el.addClass(this.invalidClass);
30689 this.el.removeClass('is-valid');
30690 this.el.addClass('is-invalid');
30694 this.fireEvent('invalid', this, msg);
30700 Roo.apply(Roo.bootstrap.FieldLabel, {
30705 * register a FieldLabel Group
30706 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
30708 register : function(label)
30710 if(this.groups.hasOwnProperty(label.target)){
30714 this.groups[label.target] = label;
30718 * fetch a FieldLabel Group based on the target
30719 * @param {string} target
30720 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
30722 get: function(target) {
30723 if (typeof(this.groups[target]) == 'undefined') {
30727 return this.groups[target] ;
30736 * page DateSplitField.
30742 * @class Roo.bootstrap.DateSplitField
30743 * @extends Roo.bootstrap.Component
30744 * Bootstrap DateSplitField class
30745 * @cfg {string} fieldLabel - the label associated
30746 * @cfg {Number} labelWidth set the width of label (0-12)
30747 * @cfg {String} labelAlign (top|left)
30748 * @cfg {Boolean} dayAllowBlank (true|false) default false
30749 * @cfg {Boolean} monthAllowBlank (true|false) default false
30750 * @cfg {Boolean} yearAllowBlank (true|false) default false
30751 * @cfg {string} dayPlaceholder
30752 * @cfg {string} monthPlaceholder
30753 * @cfg {string} yearPlaceholder
30754 * @cfg {string} dayFormat default 'd'
30755 * @cfg {string} monthFormat default 'm'
30756 * @cfg {string} yearFormat default 'Y'
30757 * @cfg {Number} labellg set the width of label (1-12)
30758 * @cfg {Number} labelmd set the width of label (1-12)
30759 * @cfg {Number} labelsm set the width of label (1-12)
30760 * @cfg {Number} labelxs set the width of label (1-12)
30764 * Create a new DateSplitField
30765 * @param {Object} config The config object
30768 Roo.bootstrap.DateSplitField = function(config){
30769 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
30775 * getting the data of years
30776 * @param {Roo.bootstrap.DateSplitField} this
30777 * @param {Object} years
30782 * getting the data of days
30783 * @param {Roo.bootstrap.DateSplitField} this
30784 * @param {Object} days
30789 * Fires after the field has been marked as invalid.
30790 * @param {Roo.form.Field} this
30791 * @param {String} msg The validation message
30796 * Fires after the field has been validated with no errors.
30797 * @param {Roo.form.Field} this
30803 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
30806 labelAlign : 'top',
30808 dayAllowBlank : false,
30809 monthAllowBlank : false,
30810 yearAllowBlank : false,
30811 dayPlaceholder : '',
30812 monthPlaceholder : '',
30813 yearPlaceholder : '',
30817 isFormField : true,
30823 getAutoCreate : function()
30827 cls : 'row roo-date-split-field-group',
30832 cls : 'form-hidden-field roo-date-split-field-group-value',
30838 var labelCls = 'col-md-12';
30839 var contentCls = 'col-md-4';
30841 if(this.fieldLabel){
30845 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
30849 html : this.fieldLabel
30854 if(this.labelAlign == 'left'){
30856 if(this.labelWidth > 12){
30857 label.style = "width: " + this.labelWidth + 'px';
30860 if(this.labelWidth < 13 && this.labelmd == 0){
30861 this.labelmd = this.labelWidth;
30864 if(this.labellg > 0){
30865 labelCls = ' col-lg-' + this.labellg;
30866 contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
30869 if(this.labelmd > 0){
30870 labelCls = ' col-md-' + this.labelmd;
30871 contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
30874 if(this.labelsm > 0){
30875 labelCls = ' col-sm-' + this.labelsm;
30876 contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
30879 if(this.labelxs > 0){
30880 labelCls = ' col-xs-' + this.labelxs;
30881 contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
30885 label.cls += ' ' + labelCls;
30887 cfg.cn.push(label);
30890 Roo.each(['day', 'month', 'year'], function(t){
30893 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
30900 inputEl: function ()
30902 return this.el.select('.roo-date-split-field-group-value', true).first();
30905 onRender : function(ct, position)
30909 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30911 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
30913 this.dayField = new Roo.bootstrap.ComboBox({
30914 allowBlank : this.dayAllowBlank,
30915 alwaysQuery : true,
30916 displayField : 'value',
30919 forceSelection : true,
30921 placeholder : this.dayPlaceholder,
30922 selectOnFocus : true,
30923 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30924 triggerAction : 'all',
30926 valueField : 'value',
30927 store : new Roo.data.SimpleStore({
30928 data : (function() {
30930 _this.fireEvent('days', _this, days);
30933 fields : [ 'value' ]
30936 select : function (_self, record, index)
30938 _this.setValue(_this.getValue());
30943 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
30945 this.monthField = new Roo.bootstrap.MonthField({
30946 after : '<i class=\"fa fa-calendar\"></i>',
30947 allowBlank : this.monthAllowBlank,
30948 placeholder : this.monthPlaceholder,
30951 render : function (_self)
30953 this.el.select('span.input-group-addon', true).first().on('click', function(e){
30954 e.preventDefault();
30958 select : function (_self, oldvalue, newvalue)
30960 _this.setValue(_this.getValue());
30965 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
30967 this.yearField = new Roo.bootstrap.ComboBox({
30968 allowBlank : this.yearAllowBlank,
30969 alwaysQuery : true,
30970 displayField : 'value',
30973 forceSelection : true,
30975 placeholder : this.yearPlaceholder,
30976 selectOnFocus : true,
30977 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30978 triggerAction : 'all',
30980 valueField : 'value',
30981 store : new Roo.data.SimpleStore({
30982 data : (function() {
30984 _this.fireEvent('years', _this, years);
30987 fields : [ 'value' ]
30990 select : function (_self, record, index)
30992 _this.setValue(_this.getValue());
30997 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
31000 setValue : function(v, format)
31002 this.inputEl.dom.value = v;
31004 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
31006 var d = Date.parseDate(v, f);
31013 this.setDay(d.format(this.dayFormat));
31014 this.setMonth(d.format(this.monthFormat));
31015 this.setYear(d.format(this.yearFormat));
31022 setDay : function(v)
31024 this.dayField.setValue(v);
31025 this.inputEl.dom.value = this.getValue();
31030 setMonth : function(v)
31032 this.monthField.setValue(v, true);
31033 this.inputEl.dom.value = this.getValue();
31038 setYear : function(v)
31040 this.yearField.setValue(v);
31041 this.inputEl.dom.value = this.getValue();
31046 getDay : function()
31048 return this.dayField.getValue();
31051 getMonth : function()
31053 return this.monthField.getValue();
31056 getYear : function()
31058 return this.yearField.getValue();
31061 getValue : function()
31063 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
31065 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
31075 this.inputEl.dom.value = '';
31080 validate : function()
31082 var d = this.dayField.validate();
31083 var m = this.monthField.validate();
31084 var y = this.yearField.validate();
31089 (!this.dayAllowBlank && !d) ||
31090 (!this.monthAllowBlank && !m) ||
31091 (!this.yearAllowBlank && !y)
31096 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
31105 this.markInvalid();
31110 markValid : function()
31113 var label = this.el.select('label', true).first();
31114 var icon = this.el.select('i.fa-star', true).first();
31120 this.fireEvent('valid', this);
31124 * Mark this field as invalid
31125 * @param {String} msg The validation message
31127 markInvalid : function(msg)
31130 var label = this.el.select('label', true).first();
31131 var icon = this.el.select('i.fa-star', true).first();
31133 if(label && !icon){
31134 this.el.select('.roo-date-split-field-label', true).createChild({
31136 cls : 'text-danger fa fa-lg fa-star',
31137 tooltip : 'This field is required',
31138 style : 'margin-right:5px;'
31142 this.fireEvent('invalid', this, msg);
31145 clearInvalid : function()
31147 var label = this.el.select('label', true).first();
31148 var icon = this.el.select('i.fa-star', true).first();
31154 this.fireEvent('valid', this);
31157 getName: function()
31167 * http://masonry.desandro.com
31169 * The idea is to render all the bricks based on vertical width...
31171 * The original code extends 'outlayer' - we might need to use that....
31177 * @class Roo.bootstrap.LayoutMasonry
31178 * @extends Roo.bootstrap.Component
31179 * Bootstrap Layout Masonry class
31182 * Create a new Element
31183 * @param {Object} config The config object
31186 Roo.bootstrap.LayoutMasonry = function(config){
31188 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
31192 Roo.bootstrap.LayoutMasonry.register(this);
31198 * Fire after layout the items
31199 * @param {Roo.bootstrap.LayoutMasonry} this
31200 * @param {Roo.EventObject} e
31207 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
31210 * @cfg {Boolean} isLayoutInstant = no animation?
31212 isLayoutInstant : false, // needed?
31215 * @cfg {Number} boxWidth width of the columns
31220 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
31225 * @cfg {Number} padWidth padding below box..
31230 * @cfg {Number} gutter gutter width..
31235 * @cfg {Number} maxCols maximum number of columns
31241 * @cfg {Boolean} isAutoInitial defalut true
31243 isAutoInitial : true,
31248 * @cfg {Boolean} isHorizontal defalut false
31250 isHorizontal : false,
31252 currentSize : null,
31258 bricks: null, //CompositeElement
31262 _isLayoutInited : false,
31264 // isAlternative : false, // only use for vertical layout...
31267 * @cfg {Number} alternativePadWidth padding below box..
31269 alternativePadWidth : 50,
31271 selectedBrick : [],
31273 getAutoCreate : function(){
31275 var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
31279 cls: 'blog-masonary-wrapper ' + this.cls,
31281 cls : 'mas-boxes masonary'
31288 getChildContainer: function( )
31290 if (this.boxesEl) {
31291 return this.boxesEl;
31294 this.boxesEl = this.el.select('.mas-boxes').first();
31296 return this.boxesEl;
31300 initEvents : function()
31304 if(this.isAutoInitial){
31305 Roo.log('hook children rendered');
31306 this.on('childrenrendered', function() {
31307 Roo.log('children rendered');
31313 initial : function()
31315 this.selectedBrick = [];
31317 this.currentSize = this.el.getBox(true);
31319 Roo.EventManager.onWindowResize(this.resize, this);
31321 if(!this.isAutoInitial){
31329 //this.layout.defer(500,this);
31333 resize : function()
31335 var cs = this.el.getBox(true);
31338 this.currentSize.width == cs.width &&
31339 this.currentSize.x == cs.x &&
31340 this.currentSize.height == cs.height &&
31341 this.currentSize.y == cs.y
31343 Roo.log("no change in with or X or Y");
31347 this.currentSize = cs;
31353 layout : function()
31355 this._resetLayout();
31357 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
31359 this.layoutItems( isInstant );
31361 this._isLayoutInited = true;
31363 this.fireEvent('layout', this);
31367 _resetLayout : function()
31369 if(this.isHorizontal){
31370 this.horizontalMeasureColumns();
31374 this.verticalMeasureColumns();
31378 verticalMeasureColumns : function()
31380 this.getContainerWidth();
31382 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
31383 // this.colWidth = Math.floor(this.containerWidth * 0.8);
31387 var boxWidth = this.boxWidth + this.padWidth;
31389 if(this.containerWidth < this.boxWidth){
31390 boxWidth = this.containerWidth
31393 var containerWidth = this.containerWidth;
31395 var cols = Math.floor(containerWidth / boxWidth);
31397 this.cols = Math.max( cols, 1 );
31399 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
31401 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
31403 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
31405 this.colWidth = boxWidth + avail - this.padWidth;
31407 this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
31408 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
31411 horizontalMeasureColumns : function()
31413 this.getContainerWidth();
31415 var boxWidth = this.boxWidth;
31417 if(this.containerWidth < boxWidth){
31418 boxWidth = this.containerWidth;
31421 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
31423 this.el.setHeight(boxWidth);
31427 getContainerWidth : function()
31429 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
31432 layoutItems : function( isInstant )
31434 Roo.log(this.bricks);
31436 var items = Roo.apply([], this.bricks);
31438 if(this.isHorizontal){
31439 this._horizontalLayoutItems( items , isInstant );
31443 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
31444 // this._verticalAlternativeLayoutItems( items , isInstant );
31448 this._verticalLayoutItems( items , isInstant );
31452 _verticalLayoutItems : function ( items , isInstant)
31454 if ( !items || !items.length ) {
31459 ['xs', 'xs', 'xs', 'tall'],
31460 ['xs', 'xs', 'tall'],
31461 ['xs', 'xs', 'sm'],
31462 ['xs', 'xs', 'xs'],
31468 ['sm', 'xs', 'xs'],
31472 ['tall', 'xs', 'xs', 'xs'],
31473 ['tall', 'xs', 'xs'],
31485 Roo.each(items, function(item, k){
31487 switch (item.size) {
31488 // these layouts take up a full box,
31499 boxes.push([item]);
31522 var filterPattern = function(box, length)
31530 var pattern = box.slice(0, length);
31534 Roo.each(pattern, function(i){
31535 format.push(i.size);
31538 Roo.each(standard, function(s){
31540 if(String(s) != String(format)){
31549 if(!match && length == 1){
31554 filterPattern(box, length - 1);
31558 queue.push(pattern);
31560 box = box.slice(length, box.length);
31562 filterPattern(box, 4);
31568 Roo.each(boxes, function(box, k){
31574 if(box.length == 1){
31579 filterPattern(box, 4);
31583 this._processVerticalLayoutQueue( queue, isInstant );
31587 // _verticalAlternativeLayoutItems : function( items , isInstant )
31589 // if ( !items || !items.length ) {
31593 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
31597 _horizontalLayoutItems : function ( items , isInstant)
31599 if ( !items || !items.length || items.length < 3) {
31605 var eItems = items.slice(0, 3);
31607 items = items.slice(3, items.length);
31610 ['xs', 'xs', 'xs', 'wide'],
31611 ['xs', 'xs', 'wide'],
31612 ['xs', 'xs', 'sm'],
31613 ['xs', 'xs', 'xs'],
31619 ['sm', 'xs', 'xs'],
31623 ['wide', 'xs', 'xs', 'xs'],
31624 ['wide', 'xs', 'xs'],
31637 Roo.each(items, function(item, k){
31639 switch (item.size) {
31650 boxes.push([item]);
31674 var filterPattern = function(box, length)
31682 var pattern = box.slice(0, length);
31686 Roo.each(pattern, function(i){
31687 format.push(i.size);
31690 Roo.each(standard, function(s){
31692 if(String(s) != String(format)){
31701 if(!match && length == 1){
31706 filterPattern(box, length - 1);
31710 queue.push(pattern);
31712 box = box.slice(length, box.length);
31714 filterPattern(box, 4);
31720 Roo.each(boxes, function(box, k){
31726 if(box.length == 1){
31731 filterPattern(box, 4);
31738 var pos = this.el.getBox(true);
31742 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31744 var hit_end = false;
31746 Roo.each(queue, function(box){
31750 Roo.each(box, function(b){
31752 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31762 Roo.each(box, function(b){
31764 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31767 mx = Math.max(mx, b.x);
31771 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
31775 Roo.each(box, function(b){
31777 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31791 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
31794 /** Sets position of item in DOM
31795 * @param {Element} item
31796 * @param {Number} x - horizontal position
31797 * @param {Number} y - vertical position
31798 * @param {Boolean} isInstant - disables transitions
31800 _processVerticalLayoutQueue : function( queue, isInstant )
31802 var pos = this.el.getBox(true);
31807 for (var i = 0; i < this.cols; i++){
31811 Roo.each(queue, function(box, k){
31813 var col = k % this.cols;
31815 Roo.each(box, function(b,kk){
31817 b.el.position('absolute');
31819 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31820 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31822 if(b.size == 'md-left' || b.size == 'md-right'){
31823 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31824 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31827 b.el.setWidth(width);
31828 b.el.setHeight(height);
31830 b.el.select('iframe',true).setSize(width,height);
31834 for (var i = 0; i < this.cols; i++){
31836 if(maxY[i] < maxY[col]){
31841 col = Math.min(col, i);
31845 x = pos.x + col * (this.colWidth + this.padWidth);
31849 var positions = [];
31851 switch (box.length){
31853 positions = this.getVerticalOneBoxColPositions(x, y, box);
31856 positions = this.getVerticalTwoBoxColPositions(x, y, box);
31859 positions = this.getVerticalThreeBoxColPositions(x, y, box);
31862 positions = this.getVerticalFourBoxColPositions(x, y, box);
31868 Roo.each(box, function(b,kk){
31870 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31872 var sz = b.el.getSize();
31874 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
31882 for (var i = 0; i < this.cols; i++){
31883 mY = Math.max(mY, maxY[i]);
31886 this.el.setHeight(mY - pos.y);
31890 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
31892 // var pos = this.el.getBox(true);
31895 // var maxX = pos.right;
31897 // var maxHeight = 0;
31899 // Roo.each(items, function(item, k){
31903 // item.el.position('absolute');
31905 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
31907 // item.el.setWidth(width);
31909 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
31911 // item.el.setHeight(height);
31914 // item.el.setXY([x, y], isInstant ? false : true);
31916 // item.el.setXY([maxX - width, y], isInstant ? false : true);
31919 // y = y + height + this.alternativePadWidth;
31921 // maxHeight = maxHeight + height + this.alternativePadWidth;
31925 // this.el.setHeight(maxHeight);
31929 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
31931 var pos = this.el.getBox(true);
31936 var maxX = pos.right;
31938 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
31940 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31942 Roo.each(queue, function(box, k){
31944 Roo.each(box, function(b, kk){
31946 b.el.position('absolute');
31948 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31949 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31951 if(b.size == 'md-left' || b.size == 'md-right'){
31952 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31953 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31956 b.el.setWidth(width);
31957 b.el.setHeight(height);
31965 var positions = [];
31967 switch (box.length){
31969 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
31972 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
31975 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
31978 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
31984 Roo.each(box, function(b,kk){
31986 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31988 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
31996 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
31998 Roo.each(eItems, function(b,k){
32000 b.size = (k == 0) ? 'sm' : 'xs';
32001 b.x = (k == 0) ? 2 : 1;
32002 b.y = (k == 0) ? 2 : 1;
32004 b.el.position('absolute');
32006 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
32008 b.el.setWidth(width);
32010 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
32012 b.el.setHeight(height);
32016 var positions = [];
32019 x : maxX - this.unitWidth * 2 - this.gutter,
32024 x : maxX - this.unitWidth,
32025 y : minY + (this.unitWidth + this.gutter) * 2
32029 x : maxX - this.unitWidth * 3 - this.gutter * 2,
32033 Roo.each(eItems, function(b,k){
32035 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
32041 getVerticalOneBoxColPositions : function(x, y, box)
32045 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
32047 if(box[0].size == 'md-left'){
32051 if(box[0].size == 'md-right'){
32056 x : x + (this.unitWidth + this.gutter) * rand,
32063 getVerticalTwoBoxColPositions : function(x, y, box)
32067 if(box[0].size == 'xs'){
32071 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
32075 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
32089 x : x + (this.unitWidth + this.gutter) * 2,
32090 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
32097 getVerticalThreeBoxColPositions : function(x, y, box)
32101 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
32109 x : x + (this.unitWidth + this.gutter) * 1,
32114 x : x + (this.unitWidth + this.gutter) * 2,
32122 if(box[0].size == 'xs' && box[1].size == 'xs'){
32131 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
32135 x : x + (this.unitWidth + this.gutter) * 1,
32149 x : x + (this.unitWidth + this.gutter) * 2,
32154 x : x + (this.unitWidth + this.gutter) * 2,
32155 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
32162 getVerticalFourBoxColPositions : function(x, y, box)
32166 if(box[0].size == 'xs'){
32175 y : y + (this.unitHeight + this.gutter) * 1
32180 y : y + (this.unitHeight + this.gutter) * 2
32184 x : x + (this.unitWidth + this.gutter) * 1,
32198 x : x + (this.unitWidth + this.gutter) * 2,
32203 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
32204 y : y + (this.unitHeight + this.gutter) * 1
32208 x : x + (this.unitWidth + this.gutter) * 2,
32209 y : y + (this.unitWidth + this.gutter) * 2
32216 getHorizontalOneBoxColPositions : function(maxX, minY, box)
32220 if(box[0].size == 'md-left'){
32222 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
32229 if(box[0].size == 'md-right'){
32231 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
32232 y : minY + (this.unitWidth + this.gutter) * 1
32238 var rand = Math.floor(Math.random() * (4 - box[0].y));
32241 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32242 y : minY + (this.unitWidth + this.gutter) * rand
32249 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
32253 if(box[0].size == 'xs'){
32256 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32261 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32262 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
32270 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32275 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32276 y : minY + (this.unitWidth + this.gutter) * 2
32283 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
32287 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
32290 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32295 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32296 y : minY + (this.unitWidth + this.gutter) * 1
32300 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32301 y : minY + (this.unitWidth + this.gutter) * 2
32308 if(box[0].size == 'xs' && box[1].size == 'xs'){
32311 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32316 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32321 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32322 y : minY + (this.unitWidth + this.gutter) * 1
32330 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32335 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32336 y : minY + (this.unitWidth + this.gutter) * 2
32340 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32341 y : minY + (this.unitWidth + this.gutter) * 2
32348 getHorizontalFourBoxColPositions : function(maxX, minY, box)
32352 if(box[0].size == 'xs'){
32355 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32360 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32365 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),
32370 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
32371 y : minY + (this.unitWidth + this.gutter) * 1
32379 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32384 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32385 y : minY + (this.unitWidth + this.gutter) * 2
32389 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32390 y : minY + (this.unitWidth + this.gutter) * 2
32394 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),
32395 y : minY + (this.unitWidth + this.gutter) * 2
32403 * remove a Masonry Brick
32404 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
32406 removeBrick : function(brick_id)
32412 for (var i = 0; i<this.bricks.length; i++) {
32413 if (this.bricks[i].id == brick_id) {
32414 this.bricks.splice(i,1);
32415 this.el.dom.removeChild(Roo.get(brick_id).dom);
32422 * adds a Masonry Brick
32423 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32425 addBrick : function(cfg)
32427 var cn = new Roo.bootstrap.MasonryBrick(cfg);
32428 //this.register(cn);
32429 cn.parentId = this.id;
32430 cn.render(this.el);
32435 * register a Masonry Brick
32436 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32439 register : function(brick)
32441 this.bricks.push(brick);
32442 brick.masonryId = this.id;
32446 * clear all the Masonry Brick
32448 clearAll : function()
32451 //this.getChildContainer().dom.innerHTML = "";
32452 this.el.dom.innerHTML = '';
32455 getSelected : function()
32457 if (!this.selectedBrick) {
32461 return this.selectedBrick;
32465 Roo.apply(Roo.bootstrap.LayoutMasonry, {
32469 * register a Masonry Layout
32470 * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
32473 register : function(layout)
32475 this.groups[layout.id] = layout;
32478 * fetch a Masonry Layout based on the masonry layout ID
32479 * @param {string} the masonry layout to add
32480 * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
32483 get: function(layout_id) {
32484 if (typeof(this.groups[layout_id]) == 'undefined') {
32487 return this.groups[layout_id] ;
32499 * http://masonry.desandro.com
32501 * The idea is to render all the bricks based on vertical width...
32503 * The original code extends 'outlayer' - we might need to use that....
32509 * @class Roo.bootstrap.LayoutMasonryAuto
32510 * @extends Roo.bootstrap.Component
32511 * Bootstrap Layout Masonry class
32514 * Create a new Element
32515 * @param {Object} config The config object
32518 Roo.bootstrap.LayoutMasonryAuto = function(config){
32519 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
32522 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
32525 * @cfg {Boolean} isFitWidth - resize the width..
32527 isFitWidth : false, // options..
32529 * @cfg {Boolean} isOriginLeft = left align?
32531 isOriginLeft : true,
32533 * @cfg {Boolean} isOriginTop = top align?
32535 isOriginTop : false,
32537 * @cfg {Boolean} isLayoutInstant = no animation?
32539 isLayoutInstant : false, // needed?
32541 * @cfg {Boolean} isResizingContainer = not sure if this is used..
32543 isResizingContainer : true,
32545 * @cfg {Number} columnWidth width of the columns
32551 * @cfg {Number} maxCols maximum number of columns
32556 * @cfg {Number} padHeight padding below box..
32562 * @cfg {Boolean} isAutoInitial defalut true
32565 isAutoInitial : true,
32571 initialColumnWidth : 0,
32572 currentSize : null,
32574 colYs : null, // array.
32581 bricks: null, //CompositeElement
32582 cols : 0, // array?
32583 // element : null, // wrapped now this.el
32584 _isLayoutInited : null,
32587 getAutoCreate : function(){
32591 cls: 'blog-masonary-wrapper ' + this.cls,
32593 cls : 'mas-boxes masonary'
32600 getChildContainer: function( )
32602 if (this.boxesEl) {
32603 return this.boxesEl;
32606 this.boxesEl = this.el.select('.mas-boxes').first();
32608 return this.boxesEl;
32612 initEvents : function()
32616 if(this.isAutoInitial){
32617 Roo.log('hook children rendered');
32618 this.on('childrenrendered', function() {
32619 Roo.log('children rendered');
32626 initial : function()
32628 this.reloadItems();
32630 this.currentSize = this.el.getBox(true);
32632 /// was window resize... - let's see if this works..
32633 Roo.EventManager.onWindowResize(this.resize, this);
32635 if(!this.isAutoInitial){
32640 this.layout.defer(500,this);
32643 reloadItems: function()
32645 this.bricks = this.el.select('.masonry-brick', true);
32647 this.bricks.each(function(b) {
32648 //Roo.log(b.getSize());
32649 if (!b.attr('originalwidth')) {
32650 b.attr('originalwidth', b.getSize().width);
32655 Roo.log(this.bricks.elements.length);
32658 resize : function()
32661 var cs = this.el.getBox(true);
32663 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
32664 Roo.log("no change in with or X");
32667 this.currentSize = cs;
32671 layout : function()
32674 this._resetLayout();
32675 //this._manageStamps();
32677 // don't animate first layout
32678 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
32679 this.layoutItems( isInstant );
32681 // flag for initalized
32682 this._isLayoutInited = true;
32685 layoutItems : function( isInstant )
32687 //var items = this._getItemsForLayout( this.items );
32688 // original code supports filtering layout items.. we just ignore it..
32690 this._layoutItems( this.bricks , isInstant );
32692 this._postLayout();
32694 _layoutItems : function ( items , isInstant)
32696 //this.fireEvent( 'layout', this, items );
32699 if ( !items || !items.elements.length ) {
32700 // no items, emit event with empty array
32705 items.each(function(item) {
32706 Roo.log("layout item");
32708 // get x/y object from method
32709 var position = this._getItemLayoutPosition( item );
32711 position.item = item;
32712 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
32713 queue.push( position );
32716 this._processLayoutQueue( queue );
32718 /** Sets position of item in DOM
32719 * @param {Element} item
32720 * @param {Number} x - horizontal position
32721 * @param {Number} y - vertical position
32722 * @param {Boolean} isInstant - disables transitions
32724 _processLayoutQueue : function( queue )
32726 for ( var i=0, len = queue.length; i < len; i++ ) {
32727 var obj = queue[i];
32728 obj.item.position('absolute');
32729 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
32735 * Any logic you want to do after each layout,
32736 * i.e. size the container
32738 _postLayout : function()
32740 this.resizeContainer();
32743 resizeContainer : function()
32745 if ( !this.isResizingContainer ) {
32748 var size = this._getContainerSize();
32750 this.el.setSize(size.width,size.height);
32751 this.boxesEl.setSize(size.width,size.height);
32757 _resetLayout : function()
32759 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
32760 this.colWidth = this.el.getWidth();
32761 //this.gutter = this.el.getWidth();
32763 this.measureColumns();
32769 this.colYs.push( 0 );
32775 measureColumns : function()
32777 this.getContainerWidth();
32778 // if columnWidth is 0, default to outerWidth of first item
32779 if ( !this.columnWidth ) {
32780 var firstItem = this.bricks.first();
32781 Roo.log(firstItem);
32782 this.columnWidth = this.containerWidth;
32783 if (firstItem && firstItem.attr('originalwidth') ) {
32784 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
32786 // columnWidth fall back to item of first element
32787 Roo.log("set column width?");
32788 this.initialColumnWidth = this.columnWidth ;
32790 // if first elem has no width, default to size of container
32795 if (this.initialColumnWidth) {
32796 this.columnWidth = this.initialColumnWidth;
32801 // column width is fixed at the top - however if container width get's smaller we should
32804 // this bit calcs how man columns..
32806 var columnWidth = this.columnWidth += this.gutter;
32808 // calculate columns
32809 var containerWidth = this.containerWidth + this.gutter;
32811 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
32812 // fix rounding errors, typically with gutters
32813 var excess = columnWidth - containerWidth % columnWidth;
32816 // if overshoot is less than a pixel, round up, otherwise floor it
32817 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
32818 cols = Math[ mathMethod ]( cols );
32819 this.cols = Math.max( cols, 1 );
32820 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
32822 // padding positioning..
32823 var totalColWidth = this.cols * this.columnWidth;
32824 var padavail = this.containerWidth - totalColWidth;
32825 // so for 2 columns - we need 3 'pads'
32827 var padNeeded = (1+this.cols) * this.padWidth;
32829 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
32831 this.columnWidth += padExtra
32832 //this.padWidth = Math.floor(padavail / ( this.cols));
32834 // adjust colum width so that padding is fixed??
32836 // we have 3 columns ... total = width * 3
32837 // we have X left over... that should be used by
32839 //if (this.expandC) {
32847 getContainerWidth : function()
32849 /* // container is parent if fit width
32850 var container = this.isFitWidth ? this.element.parentNode : this.element;
32851 // check that this.size and size are there
32852 // IE8 triggers resize on body size change, so they might not be
32854 var size = getSize( container ); //FIXME
32855 this.containerWidth = size && size.innerWidth; //FIXME
32858 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
32862 _getItemLayoutPosition : function( item ) // what is item?
32864 // we resize the item to our columnWidth..
32866 item.setWidth(this.columnWidth);
32867 item.autoBoxAdjust = false;
32869 var sz = item.getSize();
32871 // how many columns does this brick span
32872 var remainder = this.containerWidth % this.columnWidth;
32874 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
32875 // round if off by 1 pixel, otherwise use ceil
32876 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
32877 colSpan = Math.min( colSpan, this.cols );
32879 // normally this should be '1' as we dont' currently allow multi width columns..
32881 var colGroup = this._getColGroup( colSpan );
32882 // get the minimum Y value from the columns
32883 var minimumY = Math.min.apply( Math, colGroup );
32884 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32886 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
32888 // position the brick
32890 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
32891 y: this.currentSize.y + minimumY + this.padHeight
32895 // apply setHeight to necessary columns
32896 var setHeight = minimumY + sz.height + this.padHeight;
32897 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32899 var setSpan = this.cols + 1 - colGroup.length;
32900 for ( var i = 0; i < setSpan; i++ ) {
32901 this.colYs[ shortColIndex + i ] = setHeight ;
32908 * @param {Number} colSpan - number of columns the element spans
32909 * @returns {Array} colGroup
32911 _getColGroup : function( colSpan )
32913 if ( colSpan < 2 ) {
32914 // if brick spans only one column, use all the column Ys
32919 // how many different places could this brick fit horizontally
32920 var groupCount = this.cols + 1 - colSpan;
32921 // for each group potential horizontal position
32922 for ( var i = 0; i < groupCount; i++ ) {
32923 // make an array of colY values for that one group
32924 var groupColYs = this.colYs.slice( i, i + colSpan );
32925 // and get the max value of the array
32926 colGroup[i] = Math.max.apply( Math, groupColYs );
32931 _manageStamp : function( stamp )
32933 var stampSize = stamp.getSize();
32934 var offset = stamp.getBox();
32935 // get the columns that this stamp affects
32936 var firstX = this.isOriginLeft ? offset.x : offset.right;
32937 var lastX = firstX + stampSize.width;
32938 var firstCol = Math.floor( firstX / this.columnWidth );
32939 firstCol = Math.max( 0, firstCol );
32941 var lastCol = Math.floor( lastX / this.columnWidth );
32942 // lastCol should not go over if multiple of columnWidth #425
32943 lastCol -= lastX % this.columnWidth ? 0 : 1;
32944 lastCol = Math.min( this.cols - 1, lastCol );
32946 // set colYs to bottom of the stamp
32947 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
32950 for ( var i = firstCol; i <= lastCol; i++ ) {
32951 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
32956 _getContainerSize : function()
32958 this.maxY = Math.max.apply( Math, this.colYs );
32963 if ( this.isFitWidth ) {
32964 size.width = this._getContainerFitWidth();
32970 _getContainerFitWidth : function()
32972 var unusedCols = 0;
32973 // count unused columns
32976 if ( this.colYs[i] !== 0 ) {
32981 // fit container to columns that have been used
32982 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
32985 needsResizeLayout : function()
32987 var previousWidth = this.containerWidth;
32988 this.getContainerWidth();
32989 return previousWidth !== this.containerWidth;
33004 * @class Roo.bootstrap.MasonryBrick
33005 * @extends Roo.bootstrap.Component
33006 * Bootstrap MasonryBrick class
33009 * Create a new MasonryBrick
33010 * @param {Object} config The config object
33013 Roo.bootstrap.MasonryBrick = function(config){
33015 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
33017 Roo.bootstrap.MasonryBrick.register(this);
33023 * When a MasonryBrick is clcik
33024 * @param {Roo.bootstrap.MasonryBrick} this
33025 * @param {Roo.EventObject} e
33031 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
33034 * @cfg {String} title
33038 * @cfg {String} html
33042 * @cfg {String} bgimage
33046 * @cfg {String} videourl
33050 * @cfg {String} cls
33054 * @cfg {String} href
33058 * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
33063 * @cfg {String} placetitle (center|bottom)
33068 * @cfg {Boolean} isFitContainer defalut true
33070 isFitContainer : true,
33073 * @cfg {Boolean} preventDefault defalut false
33075 preventDefault : false,
33078 * @cfg {Boolean} inverse defalut false
33080 maskInverse : false,
33082 getAutoCreate : function()
33084 if(!this.isFitContainer){
33085 return this.getSplitAutoCreate();
33088 var cls = 'masonry-brick masonry-brick-full';
33090 if(this.href.length){
33091 cls += ' masonry-brick-link';
33094 if(this.bgimage.length){
33095 cls += ' masonry-brick-image';
33098 if(this.maskInverse){
33099 cls += ' mask-inverse';
33102 if(!this.html.length && !this.maskInverse && !this.videourl.length){
33103 cls += ' enable-mask';
33107 cls += ' masonry-' + this.size + '-brick';
33110 if(this.placetitle.length){
33112 switch (this.placetitle) {
33114 cls += ' masonry-center-title';
33117 cls += ' masonry-bottom-title';
33124 if(!this.html.length && !this.bgimage.length){
33125 cls += ' masonry-center-title';
33128 if(!this.html.length && this.bgimage.length){
33129 cls += ' masonry-bottom-title';
33134 cls += ' ' + this.cls;
33138 tag: (this.href.length) ? 'a' : 'div',
33143 cls: 'masonry-brick-mask'
33147 cls: 'masonry-brick-paragraph',
33153 if(this.href.length){
33154 cfg.href = this.href;
33157 var cn = cfg.cn[1].cn;
33159 if(this.title.length){
33162 cls: 'masonry-brick-title',
33167 if(this.html.length){
33170 cls: 'masonry-brick-text',
33175 if (!this.title.length && !this.html.length) {
33176 cfg.cn[1].cls += ' hide';
33179 if(this.bgimage.length){
33182 cls: 'masonry-brick-image-view',
33187 if(this.videourl.length){
33188 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
33189 // youtube support only?
33192 cls: 'masonry-brick-image-view',
33195 allowfullscreen : true
33203 getSplitAutoCreate : function()
33205 var cls = 'masonry-brick masonry-brick-split';
33207 if(this.href.length){
33208 cls += ' masonry-brick-link';
33211 if(this.bgimage.length){
33212 cls += ' masonry-brick-image';
33216 cls += ' masonry-' + this.size + '-brick';
33219 switch (this.placetitle) {
33221 cls += ' masonry-center-title';
33224 cls += ' masonry-bottom-title';
33227 if(!this.bgimage.length){
33228 cls += ' masonry-center-title';
33231 if(this.bgimage.length){
33232 cls += ' masonry-bottom-title';
33238 cls += ' ' + this.cls;
33242 tag: (this.href.length) ? 'a' : 'div',
33247 cls: 'masonry-brick-split-head',
33251 cls: 'masonry-brick-paragraph',
33258 cls: 'masonry-brick-split-body',
33264 if(this.href.length){
33265 cfg.href = this.href;
33268 if(this.title.length){
33269 cfg.cn[0].cn[0].cn.push({
33271 cls: 'masonry-brick-title',
33276 if(this.html.length){
33277 cfg.cn[1].cn.push({
33279 cls: 'masonry-brick-text',
33284 if(this.bgimage.length){
33285 cfg.cn[0].cn.push({
33287 cls: 'masonry-brick-image-view',
33292 if(this.videourl.length){
33293 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
33294 // youtube support only?
33295 cfg.cn[0].cn.cn.push({
33297 cls: 'masonry-brick-image-view',
33300 allowfullscreen : true
33307 initEvents: function()
33309 switch (this.size) {
33342 this.el.on('touchstart', this.onTouchStart, this);
33343 this.el.on('touchmove', this.onTouchMove, this);
33344 this.el.on('touchend', this.onTouchEnd, this);
33345 this.el.on('contextmenu', this.onContextMenu, this);
33347 this.el.on('mouseenter' ,this.enter, this);
33348 this.el.on('mouseleave', this.leave, this);
33349 this.el.on('click', this.onClick, this);
33352 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
33353 this.parent().bricks.push(this);
33358 onClick: function(e, el)
33360 var time = this.endTimer - this.startTimer;
33361 // Roo.log(e.preventDefault());
33364 e.preventDefault();
33369 if(!this.preventDefault){
33373 e.preventDefault();
33375 if (this.activeClass != '') {
33376 this.selectBrick();
33379 this.fireEvent('click', this, e);
33382 enter: function(e, el)
33384 e.preventDefault();
33386 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
33390 if(this.bgimage.length && this.html.length){
33391 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
33395 leave: function(e, el)
33397 e.preventDefault();
33399 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
33403 if(this.bgimage.length && this.html.length){
33404 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
33408 onTouchStart: function(e, el)
33410 // e.preventDefault();
33412 this.touchmoved = false;
33414 if(!this.isFitContainer){
33418 if(!this.bgimage.length || !this.html.length){
33422 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
33424 this.timer = new Date().getTime();
33428 onTouchMove: function(e, el)
33430 this.touchmoved = true;
33433 onContextMenu : function(e,el)
33435 e.preventDefault();
33436 e.stopPropagation();
33440 onTouchEnd: function(e, el)
33442 // e.preventDefault();
33444 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
33451 if(!this.bgimage.length || !this.html.length){
33453 if(this.href.length){
33454 window.location.href = this.href;
33460 if(!this.isFitContainer){
33464 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
33466 window.location.href = this.href;
33469 //selection on single brick only
33470 selectBrick : function() {
33472 if (!this.parentId) {
33476 var m = Roo.bootstrap.LayoutMasonry.get(this.parentId);
33477 var index = m.selectedBrick.indexOf(this.id);
33480 m.selectedBrick.splice(index,1);
33481 this.el.removeClass(this.activeClass);
33485 for(var i = 0; i < m.selectedBrick.length; i++) {
33486 var b = Roo.bootstrap.MasonryBrick.get(m.selectedBrick[i]);
33487 b.el.removeClass(b.activeClass);
33490 m.selectedBrick = [];
33492 m.selectedBrick.push(this.id);
33493 this.el.addClass(this.activeClass);
33497 isSelected : function(){
33498 return this.el.hasClass(this.activeClass);
33503 Roo.apply(Roo.bootstrap.MasonryBrick, {
33506 groups : new Roo.util.MixedCollection(false, function(o) { return o.el.id; }),
33508 * register a Masonry Brick
33509 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
33512 register : function(brick)
33514 //this.groups[brick.id] = brick;
33515 this.groups.add(brick.id, brick);
33518 * fetch a masonry brick based on the masonry brick ID
33519 * @param {string} the masonry brick to add
33520 * @returns {Roo.bootstrap.MasonryBrick} the masonry brick
33523 get: function(brick_id)
33525 // if (typeof(this.groups[brick_id]) == 'undefined') {
33528 // return this.groups[brick_id] ;
33530 if(this.groups.key(brick_id)) {
33531 return this.groups.key(brick_id);
33549 * @class Roo.bootstrap.Brick
33550 * @extends Roo.bootstrap.Component
33551 * Bootstrap Brick class
33554 * Create a new Brick
33555 * @param {Object} config The config object
33558 Roo.bootstrap.Brick = function(config){
33559 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
33565 * When a Brick is click
33566 * @param {Roo.bootstrap.Brick} this
33567 * @param {Roo.EventObject} e
33573 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
33576 * @cfg {String} title
33580 * @cfg {String} html
33584 * @cfg {String} bgimage
33588 * @cfg {String} cls
33592 * @cfg {String} href
33596 * @cfg {String} video
33600 * @cfg {Boolean} square
33604 getAutoCreate : function()
33606 var cls = 'roo-brick';
33608 if(this.href.length){
33609 cls += ' roo-brick-link';
33612 if(this.bgimage.length){
33613 cls += ' roo-brick-image';
33616 if(!this.html.length && !this.bgimage.length){
33617 cls += ' roo-brick-center-title';
33620 if(!this.html.length && this.bgimage.length){
33621 cls += ' roo-brick-bottom-title';
33625 cls += ' ' + this.cls;
33629 tag: (this.href.length) ? 'a' : 'div',
33634 cls: 'roo-brick-paragraph',
33640 if(this.href.length){
33641 cfg.href = this.href;
33644 var cn = cfg.cn[0].cn;
33646 if(this.title.length){
33649 cls: 'roo-brick-title',
33654 if(this.html.length){
33657 cls: 'roo-brick-text',
33664 if(this.bgimage.length){
33667 cls: 'roo-brick-image-view',
33675 initEvents: function()
33677 if(this.title.length || this.html.length){
33678 this.el.on('mouseenter' ,this.enter, this);
33679 this.el.on('mouseleave', this.leave, this);
33682 Roo.EventManager.onWindowResize(this.resize, this);
33684 if(this.bgimage.length){
33685 this.imageEl = this.el.select('.roo-brick-image-view', true).first();
33686 this.imageEl.on('load', this.onImageLoad, this);
33693 onImageLoad : function()
33698 resize : function()
33700 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
33702 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
33704 if(this.bgimage.length){
33705 var image = this.el.select('.roo-brick-image-view', true).first();
33707 image.setWidth(paragraph.getWidth());
33710 image.setHeight(paragraph.getWidth());
33713 this.el.setHeight(image.getHeight());
33714 paragraph.setHeight(image.getHeight());
33720 enter: function(e, el)
33722 e.preventDefault();
33724 if(this.bgimage.length){
33725 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
33726 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
33730 leave: function(e, el)
33732 e.preventDefault();
33734 if(this.bgimage.length){
33735 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
33736 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
33751 * @class Roo.bootstrap.NumberField
33752 * @extends Roo.bootstrap.Input
33753 * Bootstrap NumberField class
33759 * Create a new NumberField
33760 * @param {Object} config The config object
33763 Roo.bootstrap.NumberField = function(config){
33764 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
33767 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
33770 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
33772 allowDecimals : true,
33774 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
33776 decimalSeparator : ".",
33778 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
33780 decimalPrecision : 2,
33782 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
33784 allowNegative : true,
33787 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
33791 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
33793 minValue : Number.NEGATIVE_INFINITY,
33795 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
33797 maxValue : Number.MAX_VALUE,
33799 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
33801 minText : "The minimum value for this field is {0}",
33803 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
33805 maxText : "The maximum value for this field is {0}",
33807 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
33808 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
33810 nanText : "{0} is not a valid number",
33812 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
33814 thousandsDelimiter : false,
33816 * @cfg {String} valueAlign alignment of value
33818 valueAlign : "left",
33820 getAutoCreate : function()
33822 var hiddenInput = {
33826 cls: 'hidden-number-input'
33830 hiddenInput.name = this.name;
33835 var cfg = Roo.bootstrap.NumberField.superclass.getAutoCreate.call(this);
33837 this.name = hiddenInput.name;
33839 if(cfg.cn.length > 0) {
33840 cfg.cn.push(hiddenInput);
33847 initEvents : function()
33849 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
33851 var allowed = "0123456789";
33853 if(this.allowDecimals){
33854 allowed += this.decimalSeparator;
33857 if(this.allowNegative){
33861 if(this.thousandsDelimiter) {
33865 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
33867 var keyPress = function(e){
33869 var k = e.getKey();
33871 var c = e.getCharCode();
33874 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
33875 allowed.indexOf(String.fromCharCode(c)) === -1
33881 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
33885 if(allowed.indexOf(String.fromCharCode(c)) === -1){
33890 this.el.on("keypress", keyPress, this);
33893 validateValue : function(value)
33896 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
33900 var num = this.parseValue(value);
33903 this.markInvalid(String.format(this.nanText, value));
33907 if(num < this.minValue){
33908 this.markInvalid(String.format(this.minText, this.minValue));
33912 if(num > this.maxValue){
33913 this.markInvalid(String.format(this.maxText, this.maxValue));
33920 getValue : function()
33922 var v = this.hiddenEl().getValue();
33924 return this.fixPrecision(this.parseValue(v));
33927 parseValue : function(value)
33929 if(this.thousandsDelimiter) {
33931 r = new RegExp(",", "g");
33932 value = value.replace(r, "");
33935 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
33936 return isNaN(value) ? '' : value;
33939 fixPrecision : function(value)
33941 if(this.thousandsDelimiter) {
33943 r = new RegExp(",", "g");
33944 value = value.replace(r, "");
33947 var nan = isNaN(value);
33949 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
33950 return nan ? '' : value;
33952 return parseFloat(value).toFixed(this.decimalPrecision);
33955 setValue : function(v)
33957 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
33963 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
33965 this.inputEl().dom.value = (v == '') ? '' :
33966 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
33968 if(!this.allowZero && v === '0') {
33969 this.hiddenEl().dom.value = '';
33970 this.inputEl().dom.value = '';
33977 decimalPrecisionFcn : function(v)
33979 return Math.floor(v);
33982 beforeBlur : function()
33984 var v = this.parseValue(this.getRawValue());
33986 if(v || v === 0 || v === ''){
33991 hiddenEl : function()
33993 return this.el.select('input.hidden-number-input',true).first();
34005 * @class Roo.bootstrap.DocumentSlider
34006 * @extends Roo.bootstrap.Component
34007 * Bootstrap DocumentSlider class
34010 * Create a new DocumentViewer
34011 * @param {Object} config The config object
34014 Roo.bootstrap.DocumentSlider = function(config){
34015 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
34022 * Fire after initEvent
34023 * @param {Roo.bootstrap.DocumentSlider} this
34028 * Fire after update
34029 * @param {Roo.bootstrap.DocumentSlider} this
34035 * @param {Roo.bootstrap.DocumentSlider} this
34041 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
34047 getAutoCreate : function()
34051 cls : 'roo-document-slider',
34055 cls : 'roo-document-slider-header',
34059 cls : 'roo-document-slider-header-title'
34065 cls : 'roo-document-slider-body',
34069 cls : 'roo-document-slider-prev',
34073 cls : 'fa fa-chevron-left'
34079 cls : 'roo-document-slider-thumb',
34083 cls : 'roo-document-slider-image'
34089 cls : 'roo-document-slider-next',
34093 cls : 'fa fa-chevron-right'
34105 initEvents : function()
34107 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
34108 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
34110 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
34111 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
34113 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
34114 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
34116 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
34117 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
34119 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
34120 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
34122 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
34123 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
34125 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
34126 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
34128 this.thumbEl.on('click', this.onClick, this);
34130 this.prevIndicator.on('click', this.prev, this);
34132 this.nextIndicator.on('click', this.next, this);
34136 initial : function()
34138 if(this.files.length){
34139 this.indicator = 1;
34143 this.fireEvent('initial', this);
34146 update : function()
34148 this.imageEl.attr('src', this.files[this.indicator - 1]);
34150 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
34152 this.prevIndicator.show();
34154 if(this.indicator == 1){
34155 this.prevIndicator.hide();
34158 this.nextIndicator.show();
34160 if(this.indicator == this.files.length){
34161 this.nextIndicator.hide();
34164 this.thumbEl.scrollTo('top');
34166 this.fireEvent('update', this);
34169 onClick : function(e)
34171 e.preventDefault();
34173 this.fireEvent('click', this);
34178 e.preventDefault();
34180 this.indicator = Math.max(1, this.indicator - 1);
34187 e.preventDefault();
34189 this.indicator = Math.min(this.files.length, this.indicator + 1);
34203 * @class Roo.bootstrap.RadioSet
34204 * @extends Roo.bootstrap.Input
34205 * Bootstrap RadioSet class
34206 * @cfg {String} indicatorpos (left|right) default left
34207 * @cfg {Boolean} inline (true|false) inline the element (default true)
34208 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
34210 * Create a new RadioSet
34211 * @param {Object} config The config object
34214 Roo.bootstrap.RadioSet = function(config){
34216 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
34220 Roo.bootstrap.RadioSet.register(this);
34225 * Fires when the element is checked or unchecked.
34226 * @param {Roo.bootstrap.RadioSet} this This radio
34227 * @param {Roo.bootstrap.Radio} item The checked item
34232 * Fires when the element is click.
34233 * @param {Roo.bootstrap.RadioSet} this This radio set
34234 * @param {Roo.bootstrap.Radio} item The checked item
34235 * @param {Roo.EventObject} e The event object
34242 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
34250 indicatorpos : 'left',
34252 getAutoCreate : function()
34256 cls : 'roo-radio-set-label',
34260 html : this.fieldLabel
34264 if (Roo.bootstrap.version == 3) {
34267 if(this.indicatorpos == 'left'){
34270 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
34271 tooltip : 'This field is required'
34276 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
34277 tooltip : 'This field is required'
34283 cls : 'roo-radio-set-items'
34286 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
34288 if (align === 'left' && this.fieldLabel.length) {
34291 cls : "roo-radio-set-right",
34297 if(this.labelWidth > 12){
34298 label.style = "width: " + this.labelWidth + 'px';
34301 if(this.labelWidth < 13 && this.labelmd == 0){
34302 this.labelmd = this.labelWidth;
34305 if(this.labellg > 0){
34306 label.cls += ' col-lg-' + this.labellg;
34307 items.cls += ' col-lg-' + (12 - this.labellg);
34310 if(this.labelmd > 0){
34311 label.cls += ' col-md-' + this.labelmd;
34312 items.cls += ' col-md-' + (12 - this.labelmd);
34315 if(this.labelsm > 0){
34316 label.cls += ' col-sm-' + this.labelsm;
34317 items.cls += ' col-sm-' + (12 - this.labelsm);
34320 if(this.labelxs > 0){
34321 label.cls += ' col-xs-' + this.labelxs;
34322 items.cls += ' col-xs-' + (12 - this.labelxs);
34328 cls : 'roo-radio-set',
34332 cls : 'roo-radio-set-input',
34335 value : this.value ? this.value : ''
34342 if(this.weight.length){
34343 cfg.cls += ' roo-radio-' + this.weight;
34347 cfg.cls += ' roo-radio-set-inline';
34351 ['xs','sm','md','lg'].map(function(size){
34352 if (settings[size]) {
34353 cfg.cls += ' col-' + size + '-' + settings[size];
34361 initEvents : function()
34363 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
34364 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
34366 if(!this.fieldLabel.length){
34367 this.labelEl.hide();
34370 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
34371 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
34373 this.indicator = this.indicatorEl();
34375 if(this.indicator){
34376 this.indicator.addClass('invisible');
34379 this.originalValue = this.getValue();
34383 inputEl: function ()
34385 return this.el.select('.roo-radio-set-input', true).first();
34388 getChildContainer : function()
34390 return this.itemsEl;
34393 register : function(item)
34395 this.radioes.push(item);
34399 validate : function()
34401 if(this.getVisibilityEl().hasClass('hidden')){
34407 Roo.each(this.radioes, function(i){
34416 if(this.allowBlank) {
34420 if(this.disabled || valid){
34425 this.markInvalid();
34430 markValid : function()
34432 if(this.labelEl.isVisible(true) && this.indicatorEl()){
34433 this.indicatorEl().removeClass('visible');
34434 this.indicatorEl().addClass('invisible');
34438 if (Roo.bootstrap.version == 3) {
34439 this.el.removeClass([this.invalidClass, this.validClass]);
34440 this.el.addClass(this.validClass);
34442 this.el.removeClass(['is-invalid','is-valid']);
34443 this.el.addClass(['is-valid']);
34445 this.fireEvent('valid', this);
34448 markInvalid : function(msg)
34450 if(this.allowBlank || this.disabled){
34454 if(this.labelEl.isVisible(true) && this.indicatorEl()){
34455 this.indicatorEl().removeClass('invisible');
34456 this.indicatorEl().addClass('visible');
34458 if (Roo.bootstrap.version == 3) {
34459 this.el.removeClass([this.invalidClass, this.validClass]);
34460 this.el.addClass(this.invalidClass);
34462 this.el.removeClass(['is-invalid','is-valid']);
34463 this.el.addClass(['is-invalid']);
34466 this.fireEvent('invalid', this, msg);
34470 setValue : function(v, suppressEvent)
34472 if(this.value === v){
34479 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
34482 Roo.each(this.radioes, function(i){
34484 i.el.removeClass('checked');
34487 Roo.each(this.radioes, function(i){
34489 if(i.value === v || i.value.toString() === v.toString()){
34491 i.el.addClass('checked');
34493 if(suppressEvent !== true){
34494 this.fireEvent('check', this, i);
34505 clearInvalid : function(){
34507 if(!this.el || this.preventMark){
34511 this.el.removeClass([this.invalidClass]);
34513 this.fireEvent('valid', this);
34518 Roo.apply(Roo.bootstrap.RadioSet, {
34522 register : function(set)
34524 this.groups[set.name] = set;
34527 get: function(name)
34529 if (typeof(this.groups[name]) == 'undefined') {
34533 return this.groups[name] ;
34539 * Ext JS Library 1.1.1
34540 * Copyright(c) 2006-2007, Ext JS, LLC.
34542 * Originally Released Under LGPL - original licence link has changed is not relivant.
34545 * <script type="text/javascript">
34550 * @class Roo.bootstrap.SplitBar
34551 * @extends Roo.util.Observable
34552 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
34556 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
34557 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
34558 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
34559 split.minSize = 100;
34560 split.maxSize = 600;
34561 split.animate = true;
34562 split.on('moved', splitterMoved);
34565 * Create a new SplitBar
34566 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
34567 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
34568 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34569 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
34570 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
34571 position of the SplitBar).
34573 Roo.bootstrap.SplitBar = function(cfg){
34578 // dragElement : elm
34579 // resizingElement: el,
34581 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
34582 // placement : Roo.bootstrap.SplitBar.LEFT ,
34583 // existingProxy ???
34586 this.el = Roo.get(cfg.dragElement, true);
34587 this.el.dom.unselectable = "on";
34589 this.resizingEl = Roo.get(cfg.resizingElement, true);
34593 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34594 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
34597 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
34600 * The minimum size of the resizing element. (Defaults to 0)
34606 * The maximum size of the resizing element. (Defaults to 2000)
34609 this.maxSize = 2000;
34612 * Whether to animate the transition to the new size
34615 this.animate = false;
34618 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
34621 this.useShim = false;
34626 if(!cfg.existingProxy){
34628 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
34630 this.proxy = Roo.get(cfg.existingProxy).dom;
34633 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
34636 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
34639 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
34642 this.dragSpecs = {};
34645 * @private The adapter to use to positon and resize elements
34647 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34648 this.adapter.init(this);
34650 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34652 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
34653 this.el.addClass("roo-splitbar-h");
34656 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
34657 this.el.addClass("roo-splitbar-v");
34663 * Fires when the splitter is moved (alias for {@link #event-moved})
34664 * @param {Roo.bootstrap.SplitBar} this
34665 * @param {Number} newSize the new width or height
34670 * Fires when the splitter is moved
34671 * @param {Roo.bootstrap.SplitBar} this
34672 * @param {Number} newSize the new width or height
34676 * @event beforeresize
34677 * Fires before the splitter is dragged
34678 * @param {Roo.bootstrap.SplitBar} this
34680 "beforeresize" : true,
34682 "beforeapply" : true
34685 Roo.util.Observable.call(this);
34688 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
34689 onStartProxyDrag : function(x, y){
34690 this.fireEvent("beforeresize", this);
34692 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
34694 o.enableDisplayMode("block");
34695 // all splitbars share the same overlay
34696 Roo.bootstrap.SplitBar.prototype.overlay = o;
34698 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
34699 this.overlay.show();
34700 Roo.get(this.proxy).setDisplayed("block");
34701 var size = this.adapter.getElementSize(this);
34702 this.activeMinSize = this.getMinimumSize();;
34703 this.activeMaxSize = this.getMaximumSize();;
34704 var c1 = size - this.activeMinSize;
34705 var c2 = Math.max(this.activeMaxSize - size, 0);
34706 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34707 this.dd.resetConstraints();
34708 this.dd.setXConstraint(
34709 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
34710 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
34712 this.dd.setYConstraint(0, 0);
34714 this.dd.resetConstraints();
34715 this.dd.setXConstraint(0, 0);
34716 this.dd.setYConstraint(
34717 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
34718 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
34721 this.dragSpecs.startSize = size;
34722 this.dragSpecs.startPoint = [x, y];
34723 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
34727 * @private Called after the drag operation by the DDProxy
34729 onEndProxyDrag : function(e){
34730 Roo.get(this.proxy).setDisplayed(false);
34731 var endPoint = Roo.lib.Event.getXY(e);
34733 this.overlay.hide();
34736 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34737 newSize = this.dragSpecs.startSize +
34738 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
34739 endPoint[0] - this.dragSpecs.startPoint[0] :
34740 this.dragSpecs.startPoint[0] - endPoint[0]
34743 newSize = this.dragSpecs.startSize +
34744 (this.placement == Roo.bootstrap.SplitBar.TOP ?
34745 endPoint[1] - this.dragSpecs.startPoint[1] :
34746 this.dragSpecs.startPoint[1] - endPoint[1]
34749 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
34750 if(newSize != this.dragSpecs.startSize){
34751 if(this.fireEvent('beforeapply', this, newSize) !== false){
34752 this.adapter.setElementSize(this, newSize);
34753 this.fireEvent("moved", this, newSize);
34754 this.fireEvent("resize", this, newSize);
34760 * Get the adapter this SplitBar uses
34761 * @return The adapter object
34763 getAdapter : function(){
34764 return this.adapter;
34768 * Set the adapter this SplitBar uses
34769 * @param {Object} adapter A SplitBar adapter object
34771 setAdapter : function(adapter){
34772 this.adapter = adapter;
34773 this.adapter.init(this);
34777 * Gets the minimum size for the resizing element
34778 * @return {Number} The minimum size
34780 getMinimumSize : function(){
34781 return this.minSize;
34785 * Sets the minimum size for the resizing element
34786 * @param {Number} minSize The minimum size
34788 setMinimumSize : function(minSize){
34789 this.minSize = minSize;
34793 * Gets the maximum size for the resizing element
34794 * @return {Number} The maximum size
34796 getMaximumSize : function(){
34797 return this.maxSize;
34801 * Sets the maximum size for the resizing element
34802 * @param {Number} maxSize The maximum size
34804 setMaximumSize : function(maxSize){
34805 this.maxSize = maxSize;
34809 * Sets the initialize size for the resizing element
34810 * @param {Number} size The initial size
34812 setCurrentSize : function(size){
34813 var oldAnimate = this.animate;
34814 this.animate = false;
34815 this.adapter.setElementSize(this, size);
34816 this.animate = oldAnimate;
34820 * Destroy this splitbar.
34821 * @param {Boolean} removeEl True to remove the element
34823 destroy : function(removeEl){
34825 this.shim.remove();
34828 this.proxy.parentNode.removeChild(this.proxy);
34836 * @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.
34838 Roo.bootstrap.SplitBar.createProxy = function(dir){
34839 var proxy = new Roo.Element(document.createElement("div"));
34840 proxy.unselectable();
34841 var cls = 'roo-splitbar-proxy';
34842 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
34843 document.body.appendChild(proxy.dom);
34848 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
34849 * Default Adapter. It assumes the splitter and resizing element are not positioned
34850 * elements and only gets/sets the width of the element. Generally used for table based layouts.
34852 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
34855 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
34856 // do nothing for now
34857 init : function(s){
34861 * Called before drag operations to get the current size of the resizing element.
34862 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34864 getElementSize : function(s){
34865 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34866 return s.resizingEl.getWidth();
34868 return s.resizingEl.getHeight();
34873 * Called after drag operations to set the size of the resizing element.
34874 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34875 * @param {Number} newSize The new size to set
34876 * @param {Function} onComplete A function to be invoked when resizing is complete
34878 setElementSize : function(s, newSize, onComplete){
34879 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34881 s.resizingEl.setWidth(newSize);
34883 onComplete(s, newSize);
34886 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
34891 s.resizingEl.setHeight(newSize);
34893 onComplete(s, newSize);
34896 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
34903 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
34904 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
34905 * Adapter that moves the splitter element to align with the resized sizing element.
34906 * Used with an absolute positioned SplitBar.
34907 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
34908 * document.body, make sure you assign an id to the body element.
34910 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
34911 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34912 this.container = Roo.get(container);
34915 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
34916 init : function(s){
34917 this.basic.init(s);
34920 getElementSize : function(s){
34921 return this.basic.getElementSize(s);
34924 setElementSize : function(s, newSize, onComplete){
34925 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
34928 moveSplitter : function(s){
34929 var yes = Roo.bootstrap.SplitBar;
34930 switch(s.placement){
34932 s.el.setX(s.resizingEl.getRight());
34935 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
34938 s.el.setY(s.resizingEl.getBottom());
34941 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
34948 * Orientation constant - Create a vertical SplitBar
34952 Roo.bootstrap.SplitBar.VERTICAL = 1;
34955 * Orientation constant - Create a horizontal SplitBar
34959 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
34962 * Placement constant - The resizing element is to the left of the splitter element
34966 Roo.bootstrap.SplitBar.LEFT = 1;
34969 * Placement constant - The resizing element is to the right of the splitter element
34973 Roo.bootstrap.SplitBar.RIGHT = 2;
34976 * Placement constant - The resizing element is positioned above the splitter element
34980 Roo.bootstrap.SplitBar.TOP = 3;
34983 * Placement constant - The resizing element is positioned under splitter element
34987 Roo.bootstrap.SplitBar.BOTTOM = 4;
34988 Roo.namespace("Roo.bootstrap.layout");/*
34990 * Ext JS Library 1.1.1
34991 * Copyright(c) 2006-2007, Ext JS, LLC.
34993 * Originally Released Under LGPL - original licence link has changed is not relivant.
34996 * <script type="text/javascript">
35000 * @class Roo.bootstrap.layout.Manager
35001 * @extends Roo.bootstrap.Component
35002 * Base class for layout managers.
35004 Roo.bootstrap.layout.Manager = function(config)
35006 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
35012 /** false to disable window resize monitoring @type Boolean */
35013 this.monitorWindowResize = true;
35018 * Fires when a layout is performed.
35019 * @param {Roo.LayoutManager} this
35023 * @event regionresized
35024 * Fires when the user resizes a region.
35025 * @param {Roo.LayoutRegion} region The resized region
35026 * @param {Number} newSize The new size (width for east/west, height for north/south)
35028 "regionresized" : true,
35030 * @event regioncollapsed
35031 * Fires when a region is collapsed.
35032 * @param {Roo.LayoutRegion} region The collapsed region
35034 "regioncollapsed" : true,
35036 * @event regionexpanded
35037 * Fires when a region is expanded.
35038 * @param {Roo.LayoutRegion} region The expanded region
35040 "regionexpanded" : true
35042 this.updating = false;
35045 this.el = Roo.get(config.el);
35051 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
35056 monitorWindowResize : true,
35062 onRender : function(ct, position)
35065 this.el = Roo.get(ct);
35068 //this.fireEvent('render',this);
35072 initEvents: function()
35076 // ie scrollbar fix
35077 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
35078 document.body.scroll = "no";
35079 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
35080 this.el.position('relative');
35082 this.id = this.el.id;
35083 this.el.addClass("roo-layout-container");
35084 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
35085 if(this.el.dom != document.body ) {
35086 this.el.on('resize', this.layout,this);
35087 this.el.on('show', this.layout,this);
35093 * Returns true if this layout is currently being updated
35094 * @return {Boolean}
35096 isUpdating : function(){
35097 return this.updating;
35101 * Suspend the LayoutManager from doing auto-layouts while
35102 * making multiple add or remove calls
35104 beginUpdate : function(){
35105 this.updating = true;
35109 * Restore auto-layouts and optionally disable the manager from performing a layout
35110 * @param {Boolean} noLayout true to disable a layout update
35112 endUpdate : function(noLayout){
35113 this.updating = false;
35119 layout: function(){
35123 onRegionResized : function(region, newSize){
35124 this.fireEvent("regionresized", region, newSize);
35128 onRegionCollapsed : function(region){
35129 this.fireEvent("regioncollapsed", region);
35132 onRegionExpanded : function(region){
35133 this.fireEvent("regionexpanded", region);
35137 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
35138 * performs box-model adjustments.
35139 * @return {Object} The size as an object {width: (the width), height: (the height)}
35141 getViewSize : function()
35144 if(this.el.dom != document.body){
35145 size = this.el.getSize();
35147 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
35149 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
35150 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
35155 * Returns the Element this layout is bound to.
35156 * @return {Roo.Element}
35158 getEl : function(){
35163 * Returns the specified region.
35164 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
35165 * @return {Roo.LayoutRegion}
35167 getRegion : function(target){
35168 return this.regions[target.toLowerCase()];
35171 onWindowResize : function(){
35172 if(this.monitorWindowResize){
35179 * Ext JS Library 1.1.1
35180 * Copyright(c) 2006-2007, Ext JS, LLC.
35182 * Originally Released Under LGPL - original licence link has changed is not relivant.
35185 * <script type="text/javascript">
35188 * @class Roo.bootstrap.layout.Border
35189 * @extends Roo.bootstrap.layout.Manager
35190 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
35191 * please see: examples/bootstrap/nested.html<br><br>
35193 <b>The container the layout is rendered into can be either the body element or any other element.
35194 If it is not the body element, the container needs to either be an absolute positioned element,
35195 or you will need to add "position:relative" to the css of the container. You will also need to specify
35196 the container size if it is not the body element.</b>
35199 * Create a new Border
35200 * @param {Object} config Configuration options
35202 Roo.bootstrap.layout.Border = function(config){
35203 config = config || {};
35204 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
35208 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
35209 if(config[region]){
35210 config[region].region = region;
35211 this.addRegion(config[region]);
35217 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
35219 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
35221 parent : false, // this might point to a 'nest' or a ???
35224 * Creates and adds a new region if it doesn't already exist.
35225 * @param {String} target The target region key (north, south, east, west or center).
35226 * @param {Object} config The regions config object
35227 * @return {BorderLayoutRegion} The new region
35229 addRegion : function(config)
35231 if(!this.regions[config.region]){
35232 var r = this.factory(config);
35233 this.bindRegion(r);
35235 return this.regions[config.region];
35239 bindRegion : function(r){
35240 this.regions[r.config.region] = r;
35242 r.on("visibilitychange", this.layout, this);
35243 r.on("paneladded", this.layout, this);
35244 r.on("panelremoved", this.layout, this);
35245 r.on("invalidated", this.layout, this);
35246 r.on("resized", this.onRegionResized, this);
35247 r.on("collapsed", this.onRegionCollapsed, this);
35248 r.on("expanded", this.onRegionExpanded, this);
35252 * Performs a layout update.
35254 layout : function()
35256 if(this.updating) {
35260 // render all the rebions if they have not been done alreayd?
35261 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
35262 if(this.regions[region] && !this.regions[region].bodyEl){
35263 this.regions[region].onRender(this.el)
35267 var size = this.getViewSize();
35268 var w = size.width;
35269 var h = size.height;
35274 //var x = 0, y = 0;
35276 var rs = this.regions;
35277 var north = rs["north"];
35278 var south = rs["south"];
35279 var west = rs["west"];
35280 var east = rs["east"];
35281 var center = rs["center"];
35282 //if(this.hideOnLayout){ // not supported anymore
35283 //c.el.setStyle("display", "none");
35285 if(north && north.isVisible()){
35286 var b = north.getBox();
35287 var m = north.getMargins();
35288 b.width = w - (m.left+m.right);
35291 centerY = b.height + b.y + m.bottom;
35292 centerH -= centerY;
35293 north.updateBox(this.safeBox(b));
35295 if(south && south.isVisible()){
35296 var b = south.getBox();
35297 var m = south.getMargins();
35298 b.width = w - (m.left+m.right);
35300 var totalHeight = (b.height + m.top + m.bottom);
35301 b.y = h - totalHeight + m.top;
35302 centerH -= totalHeight;
35303 south.updateBox(this.safeBox(b));
35305 if(west && west.isVisible()){
35306 var b = west.getBox();
35307 var m = west.getMargins();
35308 b.height = centerH - (m.top+m.bottom);
35310 b.y = centerY + m.top;
35311 var totalWidth = (b.width + m.left + m.right);
35312 centerX += totalWidth;
35313 centerW -= totalWidth;
35314 west.updateBox(this.safeBox(b));
35316 if(east && east.isVisible()){
35317 var b = east.getBox();
35318 var m = east.getMargins();
35319 b.height = centerH - (m.top+m.bottom);
35320 var totalWidth = (b.width + m.left + m.right);
35321 b.x = w - totalWidth + m.left;
35322 b.y = centerY + m.top;
35323 centerW -= totalWidth;
35324 east.updateBox(this.safeBox(b));
35327 var m = center.getMargins();
35329 x: centerX + m.left,
35330 y: centerY + m.top,
35331 width: centerW - (m.left+m.right),
35332 height: centerH - (m.top+m.bottom)
35334 //if(this.hideOnLayout){
35335 //center.el.setStyle("display", "block");
35337 center.updateBox(this.safeBox(centerBox));
35340 this.fireEvent("layout", this);
35344 safeBox : function(box){
35345 box.width = Math.max(0, box.width);
35346 box.height = Math.max(0, box.height);
35351 * Adds a ContentPanel (or subclass) to this layout.
35352 * @param {String} target The target region key (north, south, east, west or center).
35353 * @param {Roo.ContentPanel} panel The panel to add
35354 * @return {Roo.ContentPanel} The added panel
35356 add : function(target, panel){
35358 target = target.toLowerCase();
35359 return this.regions[target].add(panel);
35363 * Remove a ContentPanel (or subclass) to this layout.
35364 * @param {String} target The target region key (north, south, east, west or center).
35365 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
35366 * @return {Roo.ContentPanel} The removed panel
35368 remove : function(target, panel){
35369 target = target.toLowerCase();
35370 return this.regions[target].remove(panel);
35374 * Searches all regions for a panel with the specified id
35375 * @param {String} panelId
35376 * @return {Roo.ContentPanel} The panel or null if it wasn't found
35378 findPanel : function(panelId){
35379 var rs = this.regions;
35380 for(var target in rs){
35381 if(typeof rs[target] != "function"){
35382 var p = rs[target].getPanel(panelId);
35392 * Searches all regions for a panel with the specified id and activates (shows) it.
35393 * @param {String/ContentPanel} panelId The panels id or the panel itself
35394 * @return {Roo.ContentPanel} The shown panel or null
35396 showPanel : function(panelId) {
35397 var rs = this.regions;
35398 for(var target in rs){
35399 var r = rs[target];
35400 if(typeof r != "function"){
35401 if(r.hasPanel(panelId)){
35402 return r.showPanel(panelId);
35410 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
35411 * @param {Roo.state.Provider} provider (optional) An alternate state provider
35414 restoreState : function(provider){
35416 provider = Roo.state.Manager;
35418 var sm = new Roo.LayoutStateManager();
35419 sm.init(this, provider);
35425 * Adds a xtype elements to the layout.
35429 xtype : 'ContentPanel',
35436 xtype : 'NestedLayoutPanel',
35442 items : [ ... list of content panels or nested layout panels.. ]
35446 * @param {Object} cfg Xtype definition of item to add.
35448 addxtype : function(cfg)
35450 // basically accepts a pannel...
35451 // can accept a layout region..!?!?
35452 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
35455 // theory? children can only be panels??
35457 //if (!cfg.xtype.match(/Panel$/)) {
35462 if (typeof(cfg.region) == 'undefined') {
35463 Roo.log("Failed to add Panel, region was not set");
35467 var region = cfg.region;
35473 xitems = cfg.items;
35478 if ( region == 'center') {
35479 Roo.log("Center: " + cfg.title);
35485 case 'Content': // ContentPanel (el, cfg)
35486 case 'Scroll': // ContentPanel (el, cfg)
35488 cfg.autoCreate = cfg.autoCreate || true;
35489 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35491 // var el = this.el.createChild();
35492 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
35495 this.add(region, ret);
35499 case 'TreePanel': // our new panel!
35500 cfg.el = this.el.createChild();
35501 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
35502 this.add(region, ret);
35507 // create a new Layout (which is a Border Layout...
35509 var clayout = cfg.layout;
35510 clayout.el = this.el.createChild();
35511 clayout.items = clayout.items || [];
35515 // replace this exitems with the clayout ones..
35516 xitems = clayout.items;
35518 // force background off if it's in center...
35519 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
35520 cfg.background = false;
35522 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
35525 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35526 //console.log('adding nested layout panel ' + cfg.toSource());
35527 this.add(region, ret);
35528 nb = {}; /// find first...
35533 // needs grid and region
35535 //var el = this.getRegion(region).el.createChild();
35537 *var el = this.el.createChild();
35538 // create the grid first...
35539 cfg.grid.container = el;
35540 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
35543 if (region == 'center' && this.active ) {
35544 cfg.background = false;
35547 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35549 this.add(region, ret);
35551 if (cfg.background) {
35552 // render grid on panel activation (if panel background)
35553 ret.on('activate', function(gp) {
35554 if (!gp.grid.rendered) {
35555 // gp.grid.render(el);
35559 // cfg.grid.render(el);
35565 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
35566 // it was the old xcomponent building that caused this before.
35567 // espeically if border is the top element in the tree.
35577 if (typeof(Roo[cfg.xtype]) != 'undefined') {
35579 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
35580 this.add(region, ret);
35584 throw "Can not add '" + cfg.xtype + "' to Border";
35590 this.beginUpdate();
35594 Roo.each(xitems, function(i) {
35595 region = nb && i.region ? i.region : false;
35597 var add = ret.addxtype(i);
35600 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
35601 if (!i.background) {
35602 abn[region] = nb[region] ;
35609 // make the last non-background panel active..
35610 //if (nb) { Roo.log(abn); }
35613 for(var r in abn) {
35614 region = this.getRegion(r);
35616 // tried using nb[r], but it does not work..
35618 region.showPanel(abn[r]);
35629 factory : function(cfg)
35632 var validRegions = Roo.bootstrap.layout.Border.regions;
35634 var target = cfg.region;
35637 var r = Roo.bootstrap.layout;
35641 return new r.North(cfg);
35643 return new r.South(cfg);
35645 return new r.East(cfg);
35647 return new r.West(cfg);
35649 return new r.Center(cfg);
35651 throw 'Layout region "'+target+'" not supported.';
35658 * Ext JS Library 1.1.1
35659 * Copyright(c) 2006-2007, Ext JS, LLC.
35661 * Originally Released Under LGPL - original licence link has changed is not relivant.
35664 * <script type="text/javascript">
35668 * @class Roo.bootstrap.layout.Basic
35669 * @extends Roo.util.Observable
35670 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
35671 * and does not have a titlebar, tabs or any other features. All it does is size and position
35672 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
35673 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35674 * @cfg {string} region the region that it inhabits..
35675 * @cfg {bool} skipConfig skip config?
35679 Roo.bootstrap.layout.Basic = function(config){
35681 this.mgr = config.mgr;
35683 this.position = config.region;
35685 var skipConfig = config.skipConfig;
35689 * @scope Roo.BasicLayoutRegion
35693 * @event beforeremove
35694 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
35695 * @param {Roo.LayoutRegion} this
35696 * @param {Roo.ContentPanel} panel The panel
35697 * @param {Object} e The cancel event object
35699 "beforeremove" : true,
35701 * @event invalidated
35702 * Fires when the layout for this region is changed.
35703 * @param {Roo.LayoutRegion} this
35705 "invalidated" : true,
35707 * @event visibilitychange
35708 * Fires when this region is shown or hidden
35709 * @param {Roo.LayoutRegion} this
35710 * @param {Boolean} visibility true or false
35712 "visibilitychange" : true,
35714 * @event paneladded
35715 * Fires when a panel is added.
35716 * @param {Roo.LayoutRegion} this
35717 * @param {Roo.ContentPanel} panel The panel
35719 "paneladded" : true,
35721 * @event panelremoved
35722 * Fires when a panel is removed.
35723 * @param {Roo.LayoutRegion} this
35724 * @param {Roo.ContentPanel} panel The panel
35726 "panelremoved" : true,
35728 * @event beforecollapse
35729 * Fires when this region before collapse.
35730 * @param {Roo.LayoutRegion} this
35732 "beforecollapse" : true,
35735 * Fires when this region is collapsed.
35736 * @param {Roo.LayoutRegion} this
35738 "collapsed" : true,
35741 * Fires when this region is expanded.
35742 * @param {Roo.LayoutRegion} this
35747 * Fires when this region is slid into view.
35748 * @param {Roo.LayoutRegion} this
35750 "slideshow" : true,
35753 * Fires when this region slides out of view.
35754 * @param {Roo.LayoutRegion} this
35756 "slidehide" : true,
35758 * @event panelactivated
35759 * Fires when a panel is activated.
35760 * @param {Roo.LayoutRegion} this
35761 * @param {Roo.ContentPanel} panel The activated panel
35763 "panelactivated" : true,
35766 * Fires when the user resizes this region.
35767 * @param {Roo.LayoutRegion} this
35768 * @param {Number} newSize The new size (width for east/west, height for north/south)
35772 /** A collection of panels in this region. @type Roo.util.MixedCollection */
35773 this.panels = new Roo.util.MixedCollection();
35774 this.panels.getKey = this.getPanelId.createDelegate(this);
35776 this.activePanel = null;
35777 // ensure listeners are added...
35779 if (config.listeners || config.events) {
35780 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
35781 listeners : config.listeners || {},
35782 events : config.events || {}
35786 if(skipConfig !== true){
35787 this.applyConfig(config);
35791 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
35793 getPanelId : function(p){
35797 applyConfig : function(config){
35798 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35799 this.config = config;
35804 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
35805 * the width, for horizontal (north, south) the height.
35806 * @param {Number} newSize The new width or height
35808 resizeTo : function(newSize){
35809 var el = this.el ? this.el :
35810 (this.activePanel ? this.activePanel.getEl() : null);
35812 switch(this.position){
35815 el.setWidth(newSize);
35816 this.fireEvent("resized", this, newSize);
35820 el.setHeight(newSize);
35821 this.fireEvent("resized", this, newSize);
35827 getBox : function(){
35828 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
35831 getMargins : function(){
35832 return this.margins;
35835 updateBox : function(box){
35837 var el = this.activePanel.getEl();
35838 el.dom.style.left = box.x + "px";
35839 el.dom.style.top = box.y + "px";
35840 this.activePanel.setSize(box.width, box.height);
35844 * Returns the container element for this region.
35845 * @return {Roo.Element}
35847 getEl : function(){
35848 return this.activePanel;
35852 * Returns true if this region is currently visible.
35853 * @return {Boolean}
35855 isVisible : function(){
35856 return this.activePanel ? true : false;
35859 setActivePanel : function(panel){
35860 panel = this.getPanel(panel);
35861 if(this.activePanel && this.activePanel != panel){
35862 this.activePanel.setActiveState(false);
35863 this.activePanel.getEl().setLeftTop(-10000,-10000);
35865 this.activePanel = panel;
35866 panel.setActiveState(true);
35868 panel.setSize(this.box.width, this.box.height);
35870 this.fireEvent("panelactivated", this, panel);
35871 this.fireEvent("invalidated");
35875 * Show the specified panel.
35876 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
35877 * @return {Roo.ContentPanel} The shown panel or null
35879 showPanel : function(panel){
35880 panel = this.getPanel(panel);
35882 this.setActivePanel(panel);
35888 * Get the active panel for this region.
35889 * @return {Roo.ContentPanel} The active panel or null
35891 getActivePanel : function(){
35892 return this.activePanel;
35896 * Add the passed ContentPanel(s)
35897 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35898 * @return {Roo.ContentPanel} The panel added (if only one was added)
35900 add : function(panel){
35901 if(arguments.length > 1){
35902 for(var i = 0, len = arguments.length; i < len; i++) {
35903 this.add(arguments[i]);
35907 if(this.hasPanel(panel)){
35908 this.showPanel(panel);
35911 var el = panel.getEl();
35912 if(el.dom.parentNode != this.mgr.el.dom){
35913 this.mgr.el.dom.appendChild(el.dom);
35915 if(panel.setRegion){
35916 panel.setRegion(this);
35918 this.panels.add(panel);
35919 el.setStyle("position", "absolute");
35920 if(!panel.background){
35921 this.setActivePanel(panel);
35922 if(this.config.initialSize && this.panels.getCount()==1){
35923 this.resizeTo(this.config.initialSize);
35926 this.fireEvent("paneladded", this, panel);
35931 * Returns true if the panel is in this region.
35932 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35933 * @return {Boolean}
35935 hasPanel : function(panel){
35936 if(typeof panel == "object"){ // must be panel obj
35937 panel = panel.getId();
35939 return this.getPanel(panel) ? true : false;
35943 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35944 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35945 * @param {Boolean} preservePanel Overrides the config preservePanel option
35946 * @return {Roo.ContentPanel} The panel that was removed
35948 remove : function(panel, preservePanel){
35949 panel = this.getPanel(panel);
35954 this.fireEvent("beforeremove", this, panel, e);
35955 if(e.cancel === true){
35958 var panelId = panel.getId();
35959 this.panels.removeKey(panelId);
35964 * Returns the panel specified or null if it's not in this region.
35965 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35966 * @return {Roo.ContentPanel}
35968 getPanel : function(id){
35969 if(typeof id == "object"){ // must be panel obj
35972 return this.panels.get(id);
35976 * Returns this regions position (north/south/east/west/center).
35979 getPosition: function(){
35980 return this.position;
35984 * Ext JS Library 1.1.1
35985 * Copyright(c) 2006-2007, Ext JS, LLC.
35987 * Originally Released Under LGPL - original licence link has changed is not relivant.
35990 * <script type="text/javascript">
35994 * @class Roo.bootstrap.layout.Region
35995 * @extends Roo.bootstrap.layout.Basic
35996 * This class represents a region in a layout manager.
35998 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
35999 * @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})
36000 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
36001 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
36002 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
36003 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
36004 * @cfg {String} title The title for the region (overrides panel titles)
36005 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
36006 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
36007 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
36008 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
36009 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
36010 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
36011 * the space available, similar to FireFox 1.5 tabs (defaults to false)
36012 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
36013 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
36014 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
36016 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
36017 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
36018 * @cfg {Boolean} disableTabTips True to disable tab tooltips
36019 * @cfg {Number} width For East/West panels
36020 * @cfg {Number} height For North/South panels
36021 * @cfg {Boolean} split To show the splitter
36022 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
36024 * @cfg {string} cls Extra CSS classes to add to region
36026 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
36027 * @cfg {string} region the region that it inhabits..
36030 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
36031 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
36033 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
36034 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
36035 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
36037 Roo.bootstrap.layout.Region = function(config)
36039 this.applyConfig(config);
36041 var mgr = config.mgr;
36042 var pos = config.region;
36043 config.skipConfig = true;
36044 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
36047 this.onRender(mgr.el);
36050 this.visible = true;
36051 this.collapsed = false;
36052 this.unrendered_panels = [];
36055 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
36057 position: '', // set by wrapper (eg. north/south etc..)
36058 unrendered_panels : null, // unrendered panels.
36060 tabPosition : false,
36062 mgr: false, // points to 'Border'
36065 createBody : function(){
36066 /** This region's body element
36067 * @type Roo.Element */
36068 this.bodyEl = this.el.createChild({
36070 cls: "roo-layout-panel-body tab-content" // bootstrap added...
36074 onRender: function(ctr, pos)
36076 var dh = Roo.DomHelper;
36077 /** This region's container element
36078 * @type Roo.Element */
36079 this.el = dh.append(ctr.dom, {
36081 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
36083 /** This region's title element
36084 * @type Roo.Element */
36086 this.titleEl = dh.append(this.el.dom, {
36088 unselectable: "on",
36089 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
36091 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
36092 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
36096 this.titleEl.enableDisplayMode();
36097 /** This region's title text element
36098 * @type HTMLElement */
36099 this.titleTextEl = this.titleEl.dom.firstChild;
36100 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
36102 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
36103 this.closeBtn.enableDisplayMode();
36104 this.closeBtn.on("click", this.closeClicked, this);
36105 this.closeBtn.hide();
36107 this.createBody(this.config);
36108 if(this.config.hideWhenEmpty){
36110 this.on("paneladded", this.validateVisibility, this);
36111 this.on("panelremoved", this.validateVisibility, this);
36113 if(this.autoScroll){
36114 this.bodyEl.setStyle("overflow", "auto");
36116 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
36118 //if(c.titlebar !== false){
36119 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
36120 this.titleEl.hide();
36122 this.titleEl.show();
36123 if(this.config.title){
36124 this.titleTextEl.innerHTML = this.config.title;
36128 if(this.config.collapsed){
36129 this.collapse(true);
36131 if(this.config.hidden){
36135 if (this.unrendered_panels && this.unrendered_panels.length) {
36136 for (var i =0;i< this.unrendered_panels.length; i++) {
36137 this.add(this.unrendered_panels[i]);
36139 this.unrendered_panels = null;
36145 applyConfig : function(c)
36148 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
36149 var dh = Roo.DomHelper;
36150 if(c.titlebar !== false){
36151 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
36152 this.collapseBtn.on("click", this.collapse, this);
36153 this.collapseBtn.enableDisplayMode();
36155 if(c.showPin === true || this.showPin){
36156 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
36157 this.stickBtn.enableDisplayMode();
36158 this.stickBtn.on("click", this.expand, this);
36159 this.stickBtn.hide();
36164 /** This region's collapsed element
36165 * @type Roo.Element */
36168 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
36169 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
36172 if(c.floatable !== false){
36173 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
36174 this.collapsedEl.on("click", this.collapseClick, this);
36177 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
36178 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
36179 id: "message", unselectable: "on", style:{"float":"left"}});
36180 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
36182 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
36183 this.expandBtn.on("click", this.expand, this);
36187 if(this.collapseBtn){
36188 this.collapseBtn.setVisible(c.collapsible == true);
36191 this.cmargins = c.cmargins || this.cmargins ||
36192 (this.position == "west" || this.position == "east" ?
36193 {top: 0, left: 2, right:2, bottom: 0} :
36194 {top: 2, left: 0, right:0, bottom: 2});
36196 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
36199 this.tabPosition = [ 'top','bottom', 'west'].indexOf(c.tabPosition) > -1 ? c.tabPosition : "top";
36201 this.autoScroll = c.autoScroll || false;
36206 this.duration = c.duration || .30;
36207 this.slideDuration = c.slideDuration || .45;
36212 * Returns true if this region is currently visible.
36213 * @return {Boolean}
36215 isVisible : function(){
36216 return this.visible;
36220 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
36221 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
36223 //setCollapsedTitle : function(title){
36224 // title = title || " ";
36225 // if(this.collapsedTitleTextEl){
36226 // this.collapsedTitleTextEl.innerHTML = title;
36230 getBox : function(){
36232 // if(!this.collapsed){
36233 b = this.el.getBox(false, true);
36235 // b = this.collapsedEl.getBox(false, true);
36240 getMargins : function(){
36241 return this.margins;
36242 //return this.collapsed ? this.cmargins : this.margins;
36245 highlight : function(){
36246 this.el.addClass("x-layout-panel-dragover");
36249 unhighlight : function(){
36250 this.el.removeClass("x-layout-panel-dragover");
36253 updateBox : function(box)
36255 if (!this.bodyEl) {
36256 return; // not rendered yet..
36260 if(!this.collapsed){
36261 this.el.dom.style.left = box.x + "px";
36262 this.el.dom.style.top = box.y + "px";
36263 this.updateBody(box.width, box.height);
36265 this.collapsedEl.dom.style.left = box.x + "px";
36266 this.collapsedEl.dom.style.top = box.y + "px";
36267 this.collapsedEl.setSize(box.width, box.height);
36270 this.tabs.autoSizeTabs();
36274 updateBody : function(w, h)
36277 this.el.setWidth(w);
36278 w -= this.el.getBorderWidth("rl");
36279 if(this.config.adjustments){
36280 w += this.config.adjustments[0];
36283 if(h !== null && h > 0){
36284 this.el.setHeight(h);
36285 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
36286 h -= this.el.getBorderWidth("tb");
36287 if(this.config.adjustments){
36288 h += this.config.adjustments[1];
36290 this.bodyEl.setHeight(h);
36292 h = this.tabs.syncHeight(h);
36295 if(this.panelSize){
36296 w = w !== null ? w : this.panelSize.width;
36297 h = h !== null ? h : this.panelSize.height;
36299 if(this.activePanel){
36300 var el = this.activePanel.getEl();
36301 w = w !== null ? w : el.getWidth();
36302 h = h !== null ? h : el.getHeight();
36303 this.panelSize = {width: w, height: h};
36304 this.activePanel.setSize(w, h);
36306 if(Roo.isIE && this.tabs){
36307 this.tabs.el.repaint();
36312 * Returns the container element for this region.
36313 * @return {Roo.Element}
36315 getEl : function(){
36320 * Hides this region.
36323 //if(!this.collapsed){
36324 this.el.dom.style.left = "-2000px";
36327 // this.collapsedEl.dom.style.left = "-2000px";
36328 // this.collapsedEl.hide();
36330 this.visible = false;
36331 this.fireEvent("visibilitychange", this, false);
36335 * Shows this region if it was previously hidden.
36338 //if(!this.collapsed){
36341 // this.collapsedEl.show();
36343 this.visible = true;
36344 this.fireEvent("visibilitychange", this, true);
36347 closeClicked : function(){
36348 if(this.activePanel){
36349 this.remove(this.activePanel);
36353 collapseClick : function(e){
36355 e.stopPropagation();
36358 e.stopPropagation();
36364 * Collapses this region.
36365 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
36368 collapse : function(skipAnim, skipCheck = false){
36369 if(this.collapsed) {
36373 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
36375 this.collapsed = true;
36377 this.split.el.hide();
36379 if(this.config.animate && skipAnim !== true){
36380 this.fireEvent("invalidated", this);
36381 this.animateCollapse();
36383 this.el.setLocation(-20000,-20000);
36385 this.collapsedEl.show();
36386 this.fireEvent("collapsed", this);
36387 this.fireEvent("invalidated", this);
36393 animateCollapse : function(){
36398 * Expands this region if it was previously collapsed.
36399 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
36400 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
36403 expand : function(e, skipAnim){
36405 e.stopPropagation();
36407 if(!this.collapsed || this.el.hasActiveFx()) {
36411 this.afterSlideIn();
36414 this.collapsed = false;
36415 if(this.config.animate && skipAnim !== true){
36416 this.animateExpand();
36420 this.split.el.show();
36422 this.collapsedEl.setLocation(-2000,-2000);
36423 this.collapsedEl.hide();
36424 this.fireEvent("invalidated", this);
36425 this.fireEvent("expanded", this);
36429 animateExpand : function(){
36433 initTabs : function()
36435 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
36437 var ts = new Roo.bootstrap.panel.Tabs({
36438 el: this.bodyEl.dom,
36440 tabPosition: this.tabPosition ? this.tabPosition : 'top',
36441 disableTooltips: this.config.disableTabTips,
36442 toolbar : this.config.toolbar
36445 if(this.config.hideTabs){
36446 ts.stripWrap.setDisplayed(false);
36449 ts.resizeTabs = this.config.resizeTabs === true;
36450 ts.minTabWidth = this.config.minTabWidth || 40;
36451 ts.maxTabWidth = this.config.maxTabWidth || 250;
36452 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
36453 ts.monitorResize = false;
36454 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
36455 ts.bodyEl.addClass('roo-layout-tabs-body');
36456 this.panels.each(this.initPanelAsTab, this);
36459 initPanelAsTab : function(panel){
36460 var ti = this.tabs.addTab(
36464 this.config.closeOnTab && panel.isClosable(),
36467 if(panel.tabTip !== undefined){
36468 ti.setTooltip(panel.tabTip);
36470 ti.on("activate", function(){
36471 this.setActivePanel(panel);
36474 if(this.config.closeOnTab){
36475 ti.on("beforeclose", function(t, e){
36477 this.remove(panel);
36481 panel.tabItem = ti;
36486 updatePanelTitle : function(panel, title)
36488 if(this.activePanel == panel){
36489 this.updateTitle(title);
36492 var ti = this.tabs.getTab(panel.getEl().id);
36494 if(panel.tabTip !== undefined){
36495 ti.setTooltip(panel.tabTip);
36500 updateTitle : function(title){
36501 if(this.titleTextEl && !this.config.title){
36502 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
36506 setActivePanel : function(panel)
36508 panel = this.getPanel(panel);
36509 if(this.activePanel && this.activePanel != panel){
36510 if(this.activePanel.setActiveState(false) === false){
36514 this.activePanel = panel;
36515 panel.setActiveState(true);
36516 if(this.panelSize){
36517 panel.setSize(this.panelSize.width, this.panelSize.height);
36520 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
36522 this.updateTitle(panel.getTitle());
36524 this.fireEvent("invalidated", this);
36526 this.fireEvent("panelactivated", this, panel);
36530 * Shows the specified panel.
36531 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
36532 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
36534 showPanel : function(panel)
36536 panel = this.getPanel(panel);
36539 var tab = this.tabs.getTab(panel.getEl().id);
36540 if(tab.isHidden()){
36541 this.tabs.unhideTab(tab.id);
36545 this.setActivePanel(panel);
36552 * Get the active panel for this region.
36553 * @return {Roo.ContentPanel} The active panel or null
36555 getActivePanel : function(){
36556 return this.activePanel;
36559 validateVisibility : function(){
36560 if(this.panels.getCount() < 1){
36561 this.updateTitle(" ");
36562 this.closeBtn.hide();
36565 if(!this.isVisible()){
36572 * Adds the passed ContentPanel(s) to this region.
36573 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
36574 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
36576 add : function(panel)
36578 if(arguments.length > 1){
36579 for(var i = 0, len = arguments.length; i < len; i++) {
36580 this.add(arguments[i]);
36585 // if we have not been rendered yet, then we can not really do much of this..
36586 if (!this.bodyEl) {
36587 this.unrendered_panels.push(panel);
36594 if(this.hasPanel(panel)){
36595 this.showPanel(panel);
36598 panel.setRegion(this);
36599 this.panels.add(panel);
36600 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
36601 // sinle panel - no tab...?? would it not be better to render it with the tabs,
36602 // and hide them... ???
36603 this.bodyEl.dom.appendChild(panel.getEl().dom);
36604 if(panel.background !== true){
36605 this.setActivePanel(panel);
36607 this.fireEvent("paneladded", this, panel);
36614 this.initPanelAsTab(panel);
36618 if(panel.background !== true){
36619 this.tabs.activate(panel.getEl().id);
36621 this.fireEvent("paneladded", this, panel);
36626 * Hides the tab for the specified panel.
36627 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36629 hidePanel : function(panel){
36630 if(this.tabs && (panel = this.getPanel(panel))){
36631 this.tabs.hideTab(panel.getEl().id);
36636 * Unhides the tab for a previously hidden panel.
36637 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36639 unhidePanel : function(panel){
36640 if(this.tabs && (panel = this.getPanel(panel))){
36641 this.tabs.unhideTab(panel.getEl().id);
36645 clearPanels : function(){
36646 while(this.panels.getCount() > 0){
36647 this.remove(this.panels.first());
36652 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
36653 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36654 * @param {Boolean} preservePanel Overrides the config preservePanel option
36655 * @return {Roo.ContentPanel} The panel that was removed
36657 remove : function(panel, preservePanel)
36659 panel = this.getPanel(panel);
36664 this.fireEvent("beforeremove", this, panel, e);
36665 if(e.cancel === true){
36668 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
36669 var panelId = panel.getId();
36670 this.panels.removeKey(panelId);
36672 document.body.appendChild(panel.getEl().dom);
36675 this.tabs.removeTab(panel.getEl().id);
36676 }else if (!preservePanel){
36677 this.bodyEl.dom.removeChild(panel.getEl().dom);
36679 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
36680 var p = this.panels.first();
36681 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
36682 tempEl.appendChild(p.getEl().dom);
36683 this.bodyEl.update("");
36684 this.bodyEl.dom.appendChild(p.getEl().dom);
36686 this.updateTitle(p.getTitle());
36688 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
36689 this.setActivePanel(p);
36691 panel.setRegion(null);
36692 if(this.activePanel == panel){
36693 this.activePanel = null;
36695 if(this.config.autoDestroy !== false && preservePanel !== true){
36696 try{panel.destroy();}catch(e){}
36698 this.fireEvent("panelremoved", this, panel);
36703 * Returns the TabPanel component used by this region
36704 * @return {Roo.TabPanel}
36706 getTabs : function(){
36710 createTool : function(parentEl, className){
36711 var btn = Roo.DomHelper.append(parentEl, {
36713 cls: "x-layout-tools-button",
36716 cls: "roo-layout-tools-button-inner " + className,
36720 btn.addClassOnOver("roo-layout-tools-button-over");
36725 * Ext JS Library 1.1.1
36726 * Copyright(c) 2006-2007, Ext JS, LLC.
36728 * Originally Released Under LGPL - original licence link has changed is not relivant.
36731 * <script type="text/javascript">
36737 * @class Roo.SplitLayoutRegion
36738 * @extends Roo.LayoutRegion
36739 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
36741 Roo.bootstrap.layout.Split = function(config){
36742 this.cursor = config.cursor;
36743 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
36746 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
36748 splitTip : "Drag to resize.",
36749 collapsibleSplitTip : "Drag to resize. Double click to hide.",
36750 useSplitTips : false,
36752 applyConfig : function(config){
36753 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
36756 onRender : function(ctr,pos) {
36758 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
36759 if(!this.config.split){
36764 var splitEl = Roo.DomHelper.append(ctr.dom, {
36766 id: this.el.id + "-split",
36767 cls: "roo-layout-split roo-layout-split-"+this.position,
36770 /** The SplitBar for this region
36771 * @type Roo.SplitBar */
36772 // does not exist yet...
36773 Roo.log([this.position, this.orientation]);
36775 this.split = new Roo.bootstrap.SplitBar({
36776 dragElement : splitEl,
36777 resizingElement: this.el,
36778 orientation : this.orientation
36781 this.split.on("moved", this.onSplitMove, this);
36782 this.split.useShim = this.config.useShim === true;
36783 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
36784 if(this.useSplitTips){
36785 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
36787 //if(config.collapsible){
36788 // this.split.el.on("dblclick", this.collapse, this);
36791 if(typeof this.config.minSize != "undefined"){
36792 this.split.minSize = this.config.minSize;
36794 if(typeof this.config.maxSize != "undefined"){
36795 this.split.maxSize = this.config.maxSize;
36797 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
36798 this.hideSplitter();
36803 getHMaxSize : function(){
36804 var cmax = this.config.maxSize || 10000;
36805 var center = this.mgr.getRegion("center");
36806 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
36809 getVMaxSize : function(){
36810 var cmax = this.config.maxSize || 10000;
36811 var center = this.mgr.getRegion("center");
36812 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
36815 onSplitMove : function(split, newSize){
36816 this.fireEvent("resized", this, newSize);
36820 * Returns the {@link Roo.SplitBar} for this region.
36821 * @return {Roo.SplitBar}
36823 getSplitBar : function(){
36828 this.hideSplitter();
36829 Roo.bootstrap.layout.Split.superclass.hide.call(this);
36832 hideSplitter : function(){
36834 this.split.el.setLocation(-2000,-2000);
36835 this.split.el.hide();
36841 this.split.el.show();
36843 Roo.bootstrap.layout.Split.superclass.show.call(this);
36846 beforeSlide: function(){
36847 if(Roo.isGecko){// firefox overflow auto bug workaround
36848 this.bodyEl.clip();
36850 this.tabs.bodyEl.clip();
36852 if(this.activePanel){
36853 this.activePanel.getEl().clip();
36855 if(this.activePanel.beforeSlide){
36856 this.activePanel.beforeSlide();
36862 afterSlide : function(){
36863 if(Roo.isGecko){// firefox overflow auto bug workaround
36864 this.bodyEl.unclip();
36866 this.tabs.bodyEl.unclip();
36868 if(this.activePanel){
36869 this.activePanel.getEl().unclip();
36870 if(this.activePanel.afterSlide){
36871 this.activePanel.afterSlide();
36877 initAutoHide : function(){
36878 if(this.autoHide !== false){
36879 if(!this.autoHideHd){
36880 var st = new Roo.util.DelayedTask(this.slideIn, this);
36881 this.autoHideHd = {
36882 "mouseout": function(e){
36883 if(!e.within(this.el, true)){
36887 "mouseover" : function(e){
36893 this.el.on(this.autoHideHd);
36897 clearAutoHide : function(){
36898 if(this.autoHide !== false){
36899 this.el.un("mouseout", this.autoHideHd.mouseout);
36900 this.el.un("mouseover", this.autoHideHd.mouseover);
36904 clearMonitor : function(){
36905 Roo.get(document).un("click", this.slideInIf, this);
36908 // these names are backwards but not changed for compat
36909 slideOut : function(){
36910 if(this.isSlid || this.el.hasActiveFx()){
36913 this.isSlid = true;
36914 if(this.collapseBtn){
36915 this.collapseBtn.hide();
36917 this.closeBtnState = this.closeBtn.getStyle('display');
36918 this.closeBtn.hide();
36920 this.stickBtn.show();
36923 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
36924 this.beforeSlide();
36925 this.el.setStyle("z-index", 10001);
36926 this.el.slideIn(this.getSlideAnchor(), {
36927 callback: function(){
36929 this.initAutoHide();
36930 Roo.get(document).on("click", this.slideInIf, this);
36931 this.fireEvent("slideshow", this);
36938 afterSlideIn : function(){
36939 this.clearAutoHide();
36940 this.isSlid = false;
36941 this.clearMonitor();
36942 this.el.setStyle("z-index", "");
36943 if(this.collapseBtn){
36944 this.collapseBtn.show();
36946 this.closeBtn.setStyle('display', this.closeBtnState);
36948 this.stickBtn.hide();
36950 this.fireEvent("slidehide", this);
36953 slideIn : function(cb){
36954 if(!this.isSlid || this.el.hasActiveFx()){
36958 this.isSlid = false;
36959 this.beforeSlide();
36960 this.el.slideOut(this.getSlideAnchor(), {
36961 callback: function(){
36962 this.el.setLeftTop(-10000, -10000);
36964 this.afterSlideIn();
36972 slideInIf : function(e){
36973 if(!e.within(this.el)){
36978 animateCollapse : function(){
36979 this.beforeSlide();
36980 this.el.setStyle("z-index", 20000);
36981 var anchor = this.getSlideAnchor();
36982 this.el.slideOut(anchor, {
36983 callback : function(){
36984 this.el.setStyle("z-index", "");
36985 this.collapsedEl.slideIn(anchor, {duration:.3});
36987 this.el.setLocation(-10000,-10000);
36989 this.fireEvent("collapsed", this);
36996 animateExpand : function(){
36997 this.beforeSlide();
36998 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
36999 this.el.setStyle("z-index", 20000);
37000 this.collapsedEl.hide({
37003 this.el.slideIn(this.getSlideAnchor(), {
37004 callback : function(){
37005 this.el.setStyle("z-index", "");
37008 this.split.el.show();
37010 this.fireEvent("invalidated", this);
37011 this.fireEvent("expanded", this);
37039 getAnchor : function(){
37040 return this.anchors[this.position];
37043 getCollapseAnchor : function(){
37044 return this.canchors[this.position];
37047 getSlideAnchor : function(){
37048 return this.sanchors[this.position];
37051 getAlignAdj : function(){
37052 var cm = this.cmargins;
37053 switch(this.position){
37069 getExpandAdj : function(){
37070 var c = this.collapsedEl, cm = this.cmargins;
37071 switch(this.position){
37073 return [-(cm.right+c.getWidth()+cm.left), 0];
37076 return [cm.right+c.getWidth()+cm.left, 0];
37079 return [0, -(cm.top+cm.bottom+c.getHeight())];
37082 return [0, cm.top+cm.bottom+c.getHeight()];
37088 * Ext JS Library 1.1.1
37089 * Copyright(c) 2006-2007, Ext JS, LLC.
37091 * Originally Released Under LGPL - original licence link has changed is not relivant.
37094 * <script type="text/javascript">
37097 * These classes are private internal classes
37099 Roo.bootstrap.layout.Center = function(config){
37100 config.region = "center";
37101 Roo.bootstrap.layout.Region.call(this, config);
37102 this.visible = true;
37103 this.minWidth = config.minWidth || 20;
37104 this.minHeight = config.minHeight || 20;
37107 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
37109 // center panel can't be hidden
37113 // center panel can't be hidden
37116 getMinWidth: function(){
37117 return this.minWidth;
37120 getMinHeight: function(){
37121 return this.minHeight;
37135 Roo.bootstrap.layout.North = function(config)
37137 config.region = 'north';
37138 config.cursor = 'n-resize';
37140 Roo.bootstrap.layout.Split.call(this, config);
37144 this.split.placement = Roo.bootstrap.SplitBar.TOP;
37145 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
37146 this.split.el.addClass("roo-layout-split-v");
37148 var size = config.initialSize || config.height;
37149 if(typeof size != "undefined"){
37150 this.el.setHeight(size);
37153 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
37155 orientation: Roo.bootstrap.SplitBar.VERTICAL,
37159 getBox : function(){
37160 if(this.collapsed){
37161 return this.collapsedEl.getBox();
37163 var box = this.el.getBox();
37165 box.height += this.split.el.getHeight();
37170 updateBox : function(box){
37171 if(this.split && !this.collapsed){
37172 box.height -= this.split.el.getHeight();
37173 this.split.el.setLeft(box.x);
37174 this.split.el.setTop(box.y+box.height);
37175 this.split.el.setWidth(box.width);
37177 if(this.collapsed){
37178 this.updateBody(box.width, null);
37180 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37188 Roo.bootstrap.layout.South = function(config){
37189 config.region = 'south';
37190 config.cursor = 's-resize';
37191 Roo.bootstrap.layout.Split.call(this, config);
37193 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
37194 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
37195 this.split.el.addClass("roo-layout-split-v");
37197 var size = config.initialSize || config.height;
37198 if(typeof size != "undefined"){
37199 this.el.setHeight(size);
37203 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
37204 orientation: Roo.bootstrap.SplitBar.VERTICAL,
37205 getBox : function(){
37206 if(this.collapsed){
37207 return this.collapsedEl.getBox();
37209 var box = this.el.getBox();
37211 var sh = this.split.el.getHeight();
37218 updateBox : function(box){
37219 if(this.split && !this.collapsed){
37220 var sh = this.split.el.getHeight();
37223 this.split.el.setLeft(box.x);
37224 this.split.el.setTop(box.y-sh);
37225 this.split.el.setWidth(box.width);
37227 if(this.collapsed){
37228 this.updateBody(box.width, null);
37230 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37234 Roo.bootstrap.layout.East = function(config){
37235 config.region = "east";
37236 config.cursor = "e-resize";
37237 Roo.bootstrap.layout.Split.call(this, config);
37239 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
37240 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
37241 this.split.el.addClass("roo-layout-split-h");
37243 var size = config.initialSize || config.width;
37244 if(typeof size != "undefined"){
37245 this.el.setWidth(size);
37248 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
37249 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
37250 getBox : function(){
37251 if(this.collapsed){
37252 return this.collapsedEl.getBox();
37254 var box = this.el.getBox();
37256 var sw = this.split.el.getWidth();
37263 updateBox : function(box){
37264 if(this.split && !this.collapsed){
37265 var sw = this.split.el.getWidth();
37267 this.split.el.setLeft(box.x);
37268 this.split.el.setTop(box.y);
37269 this.split.el.setHeight(box.height);
37272 if(this.collapsed){
37273 this.updateBody(null, box.height);
37275 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37279 Roo.bootstrap.layout.West = function(config){
37280 config.region = "west";
37281 config.cursor = "w-resize";
37283 Roo.bootstrap.layout.Split.call(this, config);
37285 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
37286 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
37287 this.split.el.addClass("roo-layout-split-h");
37291 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
37292 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
37294 onRender: function(ctr, pos)
37296 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
37297 var size = this.config.initialSize || this.config.width;
37298 if(typeof size != "undefined"){
37299 this.el.setWidth(size);
37303 getBox : function(){
37304 if(this.collapsed){
37305 return this.collapsedEl.getBox();
37307 var box = this.el.getBox();
37309 box.width += this.split.el.getWidth();
37314 updateBox : function(box){
37315 if(this.split && !this.collapsed){
37316 var sw = this.split.el.getWidth();
37318 this.split.el.setLeft(box.x+box.width);
37319 this.split.el.setTop(box.y);
37320 this.split.el.setHeight(box.height);
37322 if(this.collapsed){
37323 this.updateBody(null, box.height);
37325 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37327 });Roo.namespace("Roo.bootstrap.panel");/*
37329 * Ext JS Library 1.1.1
37330 * Copyright(c) 2006-2007, Ext JS, LLC.
37332 * Originally Released Under LGPL - original licence link has changed is not relivant.
37335 * <script type="text/javascript">
37338 * @class Roo.ContentPanel
37339 * @extends Roo.util.Observable
37340 * A basic ContentPanel element.
37341 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
37342 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
37343 * @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
37344 * @cfg {Boolean} closable True if the panel can be closed/removed
37345 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
37346 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
37347 * @cfg {Toolbar} toolbar A toolbar for this panel
37348 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
37349 * @cfg {String} title The title for this panel
37350 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
37351 * @cfg {String} url Calls {@link #setUrl} with this value
37352 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
37353 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
37354 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
37355 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
37356 * @cfg {Boolean} badges render the badges
37359 * Create a new ContentPanel.
37360 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
37361 * @param {String/Object} config A string to set only the title or a config object
37362 * @param {String} content (optional) Set the HTML content for this panel
37363 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
37365 Roo.bootstrap.panel.Content = function( config){
37367 this.tpl = config.tpl || false;
37369 var el = config.el;
37370 var content = config.content;
37372 if(config.autoCreate){ // xtype is available if this is called from factory
37375 this.el = Roo.get(el);
37376 if(!this.el && config && config.autoCreate){
37377 if(typeof config.autoCreate == "object"){
37378 if(!config.autoCreate.id){
37379 config.autoCreate.id = config.id||el;
37381 this.el = Roo.DomHelper.append(document.body,
37382 config.autoCreate, true);
37384 var elcfg = { tag: "div",
37385 cls: "roo-layout-inactive-content",
37389 elcfg.html = config.html;
37393 this.el = Roo.DomHelper.append(document.body, elcfg , true);
37396 this.closable = false;
37397 this.loaded = false;
37398 this.active = false;
37401 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
37403 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
37405 this.wrapEl = this.el; //this.el.wrap();
37407 if (config.toolbar.items) {
37408 ti = config.toolbar.items ;
37409 delete config.toolbar.items ;
37413 this.toolbar.render(this.wrapEl, 'before');
37414 for(var i =0;i < ti.length;i++) {
37415 // Roo.log(['add child', items[i]]);
37416 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37418 this.toolbar.items = nitems;
37419 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
37420 delete config.toolbar;
37424 // xtype created footer. - not sure if will work as we normally have to render first..
37425 if (this.footer && !this.footer.el && this.footer.xtype) {
37426 if (!this.wrapEl) {
37427 this.wrapEl = this.el.wrap();
37430 this.footer.container = this.wrapEl.createChild();
37432 this.footer = Roo.factory(this.footer, Roo);
37437 if(typeof config == "string"){
37438 this.title = config;
37440 Roo.apply(this, config);
37444 this.resizeEl = Roo.get(this.resizeEl, true);
37446 this.resizeEl = this.el;
37448 // handle view.xtype
37456 * Fires when this panel is activated.
37457 * @param {Roo.ContentPanel} this
37461 * @event deactivate
37462 * Fires when this panel is activated.
37463 * @param {Roo.ContentPanel} this
37465 "deactivate" : true,
37469 * Fires when this panel is resized if fitToFrame is true.
37470 * @param {Roo.ContentPanel} this
37471 * @param {Number} width The width after any component adjustments
37472 * @param {Number} height The height after any component adjustments
37478 * Fires when this tab is created
37479 * @param {Roo.ContentPanel} this
37490 if(this.autoScroll){
37491 this.resizeEl.setStyle("overflow", "auto");
37493 // fix randome scrolling
37494 //this.el.on('scroll', function() {
37495 // Roo.log('fix random scolling');
37496 // this.scrollTo('top',0);
37499 content = content || this.content;
37501 this.setContent(content);
37503 if(config && config.url){
37504 this.setUrl(this.url, this.params, this.loadOnce);
37509 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
37511 if (this.view && typeof(this.view.xtype) != 'undefined') {
37512 this.view.el = this.el.appendChild(document.createElement("div"));
37513 this.view = Roo.factory(this.view);
37514 this.view.render && this.view.render(false, '');
37518 this.fireEvent('render', this);
37521 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
37525 setRegion : function(region){
37526 this.region = region;
37527 this.setActiveClass(region && !this.background);
37531 setActiveClass: function(state)
37534 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
37535 this.el.setStyle('position','relative');
37537 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
37538 this.el.setStyle('position', 'absolute');
37543 * Returns the toolbar for this Panel if one was configured.
37544 * @return {Roo.Toolbar}
37546 getToolbar : function(){
37547 return this.toolbar;
37550 setActiveState : function(active)
37552 this.active = active;
37553 this.setActiveClass(active);
37555 if(this.fireEvent("deactivate", this) === false){
37560 this.fireEvent("activate", this);
37564 * Updates this panel's element
37565 * @param {String} content The new content
37566 * @param {Boolean} loadScripts (optional) true to look for and process scripts
37568 setContent : function(content, loadScripts){
37569 this.el.update(content, loadScripts);
37572 ignoreResize : function(w, h){
37573 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
37576 this.lastSize = {width: w, height: h};
37581 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
37582 * @return {Roo.UpdateManager} The UpdateManager
37584 getUpdateManager : function(){
37585 return this.el.getUpdateManager();
37588 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
37589 * @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:
37592 url: "your-url.php",
37593 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
37594 callback: yourFunction,
37595 scope: yourObject, //(optional scope)
37598 text: "Loading...",
37603 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
37604 * 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.
37605 * @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}
37606 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
37607 * @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.
37608 * @return {Roo.ContentPanel} this
37611 var um = this.el.getUpdateManager();
37612 um.update.apply(um, arguments);
37618 * 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.
37619 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
37620 * @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)
37621 * @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)
37622 * @return {Roo.UpdateManager} The UpdateManager
37624 setUrl : function(url, params, loadOnce){
37625 if(this.refreshDelegate){
37626 this.removeListener("activate", this.refreshDelegate);
37628 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
37629 this.on("activate", this.refreshDelegate);
37630 return this.el.getUpdateManager();
37633 _handleRefresh : function(url, params, loadOnce){
37634 if(!loadOnce || !this.loaded){
37635 var updater = this.el.getUpdateManager();
37636 updater.update(url, params, this._setLoaded.createDelegate(this));
37640 _setLoaded : function(){
37641 this.loaded = true;
37645 * Returns this panel's id
37648 getId : function(){
37653 * Returns this panel's element - used by regiosn to add.
37654 * @return {Roo.Element}
37656 getEl : function(){
37657 return this.wrapEl || this.el;
37662 adjustForComponents : function(width, height)
37664 //Roo.log('adjustForComponents ');
37665 if(this.resizeEl != this.el){
37666 width -= this.el.getFrameWidth('lr');
37667 height -= this.el.getFrameWidth('tb');
37670 var te = this.toolbar.getEl();
37671 te.setWidth(width);
37672 height -= te.getHeight();
37675 var te = this.footer.getEl();
37676 te.setWidth(width);
37677 height -= te.getHeight();
37681 if(this.adjustments){
37682 width += this.adjustments[0];
37683 height += this.adjustments[1];
37685 return {"width": width, "height": height};
37688 setSize : function(width, height){
37689 if(this.fitToFrame && !this.ignoreResize(width, height)){
37690 if(this.fitContainer && this.resizeEl != this.el){
37691 this.el.setSize(width, height);
37693 var size = this.adjustForComponents(width, height);
37694 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
37695 this.fireEvent('resize', this, size.width, size.height);
37700 * Returns this panel's title
37703 getTitle : function(){
37705 if (typeof(this.title) != 'object') {
37710 for (var k in this.title) {
37711 if (!this.title.hasOwnProperty(k)) {
37715 if (k.indexOf('-') >= 0) {
37716 var s = k.split('-');
37717 for (var i = 0; i<s.length; i++) {
37718 t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
37721 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
37728 * Set this panel's title
37729 * @param {String} title
37731 setTitle : function(title){
37732 this.title = title;
37734 this.region.updatePanelTitle(this, title);
37739 * Returns true is this panel was configured to be closable
37740 * @return {Boolean}
37742 isClosable : function(){
37743 return this.closable;
37746 beforeSlide : function(){
37748 this.resizeEl.clip();
37751 afterSlide : function(){
37753 this.resizeEl.unclip();
37757 * Force a content refresh from the URL specified in the {@link #setUrl} method.
37758 * Will fail silently if the {@link #setUrl} method has not been called.
37759 * This does not activate the panel, just updates its content.
37761 refresh : function(){
37762 if(this.refreshDelegate){
37763 this.loaded = false;
37764 this.refreshDelegate();
37769 * Destroys this panel
37771 destroy : function(){
37772 this.el.removeAllListeners();
37773 var tempEl = document.createElement("span");
37774 tempEl.appendChild(this.el.dom);
37775 tempEl.innerHTML = "";
37781 * form - if the content panel contains a form - this is a reference to it.
37782 * @type {Roo.form.Form}
37786 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
37787 * This contains a reference to it.
37793 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
37803 * @param {Object} cfg Xtype definition of item to add.
37807 getChildContainer: function () {
37808 return this.getEl();
37813 var ret = new Roo.factory(cfg);
37818 if (cfg.xtype.match(/^Form$/)) {
37821 //if (this.footer) {
37822 // el = this.footer.container.insertSibling(false, 'before');
37824 el = this.el.createChild();
37827 this.form = new Roo.form.Form(cfg);
37830 if ( this.form.allItems.length) {
37831 this.form.render(el.dom);
37835 // should only have one of theses..
37836 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
37837 // views.. should not be just added - used named prop 'view''
37839 cfg.el = this.el.appendChild(document.createElement("div"));
37842 var ret = new Roo.factory(cfg);
37844 ret.render && ret.render(false, ''); // render blank..
37854 * @class Roo.bootstrap.panel.Grid
37855 * @extends Roo.bootstrap.panel.Content
37857 * Create a new GridPanel.
37858 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
37859 * @param {Object} config A the config object
37865 Roo.bootstrap.panel.Grid = function(config)
37869 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
37870 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
37872 config.el = this.wrapper;
37873 //this.el = this.wrapper;
37875 if (config.container) {
37876 // ctor'ed from a Border/panel.grid
37879 this.wrapper.setStyle("overflow", "hidden");
37880 this.wrapper.addClass('roo-grid-container');
37885 if(config.toolbar){
37886 var tool_el = this.wrapper.createChild();
37887 this.toolbar = Roo.factory(config.toolbar);
37889 if (config.toolbar.items) {
37890 ti = config.toolbar.items ;
37891 delete config.toolbar.items ;
37895 this.toolbar.render(tool_el);
37896 for(var i =0;i < ti.length;i++) {
37897 // Roo.log(['add child', items[i]]);
37898 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37900 this.toolbar.items = nitems;
37902 delete config.toolbar;
37905 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
37906 config.grid.scrollBody = true;;
37907 config.grid.monitorWindowResize = false; // turn off autosizing
37908 config.grid.autoHeight = false;
37909 config.grid.autoWidth = false;
37911 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
37913 if (config.background) {
37914 // render grid on panel activation (if panel background)
37915 this.on('activate', function(gp) {
37916 if (!gp.grid.rendered) {
37917 gp.grid.render(this.wrapper);
37918 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37923 this.grid.render(this.wrapper);
37924 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37927 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
37928 // ??? needed ??? config.el = this.wrapper;
37933 // xtype created footer. - not sure if will work as we normally have to render first..
37934 if (this.footer && !this.footer.el && this.footer.xtype) {
37936 var ctr = this.grid.getView().getFooterPanel(true);
37937 this.footer.dataSource = this.grid.dataSource;
37938 this.footer = Roo.factory(this.footer, Roo);
37939 this.footer.render(ctr);
37949 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
37950 getId : function(){
37951 return this.grid.id;
37955 * Returns the grid for this panel
37956 * @return {Roo.bootstrap.Table}
37958 getGrid : function(){
37962 setSize : function(width, height){
37963 if(!this.ignoreResize(width, height)){
37964 var grid = this.grid;
37965 var size = this.adjustForComponents(width, height);
37966 var gridel = grid.getGridEl();
37967 gridel.setSize(size.width, size.height);
37969 var thd = grid.getGridEl().select('thead',true).first();
37970 var tbd = grid.getGridEl().select('tbody', true).first();
37972 tbd.setSize(width, height - thd.getHeight());
37981 beforeSlide : function(){
37982 this.grid.getView().scroller.clip();
37985 afterSlide : function(){
37986 this.grid.getView().scroller.unclip();
37989 destroy : function(){
37990 this.grid.destroy();
37992 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
37997 * @class Roo.bootstrap.panel.Nest
37998 * @extends Roo.bootstrap.panel.Content
38000 * Create a new Panel, that can contain a layout.Border.
38003 * @param {Roo.BorderLayout} layout The layout for this panel
38004 * @param {String/Object} config A string to set only the title or a config object
38006 Roo.bootstrap.panel.Nest = function(config)
38008 // construct with only one argument..
38009 /* FIXME - implement nicer consturctors
38010 if (layout.layout) {
38012 layout = config.layout;
38013 delete config.layout;
38015 if (layout.xtype && !layout.getEl) {
38016 // then layout needs constructing..
38017 layout = Roo.factory(layout, Roo);
38021 config.el = config.layout.getEl();
38023 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
38025 config.layout.monitorWindowResize = false; // turn off autosizing
38026 this.layout = config.layout;
38027 this.layout.getEl().addClass("roo-layout-nested-layout");
38028 this.layout.parent = this;
38035 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
38037 setSize : function(width, height){
38038 if(!this.ignoreResize(width, height)){
38039 var size = this.adjustForComponents(width, height);
38040 var el = this.layout.getEl();
38041 if (size.height < 1) {
38042 el.setWidth(size.width);
38044 el.setSize(size.width, size.height);
38046 var touch = el.dom.offsetWidth;
38047 this.layout.layout();
38048 // ie requires a double layout on the first pass
38049 if(Roo.isIE && !this.initialized){
38050 this.initialized = true;
38051 this.layout.layout();
38056 // activate all subpanels if not currently active..
38058 setActiveState : function(active){
38059 this.active = active;
38060 this.setActiveClass(active);
38063 this.fireEvent("deactivate", this);
38067 this.fireEvent("activate", this);
38068 // not sure if this should happen before or after..
38069 if (!this.layout) {
38070 return; // should not happen..
38073 for (var r in this.layout.regions) {
38074 reg = this.layout.getRegion(r);
38075 if (reg.getActivePanel()) {
38076 //reg.showPanel(reg.getActivePanel()); // force it to activate..
38077 reg.setActivePanel(reg.getActivePanel());
38080 if (!reg.panels.length) {
38083 reg.showPanel(reg.getPanel(0));
38092 * Returns the nested BorderLayout for this panel
38093 * @return {Roo.BorderLayout}
38095 getLayout : function(){
38096 return this.layout;
38100 * Adds a xtype elements to the layout of the nested panel
38104 xtype : 'ContentPanel',
38111 xtype : 'NestedLayoutPanel',
38117 items : [ ... list of content panels or nested layout panels.. ]
38121 * @param {Object} cfg Xtype definition of item to add.
38123 addxtype : function(cfg) {
38124 return this.layout.addxtype(cfg);
38129 * Ext JS Library 1.1.1
38130 * Copyright(c) 2006-2007, Ext JS, LLC.
38132 * Originally Released Under LGPL - original licence link has changed is not relivant.
38135 * <script type="text/javascript">
38138 * @class Roo.TabPanel
38139 * @extends Roo.util.Observable
38140 * A lightweight tab container.
38144 // basic tabs 1, built from existing content
38145 var tabs = new Roo.TabPanel("tabs1");
38146 tabs.addTab("script", "View Script");
38147 tabs.addTab("markup", "View Markup");
38148 tabs.activate("script");
38150 // more advanced tabs, built from javascript
38151 var jtabs = new Roo.TabPanel("jtabs");
38152 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
38154 // set up the UpdateManager
38155 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
38156 var updater = tab2.getUpdateManager();
38157 updater.setDefaultUrl("ajax1.htm");
38158 tab2.on('activate', updater.refresh, updater, true);
38160 // Use setUrl for Ajax loading
38161 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
38162 tab3.setUrl("ajax2.htm", null, true);
38165 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
38168 jtabs.activate("jtabs-1");
38171 * Create a new TabPanel.
38172 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
38173 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
38175 Roo.bootstrap.panel.Tabs = function(config){
38177 * The container element for this TabPanel.
38178 * @type Roo.Element
38180 this.el = Roo.get(config.el);
38183 if(typeof config == "boolean"){
38184 this.tabPosition = config ? "bottom" : "top";
38186 Roo.apply(this, config);
38190 if(this.tabPosition == "bottom"){
38191 // if tabs are at the bottom = create the body first.
38192 this.bodyEl = Roo.get(this.createBody(this.el.dom));
38193 this.el.addClass("roo-tabs-bottom");
38195 // next create the tabs holders
38197 if (this.tabPosition == "west"){
38199 var reg = this.region; // fake it..
38201 if (!reg.mgr.parent) {
38204 reg = reg.mgr.parent.region;
38206 Roo.log("got nest?");
38208 if (reg.mgr.getRegion('west')) {
38209 var ctrdom = reg.mgr.getRegion('west').bodyEl.dom;
38210 this.stripWrap = Roo.get(this.createStrip(ctrdom ), true);
38211 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
38212 this.stripEl.setVisibilityMode(Roo.Element.DISPLAY);
38213 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
38221 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
38222 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
38223 this.stripEl.setVisibilityMode(Roo.Element.DISPLAY);
38224 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
38229 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
38232 // finally - if tabs are at the top, then create the body last..
38233 if(this.tabPosition != "bottom"){
38234 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
38235 * @type Roo.Element
38237 this.bodyEl = Roo.get(this.createBody(this.el.dom));
38238 this.el.addClass("roo-tabs-top");
38242 this.bodyEl.setStyle("position", "relative");
38244 this.active = null;
38245 this.activateDelegate = this.activate.createDelegate(this);
38250 * Fires when the active tab changes
38251 * @param {Roo.TabPanel} this
38252 * @param {Roo.TabPanelItem} activePanel The new active tab
38256 * @event beforetabchange
38257 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
38258 * @param {Roo.TabPanel} this
38259 * @param {Object} e Set cancel to true on this object to cancel the tab change
38260 * @param {Roo.TabPanelItem} tab The tab being changed to
38262 "beforetabchange" : true
38265 Roo.EventManager.onWindowResize(this.onResize, this);
38266 this.cpad = this.el.getPadding("lr");
38267 this.hiddenCount = 0;
38270 // toolbar on the tabbar support...
38271 if (this.toolbar) {
38272 alert("no toolbar support yet");
38273 this.toolbar = false;
38275 var tcfg = this.toolbar;
38276 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
38277 this.toolbar = new Roo.Toolbar(tcfg);
38278 if (Roo.isSafari) {
38279 var tbl = tcfg.container.child('table', true);
38280 tbl.setAttribute('width', '100%');
38288 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
38291 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
38293 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
38295 tabPosition : "top",
38297 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
38299 currentTabWidth : 0,
38301 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
38305 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
38309 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
38311 preferredTabWidth : 175,
38313 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
38315 resizeTabs : false,
38317 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
38319 monitorResize : true,
38321 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
38323 toolbar : false, // set by caller..
38325 region : false, /// set by caller
38327 disableTooltips : true, // not used yet...
38330 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
38331 * @param {String} id The id of the div to use <b>or create</b>
38332 * @param {String} text The text for the tab
38333 * @param {String} content (optional) Content to put in the TabPanelItem body
38334 * @param {Boolean} closable (optional) True to create a close icon on the tab
38335 * @return {Roo.TabPanelItem} The created TabPanelItem
38337 addTab : function(id, text, content, closable, tpl)
38339 var item = new Roo.bootstrap.panel.TabItem({
38343 closable : closable,
38346 this.addTabItem(item);
38348 item.setContent(content);
38354 * Returns the {@link Roo.TabPanelItem} with the specified id/index
38355 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
38356 * @return {Roo.TabPanelItem}
38358 getTab : function(id){
38359 return this.items[id];
38363 * Hides the {@link Roo.TabPanelItem} with the specified id/index
38364 * @param {String/Number} id The id or index of the TabPanelItem to hide.
38366 hideTab : function(id){
38367 var t = this.items[id];
38370 this.hiddenCount++;
38371 this.autoSizeTabs();
38376 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
38377 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
38379 unhideTab : function(id){
38380 var t = this.items[id];
38382 t.setHidden(false);
38383 this.hiddenCount--;
38384 this.autoSizeTabs();
38389 * Adds an existing {@link Roo.TabPanelItem}.
38390 * @param {Roo.TabPanelItem} item The TabPanelItem to add
38392 addTabItem : function(item)
38394 this.items[item.id] = item;
38395 this.items.push(item);
38396 this.autoSizeTabs();
38397 // if(this.resizeTabs){
38398 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
38399 // this.autoSizeTabs();
38401 // item.autoSize();
38406 * Removes a {@link Roo.TabPanelItem}.
38407 * @param {String/Number} id The id or index of the TabPanelItem to remove.
38409 removeTab : function(id){
38410 var items = this.items;
38411 var tab = items[id];
38412 if(!tab) { return; }
38413 var index = items.indexOf(tab);
38414 if(this.active == tab && items.length > 1){
38415 var newTab = this.getNextAvailable(index);
38420 this.stripEl.dom.removeChild(tab.pnode.dom);
38421 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
38422 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
38424 items.splice(index, 1);
38425 delete this.items[tab.id];
38426 tab.fireEvent("close", tab);
38427 tab.purgeListeners();
38428 this.autoSizeTabs();
38431 getNextAvailable : function(start){
38432 var items = this.items;
38434 // look for a next tab that will slide over to
38435 // replace the one being removed
38436 while(index < items.length){
38437 var item = items[++index];
38438 if(item && !item.isHidden()){
38442 // if one isn't found select the previous tab (on the left)
38445 var item = items[--index];
38446 if(item && !item.isHidden()){
38454 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
38455 * @param {String/Number} id The id or index of the TabPanelItem to disable.
38457 disableTab : function(id){
38458 var tab = this.items[id];
38459 if(tab && this.active != tab){
38465 * Enables a {@link Roo.TabPanelItem} that is disabled.
38466 * @param {String/Number} id The id or index of the TabPanelItem to enable.
38468 enableTab : function(id){
38469 var tab = this.items[id];
38474 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
38475 * @param {String/Number} id The id or index of the TabPanelItem to activate.
38476 * @return {Roo.TabPanelItem} The TabPanelItem.
38478 activate : function(id)
38480 //Roo.log('activite:' + id);
38482 var tab = this.items[id];
38486 if(tab == this.active || tab.disabled){
38490 this.fireEvent("beforetabchange", this, e, tab);
38491 if(e.cancel !== true && !tab.disabled){
38493 this.active.hide();
38495 this.active = this.items[id];
38496 this.active.show();
38497 this.fireEvent("tabchange", this, this.active);
38503 * Gets the active {@link Roo.TabPanelItem}.
38504 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
38506 getActiveTab : function(){
38507 return this.active;
38511 * Updates the tab body element to fit the height of the container element
38512 * for overflow scrolling
38513 * @param {Number} targetHeight (optional) Override the starting height from the elements height
38515 syncHeight : function(targetHeight){
38516 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
38517 var bm = this.bodyEl.getMargins();
38518 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
38519 this.bodyEl.setHeight(newHeight);
38523 onResize : function(){
38524 if(this.monitorResize){
38525 this.autoSizeTabs();
38530 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
38532 beginUpdate : function(){
38533 this.updating = true;
38537 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
38539 endUpdate : function(){
38540 this.updating = false;
38541 this.autoSizeTabs();
38545 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
38547 autoSizeTabs : function()
38549 var count = this.items.length;
38550 var vcount = count - this.hiddenCount;
38553 this.stripEl.hide();
38555 this.stripEl.show();
38558 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
38563 var w = Math.max(this.el.getWidth() - this.cpad, 10);
38564 var availWidth = Math.floor(w / vcount);
38565 var b = this.stripBody;
38566 if(b.getWidth() > w){
38567 var tabs = this.items;
38568 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
38569 if(availWidth < this.minTabWidth){
38570 /*if(!this.sleft){ // incomplete scrolling code
38571 this.createScrollButtons();
38574 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
38577 if(this.currentTabWidth < this.preferredTabWidth){
38578 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
38584 * Returns the number of tabs in this TabPanel.
38587 getCount : function(){
38588 return this.items.length;
38592 * Resizes all the tabs to the passed width
38593 * @param {Number} The new width
38595 setTabWidth : function(width){
38596 this.currentTabWidth = width;
38597 for(var i = 0, len = this.items.length; i < len; i++) {
38598 if(!this.items[i].isHidden()) {
38599 this.items[i].setWidth(width);
38605 * Destroys this TabPanel
38606 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
38608 destroy : function(removeEl){
38609 Roo.EventManager.removeResizeListener(this.onResize, this);
38610 for(var i = 0, len = this.items.length; i < len; i++){
38611 this.items[i].purgeListeners();
38613 if(removeEl === true){
38614 this.el.update("");
38619 createStrip : function(container)
38621 var strip = document.createElement("nav");
38622 strip.className = Roo.bootstrap.version == 4 ?
38623 "navbar-light bg-light" :
38624 "navbar navbar-default"; //"x-tabs-wrap";
38625 container.appendChild(strip);
38629 createStripList : function(strip)
38631 // div wrapper for retard IE
38632 // returns the "tr" element.
38633 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
38634 //'<div class="x-tabs-strip-wrap">'+
38635 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
38636 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
38637 return strip.firstChild; //.firstChild.firstChild.firstChild;
38639 createBody : function(container)
38641 var body = document.createElement("div");
38642 Roo.id(body, "tab-body");
38643 //Roo.fly(body).addClass("x-tabs-body");
38644 Roo.fly(body).addClass("tab-content");
38645 container.appendChild(body);
38648 createItemBody :function(bodyEl, id){
38649 var body = Roo.getDom(id);
38651 body = document.createElement("div");
38654 //Roo.fly(body).addClass("x-tabs-item-body");
38655 Roo.fly(body).addClass("tab-pane");
38656 bodyEl.insertBefore(body, bodyEl.firstChild);
38660 createStripElements : function(stripEl, text, closable, tpl)
38662 var td = document.createElement("li"); // was td..
38663 td.className = 'nav-item';
38665 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
38668 stripEl.appendChild(td);
38670 td.className = "x-tabs-closable";
38671 if(!this.closeTpl){
38672 this.closeTpl = new Roo.Template(
38673 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38674 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
38675 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
38678 var el = this.closeTpl.overwrite(td, {"text": text});
38679 var close = el.getElementsByTagName("div")[0];
38680 var inner = el.getElementsByTagName("em")[0];
38681 return {"el": el, "close": close, "inner": inner};
38684 // not sure what this is..
38685 // if(!this.tabTpl){
38686 //this.tabTpl = new Roo.Template(
38687 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38688 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
38690 // this.tabTpl = new Roo.Template(
38691 // '<a href="#">' +
38692 // '<span unselectable="on"' +
38693 // (this.disableTooltips ? '' : ' title="{text}"') +
38694 // ' >{text}</span></a>'
38700 var template = tpl || this.tabTpl || false;
38703 template = new Roo.Template(
38704 Roo.bootstrap.version == 4 ?
38706 '<a class="nav-link" href="#" unselectable="on"' +
38707 (this.disableTooltips ? '' : ' title="{text}"') +
38710 '<a class="nav-link" href="#">' +
38711 '<span unselectable="on"' +
38712 (this.disableTooltips ? '' : ' title="{text}"') +
38713 ' >{text}</span></a>'
38718 switch (typeof(template)) {
38722 template = new Roo.Template(template);
38728 var el = template.overwrite(td, {"text": text});
38730 var inner = el.getElementsByTagName("span")[0];
38732 return {"el": el, "inner": inner};
38740 * @class Roo.TabPanelItem
38741 * @extends Roo.util.Observable
38742 * Represents an individual item (tab plus body) in a TabPanel.
38743 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
38744 * @param {String} id The id of this TabPanelItem
38745 * @param {String} text The text for the tab of this TabPanelItem
38746 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
38748 Roo.bootstrap.panel.TabItem = function(config){
38750 * The {@link Roo.TabPanel} this TabPanelItem belongs to
38751 * @type Roo.TabPanel
38753 this.tabPanel = config.panel;
38755 * The id for this TabPanelItem
38758 this.id = config.id;
38760 this.disabled = false;
38762 this.text = config.text;
38764 this.loaded = false;
38765 this.closable = config.closable;
38768 * The body element for this TabPanelItem.
38769 * @type Roo.Element
38771 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
38772 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
38773 this.bodyEl.setStyle("display", "block");
38774 this.bodyEl.setStyle("zoom", "1");
38775 //this.hideAction();
38777 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
38779 this.el = Roo.get(els.el);
38780 this.inner = Roo.get(els.inner, true);
38781 this.textEl = Roo.bootstrap.version == 4 ?
38782 this.el : Roo.get(this.el.dom.firstChild, true);
38784 this.pnode = this.linode = Roo.get(els.el.parentNode, true);
38785 this.status_node = Roo.bootstrap.version == 4 ? this.el : this.linode;
38788 // this.el.on("mousedown", this.onTabMouseDown, this);
38789 this.el.on("click", this.onTabClick, this);
38791 if(config.closable){
38792 var c = Roo.get(els.close, true);
38793 c.dom.title = this.closeText;
38794 c.addClassOnOver("close-over");
38795 c.on("click", this.closeClick, this);
38801 * Fires when this tab becomes the active tab.
38802 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38803 * @param {Roo.TabPanelItem} this
38807 * @event beforeclose
38808 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
38809 * @param {Roo.TabPanelItem} this
38810 * @param {Object} e Set cancel to true on this object to cancel the close.
38812 "beforeclose": true,
38815 * Fires when this tab is closed.
38816 * @param {Roo.TabPanelItem} this
38820 * @event deactivate
38821 * Fires when this tab is no longer the active tab.
38822 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38823 * @param {Roo.TabPanelItem} this
38825 "deactivate" : true
38827 this.hidden = false;
38829 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
38832 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
38834 purgeListeners : function(){
38835 Roo.util.Observable.prototype.purgeListeners.call(this);
38836 this.el.removeAllListeners();
38839 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
38842 this.status_node.addClass("active");
38845 this.tabPanel.stripWrap.repaint();
38847 this.fireEvent("activate", this.tabPanel, this);
38851 * Returns true if this tab is the active tab.
38852 * @return {Boolean}
38854 isActive : function(){
38855 return this.tabPanel.getActiveTab() == this;
38859 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
38862 this.status_node.removeClass("active");
38864 this.fireEvent("deactivate", this.tabPanel, this);
38867 hideAction : function(){
38868 this.bodyEl.hide();
38869 this.bodyEl.setStyle("position", "absolute");
38870 this.bodyEl.setLeft("-20000px");
38871 this.bodyEl.setTop("-20000px");
38874 showAction : function(){
38875 this.bodyEl.setStyle("position", "relative");
38876 this.bodyEl.setTop("");
38877 this.bodyEl.setLeft("");
38878 this.bodyEl.show();
38882 * Set the tooltip for the tab.
38883 * @param {String} tooltip The tab's tooltip
38885 setTooltip : function(text){
38886 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
38887 this.textEl.dom.qtip = text;
38888 this.textEl.dom.removeAttribute('title');
38890 this.textEl.dom.title = text;
38894 onTabClick : function(e){
38895 e.preventDefault();
38896 this.tabPanel.activate(this.id);
38899 onTabMouseDown : function(e){
38900 e.preventDefault();
38901 this.tabPanel.activate(this.id);
38904 getWidth : function(){
38905 return this.inner.getWidth();
38908 setWidth : function(width){
38909 var iwidth = width - this.linode.getPadding("lr");
38910 this.inner.setWidth(iwidth);
38911 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
38912 this.linode.setWidth(width);
38916 * Show or hide the tab
38917 * @param {Boolean} hidden True to hide or false to show.
38919 setHidden : function(hidden){
38920 this.hidden = hidden;
38921 this.linode.setStyle("display", hidden ? "none" : "");
38925 * Returns true if this tab is "hidden"
38926 * @return {Boolean}
38928 isHidden : function(){
38929 return this.hidden;
38933 * Returns the text for this tab
38936 getText : function(){
38940 autoSize : function(){
38941 //this.el.beginMeasure();
38942 this.textEl.setWidth(1);
38944 * #2804 [new] Tabs in Roojs
38945 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
38947 //this.setWidth(this.textEl.dom.scrollWidth+this.linode.getPadding("lr")+this.inner.getPadding("lr") + 2);
38948 //this.el.endMeasure();
38952 * Sets the text for the tab (Note: this also sets the tooltip text)
38953 * @param {String} text The tab's text and tooltip
38955 setText : function(text){
38957 this.textEl.update(text);
38958 this.setTooltip(text);
38959 //if(!this.tabPanel.resizeTabs){
38960 // this.autoSize();
38964 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
38966 activate : function(){
38967 this.tabPanel.activate(this.id);
38971 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
38973 disable : function(){
38974 if(this.tabPanel.active != this){
38975 this.disabled = true;
38976 this.status_node.addClass("disabled");
38981 * Enables this TabPanelItem if it was previously disabled.
38983 enable : function(){
38984 this.disabled = false;
38985 this.status_node.removeClass("disabled");
38989 * Sets the content for this TabPanelItem.
38990 * @param {String} content The content
38991 * @param {Boolean} loadScripts true to look for and load scripts
38993 setContent : function(content, loadScripts){
38994 this.bodyEl.update(content, loadScripts);
38998 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
38999 * @return {Roo.UpdateManager} The UpdateManager
39001 getUpdateManager : function(){
39002 return this.bodyEl.getUpdateManager();
39006 * Set a URL to be used to load the content for this TabPanelItem.
39007 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
39008 * @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)
39009 * @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)
39010 * @return {Roo.UpdateManager} The UpdateManager
39012 setUrl : function(url, params, loadOnce){
39013 if(this.refreshDelegate){
39014 this.un('activate', this.refreshDelegate);
39016 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
39017 this.on("activate", this.refreshDelegate);
39018 return this.bodyEl.getUpdateManager();
39022 _handleRefresh : function(url, params, loadOnce){
39023 if(!loadOnce || !this.loaded){
39024 var updater = this.bodyEl.getUpdateManager();
39025 updater.update(url, params, this._setLoaded.createDelegate(this));
39030 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
39031 * Will fail silently if the setUrl method has not been called.
39032 * This does not activate the panel, just updates its content.
39034 refresh : function(){
39035 if(this.refreshDelegate){
39036 this.loaded = false;
39037 this.refreshDelegate();
39042 _setLoaded : function(){
39043 this.loaded = true;
39047 closeClick : function(e){
39050 this.fireEvent("beforeclose", this, o);
39051 if(o.cancel !== true){
39052 this.tabPanel.removeTab(this.id);
39056 * The text displayed in the tooltip for the close icon.
39059 closeText : "Close this tab"
39062 * This script refer to:
39063 * Title: International Telephone Input
39064 * Author: Jack O'Connor
39065 * Code version: v12.1.12
39066 * Availability: https://github.com/jackocnr/intl-tel-input.git
39069 Roo.bootstrap.PhoneInputData = function() {
39072 "Afghanistan (افغانستان)",
39077 "Albania (Shqipëri)",
39082 "Algeria (الجزائر)",
39107 "Antigua and Barbuda",
39117 "Armenia (Հայաստան)",
39133 "Austria (Österreich)",
39138 "Azerbaijan (Azərbaycan)",
39148 "Bahrain (البحرين)",
39153 "Bangladesh (বাংলাদেশ)",
39163 "Belarus (Беларусь)",
39168 "Belgium (België)",
39198 "Bosnia and Herzegovina (Босна и Херцеговина)",
39213 "British Indian Ocean Territory",
39218 "British Virgin Islands",
39228 "Bulgaria (България)",
39238 "Burundi (Uburundi)",
39243 "Cambodia (កម្ពុជា)",
39248 "Cameroon (Cameroun)",
39257 ["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"]
39260 "Cape Verde (Kabu Verdi)",
39265 "Caribbean Netherlands",
39276 "Central African Republic (République centrafricaine)",
39296 "Christmas Island",
39302 "Cocos (Keeling) Islands",
39313 "Comoros (جزر القمر)",
39318 "Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)",
39323 "Congo (Republic) (Congo-Brazzaville)",
39343 "Croatia (Hrvatska)",
39364 "Czech Republic (Česká republika)",
39369 "Denmark (Danmark)",
39384 "Dominican Republic (República Dominicana)",
39388 ["809", "829", "849"]
39406 "Equatorial Guinea (Guinea Ecuatorial)",
39426 "Falkland Islands (Islas Malvinas)",
39431 "Faroe Islands (Føroyar)",
39452 "French Guiana (Guyane française)",
39457 "French Polynesia (Polynésie française)",
39472 "Georgia (საქართველო)",
39477 "Germany (Deutschland)",
39497 "Greenland (Kalaallit Nunaat)",
39534 "Guinea-Bissau (Guiné Bissau)",
39559 "Hungary (Magyarország)",
39564 "Iceland (Ísland)",
39584 "Iraq (العراق)",
39600 "Israel (ישראל)",
39627 "Jordan (الأردن)",
39632 "Kazakhstan (Казахстан)",
39653 "Kuwait (الكويت)",
39658 "Kyrgyzstan (Кыргызстан)",
39668 "Latvia (Latvija)",
39673 "Lebanon (لبنان)",
39688 "Libya (ليبيا)",
39698 "Lithuania (Lietuva)",
39713 "Macedonia (FYROM) (Македонија)",
39718 "Madagascar (Madagasikara)",
39748 "Marshall Islands",
39758 "Mauritania (موريتانيا)",
39763 "Mauritius (Moris)",
39784 "Moldova (Republica Moldova)",
39794 "Mongolia (Монгол)",
39799 "Montenegro (Crna Gora)",
39809 "Morocco (المغرب)",
39815 "Mozambique (Moçambique)",
39820 "Myanmar (Burma) (မြန်မာ)",
39825 "Namibia (Namibië)",
39840 "Netherlands (Nederland)",
39845 "New Caledonia (Nouvelle-Calédonie)",
39880 "North Korea (조선 민주주의 인민 공화국)",
39885 "Northern Mariana Islands",
39901 "Pakistan (پاکستان)",
39911 "Palestine (فلسطين)",
39921 "Papua New Guinea",
39963 "Réunion (La Réunion)",
39969 "Romania (România)",
39985 "Saint Barthélemy",
39996 "Saint Kitts and Nevis",
40006 "Saint Martin (Saint-Martin (partie française))",
40012 "Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)",
40017 "Saint Vincent and the Grenadines",
40032 "São Tomé and Príncipe (São Tomé e Príncipe)",
40037 "Saudi Arabia (المملكة العربية السعودية)",
40042 "Senegal (Sénégal)",
40072 "Slovakia (Slovensko)",
40077 "Slovenia (Slovenija)",
40087 "Somalia (Soomaaliya)",
40097 "South Korea (대한민국)",
40102 "South Sudan (جنوب السودان)",
40112 "Sri Lanka (ශ්රී ලංකාව)",
40117 "Sudan (السودان)",
40127 "Svalbard and Jan Mayen",
40138 "Sweden (Sverige)",
40143 "Switzerland (Schweiz)",
40148 "Syria (سوريا)",
40193 "Trinidad and Tobago",
40198 "Tunisia (تونس)",
40203 "Turkey (Türkiye)",
40213 "Turks and Caicos Islands",
40223 "U.S. Virgin Islands",
40233 "Ukraine (Україна)",
40238 "United Arab Emirates (الإمارات العربية المتحدة)",
40260 "Uzbekistan (Oʻzbekiston)",
40270 "Vatican City (Città del Vaticano)",
40281 "Vietnam (Việt Nam)",
40286 "Wallis and Futuna (Wallis-et-Futuna)",
40291 "Western Sahara (الصحراء الغربية)",
40297 "Yemen (اليمن)",
40321 * This script refer to:
40322 * Title: International Telephone Input
40323 * Author: Jack O'Connor
40324 * Code version: v12.1.12
40325 * Availability: https://github.com/jackocnr/intl-tel-input.git
40329 * @class Roo.bootstrap.PhoneInput
40330 * @extends Roo.bootstrap.TriggerField
40331 * An input with International dial-code selection
40333 * @cfg {String} defaultDialCode default '+852'
40334 * @cfg {Array} preferedCountries default []
40337 * Create a new PhoneInput.
40338 * @param {Object} config Configuration options
40341 Roo.bootstrap.PhoneInput = function(config) {
40342 Roo.bootstrap.PhoneInput.superclass.constructor.call(this, config);
40345 Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
40347 listWidth: undefined,
40349 selectedClass: 'active',
40351 invalidClass : "has-warning",
40353 validClass: 'has-success',
40355 allowed: '0123456789',
40360 * @cfg {String} defaultDialCode The default dial code when initializing the input
40362 defaultDialCode: '+852',
40365 * @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
40367 preferedCountries: false,
40369 getAutoCreate : function()
40371 var data = Roo.bootstrap.PhoneInputData();
40372 var align = this.labelAlign || this.parentLabelAlign();
40375 this.allCountries = [];
40376 this.dialCodeMapping = [];
40378 for (var i = 0; i < data.length; i++) {
40380 this.allCountries[i] = {
40384 priority: c[3] || 0,
40385 areaCodes: c[4] || null
40387 this.dialCodeMapping[c[2]] = {
40390 priority: c[3] || 0,
40391 areaCodes: c[4] || null
40403 // type: 'number', -- do not use number - we get the flaky up/down arrows.
40404 maxlength: this.max_length,
40405 cls : 'form-control tel-input',
40406 autocomplete: 'new-password'
40409 var hiddenInput = {
40412 cls: 'hidden-tel-input'
40416 hiddenInput.name = this.name;
40419 if (this.disabled) {
40420 input.disabled = true;
40423 var flag_container = {
40440 cls: this.hasFeedback ? 'has-feedback' : '',
40446 cls: 'dial-code-holder',
40453 cls: 'roo-select2-container input-group',
40460 if (this.fieldLabel.length) {
40463 tooltip: 'This field is required'
40469 cls: 'control-label',
40475 html: this.fieldLabel
40478 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40484 if(this.indicatorpos == 'right') {
40485 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40492 if(align == 'left') {
40500 if(this.labelWidth > 12){
40501 label.style = "width: " + this.labelWidth + 'px';
40503 if(this.labelWidth < 13 && this.labelmd == 0){
40504 this.labelmd = this.labelWidth;
40506 if(this.labellg > 0){
40507 label.cls += ' col-lg-' + this.labellg;
40508 input.cls += ' col-lg-' + (12 - this.labellg);
40510 if(this.labelmd > 0){
40511 label.cls += ' col-md-' + this.labelmd;
40512 container.cls += ' col-md-' + (12 - this.labelmd);
40514 if(this.labelsm > 0){
40515 label.cls += ' col-sm-' + this.labelsm;
40516 container.cls += ' col-sm-' + (12 - this.labelsm);
40518 if(this.labelxs > 0){
40519 label.cls += ' col-xs-' + this.labelxs;
40520 container.cls += ' col-xs-' + (12 - this.labelxs);
40530 var settings = this;
40532 ['xs','sm','md','lg'].map(function(size){
40533 if (settings[size]) {
40534 cfg.cls += ' col-' + size + '-' + settings[size];
40538 this.store = new Roo.data.Store({
40539 proxy : new Roo.data.MemoryProxy({}),
40540 reader : new Roo.data.JsonReader({
40551 'name' : 'dialCode',
40555 'name' : 'priority',
40559 'name' : 'areaCodes',
40566 if(!this.preferedCountries) {
40567 this.preferedCountries = [
40574 var p = this.preferedCountries.reverse();
40577 for (var i = 0; i < p.length; i++) {
40578 for (var j = 0; j < this.allCountries.length; j++) {
40579 if(this.allCountries[j].iso2 == p[i]) {
40580 var t = this.allCountries[j];
40581 this.allCountries.splice(j,1);
40582 this.allCountries.unshift(t);
40588 this.store.proxy.data = {
40590 data: this.allCountries
40596 initEvents : function()
40599 Roo.bootstrap.PhoneInput.superclass.initEvents.call(this);
40601 this.indicator = this.indicatorEl();
40602 this.flag = this.flagEl();
40603 this.dialCodeHolder = this.dialCodeHolderEl();
40605 this.trigger = this.el.select('div.flag-box',true).first();
40606 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
40611 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40612 _this.list.setWidth(lw);
40615 this.list.on('mouseover', this.onViewOver, this);
40616 this.list.on('mousemove', this.onViewMove, this);
40617 this.inputEl().on("keyup", this.onKeyUp, this);
40618 this.inputEl().on("keypress", this.onKeyPress, this);
40620 this.tpl = '<li><a href="#"><div class="flag {iso2}"></div>{name} <span class="dial-code">+{dialCode}</span></a></li>';
40622 this.view = new Roo.View(this.list, this.tpl, {
40623 singleSelect:true, store: this.store, selectedClass: this.selectedClass
40626 this.view.on('click', this.onViewClick, this);
40627 this.setValue(this.defaultDialCode);
40630 onTriggerClick : function(e)
40632 Roo.log('trigger click');
40637 if(this.isExpanded()){
40639 this.hasFocus = false;
40641 this.store.load({});
40642 this.hasFocus = true;
40647 isExpanded : function()
40649 return this.list.isVisible();
40652 collapse : function()
40654 if(!this.isExpanded()){
40658 Roo.get(document).un('mousedown', this.collapseIf, this);
40659 Roo.get(document).un('mousewheel', this.collapseIf, this);
40660 this.fireEvent('collapse', this);
40664 expand : function()
40668 if(this.isExpanded() || !this.hasFocus){
40672 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
40673 this.list.setWidth(lw);
40676 this.restrictHeight();
40678 Roo.get(document).on('mousedown', this.collapseIf, this);
40679 Roo.get(document).on('mousewheel', this.collapseIf, this);
40681 this.fireEvent('expand', this);
40684 restrictHeight : function()
40686 this.list.alignTo(this.inputEl(), this.listAlign);
40687 this.list.alignTo(this.inputEl(), this.listAlign);
40690 onViewOver : function(e, t)
40692 if(this.inKeyMode){
40695 var item = this.view.findItemFromChild(t);
40698 var index = this.view.indexOf(item);
40699 this.select(index, false);
40704 onViewClick : function(view, doFocus, el, e)
40706 var index = this.view.getSelectedIndexes()[0];
40708 var r = this.store.getAt(index);
40711 this.onSelect(r, index);
40713 if(doFocus !== false && !this.blockFocus){
40714 this.inputEl().focus();
40718 onViewMove : function(e, t)
40720 this.inKeyMode = false;
40723 select : function(index, scrollIntoView)
40725 this.selectedIndex = index;
40726 this.view.select(index);
40727 if(scrollIntoView !== false){
40728 var el = this.view.getNode(index);
40730 this.list.scrollChildIntoView(el, false);
40735 createList : function()
40737 this.list = Roo.get(document.body).createChild({
40739 cls: 'typeahead typeahead-long dropdown-menu tel-list',
40740 style: 'display:none'
40743 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
40746 collapseIf : function(e)
40748 var in_combo = e.within(this.el);
40749 var in_list = e.within(this.list);
40750 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
40752 if (in_combo || in_list || is_list) {
40758 onSelect : function(record, index)
40760 if(this.fireEvent('beforeselect', this, record, index) !== false){
40762 this.setFlagClass(record.data.iso2);
40763 this.setDialCode(record.data.dialCode);
40764 this.hasFocus = false;
40766 this.fireEvent('select', this, record, index);
40770 flagEl : function()
40772 var flag = this.el.select('div.flag',true).first();
40779 dialCodeHolderEl : function()
40781 var d = this.el.select('input.dial-code-holder',true).first();
40788 setDialCode : function(v)
40790 this.dialCodeHolder.dom.value = '+'+v;
40793 setFlagClass : function(n)
40795 this.flag.dom.className = 'flag '+n;
40798 getValue : function()
40800 var v = this.inputEl().getValue();
40801 if(this.dialCodeHolder) {
40802 v = this.dialCodeHolder.dom.value+this.inputEl().getValue();
40807 setValue : function(v)
40809 var d = this.getDialCode(v);
40811 //invalid dial code
40812 if(v.length == 0 || !d || d.length == 0) {
40814 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
40815 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
40821 this.setFlagClass(this.dialCodeMapping[d].iso2);
40822 this.setDialCode(d);
40823 this.inputEl().dom.value = v.replace('+'+d,'');
40824 this.hiddenEl().dom.value = this.getValue();
40829 getDialCode : function(v)
40833 if (v.length == 0) {
40834 return this.dialCodeHolder.dom.value;
40838 if (v.charAt(0) != "+") {
40841 var numericChars = "";
40842 for (var i = 1; i < v.length; i++) {
40843 var c = v.charAt(i);
40846 if (this.dialCodeMapping[numericChars]) {
40847 dialCode = v.substr(1, i);
40849 if (numericChars.length == 4) {
40859 this.setValue(this.defaultDialCode);
40863 hiddenEl : function()
40865 return this.el.select('input.hidden-tel-input',true).first();
40868 // after setting val
40869 onKeyUp : function(e){
40870 this.setValue(this.getValue());
40873 onKeyPress : function(e){
40874 if(this.allowed.indexOf(String.fromCharCode(e.getCharCode())) === -1){
40881 * @class Roo.bootstrap.MoneyField
40882 * @extends Roo.bootstrap.ComboBox
40883 * Bootstrap MoneyField class
40886 * Create a new MoneyField.
40887 * @param {Object} config Configuration options
40890 Roo.bootstrap.MoneyField = function(config) {
40892 Roo.bootstrap.MoneyField.superclass.constructor.call(this, config);
40896 Roo.extend(Roo.bootstrap.MoneyField, Roo.bootstrap.ComboBox, {
40899 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
40901 allowDecimals : true,
40903 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
40905 decimalSeparator : ".",
40907 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
40909 decimalPrecision : 0,
40911 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
40913 allowNegative : true,
40915 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
40919 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
40921 minValue : Number.NEGATIVE_INFINITY,
40923 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
40925 maxValue : Number.MAX_VALUE,
40927 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
40929 minText : "The minimum value for this field is {0}",
40931 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
40933 maxText : "The maximum value for this field is {0}",
40935 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
40936 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
40938 nanText : "{0} is not a valid number",
40940 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
40944 * @cfg {String} defaults currency of the MoneyField
40945 * value should be in lkey
40947 defaultCurrency : false,
40949 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
40951 thousandsDelimiter : false,
40953 * @cfg {Number} max_length Maximum input field length allowed (defaults to Number.MAX_VALUE)
40964 getAutoCreate : function()
40966 var align = this.labelAlign || this.parentLabelAlign();
40978 cls : 'form-control roo-money-amount-input',
40979 autocomplete: 'new-password'
40982 var hiddenInput = {
40986 cls: 'hidden-number-input'
40989 if(this.max_length) {
40990 input.maxlength = this.max_length;
40994 hiddenInput.name = this.name;
40997 if (this.disabled) {
40998 input.disabled = true;
41001 var clg = 12 - this.inputlg;
41002 var cmd = 12 - this.inputmd;
41003 var csm = 12 - this.inputsm;
41004 var cxs = 12 - this.inputxs;
41008 cls : 'row roo-money-field',
41012 cls : 'roo-money-currency column col-lg-' + clg + ' col-md-' + cmd + ' col-sm-' + csm + ' col-xs-' + cxs,
41016 cls: 'roo-select2-container input-group',
41020 cls : 'form-control roo-money-currency-input',
41021 autocomplete: 'new-password',
41023 name : this.currencyName
41027 cls : 'input-group-addon',
41041 cls : 'roo-money-amount column col-lg-' + this.inputlg + ' col-md-' + this.inputmd + ' col-sm-' + this.inputsm + ' col-xs-' + this.inputxs,
41045 cls: this.hasFeedback ? 'has-feedback' : '',
41056 if (this.fieldLabel.length) {
41059 tooltip: 'This field is required'
41065 cls: 'control-label',
41071 html: this.fieldLabel
41074 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
41080 if(this.indicatorpos == 'right') {
41081 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
41088 if(align == 'left') {
41096 if(this.labelWidth > 12){
41097 label.style = "width: " + this.labelWidth + 'px';
41099 if(this.labelWidth < 13 && this.labelmd == 0){
41100 this.labelmd = this.labelWidth;
41102 if(this.labellg > 0){
41103 label.cls += ' col-lg-' + this.labellg;
41104 input.cls += ' col-lg-' + (12 - this.labellg);
41106 if(this.labelmd > 0){
41107 label.cls += ' col-md-' + this.labelmd;
41108 container.cls += ' col-md-' + (12 - this.labelmd);
41110 if(this.labelsm > 0){
41111 label.cls += ' col-sm-' + this.labelsm;
41112 container.cls += ' col-sm-' + (12 - this.labelsm);
41114 if(this.labelxs > 0){
41115 label.cls += ' col-xs-' + this.labelxs;
41116 container.cls += ' col-xs-' + (12 - this.labelxs);
41127 var settings = this;
41129 ['xs','sm','md','lg'].map(function(size){
41130 if (settings[size]) {
41131 cfg.cls += ' col-' + size + '-' + settings[size];
41138 initEvents : function()
41140 this.indicator = this.indicatorEl();
41142 this.initCurrencyEvent();
41144 this.initNumberEvent();
41147 initCurrencyEvent : function()
41150 throw "can not find store for combo";
41153 this.store = Roo.factory(this.store, Roo.data);
41154 this.store.parent = this;
41158 this.triggerEl = this.el.select('.input-group-addon', true).first();
41160 this.triggerEl.on("click", this.onTriggerClick, this, { preventDefault : true });
41165 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
41166 _this.list.setWidth(lw);
41169 this.list.on('mouseover', this.onViewOver, this);
41170 this.list.on('mousemove', this.onViewMove, this);
41171 this.list.on('scroll', this.onViewScroll, this);
41174 this.tpl = '<li><a href="#">{' + this.currencyField + '}</a></li>';
41177 this.view = new Roo.View(this.list, this.tpl, {
41178 singleSelect:true, store: this.store, selectedClass: this.selectedClass
41181 this.view.on('click', this.onViewClick, this);
41183 this.store.on('beforeload', this.onBeforeLoad, this);
41184 this.store.on('load', this.onLoad, this);
41185 this.store.on('loadexception', this.onLoadException, this);
41187 this.keyNav = new Roo.KeyNav(this.currencyEl(), {
41188 "up" : function(e){
41189 this.inKeyMode = true;
41193 "down" : function(e){
41194 if(!this.isExpanded()){
41195 this.onTriggerClick();
41197 this.inKeyMode = true;
41202 "enter" : function(e){
41205 if(this.fireEvent("specialkey", this, e)){
41206 this.onViewClick(false);
41212 "esc" : function(e){
41216 "tab" : function(e){
41219 if(this.fireEvent("specialkey", this, e)){
41220 this.onViewClick(false);
41228 doRelay : function(foo, bar, hname){
41229 if(hname == 'down' || this.scope.isExpanded()){
41230 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
41238 this.currencyEl().on("click", this.onTriggerClick, this, { preventDefault : true });
41242 initNumberEvent : function(e)
41244 this.inputEl().on("keydown" , this.fireKey, this);
41245 this.inputEl().on("focus", this.onFocus, this);
41246 this.inputEl().on("blur", this.onBlur, this);
41248 this.inputEl().relayEvent('keyup', this);
41250 if(this.indicator){
41251 this.indicator.addClass('invisible');
41254 this.originalValue = this.getValue();
41256 if(this.validationEvent == 'keyup'){
41257 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
41258 this.inputEl().on('keyup', this.filterValidation, this);
41260 else if(this.validationEvent !== false){
41261 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
41264 if(this.selectOnFocus){
41265 this.on("focus", this.preFocus, this);
41268 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
41269 this.inputEl().on("keypress", this.filterKeys, this);
41271 this.inputEl().relayEvent('keypress', this);
41274 var allowed = "0123456789";
41276 if(this.allowDecimals){
41277 allowed += this.decimalSeparator;
41280 if(this.allowNegative){
41284 if(this.thousandsDelimiter) {
41288 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
41290 var keyPress = function(e){
41292 var k = e.getKey();
41294 var c = e.getCharCode();
41297 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
41298 allowed.indexOf(String.fromCharCode(c)) === -1
41304 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
41308 if(allowed.indexOf(String.fromCharCode(c)) === -1){
41313 this.inputEl().on("keypress", keyPress, this);
41317 onTriggerClick : function(e)
41324 this.loadNext = false;
41326 if(this.isExpanded()){
41331 this.hasFocus = true;
41333 if(this.triggerAction == 'all') {
41334 this.doQuery(this.allQuery, true);
41338 this.doQuery(this.getRawValue());
41341 getCurrency : function()
41343 var v = this.currencyEl().getValue();
41348 restrictHeight : function()
41350 this.list.alignTo(this.currencyEl(), this.listAlign);
41351 this.list.alignTo(this.currencyEl(), this.listAlign);
41354 onViewClick : function(view, doFocus, el, e)
41356 var index = this.view.getSelectedIndexes()[0];
41358 var r = this.store.getAt(index);
41361 this.onSelect(r, index);
41365 onSelect : function(record, index){
41367 if(this.fireEvent('beforeselect', this, record, index) !== false){
41369 this.setFromCurrencyData(index > -1 ? record.data : false);
41373 this.fireEvent('select', this, record, index);
41377 setFromCurrencyData : function(o)
41381 this.lastCurrency = o;
41383 if (this.currencyField) {
41384 currency = !o || typeof(o[this.currencyField]) == 'undefined' ? '' : o[this.currencyField];
41386 Roo.log('no currencyField value set for '+ (this.name ? this.name : this.id));
41389 this.lastSelectionText = currency;
41391 //setting default currency
41392 if(o[this.currencyField] * 1 == 0 && this.defaultCurrency) {
41393 this.setCurrency(this.defaultCurrency);
41397 this.setCurrency(currency);
41400 setFromData : function(o)
41404 c[this.currencyField] = !o || typeof(o[this.currencyName]) == 'undefined' ? '' : o[this.currencyName];
41406 this.setFromCurrencyData(c);
41411 value = !o || typeof(o[this.name]) == 'undefined' ? '' : o[this.name];
41413 Roo.log('no value set for '+ (this.name ? this.name : this.id));
41416 this.setValue(value);
41420 setCurrency : function(v)
41422 this.currencyValue = v;
41425 this.currencyEl().dom.value = (v === null || v === undefined ? '' : v);
41430 setValue : function(v)
41432 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
41438 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
41440 this.inputEl().dom.value = (v == '') ? '' :
41441 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
41443 if(!this.allowZero && v === '0') {
41444 this.hiddenEl().dom.value = '';
41445 this.inputEl().dom.value = '';
41452 getRawValue : function()
41454 var v = this.inputEl().getValue();
41459 getValue : function()
41461 return this.fixPrecision(this.parseValue(this.getRawValue()));
41464 parseValue : function(value)
41466 if(this.thousandsDelimiter) {
41468 r = new RegExp(",", "g");
41469 value = value.replace(r, "");
41472 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
41473 return isNaN(value) ? '' : value;
41477 fixPrecision : function(value)
41479 if(this.thousandsDelimiter) {
41481 r = new RegExp(",", "g");
41482 value = value.replace(r, "");
41485 var nan = isNaN(value);
41487 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
41488 return nan ? '' : value;
41490 return parseFloat(value).toFixed(this.decimalPrecision);
41493 decimalPrecisionFcn : function(v)
41495 return Math.floor(v);
41498 validateValue : function(value)
41500 if(!Roo.bootstrap.MoneyField.superclass.validateValue.call(this, value)){
41504 var num = this.parseValue(value);
41507 this.markInvalid(String.format(this.nanText, value));
41511 if(num < this.minValue){
41512 this.markInvalid(String.format(this.minText, this.minValue));
41516 if(num > this.maxValue){
41517 this.markInvalid(String.format(this.maxText, this.maxValue));
41524 validate : function()
41526 if(this.disabled || this.allowBlank){
41531 var currency = this.getCurrency();
41533 if(this.validateValue(this.getRawValue()) && currency.length){
41538 this.markInvalid();
41542 getName: function()
41547 beforeBlur : function()
41553 var v = this.parseValue(this.getRawValue());
41560 onBlur : function()
41564 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
41565 //this.el.removeClass(this.focusClass);
41568 this.hasFocus = false;
41570 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
41574 var v = this.getValue();
41576 if(String(v) !== String(this.startValue)){
41577 this.fireEvent('change', this, v, this.startValue);
41580 this.fireEvent("blur", this);
41583 inputEl : function()
41585 return this.el.select('.roo-money-amount-input', true).first();
41588 currencyEl : function()
41590 return this.el.select('.roo-money-currency-input', true).first();
41593 hiddenEl : function()
41595 return this.el.select('input.hidden-number-input',true).first();
41599 * @class Roo.bootstrap.BezierSignature
41600 * @extends Roo.bootstrap.Component
41601 * Bootstrap BezierSignature class
41602 * This script refer to:
41603 * Title: Signature Pad
41605 * Availability: https://github.com/szimek/signature_pad
41608 * Create a new BezierSignature
41609 * @param {Object} config The config object
41612 Roo.bootstrap.BezierSignature = function(config){
41613 Roo.bootstrap.BezierSignature.superclass.constructor.call(this, config);
41619 Roo.extend(Roo.bootstrap.BezierSignature, Roo.bootstrap.Component,
41626 mouse_btn_down: true,
41629 * @cfg {int} canvas height
41631 canvas_height: '200px',
41634 * @cfg {float|function} Radius of a single dot.
41639 * @cfg {float} Minimum width of a line. Defaults to 0.5.
41644 * @cfg {float} Maximum width of a line. Defaults to 2.5.
41649 * @cfg {integer} Draw the next point at most once per every x milliseconds. Set it to 0 to turn off throttling. Defaults to 16.
41654 * @cfg {integer} Add the next point only if the previous one is farther than x pixels. Defaults to 5.
41659 * @cfg {string} Color used to clear the background. Can be any color format accepted by context.fillStyle. Defaults to "rgba(0,0,0,0)" (transparent black). Use a non-transparent color e.g. "rgb(255,255,255)" (opaque white) if you'd like to save signatures as JPEG images.
41661 bg_color: 'rgba(0, 0, 0, 0)',
41664 * @cfg {string} Color used to draw the lines. Can be any color format accepted by context.fillStyle. Defaults to "black".
41666 dot_color: 'black',
41669 * @cfg {float} Weight used to modify new velocity based on the previous velocity. Defaults to 0.7.
41671 velocity_filter_weight: 0.7,
41674 * @cfg {function} Callback when stroke begin.
41679 * @cfg {function} Callback when stroke end.
41683 getAutoCreate : function()
41685 var cls = 'roo-signature column';
41688 cls += ' ' + this.cls;
41698 for(var i = 0; i < col_sizes.length; i++) {
41699 if(this[col_sizes[i]]) {
41700 cls += " col-"+col_sizes[i]+"-"+this[col_sizes[i]];
41710 cls: 'roo-signature-body',
41714 cls: 'roo-signature-body-canvas',
41715 height: this.canvas_height,
41716 width: this.canvas_width
41723 style: 'display: none'
41731 initEvents: function()
41733 Roo.bootstrap.BezierSignature.superclass.initEvents.call(this);
41735 var canvas = this.canvasEl();
41737 // mouse && touch event swapping...
41738 canvas.dom.style.touchAction = 'none';
41739 canvas.dom.style.msTouchAction = 'none';
41741 this.mouse_btn_down = false;
41742 canvas.on('mousedown', this._handleMouseDown, this);
41743 canvas.on('mousemove', this._handleMouseMove, this);
41744 Roo.select('html').first().on('mouseup', this._handleMouseUp, this);
41746 if (window.PointerEvent) {
41747 canvas.on('pointerdown', this._handleMouseDown, this);
41748 canvas.on('pointermove', this._handleMouseMove, this);
41749 Roo.select('html').first().on('pointerup', this._handleMouseUp, this);
41752 if ('ontouchstart' in window) {
41753 canvas.on('touchstart', this._handleTouchStart, this);
41754 canvas.on('touchmove', this._handleTouchMove, this);
41755 canvas.on('touchend', this._handleTouchEnd, this);
41758 Roo.EventManager.onWindowResize(this.resize, this, true);
41760 // file input event
41761 this.fileEl().on('change', this.uploadImage, this);
41768 resize: function(){
41770 var canvas = this.canvasEl().dom;
41771 var ctx = this.canvasElCtx();
41772 var img_data = false;
41774 if(canvas.width > 0) {
41775 var img_data = ctx.getImageData(0, 0, canvas.width, canvas.height);
41777 // setting canvas width will clean img data
41780 var style = window.getComputedStyle ?
41781 getComputedStyle(this.el.dom, null) : this.el.dom.currentStyle;
41783 var padding_left = parseInt(style.paddingLeft) || 0;
41784 var padding_right = parseInt(style.paddingRight) || 0;
41786 canvas.width = this.el.dom.clientWidth - padding_left - padding_right;
41789 ctx.putImageData(img_data, 0, 0);
41793 _handleMouseDown: function(e)
41795 if (e.browserEvent.which === 1) {
41796 this.mouse_btn_down = true;
41797 this.strokeBegin(e);
41801 _handleMouseMove: function (e)
41803 if (this.mouse_btn_down) {
41804 this.strokeMoveUpdate(e);
41808 _handleMouseUp: function (e)
41810 if (e.browserEvent.which === 1 && this.mouse_btn_down) {
41811 this.mouse_btn_down = false;
41816 _handleTouchStart: function (e) {
41818 e.preventDefault();
41819 if (e.browserEvent.targetTouches.length === 1) {
41820 // var touch = e.browserEvent.changedTouches[0];
41821 // this.strokeBegin(touch);
41823 this.strokeBegin(e); // assume e catching the correct xy...
41827 _handleTouchMove: function (e) {
41828 e.preventDefault();
41829 // var touch = event.targetTouches[0];
41830 // _this._strokeMoveUpdate(touch);
41831 this.strokeMoveUpdate(e);
41834 _handleTouchEnd: function (e) {
41835 var wasCanvasTouched = e.target === this.canvasEl().dom;
41836 if (wasCanvasTouched) {
41837 e.preventDefault();
41838 // var touch = event.changedTouches[0];
41839 // _this._strokeEnd(touch);
41844 reset: function () {
41845 this._lastPoints = [];
41846 this._lastVelocity = 0;
41847 this._lastWidth = (this.min_width + this.max_width) / 2;
41848 this.canvasElCtx().fillStyle = this.dot_color;
41851 strokeMoveUpdate: function(e)
41853 this.strokeUpdate(e);
41855 if (this.throttle) {
41856 this.throttleStroke(this.strokeUpdate, this.throttle);
41859 this.strokeUpdate(e);
41863 strokeBegin: function(e)
41865 var newPointGroup = {
41866 color: this.dot_color,
41870 if (typeof this.onBegin === 'function') {
41874 this.curve_data.push(newPointGroup);
41876 this.strokeUpdate(e);
41879 strokeUpdate: function(e)
41881 var rect = this.canvasEl().dom.getBoundingClientRect();
41882 var point = new this.Point(e.xy[0] - rect.left, e.xy[1] - rect.top, new Date().getTime());
41883 var lastPointGroup = this.curve_data[this.curve_data.length - 1];
41884 var lastPoints = lastPointGroup.points;
41885 var lastPoint = lastPoints.length > 0 && lastPoints[lastPoints.length - 1];
41886 var isLastPointTooClose = lastPoint
41887 ? point.distanceTo(lastPoint) <= this.min_distance
41889 var color = lastPointGroup.color;
41890 if (!lastPoint || !(lastPoint && isLastPointTooClose)) {
41891 var curve = this.addPoint(point);
41893 this.drawDot({color: color, point: point});
41896 this.drawCurve({color: color, curve: curve});
41906 strokeEnd: function(e)
41908 this.strokeUpdate(e);
41909 if (typeof this.onEnd === 'function') {
41914 addPoint: function (point) {
41915 var _lastPoints = this._lastPoints;
41916 _lastPoints.push(point);
41917 if (_lastPoints.length > 2) {
41918 if (_lastPoints.length === 3) {
41919 _lastPoints.unshift(_lastPoints[0]);
41921 var widths = this.calculateCurveWidths(_lastPoints[1], _lastPoints[2]);
41922 var curve = this.Bezier.fromPoints(_lastPoints, widths, this);
41923 _lastPoints.shift();
41929 calculateCurveWidths: function (startPoint, endPoint) {
41930 var velocity = this.velocity_filter_weight * endPoint.velocityFrom(startPoint) +
41931 (1 - this.velocity_filter_weight) * this._lastVelocity;
41933 var newWidth = Math.max(this.max_width / (velocity + 1), this.min_width);
41936 start: this._lastWidth
41939 this._lastVelocity = velocity;
41940 this._lastWidth = newWidth;
41944 drawDot: function (_a) {
41945 var color = _a.color, point = _a.point;
41946 var ctx = this.canvasElCtx();
41947 var width = typeof this.dot_size === 'function' ? this.dot_size() : this.dot_size;
41949 this.drawCurveSegment(point.x, point.y, width);
41951 ctx.fillStyle = color;
41955 drawCurve: function (_a) {
41956 var color = _a.color, curve = _a.curve;
41957 var ctx = this.canvasElCtx();
41958 var widthDelta = curve.endWidth - curve.startWidth;
41959 var drawSteps = Math.floor(curve.length()) * 2;
41961 ctx.fillStyle = color;
41962 for (var i = 0; i < drawSteps; i += 1) {
41963 var t = i / drawSteps;
41969 var x = uuu * curve.startPoint.x;
41970 x += 3 * uu * t * curve.control1.x;
41971 x += 3 * u * tt * curve.control2.x;
41972 x += ttt * curve.endPoint.x;
41973 var y = uuu * curve.startPoint.y;
41974 y += 3 * uu * t * curve.control1.y;
41975 y += 3 * u * tt * curve.control2.y;
41976 y += ttt * curve.endPoint.y;
41977 var width = curve.startWidth + ttt * widthDelta;
41978 this.drawCurveSegment(x, y, width);
41984 drawCurveSegment: function (x, y, width) {
41985 var ctx = this.canvasElCtx();
41987 ctx.arc(x, y, width, 0, 2 * Math.PI, false);
41988 this.is_empty = false;
41993 var ctx = this.canvasElCtx();
41994 var canvas = this.canvasEl().dom;
41995 ctx.fillStyle = this.bg_color;
41996 ctx.clearRect(0, 0, canvas.width, canvas.height);
41997 ctx.fillRect(0, 0, canvas.width, canvas.height);
41998 this.curve_data = [];
42000 this.is_empty = true;
42005 return this.el.select('input',true).first();
42008 canvasEl: function()
42010 return this.el.select('canvas',true).first();
42013 canvasElCtx: function()
42015 return this.el.select('canvas',true).first().dom.getContext('2d');
42018 getImage: function(type)
42020 if(this.is_empty) {
42025 return this.canvasEl().dom.toDataURL('image/'+type, 1);
42028 drawFromImage: function(img_src)
42030 var img = new Image();
42032 img.onload = function(){
42033 this.canvasElCtx().drawImage(img, 0, 0);
42038 this.is_empty = false;
42041 selectImage: function()
42043 this.fileEl().dom.click();
42046 uploadImage: function(e)
42048 var reader = new FileReader();
42050 reader.onload = function(e){
42051 var img = new Image();
42052 img.onload = function(){
42054 this.canvasElCtx().drawImage(img, 0, 0);
42056 img.src = e.target.result;
42059 reader.readAsDataURL(e.target.files[0]);
42062 // Bezier Point Constructor
42063 Point: (function () {
42064 function Point(x, y, time) {
42067 this.time = time || Date.now();
42069 Point.prototype.distanceTo = function (start) {
42070 return Math.sqrt(Math.pow(this.x - start.x, 2) + Math.pow(this.y - start.y, 2));
42072 Point.prototype.equals = function (other) {
42073 return this.x === other.x && this.y === other.y && this.time === other.time;
42075 Point.prototype.velocityFrom = function (start) {
42076 return this.time !== start.time
42077 ? this.distanceTo(start) / (this.time - start.time)
42084 // Bezier Constructor
42085 Bezier: (function () {
42086 function Bezier(startPoint, control2, control1, endPoint, startWidth, endWidth) {
42087 this.startPoint = startPoint;
42088 this.control2 = control2;
42089 this.control1 = control1;
42090 this.endPoint = endPoint;
42091 this.startWidth = startWidth;
42092 this.endWidth = endWidth;
42094 Bezier.fromPoints = function (points, widths, scope) {
42095 var c2 = this.calculateControlPoints(points[0], points[1], points[2], scope).c2;
42096 var c3 = this.calculateControlPoints(points[1], points[2], points[3], scope).c1;
42097 return new Bezier(points[1], c2, c3, points[2], widths.start, widths.end);
42099 Bezier.calculateControlPoints = function (s1, s2, s3, scope) {
42100 var dx1 = s1.x - s2.x;
42101 var dy1 = s1.y - s2.y;
42102 var dx2 = s2.x - s3.x;
42103 var dy2 = s2.y - s3.y;
42104 var m1 = { x: (s1.x + s2.x) / 2.0, y: (s1.y + s2.y) / 2.0 };
42105 var m2 = { x: (s2.x + s3.x) / 2.0, y: (s2.y + s3.y) / 2.0 };
42106 var l1 = Math.sqrt(dx1 * dx1 + dy1 * dy1);
42107 var l2 = Math.sqrt(dx2 * dx2 + dy2 * dy2);
42108 var dxm = m1.x - m2.x;
42109 var dym = m1.y - m2.y;
42110 var k = l2 / (l1 + l2);
42111 var cm = { x: m2.x + dxm * k, y: m2.y + dym * k };
42112 var tx = s2.x - cm.x;
42113 var ty = s2.y - cm.y;
42115 c1: new scope.Point(m1.x + tx, m1.y + ty),
42116 c2: new scope.Point(m2.x + tx, m2.y + ty)
42119 Bezier.prototype.length = function () {
42124 for (var i = 0; i <= steps; i += 1) {
42126 var cx = this.point(t, this.startPoint.x, this.control1.x, this.control2.x, this.endPoint.x);
42127 var cy = this.point(t, this.startPoint.y, this.control1.y, this.control2.y, this.endPoint.y);
42129 var xdiff = cx - px;
42130 var ydiff = cy - py;
42131 length += Math.sqrt(xdiff * xdiff + ydiff * ydiff);
42138 Bezier.prototype.point = function (t, start, c1, c2, end) {
42139 return (start * (1.0 - t) * (1.0 - t) * (1.0 - t))
42140 + (3.0 * c1 * (1.0 - t) * (1.0 - t) * t)
42141 + (3.0 * c2 * (1.0 - t) * t * t)
42142 + (end * t * t * t);
42147 throttleStroke: function(fn, wait) {
42148 if (wait === void 0) { wait = 250; }
42150 var timeout = null;
42154 var later = function () {
42155 previous = Date.now();
42157 result = fn.apply(storedContext, storedArgs);
42159 storedContext = null;
42163 return function wrapper() {
42165 for (var _i = 0; _i < arguments.length; _i++) {
42166 args[_i] = arguments[_i];
42168 var now = Date.now();
42169 var remaining = wait - (now - previous);
42170 storedContext = this;
42172 if (remaining <= 0 || remaining > wait) {
42174 clearTimeout(timeout);
42178 result = fn.apply(storedContext, storedArgs);
42180 storedContext = null;
42184 else if (!timeout) {
42185 timeout = window.setTimeout(later, remaining);