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 cn.addxtypeChildren(tree.items, skip_children);
368 * add a number of children to this object,
369 * which in turn calls render...
373 addxtypeChildren: function(child_array, skip_children)
376 if (!child_array || !child_array.length ) {
381 for(var i =0;i < child_array.length;i++) {
385 // Roo.log(['add child', items[i]]);
386 nitems.push(this.addxtype(Roo.apply({}, child_array[i])));
390 this.fireEvent('childrenrendered', this);
398 * Set the element that will be used to show or hide
400 setVisibilityEl : function(el)
402 this.visibilityEl = el;
406 * Get the element that will be used to show or hide
408 getVisibilityEl : function()
410 if (typeof(this.visibilityEl) == 'object') {
411 return this.visibilityEl;
414 if (typeof(this.visibilityEl) == 'string') {
415 return this.visibilityEl == 'parent' ? this.parent().getEl() : this.getEl();
422 * Show a component - removes 'hidden' class
426 if(!this.getVisibilityEl()){
430 this.getVisibilityEl().removeClass(['hidden','d-none']);
432 this.fireEvent('show', this);
437 * Hide a component - adds 'hidden' class
441 if(!this.getVisibilityEl()){
445 this.getVisibilityEl().addClass(['hidden','d-none']);
447 this.fireEvent('hide', this);
460 * @class Roo.bootstrap.Body
461 * @extends Roo.bootstrap.Component
462 * Bootstrap Body class
466 * @param {Object} config The config object
469 Roo.bootstrap.Body = function(config){
471 config = config || {};
473 Roo.bootstrap.Body.superclass.constructor.call(this, config);
474 this.el = Roo.get(config.el ? config.el : document.body );
475 if (this.cls && this.cls.length) {
476 Roo.get(document.body).addClass(this.cls);
480 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
482 is_body : true,// just to make sure it's constructed?
487 onRender : function(ct, position)
489 /* Roo.log("Roo.bootstrap.Body - onRender");
490 if (this.cls && this.cls.length) {
491 Roo.get(document.body).addClass(this.cls);
510 * @class Roo.bootstrap.ButtonGroup
511 * @extends Roo.bootstrap.Component
512 * Bootstrap ButtonGroup class
513 * @cfg {String} size lg | sm | xs (default empty normal)
514 * @cfg {String} align vertical | justified (default none)
515 * @cfg {String} direction up | down (default down)
516 * @cfg {Boolean} toolbar false | true
517 * @cfg {Boolean} btn true | false
522 * @param {Object} config The config object
525 Roo.bootstrap.ButtonGroup = function(config){
526 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
529 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
537 getAutoCreate : function(){
543 cfg.html = this.html || cfg.html;
554 if (['vertical','justified'].indexOf(this.align)!==-1) {
555 cfg.cls = 'btn-group-' + this.align;
557 if (this.align == 'justified') {
558 console.log(this.items);
562 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
563 cfg.cls += ' btn-group-' + this.size;
566 if (this.direction == 'up') {
567 cfg.cls += ' dropup' ;
573 * Add a button to the group (similar to NavItem API.)
575 addItem : function(cfg)
577 var cn = new Roo.bootstrap.Button(cfg);
579 cn.parentId = this.id;
580 cn.onRender(this.el, null);
594 * @class Roo.bootstrap.Button
595 * @extends Roo.bootstrap.Component
596 * Bootstrap Button class
597 * @cfg {String} html The button content
598 * @cfg {String} weight (default | primary | secondary | success | info | warning | danger | link ) default
599 * @cfg {String} badge_weight (default | primary | secondary | success | info | warning | danger | link ) default (same as button)
600 * @cfg {Boolean} outline default false (except for weight=default which emulates old behaveiour with an outline)
601 * @cfg {String} size ( lg | sm | xs)
602 * @cfg {String} tag ( a | input | submit)
603 * @cfg {String} href empty or href
604 * @cfg {Boolean} disabled default false;
605 * @cfg {Boolean} isClose default false;
606 * @cfg {String} glyphicon depricated - use fa
607 * @cfg {String} fa fontawesome icon - eg. 'comment' - without the fa/fas etc..
608 * @cfg {String} badge text for badge
609 * @cfg {String} theme (default|glow)
610 * @cfg {Boolean} inverse dark themed version
611 * @cfg {Boolean} toggle is it a slidy toggle button
612 * @cfg {Boolean} pressed (true|false) default null - if the button ahs active state
613 * @cfg {String} ontext text for on slidy toggle state
614 * @cfg {String} offtext text for off slidy toggle state
615 * @cfg {Boolean} preventDefault default true (stop click event triggering the URL if it's a link.)
616 * @cfg {Boolean} removeClass remove the standard class..
617 * @cfg {String} target target for a href. (_self|_blank|_parent|_top| other)
620 * Create a new button
621 * @param {Object} config The config object
625 Roo.bootstrap.Button = function(config){
626 Roo.bootstrap.Button.superclass.constructor.call(this, config);
627 this.weightClass = ["btn-default btn-outline-secondary",
639 * When a butotn is pressed
640 * @param {Roo.bootstrap.Button} btn
641 * @param {Roo.EventObject} e
646 * After the button has been toggles
647 * @param {Roo.bootstrap.Button} btn
648 * @param {Roo.EventObject} e
649 * @param {boolean} pressed (also available as button.pressed)
655 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
676 preventDefault: true,
684 getAutoCreate : function(){
692 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
693 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
698 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
700 if (this.toggle == true) {
703 cls: 'slider-frame roo-button',
708 'data-off-text':'OFF',
709 cls: 'slider-button',
715 if (['default', 'secondary' , 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
716 cfg.cls += ' '+this.weight;
725 cfg["aria-hidden"] = true;
727 cfg.html = "×";
733 if (this.theme==='default') {
734 cfg.cls = 'btn roo-button';
736 //if (this.parentType != 'Navbar') {
737 this.weight = this.weight.length ? this.weight : 'default';
739 if (['default', 'primary', 'secondary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
741 var outline = this.outline || this.weight == 'default' ? 'outline-' : '';
742 var weight = this.weight == 'default' ? 'secondary' : this.weight;
743 cfg.cls += ' btn-' + outline + weight;
744 if (this.weight == 'default') {
746 cfg.cls += ' btn-' + this.weight;
749 } else if (this.theme==='glow') {
752 cfg.cls = 'btn-glow roo-button';
754 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
756 cfg.cls += ' ' + this.weight;
762 this.cls += ' inverse';
766 if (this.active || this.pressed === true) {
767 cfg.cls += ' active';
771 cfg.disabled = 'disabled';
775 Roo.log('changing to ul' );
777 this.glyphicon = 'caret';
778 if (Roo.bootstrap.version == 4) {
779 this.fa = 'caret-down';
784 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
786 //gsRoo.log(this.parentType);
787 if (this.parentType === 'Navbar' && !this.parent().bar) {
788 Roo.log('changing to li?');
797 href : this.href || '#'
800 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
801 cfg.cls += ' dropdown';
808 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
810 if (this.glyphicon) {
811 cfg.html = ' ' + cfg.html;
816 cls: 'glyphicon glyphicon-' + this.glyphicon
821 cfg.html = ' ' + cfg.html;
826 cls: 'fa fas fa-' + this.fa
836 // cfg.cls='btn roo-button';
840 var value = cfg.html;
845 cls: 'glyphicon glyphicon-' + this.glyphicon,
852 cls: 'fa fas fa-' + this.fa,
857 var bw = this.badge_weight.length ? this.badge_weight :
858 (this.weight.length ? this.weight : 'secondary');
859 bw = bw == 'default' ? 'secondary' : bw;
865 cls: 'badge badge-' + bw,
874 cfg.cls += ' dropdown';
875 cfg.html = typeof(cfg.html) != 'undefined' ?
876 cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
879 if (cfg.tag !== 'a' && this.href !== '') {
880 throw "Tag must be a to set href.";
881 } else if (this.href.length > 0) {
882 cfg.href = this.href;
885 if(this.removeClass){
890 cfg.target = this.target;
895 initEvents: function() {
896 // Roo.log('init events?');
897 // Roo.log(this.el.dom);
900 if (typeof (this.menu) != 'undefined') {
901 this.menu.parentType = this.xtype;
902 this.menu.triggerEl = this.el;
903 this.addxtype(Roo.apply({}, this.menu));
907 if (this.el.hasClass('roo-button')) {
908 this.el.on('click', this.onClick, this);
910 this.el.select('.roo-button').on('click', this.onClick, this);
913 if(this.removeClass){
914 this.el.on('click', this.onClick, this);
917 this.el.enableDisplayMode();
920 onClick : function(e)
926 Roo.log('button on click ');
927 if(this.preventDefault){
931 if (this.pressed === true || this.pressed === false) {
932 this.toggleActive(e);
936 this.fireEvent('click', this, e);
940 * Enables this button
944 this.disabled = false;
945 this.el.removeClass('disabled');
949 * Disable this button
953 this.disabled = true;
954 this.el.addClass('disabled');
957 * sets the active state on/off,
958 * @param {Boolean} state (optional) Force a particular state
960 setActive : function(v) {
962 this.el[v ? 'addClass' : 'removeClass']('active');
966 * toggles the current active state
968 toggleActive : function(e)
970 this.setActive(!this.pressed);
971 this.fireEvent('toggle', this, e, !this.pressed);
974 * get the current active state
975 * @return {boolean} true if it's active
977 isActive : function()
979 return this.el.hasClass('active');
982 * set the text of the first selected button
984 setText : function(str)
986 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
989 * get the text of the first selected button
993 return this.el.select('.roo-button-text',true).first().dom.innerHTML;
996 setWeight : function(str)
998 this.el.removeClass(this.weightClass);
1000 var outline = this.outline ? 'outline-' : '';
1001 if (str == 'default') {
1002 this.el.addClass('btn-default btn-outline-secondary');
1005 this.el.addClass('btn-' + outline + str);
1019 * @class Roo.bootstrap.Column
1020 * @extends Roo.bootstrap.Component
1021 * Bootstrap Column class
1022 * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
1023 * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
1024 * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
1025 * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
1026 * @cfg {Number} xsoff colspan offset out of 12 for mobile-sized screens or 0 for hidden
1027 * @cfg {Number} smoff colspan offset out of 12 for tablet-sized screens or 0 for hidden
1028 * @cfg {Number} mdoff colspan offset out of 12 for computer-sized screens or 0 for hidden
1029 * @cfg {Number} lgoff colspan offset out of 12 for large computer-sized screens or 0 for hidden
1032 * @cfg {Boolean} hidden (true|false) hide the element
1033 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
1034 * @cfg {String} fa (ban|check|...) font awesome icon
1035 * @cfg {Number} fasize (1|2|....) font awsome size
1037 * @cfg {String} icon (info-sign|check|...) glyphicon name
1039 * @cfg {String} html content of column.
1042 * Create a new Column
1043 * @param {Object} config The config object
1046 Roo.bootstrap.Column = function(config){
1047 Roo.bootstrap.Column.superclass.constructor.call(this, config);
1050 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
1068 getAutoCreate : function(){
1069 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
1077 ['xs','sm','md','lg'].map(function(size){
1078 //Roo.log( size + ':' + settings[size]);
1080 if (settings[size+'off'] !== false) {
1081 cfg.cls += ' col-' + size + '-offset-' + settings[size+'off'] ;
1084 if (settings[size] === false) {
1088 if (!settings[size]) { // 0 = hidden
1089 cfg.cls += ' hidden-' + size + ' hidden' + size + '-down';;
1092 cfg.cls += ' col-' + size + '-' + settings[size] + (
1093 size == 'xs' ? (' col-' + settings[size] ) : '' // bs4 col-{num} replaces col-xs
1099 cfg.cls += ' hidden';
1102 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1103 cfg.cls +=' alert alert-' + this.alert;
1107 if (this.html.length) {
1108 cfg.html = this.html;
1112 if (this.fasize > 1) {
1113 fasize = ' fa-' + this.fasize + 'x';
1115 cfg.html = '<i class="fa fa-'+this.fa + fasize + '"></i>' + (cfg.html || '');
1120 cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + (cfg.html || '');
1139 * @class Roo.bootstrap.Container
1140 * @extends Roo.bootstrap.Component
1141 * Bootstrap Container class
1142 * @cfg {Boolean} jumbotron is it a jumbotron element
1143 * @cfg {String} html content of element
1144 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
1145 * @cfg {String} panel (default|primary|success|info|warning|danger) render as panel - type - primary/success.....
1146 * @cfg {String} header content of header (for panel)
1147 * @cfg {String} footer content of footer (for panel)
1148 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
1149 * @cfg {String} tag (header|aside|section) type of HTML tag.
1150 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
1151 * @cfg {String} fa font awesome icon
1152 * @cfg {String} icon (info-sign|check|...) glyphicon name
1153 * @cfg {Boolean} hidden (true|false) hide the element
1154 * @cfg {Boolean} expandable (true|false) default false
1155 * @cfg {Boolean} expanded (true|false) default true
1156 * @cfg {String} rheader contet on the right of header
1157 * @cfg {Boolean} clickable (true|false) default false
1161 * Create a new Container
1162 * @param {Object} config The config object
1165 Roo.bootstrap.Container = function(config){
1166 Roo.bootstrap.Container.superclass.constructor.call(this, config);
1172 * After the panel has been expand
1174 * @param {Roo.bootstrap.Container} this
1179 * After the panel has been collapsed
1181 * @param {Roo.bootstrap.Container} this
1186 * When a element is chick
1187 * @param {Roo.bootstrap.Container} this
1188 * @param {Roo.EventObject} e
1194 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
1212 getChildContainer : function() {
1218 if (this.panel.length) {
1219 return this.el.select('.panel-body',true).first();
1226 getAutoCreate : function(){
1229 tag : this.tag || 'div',
1233 if (this.jumbotron) {
1234 cfg.cls = 'jumbotron';
1239 // - this is applied by the parent..
1241 // cfg.cls = this.cls + '';
1244 if (this.sticky.length) {
1246 var bd = Roo.get(document.body);
1247 if (!bd.hasClass('bootstrap-sticky')) {
1248 bd.addClass('bootstrap-sticky');
1249 Roo.select('html',true).setStyle('height', '100%');
1252 cfg.cls += 'bootstrap-sticky-' + this.sticky;
1256 if (this.well.length) {
1257 switch (this.well) {
1260 cfg.cls +=' well well-' +this.well;
1269 cfg.cls += ' hidden';
1273 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1274 cfg.cls +=' alert alert-' + this.alert;
1279 if (this.panel.length) {
1280 cfg.cls += ' panel panel-' + this.panel;
1282 if (this.header.length) {
1286 if(this.expandable){
1288 cfg.cls = cfg.cls + ' expandable';
1292 cls: (this.expanded ? 'fa fa-minus' : 'fa fa-plus')
1300 cls : 'panel-title',
1301 html : (this.expandable ? ' ' : '') + this.header
1305 cls: 'panel-header-right',
1311 cls : 'panel-heading',
1312 style : this.expandable ? 'cursor: pointer' : '',
1320 cls : 'panel-body' + (this.expanded ? '' : ' hide'),
1325 if (this.footer.length) {
1327 cls : 'panel-footer',
1336 body.html = this.html || cfg.html;
1337 // prefix with the icons..
1339 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1342 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1347 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1348 cfg.cls = 'container';
1354 initEvents: function()
1356 if(this.expandable){
1357 var headerEl = this.headerEl();
1360 headerEl.on('click', this.onToggleClick, this);
1365 this.el.on('click', this.onClick, this);
1370 onToggleClick : function()
1372 var headerEl = this.headerEl();
1388 if(this.fireEvent('expand', this)) {
1390 this.expanded = true;
1392 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).show();
1394 this.el.select('.panel-body',true).first().removeClass('hide');
1396 var toggleEl = this.toggleEl();
1402 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-minus']);
1407 collapse : function()
1409 if(this.fireEvent('collapse', this)) {
1411 this.expanded = false;
1413 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).hide();
1414 this.el.select('.panel-body',true).first().addClass('hide');
1416 var toggleEl = this.toggleEl();
1422 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-plus']);
1426 toggleEl : function()
1428 if(!this.el || !this.panel.length || !this.header.length || !this.expandable){
1432 return this.el.select('.panel-heading .fa',true).first();
1435 headerEl : function()
1437 if(!this.el || !this.panel.length || !this.header.length){
1441 return this.el.select('.panel-heading',true).first()
1446 if(!this.el || !this.panel.length){
1450 return this.el.select('.panel-body',true).first()
1453 titleEl : function()
1455 if(!this.el || !this.panel.length || !this.header.length){
1459 return this.el.select('.panel-title',true).first();
1462 setTitle : function(v)
1464 var titleEl = this.titleEl();
1470 titleEl.dom.innerHTML = v;
1473 getTitle : function()
1476 var titleEl = this.titleEl();
1482 return titleEl.dom.innerHTML;
1485 setRightTitle : function(v)
1487 var t = this.el.select('.panel-header-right',true).first();
1493 t.dom.innerHTML = v;
1496 onClick : function(e)
1500 this.fireEvent('click', this, e);
1513 * @class Roo.bootstrap.Img
1514 * @extends Roo.bootstrap.Component
1515 * Bootstrap Img class
1516 * @cfg {Boolean} imgResponsive false | true
1517 * @cfg {String} border rounded | circle | thumbnail
1518 * @cfg {String} src image source
1519 * @cfg {String} alt image alternative text
1520 * @cfg {String} href a tag href
1521 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1522 * @cfg {String} xsUrl xs image source
1523 * @cfg {String} smUrl sm image source
1524 * @cfg {String} mdUrl md image source
1525 * @cfg {String} lgUrl lg image source
1528 * Create a new Input
1529 * @param {Object} config The config object
1532 Roo.bootstrap.Img = function(config){
1533 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1539 * The img click event for the img.
1540 * @param {Roo.EventObject} e
1546 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1548 imgResponsive: true,
1558 getAutoCreate : function()
1560 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1561 return this.createSingleImg();
1566 cls: 'roo-image-responsive-group',
1571 Roo.each(['xs', 'sm', 'md', 'lg'], function(size){
1573 if(!_this[size + 'Url']){
1579 cls: (_this.imgResponsive) ? 'img-responsive' : '',
1580 html: _this.html || cfg.html,
1581 src: _this[size + 'Url']
1584 img.cls += ' roo-image-responsive-' + size;
1586 var s = ['xs', 'sm', 'md', 'lg'];
1588 s.splice(s.indexOf(size), 1);
1590 Roo.each(s, function(ss){
1591 img.cls += ' hidden-' + ss;
1594 if (['rounded','circle','thumbnail'].indexOf(_this.border)>-1) {
1595 cfg.cls += ' img-' + _this.border;
1599 cfg.alt = _this.alt;
1612 a.target = _this.target;
1616 cfg.cn.push((_this.href) ? a : img);
1623 createSingleImg : function()
1627 cls: (this.imgResponsive) ? 'img-responsive' : '',
1629 src : 'about:blank' // just incase src get's set to undefined?!?
1632 cfg.html = this.html || cfg.html;
1634 cfg.src = this.src || cfg.src;
1636 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1637 cfg.cls += ' img-' + this.border;
1654 a.target = this.target;
1659 return (this.href) ? a : cfg;
1662 initEvents: function()
1665 this.el.on('click', this.onClick, this);
1670 onClick : function(e)
1672 Roo.log('img onclick');
1673 this.fireEvent('click', this, e);
1676 * Sets the url of the image - used to update it
1677 * @param {String} url the url of the image
1680 setSrc : function(url)
1684 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1685 this.el.dom.src = url;
1689 this.el.select('img', true).first().dom.src = url;
1705 * @class Roo.bootstrap.Link
1706 * @extends Roo.bootstrap.Component
1707 * Bootstrap Link Class
1708 * @cfg {String} alt image alternative text
1709 * @cfg {String} href a tag href
1710 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1711 * @cfg {String} html the content of the link.
1712 * @cfg {String} anchor name for the anchor link
1713 * @cfg {String} fa - favicon
1715 * @cfg {Boolean} preventDefault (true | false) default false
1719 * Create a new Input
1720 * @param {Object} config The config object
1723 Roo.bootstrap.Link = function(config){
1724 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1730 * The img click event for the img.
1731 * @param {Roo.EventObject} e
1737 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1741 preventDefault: false,
1747 getAutoCreate : function()
1749 var html = this.html || '';
1751 if (this.fa !== false) {
1752 html = '<i class="fa fa-' + this.fa + '"></i>';
1757 // anchor's do not require html/href...
1758 if (this.anchor === false) {
1760 cfg.href = this.href || '#';
1762 cfg.name = this.anchor;
1763 if (this.html !== false || this.fa !== false) {
1766 if (this.href !== false) {
1767 cfg.href = this.href;
1771 if(this.alt !== false){
1776 if(this.target !== false) {
1777 cfg.target = this.target;
1783 initEvents: function() {
1785 if(!this.href || this.preventDefault){
1786 this.el.on('click', this.onClick, this);
1790 onClick : function(e)
1792 if(this.preventDefault){
1795 //Roo.log('img onclick');
1796 this.fireEvent('click', this, e);
1809 * @class Roo.bootstrap.Header
1810 * @extends Roo.bootstrap.Component
1811 * Bootstrap Header class
1812 * @cfg {String} html content of header
1813 * @cfg {Number} level (1|2|3|4|5|6) default 1
1816 * Create a new Header
1817 * @param {Object} config The config object
1821 Roo.bootstrap.Header = function(config){
1822 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1825 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1833 getAutoCreate : function(){
1838 tag: 'h' + (1 *this.level),
1839 html: this.html || ''
1851 * Ext JS Library 1.1.1
1852 * Copyright(c) 2006-2007, Ext JS, LLC.
1854 * Originally Released Under LGPL - original licence link has changed is not relivant.
1857 * <script type="text/javascript">
1861 * @class Roo.bootstrap.MenuMgr
1862 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1865 Roo.bootstrap.MenuMgr = function(){
1866 var menus, active, groups = {}, attached = false, lastShow = new Date();
1868 // private - called when first menu is created
1871 active = new Roo.util.MixedCollection();
1872 Roo.get(document).addKeyListener(27, function(){
1873 if(active.length > 0){
1881 if(active && active.length > 0){
1882 var c = active.clone();
1892 if(active.length < 1){
1893 Roo.get(document).un("mouseup", onMouseDown);
1901 var last = active.last();
1902 lastShow = new Date();
1905 Roo.get(document).on("mouseup", onMouseDown);
1910 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1911 m.parentMenu.activeChild = m;
1912 }else if(last && last.isVisible()){
1913 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1918 function onBeforeHide(m){
1920 m.activeChild.hide();
1922 if(m.autoHideTimer){
1923 clearTimeout(m.autoHideTimer);
1924 delete m.autoHideTimer;
1929 function onBeforeShow(m){
1930 var pm = m.parentMenu;
1931 if(!pm && !m.allowOtherMenus){
1933 }else if(pm && pm.activeChild && active != m){
1934 pm.activeChild.hide();
1938 // private this should really trigger on mouseup..
1939 function onMouseDown(e){
1940 Roo.log("on Mouse Up");
1942 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".dropdown-menu") && !e.getTarget('.user-menu')){
1943 Roo.log("MenuManager hideAll");
1952 function onBeforeCheck(mi, state){
1954 var g = groups[mi.group];
1955 for(var i = 0, l = g.length; i < l; i++){
1957 g[i].setChecked(false);
1966 * Hides all menus that are currently visible
1968 hideAll : function(){
1973 register : function(menu){
1977 menus[menu.id] = menu;
1978 menu.on("beforehide", onBeforeHide);
1979 menu.on("hide", onHide);
1980 menu.on("beforeshow", onBeforeShow);
1981 menu.on("show", onShow);
1983 if(g && menu.events["checkchange"]){
1987 groups[g].push(menu);
1988 menu.on("checkchange", onCheck);
1993 * Returns a {@link Roo.menu.Menu} object
1994 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1995 * be used to generate and return a new Menu instance.
1997 get : function(menu){
1998 if(typeof menu == "string"){ // menu id
2000 }else if(menu.events){ // menu instance
2003 /*else if(typeof menu.length == 'number'){ // array of menu items?
2004 return new Roo.bootstrap.Menu({items:menu});
2005 }else{ // otherwise, must be a config
2006 return new Roo.bootstrap.Menu(menu);
2013 unregister : function(menu){
2014 delete menus[menu.id];
2015 menu.un("beforehide", onBeforeHide);
2016 menu.un("hide", onHide);
2017 menu.un("beforeshow", onBeforeShow);
2018 menu.un("show", onShow);
2020 if(g && menu.events["checkchange"]){
2021 groups[g].remove(menu);
2022 menu.un("checkchange", onCheck);
2027 registerCheckable : function(menuItem){
2028 var g = menuItem.group;
2033 groups[g].push(menuItem);
2034 menuItem.on("beforecheckchange", onBeforeCheck);
2039 unregisterCheckable : function(menuItem){
2040 var g = menuItem.group;
2042 groups[g].remove(menuItem);
2043 menuItem.un("beforecheckchange", onBeforeCheck);
2055 * @class Roo.bootstrap.Menu
2056 * @extends Roo.bootstrap.Component
2057 * Bootstrap Menu class - container for MenuItems
2058 * @cfg {String} type (dropdown|treeview|submenu) type of menu
2059 * @cfg {bool} hidden if the menu should be hidden when rendered.
2060 * @cfg {bool} stopEvent (true|false) Stop event after trigger press (default true)
2061 * @cfg {bool} isLink (true|false) the menu has link disable auto expand and collaspe (default false)
2065 * @param {Object} config The config object
2069 Roo.bootstrap.Menu = function(config){
2070 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
2071 if (this.registerMenu && this.type != 'treeview') {
2072 Roo.bootstrap.MenuMgr.register(this);
2079 * Fires before this menu is displayed (return false to block)
2080 * @param {Roo.menu.Menu} this
2085 * Fires before this menu is hidden (return false to block)
2086 * @param {Roo.menu.Menu} this
2091 * Fires after this menu is displayed
2092 * @param {Roo.menu.Menu} this
2097 * Fires after this menu is hidden
2098 * @param {Roo.menu.Menu} this
2103 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
2104 * @param {Roo.menu.Menu} this
2105 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2106 * @param {Roo.EventObject} e
2111 * Fires when the mouse is hovering over this menu
2112 * @param {Roo.menu.Menu} this
2113 * @param {Roo.EventObject} e
2114 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2119 * Fires when the mouse exits this menu
2120 * @param {Roo.menu.Menu} this
2121 * @param {Roo.EventObject} e
2122 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2127 * Fires when a menu item contained in this menu is clicked
2128 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
2129 * @param {Roo.EventObject} e
2133 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
2136 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
2140 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
2143 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
2145 registerMenu : true,
2147 menuItems :false, // stores the menu items..
2157 getChildContainer : function() {
2161 getAutoCreate : function(){
2163 //if (['right'].indexOf(this.align)!==-1) {
2164 // cfg.cn[1].cls += ' pull-right'
2170 cls : 'dropdown-menu' ,
2171 style : 'z-index:1000'
2175 if (this.type === 'submenu') {
2176 cfg.cls = 'submenu active';
2178 if (this.type === 'treeview') {
2179 cfg.cls = 'treeview-menu';
2184 initEvents : function() {
2186 // Roo.log("ADD event");
2187 // Roo.log(this.triggerEl.dom);
2189 this.triggerEl.on('click', this.onTriggerClick, this);
2191 this.triggerEl.on(Roo.isTouch ? 'touchstart' : 'mouseup', this.onTriggerPress, this);
2194 if (this.triggerEl.hasClass('nav-item')) {
2195 // dropdown toggle on the 'a' in BS4?
2196 this.triggerEl.select('.nav-link',true).first().addClass('dropdown-toggle');
2198 this.triggerEl.addClass('dropdown-toggle');
2201 this.el.on('touchstart' , this.onTouch, this);
2203 this.el.on('click' , this.onClick, this);
2205 this.el.on("mouseover", this.onMouseOver, this);
2206 this.el.on("mouseout", this.onMouseOut, this);
2210 findTargetItem : function(e)
2212 var t = e.getTarget(".dropdown-menu-item", this.el, true);
2216 //Roo.log(t); Roo.log(t.id);
2218 //Roo.log(this.menuitems);
2219 return this.menuitems.get(t.id);
2221 //return this.items.get(t.menuItemId);
2227 onTouch : function(e)
2229 Roo.log("menu.onTouch");
2230 //e.stopEvent(); this make the user popdown broken
2234 onClick : function(e)
2236 Roo.log("menu.onClick");
2238 var t = this.findTargetItem(e);
2239 if(!t || t.isContainer){
2244 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
2245 if(t == this.activeItem && t.shouldDeactivate(e)){
2246 this.activeItem.deactivate();
2247 delete this.activeItem;
2251 this.setActiveItem(t, true);
2259 Roo.log('pass click event');
2263 this.fireEvent("click", this, t, e);
2267 if(!t.href.length || t.href == '#'){
2268 (function() { _this.hide(); }).defer(100);
2273 onMouseOver : function(e){
2274 var t = this.findTargetItem(e);
2277 // if(t.canActivate && !t.disabled){
2278 // this.setActiveItem(t, true);
2282 this.fireEvent("mouseover", this, e, t);
2284 isVisible : function(){
2285 return !this.hidden;
2287 onMouseOut : function(e){
2288 var t = this.findTargetItem(e);
2291 // if(t == this.activeItem && t.shouldDeactivate(e)){
2292 // this.activeItem.deactivate();
2293 // delete this.activeItem;
2296 this.fireEvent("mouseout", this, e, t);
2301 * Displays this menu relative to another element
2302 * @param {String/HTMLElement/Roo.Element} element The element to align to
2303 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
2304 * the element (defaults to this.defaultAlign)
2305 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2307 show : function(el, pos, parentMenu)
2309 if (false === this.fireEvent("beforeshow", this)) {
2310 Roo.log("show canceled");
2313 this.parentMenu = parentMenu;
2318 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
2321 * Displays this menu at a specific xy position
2322 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
2323 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2325 showAt : function(xy, parentMenu, /* private: */_e){
2326 this.parentMenu = parentMenu;
2331 this.fireEvent("beforeshow", this);
2332 //xy = this.el.adjustForConstraints(xy);
2336 this.hideMenuItems();
2337 this.hidden = false;
2338 this.triggerEl.addClass('open');
2339 this.el.addClass('show');
2341 // reassign x when hitting right
2342 if(this.el.getWidth() + xy[0] >= Roo.lib.Dom.getViewWidth()){
2343 xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
2346 // reassign y when hitting bottom
2347 if(this.el.getHeight() + xy[1] >= Roo.lib.Dom.getViewHeight()){
2348 xy[1] = xy[1] - this.el.getHeight() - this.triggerEl.getHeight();
2351 // but the list may align on trigger left or trigger top... should it be a properity?
2353 if(this.el.getStyle('top') != 'auto' && this.el.getStyle('top').slice(-1) != "%"){
2358 this.fireEvent("show", this);
2364 this.doFocus.defer(50, this);
2368 doFocus : function(){
2370 this.focusEl.focus();
2375 * Hides this menu and optionally all parent menus
2376 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
2378 hide : function(deep)
2380 if (false === this.fireEvent("beforehide", this)) {
2381 Roo.log("hide canceled");
2384 this.hideMenuItems();
2385 if(this.el && this.isVisible()){
2387 if(this.activeItem){
2388 this.activeItem.deactivate();
2389 this.activeItem = null;
2391 this.triggerEl.removeClass('open');;
2392 this.el.removeClass('show');
2394 this.fireEvent("hide", this);
2396 if(deep === true && this.parentMenu){
2397 this.parentMenu.hide(true);
2401 onTriggerClick : function(e)
2403 Roo.log('trigger click');
2405 var target = e.getTarget();
2407 Roo.log(target.nodeName.toLowerCase());
2409 if(target.nodeName.toLowerCase() === 'i'){
2415 onTriggerPress : function(e)
2417 Roo.log('trigger press');
2418 //Roo.log(e.getTarget());
2419 // Roo.log(this.triggerEl.dom);
2421 // trigger only occurs on normal menu's -- if it's a treeview or dropdown... do not hide/show..
2422 var pel = Roo.get(e.getTarget());
2423 if (pel.findParent('.dropdown-menu') || pel.findParent('.treeview-menu') ) {
2424 Roo.log('is treeview or dropdown?');
2428 if(e.getTarget().nodeName.toLowerCase() !== 'i' && this.isLink){
2432 if (this.isVisible()) {
2437 this.show(this.triggerEl, '?', false);
2440 if(this.stopEvent || e.getTarget().nodeName.toLowerCase() === 'i'){
2447 hideMenuItems : function()
2449 Roo.log("hide Menu Items");
2454 this.el.select('.open',true).each(function(aa) {
2456 aa.removeClass('open');
2460 addxtypeChild : function (tree, cntr) {
2461 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
2463 this.menuitems.add(comp);
2475 this.getEl().dom.innerHTML = '';
2476 this.menuitems.clear();
2490 * @class Roo.bootstrap.MenuItem
2491 * @extends Roo.bootstrap.Component
2492 * Bootstrap MenuItem class
2493 * @cfg {String} html the menu label
2494 * @cfg {String} href the link
2495 * @cfg {Boolean} preventDefault do not trigger A href on clicks (default false).
2496 * @cfg {Boolean} isContainer is it a container - just returns a drop down item..
2497 * @cfg {Boolean} active used on sidebars to highlight active itesm
2498 * @cfg {String} fa favicon to show on left of menu item.
2499 * @cfg {Roo.bootsrap.Menu} menu the child menu.
2503 * Create a new MenuItem
2504 * @param {Object} config The config object
2508 Roo.bootstrap.MenuItem = function(config){
2509 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
2514 * The raw click event for the entire grid.
2515 * @param {Roo.bootstrap.MenuItem} this
2516 * @param {Roo.EventObject} e
2522 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
2526 preventDefault: false,
2527 isContainer : false,
2531 getAutoCreate : function(){
2533 if(this.isContainer){
2536 cls: 'dropdown-menu-item '
2546 cls : 'dropdown-item',
2551 if (this.fa !== false) {
2554 cls : 'fa fa-' + this.fa
2563 cls: 'dropdown-menu-item',
2566 if (this.parent().type == 'treeview') {
2567 cfg.cls = 'treeview-menu';
2570 cfg.cls += ' active';
2575 anc.href = this.href || cfg.cn[0].href ;
2576 ctag.html = this.html || cfg.cn[0].html ;
2580 initEvents: function()
2582 if (this.parent().type == 'treeview') {
2583 this.el.select('a').on('click', this.onClick, this);
2587 this.menu.parentType = this.xtype;
2588 this.menu.triggerEl = this.el;
2589 this.menu = this.addxtype(Roo.apply({}, this.menu));
2593 onClick : function(e)
2595 Roo.log('item on click ');
2597 if(this.preventDefault){
2600 //this.parent().hideMenuItems();
2602 this.fireEvent('click', this, e);
2621 * @class Roo.bootstrap.MenuSeparator
2622 * @extends Roo.bootstrap.Component
2623 * Bootstrap MenuSeparator class
2626 * Create a new MenuItem
2627 * @param {Object} config The config object
2631 Roo.bootstrap.MenuSeparator = function(config){
2632 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2635 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2637 getAutoCreate : function(){
2656 * @class Roo.bootstrap.Modal
2657 * @extends Roo.bootstrap.Component
2658 * Bootstrap Modal class
2659 * @cfg {String} title Title of dialog
2660 * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2661 * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method adn
2662 * @cfg {Boolean} specificTitle default false
2663 * @cfg {Array} buttons Array of buttons or standard button set..
2664 * @cfg {String} buttonPosition (left|right|center) default right (DEPRICATED) - use mr-auto on buttons to put them on the left
2665 * @cfg {Boolean} animate default true
2666 * @cfg {Boolean} allow_close default true
2667 * @cfg {Boolean} fitwindow default false
2668 * @cfg {String} size (sm|lg) default empty
2669 * @cfg {Number} max_width set the max width of modal
2673 * Create a new Modal Dialog
2674 * @param {Object} config The config object
2677 Roo.bootstrap.Modal = function(config){
2678 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2683 * The raw btnclick event for the button
2684 * @param {Roo.EventObject} e
2689 * Fire when dialog resize
2690 * @param {Roo.bootstrap.Modal} this
2691 * @param {Roo.EventObject} e
2695 this.buttons = this.buttons || [];
2698 this.tmpl = Roo.factory(this.tmpl);
2703 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2705 title : 'test dialog',
2715 specificTitle: false,
2717 buttonPosition: 'right',
2740 onRender : function(ct, position)
2742 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2745 var cfg = Roo.apply({}, this.getAutoCreate());
2748 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2750 //if (!cfg.name.length) {
2754 cfg.cls += ' ' + this.cls;
2757 cfg.style = this.style;
2759 this.el = Roo.get(document.body).createChild(cfg, position);
2761 //var type = this.el.dom.type;
2764 if(this.tabIndex !== undefined){
2765 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2768 this.dialogEl = this.el.select('.modal-dialog',true).first();
2769 this.bodyEl = this.el.select('.modal-body',true).first();
2770 this.closeEl = this.el.select('.modal-header .close', true).first();
2771 this.headerEl = this.el.select('.modal-header',true).first();
2772 this.titleEl = this.el.select('.modal-title',true).first();
2773 this.footerEl = this.el.select('.modal-footer',true).first();
2775 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2777 //this.el.addClass("x-dlg-modal");
2779 if (this.buttons.length) {
2780 Roo.each(this.buttons, function(bb) {
2781 var b = Roo.apply({}, bb);
2782 b.xns = b.xns || Roo.bootstrap;
2783 b.xtype = b.xtype || 'Button';
2784 if (typeof(b.listeners) == 'undefined') {
2785 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2788 var btn = Roo.factory(b);
2790 btn.render(this.getButtonContainer());
2794 // render the children.
2797 if(typeof(this.items) != 'undefined'){
2798 var items = this.items;
2801 for(var i =0;i < items.length;i++) {
2802 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2806 this.items = nitems;
2808 // where are these used - they used to be body/close/footer
2812 //this.el.addClass([this.fieldClass, this.cls]);
2816 getAutoCreate : function()
2820 html : this.html || ''
2825 cls : 'modal-title',
2829 if(this.specificTitle){
2835 if (this.allow_close && Roo.bootstrap.version == 3) {
2845 if (this.allow_close && Roo.bootstrap.version == 4) {
2855 if(this.size.length){
2856 size = 'modal-' + this.size;
2859 var footer = Roo.bootstrap.version == 3 ?
2861 cls : 'modal-footer',
2865 cls: 'btn-' + this.buttonPosition
2870 { // BS4 uses mr-auto on left buttons....
2871 cls : 'modal-footer'
2882 cls: "modal-dialog " + size,
2885 cls : "modal-content",
2888 cls : 'modal-header',
2903 modal.cls += ' fade';
2909 getChildContainer : function() {
2914 getButtonContainer : function() {
2916 return Roo.bootstrap.version == 4 ?
2917 this.el.select('.modal-footer',true).first()
2918 : this.el.select('.modal-footer div',true).first();
2921 initEvents : function()
2923 if (this.allow_close) {
2924 this.closeEl.on('click', this.hide, this);
2926 Roo.EventManager.onWindowResize(this.resize, this, true);
2934 this.maskEl.setSize(
2935 Roo.lib.Dom.getViewWidth(true),
2936 Roo.lib.Dom.getViewHeight(true)
2939 if (this.fitwindow) {
2943 this.width || Roo.lib.Dom.getViewportWidth(true) - 30,
2944 this.height || Roo.lib.Dom.getViewportHeight(true) // catering margin-top 30 margin-bottom 30
2949 if(this.max_width !== 0) {
2951 var w = Math.min(this.max_width, Roo.lib.Dom.getViewportWidth(true) - 30);
2954 this.setSize(w, this.height);
2958 if(this.max_height) {
2959 this.setSize(w,Math.min(
2961 Roo.lib.Dom.getViewportHeight(true) - 60
2967 if(!this.fit_content) {
2968 this.setSize(w, Roo.lib.Dom.getViewportHeight(true) - 60);
2972 this.setSize(w, Math.min(
2974 this.headerEl.getHeight() +
2975 this.footerEl.getHeight() +
2976 this.getChildHeight(this.bodyEl.dom.childNodes),
2977 Roo.lib.Dom.getViewportHeight(true) - 60)
2983 setSize : function(w,h)
2994 if (!this.rendered) {
2998 //this.el.setStyle('display', 'block');
2999 this.el.removeClass('hideing');
3000 this.el.dom.style.display='block';
3002 Roo.get(document.body).addClass('modal-open');
3004 if(this.animate){ // element has 'fade' - so stuff happens after .3s ?- not sure why the delay?
3007 this.el.addClass('show');
3008 this.el.addClass('in');
3011 this.el.addClass('show');
3012 this.el.addClass('in');
3015 // not sure how we can show data in here..
3017 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
3020 Roo.get(document.body).addClass("x-body-masked");
3022 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
3023 this.maskEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
3024 this.maskEl.dom.style.display = 'block';
3025 this.maskEl.addClass('show');
3030 this.fireEvent('show', this);
3032 // set zindex here - otherwise it appears to be ignored...
3033 this.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
3036 this.items.forEach( function(e) {
3037 e.layout ? e.layout() : false;
3045 if(this.fireEvent("beforehide", this) !== false){
3047 this.maskEl.removeClass('show');
3049 this.maskEl.dom.style.display = '';
3050 Roo.get(document.body).removeClass("x-body-masked");
3051 this.el.removeClass('in');
3052 this.el.select('.modal-dialog', true).first().setStyle('transform','');
3054 if(this.animate){ // why
3055 this.el.addClass('hideing');
3056 this.el.removeClass('show');
3058 if (!this.el.hasClass('hideing')) {
3059 return; // it's been shown again...
3062 this.el.dom.style.display='';
3064 Roo.get(document.body).removeClass('modal-open');
3065 this.el.removeClass('hideing');
3069 this.el.removeClass('show');
3070 this.el.dom.style.display='';
3071 Roo.get(document.body).removeClass('modal-open');
3074 this.fireEvent('hide', this);
3077 isVisible : function()
3080 return this.el.hasClass('show') && !this.el.hasClass('hideing');
3084 addButton : function(str, cb)
3088 var b = Roo.apply({}, { html : str } );
3089 b.xns = b.xns || Roo.bootstrap;
3090 b.xtype = b.xtype || 'Button';
3091 if (typeof(b.listeners) == 'undefined') {
3092 b.listeners = { click : cb.createDelegate(this) };
3095 var btn = Roo.factory(b);
3097 btn.render(this.getButtonContainer());
3103 setDefaultButton : function(btn)
3105 //this.el.select('.modal-footer').()
3108 resizeTo: function(w,h)
3110 this.dialogEl.setWidth(w);
3112 var diff = this.headerEl.getHeight() + this.footerEl.getHeight() + 60; // dialog margin-bottom: 30
3114 this.bodyEl.setHeight(h - diff);
3116 this.fireEvent('resize', this);
3119 setContentSize : function(w, h)
3123 onButtonClick: function(btn,e)
3126 this.fireEvent('btnclick', btn.name, e);
3129 * Set the title of the Dialog
3130 * @param {String} str new Title
3132 setTitle: function(str) {
3133 this.titleEl.dom.innerHTML = str;
3136 * Set the body of the Dialog
3137 * @param {String} str new Title
3139 setBody: function(str) {
3140 this.bodyEl.dom.innerHTML = str;
3143 * Set the body of the Dialog using the template
3144 * @param {Obj} data - apply this data to the template and replace the body contents.
3146 applyBody: function(obj)
3149 Roo.log("Error - using apply Body without a template");
3152 this.tmpl.overwrite(this.bodyEl, obj);
3155 getChildHeight : function(child_nodes)
3159 child_nodes.length == 0
3164 var child_height = 0;
3166 for(var i = 0; i < child_nodes.length; i++) {
3169 * for modal with tabs...
3170 if(child_nodes[i].classList.contains('roo-layout-panel')) {
3172 var layout_childs = child_nodes[i].childNodes;
3174 for(var j = 0; j < layout_childs.length; j++) {
3176 if(layout_childs[j].classList.contains('roo-layout-panel-body')) {
3178 var layout_body_childs = layout_childs[j].childNodes;
3180 for(var k = 0; k < layout_body_childs.length; k++) {
3182 if(layout_body_childs[k].classList.contains('navbar')) {
3183 child_height += layout_body_childs[k].offsetHeight;
3187 if(layout_body_childs[k].classList.contains('roo-layout-tabs-body')) {
3189 var layout_body_tab_childs = layout_body_childs[k].childNodes;
3191 for(var m = 0; m < layout_body_tab_childs.length; m++) {
3193 if(layout_body_tab_childs[m].classList.contains('roo-layout-active-content')) {
3194 child_height += this.getChildHeight(layout_body_tab_childs[m].childNodes);
3209 child_height += child_nodes[i].offsetHeight;
3210 // Roo.log(child_nodes[i].offsetHeight);
3213 return child_height;
3219 Roo.apply(Roo.bootstrap.Modal, {
3221 * Button config that displays a single OK button
3230 * Button config that displays Yes and No buttons
3246 * Button config that displays OK and Cancel buttons
3261 * Button config that displays Yes, No and Cancel buttons
3285 * messagebox - can be used as a replace
3289 * @class Roo.MessageBox
3290 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
3294 Roo.Msg.alert('Status', 'Changes saved successfully.');
3296 // Prompt for user data:
3297 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
3299 // process text value...
3303 // Show a dialog using config options:
3305 title:'Save Changes?',
3306 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
3307 buttons: Roo.Msg.YESNOCANCEL,
3314 Roo.bootstrap.MessageBox = function(){
3315 var dlg, opt, mask, waitTimer;
3316 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
3317 var buttons, activeTextEl, bwidth;
3321 var handleButton = function(button){
3323 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
3327 var handleHide = function(){
3329 dlg.el.removeClass(opt.cls);
3332 // Roo.TaskMgr.stop(waitTimer);
3333 // waitTimer = null;
3338 var updateButtons = function(b){
3341 buttons["ok"].hide();
3342 buttons["cancel"].hide();
3343 buttons["yes"].hide();
3344 buttons["no"].hide();
3345 dlg.footerEl.hide();
3349 dlg.footerEl.show();
3350 for(var k in buttons){
3351 if(typeof buttons[k] != "function"){
3354 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
3355 width += buttons[k].el.getWidth()+15;
3365 var handleEsc = function(d, k, e){
3366 if(opt && opt.closable !== false){
3376 * Returns a reference to the underlying {@link Roo.BasicDialog} element
3377 * @return {Roo.BasicDialog} The BasicDialog element
3379 getDialog : function(){
3381 dlg = new Roo.bootstrap.Modal( {
3384 //constraintoviewport:false,
3386 //collapsible : false,
3391 //buttonAlign:"center",
3392 closeClick : function(){
3393 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
3396 handleButton("cancel");
3401 dlg.on("hide", handleHide);
3403 //dlg.addKeyListener(27, handleEsc);
3405 this.buttons = buttons;
3406 var bt = this.buttonText;
3407 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
3408 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
3409 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
3410 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
3412 bodyEl = dlg.bodyEl.createChild({
3414 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
3415 '<textarea class="roo-mb-textarea"></textarea>' +
3416 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
3418 msgEl = bodyEl.dom.firstChild;
3419 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
3420 textboxEl.enableDisplayMode();
3421 textboxEl.addKeyListener([10,13], function(){
3422 if(dlg.isVisible() && opt && opt.buttons){
3425 }else if(opt.buttons.yes){
3426 handleButton("yes");
3430 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
3431 textareaEl.enableDisplayMode();
3432 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
3433 progressEl.enableDisplayMode();
3435 // This is supposed to be the progessElement.. but I think it's controlling the height of everything..
3436 var pf = progressEl.dom.firstChild;
3438 pp = Roo.get(pf.firstChild);
3439 pp.setHeight(pf.offsetHeight);
3447 * Updates the message box body text
3448 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
3449 * the XHTML-compliant non-breaking space character '&#160;')
3450 * @return {Roo.MessageBox} This message box
3452 updateText : function(text)
3454 if(!dlg.isVisible() && !opt.width){
3455 dlg.dialogEl.setStyle({ 'max-width' : this.maxWidth});
3456 // dlg.resizeTo(this.maxWidth, 100); // forcing the height breaks long alerts()
3458 msgEl.innerHTML = text || ' ';
3460 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
3461 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
3463 Math.min(opt.width || cw , this.maxWidth),
3464 Math.max(opt.minWidth || this.minWidth, bwidth)
3467 activeTextEl.setWidth(w);
3469 if(dlg.isVisible()){
3470 dlg.fixedcenter = false;
3472 // to big, make it scroll. = But as usual stupid IE does not support
3475 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
3476 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
3477 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
3479 bodyEl.dom.style.height = '';
3480 bodyEl.dom.style.overflowY = '';
3483 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
3485 bodyEl.dom.style.overflowX = '';
3488 dlg.setContentSize(w, bodyEl.getHeight());
3489 if(dlg.isVisible()){
3490 dlg.fixedcenter = true;
3496 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
3497 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
3498 * @param {Number} value Any number between 0 and 1 (e.g., .5)
3499 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
3500 * @return {Roo.MessageBox} This message box
3502 updateProgress : function(value, text){
3504 this.updateText(text);
3507 if (pp) { // weird bug on my firefox - for some reason this is not defined
3508 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
3509 pp.setHeight(Math.floor(progressEl.dom.firstChild.offsetHeight));
3515 * Returns true if the message box is currently displayed
3516 * @return {Boolean} True if the message box is visible, else false
3518 isVisible : function(){
3519 return dlg && dlg.isVisible();
3523 * Hides the message box if it is displayed
3526 if(this.isVisible()){
3532 * Displays a new message box, or reinitializes an existing message box, based on the config options
3533 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
3534 * The following config object properties are supported:
3536 Property Type Description
3537 ---------- --------------- ------------------------------------------------------------------------------------
3538 animEl String/Element An id or Element from which the message box should animate as it opens and
3539 closes (defaults to undefined)
3540 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
3541 cancel:'Bar'}), or false to not show any buttons (defaults to false)
3542 closable Boolean False to hide the top-right close button (defaults to true). Note that
3543 progress and wait dialogs will ignore this property and always hide the
3544 close button as they can only be closed programmatically.
3545 cls String A custom CSS class to apply to the message box element
3546 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
3547 displayed (defaults to 75)
3548 fn Function A callback function to execute after closing the dialog. The arguments to the
3549 function will be btn (the name of the button that was clicked, if applicable,
3550 e.g. "ok"), and text (the value of the active text field, if applicable).
3551 Progress and wait dialogs will ignore this option since they do not respond to
3552 user actions and can only be closed programmatically, so any required function
3553 should be called by the same code after it closes the dialog.
3554 icon String A CSS class that provides a background image to be used as an icon for
3555 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
3556 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
3557 minWidth Number The minimum width in pixels of the message box (defaults to 100)
3558 modal Boolean False to allow user interaction with the page while the message box is
3559 displayed (defaults to true)
3560 msg String A string that will replace the existing message box body text (defaults
3561 to the XHTML-compliant non-breaking space character ' ')
3562 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
3563 progress Boolean True to display a progress bar (defaults to false)
3564 progressText String The text to display inside the progress bar if progress = true (defaults to '')
3565 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
3566 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
3567 title String The title text
3568 value String The string value to set into the active textbox element if displayed
3569 wait Boolean True to display a progress bar (defaults to false)
3570 width Number The width of the dialog in pixels
3577 msg: 'Please enter your address:',
3579 buttons: Roo.MessageBox.OKCANCEL,
3582 animEl: 'addAddressBtn'
3585 * @param {Object} config Configuration options
3586 * @return {Roo.MessageBox} This message box
3588 show : function(options)
3591 // this causes nightmares if you show one dialog after another
3592 // especially on callbacks..
3594 if(this.isVisible()){
3597 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
3598 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
3599 Roo.log("New Dialog Message:" + options.msg )
3600 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
3601 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
3604 var d = this.getDialog();
3606 d.setTitle(opt.title || " ");
3607 d.closeEl.setDisplayed(opt.closable !== false);
3608 activeTextEl = textboxEl;
3609 opt.prompt = opt.prompt || (opt.multiline ? true : false);
3614 textareaEl.setHeight(typeof opt.multiline == "number" ?
3615 opt.multiline : this.defaultTextHeight);
3616 activeTextEl = textareaEl;
3625 progressEl.setDisplayed(opt.progress === true);
3627 d.animate = false; // do not animate progress, as it may not have finished animating before we close it..
3629 this.updateProgress(0);
3630 activeTextEl.dom.value = opt.value || "";
3632 dlg.setDefaultButton(activeTextEl);
3634 var bs = opt.buttons;
3638 }else if(bs && bs.yes){
3639 db = buttons["yes"];
3641 dlg.setDefaultButton(db);
3643 bwidth = updateButtons(opt.buttons);
3644 this.updateText(opt.msg);
3646 d.el.addClass(opt.cls);
3648 d.proxyDrag = opt.proxyDrag === true;
3649 d.modal = opt.modal !== false;
3650 d.mask = opt.modal !== false ? mask : false;
3652 // force it to the end of the z-index stack so it gets a cursor in FF
3653 document.body.appendChild(dlg.el.dom);
3654 d.animateTarget = null;
3655 d.show(options.animEl);
3661 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
3662 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
3663 * and closing the message box when the process is complete.
3664 * @param {String} title The title bar text
3665 * @param {String} msg The message box body text
3666 * @return {Roo.MessageBox} This message box
3668 progress : function(title, msg){
3675 minWidth: this.minProgressWidth,
3682 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
3683 * If a callback function is passed it will be called after the user clicks the button, and the
3684 * id of the button that was clicked will be passed as the only parameter to the callback
3685 * (could also be the top-right close button).
3686 * @param {String} title The title bar text
3687 * @param {String} msg The message box body text
3688 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3689 * @param {Object} scope (optional) The scope of the callback function
3690 * @return {Roo.MessageBox} This message box
3692 alert : function(title, msg, fn, scope)
3707 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
3708 * interaction while waiting for a long-running process to complete that does not have defined intervals.
3709 * You are responsible for closing the message box when the process is complete.
3710 * @param {String} msg The message box body text
3711 * @param {String} title (optional) The title bar text
3712 * @return {Roo.MessageBox} This message box
3714 wait : function(msg, title){
3725 waitTimer = Roo.TaskMgr.start({
3727 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
3735 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
3736 * If a callback function is passed it will be called after the user clicks either button, and the id of the
3737 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
3738 * @param {String} title The title bar text
3739 * @param {String} msg The message box body text
3740 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3741 * @param {Object} scope (optional) The scope of the callback function
3742 * @return {Roo.MessageBox} This message box
3744 confirm : function(title, msg, fn, scope){
3748 buttons: this.YESNO,
3757 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
3758 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
3759 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
3760 * (could also be the top-right close button) and the text that was entered will be passed as the two
3761 * parameters to the callback.
3762 * @param {String} title The title bar text
3763 * @param {String} msg The message box body text
3764 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3765 * @param {Object} scope (optional) The scope of the callback function
3766 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
3767 * property, or the height in pixels to create the textbox (defaults to false / single-line)
3768 * @return {Roo.MessageBox} This message box
3770 prompt : function(title, msg, fn, scope, multiline){
3774 buttons: this.OKCANCEL,
3779 multiline: multiline,
3786 * Button config that displays a single OK button
3791 * Button config that displays Yes and No buttons
3794 YESNO : {yes:true, no:true},
3796 * Button config that displays OK and Cancel buttons
3799 OKCANCEL : {ok:true, cancel:true},
3801 * Button config that displays Yes, No and Cancel buttons
3804 YESNOCANCEL : {yes:true, no:true, cancel:true},
3807 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3810 defaultTextHeight : 75,
3812 * The maximum width in pixels of the message box (defaults to 600)
3817 * The minimum width in pixels of the message box (defaults to 100)
3822 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3823 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3826 minProgressWidth : 250,
3828 * An object containing the default button text strings that can be overriden for localized language support.
3829 * Supported properties are: ok, cancel, yes and no.
3830 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3843 * Shorthand for {@link Roo.MessageBox}
3845 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3846 Roo.Msg = Roo.Msg || Roo.MessageBox;
3855 * @class Roo.bootstrap.Navbar
3856 * @extends Roo.bootstrap.Component
3857 * Bootstrap Navbar class
3860 * Create a new Navbar
3861 * @param {Object} config The config object
3865 Roo.bootstrap.Navbar = function(config){
3866 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3870 * @event beforetoggle
3871 * Fire before toggle the menu
3872 * @param {Roo.EventObject} e
3874 "beforetoggle" : true
3878 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3887 getAutoCreate : function(){
3890 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3894 initEvents :function ()
3896 //Roo.log(this.el.select('.navbar-toggle',true));
3897 this.el.select('.navbar-toggle',true).on('click', this.onToggle , this);
3904 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3906 var size = this.el.getSize();
3907 this.maskEl.setSize(size.width, size.height);
3908 this.maskEl.enableDisplayMode("block");
3917 getChildContainer : function()
3919 if (this.el && this.el.select('.collapse').getCount()) {
3920 return this.el.select('.collapse',true).first();
3935 onToggle : function()
3938 if(this.fireEvent('beforetoggle', this) === false){
3941 var ce = this.el.select('.navbar-collapse',true).first();
3943 if (!ce.hasClass('show')) {
3953 * Expand the navbar pulldown
3955 expand : function ()
3958 var ce = this.el.select('.navbar-collapse',true).first();
3959 if (ce.hasClass('collapsing')) {
3962 ce.dom.style.height = '';
3964 ce.addClass('in'); // old...
3965 ce.removeClass('collapse');
3966 ce.addClass('show');
3967 var h = ce.getHeight();
3969 ce.removeClass('show');
3970 // at this point we should be able to see it..
3971 ce.addClass('collapsing');
3973 ce.setHeight(0); // resize it ...
3974 ce.on('transitionend', function() {
3975 //Roo.log('done transition');
3976 ce.removeClass('collapsing');
3977 ce.addClass('show');
3978 ce.removeClass('collapse');
3980 ce.dom.style.height = '';
3981 }, this, { single: true} );
3983 ce.dom.scrollTop = 0;
3986 * Collapse the navbar pulldown
3988 collapse : function()
3990 var ce = this.el.select('.navbar-collapse',true).first();
3992 if (ce.hasClass('collapsing') || ce.hasClass('collapse') ) {
3993 // it's collapsed or collapsing..
3996 ce.removeClass('in'); // old...
3997 ce.setHeight(ce.getHeight());
3998 ce.removeClass('show');
3999 ce.addClass('collapsing');
4001 ce.on('transitionend', function() {
4002 ce.dom.style.height = '';
4003 ce.removeClass('collapsing');
4004 ce.addClass('collapse');
4005 }, this, { single: true} );
4025 * @class Roo.bootstrap.NavSimplebar
4026 * @extends Roo.bootstrap.Navbar
4027 * Bootstrap Sidebar class
4029 * @cfg {Boolean} inverse is inverted color
4031 * @cfg {String} type (nav | pills | tabs)
4032 * @cfg {Boolean} arrangement stacked | justified
4033 * @cfg {String} align (left | right) alignment
4035 * @cfg {Boolean} main (true|false) main nav bar? default false
4036 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
4038 * @cfg {String} tag (header|footer|nav|div) default is nav
4040 * @cfg {String} weight (light|primary|secondary|success|danger|warning|info|dark|white) default is light.
4044 * Create a new Sidebar
4045 * @param {Object} config The config object
4049 Roo.bootstrap.NavSimplebar = function(config){
4050 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
4053 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
4069 getAutoCreate : function(){
4073 tag : this.tag || 'div',
4074 cls : 'navbar roo-navbar-simple' //navbar-expand-lg ??
4076 if (['light','white'].indexOf(this.weight) > -1) {
4077 cfg.cls += ['light','white'].indexOf(this.weight) > -1 ? ' navbar-light' : ' navbar-dark';
4079 cfg.cls += ' bg-' + this.weight;
4082 cfg.cls += ' navbar-inverse';
4086 // i'm not actually sure these are really used - normally we add a navGroup to a navbar
4088 if (Roo.bootstrap.version == 4 && this.xtype == 'NavSimplebar') {
4097 cls: 'nav nav-' + this.xtype,
4103 this.type = this.type || 'nav';
4104 if (['tabs','pills'].indexOf(this.type) != -1) {
4105 cfg.cn[0].cls += ' nav-' + this.type
4109 if (this.type!=='nav') {
4110 Roo.log('nav type must be nav/tabs/pills')
4112 cfg.cn[0].cls += ' navbar-nav'
4118 if (['stacked','justified'].indexOf(this.arrangement) != -1) {
4119 cfg.cn[0].cls += ' nav-' + this.arrangement;
4123 if (this.align === 'right') {
4124 cfg.cn[0].cls += ' navbar-right';
4149 * navbar-expand-md fixed-top
4153 * @class Roo.bootstrap.NavHeaderbar
4154 * @extends Roo.bootstrap.NavSimplebar
4155 * Bootstrap Sidebar class
4157 * @cfg {String} brand what is brand
4158 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
4159 * @cfg {String} brand_href href of the brand
4160 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
4161 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
4162 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
4163 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
4166 * Create a new Sidebar
4167 * @param {Object} config The config object
4171 Roo.bootstrap.NavHeaderbar = function(config){
4172 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
4176 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
4183 desktopCenter : false,
4186 getAutoCreate : function(){
4189 tag: this.nav || 'nav',
4190 cls: 'navbar navbar-expand-md',
4196 if (this.desktopCenter) {
4197 cn.push({cls : 'container', cn : []});
4205 cls: 'navbar-toggle navbar-toggler',
4206 'data-toggle': 'collapse',
4211 html: 'Toggle navigation'
4215 cls: 'icon-bar navbar-toggler-icon'
4228 cn.push( Roo.bootstrap.version == 4 ? btn : {
4230 cls: 'navbar-header',
4239 cls: Roo.bootstrap.version == 4 ? 'nav flex-row roo-navbar-collapse' : 'collapse navbar-collapse roo-navbar-collapse',
4243 cfg.cls += this.inverse ? ' navbar-inverse navbar-dark bg-dark' : ' navbar-default';
4245 if (['light','white'].indexOf(this.weight) > -1) {
4246 cfg.cls += ['light','white'].indexOf(this.weight) > -1 ? ' navbar-light' : ' navbar-dark';
4248 cfg.cls += ' bg-' + this.weight;
4251 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
4252 cfg.cls += ' navbar-' + this.position + ' ' + this.position ;
4254 // tag can override this..
4256 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
4259 if (this.brand !== '') {
4260 var cp = Roo.bootstrap.version == 4 ? cn : cn[0].cn;
4261 cp.unshift({ // changed from push ?? BS4 needs it at the start? - does this break or exsiting?
4263 href: this.brand_href ? this.brand_href : '#',
4264 cls: 'navbar-brand',
4272 cfg.cls += ' main-nav';
4280 getHeaderChildContainer : function()
4282 if (this.srButton && this.el.select('.navbar-header').getCount()) {
4283 return this.el.select('.navbar-header',true).first();
4286 return this.getChildContainer();
4290 initEvents : function()
4292 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
4294 if (this.autohide) {
4299 Roo.get(document).on('scroll',function(e) {
4300 var ns = Roo.get(document).getScroll().top;
4301 var os = prevScroll;
4305 ft.removeClass('slideDown');
4306 ft.addClass('slideUp');
4309 ft.removeClass('slideUp');
4310 ft.addClass('slideDown');
4331 * @class Roo.bootstrap.NavSidebar
4332 * @extends Roo.bootstrap.Navbar
4333 * Bootstrap Sidebar class
4336 * Create a new Sidebar
4337 * @param {Object} config The config object
4341 Roo.bootstrap.NavSidebar = function(config){
4342 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
4345 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
4347 sidebar : true, // used by Navbar Item and NavbarGroup at present...
4349 getAutoCreate : function(){
4354 cls: 'sidebar sidebar-nav'
4376 * @class Roo.bootstrap.NavGroup
4377 * @extends Roo.bootstrap.Component
4378 * Bootstrap NavGroup class
4379 * @cfg {String} align (left|right)
4380 * @cfg {Boolean} inverse
4381 * @cfg {String} type (nav|pills|tab) default nav
4382 * @cfg {String} navId - reference Id for navbar.
4386 * Create a new nav group
4387 * @param {Object} config The config object
4390 Roo.bootstrap.NavGroup = function(config){
4391 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
4394 Roo.bootstrap.NavGroup.register(this);
4398 * Fires when the active item changes
4399 * @param {Roo.bootstrap.NavGroup} this
4400 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
4401 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
4408 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
4419 getAutoCreate : function()
4421 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
4427 if (Roo.bootstrap.version == 4) {
4428 if (['tabs','pills'].indexOf(this.type) != -1) {
4429 cfg.cls += ' nav-' + this.type;
4431 // trying to remove so header bar can right align top?
4432 if (this.parent() && this.parent().xtype != 'NavHeaderbar') {
4433 // do not use on header bar...
4434 cfg.cls += ' navbar-nav';
4439 if (['tabs','pills'].indexOf(this.type) != -1) {
4440 cfg.cls += ' nav-' + this.type
4442 if (this.type !== 'nav') {
4443 Roo.log('nav type must be nav/tabs/pills')
4445 cfg.cls += ' navbar-nav'
4449 if (this.parent() && this.parent().sidebar) {
4452 cls: 'dashboard-menu sidebar-menu'
4458 if (this.form === true) {
4461 cls: 'navbar-form form-inline'
4463 //nav navbar-right ml-md-auto
4464 if (this.align === 'right') {
4465 cfg.cls += ' navbar-right ml-md-auto';
4467 cfg.cls += ' navbar-left';
4471 if (this.align === 'right') {
4472 cfg.cls += ' navbar-right ml-md-auto';
4474 cfg.cls += ' mr-auto';
4478 cfg.cls += ' navbar-inverse';
4486 * sets the active Navigation item
4487 * @param {Roo.bootstrap.NavItem} the new current navitem
4489 setActiveItem : function(item)
4492 Roo.each(this.navItems, function(v){
4497 v.setActive(false, true);
4504 item.setActive(true, true);
4505 this.fireEvent('changed', this, item, prev);
4510 * gets the active Navigation item
4511 * @return {Roo.bootstrap.NavItem} the current navitem
4513 getActive : function()
4517 Roo.each(this.navItems, function(v){
4528 indexOfNav : function()
4532 Roo.each(this.navItems, function(v,i){
4543 * adds a Navigation item
4544 * @param {Roo.bootstrap.NavItem} the navitem to add
4546 addItem : function(cfg)
4548 if (this.form && Roo.bootstrap.version == 4) {
4551 var cn = new Roo.bootstrap.NavItem(cfg);
4553 cn.parentId = this.id;
4554 cn.onRender(this.el, null);
4558 * register a Navigation item
4559 * @param {Roo.bootstrap.NavItem} the navitem to add
4561 register : function(item)
4563 this.navItems.push( item);
4564 item.navId = this.navId;
4569 * clear all the Navigation item
4572 clearAll : function()
4575 this.el.dom.innerHTML = '';
4578 getNavItem: function(tabId)
4581 Roo.each(this.navItems, function(e) {
4582 if (e.tabId == tabId) {
4592 setActiveNext : function()
4594 var i = this.indexOfNav(this.getActive());
4595 if (i > this.navItems.length) {
4598 this.setActiveItem(this.navItems[i+1]);
4600 setActivePrev : function()
4602 var i = this.indexOfNav(this.getActive());
4606 this.setActiveItem(this.navItems[i-1]);
4608 clearWasActive : function(except) {
4609 Roo.each(this.navItems, function(e) {
4610 if (e.tabId != except.tabId && e.was_active) {
4611 e.was_active = false;
4618 getWasActive : function ()
4621 Roo.each(this.navItems, function(e) {
4636 Roo.apply(Roo.bootstrap.NavGroup, {
4640 * register a Navigation Group
4641 * @param {Roo.bootstrap.NavGroup} the navgroup to add
4643 register : function(navgrp)
4645 this.groups[navgrp.navId] = navgrp;
4649 * fetch a Navigation Group based on the navigation ID
4650 * @param {string} the navgroup to add
4651 * @returns {Roo.bootstrap.NavGroup} the navgroup
4653 get: function(navId) {
4654 if (typeof(this.groups[navId]) == 'undefined') {
4656 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
4658 return this.groups[navId] ;
4673 * @class Roo.bootstrap.NavItem
4674 * @extends Roo.bootstrap.Component
4675 * Bootstrap Navbar.NavItem class
4676 * @cfg {String} href link to
4677 * @cfg {String} button_weight (default | primary | secondary | success | info | warning | danger | link ) default none
4679 * @cfg {String} html content of button
4680 * @cfg {String} badge text inside badge
4681 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
4682 * @cfg {String} glyphicon DEPRICATED - use fa
4683 * @cfg {String} icon DEPRICATED - use fa
4684 * @cfg {String} fa - Fontawsome icon name (can add stuff to it like fa-2x)
4685 * @cfg {Boolean} active Is item active
4686 * @cfg {Boolean} disabled Is item disabled
4688 * @cfg {Boolean} preventDefault (true | false) default false
4689 * @cfg {String} tabId the tab that this item activates.
4690 * @cfg {String} tagtype (a|span) render as a href or span?
4691 * @cfg {Boolean} animateRef (true|false) link to element default false
4694 * Create a new Navbar Item
4695 * @param {Object} config The config object
4697 Roo.bootstrap.NavItem = function(config){
4698 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
4703 * The raw click event for the entire grid.
4704 * @param {Roo.EventObject} e
4709 * Fires when the active item active state changes
4710 * @param {Roo.bootstrap.NavItem} this
4711 * @param {boolean} state the new state
4717 * Fires when scroll to element
4718 * @param {Roo.bootstrap.NavItem} this
4719 * @param {Object} options
4720 * @param {Roo.EventObject} e
4728 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
4737 preventDefault : false,
4745 button_outline : false,
4749 getAutoCreate : function(){
4757 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
4759 if (this.disabled) {
4760 cfg.cls += ' disabled';
4764 if (this.button_weight.length) {
4765 cfg.tag = this.href ? 'a' : 'button';
4766 cfg.html = this.html || '';
4767 cfg.cls += ' btn btn' + (this.button_outline ? '-outline' : '') + '-' + this.button_weight;
4769 cfg.href = this.href;
4772 cfg.html = '<i class="fa fas fa-'+this.fa+'"></i> <span>' + this.html + '</span>';
4775 // menu .. should add dropdown-menu class - so no need for carat..
4777 if (this.badge !== '') {
4779 cfg.html += ' <span class="badge badge-secondary">' + this.badge + '</span>';
4784 if (this.href || this.html || this.glyphicon || this.icon || this.fa) {
4788 href : this.href || "#",
4789 html: this.html || ''
4792 if (this.tagtype == 'a') {
4793 cfg.cn[0].cls = 'nav-link';
4796 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>';
4799 cfg.cn[0].html = '<i class="fa fas fa-'+this.fa+'"></i> <span>' + cfg.cn[0].html + '</span>';
4801 if(this.glyphicon) {
4802 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
4807 cfg.cn[0].html += " <span class='caret'></span>";
4811 if (this.badge !== '') {
4813 cfg.cn[0].html += ' <span class="badge badge-secondary">' + this.badge + '</span>';
4821 onRender : function(ct, position)
4823 // Roo.log("Call onRender: " + this.xtype);
4824 if (Roo.bootstrap.version == 4 && ct.dom.type != 'ul') {
4828 var ret = Roo.bootstrap.NavItem.superclass.onRender.call(this, ct, position);
4829 this.navLink = this.el.select('.nav-link',true).first();
4834 initEvents: function()
4836 if (typeof (this.menu) != 'undefined') {
4837 this.menu.parentType = this.xtype;
4838 this.menu.triggerEl = this.el;
4839 this.menu = this.addxtype(Roo.apply({}, this.menu));
4842 this.el.select('a',true).on('click', this.onClick, this);
4844 if(this.tagtype == 'span'){
4845 this.el.select('span',true).on('click', this.onClick, this);
4848 // at this point parent should be available..
4849 this.parent().register(this);
4852 onClick : function(e)
4854 if (e.getTarget('.dropdown-menu-item')) {
4855 // did you click on a menu itemm.... - then don't trigger onclick..
4860 this.preventDefault ||
4863 Roo.log("NavItem - prevent Default?");
4867 if (this.disabled) {
4871 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4872 if (tg && tg.transition) {
4873 Roo.log("waiting for the transitionend");
4879 //Roo.log("fire event clicked");
4880 if(this.fireEvent('click', this, e) === false){
4884 if(this.tagtype == 'span'){
4888 //Roo.log(this.href);
4889 var ael = this.el.select('a',true).first();
4892 if(ael && this.animateRef && this.href.indexOf('#') > -1){
4893 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4894 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4895 return; // ignore... - it's a 'hash' to another page.
4897 Roo.log("NavItem - prevent Default?");
4899 this.scrollToElement(e);
4903 var p = this.parent();
4905 if (['tabs','pills'].indexOf(p.type)!==-1) {
4906 if (typeof(p.setActiveItem) !== 'undefined') {
4907 p.setActiveItem(this);
4911 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4912 if (p.parentType == 'NavHeaderbar' && !this.menu) {
4913 // remove the collapsed menu expand...
4914 p.parent().el.select('.roo-navbar-collapse',true).removeClass('in');
4918 isActive: function () {
4921 setActive : function(state, fire, is_was_active)
4923 if (this.active && !state && this.navId) {
4924 this.was_active = true;
4925 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4927 nv.clearWasActive(this);
4931 this.active = state;
4934 this.el.removeClass('active');
4935 this.navLink ? this.navLink.removeClass('active') : false;
4936 } else if (!this.el.hasClass('active')) {
4938 this.el.addClass('active');
4939 if (Roo.bootstrap.version == 4 && this.navLink ) {
4940 this.navLink.addClass('active');
4945 this.fireEvent('changed', this, state);
4948 // show a panel if it's registered and related..
4950 if (!this.navId || !this.tabId || !state || is_was_active) {
4954 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4958 var pan = tg.getPanelByName(this.tabId);
4962 // if we can not flip to new panel - go back to old nav highlight..
4963 if (false == tg.showPanel(pan)) {
4964 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4966 var onav = nv.getWasActive();
4968 onav.setActive(true, false, true);
4977 // this should not be here...
4978 setDisabled : function(state)
4980 this.disabled = state;
4982 this.el.removeClass('disabled');
4983 } else if (!this.el.hasClass('disabled')) {
4984 this.el.addClass('disabled');
4990 * Fetch the element to display the tooltip on.
4991 * @return {Roo.Element} defaults to this.el
4993 tooltipEl : function()
4995 return this.el.select('' + this.tagtype + '', true).first();
4998 scrollToElement : function(e)
5000 var c = document.body;
5003 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
5005 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
5006 c = document.documentElement;
5009 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
5015 var o = target.calcOffsetsTo(c);
5022 this.fireEvent('scrollto', this, options, e);
5024 Roo.get(c).scrollTo('top', options.value, true);
5037 * <span> icon </span>
5038 * <span> text </span>
5039 * <span>badge </span>
5043 * @class Roo.bootstrap.NavSidebarItem
5044 * @extends Roo.bootstrap.NavItem
5045 * Bootstrap Navbar.NavSidebarItem class
5046 * {String} badgeWeight (default|primary|success|info|warning|danger)the extra classes for the badge
5047 * {Boolean} open is the menu open
5048 * {Boolean} buttonView use button as the tigger el rather that a (default false)
5049 * {String} buttonWeight (default|primary|success|info|warning|danger)the extra classes for the button
5050 * {String} buttonSize (sm|md|lg)the extra classes for the button
5051 * {Boolean} showArrow show arrow next to the text (default true)
5053 * Create a new Navbar Button
5054 * @param {Object} config The config object
5056 Roo.bootstrap.NavSidebarItem = function(config){
5057 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
5062 * The raw click event for the entire grid.
5063 * @param {Roo.EventObject} e
5068 * Fires when the active item active state changes
5069 * @param {Roo.bootstrap.NavSidebarItem} this
5070 * @param {boolean} state the new state
5078 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
5080 badgeWeight : 'default',
5086 buttonWeight : 'default',
5092 getAutoCreate : function(){
5097 href : this.href || '#',
5103 if(this.buttonView){
5106 href : this.href || '#',
5107 cls: 'btn btn-' + this.buttonWeight + ' btn-' + this.buttonSize + 'roo-button-dropdown-toggle',
5120 cfg.cls += ' active';
5123 if (this.disabled) {
5124 cfg.cls += ' disabled';
5127 cfg.cls += ' open x-open';
5130 if (this.glyphicon || this.icon) {
5131 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
5132 a.cn.push({ tag : 'i', cls : c }) ;
5135 if(!this.buttonView){
5138 html : this.html || ''
5145 if (this.badge !== '') {
5146 a.cn.push({ tag: 'span', cls : 'badge pull-right badge-' + this.badgeWeight, html: this.badge });
5152 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
5155 a.cls += ' dropdown-toggle treeview' ;
5161 initEvents : function()
5163 if (typeof (this.menu) != 'undefined') {
5164 this.menu.parentType = this.xtype;
5165 this.menu.triggerEl = this.el;
5166 this.menu = this.addxtype(Roo.apply({}, this.menu));
5169 this.el.on('click', this.onClick, this);
5171 if(this.badge !== ''){
5172 this.badgeEl = this.el.select('.badge', true).first().setVisibilityMode(Roo.Element.DISPLAY);
5177 onClick : function(e)
5184 if(this.preventDefault){
5188 this.fireEvent('click', this, e);
5191 disable : function()
5193 this.setDisabled(true);
5198 this.setDisabled(false);
5201 setDisabled : function(state)
5203 if(this.disabled == state){
5207 this.disabled = state;
5210 this.el.addClass('disabled');
5214 this.el.removeClass('disabled');
5219 setActive : function(state)
5221 if(this.active == state){
5225 this.active = state;
5228 this.el.addClass('active');
5232 this.el.removeClass('active');
5237 isActive: function ()
5242 setBadge : function(str)
5248 this.badgeEl.dom.innerHTML = str;
5265 * @class Roo.bootstrap.Row
5266 * @extends Roo.bootstrap.Component
5267 * Bootstrap Row class (contains columns...)
5271 * @param {Object} config The config object
5274 Roo.bootstrap.Row = function(config){
5275 Roo.bootstrap.Row.superclass.constructor.call(this, config);
5278 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
5280 getAutoCreate : function(){
5299 * @class Roo.bootstrap.Element
5300 * @extends Roo.bootstrap.Component
5301 * Bootstrap Element class
5302 * @cfg {String} html contents of the element
5303 * @cfg {String} tag tag of the element
5304 * @cfg {String} cls class of the element
5305 * @cfg {Boolean} preventDefault (true|false) default false
5306 * @cfg {Boolean} clickable (true|false) default false
5309 * Create a new Element
5310 * @param {Object} config The config object
5313 Roo.bootstrap.Element = function(config){
5314 Roo.bootstrap.Element.superclass.constructor.call(this, config);
5320 * When a element is chick
5321 * @param {Roo.bootstrap.Element} this
5322 * @param {Roo.EventObject} e
5328 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
5333 preventDefault: false,
5336 getAutoCreate : function(){
5340 // cls: this.cls, double assign in parent class Component.js :: onRender
5347 initEvents: function()
5349 Roo.bootstrap.Element.superclass.initEvents.call(this);
5352 this.el.on('click', this.onClick, this);
5357 onClick : function(e)
5359 if(this.preventDefault){
5363 this.fireEvent('click', this, e);
5366 getValue : function()
5368 return this.el.dom.innerHTML;
5371 setValue : function(value)
5373 this.el.dom.innerHTML = value;
5388 * @class Roo.bootstrap.Pagination
5389 * @extends Roo.bootstrap.Component
5390 * Bootstrap Pagination class
5391 * @cfg {String} size xs | sm | md | lg
5392 * @cfg {Boolean} inverse false | true
5395 * Create a new Pagination
5396 * @param {Object} config The config object
5399 Roo.bootstrap.Pagination = function(config){
5400 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
5403 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
5409 getAutoCreate : function(){
5415 cfg.cls += ' inverse';
5421 cfg.cls += " " + this.cls;
5439 * @class Roo.bootstrap.PaginationItem
5440 * @extends Roo.bootstrap.Component
5441 * Bootstrap PaginationItem class
5442 * @cfg {String} html text
5443 * @cfg {String} href the link
5444 * @cfg {Boolean} preventDefault (true | false) default true
5445 * @cfg {Boolean} active (true | false) default false
5446 * @cfg {Boolean} disabled default false
5450 * Create a new PaginationItem
5451 * @param {Object} config The config object
5455 Roo.bootstrap.PaginationItem = function(config){
5456 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
5461 * The raw click event for the entire grid.
5462 * @param {Roo.EventObject} e
5468 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
5472 preventDefault: true,
5477 getAutoCreate : function(){
5483 href : this.href ? this.href : '#',
5484 html : this.html ? this.html : ''
5494 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
5498 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
5504 initEvents: function() {
5506 this.el.on('click', this.onClick, this);
5509 onClick : function(e)
5511 Roo.log('PaginationItem on click ');
5512 if(this.preventDefault){
5520 this.fireEvent('click', this, e);
5536 * @class Roo.bootstrap.Slider
5537 * @extends Roo.bootstrap.Component
5538 * Bootstrap Slider class
5541 * Create a new Slider
5542 * @param {Object} config The config object
5545 Roo.bootstrap.Slider = function(config){
5546 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
5549 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
5551 getAutoCreate : function(){
5555 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
5559 cls: 'ui-slider-handle ui-state-default ui-corner-all'
5571 * Ext JS Library 1.1.1
5572 * Copyright(c) 2006-2007, Ext JS, LLC.
5574 * Originally Released Under LGPL - original licence link has changed is not relivant.
5577 * <script type="text/javascript">
5582 * @class Roo.grid.ColumnModel
5583 * @extends Roo.util.Observable
5584 * This is the default implementation of a ColumnModel used by the Grid. It defines
5585 * the columns in the grid.
5588 var colModel = new Roo.grid.ColumnModel([
5589 {header: "Ticker", width: 60, sortable: true, locked: true},
5590 {header: "Company Name", width: 150, sortable: true},
5591 {header: "Market Cap.", width: 100, sortable: true},
5592 {header: "$ Sales", width: 100, sortable: true, renderer: money},
5593 {header: "Employees", width: 100, sortable: true, resizable: false}
5598 * The config options listed for this class are options which may appear in each
5599 * individual column definition.
5600 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
5602 * @param {Object} config An Array of column config objects. See this class's
5603 * config objects for details.
5605 Roo.grid.ColumnModel = function(config){
5607 * The config passed into the constructor
5609 this.config = config;
5612 // if no id, create one
5613 // if the column does not have a dataIndex mapping,
5614 // map it to the order it is in the config
5615 for(var i = 0, len = config.length; i < len; i++){
5617 if(typeof c.dataIndex == "undefined"){
5620 if(typeof c.renderer == "string"){
5621 c.renderer = Roo.util.Format[c.renderer];
5623 if(typeof c.id == "undefined"){
5626 if(c.editor && c.editor.xtype){
5627 c.editor = Roo.factory(c.editor, Roo.grid);
5629 if(c.editor && c.editor.isFormField){
5630 c.editor = new Roo.grid.GridEditor(c.editor);
5632 this.lookup[c.id] = c;
5636 * The width of columns which have no width specified (defaults to 100)
5639 this.defaultWidth = 100;
5642 * Default sortable of columns which have no sortable specified (defaults to false)
5645 this.defaultSortable = false;
5649 * @event widthchange
5650 * Fires when the width of a column changes.
5651 * @param {ColumnModel} this
5652 * @param {Number} columnIndex The column index
5653 * @param {Number} newWidth The new width
5655 "widthchange": true,
5657 * @event headerchange
5658 * Fires when the text of a header changes.
5659 * @param {ColumnModel} this
5660 * @param {Number} columnIndex The column index
5661 * @param {Number} newText The new header text
5663 "headerchange": true,
5665 * @event hiddenchange
5666 * Fires when a column is hidden or "unhidden".
5667 * @param {ColumnModel} this
5668 * @param {Number} columnIndex The column index
5669 * @param {Boolean} hidden true if hidden, false otherwise
5671 "hiddenchange": true,
5673 * @event columnmoved
5674 * Fires when a column is moved.
5675 * @param {ColumnModel} this
5676 * @param {Number} oldIndex
5677 * @param {Number} newIndex
5679 "columnmoved" : true,
5681 * @event columlockchange
5682 * Fires when a column's locked state is changed
5683 * @param {ColumnModel} this
5684 * @param {Number} colIndex
5685 * @param {Boolean} locked true if locked
5687 "columnlockchange" : true
5689 Roo.grid.ColumnModel.superclass.constructor.call(this);
5691 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
5693 * @cfg {String} header The header text to display in the Grid view.
5696 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
5697 * {@link Roo.data.Record} definition from which to draw the column's value. If not
5698 * specified, the column's index is used as an index into the Record's data Array.
5701 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
5702 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
5705 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
5706 * Defaults to the value of the {@link #defaultSortable} property.
5707 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
5710 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
5713 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
5716 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
5719 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
5722 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
5723 * given the cell's data value. See {@link #setRenderer}. If not specified, the
5724 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
5725 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
5728 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
5731 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
5734 * @cfg {String} valign (Optional) Set the CSS vertical-align property of the column (eg. middle, top, bottom etc). Defaults to undefined.
5737 * @cfg {String} cursor (Optional)
5740 * @cfg {String} tooltip (Optional)
5743 * @cfg {Number} xs (Optional)
5746 * @cfg {Number} sm (Optional)
5749 * @cfg {Number} md (Optional)
5752 * @cfg {Number} lg (Optional)
5755 * Returns the id of the column at the specified index.
5756 * @param {Number} index The column index
5757 * @return {String} the id
5759 getColumnId : function(index){
5760 return this.config[index].id;
5764 * Returns the column for a specified id.
5765 * @param {String} id The column id
5766 * @return {Object} the column
5768 getColumnById : function(id){
5769 return this.lookup[id];
5774 * Returns the column for a specified dataIndex.
5775 * @param {String} dataIndex The column dataIndex
5776 * @return {Object|Boolean} the column or false if not found
5778 getColumnByDataIndex: function(dataIndex){
5779 var index = this.findColumnIndex(dataIndex);
5780 return index > -1 ? this.config[index] : false;
5784 * Returns the index for a specified column id.
5785 * @param {String} id The column id
5786 * @return {Number} the index, or -1 if not found
5788 getIndexById : function(id){
5789 for(var i = 0, len = this.config.length; i < len; i++){
5790 if(this.config[i].id == id){
5798 * Returns the index for a specified column dataIndex.
5799 * @param {String} dataIndex The column dataIndex
5800 * @return {Number} the index, or -1 if not found
5803 findColumnIndex : function(dataIndex){
5804 for(var i = 0, len = this.config.length; i < len; i++){
5805 if(this.config[i].dataIndex == dataIndex){
5813 moveColumn : function(oldIndex, newIndex){
5814 var c = this.config[oldIndex];
5815 this.config.splice(oldIndex, 1);
5816 this.config.splice(newIndex, 0, c);
5817 this.dataMap = null;
5818 this.fireEvent("columnmoved", this, oldIndex, newIndex);
5821 isLocked : function(colIndex){
5822 return this.config[colIndex].locked === true;
5825 setLocked : function(colIndex, value, suppressEvent){
5826 if(this.isLocked(colIndex) == value){
5829 this.config[colIndex].locked = value;
5831 this.fireEvent("columnlockchange", this, colIndex, value);
5835 getTotalLockedWidth : function(){
5837 for(var i = 0; i < this.config.length; i++){
5838 if(this.isLocked(i) && !this.isHidden(i)){
5839 this.totalWidth += this.getColumnWidth(i);
5845 getLockedCount : function(){
5846 for(var i = 0, len = this.config.length; i < len; i++){
5847 if(!this.isLocked(i)){
5852 return this.config.length;
5856 * Returns the number of columns.
5859 getColumnCount : function(visibleOnly){
5860 if(visibleOnly === true){
5862 for(var i = 0, len = this.config.length; i < len; i++){
5863 if(!this.isHidden(i)){
5869 return this.config.length;
5873 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
5874 * @param {Function} fn
5875 * @param {Object} scope (optional)
5876 * @return {Array} result
5878 getColumnsBy : function(fn, scope){
5880 for(var i = 0, len = this.config.length; i < len; i++){
5881 var c = this.config[i];
5882 if(fn.call(scope||this, c, i) === true){
5890 * Returns true if the specified column is sortable.
5891 * @param {Number} col The column index
5894 isSortable : function(col){
5895 if(typeof this.config[col].sortable == "undefined"){
5896 return this.defaultSortable;
5898 return this.config[col].sortable;
5902 * Returns the rendering (formatting) function defined for the column.
5903 * @param {Number} col The column index.
5904 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
5906 getRenderer : function(col){
5907 if(!this.config[col].renderer){
5908 return Roo.grid.ColumnModel.defaultRenderer;
5910 return this.config[col].renderer;
5914 * Sets the rendering (formatting) function for a column.
5915 * @param {Number} col The column index
5916 * @param {Function} fn The function to use to process the cell's raw data
5917 * to return HTML markup for the grid view. The render function is called with
5918 * the following parameters:<ul>
5919 * <li>Data value.</li>
5920 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
5921 * <li>css A CSS style string to apply to the table cell.</li>
5922 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
5923 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
5924 * <li>Row index</li>
5925 * <li>Column index</li>
5926 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
5928 setRenderer : function(col, fn){
5929 this.config[col].renderer = fn;
5933 * Returns the width for the specified column.
5934 * @param {Number} col The column index
5937 getColumnWidth : function(col){
5938 return this.config[col].width * 1 || this.defaultWidth;
5942 * Sets the width for a column.
5943 * @param {Number} col The column index
5944 * @param {Number} width The new width
5946 setColumnWidth : function(col, width, suppressEvent){
5947 this.config[col].width = width;
5948 this.totalWidth = null;
5950 this.fireEvent("widthchange", this, col, width);
5955 * Returns the total width of all columns.
5956 * @param {Boolean} includeHidden True to include hidden column widths
5959 getTotalWidth : function(includeHidden){
5960 if(!this.totalWidth){
5961 this.totalWidth = 0;
5962 for(var i = 0, len = this.config.length; i < len; i++){
5963 if(includeHidden || !this.isHidden(i)){
5964 this.totalWidth += this.getColumnWidth(i);
5968 return this.totalWidth;
5972 * Returns the header for the specified column.
5973 * @param {Number} col The column index
5976 getColumnHeader : function(col){
5977 return this.config[col].header;
5981 * Sets the header for a column.
5982 * @param {Number} col The column index
5983 * @param {String} header The new header
5985 setColumnHeader : function(col, header){
5986 this.config[col].header = header;
5987 this.fireEvent("headerchange", this, col, header);
5991 * Returns the tooltip for the specified column.
5992 * @param {Number} col The column index
5995 getColumnTooltip : function(col){
5996 return this.config[col].tooltip;
5999 * Sets the tooltip for a column.
6000 * @param {Number} col The column index
6001 * @param {String} tooltip The new tooltip
6003 setColumnTooltip : function(col, tooltip){
6004 this.config[col].tooltip = tooltip;
6008 * Returns the dataIndex for the specified column.
6009 * @param {Number} col The column index
6012 getDataIndex : function(col){
6013 return this.config[col].dataIndex;
6017 * Sets the dataIndex for a column.
6018 * @param {Number} col The column index
6019 * @param {Number} dataIndex The new dataIndex
6021 setDataIndex : function(col, dataIndex){
6022 this.config[col].dataIndex = dataIndex;
6028 * Returns true if the cell is editable.
6029 * @param {Number} colIndex The column index
6030 * @param {Number} rowIndex The row index - this is nto actually used..?
6033 isCellEditable : function(colIndex, rowIndex){
6034 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
6038 * Returns the editor defined for the cell/column.
6039 * return false or null to disable editing.
6040 * @param {Number} colIndex The column index
6041 * @param {Number} rowIndex The row index
6044 getCellEditor : function(colIndex, rowIndex){
6045 return this.config[colIndex].editor;
6049 * Sets if a column is editable.
6050 * @param {Number} col The column index
6051 * @param {Boolean} editable True if the column is editable
6053 setEditable : function(col, editable){
6054 this.config[col].editable = editable;
6059 * Returns true if the column is hidden.
6060 * @param {Number} colIndex The column index
6063 isHidden : function(colIndex){
6064 return this.config[colIndex].hidden;
6069 * Returns true if the column width cannot be changed
6071 isFixed : function(colIndex){
6072 return this.config[colIndex].fixed;
6076 * Returns true if the column can be resized
6079 isResizable : function(colIndex){
6080 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
6083 * Sets if a column is hidden.
6084 * @param {Number} colIndex The column index
6085 * @param {Boolean} hidden True if the column is hidden
6087 setHidden : function(colIndex, hidden){
6088 this.config[colIndex].hidden = hidden;
6089 this.totalWidth = null;
6090 this.fireEvent("hiddenchange", this, colIndex, hidden);
6094 * Sets the editor for a column.
6095 * @param {Number} col The column index
6096 * @param {Object} editor The editor object
6098 setEditor : function(col, editor){
6099 this.config[col].editor = editor;
6103 Roo.grid.ColumnModel.defaultRenderer = function(value)
6105 if(typeof value == "object") {
6108 if(typeof value == "string" && value.length < 1){
6112 return String.format("{0}", value);
6115 // Alias for backwards compatibility
6116 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
6119 * Ext JS Library 1.1.1
6120 * Copyright(c) 2006-2007, Ext JS, LLC.
6122 * Originally Released Under LGPL - original licence link has changed is not relivant.
6125 * <script type="text/javascript">
6129 * @class Roo.LoadMask
6130 * A simple utility class for generically masking elements while loading data. If the element being masked has
6131 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
6132 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
6133 * element's UpdateManager load indicator and will be destroyed after the initial load.
6135 * Create a new LoadMask
6136 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
6137 * @param {Object} config The config object
6139 Roo.LoadMask = function(el, config){
6140 this.el = Roo.get(el);
6141 Roo.apply(this, config);
6143 this.store.on('beforeload', this.onBeforeLoad, this);
6144 this.store.on('load', this.onLoad, this);
6145 this.store.on('loadexception', this.onLoadException, this);
6146 this.removeMask = false;
6148 var um = this.el.getUpdateManager();
6149 um.showLoadIndicator = false; // disable the default indicator
6150 um.on('beforeupdate', this.onBeforeLoad, this);
6151 um.on('update', this.onLoad, this);
6152 um.on('failure', this.onLoad, this);
6153 this.removeMask = true;
6157 Roo.LoadMask.prototype = {
6159 * @cfg {Boolean} removeMask
6160 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
6161 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
6165 * The text to display in a centered loading message box (defaults to 'Loading...')
6169 * @cfg {String} msgCls
6170 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
6172 msgCls : 'x-mask-loading',
6175 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
6181 * Disables the mask to prevent it from being displayed
6183 disable : function(){
6184 this.disabled = true;
6188 * Enables the mask so that it can be displayed
6190 enable : function(){
6191 this.disabled = false;
6194 onLoadException : function()
6198 if (typeof(arguments[3]) != 'undefined') {
6199 Roo.MessageBox.alert("Error loading",arguments[3]);
6203 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
6204 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
6211 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
6216 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
6220 onBeforeLoad : function(){
6222 (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
6227 destroy : function(){
6229 this.store.un('beforeload', this.onBeforeLoad, this);
6230 this.store.un('load', this.onLoad, this);
6231 this.store.un('loadexception', this.onLoadException, this);
6233 var um = this.el.getUpdateManager();
6234 um.un('beforeupdate', this.onBeforeLoad, this);
6235 um.un('update', this.onLoad, this);
6236 um.un('failure', this.onLoad, this);
6247 * @class Roo.bootstrap.Table
6248 * @extends Roo.bootstrap.Component
6249 * Bootstrap Table class
6250 * @cfg {String} cls table class
6251 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
6252 * @cfg {String} bgcolor Specifies the background color for a table
6253 * @cfg {Number} border Specifies whether the table cells should have borders or not
6254 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
6255 * @cfg {Number} cellspacing Specifies the space between cells
6256 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
6257 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
6258 * @cfg {String} sortable Specifies that the table should be sortable
6259 * @cfg {String} summary Specifies a summary of the content of a table
6260 * @cfg {Number} width Specifies the width of a table
6261 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
6263 * @cfg {boolean} striped Should the rows be alternative striped
6264 * @cfg {boolean} bordered Add borders to the table
6265 * @cfg {boolean} hover Add hover highlighting
6266 * @cfg {boolean} condensed Format condensed
6267 * @cfg {boolean} responsive Format condensed
6268 * @cfg {Boolean} loadMask (true|false) default false
6269 * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
6270 * @cfg {Boolean} headerShow (true|false) generate thead, default true
6271 * @cfg {Boolean} rowSelection (true|false) default false
6272 * @cfg {Boolean} cellSelection (true|false) default false
6273 * @cfg {Boolean} scrollBody (true|false) default false - body scrolled / fixed header
6274 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
6275 * @cfg {Boolean} lazyLoad auto load data while scrolling to the end (default false)
6276 * @cfg {Boolean} auto_hide_footer auto hide footer if only one page (default false)
6280 * Create a new Table
6281 * @param {Object} config The config object
6284 Roo.bootstrap.Table = function(config){
6285 Roo.bootstrap.Table.superclass.constructor.call(this, config);
6290 this.rowSelection = (typeof(config.rowSelection) != 'undefined') ? config.rowSelection : this.rowSelection;
6291 this.cellSelection = (typeof(config.cellSelection) != 'undefined') ? config.cellSelection : this.cellSelection;
6292 this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
6293 this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
6295 this.sm = this.sm || {xtype: 'RowSelectionModel'};
6297 this.sm.grid = this;
6298 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
6299 this.sm = this.selModel;
6300 this.sm.xmodule = this.xmodule || false;
6303 if (this.cm && typeof(this.cm.config) == 'undefined') {
6304 this.colModel = new Roo.grid.ColumnModel(this.cm);
6305 this.cm = this.colModel;
6306 this.cm.xmodule = this.xmodule || false;
6309 this.store= Roo.factory(this.store, Roo.data);
6310 this.ds = this.store;
6311 this.ds.xmodule = this.xmodule || false;
6314 if (this.footer && this.store) {
6315 this.footer.dataSource = this.ds;
6316 this.footer = Roo.factory(this.footer);
6323 * Fires when a cell is clicked
6324 * @param {Roo.bootstrap.Table} this
6325 * @param {Roo.Element} el
6326 * @param {Number} rowIndex
6327 * @param {Number} columnIndex
6328 * @param {Roo.EventObject} e
6332 * @event celldblclick
6333 * Fires when a cell is double clicked
6334 * @param {Roo.bootstrap.Table} this
6335 * @param {Roo.Element} el
6336 * @param {Number} rowIndex
6337 * @param {Number} columnIndex
6338 * @param {Roo.EventObject} e
6340 "celldblclick" : true,
6343 * Fires when a row is clicked
6344 * @param {Roo.bootstrap.Table} this
6345 * @param {Roo.Element} el
6346 * @param {Number} rowIndex
6347 * @param {Roo.EventObject} e
6351 * @event rowdblclick
6352 * Fires when a row is double clicked
6353 * @param {Roo.bootstrap.Table} this
6354 * @param {Roo.Element} el
6355 * @param {Number} rowIndex
6356 * @param {Roo.EventObject} e
6358 "rowdblclick" : true,
6361 * Fires when a mouseover occur
6362 * @param {Roo.bootstrap.Table} this
6363 * @param {Roo.Element} el
6364 * @param {Number} rowIndex
6365 * @param {Number} columnIndex
6366 * @param {Roo.EventObject} e
6371 * Fires when a mouseout occur
6372 * @param {Roo.bootstrap.Table} this
6373 * @param {Roo.Element} el
6374 * @param {Number} rowIndex
6375 * @param {Number} columnIndex
6376 * @param {Roo.EventObject} e
6381 * Fires when a row is rendered, so you can change add a style to it.
6382 * @param {Roo.bootstrap.Table} this
6383 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
6387 * @event rowsrendered
6388 * Fires when all the rows have been rendered
6389 * @param {Roo.bootstrap.Table} this
6391 'rowsrendered' : true,
6393 * @event contextmenu
6394 * The raw contextmenu event for the entire grid.
6395 * @param {Roo.EventObject} e
6397 "contextmenu" : true,
6399 * @event rowcontextmenu
6400 * Fires when a row is right clicked
6401 * @param {Roo.bootstrap.Table} this
6402 * @param {Number} rowIndex
6403 * @param {Roo.EventObject} e
6405 "rowcontextmenu" : true,
6407 * @event cellcontextmenu
6408 * Fires when a cell is right clicked
6409 * @param {Roo.bootstrap.Table} this
6410 * @param {Number} rowIndex
6411 * @param {Number} cellIndex
6412 * @param {Roo.EventObject} e
6414 "cellcontextmenu" : true,
6416 * @event headercontextmenu
6417 * Fires when a header is right clicked
6418 * @param {Roo.bootstrap.Table} this
6419 * @param {Number} columnIndex
6420 * @param {Roo.EventObject} e
6422 "headercontextmenu" : true
6426 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
6452 rowSelection : false,
6453 cellSelection : false,
6456 // Roo.Element - the tbody
6458 // Roo.Element - thead element
6461 container: false, // used by gridpanel...
6467 auto_hide_footer : false,
6469 getAutoCreate : function()
6471 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
6478 if (this.scrollBody) {
6479 cfg.cls += ' table-body-fixed';
6482 cfg.cls += ' table-striped';
6486 cfg.cls += ' table-hover';
6488 if (this.bordered) {
6489 cfg.cls += ' table-bordered';
6491 if (this.condensed) {
6492 cfg.cls += ' table-condensed';
6494 if (this.responsive) {
6495 cfg.cls += ' table-responsive';
6499 cfg.cls+= ' ' +this.cls;
6502 // this lot should be simplifed...
6515 ].forEach(function(k) {
6523 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
6526 if(this.store || this.cm){
6527 if(this.headerShow){
6528 cfg.cn.push(this.renderHeader());
6531 cfg.cn.push(this.renderBody());
6533 if(this.footerShow){
6534 cfg.cn.push(this.renderFooter());
6536 // where does this come from?
6537 //cfg.cls+= ' TableGrid';
6540 return { cn : [ cfg ] };
6543 initEvents : function()
6545 if(!this.store || !this.cm){
6548 if (this.selModel) {
6549 this.selModel.initEvents();
6553 //Roo.log('initEvents with ds!!!!');
6555 this.mainBody = this.el.select('tbody', true).first();
6556 this.mainHead = this.el.select('thead', true).first();
6557 this.mainFoot = this.el.select('tfoot', true).first();
6563 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6564 e.on('click', _this.sort, _this);
6567 this.mainBody.on("click", this.onClick, this);
6568 this.mainBody.on("dblclick", this.onDblClick, this);
6570 // why is this done????? = it breaks dialogs??
6571 //this.parent().el.setStyle('position', 'relative');
6575 this.footer.parentId = this.id;
6576 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
6579 this.el.select('tfoot tr td').first().addClass('hide');
6584 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
6587 this.store.on('load', this.onLoad, this);
6588 this.store.on('beforeload', this.onBeforeLoad, this);
6589 this.store.on('update', this.onUpdate, this);
6590 this.store.on('add', this.onAdd, this);
6591 this.store.on("clear", this.clear, this);
6593 this.el.on("contextmenu", this.onContextMenu, this);
6595 this.mainBody.on('scroll', this.onBodyScroll, this);
6597 this.cm.on("headerchange", this.onHeaderChange, this);
6599 this.cm.on("hiddenchange", this.onHiddenChange, this, arguments);
6603 onContextMenu : function(e, t)
6605 this.processEvent("contextmenu", e);
6608 processEvent : function(name, e)
6610 if (name != 'touchstart' ) {
6611 this.fireEvent(name, e);
6614 var t = e.getTarget();
6616 var cell = Roo.get(t);
6622 if(cell.findParent('tfoot', false, true)){
6626 if(cell.findParent('thead', false, true)){
6628 if(e.getTarget().nodeName.toLowerCase() != 'th'){
6629 cell = Roo.get(t).findParent('th', false, true);
6631 Roo.log("failed to find th in thead?");
6632 Roo.log(e.getTarget());
6637 var cellIndex = cell.dom.cellIndex;
6639 var ename = name == 'touchstart' ? 'click' : name;
6640 this.fireEvent("header" + ename, this, cellIndex, e);
6645 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6646 cell = Roo.get(t).findParent('td', false, true);
6648 Roo.log("failed to find th in tbody?");
6649 Roo.log(e.getTarget());
6654 var row = cell.findParent('tr', false, true);
6655 var cellIndex = cell.dom.cellIndex;
6656 var rowIndex = row.dom.rowIndex - 1;
6660 this.fireEvent("row" + name, this, rowIndex, e);
6664 this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
6670 onMouseover : function(e, el)
6672 var cell = Roo.get(el);
6678 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6679 cell = cell.findParent('td', false, true);
6682 var row = cell.findParent('tr', false, true);
6683 var cellIndex = cell.dom.cellIndex;
6684 var rowIndex = row.dom.rowIndex - 1; // start from 0
6686 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
6690 onMouseout : function(e, el)
6692 var cell = Roo.get(el);
6698 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6699 cell = cell.findParent('td', false, true);
6702 var row = cell.findParent('tr', false, true);
6703 var cellIndex = cell.dom.cellIndex;
6704 var rowIndex = row.dom.rowIndex - 1; // start from 0
6706 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
6710 onClick : function(e, el)
6712 var cell = Roo.get(el);
6714 if(!cell || (!this.cellSelection && !this.rowSelection)){
6718 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6719 cell = cell.findParent('td', false, true);
6722 if(!cell || typeof(cell) == 'undefined'){
6726 var row = cell.findParent('tr', false, true);
6728 if(!row || typeof(row) == 'undefined'){
6732 var cellIndex = cell.dom.cellIndex;
6733 var rowIndex = this.getRowIndex(row);
6735 // why??? - should these not be based on SelectionModel?
6736 if(this.cellSelection){
6737 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
6740 if(this.rowSelection){
6741 this.fireEvent('rowclick', this, row, rowIndex, e);
6747 onDblClick : function(e,el)
6749 var cell = Roo.get(el);
6751 if(!cell || (!this.cellSelection && !this.rowSelection)){
6755 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6756 cell = cell.findParent('td', false, true);
6759 if(!cell || typeof(cell) == 'undefined'){
6763 var row = cell.findParent('tr', false, true);
6765 if(!row || typeof(row) == 'undefined'){
6769 var cellIndex = cell.dom.cellIndex;
6770 var rowIndex = this.getRowIndex(row);
6772 if(this.cellSelection){
6773 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
6776 if(this.rowSelection){
6777 this.fireEvent('rowdblclick', this, row, rowIndex, e);
6781 sort : function(e,el)
6783 var col = Roo.get(el);
6785 if(!col.hasClass('sortable')){
6789 var sort = col.attr('sort');
6792 if(col.select('i', true).first().hasClass('glyphicon-arrow-up')){
6796 this.store.sortInfo = {field : sort, direction : dir};
6799 Roo.log("calling footer first");
6800 this.footer.onClick('first');
6803 this.store.load({ params : { start : 0 } });
6807 renderHeader : function()
6815 this.totalWidth = 0;
6817 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6819 var config = cm.config[i];
6823 cls : 'x-hcol-' + i,
6825 html: cm.getColumnHeader(i)
6830 if(typeof(config.sortable) != 'undefined' && config.sortable){
6832 c.html = '<i class="glyphicon"></i>' + c.html;
6835 // could use BS4 hidden-..-down
6837 if(typeof(config.lgHeader) != 'undefined'){
6838 hh += '<span class="hidden-xs hidden-sm hidden-md ">' + config.lgHeader + '</span>';
6841 if(typeof(config.mdHeader) != 'undefined'){
6842 hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
6845 if(typeof(config.smHeader) != 'undefined'){
6846 hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
6849 if(typeof(config.xsHeader) != 'undefined'){
6850 hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
6857 if(typeof(config.tooltip) != 'undefined'){
6858 c.tooltip = config.tooltip;
6861 if(typeof(config.colspan) != 'undefined'){
6862 c.colspan = config.colspan;
6865 if(typeof(config.hidden) != 'undefined' && config.hidden){
6866 c.style += ' display:none;';
6869 if(typeof(config.dataIndex) != 'undefined'){
6870 c.sort = config.dataIndex;
6875 if(typeof(config.align) != 'undefined' && config.align.length){
6876 c.style += ' text-align:' + config.align + ';';
6879 if(typeof(config.width) != 'undefined'){
6880 c.style += ' width:' + config.width + 'px;';
6881 this.totalWidth += config.width;
6883 this.totalWidth += 100; // assume minimum of 100 per column?
6886 if(typeof(config.cls) != 'undefined'){
6887 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
6890 ['xs','sm','md','lg'].map(function(size){
6892 if(typeof(config[size]) == 'undefined'){
6896 if (!config[size]) { // 0 = hidden
6897 // BS 4 '0' is treated as hide that column and below.
6898 c.cls += ' hidden-' + size + ' hidden' + size + '-down';
6902 c.cls += ' col-' + size + '-' + config[size] + (
6903 size == 'xs' ? (' col-' + config[size] ) : '' // bs4 col-{num} replaces col-xs
6915 renderBody : function()
6925 colspan : this.cm.getColumnCount()
6935 renderFooter : function()
6945 colspan : this.cm.getColumnCount()
6959 // Roo.log('ds onload');
6964 var ds = this.store;
6966 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6967 e.select('i', true).removeClass(['glyphicon-arrow-up', 'glyphicon-arrow-down']);
6968 if (_this.store.sortInfo) {
6970 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
6971 e.select('i', true).addClass(['glyphicon-arrow-up']);
6974 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
6975 e.select('i', true).addClass(['glyphicon-arrow-down']);
6980 var tbody = this.mainBody;
6982 if(ds.getCount() > 0){
6983 ds.data.each(function(d,rowIndex){
6984 var row = this.renderRow(cm, ds, rowIndex);
6986 tbody.createChild(row);
6990 if(row.cellObjects.length){
6991 Roo.each(row.cellObjects, function(r){
6992 _this.renderCellObject(r);
6999 var tfoot = this.el.select('tfoot', true).first();
7001 if(this.footerShow && this.auto_hide_footer && this.mainFoot){
7003 this.mainFoot.setVisibilityMode(Roo.Element.DISPLAY).hide();
7005 var total = this.ds.getTotalCount();
7007 if(this.footer.pageSize < total){
7008 this.mainFoot.show();
7012 Roo.each(this.el.select('tbody td', true).elements, function(e){
7013 e.on('mouseover', _this.onMouseover, _this);
7016 Roo.each(this.el.select('tbody td', true).elements, function(e){
7017 e.on('mouseout', _this.onMouseout, _this);
7019 this.fireEvent('rowsrendered', this);
7025 onUpdate : function(ds,record)
7027 this.refreshRow(record);
7031 onRemove : function(ds, record, index, isUpdate){
7032 if(isUpdate !== true){
7033 this.fireEvent("beforerowremoved", this, index, record);
7035 var bt = this.mainBody.dom;
7037 var rows = this.el.select('tbody > tr', true).elements;
7039 if(typeof(rows[index]) != 'undefined'){
7040 bt.removeChild(rows[index].dom);
7043 // if(bt.rows[index]){
7044 // bt.removeChild(bt.rows[index]);
7047 if(isUpdate !== true){
7048 //this.stripeRows(index);
7049 //this.syncRowHeights(index, index);
7051 this.fireEvent("rowremoved", this, index, record);
7055 onAdd : function(ds, records, rowIndex)
7057 //Roo.log('on Add called');
7058 // - note this does not handle multiple adding very well..
7059 var bt = this.mainBody.dom;
7060 for (var i =0 ; i < records.length;i++) {
7061 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
7062 //Roo.log(records[i]);
7063 //Roo.log(this.store.getAt(rowIndex+i));
7064 this.insertRow(this.store, rowIndex + i, false);
7071 refreshRow : function(record){
7072 var ds = this.store, index;
7073 if(typeof record == 'number'){
7075 record = ds.getAt(index);
7077 index = ds.indexOf(record);
7079 this.insertRow(ds, index, true);
7081 this.onRemove(ds, record, index+1, true);
7083 //this.syncRowHeights(index, index);
7085 this.fireEvent("rowupdated", this, index, record);
7088 insertRow : function(dm, rowIndex, isUpdate){
7091 this.fireEvent("beforerowsinserted", this, rowIndex);
7093 //var s = this.getScrollState();
7094 var row = this.renderRow(this.cm, this.store, rowIndex);
7095 // insert before rowIndex..
7096 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
7100 if(row.cellObjects.length){
7101 Roo.each(row.cellObjects, function(r){
7102 _this.renderCellObject(r);
7107 this.fireEvent("rowsinserted", this, rowIndex);
7108 //this.syncRowHeights(firstRow, lastRow);
7109 //this.stripeRows(firstRow);
7116 getRowDom : function(rowIndex)
7118 var rows = this.el.select('tbody > tr', true).elements;
7120 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
7123 // returns the object tree for a tr..
7126 renderRow : function(cm, ds, rowIndex)
7128 var d = ds.getAt(rowIndex);
7132 cls : 'x-row-' + rowIndex,
7136 var cellObjects = [];
7138 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
7139 var config = cm.config[i];
7141 var renderer = cm.getRenderer(i);
7145 if(typeof(renderer) !== 'undefined'){
7146 value = renderer(d.data[cm.getDataIndex(i)], false, d);
7148 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
7149 // and are rendered into the cells after the row is rendered - using the id for the element.
7151 if(typeof(value) === 'object'){
7161 rowIndex : rowIndex,
7166 this.fireEvent('rowclass', this, rowcfg);
7170 cls : rowcfg.rowClass + ' x-col-' + i,
7172 html: (typeof(value) === 'object') ? '' : value
7179 if(typeof(config.colspan) != 'undefined'){
7180 td.colspan = config.colspan;
7183 if(typeof(config.hidden) != 'undefined' && config.hidden){
7184 td.style += ' display:none;';
7187 if(typeof(config.align) != 'undefined' && config.align.length){
7188 td.style += ' text-align:' + config.align + ';';
7190 if(typeof(config.valign) != 'undefined' && config.valign.length){
7191 td.style += ' vertical-align:' + config.valign + ';';
7194 if(typeof(config.width) != 'undefined'){
7195 td.style += ' width:' + config.width + 'px;';
7198 if(typeof(config.cursor) != 'undefined'){
7199 td.style += ' cursor:' + config.cursor + ';';
7202 if(typeof(config.cls) != 'undefined'){
7203 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
7206 ['xs','sm','md','lg'].map(function(size){
7208 if(typeof(config[size]) == 'undefined'){
7214 if (!config[size]) { // 0 = hidden
7215 // BS 4 '0' is treated as hide that column and below.
7216 td.cls += ' hidden-' + size + ' hidden' + size + '-down';
7220 td.cls += ' col-' + size + '-' + config[size] + (
7221 size == 'xs' ? (' col-' + config[size] ) : '' // bs4 col-{num} replaces col-xs
7231 row.cellObjects = cellObjects;
7239 onBeforeLoad : function()
7248 this.el.select('tbody', true).first().dom.innerHTML = '';
7251 * Show or hide a row.
7252 * @param {Number} rowIndex to show or hide
7253 * @param {Boolean} state hide
7255 setRowVisibility : function(rowIndex, state)
7257 var bt = this.mainBody.dom;
7259 var rows = this.el.select('tbody > tr', true).elements;
7261 if(typeof(rows[rowIndex]) == 'undefined'){
7264 rows[rowIndex].dom.style.display = state ? '' : 'none';
7268 getSelectionModel : function(){
7270 this.selModel = new Roo.bootstrap.Table.RowSelectionModel({grid: this});
7272 return this.selModel;
7275 * Render the Roo.bootstrap object from renderder
7277 renderCellObject : function(r)
7281 r.cfg.parentId = (typeof(r.container) == 'string') ? r.container : r.container.id;
7283 var t = r.cfg.render(r.container);
7286 Roo.each(r.cfg.cn, function(c){
7288 container: t.getChildContainer(),
7291 _this.renderCellObject(child);
7296 getRowIndex : function(row)
7300 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
7311 * Returns the grid's underlying element = used by panel.Grid
7312 * @return {Element} The element
7314 getGridEl : function(){
7318 * Forces a resize - used by panel.Grid
7319 * @return {Element} The element
7321 autoSize : function()
7323 //var ctr = Roo.get(this.container.dom.parentElement);
7324 var ctr = Roo.get(this.el.dom);
7326 var thd = this.getGridEl().select('thead',true).first();
7327 var tbd = this.getGridEl().select('tbody', true).first();
7328 var tfd = this.getGridEl().select('tfoot', true).first();
7330 var cw = ctr.getWidth();
7334 tbd.setSize(ctr.getWidth(),
7335 ctr.getHeight() - ((thd ? thd.getHeight() : 0) + (tfd ? tfd.getHeight() : 0))
7337 var barsize = (tbd.dom.offsetWidth - tbd.dom.clientWidth);
7340 cw = Math.max(cw, this.totalWidth);
7341 this.getGridEl().select('tr',true).setWidth(cw);
7342 // resize 'expandable coloumn?
7344 return; // we doe not have a view in this design..
7347 onBodyScroll: function()
7349 //Roo.log("body scrolled');" + this.mainBody.dom.scrollLeft);
7351 this.mainHead.setStyle({
7352 'position' : 'relative',
7353 'left': (-1* this.mainBody.dom.scrollLeft) + 'px'
7359 var scrollHeight = this.mainBody.dom.scrollHeight;
7361 var scrollTop = Math.ceil(this.mainBody.getScroll().top);
7363 var height = this.mainBody.getHeight();
7365 if(scrollHeight - height == scrollTop) {
7367 var total = this.ds.getTotalCount();
7369 if(this.footer.cursor + this.footer.pageSize < total){
7371 this.footer.ds.load({
7373 start : this.footer.cursor + this.footer.pageSize,
7374 limit : this.footer.pageSize
7384 onHeaderChange : function()
7386 var header = this.renderHeader();
7387 var table = this.el.select('table', true).first();
7389 this.mainHead.remove();
7390 this.mainHead = table.createChild(header, this.mainBody, false);
7393 onHiddenChange : function(colModel, colIndex, hidden)
7395 var thSelector = '#' + this.id + ' .x-hcol-' + colIndex;
7396 var tdSelector = '#' + this.id + ' .x-col-' + colIndex;
7398 this.CSS.updateRule(thSelector, "display", "");
7399 this.CSS.updateRule(tdSelector, "display", "");
7402 this.CSS.updateRule(thSelector, "display", "none");
7403 this.CSS.updateRule(tdSelector, "display", "none");
7406 this.onHeaderChange();
7410 setColumnWidth: function(col_index, width)
7412 // width = "md-2 xs-2..."
7413 if(!this.colModel.config[col_index]) {
7417 var w = width.split(" ");
7419 var rows = this.el.dom.getElementsByClassName("x-col-"+col_index);
7421 var h_row = this.el.dom.getElementsByClassName("x-hcol-"+col_index);
7424 for(var j = 0; j < w.length; j++) {
7430 var size_cls = w[j].split("-");
7432 if(!Number.isInteger(size_cls[1] * 1)) {
7436 if(!this.colModel.config[col_index][size_cls[0]]) {
7440 if(!h_row[0].classList.contains("col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]])) {
7444 h_row[0].classList.replace(
7445 "col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]],
7446 "col-"+size_cls[0]+"-"+size_cls[1]
7449 for(var i = 0; i < rows.length; i++) {
7451 var size_cls = w[j].split("-");
7453 if(!Number.isInteger(size_cls[1] * 1)) {
7457 if(!this.colModel.config[col_index][size_cls[0]]) {
7461 if(!rows[i].classList.contains("col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]])) {
7465 rows[i].classList.replace(
7466 "col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]],
7467 "col-"+size_cls[0]+"-"+size_cls[1]
7471 this.colModel.config[col_index][size_cls[0]] = size_cls[1];
7486 * @class Roo.bootstrap.TableCell
7487 * @extends Roo.bootstrap.Component
7488 * Bootstrap TableCell class
7489 * @cfg {String} html cell contain text
7490 * @cfg {String} cls cell class
7491 * @cfg {String} tag cell tag (td|th) default td
7492 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
7493 * @cfg {String} align Aligns the content in a cell
7494 * @cfg {String} axis Categorizes cells
7495 * @cfg {String} bgcolor Specifies the background color of a cell
7496 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7497 * @cfg {Number} colspan Specifies the number of columns a cell should span
7498 * @cfg {String} headers Specifies one or more header cells a cell is related to
7499 * @cfg {Number} height Sets the height of a cell
7500 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
7501 * @cfg {Number} rowspan Sets the number of rows a cell should span
7502 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
7503 * @cfg {String} valign Vertical aligns the content in a cell
7504 * @cfg {Number} width Specifies the width of a cell
7507 * Create a new TableCell
7508 * @param {Object} config The config object
7511 Roo.bootstrap.TableCell = function(config){
7512 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
7515 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
7535 getAutoCreate : function(){
7536 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
7556 cfg.align=this.align
7562 cfg.bgcolor=this.bgcolor
7565 cfg.charoff=this.charoff
7568 cfg.colspan=this.colspan
7571 cfg.headers=this.headers
7574 cfg.height=this.height
7577 cfg.nowrap=this.nowrap
7580 cfg.rowspan=this.rowspan
7583 cfg.scope=this.scope
7586 cfg.valign=this.valign
7589 cfg.width=this.width
7608 * @class Roo.bootstrap.TableRow
7609 * @extends Roo.bootstrap.Component
7610 * Bootstrap TableRow class
7611 * @cfg {String} cls row class
7612 * @cfg {String} align Aligns the content in a table row
7613 * @cfg {String} bgcolor Specifies a background color for a table row
7614 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7615 * @cfg {String} valign Vertical aligns the content in a table row
7618 * Create a new TableRow
7619 * @param {Object} config The config object
7622 Roo.bootstrap.TableRow = function(config){
7623 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
7626 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
7634 getAutoCreate : function(){
7635 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
7645 cfg.align = this.align;
7648 cfg.bgcolor = this.bgcolor;
7651 cfg.charoff = this.charoff;
7654 cfg.valign = this.valign;
7672 * @class Roo.bootstrap.TableBody
7673 * @extends Roo.bootstrap.Component
7674 * Bootstrap TableBody class
7675 * @cfg {String} cls element class
7676 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
7677 * @cfg {String} align Aligns the content inside the element
7678 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
7679 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
7682 * Create a new TableBody
7683 * @param {Object} config The config object
7686 Roo.bootstrap.TableBody = function(config){
7687 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
7690 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
7698 getAutoCreate : function(){
7699 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
7713 cfg.align = this.align;
7716 cfg.charoff = this.charoff;
7719 cfg.valign = this.valign;
7726 // initEvents : function()
7733 // this.store = Roo.factory(this.store, Roo.data);
7734 // this.store.on('load', this.onLoad, this);
7736 // this.store.load();
7740 // onLoad: function ()
7742 // this.fireEvent('load', this);
7752 * Ext JS Library 1.1.1
7753 * Copyright(c) 2006-2007, Ext JS, LLC.
7755 * Originally Released Under LGPL - original licence link has changed is not relivant.
7758 * <script type="text/javascript">
7761 // as we use this in bootstrap.
7762 Roo.namespace('Roo.form');
7764 * @class Roo.form.Action
7765 * Internal Class used to handle form actions
7767 * @param {Roo.form.BasicForm} el The form element or its id
7768 * @param {Object} config Configuration options
7773 // define the action interface
7774 Roo.form.Action = function(form, options){
7776 this.options = options || {};
7779 * Client Validation Failed
7782 Roo.form.Action.CLIENT_INVALID = 'client';
7784 * Server Validation Failed
7787 Roo.form.Action.SERVER_INVALID = 'server';
7789 * Connect to Server Failed
7792 Roo.form.Action.CONNECT_FAILURE = 'connect';
7794 * Reading Data from Server Failed
7797 Roo.form.Action.LOAD_FAILURE = 'load';
7799 Roo.form.Action.prototype = {
7801 failureType : undefined,
7802 response : undefined,
7806 run : function(options){
7811 success : function(response){
7816 handleResponse : function(response){
7820 // default connection failure
7821 failure : function(response){
7823 this.response = response;
7824 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7825 this.form.afterAction(this, false);
7828 processResponse : function(response){
7829 this.response = response;
7830 if(!response.responseText){
7833 this.result = this.handleResponse(response);
7837 // utility functions used internally
7838 getUrl : function(appendParams){
7839 var url = this.options.url || this.form.url || this.form.el.dom.action;
7841 var p = this.getParams();
7843 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
7849 getMethod : function(){
7850 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
7853 getParams : function(){
7854 var bp = this.form.baseParams;
7855 var p = this.options.params;
7857 if(typeof p == "object"){
7858 p = Roo.urlEncode(Roo.applyIf(p, bp));
7859 }else if(typeof p == 'string' && bp){
7860 p += '&' + Roo.urlEncode(bp);
7863 p = Roo.urlEncode(bp);
7868 createCallback : function(){
7870 success: this.success,
7871 failure: this.failure,
7873 timeout: (this.form.timeout*1000),
7874 upload: this.form.fileUpload ? this.success : undefined
7879 Roo.form.Action.Submit = function(form, options){
7880 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
7883 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
7886 haveProgress : false,
7887 uploadComplete : false,
7889 // uploadProgress indicator.
7890 uploadProgress : function()
7892 if (!this.form.progressUrl) {
7896 if (!this.haveProgress) {
7897 Roo.MessageBox.progress("Uploading", "Uploading");
7899 if (this.uploadComplete) {
7900 Roo.MessageBox.hide();
7904 this.haveProgress = true;
7906 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
7908 var c = new Roo.data.Connection();
7910 url : this.form.progressUrl,
7915 success : function(req){
7916 //console.log(data);
7920 rdata = Roo.decode(req.responseText)
7922 Roo.log("Invalid data from server..");
7926 if (!rdata || !rdata.success) {
7928 Roo.MessageBox.alert(Roo.encode(rdata));
7931 var data = rdata.data;
7933 if (this.uploadComplete) {
7934 Roo.MessageBox.hide();
7939 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
7940 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
7943 this.uploadProgress.defer(2000,this);
7946 failure: function(data) {
7947 Roo.log('progress url failed ');
7958 // run get Values on the form, so it syncs any secondary forms.
7959 this.form.getValues();
7961 var o = this.options;
7962 var method = this.getMethod();
7963 var isPost = method == 'POST';
7964 if(o.clientValidation === false || this.form.isValid()){
7966 if (this.form.progressUrl) {
7967 this.form.findField('UPLOAD_IDENTIFIER').setValue(
7968 (new Date() * 1) + '' + Math.random());
7973 Roo.Ajax.request(Roo.apply(this.createCallback(), {
7974 form:this.form.el.dom,
7975 url:this.getUrl(!isPost),
7977 params:isPost ? this.getParams() : null,
7978 isUpload: this.form.fileUpload,
7979 formData : this.form.formData
7982 this.uploadProgress();
7984 }else if (o.clientValidation !== false){ // client validation failed
7985 this.failureType = Roo.form.Action.CLIENT_INVALID;
7986 this.form.afterAction(this, false);
7990 success : function(response)
7992 this.uploadComplete= true;
7993 if (this.haveProgress) {
7994 Roo.MessageBox.hide();
7998 var result = this.processResponse(response);
7999 if(result === true || result.success){
8000 this.form.afterAction(this, true);
8004 this.form.markInvalid(result.errors);
8005 this.failureType = Roo.form.Action.SERVER_INVALID;
8007 this.form.afterAction(this, false);
8009 failure : function(response)
8011 this.uploadComplete= true;
8012 if (this.haveProgress) {
8013 Roo.MessageBox.hide();
8016 this.response = response;
8017 this.failureType = Roo.form.Action.CONNECT_FAILURE;
8018 this.form.afterAction(this, false);
8021 handleResponse : function(response){
8022 if(this.form.errorReader){
8023 var rs = this.form.errorReader.read(response);
8026 for(var i = 0, len = rs.records.length; i < len; i++) {
8027 var r = rs.records[i];
8031 if(errors.length < 1){
8035 success : rs.success,
8041 ret = Roo.decode(response.responseText);
8045 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
8055 Roo.form.Action.Load = function(form, options){
8056 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
8057 this.reader = this.form.reader;
8060 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
8065 Roo.Ajax.request(Roo.apply(
8066 this.createCallback(), {
8067 method:this.getMethod(),
8068 url:this.getUrl(false),
8069 params:this.getParams()
8073 success : function(response){
8075 var result = this.processResponse(response);
8076 if(result === true || !result.success || !result.data){
8077 this.failureType = Roo.form.Action.LOAD_FAILURE;
8078 this.form.afterAction(this, false);
8081 this.form.clearInvalid();
8082 this.form.setValues(result.data);
8083 this.form.afterAction(this, true);
8086 handleResponse : function(response){
8087 if(this.form.reader){
8088 var rs = this.form.reader.read(response);
8089 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
8091 success : rs.success,
8095 return Roo.decode(response.responseText);
8099 Roo.form.Action.ACTION_TYPES = {
8100 'load' : Roo.form.Action.Load,
8101 'submit' : Roo.form.Action.Submit
8110 * @class Roo.bootstrap.Form
8111 * @extends Roo.bootstrap.Component
8112 * Bootstrap Form class
8113 * @cfg {String} method GET | POST (default POST)
8114 * @cfg {String} labelAlign top | left (default top)
8115 * @cfg {String} align left | right - for navbars
8116 * @cfg {Boolean} loadMask load mask when submit (default true)
8121 * @param {Object} config The config object
8125 Roo.bootstrap.Form = function(config){
8127 Roo.bootstrap.Form.superclass.constructor.call(this, config);
8129 Roo.bootstrap.Form.popover.apply();
8133 * @event clientvalidation
8134 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
8135 * @param {Form} this
8136 * @param {Boolean} valid true if the form has passed client-side validation
8138 clientvalidation: true,
8140 * @event beforeaction
8141 * Fires before any action is performed. Return false to cancel the action.
8142 * @param {Form} this
8143 * @param {Action} action The action to be performed
8147 * @event actionfailed
8148 * Fires when an action fails.
8149 * @param {Form} this
8150 * @param {Action} action The action that failed
8152 actionfailed : true,
8154 * @event actioncomplete
8155 * Fires when an action is completed.
8156 * @param {Form} this
8157 * @param {Action} action The action that completed
8159 actioncomplete : true
8163 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
8166 * @cfg {String} method
8167 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
8172 * The URL to use for form actions if one isn't supplied in the action options.
8175 * @cfg {Boolean} fileUpload
8176 * Set to true if this form is a file upload.
8180 * @cfg {Object} baseParams
8181 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
8185 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
8189 * @cfg {Sting} align (left|right) for navbar forms
8194 activeAction : null,
8197 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
8198 * element by passing it or its id or mask the form itself by passing in true.
8201 waitMsgTarget : false,
8206 * @cfg {Boolean} errorMask (true|false) default false
8211 * @cfg {Number} maskOffset Default 100
8216 * @cfg {Boolean} maskBody
8220 getAutoCreate : function(){
8224 method : this.method || 'POST',
8225 id : this.id || Roo.id(),
8228 if (this.parent().xtype.match(/^Nav/)) {
8229 cfg.cls = 'navbar-form form-inline navbar-' + this.align;
8233 if (this.labelAlign == 'left' ) {
8234 cfg.cls += ' form-horizontal';
8240 initEvents : function()
8242 this.el.on('submit', this.onSubmit, this);
8243 // this was added as random key presses on the form where triggering form submit.
8244 this.el.on('keypress', function(e) {
8245 if (e.getCharCode() != 13) {
8248 // we might need to allow it for textareas.. and some other items.
8249 // check e.getTarget().
8251 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
8255 Roo.log("keypress blocked");
8263 onSubmit : function(e){
8268 * Returns true if client-side validation on the form is successful.
8271 isValid : function(){
8272 var items = this.getItems();
8276 items.each(function(f){
8282 Roo.log('invalid field: ' + f.name);
8286 if(!target && f.el.isVisible(true)){
8292 if(this.errorMask && !valid){
8293 Roo.bootstrap.Form.popover.mask(this, target);
8300 * Returns true if any fields in this form have changed since their original load.
8303 isDirty : function(){
8305 var items = this.getItems();
8306 items.each(function(f){
8316 * Performs a predefined action (submit or load) or custom actions you define on this form.
8317 * @param {String} actionName The name of the action type
8318 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
8319 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
8320 * accept other config options):
8322 Property Type Description
8323 ---------------- --------------- ----------------------------------------------------------------------------------
8324 url String The url for the action (defaults to the form's url)
8325 method String The form method to use (defaults to the form's method, or POST if not defined)
8326 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
8327 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
8328 validate the form on the client (defaults to false)
8330 * @return {BasicForm} this
8332 doAction : function(action, options){
8333 if(typeof action == 'string'){
8334 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
8336 if(this.fireEvent('beforeaction', this, action) !== false){
8337 this.beforeAction(action);
8338 action.run.defer(100, action);
8344 beforeAction : function(action){
8345 var o = action.options;
8350 Roo.get(document.body).mask(o.waitMsg || "Sending", 'x-mask-loading')
8352 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
8355 // not really supported yet.. ??
8357 //if(this.waitMsgTarget === true){
8358 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
8359 //}else if(this.waitMsgTarget){
8360 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
8361 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
8363 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
8369 afterAction : function(action, success){
8370 this.activeAction = null;
8371 var o = action.options;
8376 Roo.get(document.body).unmask();
8382 //if(this.waitMsgTarget === true){
8383 // this.el.unmask();
8384 //}else if(this.waitMsgTarget){
8385 // this.waitMsgTarget.unmask();
8387 // Roo.MessageBox.updateProgress(1);
8388 // Roo.MessageBox.hide();
8395 Roo.callback(o.success, o.scope, [this, action]);
8396 this.fireEvent('actioncomplete', this, action);
8400 // failure condition..
8401 // we have a scenario where updates need confirming.
8402 // eg. if a locking scenario exists..
8403 // we look for { errors : { needs_confirm : true }} in the response.
8405 (typeof(action.result) != 'undefined') &&
8406 (typeof(action.result.errors) != 'undefined') &&
8407 (typeof(action.result.errors.needs_confirm) != 'undefined')
8410 Roo.log("not supported yet");
8413 Roo.MessageBox.confirm(
8414 "Change requires confirmation",
8415 action.result.errorMsg,
8420 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
8430 Roo.callback(o.failure, o.scope, [this, action]);
8431 // show an error message if no failed handler is set..
8432 if (!this.hasListener('actionfailed')) {
8433 Roo.log("need to add dialog support");
8435 Roo.MessageBox.alert("Error",
8436 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
8437 action.result.errorMsg :
8438 "Saving Failed, please check your entries or try again"
8443 this.fireEvent('actionfailed', this, action);
8448 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
8449 * @param {String} id The value to search for
8452 findField : function(id){
8453 var items = this.getItems();
8454 var field = items.get(id);
8456 items.each(function(f){
8457 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
8464 return field || null;
8467 * Mark fields in this form invalid in bulk.
8468 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
8469 * @return {BasicForm} this
8471 markInvalid : function(errors){
8472 if(errors instanceof Array){
8473 for(var i = 0, len = errors.length; i < len; i++){
8474 var fieldError = errors[i];
8475 var f = this.findField(fieldError.id);
8477 f.markInvalid(fieldError.msg);
8483 if(typeof errors[id] != 'function' && (field = this.findField(id))){
8484 field.markInvalid(errors[id]);
8488 //Roo.each(this.childForms || [], function (f) {
8489 // f.markInvalid(errors);
8496 * Set values for fields in this form in bulk.
8497 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
8498 * @return {BasicForm} this
8500 setValues : function(values){
8501 if(values instanceof Array){ // array of objects
8502 for(var i = 0, len = values.length; i < len; i++){
8504 var f = this.findField(v.id);
8506 f.setValue(v.value);
8507 if(this.trackResetOnLoad){
8508 f.originalValue = f.getValue();
8512 }else{ // object hash
8515 if(typeof values[id] != 'function' && (field = this.findField(id))){
8517 if (field.setFromData &&
8519 field.displayField &&
8520 // combos' with local stores can
8521 // be queried via setValue()
8522 // to set their value..
8523 (field.store && !field.store.isLocal)
8527 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
8528 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
8529 field.setFromData(sd);
8531 } else if(field.setFromData && (field.store && !field.store.isLocal)) {
8533 field.setFromData(values);
8536 field.setValue(values[id]);
8540 if(this.trackResetOnLoad){
8541 field.originalValue = field.getValue();
8547 //Roo.each(this.childForms || [], function (f) {
8548 // f.setValues(values);
8555 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
8556 * they are returned as an array.
8557 * @param {Boolean} asString
8560 getValues : function(asString){
8561 //if (this.childForms) {
8562 // copy values from the child forms
8563 // Roo.each(this.childForms, function (f) {
8564 // this.setValues(f.getValues());
8570 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
8571 if(asString === true){
8574 return Roo.urlDecode(fs);
8578 * Returns the fields in this form as an object with key/value pairs.
8579 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
8582 getFieldValues : function(with_hidden)
8584 var items = this.getItems();
8586 items.each(function(f){
8592 var v = f.getValue();
8594 if (f.inputType =='radio') {
8595 if (typeof(ret[f.getName()]) == 'undefined') {
8596 ret[f.getName()] = ''; // empty..
8599 if (!f.el.dom.checked) {
8607 if(f.xtype == 'MoneyField'){
8608 ret[f.currencyName] = f.getCurrency();
8611 // not sure if this supported any more..
8612 if ((typeof(v) == 'object') && f.getRawValue) {
8613 v = f.getRawValue() ; // dates..
8615 // combo boxes where name != hiddenName...
8616 if (f.name !== false && f.name != '' && f.name != f.getName()) {
8617 ret[f.name] = f.getRawValue();
8619 ret[f.getName()] = v;
8626 * Clears all invalid messages in this form.
8627 * @return {BasicForm} this
8629 clearInvalid : function(){
8630 var items = this.getItems();
8632 items.each(function(f){
8641 * @return {BasicForm} this
8644 var items = this.getItems();
8645 items.each(function(f){
8649 Roo.each(this.childForms || [], function (f) {
8657 getItems : function()
8659 var r=new Roo.util.MixedCollection(false, function(o){
8660 return o.id || (o.id = Roo.id());
8662 var iter = function(el) {
8669 Roo.each(el.items,function(e) {
8678 hideFields : function(items)
8680 Roo.each(items, function(i){
8682 var f = this.findField(i);
8693 showFields : function(items)
8695 Roo.each(items, function(i){
8697 var f = this.findField(i);
8710 Roo.apply(Roo.bootstrap.Form, {
8737 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
8738 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
8739 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
8740 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
8743 this.maskEl.top.enableDisplayMode("block");
8744 this.maskEl.left.enableDisplayMode("block");
8745 this.maskEl.bottom.enableDisplayMode("block");
8746 this.maskEl.right.enableDisplayMode("block");
8748 this.toolTip = new Roo.bootstrap.Tooltip({
8749 cls : 'roo-form-error-popover',
8751 'left' : ['r-l', [-2,0], 'right'],
8752 'right' : ['l-r', [2,0], 'left'],
8753 'bottom' : ['tl-bl', [0,2], 'top'],
8754 'top' : [ 'bl-tl', [0,-2], 'bottom']
8758 this.toolTip.render(Roo.get(document.body));
8760 this.toolTip.el.enableDisplayMode("block");
8762 Roo.get(document.body).on('click', function(){
8766 Roo.get(document.body).on('touchstart', function(){
8770 this.isApplied = true
8773 mask : function(form, target)
8777 this.target = target;
8779 if(!this.form.errorMask || !target.el){
8783 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.modal', 100, true) || Roo.get(document.body);
8785 Roo.log(scrollable);
8787 var ot = this.target.el.calcOffsetsTo(scrollable);
8789 var scrollTo = ot[1] - this.form.maskOffset;
8791 scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
8793 scrollable.scrollTo('top', scrollTo);
8795 var box = this.target.el.getBox();
8797 var zIndex = Roo.bootstrap.Modal.zIndex++;
8800 this.maskEl.top.setStyle('position', 'absolute');
8801 this.maskEl.top.setStyle('z-index', zIndex);
8802 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
8803 this.maskEl.top.setLeft(0);
8804 this.maskEl.top.setTop(0);
8805 this.maskEl.top.show();
8807 this.maskEl.left.setStyle('position', 'absolute');
8808 this.maskEl.left.setStyle('z-index', zIndex);
8809 this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
8810 this.maskEl.left.setLeft(0);
8811 this.maskEl.left.setTop(box.y - this.padding);
8812 this.maskEl.left.show();
8814 this.maskEl.bottom.setStyle('position', 'absolute');
8815 this.maskEl.bottom.setStyle('z-index', zIndex);
8816 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
8817 this.maskEl.bottom.setLeft(0);
8818 this.maskEl.bottom.setTop(box.bottom + this.padding);
8819 this.maskEl.bottom.show();
8821 this.maskEl.right.setStyle('position', 'absolute');
8822 this.maskEl.right.setStyle('z-index', zIndex);
8823 this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
8824 this.maskEl.right.setLeft(box.right + this.padding);
8825 this.maskEl.right.setTop(box.y - this.padding);
8826 this.maskEl.right.show();
8828 this.toolTip.bindEl = this.target.el;
8830 this.toolTip.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
8832 var tip = this.target.blankText;
8834 if(this.target.getValue() !== '' ) {
8836 if (this.target.invalidText.length) {
8837 tip = this.target.invalidText;
8838 } else if (this.target.regexText.length){
8839 tip = this.target.regexText;
8843 this.toolTip.show(tip);
8845 this.intervalID = window.setInterval(function() {
8846 Roo.bootstrap.Form.popover.unmask();
8849 window.onwheel = function(){ return false;};
8851 (function(){ this.isMasked = true; }).defer(500, this);
8857 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
8861 this.maskEl.top.setStyle('position', 'absolute');
8862 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
8863 this.maskEl.top.hide();
8865 this.maskEl.left.setStyle('position', 'absolute');
8866 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
8867 this.maskEl.left.hide();
8869 this.maskEl.bottom.setStyle('position', 'absolute');
8870 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
8871 this.maskEl.bottom.hide();
8873 this.maskEl.right.setStyle('position', 'absolute');
8874 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
8875 this.maskEl.right.hide();
8877 this.toolTip.hide();
8879 this.toolTip.el.hide();
8881 window.onwheel = function(){ return true;};
8883 if(this.intervalID){
8884 window.clearInterval(this.intervalID);
8885 this.intervalID = false;
8888 this.isMasked = false;
8898 * Ext JS Library 1.1.1
8899 * Copyright(c) 2006-2007, Ext JS, LLC.
8901 * Originally Released Under LGPL - original licence link has changed is not relivant.
8904 * <script type="text/javascript">
8907 * @class Roo.form.VTypes
8908 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
8911 Roo.form.VTypes = function(){
8912 // closure these in so they are only created once.
8913 var alpha = /^[a-zA-Z_]+$/;
8914 var alphanum = /^[a-zA-Z0-9_]+$/;
8915 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
8916 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
8918 // All these messages and functions are configurable
8921 * The function used to validate email addresses
8922 * @param {String} value The email address
8924 'email' : function(v){
8925 return email.test(v);
8928 * The error text to display when the email validation function returns false
8931 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
8933 * The keystroke filter mask to be applied on email input
8936 'emailMask' : /[a-z0-9_\.\-@]/i,
8939 * The function used to validate URLs
8940 * @param {String} value The URL
8942 'url' : function(v){
8946 * The error text to display when the url validation function returns false
8949 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
8952 * The function used to validate alpha values
8953 * @param {String} value The value
8955 'alpha' : function(v){
8956 return alpha.test(v);
8959 * The error text to display when the alpha validation function returns false
8962 'alphaText' : 'This field should only contain letters and _',
8964 * The keystroke filter mask to be applied on alpha input
8967 'alphaMask' : /[a-z_]/i,
8970 * The function used to validate alphanumeric values
8971 * @param {String} value The value
8973 'alphanum' : function(v){
8974 return alphanum.test(v);
8977 * The error text to display when the alphanumeric validation function returns false
8980 'alphanumText' : 'This field should only contain letters, numbers and _',
8982 * The keystroke filter mask to be applied on alphanumeric input
8985 'alphanumMask' : /[a-z0-9_]/i
8995 * @class Roo.bootstrap.Input
8996 * @extends Roo.bootstrap.Component
8997 * Bootstrap Input class
8998 * @cfg {Boolean} disabled is it disabled
8999 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
9000 * @cfg {String} name name of the input
9001 * @cfg {string} fieldLabel - the label associated
9002 * @cfg {string} placeholder - placeholder to put in text.
9003 * @cfg {string} before - input group add on before
9004 * @cfg {string} after - input group add on after
9005 * @cfg {string} size - (lg|sm) or leave empty..
9006 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
9007 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
9008 * @cfg {Number} md colspan out of 12 for computer-sized screens
9009 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
9010 * @cfg {string} value default value of the input
9011 * @cfg {Number} labelWidth set the width of label
9012 * @cfg {Number} labellg set the width of label (1-12)
9013 * @cfg {Number} labelmd set the width of label (1-12)
9014 * @cfg {Number} labelsm set the width of label (1-12)
9015 * @cfg {Number} labelxs set the width of label (1-12)
9016 * @cfg {String} labelAlign (top|left)
9017 * @cfg {Boolean} readOnly Specifies that the field should be read-only
9018 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
9019 * @cfg {String} indicatorpos (left|right) default left
9020 * @cfg {String} capture (user|camera) use for file input only. (default empty)
9021 * @cfg {String} accept (image|video|audio) use for file input only. (default empty)
9023 * @cfg {String} align (left|center|right) Default left
9024 * @cfg {Boolean} forceFeedback (true|false) Default false
9027 * Create a new Input
9028 * @param {Object} config The config object
9031 Roo.bootstrap.Input = function(config){
9033 Roo.bootstrap.Input.superclass.constructor.call(this, config);
9038 * Fires when this field receives input focus.
9039 * @param {Roo.form.Field} this
9044 * Fires when this field loses input focus.
9045 * @param {Roo.form.Field} this
9050 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
9051 * {@link Roo.EventObject#getKey} to determine which key was pressed.
9052 * @param {Roo.form.Field} this
9053 * @param {Roo.EventObject} e The event object
9058 * Fires just before the field blurs if the field value has changed.
9059 * @param {Roo.form.Field} this
9060 * @param {Mixed} newValue The new value
9061 * @param {Mixed} oldValue The original value
9066 * Fires after the field has been marked as invalid.
9067 * @param {Roo.form.Field} this
9068 * @param {String} msg The validation message
9073 * Fires after the field has been validated with no errors.
9074 * @param {Roo.form.Field} this
9079 * Fires after the key up
9080 * @param {Roo.form.Field} this
9081 * @param {Roo.EventObject} e The event Object
9087 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
9089 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
9090 automatic validation (defaults to "keyup").
9092 validationEvent : "keyup",
9094 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
9096 validateOnBlur : true,
9098 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
9100 validationDelay : 250,
9102 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
9104 focusClass : "x-form-focus", // not needed???
9108 * @cfg {String} invalidClass DEPRICATED - code uses BS4 - is-valid / is-invalid
9110 invalidClass : "has-warning",
9113 * @cfg {String} validClass DEPRICATED - code uses BS4 - is-valid / is-invalid
9115 validClass : "has-success",
9118 * @cfg {Boolean} hasFeedback (true|false) default true
9123 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
9125 invalidFeedbackClass : "glyphicon-warning-sign",
9128 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
9130 validFeedbackClass : "glyphicon-ok",
9133 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
9135 selectOnFocus : false,
9138 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
9142 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
9147 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
9149 disableKeyFilter : false,
9152 * @cfg {Boolean} disabled True to disable the field (defaults to false).
9156 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
9160 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
9162 blankText : "Please complete this mandatory field",
9165 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
9169 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
9171 maxLength : Number.MAX_VALUE,
9173 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
9175 minLengthText : "The minimum length for this field is {0}",
9177 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
9179 maxLengthText : "The maximum length for this field is {0}",
9183 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
9184 * If available, this function will be called only after the basic validators all return true, and will be passed the
9185 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
9189 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
9190 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
9191 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
9195 * @cfg {String} regexText -- Depricated - use Invalid Text
9200 * @cfg {String} invalidText The error text to display if {@link #validator} test fails during validation (defaults to "")
9206 autocomplete: false,
9225 formatedValue : false,
9226 forceFeedback : false,
9228 indicatorpos : 'left',
9238 parentLabelAlign : function()
9241 while (parent.parent()) {
9242 parent = parent.parent();
9243 if (typeof(parent.labelAlign) !='undefined') {
9244 return parent.labelAlign;
9251 getAutoCreate : function()
9253 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9259 if(this.inputType != 'hidden'){
9260 cfg.cls = 'form-group' //input-group
9266 type : this.inputType,
9268 cls : 'form-control',
9269 placeholder : this.placeholder || '',
9270 autocomplete : this.autocomplete || 'new-password'
9273 if(this.capture.length){
9274 input.capture = this.capture;
9277 if(this.accept.length){
9278 input.accept = this.accept + "/*";
9282 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
9285 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9286 input.maxLength = this.maxLength;
9289 if (this.disabled) {
9290 input.disabled=true;
9293 if (this.readOnly) {
9294 input.readonly=true;
9298 input.name = this.name;
9302 input.cls += ' input-' + this.size;
9306 ['xs','sm','md','lg'].map(function(size){
9307 if (settings[size]) {
9308 cfg.cls += ' col-' + size + '-' + settings[size];
9312 var inputblock = input;
9316 cls: 'glyphicon form-control-feedback'
9319 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9322 cls : 'has-feedback',
9330 if (this.before || this.after) {
9333 cls : 'input-group',
9337 if (this.before && typeof(this.before) == 'string') {
9339 inputblock.cn.push({
9341 cls : 'roo-input-before input-group-addon input-group-prepend input-group-text',
9345 if (this.before && typeof(this.before) == 'object') {
9346 this.before = Roo.factory(this.before);
9348 inputblock.cn.push({
9350 cls : 'roo-input-before input-group-prepend input-group-text input-group-' +
9351 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
9355 inputblock.cn.push(input);
9357 if (this.after && typeof(this.after) == 'string') {
9358 inputblock.cn.push({
9360 cls : 'roo-input-after input-group-append input-group-text input-group-addon',
9364 if (this.after && typeof(this.after) == 'object') {
9365 this.after = Roo.factory(this.after);
9367 inputblock.cn.push({
9369 cls : 'roo-input-after input-group-append input-group-text input-group-' +
9370 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
9374 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9375 inputblock.cls += ' has-feedback';
9376 inputblock.cn.push(feedback);
9381 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
9382 tooltip : 'This field is required'
9384 if (Roo.bootstrap.version == 4) {
9387 style : 'display-none'
9390 if (align ==='left' && this.fieldLabel.length) {
9392 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
9399 cls : 'control-label col-form-label',
9400 html : this.fieldLabel
9411 var labelCfg = cfg.cn[1];
9412 var contentCfg = cfg.cn[2];
9414 if(this.indicatorpos == 'right'){
9419 cls : 'control-label col-form-label',
9423 html : this.fieldLabel
9437 labelCfg = cfg.cn[0];
9438 contentCfg = cfg.cn[1];
9442 if(this.labelWidth > 12){
9443 labelCfg.style = "width: " + this.labelWidth + 'px';
9446 if(this.labelWidth < 13 && this.labelmd == 0){
9447 this.labelmd = this.labelWidth;
9450 if(this.labellg > 0){
9451 labelCfg.cls += ' col-lg-' + this.labellg;
9452 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
9455 if(this.labelmd > 0){
9456 labelCfg.cls += ' col-md-' + this.labelmd;
9457 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
9460 if(this.labelsm > 0){
9461 labelCfg.cls += ' col-sm-' + this.labelsm;
9462 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
9465 if(this.labelxs > 0){
9466 labelCfg.cls += ' col-xs-' + this.labelxs;
9467 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
9471 } else if ( this.fieldLabel.length) {
9476 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
9477 tooltip : 'This field is required'
9481 //cls : 'input-group-addon',
9482 html : this.fieldLabel
9490 if(this.indicatorpos == 'right'){
9495 //cls : 'input-group-addon',
9496 html : this.fieldLabel
9501 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9502 tooltip : 'This field is required'
9522 if (this.parentType === 'Navbar' && this.parent().bar) {
9523 cfg.cls += ' navbar-form';
9526 if (this.parentType === 'NavGroup' && !(Roo.bootstrap.version == 4 && this.parent().form)) {
9527 // on BS4 we do this only if not form
9528 cfg.cls += ' navbar-form';
9536 * return the real input element.
9538 inputEl: function ()
9540 return this.el.select('input.form-control',true).first();
9543 tooltipEl : function()
9545 return this.inputEl();
9548 indicatorEl : function()
9550 if (Roo.bootstrap.version == 4) {
9551 return false; // not enabled in v4 yet.
9554 var indicator = this.el.select('i.roo-required-indicator',true).first();
9564 setDisabled : function(v)
9566 var i = this.inputEl().dom;
9568 i.removeAttribute('disabled');
9572 i.setAttribute('disabled','true');
9574 initEvents : function()
9577 this.inputEl().on("keydown" , this.fireKey, this);
9578 this.inputEl().on("focus", this.onFocus, this);
9579 this.inputEl().on("blur", this.onBlur, this);
9581 this.inputEl().relayEvent('keyup', this);
9583 this.indicator = this.indicatorEl();
9586 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible'); // changed from invisible??? -
9589 // reference to original value for reset
9590 this.originalValue = this.getValue();
9591 //Roo.form.TextField.superclass.initEvents.call(this);
9592 if(this.validationEvent == 'keyup'){
9593 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
9594 this.inputEl().on('keyup', this.filterValidation, this);
9596 else if(this.validationEvent !== false){
9597 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
9600 if(this.selectOnFocus){
9601 this.on("focus", this.preFocus, this);
9604 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
9605 this.inputEl().on("keypress", this.filterKeys, this);
9607 this.inputEl().relayEvent('keypress', this);
9610 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
9611 this.el.on("click", this.autoSize, this);
9614 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
9615 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
9618 if (typeof(this.before) == 'object') {
9619 this.before.render(this.el.select('.roo-input-before',true).first());
9621 if (typeof(this.after) == 'object') {
9622 this.after.render(this.el.select('.roo-input-after',true).first());
9625 this.inputEl().on('change', this.onChange, this);
9628 filterValidation : function(e){
9629 if(!e.isNavKeyPress()){
9630 this.validationTask.delay(this.validationDelay);
9634 * Validates the field value
9635 * @return {Boolean} True if the value is valid, else false
9637 validate : function(){
9638 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
9639 if(this.disabled || this.validateValue(this.getRawValue())){
9650 * Validates a value according to the field's validation rules and marks the field as invalid
9651 * if the validation fails
9652 * @param {Mixed} value The value to validate
9653 * @return {Boolean} True if the value is valid, else false
9655 validateValue : function(value)
9657 if(this.getVisibilityEl().hasClass('hidden')){
9661 if(value.length < 1) { // if it's blank
9662 if(this.allowBlank){
9668 if(value.length < this.minLength){
9671 if(value.length > this.maxLength){
9675 var vt = Roo.form.VTypes;
9676 if(!vt[this.vtype](value, this)){
9680 if(typeof this.validator == "function"){
9681 var msg = this.validator(value);
9685 if (typeof(msg) == 'string') {
9686 this.invalidText = msg;
9690 if(this.regex && !this.regex.test(value)){
9698 fireKey : function(e){
9699 //Roo.log('field ' + e.getKey());
9700 if(e.isNavKeyPress()){
9701 this.fireEvent("specialkey", this, e);
9704 focus : function (selectText){
9706 this.inputEl().focus();
9707 if(selectText === true){
9708 this.inputEl().dom.select();
9714 onFocus : function(){
9715 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9716 // this.el.addClass(this.focusClass);
9719 this.hasFocus = true;
9720 this.startValue = this.getValue();
9721 this.fireEvent("focus", this);
9725 beforeBlur : Roo.emptyFn,
9729 onBlur : function(){
9731 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9732 //this.el.removeClass(this.focusClass);
9734 this.hasFocus = false;
9735 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
9738 var v = this.getValue();
9739 if(String(v) !== String(this.startValue)){
9740 this.fireEvent('change', this, v, this.startValue);
9742 this.fireEvent("blur", this);
9745 onChange : function(e)
9747 var v = this.getValue();
9748 if(String(v) !== String(this.startValue)){
9749 this.fireEvent('change', this, v, this.startValue);
9755 * Resets the current field value to the originally loaded value and clears any validation messages
9758 this.setValue(this.originalValue);
9762 * Returns the name of the field
9763 * @return {Mixed} name The name field
9765 getName: function(){
9769 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
9770 * @return {Mixed} value The field value
9772 getValue : function(){
9774 var v = this.inputEl().getValue();
9779 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
9780 * @return {Mixed} value The field value
9782 getRawValue : function(){
9783 var v = this.inputEl().getValue();
9789 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
9790 * @param {Mixed} value The value to set
9792 setRawValue : function(v){
9793 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9796 selectText : function(start, end){
9797 var v = this.getRawValue();
9799 start = start === undefined ? 0 : start;
9800 end = end === undefined ? v.length : end;
9801 var d = this.inputEl().dom;
9802 if(d.setSelectionRange){
9803 d.setSelectionRange(start, end);
9804 }else if(d.createTextRange){
9805 var range = d.createTextRange();
9806 range.moveStart("character", start);
9807 range.moveEnd("character", v.length-end);
9814 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
9815 * @param {Mixed} value The value to set
9817 setValue : function(v){
9820 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9826 processValue : function(value){
9827 if(this.stripCharsRe){
9828 var newValue = value.replace(this.stripCharsRe, '');
9829 if(newValue !== value){
9830 this.setRawValue(newValue);
9837 preFocus : function(){
9839 if(this.selectOnFocus){
9840 this.inputEl().dom.select();
9843 filterKeys : function(e){
9845 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
9848 var c = e.getCharCode(), cc = String.fromCharCode(c);
9849 if(Roo.isIE && (e.isSpecialKey() || !cc)){
9852 if(!this.maskRe.test(cc)){
9857 * Clear any invalid styles/messages for this field
9859 clearInvalid : function(){
9861 if(!this.el || this.preventMark){ // not rendered
9866 this.el.removeClass([this.invalidClass, 'is-invalid']);
9868 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9870 var feedback = this.el.select('.form-control-feedback', true).first();
9873 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9879 this.indicator.removeClass('visible');
9880 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9883 this.fireEvent('valid', this);
9887 * Mark this field as valid
9889 markValid : function()
9891 if(!this.el || this.preventMark){ // not rendered...
9895 this.el.removeClass([this.invalidClass, this.validClass]);
9896 this.inputEl().removeClass(['is-valid', 'is-invalid']);
9898 var feedback = this.el.select('.form-control-feedback', true).first();
9901 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9905 this.indicator.removeClass('visible');
9906 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9913 if(this.allowBlank && !this.getRawValue().length){
9916 if (Roo.bootstrap.version == 3) {
9917 this.el.addClass(this.validClass);
9919 this.inputEl().addClass('is-valid');
9922 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9924 var feedback = this.el.select('.form-control-feedback', true).first();
9927 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9928 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9933 this.fireEvent('valid', this);
9937 * Mark this field as invalid
9938 * @param {String} msg The validation message
9940 markInvalid : function(msg)
9942 if(!this.el || this.preventMark){ // not rendered
9946 this.el.removeClass([this.invalidClass, this.validClass]);
9947 this.inputEl().removeClass(['is-valid', 'is-invalid']);
9949 var feedback = this.el.select('.form-control-feedback', true).first();
9952 this.el.select('.form-control-feedback', true).first().removeClass(
9953 [this.invalidFeedbackClass, this.validFeedbackClass]);
9960 if(this.allowBlank && !this.getRawValue().length){
9965 this.indicator.removeClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9966 this.indicator.addClass('visible');
9968 if (Roo.bootstrap.version == 3) {
9969 this.el.addClass(this.invalidClass);
9971 this.inputEl().addClass('is-invalid');
9976 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9978 var feedback = this.el.select('.form-control-feedback', true).first();
9981 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9983 if(this.getValue().length || this.forceFeedback){
9984 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9991 this.fireEvent('invalid', this, msg);
9994 SafariOnKeyDown : function(event)
9996 // this is a workaround for a password hang bug on chrome/ webkit.
9997 if (this.inputEl().dom.type != 'password') {
10001 var isSelectAll = false;
10003 if(this.inputEl().dom.selectionEnd > 0){
10004 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
10006 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
10007 event.preventDefault();
10012 if(isSelectAll && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
10014 event.preventDefault();
10015 // this is very hacky as keydown always get's upper case.
10017 var cc = String.fromCharCode(event.getCharCode());
10018 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
10022 adjustWidth : function(tag, w){
10023 tag = tag.toLowerCase();
10024 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
10025 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
10026 if(tag == 'input'){
10029 if(tag == 'textarea'){
10032 }else if(Roo.isOpera){
10033 if(tag == 'input'){
10036 if(tag == 'textarea'){
10044 setFieldLabel : function(v)
10046 if(!this.rendered){
10050 if(this.indicatorEl()){
10051 var ar = this.el.select('label > span',true);
10053 if (ar.elements.length) {
10054 this.el.select('label > span',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
10055 this.fieldLabel = v;
10059 var br = this.el.select('label',true);
10061 if(br.elements.length) {
10062 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
10063 this.fieldLabel = v;
10067 Roo.log('Cannot Found any of label > span || label in input');
10071 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
10072 this.fieldLabel = v;
10087 * @class Roo.bootstrap.TextArea
10088 * @extends Roo.bootstrap.Input
10089 * Bootstrap TextArea class
10090 * @cfg {Number} cols Specifies the visible width of a text area
10091 * @cfg {Number} rows Specifies the visible number of lines in a text area
10092 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
10093 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
10094 * @cfg {string} html text
10097 * Create a new TextArea
10098 * @param {Object} config The config object
10101 Roo.bootstrap.TextArea = function(config){
10102 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
10106 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
10116 getAutoCreate : function(){
10118 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
10124 if(this.inputType != 'hidden'){
10125 cfg.cls = 'form-group' //input-group
10133 value : this.value || '',
10134 html: this.html || '',
10135 cls : 'form-control',
10136 placeholder : this.placeholder || ''
10140 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
10141 input.maxLength = this.maxLength;
10145 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
10149 input.cols = this.cols;
10152 if (this.readOnly) {
10153 input.readonly = true;
10157 input.name = this.name;
10161 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
10165 ['xs','sm','md','lg'].map(function(size){
10166 if (settings[size]) {
10167 cfg.cls += ' col-' + size + '-' + settings[size];
10171 var inputblock = input;
10173 if(this.hasFeedback && !this.allowBlank){
10177 cls: 'glyphicon form-control-feedback'
10181 cls : 'has-feedback',
10190 if (this.before || this.after) {
10193 cls : 'input-group',
10197 inputblock.cn.push({
10199 cls : 'input-group-addon',
10204 inputblock.cn.push(input);
10206 if(this.hasFeedback && !this.allowBlank){
10207 inputblock.cls += ' has-feedback';
10208 inputblock.cn.push(feedback);
10212 inputblock.cn.push({
10214 cls : 'input-group-addon',
10221 if (align ==='left' && this.fieldLabel.length) {
10226 cls : 'control-label',
10227 html : this.fieldLabel
10238 if(this.labelWidth > 12){
10239 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
10242 if(this.labelWidth < 13 && this.labelmd == 0){
10243 this.labelmd = this.labelWidth;
10246 if(this.labellg > 0){
10247 cfg.cn[0].cls += ' col-lg-' + this.labellg;
10248 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
10251 if(this.labelmd > 0){
10252 cfg.cn[0].cls += ' col-md-' + this.labelmd;
10253 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
10256 if(this.labelsm > 0){
10257 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
10258 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
10261 if(this.labelxs > 0){
10262 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
10263 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
10266 } else if ( this.fieldLabel.length) {
10271 //cls : 'input-group-addon',
10272 html : this.fieldLabel
10290 if (this.disabled) {
10291 input.disabled=true;
10298 * return the real textarea element.
10300 inputEl: function ()
10302 return this.el.select('textarea.form-control',true).first();
10306 * Clear any invalid styles/messages for this field
10308 clearInvalid : function()
10311 if(!this.el || this.preventMark){ // not rendered
10315 var label = this.el.select('label', true).first();
10316 var icon = this.el.select('i.fa-star', true).first();
10321 this.el.removeClass( this.validClass);
10322 this.inputEl().removeClass('is-invalid');
10324 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10326 var feedback = this.el.select('.form-control-feedback', true).first();
10329 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
10334 this.fireEvent('valid', this);
10338 * Mark this field as valid
10340 markValid : function()
10342 if(!this.el || this.preventMark){ // not rendered
10346 this.el.removeClass([this.invalidClass, this.validClass]);
10347 this.inputEl().removeClass(['is-valid', 'is-invalid']);
10349 var feedback = this.el.select('.form-control-feedback', true).first();
10352 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10355 if(this.disabled || this.allowBlank){
10359 var label = this.el.select('label', true).first();
10360 var icon = this.el.select('i.fa-star', true).first();
10365 if (Roo.bootstrap.version == 3) {
10366 this.el.addClass(this.validClass);
10368 this.inputEl().addClass('is-valid');
10372 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
10374 var feedback = this.el.select('.form-control-feedback', true).first();
10377 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10378 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
10383 this.fireEvent('valid', this);
10387 * Mark this field as invalid
10388 * @param {String} msg The validation message
10390 markInvalid : function(msg)
10392 if(!this.el || this.preventMark){ // not rendered
10396 this.el.removeClass([this.invalidClass, this.validClass]);
10397 this.inputEl().removeClass(['is-valid', 'is-invalid']);
10399 var feedback = this.el.select('.form-control-feedback', true).first();
10402 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10405 if(this.disabled || this.allowBlank){
10409 var label = this.el.select('label', true).first();
10410 var icon = this.el.select('i.fa-star', true).first();
10412 if(!this.getValue().length && label && !icon){
10413 this.el.createChild({
10415 cls : 'text-danger fa fa-lg fa-star',
10416 tooltip : 'This field is required',
10417 style : 'margin-right:5px;'
10421 if (Roo.bootstrap.version == 3) {
10422 this.el.addClass(this.invalidClass);
10424 this.inputEl().addClass('is-invalid');
10427 // fixme ... this may be depricated need to test..
10428 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10430 var feedback = this.el.select('.form-control-feedback', true).first();
10433 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10435 if(this.getValue().length || this.forceFeedback){
10436 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
10443 this.fireEvent('invalid', this, msg);
10451 * trigger field - base class for combo..
10456 * @class Roo.bootstrap.TriggerField
10457 * @extends Roo.bootstrap.Input
10458 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
10459 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
10460 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
10461 * for which you can provide a custom implementation. For example:
10463 var trigger = new Roo.bootstrap.TriggerField();
10464 trigger.onTriggerClick = myTriggerFn;
10465 trigger.applyTo('my-field');
10468 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
10469 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
10470 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
10471 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
10472 * @cfg {String} caret (search|calendar) BS3 only - carat fa name
10475 * Create a new TriggerField.
10476 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
10477 * to the base TextField)
10479 Roo.bootstrap.TriggerField = function(config){
10480 this.mimicing = false;
10481 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
10484 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
10486 * @cfg {String} triggerClass A CSS class to apply to the trigger
10489 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
10494 * @cfg {Boolean} removable (true|false) special filter default false
10498 /** @cfg {Boolean} grow @hide */
10499 /** @cfg {Number} growMin @hide */
10500 /** @cfg {Number} growMax @hide */
10506 autoSize: Roo.emptyFn,
10510 deferHeight : true,
10513 actionMode : 'wrap',
10518 getAutoCreate : function(){
10520 var align = this.labelAlign || this.parentLabelAlign();
10525 cls: 'form-group' //input-group
10532 type : this.inputType,
10533 cls : 'form-control',
10534 autocomplete: 'new-password',
10535 placeholder : this.placeholder || ''
10539 input.name = this.name;
10542 input.cls += ' input-' + this.size;
10545 if (this.disabled) {
10546 input.disabled=true;
10549 var inputblock = input;
10551 if(this.hasFeedback && !this.allowBlank){
10555 cls: 'glyphicon form-control-feedback'
10558 if(this.removable && !this.editable && !this.tickable){
10560 cls : 'has-feedback',
10566 cls : 'roo-combo-removable-btn close'
10573 cls : 'has-feedback',
10582 if(this.removable && !this.editable && !this.tickable){
10584 cls : 'roo-removable',
10590 cls : 'roo-combo-removable-btn close'
10597 if (this.before || this.after) {
10600 cls : 'input-group',
10604 inputblock.cn.push({
10606 cls : 'input-group-addon input-group-prepend input-group-text',
10611 inputblock.cn.push(input);
10613 if(this.hasFeedback && !this.allowBlank){
10614 inputblock.cls += ' has-feedback';
10615 inputblock.cn.push(feedback);
10619 inputblock.cn.push({
10621 cls : 'input-group-addon input-group-append input-group-text',
10630 var ibwrap = inputblock;
10635 cls: 'roo-select2-choices',
10639 cls: 'roo-select2-search-field',
10651 cls: 'roo-select2-container input-group',
10656 cls: 'form-hidden-field'
10662 if(!this.multiple && this.showToggleBtn){
10668 if (this.caret != false) {
10671 cls: 'fa fa-' + this.caret
10678 cls : 'input-group-addon input-group-append input-group-text btn dropdown-toggle',
10680 Roo.bootstrap.version == 3 ? caret : '',
10683 cls: 'combobox-clear',
10697 combobox.cls += ' roo-select2-container-multi';
10701 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
10702 tooltip : 'This field is required'
10704 if (Roo.bootstrap.version == 4) {
10707 style : 'display:none'
10712 if (align ==='left' && this.fieldLabel.length) {
10714 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
10721 cls : 'control-label',
10722 html : this.fieldLabel
10734 var labelCfg = cfg.cn[1];
10735 var contentCfg = cfg.cn[2];
10737 if(this.indicatorpos == 'right'){
10742 cls : 'control-label',
10746 html : this.fieldLabel
10760 labelCfg = cfg.cn[0];
10761 contentCfg = cfg.cn[1];
10764 if(this.labelWidth > 12){
10765 labelCfg.style = "width: " + this.labelWidth + 'px';
10768 if(this.labelWidth < 13 && this.labelmd == 0){
10769 this.labelmd = this.labelWidth;
10772 if(this.labellg > 0){
10773 labelCfg.cls += ' col-lg-' + this.labellg;
10774 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
10777 if(this.labelmd > 0){
10778 labelCfg.cls += ' col-md-' + this.labelmd;
10779 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
10782 if(this.labelsm > 0){
10783 labelCfg.cls += ' col-sm-' + this.labelsm;
10784 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
10787 if(this.labelxs > 0){
10788 labelCfg.cls += ' col-xs-' + this.labelxs;
10789 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
10792 } else if ( this.fieldLabel.length) {
10793 // Roo.log(" label");
10798 //cls : 'input-group-addon',
10799 html : this.fieldLabel
10807 if(this.indicatorpos == 'right'){
10815 html : this.fieldLabel
10829 // Roo.log(" no label && no align");
10836 ['xs','sm','md','lg'].map(function(size){
10837 if (settings[size]) {
10838 cfg.cls += ' col-' + size + '-' + settings[size];
10849 onResize : function(w, h){
10850 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
10851 // if(typeof w == 'number'){
10852 // var x = w - this.trigger.getWidth();
10853 // this.inputEl().setWidth(this.adjustWidth('input', x));
10854 // this.trigger.setStyle('left', x+'px');
10859 adjustSize : Roo.BoxComponent.prototype.adjustSize,
10862 getResizeEl : function(){
10863 return this.inputEl();
10867 getPositionEl : function(){
10868 return this.inputEl();
10872 alignErrorIcon : function(){
10873 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
10877 initEvents : function(){
10881 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
10882 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
10883 if(!this.multiple && this.showToggleBtn){
10884 this.trigger = this.el.select('span.dropdown-toggle',true).first();
10885 if(this.hideTrigger){
10886 this.trigger.setDisplayed(false);
10888 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10892 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
10895 if(this.removable && !this.editable && !this.tickable){
10896 var close = this.closeTriggerEl();
10899 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
10900 close.on('click', this.removeBtnClick, this, close);
10904 //this.trigger.addClassOnOver('x-form-trigger-over');
10905 //this.trigger.addClassOnClick('x-form-trigger-click');
10908 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
10912 closeTriggerEl : function()
10914 var close = this.el.select('.roo-combo-removable-btn', true).first();
10915 return close ? close : false;
10918 removeBtnClick : function(e, h, el)
10920 e.preventDefault();
10922 if(this.fireEvent("remove", this) !== false){
10924 this.fireEvent("afterremove", this)
10928 createList : function()
10930 this.list = Roo.get(document.body).createChild({
10931 tag: Roo.bootstrap.version == 4 ? 'div' : 'ul',
10932 cls: 'typeahead typeahead-long dropdown-menu',
10933 style: 'display:none'
10936 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
10941 initTrigger : function(){
10946 onDestroy : function(){
10948 this.trigger.removeAllListeners();
10949 // this.trigger.remove();
10952 // this.wrap.remove();
10954 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
10958 onFocus : function(){
10959 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
10961 if(!this.mimicing){
10962 this.wrap.addClass('x-trigger-wrap-focus');
10963 this.mimicing = true;
10964 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
10965 if(this.monitorTab){
10966 this.el.on("keydown", this.checkTab, this);
10973 checkTab : function(e){
10974 if(e.getKey() == e.TAB){
10975 this.triggerBlur();
10980 onBlur : function(){
10985 mimicBlur : function(e, t){
10987 if(!this.wrap.contains(t) && this.validateBlur()){
10988 this.triggerBlur();
10994 triggerBlur : function(){
10995 this.mimicing = false;
10996 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
10997 if(this.monitorTab){
10998 this.el.un("keydown", this.checkTab, this);
11000 //this.wrap.removeClass('x-trigger-wrap-focus');
11001 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
11005 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
11006 validateBlur : function(e, t){
11011 onDisable : function(){
11012 this.inputEl().dom.disabled = true;
11013 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
11015 // this.wrap.addClass('x-item-disabled');
11020 onEnable : function(){
11021 this.inputEl().dom.disabled = false;
11022 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
11024 // this.el.removeClass('x-item-disabled');
11029 onShow : function(){
11030 var ae = this.getActionEl();
11033 ae.dom.style.display = '';
11034 ae.dom.style.visibility = 'visible';
11040 onHide : function(){
11041 var ae = this.getActionEl();
11042 ae.dom.style.display = 'none';
11046 * The function that should handle the trigger's click event. This method does nothing by default until overridden
11047 * by an implementing function.
11049 * @param {EventObject} e
11051 onTriggerClick : Roo.emptyFn
11055 * Ext JS Library 1.1.1
11056 * Copyright(c) 2006-2007, Ext JS, LLC.
11058 * Originally Released Under LGPL - original licence link has changed is not relivant.
11061 * <script type="text/javascript">
11066 * @class Roo.data.SortTypes
11068 * Defines the default sorting (casting?) comparison functions used when sorting data.
11070 Roo.data.SortTypes = {
11072 * Default sort that does nothing
11073 * @param {Mixed} s The value being converted
11074 * @return {Mixed} The comparison value
11076 none : function(s){
11081 * The regular expression used to strip tags
11085 stripTagsRE : /<\/?[^>]+>/gi,
11088 * Strips all HTML tags to sort on text only
11089 * @param {Mixed} s The value being converted
11090 * @return {String} The comparison value
11092 asText : function(s){
11093 return String(s).replace(this.stripTagsRE, "");
11097 * Strips all HTML tags to sort on text only - Case insensitive
11098 * @param {Mixed} s The value being converted
11099 * @return {String} The comparison value
11101 asUCText : function(s){
11102 return String(s).toUpperCase().replace(this.stripTagsRE, "");
11106 * Case insensitive string
11107 * @param {Mixed} s The value being converted
11108 * @return {String} The comparison value
11110 asUCString : function(s) {
11111 return String(s).toUpperCase();
11116 * @param {Mixed} s The value being converted
11117 * @return {Number} The comparison value
11119 asDate : function(s) {
11123 if(s instanceof Date){
11124 return s.getTime();
11126 return Date.parse(String(s));
11131 * @param {Mixed} s The value being converted
11132 * @return {Float} The comparison value
11134 asFloat : function(s) {
11135 var val = parseFloat(String(s).replace(/,/g, ""));
11144 * @param {Mixed} s The value being converted
11145 * @return {Number} The comparison value
11147 asInt : function(s) {
11148 var val = parseInt(String(s).replace(/,/g, ""));
11156 * Ext JS Library 1.1.1
11157 * Copyright(c) 2006-2007, Ext JS, LLC.
11159 * Originally Released Under LGPL - original licence link has changed is not relivant.
11162 * <script type="text/javascript">
11166 * @class Roo.data.Record
11167 * Instances of this class encapsulate both record <em>definition</em> information, and record
11168 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
11169 * to access Records cached in an {@link Roo.data.Store} object.<br>
11171 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
11172 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
11175 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
11177 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
11178 * {@link #create}. The parameters are the same.
11179 * @param {Array} data An associative Array of data values keyed by the field name.
11180 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
11181 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
11182 * not specified an integer id is generated.
11184 Roo.data.Record = function(data, id){
11185 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
11190 * Generate a constructor for a specific record layout.
11191 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
11192 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
11193 * Each field definition object may contain the following properties: <ul>
11194 * <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,
11195 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
11196 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
11197 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
11198 * is being used, then this is a string containing the javascript expression to reference the data relative to
11199 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
11200 * to the data item relative to the record element. If the mapping expression is the same as the field name,
11201 * this may be omitted.</p></li>
11202 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
11203 * <ul><li>auto (Default, implies no conversion)</li>
11208 * <li>date</li></ul></p></li>
11209 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
11210 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
11211 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
11212 * by the Reader into an object that will be stored in the Record. It is passed the
11213 * following parameters:<ul>
11214 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
11216 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
11218 * <br>usage:<br><pre><code>
11219 var TopicRecord = Roo.data.Record.create(
11220 {name: 'title', mapping: 'topic_title'},
11221 {name: 'author', mapping: 'username'},
11222 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
11223 {name: 'lastPost', mapping: 'post_time', type: 'date'},
11224 {name: 'lastPoster', mapping: 'user2'},
11225 {name: 'excerpt', mapping: 'post_text'}
11228 var myNewRecord = new TopicRecord({
11229 title: 'Do my job please',
11232 lastPost: new Date(),
11233 lastPoster: 'Animal',
11234 excerpt: 'No way dude!'
11236 myStore.add(myNewRecord);
11241 Roo.data.Record.create = function(o){
11242 var f = function(){
11243 f.superclass.constructor.apply(this, arguments);
11245 Roo.extend(f, Roo.data.Record);
11246 var p = f.prototype;
11247 p.fields = new Roo.util.MixedCollection(false, function(field){
11250 for(var i = 0, len = o.length; i < len; i++){
11251 p.fields.add(new Roo.data.Field(o[i]));
11253 f.getField = function(name){
11254 return p.fields.get(name);
11259 Roo.data.Record.AUTO_ID = 1000;
11260 Roo.data.Record.EDIT = 'edit';
11261 Roo.data.Record.REJECT = 'reject';
11262 Roo.data.Record.COMMIT = 'commit';
11264 Roo.data.Record.prototype = {
11266 * Readonly flag - true if this record has been modified.
11275 join : function(store){
11276 this.store = store;
11280 * Set the named field to the specified value.
11281 * @param {String} name The name of the field to set.
11282 * @param {Object} value The value to set the field to.
11284 set : function(name, value){
11285 if(this.data[name] == value){
11289 if(!this.modified){
11290 this.modified = {};
11292 if(typeof this.modified[name] == 'undefined'){
11293 this.modified[name] = this.data[name];
11295 this.data[name] = value;
11296 if(!this.editing && this.store){
11297 this.store.afterEdit(this);
11302 * Get the value of the named field.
11303 * @param {String} name The name of the field to get the value of.
11304 * @return {Object} The value of the field.
11306 get : function(name){
11307 return this.data[name];
11311 beginEdit : function(){
11312 this.editing = true;
11313 this.modified = {};
11317 cancelEdit : function(){
11318 this.editing = false;
11319 delete this.modified;
11323 endEdit : function(){
11324 this.editing = false;
11325 if(this.dirty && this.store){
11326 this.store.afterEdit(this);
11331 * Usually called by the {@link Roo.data.Store} which owns the Record.
11332 * Rejects all changes made to the Record since either creation, or the last commit operation.
11333 * Modified fields are reverted to their original values.
11335 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
11336 * of reject operations.
11338 reject : function(){
11339 var m = this.modified;
11341 if(typeof m[n] != "function"){
11342 this.data[n] = m[n];
11345 this.dirty = false;
11346 delete this.modified;
11347 this.editing = false;
11349 this.store.afterReject(this);
11354 * Usually called by the {@link Roo.data.Store} which owns the Record.
11355 * Commits all changes made to the Record since either creation, or the last commit operation.
11357 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
11358 * of commit operations.
11360 commit : function(){
11361 this.dirty = false;
11362 delete this.modified;
11363 this.editing = false;
11365 this.store.afterCommit(this);
11370 hasError : function(){
11371 return this.error != null;
11375 clearError : function(){
11380 * Creates a copy of this record.
11381 * @param {String} id (optional) A new record id if you don't want to use this record's id
11384 copy : function(newId) {
11385 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
11389 * Ext JS Library 1.1.1
11390 * Copyright(c) 2006-2007, Ext JS, LLC.
11392 * Originally Released Under LGPL - original licence link has changed is not relivant.
11395 * <script type="text/javascript">
11401 * @class Roo.data.Store
11402 * @extends Roo.util.Observable
11403 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
11404 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
11406 * 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
11407 * has no knowledge of the format of the data returned by the Proxy.<br>
11409 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
11410 * instances from the data object. These records are cached and made available through accessor functions.
11412 * Creates a new Store.
11413 * @param {Object} config A config object containing the objects needed for the Store to access data,
11414 * and read the data into Records.
11416 Roo.data.Store = function(config){
11417 this.data = new Roo.util.MixedCollection(false);
11418 this.data.getKey = function(o){
11421 this.baseParams = {};
11423 this.paramNames = {
11428 "multisort" : "_multisort"
11431 if(config && config.data){
11432 this.inlineData = config.data;
11433 delete config.data;
11436 Roo.apply(this, config);
11438 if(this.reader){ // reader passed
11439 this.reader = Roo.factory(this.reader, Roo.data);
11440 this.reader.xmodule = this.xmodule || false;
11441 if(!this.recordType){
11442 this.recordType = this.reader.recordType;
11444 if(this.reader.onMetaChange){
11445 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
11449 if(this.recordType){
11450 this.fields = this.recordType.prototype.fields;
11452 this.modified = [];
11456 * @event datachanged
11457 * Fires when the data cache has changed, and a widget which is using this Store
11458 * as a Record cache should refresh its view.
11459 * @param {Store} this
11461 datachanged : true,
11463 * @event metachange
11464 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
11465 * @param {Store} this
11466 * @param {Object} meta The JSON metadata
11471 * Fires when Records have been added to the Store
11472 * @param {Store} this
11473 * @param {Roo.data.Record[]} records The array of Records added
11474 * @param {Number} index The index at which the record(s) were added
11479 * Fires when a Record has been removed from the Store
11480 * @param {Store} this
11481 * @param {Roo.data.Record} record The Record that was removed
11482 * @param {Number} index The index at which the record was removed
11487 * Fires when a Record has been updated
11488 * @param {Store} this
11489 * @param {Roo.data.Record} record The Record that was updated
11490 * @param {String} operation The update operation being performed. Value may be one of:
11492 Roo.data.Record.EDIT
11493 Roo.data.Record.REJECT
11494 Roo.data.Record.COMMIT
11500 * Fires when the data cache has been cleared.
11501 * @param {Store} this
11505 * @event beforeload
11506 * Fires before a request is made for a new data object. If the beforeload handler returns false
11507 * the load action will be canceled.
11508 * @param {Store} this
11509 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11513 * @event beforeloadadd
11514 * Fires after a new set of Records has been loaded.
11515 * @param {Store} this
11516 * @param {Roo.data.Record[]} records The Records that were loaded
11517 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11519 beforeloadadd : true,
11522 * Fires after a new set of Records has been loaded, before they are added to the store.
11523 * @param {Store} this
11524 * @param {Roo.data.Record[]} records The Records that were loaded
11525 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11526 * @params {Object} return from reader
11530 * @event loadexception
11531 * Fires if an exception occurs in the Proxy during loading.
11532 * Called with the signature of the Proxy's "loadexception" event.
11533 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
11536 * @param {Object} return from JsonData.reader() - success, totalRecords, records
11537 * @param {Object} load options
11538 * @param {Object} jsonData from your request (normally this contains the Exception)
11540 loadexception : true
11544 this.proxy = Roo.factory(this.proxy, Roo.data);
11545 this.proxy.xmodule = this.xmodule || false;
11546 this.relayEvents(this.proxy, ["loadexception"]);
11548 this.sortToggle = {};
11549 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
11551 Roo.data.Store.superclass.constructor.call(this);
11553 if(this.inlineData){
11554 this.loadData(this.inlineData);
11555 delete this.inlineData;
11559 Roo.extend(Roo.data.Store, Roo.util.Observable, {
11561 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
11562 * without a remote query - used by combo/forms at present.
11566 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
11569 * @cfg {Array} data Inline data to be loaded when the store is initialized.
11572 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
11573 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
11576 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
11577 * on any HTTP request
11580 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
11583 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
11587 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
11588 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
11590 remoteSort : false,
11593 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
11594 * loaded or when a record is removed. (defaults to false).
11596 pruneModifiedRecords : false,
11599 lastOptions : null,
11602 * Add Records to the Store and fires the add event.
11603 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11605 add : function(records){
11606 records = [].concat(records);
11607 for(var i = 0, len = records.length; i < len; i++){
11608 records[i].join(this);
11610 var index = this.data.length;
11611 this.data.addAll(records);
11612 this.fireEvent("add", this, records, index);
11616 * Remove a Record from the Store and fires the remove event.
11617 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
11619 remove : function(record){
11620 var index = this.data.indexOf(record);
11621 this.data.removeAt(index);
11623 if(this.pruneModifiedRecords){
11624 this.modified.remove(record);
11626 this.fireEvent("remove", this, record, index);
11630 * Remove all Records from the Store and fires the clear event.
11632 removeAll : function(){
11634 if(this.pruneModifiedRecords){
11635 this.modified = [];
11637 this.fireEvent("clear", this);
11641 * Inserts Records to the Store at the given index and fires the add event.
11642 * @param {Number} index The start index at which to insert the passed Records.
11643 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11645 insert : function(index, records){
11646 records = [].concat(records);
11647 for(var i = 0, len = records.length; i < len; i++){
11648 this.data.insert(index, records[i]);
11649 records[i].join(this);
11651 this.fireEvent("add", this, records, index);
11655 * Get the index within the cache of the passed Record.
11656 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
11657 * @return {Number} The index of the passed Record. Returns -1 if not found.
11659 indexOf : function(record){
11660 return this.data.indexOf(record);
11664 * Get the index within the cache of the Record with the passed id.
11665 * @param {String} id The id of the Record to find.
11666 * @return {Number} The index of the Record. Returns -1 if not found.
11668 indexOfId : function(id){
11669 return this.data.indexOfKey(id);
11673 * Get the Record with the specified id.
11674 * @param {String} id The id of the Record to find.
11675 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
11677 getById : function(id){
11678 return this.data.key(id);
11682 * Get the Record at the specified index.
11683 * @param {Number} index The index of the Record to find.
11684 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
11686 getAt : function(index){
11687 return this.data.itemAt(index);
11691 * Returns a range of Records between specified indices.
11692 * @param {Number} startIndex (optional) The starting index (defaults to 0)
11693 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
11694 * @return {Roo.data.Record[]} An array of Records
11696 getRange : function(start, end){
11697 return this.data.getRange(start, end);
11701 storeOptions : function(o){
11702 o = Roo.apply({}, o);
11705 this.lastOptions = o;
11709 * Loads the Record cache from the configured Proxy using the configured Reader.
11711 * If using remote paging, then the first load call must specify the <em>start</em>
11712 * and <em>limit</em> properties in the options.params property to establish the initial
11713 * position within the dataset, and the number of Records to cache on each read from the Proxy.
11715 * <strong>It is important to note that for remote data sources, loading is asynchronous,
11716 * and this call will return before the new data has been loaded. Perform any post-processing
11717 * in a callback function, or in a "load" event handler.</strong>
11719 * @param {Object} options An object containing properties which control loading options:<ul>
11720 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
11721 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
11722 * passed the following arguments:<ul>
11723 * <li>r : Roo.data.Record[]</li>
11724 * <li>options: Options object from the load call</li>
11725 * <li>success: Boolean success indicator</li></ul></li>
11726 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
11727 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
11730 load : function(options){
11731 options = options || {};
11732 if(this.fireEvent("beforeload", this, options) !== false){
11733 this.storeOptions(options);
11734 var p = Roo.apply(options.params || {}, this.baseParams);
11735 // if meta was not loaded from remote source.. try requesting it.
11736 if (!this.reader.metaFromRemote) {
11737 p._requestMeta = 1;
11739 if(this.sortInfo && this.remoteSort){
11740 var pn = this.paramNames;
11741 p[pn["sort"]] = this.sortInfo.field;
11742 p[pn["dir"]] = this.sortInfo.direction;
11744 if (this.multiSort) {
11745 var pn = this.paramNames;
11746 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
11749 this.proxy.load(p, this.reader, this.loadRecords, this, options);
11754 * Reloads the Record cache from the configured Proxy using the configured Reader and
11755 * the options from the last load operation performed.
11756 * @param {Object} options (optional) An object containing properties which may override the options
11757 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
11758 * the most recently used options are reused).
11760 reload : function(options){
11761 this.load(Roo.applyIf(options||{}, this.lastOptions));
11765 // Called as a callback by the Reader during a load operation.
11766 loadRecords : function(o, options, success){
11767 if(!o || success === false){
11768 if(success !== false){
11769 this.fireEvent("load", this, [], options, o);
11771 if(options.callback){
11772 options.callback.call(options.scope || this, [], options, false);
11776 // if data returned failure - throw an exception.
11777 if (o.success === false) {
11778 // show a message if no listener is registered.
11779 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
11780 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
11782 // loadmask wil be hooked into this..
11783 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
11786 var r = o.records, t = o.totalRecords || r.length;
11788 this.fireEvent("beforeloadadd", this, r, options, o);
11790 if(!options || options.add !== true){
11791 if(this.pruneModifiedRecords){
11792 this.modified = [];
11794 for(var i = 0, len = r.length; i < len; i++){
11798 this.data = this.snapshot;
11799 delete this.snapshot;
11802 this.data.addAll(r);
11803 this.totalLength = t;
11805 this.fireEvent("datachanged", this);
11807 this.totalLength = Math.max(t, this.data.length+r.length);
11811 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
11813 var e = new Roo.data.Record({});
11815 e.set(this.parent.displayField, this.parent.emptyTitle);
11816 e.set(this.parent.valueField, '');
11821 this.fireEvent("load", this, r, options, o);
11822 if(options.callback){
11823 options.callback.call(options.scope || this, r, options, true);
11829 * Loads data from a passed data block. A Reader which understands the format of the data
11830 * must have been configured in the constructor.
11831 * @param {Object} data The data block from which to read the Records. The format of the data expected
11832 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
11833 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
11835 loadData : function(o, append){
11836 var r = this.reader.readRecords(o);
11837 this.loadRecords(r, {add: append}, true);
11841 * Gets the number of cached records.
11843 * <em>If using paging, this may not be the total size of the dataset. If the data object
11844 * used by the Reader contains the dataset size, then the getTotalCount() function returns
11845 * the data set size</em>
11847 getCount : function(){
11848 return this.data.length || 0;
11852 * Gets the total number of records in the dataset as returned by the server.
11854 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
11855 * the dataset size</em>
11857 getTotalCount : function(){
11858 return this.totalLength || 0;
11862 * Returns the sort state of the Store as an object with two properties:
11864 field {String} The name of the field by which the Records are sorted
11865 direction {String} The sort order, "ASC" or "DESC"
11868 getSortState : function(){
11869 return this.sortInfo;
11873 applySort : function(){
11874 if(this.sortInfo && !this.remoteSort){
11875 var s = this.sortInfo, f = s.field;
11876 var st = this.fields.get(f).sortType;
11877 var fn = function(r1, r2){
11878 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
11879 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
11881 this.data.sort(s.direction, fn);
11882 if(this.snapshot && this.snapshot != this.data){
11883 this.snapshot.sort(s.direction, fn);
11889 * Sets the default sort column and order to be used by the next load operation.
11890 * @param {String} fieldName The name of the field to sort by.
11891 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11893 setDefaultSort : function(field, dir){
11894 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
11898 * Sort the Records.
11899 * If remote sorting is used, the sort is performed on the server, and the cache is
11900 * reloaded. If local sorting is used, the cache is sorted internally.
11901 * @param {String} fieldName The name of the field to sort by.
11902 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11904 sort : function(fieldName, dir){
11905 var f = this.fields.get(fieldName);
11907 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
11909 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
11910 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
11915 this.sortToggle[f.name] = dir;
11916 this.sortInfo = {field: f.name, direction: dir};
11917 if(!this.remoteSort){
11919 this.fireEvent("datachanged", this);
11921 this.load(this.lastOptions);
11926 * Calls the specified function for each of the Records in the cache.
11927 * @param {Function} fn The function to call. The Record is passed as the first parameter.
11928 * Returning <em>false</em> aborts and exits the iteration.
11929 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
11931 each : function(fn, scope){
11932 this.data.each(fn, scope);
11936 * Gets all records modified since the last commit. Modified records are persisted across load operations
11937 * (e.g., during paging).
11938 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
11940 getModifiedRecords : function(){
11941 return this.modified;
11945 createFilterFn : function(property, value, anyMatch){
11946 if(!value.exec){ // not a regex
11947 value = String(value);
11948 if(value.length == 0){
11951 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
11953 return function(r){
11954 return value.test(r.data[property]);
11959 * Sums the value of <i>property</i> for each record between start and end and returns the result.
11960 * @param {String} property A field on your records
11961 * @param {Number} start The record index to start at (defaults to 0)
11962 * @param {Number} end The last record index to include (defaults to length - 1)
11963 * @return {Number} The sum
11965 sum : function(property, start, end){
11966 var rs = this.data.items, v = 0;
11967 start = start || 0;
11968 end = (end || end === 0) ? end : rs.length-1;
11970 for(var i = start; i <= end; i++){
11971 v += (rs[i].data[property] || 0);
11977 * Filter the records by a specified property.
11978 * @param {String} field A field on your records
11979 * @param {String/RegExp} value Either a string that the field
11980 * should start with or a RegExp to test against the field
11981 * @param {Boolean} anyMatch True to match any part not just the beginning
11983 filter : function(property, value, anyMatch){
11984 var fn = this.createFilterFn(property, value, anyMatch);
11985 return fn ? this.filterBy(fn) : this.clearFilter();
11989 * Filter by a function. The specified function will be called with each
11990 * record in this data source. If the function returns true the record is included,
11991 * otherwise it is filtered.
11992 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11993 * @param {Object} scope (optional) The scope of the function (defaults to this)
11995 filterBy : function(fn, scope){
11996 this.snapshot = this.snapshot || this.data;
11997 this.data = this.queryBy(fn, scope||this);
11998 this.fireEvent("datachanged", this);
12002 * Query the records by a specified property.
12003 * @param {String} field A field on your records
12004 * @param {String/RegExp} value Either a string that the field
12005 * should start with or a RegExp to test against the field
12006 * @param {Boolean} anyMatch True to match any part not just the beginning
12007 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
12009 query : function(property, value, anyMatch){
12010 var fn = this.createFilterFn(property, value, anyMatch);
12011 return fn ? this.queryBy(fn) : this.data.clone();
12015 * Query by a function. The specified function will be called with each
12016 * record in this data source. If the function returns true the record is included
12018 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
12019 * @param {Object} scope (optional) The scope of the function (defaults to this)
12020 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
12022 queryBy : function(fn, scope){
12023 var data = this.snapshot || this.data;
12024 return data.filterBy(fn, scope||this);
12028 * Collects unique values for a particular dataIndex from this store.
12029 * @param {String} dataIndex The property to collect
12030 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
12031 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
12032 * @return {Array} An array of the unique values
12034 collect : function(dataIndex, allowNull, bypassFilter){
12035 var d = (bypassFilter === true && this.snapshot) ?
12036 this.snapshot.items : this.data.items;
12037 var v, sv, r = [], l = {};
12038 for(var i = 0, len = d.length; i < len; i++){
12039 v = d[i].data[dataIndex];
12041 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
12050 * Revert to a view of the Record cache with no filtering applied.
12051 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
12053 clearFilter : function(suppressEvent){
12054 if(this.snapshot && this.snapshot != this.data){
12055 this.data = this.snapshot;
12056 delete this.snapshot;
12057 if(suppressEvent !== true){
12058 this.fireEvent("datachanged", this);
12064 afterEdit : function(record){
12065 if(this.modified.indexOf(record) == -1){
12066 this.modified.push(record);
12068 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
12072 afterReject : function(record){
12073 this.modified.remove(record);
12074 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
12078 afterCommit : function(record){
12079 this.modified.remove(record);
12080 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
12084 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
12085 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
12087 commitChanges : function(){
12088 var m = this.modified.slice(0);
12089 this.modified = [];
12090 for(var i = 0, len = m.length; i < len; i++){
12096 * Cancel outstanding changes on all changed records.
12098 rejectChanges : function(){
12099 var m = this.modified.slice(0);
12100 this.modified = [];
12101 for(var i = 0, len = m.length; i < len; i++){
12106 onMetaChange : function(meta, rtype, o){
12107 this.recordType = rtype;
12108 this.fields = rtype.prototype.fields;
12109 delete this.snapshot;
12110 this.sortInfo = meta.sortInfo || this.sortInfo;
12111 this.modified = [];
12112 this.fireEvent('metachange', this, this.reader.meta);
12115 moveIndex : function(data, type)
12117 var index = this.indexOf(data);
12119 var newIndex = index + type;
12123 this.insert(newIndex, data);
12128 * Ext JS Library 1.1.1
12129 * Copyright(c) 2006-2007, Ext JS, LLC.
12131 * Originally Released Under LGPL - original licence link has changed is not relivant.
12134 * <script type="text/javascript">
12138 * @class Roo.data.SimpleStore
12139 * @extends Roo.data.Store
12140 * Small helper class to make creating Stores from Array data easier.
12141 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
12142 * @cfg {Array} fields An array of field definition objects, or field name strings.
12143 * @cfg {Array} data The multi-dimensional array of data
12145 * @param {Object} config
12147 Roo.data.SimpleStore = function(config){
12148 Roo.data.SimpleStore.superclass.constructor.call(this, {
12150 reader: new Roo.data.ArrayReader({
12153 Roo.data.Record.create(config.fields)
12155 proxy : new Roo.data.MemoryProxy(config.data)
12159 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
12161 * Ext JS Library 1.1.1
12162 * Copyright(c) 2006-2007, Ext JS, LLC.
12164 * Originally Released Under LGPL - original licence link has changed is not relivant.
12167 * <script type="text/javascript">
12172 * @extends Roo.data.Store
12173 * @class Roo.data.JsonStore
12174 * Small helper class to make creating Stores for JSON data easier. <br/>
12176 var store = new Roo.data.JsonStore({
12177 url: 'get-images.php',
12179 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
12182 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
12183 * JsonReader and HttpProxy (unless inline data is provided).</b>
12184 * @cfg {Array} fields An array of field definition objects, or field name strings.
12186 * @param {Object} config
12188 Roo.data.JsonStore = function(c){
12189 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
12190 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
12191 reader: new Roo.data.JsonReader(c, c.fields)
12194 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
12196 * Ext JS Library 1.1.1
12197 * Copyright(c) 2006-2007, Ext JS, LLC.
12199 * Originally Released Under LGPL - original licence link has changed is not relivant.
12202 * <script type="text/javascript">
12206 Roo.data.Field = function(config){
12207 if(typeof config == "string"){
12208 config = {name: config};
12210 Roo.apply(this, config);
12213 this.type = "auto";
12216 var st = Roo.data.SortTypes;
12217 // named sortTypes are supported, here we look them up
12218 if(typeof this.sortType == "string"){
12219 this.sortType = st[this.sortType];
12222 // set default sortType for strings and dates
12223 if(!this.sortType){
12226 this.sortType = st.asUCString;
12229 this.sortType = st.asDate;
12232 this.sortType = st.none;
12237 var stripRe = /[\$,%]/g;
12239 // prebuilt conversion function for this field, instead of
12240 // switching every time we're reading a value
12242 var cv, dateFormat = this.dateFormat;
12247 cv = function(v){ return v; };
12250 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
12254 return v !== undefined && v !== null && v !== '' ?
12255 parseInt(String(v).replace(stripRe, ""), 10) : '';
12260 return v !== undefined && v !== null && v !== '' ?
12261 parseFloat(String(v).replace(stripRe, ""), 10) : '';
12266 cv = function(v){ return v === true || v === "true" || v == 1; };
12273 if(v instanceof Date){
12277 if(dateFormat == "timestamp"){
12278 return new Date(v*1000);
12280 return Date.parseDate(v, dateFormat);
12282 var parsed = Date.parse(v);
12283 return parsed ? new Date(parsed) : null;
12292 Roo.data.Field.prototype = {
12300 * Ext JS Library 1.1.1
12301 * Copyright(c) 2006-2007, Ext JS, LLC.
12303 * Originally Released Under LGPL - original licence link has changed is not relivant.
12306 * <script type="text/javascript">
12309 // Base class for reading structured data from a data source. This class is intended to be
12310 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
12313 * @class Roo.data.DataReader
12314 * Base class for reading structured data from a data source. This class is intended to be
12315 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
12318 Roo.data.DataReader = function(meta, recordType){
12322 this.recordType = recordType instanceof Array ?
12323 Roo.data.Record.create(recordType) : recordType;
12326 Roo.data.DataReader.prototype = {
12328 * Create an empty record
12329 * @param {Object} data (optional) - overlay some values
12330 * @return {Roo.data.Record} record created.
12332 newRow : function(d) {
12334 this.recordType.prototype.fields.each(function(c) {
12336 case 'int' : da[c.name] = 0; break;
12337 case 'date' : da[c.name] = new Date(); break;
12338 case 'float' : da[c.name] = 0.0; break;
12339 case 'boolean' : da[c.name] = false; break;
12340 default : da[c.name] = ""; break;
12344 return new this.recordType(Roo.apply(da, d));
12349 * Ext JS Library 1.1.1
12350 * Copyright(c) 2006-2007, Ext JS, LLC.
12352 * Originally Released Under LGPL - original licence link has changed is not relivant.
12355 * <script type="text/javascript">
12359 * @class Roo.data.DataProxy
12360 * @extends Roo.data.Observable
12361 * This class is an abstract base class for implementations which provide retrieval of
12362 * unformatted data objects.<br>
12364 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
12365 * (of the appropriate type which knows how to parse the data object) to provide a block of
12366 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
12368 * Custom implementations must implement the load method as described in
12369 * {@link Roo.data.HttpProxy#load}.
12371 Roo.data.DataProxy = function(){
12374 * @event beforeload
12375 * Fires before a network request is made to retrieve a data object.
12376 * @param {Object} This DataProxy object.
12377 * @param {Object} params The params parameter to the load function.
12382 * Fires before the load method's callback is called.
12383 * @param {Object} This DataProxy object.
12384 * @param {Object} o The data object.
12385 * @param {Object} arg The callback argument object passed to the load function.
12389 * @event loadexception
12390 * Fires if an Exception occurs during data retrieval.
12391 * @param {Object} This DataProxy object.
12392 * @param {Object} o The data object.
12393 * @param {Object} arg The callback argument object passed to the load function.
12394 * @param {Object} e The Exception.
12396 loadexception : true
12398 Roo.data.DataProxy.superclass.constructor.call(this);
12401 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
12404 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
12408 * Ext JS Library 1.1.1
12409 * Copyright(c) 2006-2007, Ext JS, LLC.
12411 * Originally Released Under LGPL - original licence link has changed is not relivant.
12414 * <script type="text/javascript">
12417 * @class Roo.data.MemoryProxy
12418 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
12419 * to the Reader when its load method is called.
12421 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
12423 Roo.data.MemoryProxy = function(data){
12427 Roo.data.MemoryProxy.superclass.constructor.call(this);
12431 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
12434 * Load data from the requested source (in this case an in-memory
12435 * data object passed to the constructor), read the data object into
12436 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12437 * process that block using the passed callback.
12438 * @param {Object} params This parameter is not used by the MemoryProxy class.
12439 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12440 * object into a block of Roo.data.Records.
12441 * @param {Function} callback The function into which to pass the block of Roo.data.records.
12442 * The function must be passed <ul>
12443 * <li>The Record block object</li>
12444 * <li>The "arg" argument from the load function</li>
12445 * <li>A boolean success indicator</li>
12447 * @param {Object} scope The scope in which to call the callback
12448 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12450 load : function(params, reader, callback, scope, arg){
12451 params = params || {};
12454 result = reader.readRecords(params.data ? params.data :this.data);
12456 this.fireEvent("loadexception", this, arg, null, e);
12457 callback.call(scope, null, arg, false);
12460 callback.call(scope, result, arg, true);
12464 update : function(params, records){
12469 * Ext JS Library 1.1.1
12470 * Copyright(c) 2006-2007, Ext JS, LLC.
12472 * Originally Released Under LGPL - original licence link has changed is not relivant.
12475 * <script type="text/javascript">
12478 * @class Roo.data.HttpProxy
12479 * @extends Roo.data.DataProxy
12480 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
12481 * configured to reference a certain URL.<br><br>
12483 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
12484 * from which the running page was served.<br><br>
12486 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
12488 * Be aware that to enable the browser to parse an XML document, the server must set
12489 * the Content-Type header in the HTTP response to "text/xml".
12491 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
12492 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
12493 * will be used to make the request.
12495 Roo.data.HttpProxy = function(conn){
12496 Roo.data.HttpProxy.superclass.constructor.call(this);
12497 // is conn a conn config or a real conn?
12499 this.useAjax = !conn || !conn.events;
12503 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
12504 // thse are take from connection...
12507 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
12510 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
12511 * extra parameters to each request made by this object. (defaults to undefined)
12514 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
12515 * to each request made by this object. (defaults to undefined)
12518 * @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)
12521 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
12524 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
12530 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
12534 * Return the {@link Roo.data.Connection} object being used by this Proxy.
12535 * @return {Connection} The Connection object. This object may be used to subscribe to events on
12536 * a finer-grained basis than the DataProxy events.
12538 getConnection : function(){
12539 return this.useAjax ? Roo.Ajax : this.conn;
12543 * Load data from the configured {@link Roo.data.Connection}, read the data object into
12544 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
12545 * process that block using the passed callback.
12546 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12547 * for the request to the remote server.
12548 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12549 * object into a block of Roo.data.Records.
12550 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12551 * The function must be passed <ul>
12552 * <li>The Record block object</li>
12553 * <li>The "arg" argument from the load function</li>
12554 * <li>A boolean success indicator</li>
12556 * @param {Object} scope The scope in which to call the callback
12557 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12559 load : function(params, reader, callback, scope, arg){
12560 if(this.fireEvent("beforeload", this, params) !== false){
12562 params : params || {},
12564 callback : callback,
12569 callback : this.loadResponse,
12573 Roo.applyIf(o, this.conn);
12574 if(this.activeRequest){
12575 Roo.Ajax.abort(this.activeRequest);
12577 this.activeRequest = Roo.Ajax.request(o);
12579 this.conn.request(o);
12582 callback.call(scope||this, null, arg, false);
12587 loadResponse : function(o, success, response){
12588 delete this.activeRequest;
12590 this.fireEvent("loadexception", this, o, response);
12591 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12596 result = o.reader.read(response);
12598 this.fireEvent("loadexception", this, o, response, e);
12599 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12603 this.fireEvent("load", this, o, o.request.arg);
12604 o.request.callback.call(o.request.scope, result, o.request.arg, true);
12608 update : function(dataSet){
12613 updateResponse : function(dataSet){
12618 * Ext JS Library 1.1.1
12619 * Copyright(c) 2006-2007, Ext JS, LLC.
12621 * Originally Released Under LGPL - original licence link has changed is not relivant.
12624 * <script type="text/javascript">
12628 * @class Roo.data.ScriptTagProxy
12629 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
12630 * other than the originating domain of the running page.<br><br>
12632 * <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
12633 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
12635 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
12636 * source code that is used as the source inside a <script> tag.<br><br>
12638 * In order for the browser to process the returned data, the server must wrap the data object
12639 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
12640 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
12641 * depending on whether the callback name was passed:
12644 boolean scriptTag = false;
12645 String cb = request.getParameter("callback");
12648 response.setContentType("text/javascript");
12650 response.setContentType("application/x-json");
12652 Writer out = response.getWriter();
12654 out.write(cb + "(");
12656 out.print(dataBlock.toJsonString());
12663 * @param {Object} config A configuration object.
12665 Roo.data.ScriptTagProxy = function(config){
12666 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
12667 Roo.apply(this, config);
12668 this.head = document.getElementsByTagName("head")[0];
12671 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
12673 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
12675 * @cfg {String} url The URL from which to request the data object.
12678 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
12682 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
12683 * the server the name of the callback function set up by the load call to process the returned data object.
12684 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
12685 * javascript output which calls this named function passing the data object as its only parameter.
12687 callbackParam : "callback",
12689 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
12690 * name to the request.
12695 * Load data from the configured URL, read the data object into
12696 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12697 * process that block using the passed callback.
12698 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12699 * for the request to the remote server.
12700 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12701 * object into a block of Roo.data.Records.
12702 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12703 * The function must be passed <ul>
12704 * <li>The Record block object</li>
12705 * <li>The "arg" argument from the load function</li>
12706 * <li>A boolean success indicator</li>
12708 * @param {Object} scope The scope in which to call the callback
12709 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12711 load : function(params, reader, callback, scope, arg){
12712 if(this.fireEvent("beforeload", this, params) !== false){
12714 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
12716 var url = this.url;
12717 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
12719 url += "&_dc=" + (new Date().getTime());
12721 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
12724 cb : "stcCallback"+transId,
12725 scriptId : "stcScript"+transId,
12729 callback : callback,
12735 window[trans.cb] = function(o){
12736 conn.handleResponse(o, trans);
12739 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
12741 if(this.autoAbort !== false){
12745 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
12747 var script = document.createElement("script");
12748 script.setAttribute("src", url);
12749 script.setAttribute("type", "text/javascript");
12750 script.setAttribute("id", trans.scriptId);
12751 this.head.appendChild(script);
12753 this.trans = trans;
12755 callback.call(scope||this, null, arg, false);
12760 isLoading : function(){
12761 return this.trans ? true : false;
12765 * Abort the current server request.
12767 abort : function(){
12768 if(this.isLoading()){
12769 this.destroyTrans(this.trans);
12774 destroyTrans : function(trans, isLoaded){
12775 this.head.removeChild(document.getElementById(trans.scriptId));
12776 clearTimeout(trans.timeoutId);
12778 window[trans.cb] = undefined;
12780 delete window[trans.cb];
12783 // if hasn't been loaded, wait for load to remove it to prevent script error
12784 window[trans.cb] = function(){
12785 window[trans.cb] = undefined;
12787 delete window[trans.cb];
12794 handleResponse : function(o, trans){
12795 this.trans = false;
12796 this.destroyTrans(trans, true);
12799 result = trans.reader.readRecords(o);
12801 this.fireEvent("loadexception", this, o, trans.arg, e);
12802 trans.callback.call(trans.scope||window, null, trans.arg, false);
12805 this.fireEvent("load", this, o, trans.arg);
12806 trans.callback.call(trans.scope||window, result, trans.arg, true);
12810 handleFailure : function(trans){
12811 this.trans = false;
12812 this.destroyTrans(trans, false);
12813 this.fireEvent("loadexception", this, null, trans.arg);
12814 trans.callback.call(trans.scope||window, null, trans.arg, false);
12818 * Ext JS Library 1.1.1
12819 * Copyright(c) 2006-2007, Ext JS, LLC.
12821 * Originally Released Under LGPL - original licence link has changed is not relivant.
12824 * <script type="text/javascript">
12828 * @class Roo.data.JsonReader
12829 * @extends Roo.data.DataReader
12830 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
12831 * based on mappings in a provided Roo.data.Record constructor.
12833 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
12834 * in the reply previously.
12839 var RecordDef = Roo.data.Record.create([
12840 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
12841 {name: 'occupation'} // This field will use "occupation" as the mapping.
12843 var myReader = new Roo.data.JsonReader({
12844 totalProperty: "results", // The property which contains the total dataset size (optional)
12845 root: "rows", // The property which contains an Array of row objects
12846 id: "id" // The property within each row object that provides an ID for the record (optional)
12850 * This would consume a JSON file like this:
12852 { 'results': 2, 'rows': [
12853 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
12854 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
12857 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
12858 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
12859 * paged from the remote server.
12860 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
12861 * @cfg {String} root name of the property which contains the Array of row objects.
12862 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
12863 * @cfg {Array} fields Array of field definition objects
12865 * Create a new JsonReader
12866 * @param {Object} meta Metadata configuration options
12867 * @param {Object} recordType Either an Array of field definition objects,
12868 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
12870 Roo.data.JsonReader = function(meta, recordType){
12873 // set some defaults:
12874 Roo.applyIf(meta, {
12875 totalProperty: 'total',
12876 successProperty : 'success',
12881 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
12883 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
12886 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
12887 * Used by Store query builder to append _requestMeta to params.
12890 metaFromRemote : false,
12892 * This method is only used by a DataProxy which has retrieved data from a remote server.
12893 * @param {Object} response The XHR object which contains the JSON data in its responseText.
12894 * @return {Object} data A data block which is used by an Roo.data.Store object as
12895 * a cache of Roo.data.Records.
12897 read : function(response){
12898 var json = response.responseText;
12900 var o = /* eval:var:o */ eval("("+json+")");
12902 throw {message: "JsonReader.read: Json object not found"};
12908 this.metaFromRemote = true;
12909 this.meta = o.metaData;
12910 this.recordType = Roo.data.Record.create(o.metaData.fields);
12911 this.onMetaChange(this.meta, this.recordType, o);
12913 return this.readRecords(o);
12916 // private function a store will implement
12917 onMetaChange : function(meta, recordType, o){
12924 simpleAccess: function(obj, subsc) {
12931 getJsonAccessor: function(){
12933 return function(expr) {
12935 return(re.test(expr))
12936 ? new Function("obj", "return obj." + expr)
12941 return Roo.emptyFn;
12946 * Create a data block containing Roo.data.Records from an XML document.
12947 * @param {Object} o An object which contains an Array of row objects in the property specified
12948 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
12949 * which contains the total size of the dataset.
12950 * @return {Object} data A data block which is used by an Roo.data.Store object as
12951 * a cache of Roo.data.Records.
12953 readRecords : function(o){
12955 * After any data loads, the raw JSON data is available for further custom processing.
12959 var s = this.meta, Record = this.recordType,
12960 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
12962 // Generate extraction functions for the totalProperty, the root, the id, and for each field
12964 if(s.totalProperty) {
12965 this.getTotal = this.getJsonAccessor(s.totalProperty);
12967 if(s.successProperty) {
12968 this.getSuccess = this.getJsonAccessor(s.successProperty);
12970 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
12972 var g = this.getJsonAccessor(s.id);
12973 this.getId = function(rec) {
12975 return (r === undefined || r === "") ? null : r;
12978 this.getId = function(){return null;};
12981 for(var jj = 0; jj < fl; jj++){
12983 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
12984 this.ef[jj] = this.getJsonAccessor(map);
12988 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
12989 if(s.totalProperty){
12990 var vt = parseInt(this.getTotal(o), 10);
12995 if(s.successProperty){
12996 var vs = this.getSuccess(o);
12997 if(vs === false || vs === 'false'){
13002 for(var i = 0; i < c; i++){
13005 var id = this.getId(n);
13006 for(var j = 0; j < fl; j++){
13008 var v = this.ef[j](n);
13010 Roo.log('missing convert for ' + f.name);
13014 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
13016 var record = new Record(values, id);
13018 records[i] = record;
13024 totalRecords : totalRecords
13029 * Ext JS Library 1.1.1
13030 * Copyright(c) 2006-2007, Ext JS, LLC.
13032 * Originally Released Under LGPL - original licence link has changed is not relivant.
13035 * <script type="text/javascript">
13039 * @class Roo.data.ArrayReader
13040 * @extends Roo.data.DataReader
13041 * Data reader class to create an Array of Roo.data.Record objects from an Array.
13042 * Each element of that Array represents a row of data fields. The
13043 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
13044 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
13048 var RecordDef = Roo.data.Record.create([
13049 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
13050 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
13052 var myReader = new Roo.data.ArrayReader({
13053 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
13057 * This would consume an Array like this:
13059 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
13063 * Create a new JsonReader
13064 * @param {Object} meta Metadata configuration options.
13065 * @param {Object|Array} recordType Either an Array of field definition objects
13067 * @cfg {Array} fields Array of field definition objects
13068 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
13069 * as specified to {@link Roo.data.Record#create},
13070 * or an {@link Roo.data.Record} object
13073 * created using {@link Roo.data.Record#create}.
13075 Roo.data.ArrayReader = function(meta, recordType){
13078 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType||meta.fields);
13081 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
13083 * Create a data block containing Roo.data.Records from an XML document.
13084 * @param {Object} o An Array of row objects which represents the dataset.
13085 * @return {Object} A data block which is used by an {@link Roo.data.Store} object as
13086 * a cache of Roo.data.Records.
13088 readRecords : function(o){
13089 var sid = this.meta ? this.meta.id : null;
13090 var recordType = this.recordType, fields = recordType.prototype.fields;
13093 for(var i = 0; i < root.length; i++){
13096 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
13097 for(var j = 0, jlen = fields.length; j < jlen; j++){
13098 var f = fields.items[j];
13099 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
13100 var v = n[k] !== undefined ? n[k] : f.defaultValue;
13102 values[f.name] = v;
13104 var record = new recordType(values, id);
13106 records[records.length] = record;
13110 totalRecords : records.length
13119 * @class Roo.bootstrap.ComboBox
13120 * @extends Roo.bootstrap.TriggerField
13121 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
13122 * @cfg {Boolean} append (true|false) default false
13123 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
13124 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
13125 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
13126 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
13127 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
13128 * @cfg {Boolean} animate default true
13129 * @cfg {Boolean} emptyResultText only for touch device
13130 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
13131 * @cfg {String} emptyTitle default ''
13133 * Create a new ComboBox.
13134 * @param {Object} config Configuration options
13136 Roo.bootstrap.ComboBox = function(config){
13137 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
13141 * Fires when the dropdown list is expanded
13142 * @param {Roo.bootstrap.ComboBox} combo This combo box
13147 * Fires when the dropdown list is collapsed
13148 * @param {Roo.bootstrap.ComboBox} combo This combo box
13152 * @event beforeselect
13153 * Fires before a list item is selected. Return false to cancel the selection.
13154 * @param {Roo.bootstrap.ComboBox} combo This combo box
13155 * @param {Roo.data.Record} record The data record returned from the underlying store
13156 * @param {Number} index The index of the selected item in the dropdown list
13158 'beforeselect' : true,
13161 * Fires when a list item is selected
13162 * @param {Roo.bootstrap.ComboBox} combo This combo box
13163 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
13164 * @param {Number} index The index of the selected item in the dropdown list
13168 * @event beforequery
13169 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
13170 * The event object passed has these properties:
13171 * @param {Roo.bootstrap.ComboBox} combo This combo box
13172 * @param {String} query The query
13173 * @param {Boolean} forceAll true to force "all" query
13174 * @param {Boolean} cancel true to cancel the query
13175 * @param {Object} e The query event object
13177 'beforequery': true,
13180 * Fires when the 'add' icon is pressed (add a listener to enable add button)
13181 * @param {Roo.bootstrap.ComboBox} combo This combo box
13186 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
13187 * @param {Roo.bootstrap.ComboBox} combo This combo box
13188 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
13193 * Fires when the remove value from the combobox array
13194 * @param {Roo.bootstrap.ComboBox} combo This combo box
13198 * @event afterremove
13199 * Fires when the remove value from the combobox array
13200 * @param {Roo.bootstrap.ComboBox} combo This combo box
13202 'afterremove' : true,
13204 * @event specialfilter
13205 * Fires when specialfilter
13206 * @param {Roo.bootstrap.ComboBox} combo This combo box
13208 'specialfilter' : true,
13211 * Fires when tick the element
13212 * @param {Roo.bootstrap.ComboBox} combo This combo box
13216 * @event touchviewdisplay
13217 * Fires when touch view require special display (default is using displayField)
13218 * @param {Roo.bootstrap.ComboBox} combo This combo box
13219 * @param {Object} cfg set html .
13221 'touchviewdisplay' : true
13226 this.tickItems = [];
13228 this.selectedIndex = -1;
13229 if(this.mode == 'local'){
13230 if(config.queryDelay === undefined){
13231 this.queryDelay = 10;
13233 if(config.minChars === undefined){
13239 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
13242 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
13243 * rendering into an Roo.Editor, defaults to false)
13246 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
13247 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
13250 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
13253 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
13254 * the dropdown list (defaults to undefined, with no header element)
13258 * @cfg {String/Roo.Template} tpl The template to use to render the output
13262 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
13264 listWidth: undefined,
13266 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
13267 * mode = 'remote' or 'text' if mode = 'local')
13269 displayField: undefined,
13272 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
13273 * mode = 'remote' or 'value' if mode = 'local').
13274 * Note: use of a valueField requires the user make a selection
13275 * in order for a value to be mapped.
13277 valueField: undefined,
13279 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
13284 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
13285 * field's data value (defaults to the underlying DOM element's name)
13287 hiddenName: undefined,
13289 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
13293 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
13295 selectedClass: 'active',
13298 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
13302 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
13303 * anchor positions (defaults to 'tl-bl')
13305 listAlign: 'tl-bl?',
13307 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
13311 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
13312 * query specified by the allQuery config option (defaults to 'query')
13314 triggerAction: 'query',
13316 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
13317 * (defaults to 4, does not apply if editable = false)
13321 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
13322 * delay (typeAheadDelay) if it matches a known value (defaults to false)
13326 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
13327 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
13331 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
13332 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
13336 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
13337 * when editable = true (defaults to false)
13339 selectOnFocus:false,
13341 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
13343 queryParam: 'query',
13345 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
13346 * when mode = 'remote' (defaults to 'Loading...')
13348 loadingText: 'Loading...',
13350 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
13354 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
13358 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
13359 * traditional select (defaults to true)
13363 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
13367 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
13371 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
13372 * listWidth has a higher value)
13376 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
13377 * allow the user to set arbitrary text into the field (defaults to false)
13379 forceSelection:false,
13381 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
13382 * if typeAhead = true (defaults to 250)
13384 typeAheadDelay : 250,
13386 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
13387 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
13389 valueNotFoundText : undefined,
13391 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
13393 blockFocus : false,
13396 * @cfg {Boolean} disableClear Disable showing of clear button.
13398 disableClear : false,
13400 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
13402 alwaysQuery : false,
13405 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
13410 * @cfg {String} invalidClass DEPRICATED - uses BS4 is-valid now
13412 invalidClass : "has-warning",
13415 * @cfg {String} validClass DEPRICATED - uses BS4 is-valid now
13417 validClass : "has-success",
13420 * @cfg {Boolean} specialFilter (true|false) special filter default false
13422 specialFilter : false,
13425 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
13427 mobileTouchView : true,
13430 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
13432 useNativeIOS : false,
13435 * @cfg {Boolean} mobile_restrict_height (true|false) restrict height for touch view
13437 mobile_restrict_height : false,
13439 ios_options : false,
13451 btnPosition : 'right',
13452 triggerList : true,
13453 showToggleBtn : true,
13455 emptyResultText: 'Empty',
13456 triggerText : 'Select',
13459 // element that contains real text value.. (when hidden is used..)
13461 getAutoCreate : function()
13466 * Render classic select for iso
13469 if(Roo.isIOS && this.useNativeIOS){
13470 cfg = this.getAutoCreateNativeIOS();
13478 if(Roo.isTouch && this.mobileTouchView){
13479 cfg = this.getAutoCreateTouchView();
13486 if(!this.tickable){
13487 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
13492 * ComboBox with tickable selections
13495 var align = this.labelAlign || this.parentLabelAlign();
13498 cls : 'form-group roo-combobox-tickable' //input-group
13501 var btn_text_select = '';
13502 var btn_text_done = '';
13503 var btn_text_cancel = '';
13505 if (this.btn_text_show) {
13506 btn_text_select = 'Select';
13507 btn_text_done = 'Done';
13508 btn_text_cancel = 'Cancel';
13513 cls : 'tickable-buttons',
13518 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
13519 //html : this.triggerText
13520 html: btn_text_select
13526 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
13528 html: btn_text_done
13534 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
13536 html: btn_text_cancel
13542 buttons.cn.unshift({
13544 cls: 'roo-select2-search-field-input'
13550 Roo.each(buttons.cn, function(c){
13552 c.cls += ' btn-' + _this.size;
13555 if (_this.disabled) {
13562 style : 'display: contents',
13567 cls: 'form-hidden-field'
13571 cls: 'roo-select2-choices',
13575 cls: 'roo-select2-search-field',
13586 cls: 'roo-select2-container input-group roo-select2-container-multi',
13592 // cls: 'typeahead typeahead-long dropdown-menu',
13593 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
13598 if(this.hasFeedback && !this.allowBlank){
13602 cls: 'glyphicon form-control-feedback'
13605 combobox.cn.push(feedback);
13610 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
13611 tooltip : 'This field is required'
13613 if (Roo.bootstrap.version == 4) {
13616 style : 'display:none'
13619 if (align ==='left' && this.fieldLabel.length) {
13621 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
13628 cls : 'control-label col-form-label',
13629 html : this.fieldLabel
13641 var labelCfg = cfg.cn[1];
13642 var contentCfg = cfg.cn[2];
13645 if(this.indicatorpos == 'right'){
13651 cls : 'control-label col-form-label',
13655 html : this.fieldLabel
13671 labelCfg = cfg.cn[0];
13672 contentCfg = cfg.cn[1];
13676 if(this.labelWidth > 12){
13677 labelCfg.style = "width: " + this.labelWidth + 'px';
13680 if(this.labelWidth < 13 && this.labelmd == 0){
13681 this.labelmd = this.labelWidth;
13684 if(this.labellg > 0){
13685 labelCfg.cls += ' col-lg-' + this.labellg;
13686 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
13689 if(this.labelmd > 0){
13690 labelCfg.cls += ' col-md-' + this.labelmd;
13691 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
13694 if(this.labelsm > 0){
13695 labelCfg.cls += ' col-sm-' + this.labelsm;
13696 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
13699 if(this.labelxs > 0){
13700 labelCfg.cls += ' col-xs-' + this.labelxs;
13701 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
13705 } else if ( this.fieldLabel.length) {
13706 // Roo.log(" label");
13711 //cls : 'input-group-addon',
13712 html : this.fieldLabel
13717 if(this.indicatorpos == 'right'){
13721 //cls : 'input-group-addon',
13722 html : this.fieldLabel
13732 // Roo.log(" no label && no align");
13739 ['xs','sm','md','lg'].map(function(size){
13740 if (settings[size]) {
13741 cfg.cls += ' col-' + size + '-' + settings[size];
13749 _initEventsCalled : false,
13752 initEvents: function()
13754 if (this._initEventsCalled) { // as we call render... prevent looping...
13757 this._initEventsCalled = true;
13760 throw "can not find store for combo";
13763 this.indicator = this.indicatorEl();
13765 this.store = Roo.factory(this.store, Roo.data);
13766 this.store.parent = this;
13768 // if we are building from html. then this element is so complex, that we can not really
13769 // use the rendered HTML.
13770 // so we have to trash and replace the previous code.
13771 if (Roo.XComponent.build_from_html) {
13772 // remove this element....
13773 var e = this.el.dom, k=0;
13774 while (e ) { e = e.previousSibling; ++k;}
13779 this.rendered = false;
13781 this.render(this.parent().getChildContainer(true), k);
13784 if(Roo.isIOS && this.useNativeIOS){
13785 this.initIOSView();
13793 if(Roo.isTouch && this.mobileTouchView){
13794 this.initTouchView();
13799 this.initTickableEvents();
13803 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
13805 if(this.hiddenName){
13807 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13809 this.hiddenField.dom.value =
13810 this.hiddenValue !== undefined ? this.hiddenValue :
13811 this.value !== undefined ? this.value : '';
13813 // prevent input submission
13814 this.el.dom.removeAttribute('name');
13815 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13820 // this.el.dom.setAttribute('autocomplete', 'off');
13823 var cls = 'x-combo-list';
13825 //this.list = new Roo.Layer({
13826 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
13832 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13833 _this.list.setWidth(lw);
13836 this.list.on('mouseover', this.onViewOver, this);
13837 this.list.on('mousemove', this.onViewMove, this);
13838 this.list.on('scroll', this.onViewScroll, this);
13841 this.list.swallowEvent('mousewheel');
13842 this.assetHeight = 0;
13845 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
13846 this.assetHeight += this.header.getHeight();
13849 this.innerList = this.list.createChild({cls:cls+'-inner'});
13850 this.innerList.on('mouseover', this.onViewOver, this);
13851 this.innerList.on('mousemove', this.onViewMove, this);
13852 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13854 if(this.allowBlank && !this.pageSize && !this.disableClear){
13855 this.footer = this.list.createChild({cls:cls+'-ft'});
13856 this.pageTb = new Roo.Toolbar(this.footer);
13860 this.footer = this.list.createChild({cls:cls+'-ft'});
13861 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
13862 {pageSize: this.pageSize});
13866 if (this.pageTb && this.allowBlank && !this.disableClear) {
13868 this.pageTb.add(new Roo.Toolbar.Fill(), {
13869 cls: 'x-btn-icon x-btn-clear',
13871 handler: function()
13874 _this.clearValue();
13875 _this.onSelect(false, -1);
13880 this.assetHeight += this.footer.getHeight();
13885 this.tpl = Roo.bootstrap.version == 4 ?
13886 '<a class="dropdown-item" href="#">{' + this.displayField + '}</a>' : // 4 does not need <li> and it get's really confisued.
13887 '<li><a class="dropdown-item" href="#">{' + this.displayField + '}</a></li>';
13890 this.view = new Roo.View(this.list, this.tpl, {
13891 singleSelect:true, store: this.store, selectedClass: this.selectedClass
13893 //this.view.wrapEl.setDisplayed(false);
13894 this.view.on('click', this.onViewClick, this);
13897 this.store.on('beforeload', this.onBeforeLoad, this);
13898 this.store.on('load', this.onLoad, this);
13899 this.store.on('loadexception', this.onLoadException, this);
13901 if(this.resizable){
13902 this.resizer = new Roo.Resizable(this.list, {
13903 pinned:true, handles:'se'
13905 this.resizer.on('resize', function(r, w, h){
13906 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
13907 this.listWidth = w;
13908 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
13909 this.restrictHeight();
13911 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
13914 if(!this.editable){
13915 this.editable = true;
13916 this.setEditable(false);
13921 if (typeof(this.events.add.listeners) != 'undefined') {
13923 this.addicon = this.wrap.createChild(
13924 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
13926 this.addicon.on('click', function(e) {
13927 this.fireEvent('add', this);
13930 if (typeof(this.events.edit.listeners) != 'undefined') {
13932 this.editicon = this.wrap.createChild(
13933 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
13934 if (this.addicon) {
13935 this.editicon.setStyle('margin-left', '40px');
13937 this.editicon.on('click', function(e) {
13939 // we fire even if inothing is selected..
13940 this.fireEvent('edit', this, this.lastData );
13946 this.keyNav = new Roo.KeyNav(this.inputEl(), {
13947 "up" : function(e){
13948 this.inKeyMode = true;
13952 "down" : function(e){
13953 if(!this.isExpanded()){
13954 this.onTriggerClick();
13956 this.inKeyMode = true;
13961 "enter" : function(e){
13962 // this.onViewClick();
13966 if(this.fireEvent("specialkey", this, e)){
13967 this.onViewClick(false);
13973 "esc" : function(e){
13977 "tab" : function(e){
13980 if(this.fireEvent("specialkey", this, e)){
13981 this.onViewClick(false);
13989 doRelay : function(foo, bar, hname){
13990 if(hname == 'down' || this.scope.isExpanded()){
13991 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
14000 this.queryDelay = Math.max(this.queryDelay || 10,
14001 this.mode == 'local' ? 10 : 250);
14004 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
14006 if(this.typeAhead){
14007 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
14009 if(this.editable !== false){
14010 this.inputEl().on("keyup", this.onKeyUp, this);
14012 if(this.forceSelection){
14013 this.inputEl().on('blur', this.doForce, this);
14017 this.choices = this.el.select('ul.roo-select2-choices', true).first();
14018 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
14022 initTickableEvents: function()
14026 if(this.hiddenName){
14028 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
14030 this.hiddenField.dom.value =
14031 this.hiddenValue !== undefined ? this.hiddenValue :
14032 this.value !== undefined ? this.value : '';
14034 // prevent input submission
14035 this.el.dom.removeAttribute('name');
14036 this.hiddenField.dom.setAttribute('name', this.hiddenName);
14041 // this.list = this.el.select('ul.dropdown-menu',true).first();
14043 this.choices = this.el.select('ul.roo-select2-choices', true).first();
14044 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
14045 if(this.triggerList){
14046 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
14049 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
14050 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
14052 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
14053 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
14055 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
14056 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
14058 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
14059 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
14060 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
14063 this.cancelBtn.hide();
14068 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
14069 _this.list.setWidth(lw);
14072 this.list.on('mouseover', this.onViewOver, this);
14073 this.list.on('mousemove', this.onViewMove, this);
14075 this.list.on('scroll', this.onViewScroll, this);
14078 this.tpl = '<li class="roo-select2-result"><div class="checkbox"><input id="{roo-id}"' +
14079 'type="checkbox" {roo-data-checked}><label for="{roo-id}"><b>{' + this.displayField + '}</b></label></div></li>';
14082 this.view = new Roo.View(this.list, this.tpl, {
14087 selectedClass: this.selectedClass
14090 //this.view.wrapEl.setDisplayed(false);
14091 this.view.on('click', this.onViewClick, this);
14095 this.store.on('beforeload', this.onBeforeLoad, this);
14096 this.store.on('load', this.onLoad, this);
14097 this.store.on('loadexception', this.onLoadException, this);
14100 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
14101 "up" : function(e){
14102 this.inKeyMode = true;
14106 "down" : function(e){
14107 this.inKeyMode = true;
14111 "enter" : function(e){
14112 if(this.fireEvent("specialkey", this, e)){
14113 this.onViewClick(false);
14119 "esc" : function(e){
14120 this.onTickableFooterButtonClick(e, false, false);
14123 "tab" : function(e){
14124 this.fireEvent("specialkey", this, e);
14126 this.onTickableFooterButtonClick(e, false, false);
14133 doRelay : function(e, fn, key){
14134 if(this.scope.isExpanded()){
14135 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
14144 this.queryDelay = Math.max(this.queryDelay || 10,
14145 this.mode == 'local' ? 10 : 250);
14148 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
14150 if(this.typeAhead){
14151 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
14154 if(this.editable !== false){
14155 this.tickableInputEl().on("keyup", this.onKeyUp, this);
14158 this.indicator = this.indicatorEl();
14160 if(this.indicator){
14161 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
14162 this.indicator.hide();
14167 onDestroy : function(){
14169 this.view.setStore(null);
14170 this.view.el.removeAllListeners();
14171 this.view.el.remove();
14172 this.view.purgeListeners();
14175 this.list.dom.innerHTML = '';
14179 this.store.un('beforeload', this.onBeforeLoad, this);
14180 this.store.un('load', this.onLoad, this);
14181 this.store.un('loadexception', this.onLoadException, this);
14183 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
14187 fireKey : function(e){
14188 if(e.isNavKeyPress() && !this.list.isVisible()){
14189 this.fireEvent("specialkey", this, e);
14194 onResize: function(w, h){
14195 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
14197 // if(typeof w != 'number'){
14198 // // we do not handle it!?!?
14201 // var tw = this.trigger.getWidth();
14202 // // tw += this.addicon ? this.addicon.getWidth() : 0;
14203 // // tw += this.editicon ? this.editicon.getWidth() : 0;
14205 // this.inputEl().setWidth( this.adjustWidth('input', x));
14207 // //this.trigger.setStyle('left', x+'px');
14209 // if(this.list && this.listWidth === undefined){
14210 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
14211 // this.list.setWidth(lw);
14212 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
14220 * Allow or prevent the user from directly editing the field text. If false is passed,
14221 * the user will only be able to select from the items defined in the dropdown list. This method
14222 * is the runtime equivalent of setting the 'editable' config option at config time.
14223 * @param {Boolean} value True to allow the user to directly edit the field text
14225 setEditable : function(value){
14226 if(value == this.editable){
14229 this.editable = value;
14231 this.inputEl().dom.setAttribute('readOnly', true);
14232 this.inputEl().on('mousedown', this.onTriggerClick, this);
14233 this.inputEl().addClass('x-combo-noedit');
14235 this.inputEl().dom.setAttribute('readOnly', false);
14236 this.inputEl().un('mousedown', this.onTriggerClick, this);
14237 this.inputEl().removeClass('x-combo-noedit');
14243 onBeforeLoad : function(combo,opts){
14244 if(!this.hasFocus){
14248 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
14250 this.restrictHeight();
14251 this.selectedIndex = -1;
14255 onLoad : function(){
14257 this.hasQuery = false;
14259 if(!this.hasFocus){
14263 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
14264 this.loading.hide();
14267 if(this.store.getCount() > 0){
14270 this.restrictHeight();
14271 if(this.lastQuery == this.allQuery){
14272 if(this.editable && !this.tickable){
14273 this.inputEl().dom.select();
14277 !this.selectByValue(this.value, true) &&
14280 !this.store.lastOptions ||
14281 typeof(this.store.lastOptions.add) == 'undefined' ||
14282 this.store.lastOptions.add != true
14285 this.select(0, true);
14288 if(this.autoFocus){
14291 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
14292 this.taTask.delay(this.typeAheadDelay);
14296 this.onEmptyResults();
14302 onLoadException : function()
14304 this.hasQuery = false;
14306 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
14307 this.loading.hide();
14310 if(this.tickable && this.editable){
14315 // only causes errors at present
14316 //Roo.log(this.store.reader.jsonData);
14317 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
14319 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
14325 onTypeAhead : function(){
14326 if(this.store.getCount() > 0){
14327 var r = this.store.getAt(0);
14328 var newValue = r.data[this.displayField];
14329 var len = newValue.length;
14330 var selStart = this.getRawValue().length;
14332 if(selStart != len){
14333 this.setRawValue(newValue);
14334 this.selectText(selStart, newValue.length);
14340 onSelect : function(record, index){
14342 if(this.fireEvent('beforeselect', this, record, index) !== false){
14344 this.setFromData(index > -1 ? record.data : false);
14347 this.fireEvent('select', this, record, index);
14352 * Returns the currently selected field value or empty string if no value is set.
14353 * @return {String} value The selected value
14355 getValue : function()
14357 if(Roo.isIOS && this.useNativeIOS){
14358 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
14362 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
14365 if(this.valueField){
14366 return typeof this.value != 'undefined' ? this.value : '';
14368 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
14372 getRawValue : function()
14374 if(Roo.isIOS && this.useNativeIOS){
14375 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
14378 var v = this.inputEl().getValue();
14384 * Clears any text/value currently set in the field
14386 clearValue : function(){
14388 if(this.hiddenField){
14389 this.hiddenField.dom.value = '';
14392 this.setRawValue('');
14393 this.lastSelectionText = '';
14394 this.lastData = false;
14396 var close = this.closeTriggerEl();
14407 * Sets the specified value into the field. If the value finds a match, the corresponding record text
14408 * will be displayed in the field. If the value does not match the data value of an existing item,
14409 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
14410 * Otherwise the field will be blank (although the value will still be set).
14411 * @param {String} value The value to match
14413 setValue : function(v)
14415 if(Roo.isIOS && this.useNativeIOS){
14416 this.setIOSValue(v);
14426 if(this.valueField){
14427 var r = this.findRecord(this.valueField, v);
14429 text = r.data[this.displayField];
14430 }else if(this.valueNotFoundText !== undefined){
14431 text = this.valueNotFoundText;
14434 this.lastSelectionText = text;
14435 if(this.hiddenField){
14436 this.hiddenField.dom.value = v;
14438 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
14441 var close = this.closeTriggerEl();
14444 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
14450 * @property {Object} the last set data for the element
14455 * Sets the value of the field based on a object which is related to the record format for the store.
14456 * @param {Object} value the value to set as. or false on reset?
14458 setFromData : function(o){
14465 var dv = ''; // display value
14466 var vv = ''; // value value..
14468 if (this.displayField) {
14469 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14471 // this is an error condition!!!
14472 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14475 if(this.valueField){
14476 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
14479 var close = this.closeTriggerEl();
14482 if(dv.length || vv * 1 > 0){
14484 this.blockFocus=true;
14490 if(this.hiddenField){
14491 this.hiddenField.dom.value = vv;
14493 this.lastSelectionText = dv;
14494 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14498 // no hidden field.. - we store the value in 'value', but still display
14499 // display field!!!!
14500 this.lastSelectionText = dv;
14501 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14508 reset : function(){
14509 // overridden so that last data is reset..
14516 this.setValue(this.originalValue);
14517 //this.clearInvalid();
14518 this.lastData = false;
14520 this.view.clearSelections();
14526 findRecord : function(prop, value){
14528 if(this.store.getCount() > 0){
14529 this.store.each(function(r){
14530 if(r.data[prop] == value){
14540 getName: function()
14542 // returns hidden if it's set..
14543 if (!this.rendered) {return ''};
14544 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
14548 onViewMove : function(e, t){
14549 this.inKeyMode = false;
14553 onViewOver : function(e, t){
14554 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
14557 var item = this.view.findItemFromChild(t);
14560 var index = this.view.indexOf(item);
14561 this.select(index, false);
14566 onViewClick : function(view, doFocus, el, e)
14568 var index = this.view.getSelectedIndexes()[0];
14570 var r = this.store.getAt(index);
14574 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
14581 Roo.each(this.tickItems, function(v,k){
14583 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
14585 _this.tickItems.splice(k, 1);
14587 if(typeof(e) == 'undefined' && view == false){
14588 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
14600 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
14601 this.tickItems.push(r.data);
14604 if(typeof(e) == 'undefined' && view == false){
14605 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
14612 this.onSelect(r, index);
14614 if(doFocus !== false && !this.blockFocus){
14615 this.inputEl().focus();
14620 restrictHeight : function(){
14621 //this.innerList.dom.style.height = '';
14622 //var inner = this.innerList.dom;
14623 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
14624 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
14625 //this.list.beginUpdate();
14626 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
14627 this.list.alignTo(this.inputEl(), this.listAlign);
14628 this.list.alignTo(this.inputEl(), this.listAlign);
14629 //this.list.endUpdate();
14633 onEmptyResults : function(){
14635 if(this.tickable && this.editable){
14636 this.hasFocus = false;
14637 this.restrictHeight();
14645 * Returns true if the dropdown list is expanded, else false.
14647 isExpanded : function(){
14648 return this.list.isVisible();
14652 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
14653 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14654 * @param {String} value The data value of the item to select
14655 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14656 * selected item if it is not currently in view (defaults to true)
14657 * @return {Boolean} True if the value matched an item in the list, else false
14659 selectByValue : function(v, scrollIntoView){
14660 if(v !== undefined && v !== null){
14661 var r = this.findRecord(this.valueField || this.displayField, v);
14663 this.select(this.store.indexOf(r), scrollIntoView);
14671 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
14672 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14673 * @param {Number} index The zero-based index of the list item to select
14674 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14675 * selected item if it is not currently in view (defaults to true)
14677 select : function(index, scrollIntoView){
14678 this.selectedIndex = index;
14679 this.view.select(index);
14680 if(scrollIntoView !== false){
14681 var el = this.view.getNode(index);
14683 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
14686 this.list.scrollChildIntoView(el, false);
14692 selectNext : function(){
14693 var ct = this.store.getCount();
14695 if(this.selectedIndex == -1){
14697 }else if(this.selectedIndex < ct-1){
14698 this.select(this.selectedIndex+1);
14704 selectPrev : function(){
14705 var ct = this.store.getCount();
14707 if(this.selectedIndex == -1){
14709 }else if(this.selectedIndex != 0){
14710 this.select(this.selectedIndex-1);
14716 onKeyUp : function(e){
14717 if(this.editable !== false && !e.isSpecialKey()){
14718 this.lastKey = e.getKey();
14719 this.dqTask.delay(this.queryDelay);
14724 validateBlur : function(){
14725 return !this.list || !this.list.isVisible();
14729 initQuery : function(){
14731 var v = this.getRawValue();
14733 if(this.tickable && this.editable){
14734 v = this.tickableInputEl().getValue();
14741 doForce : function(){
14742 if(this.inputEl().dom.value.length > 0){
14743 this.inputEl().dom.value =
14744 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
14750 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
14751 * query allowing the query action to be canceled if needed.
14752 * @param {String} query The SQL query to execute
14753 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
14754 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
14755 * saved in the current store (defaults to false)
14757 doQuery : function(q, forceAll){
14759 if(q === undefined || q === null){
14764 forceAll: forceAll,
14768 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
14773 forceAll = qe.forceAll;
14774 if(forceAll === true || (q.length >= this.minChars)){
14776 this.hasQuery = true;
14778 if(this.lastQuery != q || this.alwaysQuery){
14779 this.lastQuery = q;
14780 if(this.mode == 'local'){
14781 this.selectedIndex = -1;
14783 this.store.clearFilter();
14786 if(this.specialFilter){
14787 this.fireEvent('specialfilter', this);
14792 this.store.filter(this.displayField, q);
14795 this.store.fireEvent("datachanged", this.store);
14802 this.store.baseParams[this.queryParam] = q;
14804 var options = {params : this.getParams(q)};
14807 options.add = true;
14808 options.params.start = this.page * this.pageSize;
14811 this.store.load(options);
14814 * this code will make the page width larger, at the beginning, the list not align correctly,
14815 * we should expand the list on onLoad
14816 * so command out it
14821 this.selectedIndex = -1;
14826 this.loadNext = false;
14830 getParams : function(q){
14832 //p[this.queryParam] = q;
14836 p.limit = this.pageSize;
14842 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
14844 collapse : function(){
14845 if(!this.isExpanded()){
14851 this.hasFocus = false;
14855 this.cancelBtn.hide();
14856 this.trigger.show();
14859 this.tickableInputEl().dom.value = '';
14860 this.tickableInputEl().blur();
14865 Roo.get(document).un('mousedown', this.collapseIf, this);
14866 Roo.get(document).un('mousewheel', this.collapseIf, this);
14867 if (!this.editable) {
14868 Roo.get(document).un('keydown', this.listKeyPress, this);
14870 this.fireEvent('collapse', this);
14876 collapseIf : function(e){
14877 var in_combo = e.within(this.el);
14878 var in_list = e.within(this.list);
14879 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
14881 if (in_combo || in_list || is_list) {
14882 //e.stopPropagation();
14887 this.onTickableFooterButtonClick(e, false, false);
14895 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
14897 expand : function(){
14899 if(this.isExpanded() || !this.hasFocus){
14903 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
14904 this.list.setWidth(lw);
14910 this.restrictHeight();
14914 this.tickItems = Roo.apply([], this.item);
14917 this.cancelBtn.show();
14918 this.trigger.hide();
14921 this.tickableInputEl().focus();
14926 Roo.get(document).on('mousedown', this.collapseIf, this);
14927 Roo.get(document).on('mousewheel', this.collapseIf, this);
14928 if (!this.editable) {
14929 Roo.get(document).on('keydown', this.listKeyPress, this);
14932 this.fireEvent('expand', this);
14936 // Implements the default empty TriggerField.onTriggerClick function
14937 onTriggerClick : function(e)
14939 Roo.log('trigger click');
14941 if(this.disabled || !this.triggerList){
14946 this.loadNext = false;
14948 if(this.isExpanded()){
14950 if (!this.blockFocus) {
14951 this.inputEl().focus();
14955 this.hasFocus = true;
14956 if(this.triggerAction == 'all') {
14957 this.doQuery(this.allQuery, true);
14959 this.doQuery(this.getRawValue());
14961 if (!this.blockFocus) {
14962 this.inputEl().focus();
14967 onTickableTriggerClick : function(e)
14974 this.loadNext = false;
14975 this.hasFocus = true;
14977 if(this.triggerAction == 'all') {
14978 this.doQuery(this.allQuery, true);
14980 this.doQuery(this.getRawValue());
14984 onSearchFieldClick : function(e)
14986 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
14987 this.onTickableFooterButtonClick(e, false, false);
14991 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
14996 this.loadNext = false;
14997 this.hasFocus = true;
14999 if(this.triggerAction == 'all') {
15000 this.doQuery(this.allQuery, true);
15002 this.doQuery(this.getRawValue());
15006 listKeyPress : function(e)
15008 //Roo.log('listkeypress');
15009 // scroll to first matching element based on key pres..
15010 if (e.isSpecialKey()) {
15013 var k = String.fromCharCode(e.getKey()).toUpperCase();
15016 var csel = this.view.getSelectedNodes();
15017 var cselitem = false;
15019 var ix = this.view.indexOf(csel[0]);
15020 cselitem = this.store.getAt(ix);
15021 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
15027 this.store.each(function(v) {
15029 // start at existing selection.
15030 if (cselitem.id == v.id) {
15036 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
15037 match = this.store.indexOf(v);
15043 if (match === false) {
15044 return true; // no more action?
15047 this.view.select(match);
15048 var sn = Roo.get(this.view.getSelectedNodes()[0]);
15049 sn.scrollIntoView(sn.dom.parentNode, false);
15052 onViewScroll : function(e, t){
15054 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){
15058 this.hasQuery = true;
15060 this.loading = this.list.select('.loading', true).first();
15062 if(this.loading === null){
15063 this.list.createChild({
15065 cls: 'loading roo-select2-more-results roo-select2-active',
15066 html: 'Loading more results...'
15069 this.loading = this.list.select('.loading', true).first();
15071 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
15073 this.loading.hide();
15076 this.loading.show();
15081 this.loadNext = true;
15083 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
15088 addItem : function(o)
15090 var dv = ''; // display value
15092 if (this.displayField) {
15093 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
15095 // this is an error condition!!!
15096 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
15103 var choice = this.choices.createChild({
15105 cls: 'roo-select2-search-choice',
15114 cls: 'roo-select2-search-choice-close fa fa-times',
15119 }, this.searchField);
15121 var close = choice.select('a.roo-select2-search-choice-close', true).first();
15123 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
15131 this.inputEl().dom.value = '';
15136 onRemoveItem : function(e, _self, o)
15138 e.preventDefault();
15140 this.lastItem = Roo.apply([], this.item);
15142 var index = this.item.indexOf(o.data) * 1;
15145 Roo.log('not this item?!');
15149 this.item.splice(index, 1);
15154 this.fireEvent('remove', this, e);
15160 syncValue : function()
15162 if(!this.item.length){
15169 Roo.each(this.item, function(i){
15170 if(_this.valueField){
15171 value.push(i[_this.valueField]);
15178 this.value = value.join(',');
15180 if(this.hiddenField){
15181 this.hiddenField.dom.value = this.value;
15184 this.store.fireEvent("datachanged", this.store);
15189 clearItem : function()
15191 if(!this.multiple){
15197 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
15205 if(this.tickable && !Roo.isTouch){
15206 this.view.refresh();
15210 inputEl: function ()
15212 if(Roo.isIOS && this.useNativeIOS){
15213 return this.el.select('select.roo-ios-select', true).first();
15216 if(Roo.isTouch && this.mobileTouchView){
15217 return this.el.select('input.form-control',true).first();
15221 return this.searchField;
15224 return this.el.select('input.form-control',true).first();
15227 onTickableFooterButtonClick : function(e, btn, el)
15229 e.preventDefault();
15231 this.lastItem = Roo.apply([], this.item);
15233 if(btn && btn.name == 'cancel'){
15234 this.tickItems = Roo.apply([], this.item);
15243 Roo.each(this.tickItems, function(o){
15251 validate : function()
15253 if(this.getVisibilityEl().hasClass('hidden')){
15257 var v = this.getRawValue();
15260 v = this.getValue();
15263 if(this.disabled || this.allowBlank || v.length){
15268 this.markInvalid();
15272 tickableInputEl : function()
15274 if(!this.tickable || !this.editable){
15275 return this.inputEl();
15278 return this.inputEl().select('.roo-select2-search-field-input', true).first();
15282 getAutoCreateTouchView : function()
15287 cls: 'form-group' //input-group
15293 type : this.inputType,
15294 cls : 'form-control x-combo-noedit',
15295 autocomplete: 'new-password',
15296 placeholder : this.placeholder || '',
15301 input.name = this.name;
15305 input.cls += ' input-' + this.size;
15308 if (this.disabled) {
15309 input.disabled = true;
15320 inputblock.cls += ' input-group';
15322 inputblock.cn.unshift({
15324 cls : 'input-group-addon input-group-prepend input-group-text',
15329 if(this.removable && !this.multiple){
15330 inputblock.cls += ' roo-removable';
15332 inputblock.cn.push({
15335 cls : 'roo-combo-removable-btn close'
15339 if(this.hasFeedback && !this.allowBlank){
15341 inputblock.cls += ' has-feedback';
15343 inputblock.cn.push({
15345 cls: 'glyphicon form-control-feedback'
15352 inputblock.cls += (this.before) ? '' : ' input-group';
15354 inputblock.cn.push({
15356 cls : 'input-group-addon input-group-append input-group-text',
15362 var ibwrap = inputblock;
15367 cls: 'roo-select2-choices',
15371 cls: 'roo-select2-search-field',
15384 cls: 'roo-select2-container input-group roo-touchview-combobox ',
15389 cls: 'form-hidden-field'
15395 if(!this.multiple && this.showToggleBtn){
15401 if (this.caret != false) {
15404 cls: 'fa fa-' + this.caret
15411 cls : 'input-group-addon input-group-append input-group-text btn dropdown-toggle',
15413 Roo.bootstrap.version == 3 ? caret : '',
15416 cls: 'combobox-clear',
15430 combobox.cls += ' roo-select2-container-multi';
15433 var align = this.labelAlign || this.parentLabelAlign();
15435 if (align ==='left' && this.fieldLabel.length) {
15440 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15441 tooltip : 'This field is required'
15445 cls : 'control-label col-form-label',
15446 html : this.fieldLabel
15457 var labelCfg = cfg.cn[1];
15458 var contentCfg = cfg.cn[2];
15461 if(this.indicatorpos == 'right'){
15466 cls : 'control-label col-form-label',
15470 html : this.fieldLabel
15474 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15475 tooltip : 'This field is required'
15488 labelCfg = cfg.cn[0];
15489 contentCfg = cfg.cn[1];
15494 if(this.labelWidth > 12){
15495 labelCfg.style = "width: " + this.labelWidth + 'px';
15498 if(this.labelWidth < 13 && this.labelmd == 0){
15499 this.labelmd = this.labelWidth;
15502 if(this.labellg > 0){
15503 labelCfg.cls += ' col-lg-' + this.labellg;
15504 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
15507 if(this.labelmd > 0){
15508 labelCfg.cls += ' col-md-' + this.labelmd;
15509 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
15512 if(this.labelsm > 0){
15513 labelCfg.cls += ' col-sm-' + this.labelsm;
15514 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
15517 if(this.labelxs > 0){
15518 labelCfg.cls += ' col-xs-' + this.labelxs;
15519 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
15523 } else if ( this.fieldLabel.length) {
15527 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15528 tooltip : 'This field is required'
15532 cls : 'control-label',
15533 html : this.fieldLabel
15544 if(this.indicatorpos == 'right'){
15548 cls : 'control-label',
15549 html : this.fieldLabel,
15553 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15554 tooltip : 'This field is required'
15571 var settings = this;
15573 ['xs','sm','md','lg'].map(function(size){
15574 if (settings[size]) {
15575 cfg.cls += ' col-' + size + '-' + settings[size];
15582 initTouchView : function()
15584 this.renderTouchView();
15586 this.touchViewEl.on('scroll', function(){
15587 this.el.dom.scrollTop = 0;
15590 this.originalValue = this.getValue();
15592 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
15594 this.inputEl().on("click", this.showTouchView, this);
15595 if (this.triggerEl) {
15596 this.triggerEl.on("click", this.showTouchView, this);
15600 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
15601 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
15603 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
15605 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
15606 this.store.on('load', this.onTouchViewLoad, this);
15607 this.store.on('loadexception', this.onTouchViewLoadException, this);
15609 if(this.hiddenName){
15611 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
15613 this.hiddenField.dom.value =
15614 this.hiddenValue !== undefined ? this.hiddenValue :
15615 this.value !== undefined ? this.value : '';
15617 this.el.dom.removeAttribute('name');
15618 this.hiddenField.dom.setAttribute('name', this.hiddenName);
15622 this.choices = this.el.select('ul.roo-select2-choices', true).first();
15623 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
15626 if(this.removable && !this.multiple){
15627 var close = this.closeTriggerEl();
15629 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
15630 close.on('click', this.removeBtnClick, this, close);
15634 * fix the bug in Safari iOS8
15636 this.inputEl().on("focus", function(e){
15637 document.activeElement.blur();
15640 this._touchViewMask = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
15647 renderTouchView : function()
15649 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
15650 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15652 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
15653 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15655 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
15656 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15657 this.touchViewBodyEl.setStyle('overflow', 'auto');
15659 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
15660 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15662 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
15663 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15667 showTouchView : function()
15673 this.touchViewHeaderEl.hide();
15675 if(this.modalTitle.length){
15676 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
15677 this.touchViewHeaderEl.show();
15680 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
15681 this.touchViewEl.show();
15683 this.touchViewEl.select('.modal-dialog', true).first().setStyle({ margin : '0px', width : '100%'});
15685 //this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
15686 // Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15688 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15690 if(this.modalTitle.length){
15691 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15694 this.touchViewBodyEl.setHeight(bodyHeight);
15698 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
15700 this.touchViewEl.addClass('in');
15703 if(this._touchViewMask){
15704 Roo.get(document.body).addClass("x-body-masked");
15705 this._touchViewMask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15706 this._touchViewMask.setStyle('z-index', 10000);
15707 this._touchViewMask.addClass('show');
15710 this.doTouchViewQuery();
15714 hideTouchView : function()
15716 this.touchViewEl.removeClass('in');
15720 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
15722 this.touchViewEl.setStyle('display', 'none');
15725 if(this._touchViewMask){
15726 this._touchViewMask.removeClass('show');
15727 Roo.get(document.body).removeClass("x-body-masked");
15731 setTouchViewValue : function()
15738 Roo.each(this.tickItems, function(o){
15743 this.hideTouchView();
15746 doTouchViewQuery : function()
15755 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
15759 if(!this.alwaysQuery || this.mode == 'local'){
15760 this.onTouchViewLoad();
15767 onTouchViewBeforeLoad : function(combo,opts)
15773 onTouchViewLoad : function()
15775 if(this.store.getCount() < 1){
15776 this.onTouchViewEmptyResults();
15780 this.clearTouchView();
15782 var rawValue = this.getRawValue();
15784 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
15786 this.tickItems = [];
15788 this.store.data.each(function(d, rowIndex){
15789 var row = this.touchViewListGroup.createChild(template);
15791 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
15792 row.addClass(d.data.cls);
15795 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15798 html : d.data[this.displayField]
15801 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
15802 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
15805 row.removeClass('selected');
15806 if(!this.multiple && this.valueField &&
15807 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
15810 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15811 row.addClass('selected');
15814 if(this.multiple && this.valueField &&
15815 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
15819 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15820 this.tickItems.push(d.data);
15823 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
15827 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
15829 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15831 if(this.modalTitle.length){
15832 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15835 var listHeight = this.touchViewListGroup.getHeight() + this.touchViewBodyEl.getPadding('tb') * 2;
15837 if(this.mobile_restrict_height && listHeight < bodyHeight){
15838 this.touchViewBodyEl.setHeight(listHeight);
15843 if(firstChecked && listHeight > bodyHeight){
15844 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
15849 onTouchViewLoadException : function()
15851 this.hideTouchView();
15854 onTouchViewEmptyResults : function()
15856 this.clearTouchView();
15858 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
15860 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
15864 clearTouchView : function()
15866 this.touchViewListGroup.dom.innerHTML = '';
15869 onTouchViewClick : function(e, el, o)
15871 e.preventDefault();
15874 var rowIndex = o.rowIndex;
15876 var r = this.store.getAt(rowIndex);
15878 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
15880 if(!this.multiple){
15881 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
15882 c.dom.removeAttribute('checked');
15885 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15887 this.setFromData(r.data);
15889 var close = this.closeTriggerEl();
15895 this.hideTouchView();
15897 this.fireEvent('select', this, r, rowIndex);
15902 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
15903 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
15904 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
15908 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15909 this.addItem(r.data);
15910 this.tickItems.push(r.data);
15914 getAutoCreateNativeIOS : function()
15917 cls: 'form-group' //input-group,
15922 cls : 'roo-ios-select'
15926 combobox.name = this.name;
15929 if (this.disabled) {
15930 combobox.disabled = true;
15933 var settings = this;
15935 ['xs','sm','md','lg'].map(function(size){
15936 if (settings[size]) {
15937 cfg.cls += ' col-' + size + '-' + settings[size];
15947 initIOSView : function()
15949 this.store.on('load', this.onIOSViewLoad, this);
15954 onIOSViewLoad : function()
15956 if(this.store.getCount() < 1){
15960 this.clearIOSView();
15962 if(this.allowBlank) {
15964 var default_text = '-- SELECT --';
15966 if(this.placeholder.length){
15967 default_text = this.placeholder;
15970 if(this.emptyTitle.length){
15971 default_text += ' - ' + this.emptyTitle + ' -';
15974 var opt = this.inputEl().createChild({
15977 html : default_text
15981 o[this.valueField] = 0;
15982 o[this.displayField] = default_text;
15984 this.ios_options.push({
15991 this.store.data.each(function(d, rowIndex){
15995 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15996 html = d.data[this.displayField];
16001 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
16002 value = d.data[this.valueField];
16011 if(this.value == d.data[this.valueField]){
16012 option['selected'] = true;
16015 var opt = this.inputEl().createChild(option);
16017 this.ios_options.push({
16024 this.inputEl().on('change', function(){
16025 this.fireEvent('select', this);
16030 clearIOSView: function()
16032 this.inputEl().dom.innerHTML = '';
16034 this.ios_options = [];
16037 setIOSValue: function(v)
16041 if(!this.ios_options){
16045 Roo.each(this.ios_options, function(opts){
16047 opts.el.dom.removeAttribute('selected');
16049 if(opts.data[this.valueField] != v){
16053 opts.el.dom.setAttribute('selected', true);
16059 * @cfg {Boolean} grow
16063 * @cfg {Number} growMin
16067 * @cfg {Number} growMax
16076 Roo.apply(Roo.bootstrap.ComboBox, {
16080 cls: 'modal-header',
16102 cls: 'list-group-item',
16106 cls: 'roo-combobox-list-group-item-value'
16110 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
16124 listItemCheckbox : {
16126 cls: 'list-group-item',
16130 cls: 'roo-combobox-list-group-item-value'
16134 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
16150 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
16155 cls: 'modal-footer',
16163 cls: 'col-xs-6 text-left',
16166 cls: 'btn btn-danger roo-touch-view-cancel',
16172 cls: 'col-xs-6 text-right',
16175 cls: 'btn btn-success roo-touch-view-ok',
16186 Roo.apply(Roo.bootstrap.ComboBox, {
16188 touchViewTemplate : {
16190 cls: 'modal fade roo-combobox-touch-view',
16194 cls: 'modal-dialog',
16195 style : 'position:fixed', // we have to fix position....
16199 cls: 'modal-content',
16201 Roo.bootstrap.ComboBox.header,
16202 Roo.bootstrap.ComboBox.body,
16203 Roo.bootstrap.ComboBox.footer
16212 * Ext JS Library 1.1.1
16213 * Copyright(c) 2006-2007, Ext JS, LLC.
16215 * Originally Released Under LGPL - original licence link has changed is not relivant.
16218 * <script type="text/javascript">
16223 * @extends Roo.util.Observable
16224 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
16225 * This class also supports single and multi selection modes. <br>
16226 * Create a data model bound view:
16228 var store = new Roo.data.Store(...);
16230 var view = new Roo.View({
16232 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
16234 singleSelect: true,
16235 selectedClass: "ydataview-selected",
16239 // listen for node click?
16240 view.on("click", function(vw, index, node, e){
16241 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
16245 dataModel.load("foobar.xml");
16247 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
16249 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
16250 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
16252 * Note: old style constructor is still suported (container, template, config)
16255 * Create a new View
16256 * @param {Object} config The config object
16259 Roo.View = function(config, depreciated_tpl, depreciated_config){
16261 this.parent = false;
16263 if (typeof(depreciated_tpl) == 'undefined') {
16264 // new way.. - universal constructor.
16265 Roo.apply(this, config);
16266 this.el = Roo.get(this.el);
16269 this.el = Roo.get(config);
16270 this.tpl = depreciated_tpl;
16271 Roo.apply(this, depreciated_config);
16273 this.wrapEl = this.el.wrap().wrap();
16274 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
16277 if(typeof(this.tpl) == "string"){
16278 this.tpl = new Roo.Template(this.tpl);
16280 // support xtype ctors..
16281 this.tpl = new Roo.factory(this.tpl, Roo);
16285 this.tpl.compile();
16290 * @event beforeclick
16291 * Fires before a click is processed. Returns false to cancel the default action.
16292 * @param {Roo.View} this
16293 * @param {Number} index The index of the target node
16294 * @param {HTMLElement} node The target node
16295 * @param {Roo.EventObject} e The raw event object
16297 "beforeclick" : true,
16300 * Fires when a template node is clicked.
16301 * @param {Roo.View} this
16302 * @param {Number} index The index of the target node
16303 * @param {HTMLElement} node The target node
16304 * @param {Roo.EventObject} e The raw event object
16309 * Fires when a template node is double clicked.
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
16317 * @event contextmenu
16318 * Fires when a template node is right 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
16324 "contextmenu" : true,
16326 * @event selectionchange
16327 * Fires when the selected nodes change.
16328 * @param {Roo.View} this
16329 * @param {Array} selections Array of the selected nodes
16331 "selectionchange" : true,
16334 * @event beforeselect
16335 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
16336 * @param {Roo.View} this
16337 * @param {HTMLElement} node The node to be selected
16338 * @param {Array} selections Array of currently selected nodes
16340 "beforeselect" : true,
16342 * @event preparedata
16343 * Fires on every row to render, to allow you to change the data.
16344 * @param {Roo.View} this
16345 * @param {Object} data to be rendered (change this)
16347 "preparedata" : true
16355 "click": this.onClick,
16356 "dblclick": this.onDblClick,
16357 "contextmenu": this.onContextMenu,
16361 this.selections = [];
16363 this.cmp = new Roo.CompositeElementLite([]);
16365 this.store = Roo.factory(this.store, Roo.data);
16366 this.setStore(this.store, true);
16369 if ( this.footer && this.footer.xtype) {
16371 var fctr = this.wrapEl.appendChild(document.createElement("div"));
16373 this.footer.dataSource = this.store;
16374 this.footer.container = fctr;
16375 this.footer = Roo.factory(this.footer, Roo);
16376 fctr.insertFirst(this.el);
16378 // this is a bit insane - as the paging toolbar seems to detach the el..
16379 // dom.parentNode.parentNode.parentNode
16380 // they get detached?
16384 Roo.View.superclass.constructor.call(this);
16389 Roo.extend(Roo.View, Roo.util.Observable, {
16392 * @cfg {Roo.data.Store} store Data store to load data from.
16397 * @cfg {String|Roo.Element} el The container element.
16402 * @cfg {String|Roo.Template} tpl The template used by this View
16406 * @cfg {String} dataName the named area of the template to use as the data area
16407 * Works with domtemplates roo-name="name"
16411 * @cfg {String} selectedClass The css class to add to selected nodes
16413 selectedClass : "x-view-selected",
16415 * @cfg {String} emptyText The empty text to show when nothing is loaded.
16420 * @cfg {String} text to display on mask (default Loading)
16424 * @cfg {Boolean} multiSelect Allow multiple selection
16426 multiSelect : false,
16428 * @cfg {Boolean} singleSelect Allow single selection
16430 singleSelect: false,
16433 * @cfg {Boolean} toggleSelect - selecting
16435 toggleSelect : false,
16438 * @cfg {Boolean} tickable - selecting
16443 * Returns the element this view is bound to.
16444 * @return {Roo.Element}
16446 getEl : function(){
16447 return this.wrapEl;
16453 * Refreshes the view. - called by datachanged on the store. - do not call directly.
16455 refresh : function(){
16456 //Roo.log('refresh');
16459 // if we are using something like 'domtemplate', then
16460 // the what gets used is:
16461 // t.applySubtemplate(NAME, data, wrapping data..)
16462 // the outer template then get' applied with
16463 // the store 'extra data'
16464 // and the body get's added to the
16465 // roo-name="data" node?
16466 // <span class='roo-tpl-{name}'></span> ?????
16470 this.clearSelections();
16471 this.el.update("");
16473 var records = this.store.getRange();
16474 if(records.length < 1) {
16476 // is this valid?? = should it render a template??
16478 this.el.update(this.emptyText);
16482 if (this.dataName) {
16483 this.el.update(t.apply(this.store.meta)); //????
16484 el = this.el.child('.roo-tpl-' + this.dataName);
16487 for(var i = 0, len = records.length; i < len; i++){
16488 var data = this.prepareData(records[i].data, i, records[i]);
16489 this.fireEvent("preparedata", this, data, i, records[i]);
16491 var d = Roo.apply({}, data);
16494 Roo.apply(d, {'roo-id' : Roo.id()});
16498 Roo.each(this.parent.item, function(item){
16499 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
16502 Roo.apply(d, {'roo-data-checked' : 'checked'});
16506 html[html.length] = Roo.util.Format.trim(
16508 t.applySubtemplate(this.dataName, d, this.store.meta) :
16515 el.update(html.join(""));
16516 this.nodes = el.dom.childNodes;
16517 this.updateIndexes(0);
16522 * Function to override to reformat the data that is sent to
16523 * the template for each node.
16524 * DEPRICATED - use the preparedata event handler.
16525 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
16526 * a JSON object for an UpdateManager bound view).
16528 prepareData : function(data, index, record)
16530 this.fireEvent("preparedata", this, data, index, record);
16534 onUpdate : function(ds, record){
16535 // Roo.log('on update');
16536 this.clearSelections();
16537 var index = this.store.indexOf(record);
16538 var n = this.nodes[index];
16539 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
16540 n.parentNode.removeChild(n);
16541 this.updateIndexes(index, index);
16547 onAdd : function(ds, records, index)
16549 //Roo.log(['on Add', ds, records, index] );
16550 this.clearSelections();
16551 if(this.nodes.length == 0){
16555 var n = this.nodes[index];
16556 for(var i = 0, len = records.length; i < len; i++){
16557 var d = this.prepareData(records[i].data, i, records[i]);
16559 this.tpl.insertBefore(n, d);
16562 this.tpl.append(this.el, d);
16565 this.updateIndexes(index);
16568 onRemove : function(ds, record, index){
16569 // Roo.log('onRemove');
16570 this.clearSelections();
16571 var el = this.dataName ?
16572 this.el.child('.roo-tpl-' + this.dataName) :
16575 el.dom.removeChild(this.nodes[index]);
16576 this.updateIndexes(index);
16580 * Refresh an individual node.
16581 * @param {Number} index
16583 refreshNode : function(index){
16584 this.onUpdate(this.store, this.store.getAt(index));
16587 updateIndexes : function(startIndex, endIndex){
16588 var ns = this.nodes;
16589 startIndex = startIndex || 0;
16590 endIndex = endIndex || ns.length - 1;
16591 for(var i = startIndex; i <= endIndex; i++){
16592 ns[i].nodeIndex = i;
16597 * Changes the data store this view uses and refresh the view.
16598 * @param {Store} store
16600 setStore : function(store, initial){
16601 if(!initial && this.store){
16602 this.store.un("datachanged", this.refresh);
16603 this.store.un("add", this.onAdd);
16604 this.store.un("remove", this.onRemove);
16605 this.store.un("update", this.onUpdate);
16606 this.store.un("clear", this.refresh);
16607 this.store.un("beforeload", this.onBeforeLoad);
16608 this.store.un("load", this.onLoad);
16609 this.store.un("loadexception", this.onLoad);
16613 store.on("datachanged", this.refresh, this);
16614 store.on("add", this.onAdd, this);
16615 store.on("remove", this.onRemove, this);
16616 store.on("update", this.onUpdate, this);
16617 store.on("clear", this.refresh, this);
16618 store.on("beforeload", this.onBeforeLoad, this);
16619 store.on("load", this.onLoad, this);
16620 store.on("loadexception", this.onLoad, this);
16628 * onbeforeLoad - masks the loading area.
16631 onBeforeLoad : function(store,opts)
16633 //Roo.log('onBeforeLoad');
16635 this.el.update("");
16637 this.el.mask(this.mask ? this.mask : "Loading" );
16639 onLoad : function ()
16646 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
16647 * @param {HTMLElement} node
16648 * @return {HTMLElement} The template node
16650 findItemFromChild : function(node){
16651 var el = this.dataName ?
16652 this.el.child('.roo-tpl-' + this.dataName,true) :
16655 if(!node || node.parentNode == el){
16658 var p = node.parentNode;
16659 while(p && p != el){
16660 if(p.parentNode == el){
16669 onClick : function(e){
16670 var item = this.findItemFromChild(e.getTarget());
16672 var index = this.indexOf(item);
16673 if(this.onItemClick(item, index, e) !== false){
16674 this.fireEvent("click", this, index, item, e);
16677 this.clearSelections();
16682 onContextMenu : function(e){
16683 var item = this.findItemFromChild(e.getTarget());
16685 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
16690 onDblClick : function(e){
16691 var item = this.findItemFromChild(e.getTarget());
16693 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
16697 onItemClick : function(item, index, e)
16699 if(this.fireEvent("beforeclick", this, index, item, e) === false){
16702 if (this.toggleSelect) {
16703 var m = this.isSelected(item) ? 'unselect' : 'select';
16706 _t[m](item, true, false);
16709 if(this.multiSelect || this.singleSelect){
16710 if(this.multiSelect && e.shiftKey && this.lastSelection){
16711 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
16713 this.select(item, this.multiSelect && e.ctrlKey);
16714 this.lastSelection = item;
16717 if(!this.tickable){
16718 e.preventDefault();
16726 * Get the number of selected nodes.
16729 getSelectionCount : function(){
16730 return this.selections.length;
16734 * Get the currently selected nodes.
16735 * @return {Array} An array of HTMLElements
16737 getSelectedNodes : function(){
16738 return this.selections;
16742 * Get the indexes of the selected nodes.
16745 getSelectedIndexes : function(){
16746 var indexes = [], s = this.selections;
16747 for(var i = 0, len = s.length; i < len; i++){
16748 indexes.push(s[i].nodeIndex);
16754 * Clear all selections
16755 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
16757 clearSelections : function(suppressEvent){
16758 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
16759 this.cmp.elements = this.selections;
16760 this.cmp.removeClass(this.selectedClass);
16761 this.selections = [];
16762 if(!suppressEvent){
16763 this.fireEvent("selectionchange", this, this.selections);
16769 * Returns true if the passed node is selected
16770 * @param {HTMLElement/Number} node The node or node index
16771 * @return {Boolean}
16773 isSelected : function(node){
16774 var s = this.selections;
16778 node = this.getNode(node);
16779 return s.indexOf(node) !== -1;
16784 * @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
16785 * @param {Boolean} keepExisting (optional) true to keep existing selections
16786 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16788 select : function(nodeInfo, keepExisting, suppressEvent){
16789 if(nodeInfo instanceof Array){
16791 this.clearSelections(true);
16793 for(var i = 0, len = nodeInfo.length; i < len; i++){
16794 this.select(nodeInfo[i], true, true);
16798 var node = this.getNode(nodeInfo);
16799 if(!node || this.isSelected(node)){
16800 return; // already selected.
16803 this.clearSelections(true);
16806 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
16807 Roo.fly(node).addClass(this.selectedClass);
16808 this.selections.push(node);
16809 if(!suppressEvent){
16810 this.fireEvent("selectionchange", this, this.selections);
16818 * @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
16819 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
16820 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16822 unselect : function(nodeInfo, keepExisting, suppressEvent)
16824 if(nodeInfo instanceof Array){
16825 Roo.each(this.selections, function(s) {
16826 this.unselect(s, nodeInfo);
16830 var node = this.getNode(nodeInfo);
16831 if(!node || !this.isSelected(node)){
16832 //Roo.log("not selected");
16833 return; // not selected.
16837 Roo.each(this.selections, function(s) {
16839 Roo.fly(node).removeClass(this.selectedClass);
16846 this.selections= ns;
16847 this.fireEvent("selectionchange", this, this.selections);
16851 * Gets a template node.
16852 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16853 * @return {HTMLElement} The node or null if it wasn't found
16855 getNode : function(nodeInfo){
16856 if(typeof nodeInfo == "string"){
16857 return document.getElementById(nodeInfo);
16858 }else if(typeof nodeInfo == "number"){
16859 return this.nodes[nodeInfo];
16865 * Gets a range template nodes.
16866 * @param {Number} startIndex
16867 * @param {Number} endIndex
16868 * @return {Array} An array of nodes
16870 getNodes : function(start, end){
16871 var ns = this.nodes;
16872 start = start || 0;
16873 end = typeof end == "undefined" ? ns.length - 1 : end;
16876 for(var i = start; i <= end; i++){
16880 for(var i = start; i >= end; i--){
16888 * Finds the index of the passed node
16889 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16890 * @return {Number} The index of the node or -1
16892 indexOf : function(node){
16893 node = this.getNode(node);
16894 if(typeof node.nodeIndex == "number"){
16895 return node.nodeIndex;
16897 var ns = this.nodes;
16898 for(var i = 0, len = ns.length; i < len; i++){
16909 * based on jquery fullcalendar
16913 Roo.bootstrap = Roo.bootstrap || {};
16915 * @class Roo.bootstrap.Calendar
16916 * @extends Roo.bootstrap.Component
16917 * Bootstrap Calendar class
16918 * @cfg {Boolean} loadMask (true|false) default false
16919 * @cfg {Object} header generate the user specific header of the calendar, default false
16922 * Create a new Container
16923 * @param {Object} config The config object
16928 Roo.bootstrap.Calendar = function(config){
16929 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
16933 * Fires when a date is selected
16934 * @param {DatePicker} this
16935 * @param {Date} date The selected date
16939 * @event monthchange
16940 * Fires when the displayed month changes
16941 * @param {DatePicker} this
16942 * @param {Date} date The selected month
16944 'monthchange': true,
16946 * @event evententer
16947 * Fires when mouse over an event
16948 * @param {Calendar} this
16949 * @param {event} Event
16951 'evententer': true,
16953 * @event eventleave
16954 * Fires when the mouse leaves an
16955 * @param {Calendar} this
16958 'eventleave': true,
16960 * @event eventclick
16961 * Fires when the mouse click an
16962 * @param {Calendar} this
16971 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
16974 * @cfg {Number} startDay
16975 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16983 getAutoCreate : function(){
16986 var fc_button = function(name, corner, style, content ) {
16987 return Roo.apply({},{
16989 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
16991 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
16994 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
17005 style : 'width:100%',
17012 cls : 'fc-header-left',
17014 fc_button('prev', 'left', 'arrow', '‹' ),
17015 fc_button('next', 'right', 'arrow', '›' ),
17016 { tag: 'span', cls: 'fc-header-space' },
17017 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
17025 cls : 'fc-header-center',
17029 cls: 'fc-header-title',
17032 html : 'month / year'
17040 cls : 'fc-header-right',
17042 /* fc_button('month', 'left', '', 'month' ),
17043 fc_button('week', '', '', 'week' ),
17044 fc_button('day', 'right', '', 'day' )
17056 header = this.header;
17059 var cal_heads = function() {
17061 // fixme - handle this.
17063 for (var i =0; i < Date.dayNames.length; i++) {
17064 var d = Date.dayNames[i];
17067 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
17068 html : d.substring(0,3)
17072 ret[0].cls += ' fc-first';
17073 ret[6].cls += ' fc-last';
17076 var cal_cell = function(n) {
17079 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
17084 cls: 'fc-day-number',
17088 cls: 'fc-day-content',
17092 style: 'position: relative;' // height: 17px;
17104 var cal_rows = function() {
17107 for (var r = 0; r < 6; r++) {
17114 for (var i =0; i < Date.dayNames.length; i++) {
17115 var d = Date.dayNames[i];
17116 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
17119 row.cn[0].cls+=' fc-first';
17120 row.cn[0].cn[0].style = 'min-height:90px';
17121 row.cn[6].cls+=' fc-last';
17125 ret[0].cls += ' fc-first';
17126 ret[4].cls += ' fc-prev-last';
17127 ret[5].cls += ' fc-last';
17134 cls: 'fc-border-separate',
17135 style : 'width:100%',
17143 cls : 'fc-first fc-last',
17161 cls : 'fc-content',
17162 style : "position: relative;",
17165 cls : 'fc-view fc-view-month fc-grid',
17166 style : 'position: relative',
17167 unselectable : 'on',
17170 cls : 'fc-event-container',
17171 style : 'position:absolute;z-index:8;top:0;left:0;'
17189 initEvents : function()
17192 throw "can not find store for calendar";
17198 style: "text-align:center",
17202 style: "background-color:white;width:50%;margin:250 auto",
17206 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
17217 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
17219 var size = this.el.select('.fc-content', true).first().getSize();
17220 this.maskEl.setSize(size.width, size.height);
17221 this.maskEl.enableDisplayMode("block");
17222 if(!this.loadMask){
17223 this.maskEl.hide();
17226 this.store = Roo.factory(this.store, Roo.data);
17227 this.store.on('load', this.onLoad, this);
17228 this.store.on('beforeload', this.onBeforeLoad, this);
17232 this.cells = this.el.select('.fc-day',true);
17233 //Roo.log(this.cells);
17234 this.textNodes = this.el.query('.fc-day-number');
17235 this.cells.addClassOnOver('fc-state-hover');
17237 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
17238 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
17239 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
17240 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
17242 this.on('monthchange', this.onMonthChange, this);
17244 this.update(new Date().clearTime());
17247 resize : function() {
17248 var sz = this.el.getSize();
17250 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
17251 this.el.select('.fc-day-content div',true).setHeight(34);
17256 showPrevMonth : function(e){
17257 this.update(this.activeDate.add("mo", -1));
17259 showToday : function(e){
17260 this.update(new Date().clearTime());
17263 showNextMonth : function(e){
17264 this.update(this.activeDate.add("mo", 1));
17268 showPrevYear : function(){
17269 this.update(this.activeDate.add("y", -1));
17273 showNextYear : function(){
17274 this.update(this.activeDate.add("y", 1));
17279 update : function(date)
17281 var vd = this.activeDate;
17282 this.activeDate = date;
17283 // if(vd && this.el){
17284 // var t = date.getTime();
17285 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
17286 // Roo.log('using add remove');
17288 // this.fireEvent('monthchange', this, date);
17290 // this.cells.removeClass("fc-state-highlight");
17291 // this.cells.each(function(c){
17292 // if(c.dateValue == t){
17293 // c.addClass("fc-state-highlight");
17294 // setTimeout(function(){
17295 // try{c.dom.firstChild.focus();}catch(e){}
17305 var days = date.getDaysInMonth();
17307 var firstOfMonth = date.getFirstDateOfMonth();
17308 var startingPos = firstOfMonth.getDay()-this.startDay;
17310 if(startingPos < this.startDay){
17314 var pm = date.add(Date.MONTH, -1);
17315 var prevStart = pm.getDaysInMonth()-startingPos;
17317 this.cells = this.el.select('.fc-day',true);
17318 this.textNodes = this.el.query('.fc-day-number');
17319 this.cells.addClassOnOver('fc-state-hover');
17321 var cells = this.cells.elements;
17322 var textEls = this.textNodes;
17324 Roo.each(cells, function(cell){
17325 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
17328 days += startingPos;
17330 // convert everything to numbers so it's fast
17331 var day = 86400000;
17332 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
17335 //Roo.log(prevStart);
17337 var today = new Date().clearTime().getTime();
17338 var sel = date.clearTime().getTime();
17339 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
17340 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
17341 var ddMatch = this.disabledDatesRE;
17342 var ddText = this.disabledDatesText;
17343 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
17344 var ddaysText = this.disabledDaysText;
17345 var format = this.format;
17347 var setCellClass = function(cal, cell){
17351 //Roo.log('set Cell Class');
17353 var t = d.getTime();
17357 cell.dateValue = t;
17359 cell.className += " fc-today";
17360 cell.className += " fc-state-highlight";
17361 cell.title = cal.todayText;
17364 // disable highlight in other month..
17365 //cell.className += " fc-state-highlight";
17370 cell.className = " fc-state-disabled";
17371 cell.title = cal.minText;
17375 cell.className = " fc-state-disabled";
17376 cell.title = cal.maxText;
17380 if(ddays.indexOf(d.getDay()) != -1){
17381 cell.title = ddaysText;
17382 cell.className = " fc-state-disabled";
17385 if(ddMatch && format){
17386 var fvalue = d.dateFormat(format);
17387 if(ddMatch.test(fvalue)){
17388 cell.title = ddText.replace("%0", fvalue);
17389 cell.className = " fc-state-disabled";
17393 if (!cell.initialClassName) {
17394 cell.initialClassName = cell.dom.className;
17397 cell.dom.className = cell.initialClassName + ' ' + cell.className;
17402 for(; i < startingPos; i++) {
17403 textEls[i].innerHTML = (++prevStart);
17404 d.setDate(d.getDate()+1);
17406 cells[i].className = "fc-past fc-other-month";
17407 setCellClass(this, cells[i]);
17412 for(; i < days; i++){
17413 intDay = i - startingPos + 1;
17414 textEls[i].innerHTML = (intDay);
17415 d.setDate(d.getDate()+1);
17417 cells[i].className = ''; // "x-date-active";
17418 setCellClass(this, cells[i]);
17422 for(; i < 42; i++) {
17423 textEls[i].innerHTML = (++extraDays);
17424 d.setDate(d.getDate()+1);
17426 cells[i].className = "fc-future fc-other-month";
17427 setCellClass(this, cells[i]);
17430 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
17432 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
17434 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
17435 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
17437 if(totalRows != 6){
17438 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
17439 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
17442 this.fireEvent('monthchange', this, date);
17446 if(!this.internalRender){
17447 var main = this.el.dom.firstChild;
17448 var w = main.offsetWidth;
17449 this.el.setWidth(w + this.el.getBorderWidth("lr"));
17450 Roo.fly(main).setWidth(w);
17451 this.internalRender = true;
17452 // opera does not respect the auto grow header center column
17453 // then, after it gets a width opera refuses to recalculate
17454 // without a second pass
17455 if(Roo.isOpera && !this.secondPass){
17456 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
17457 this.secondPass = true;
17458 this.update.defer(10, this, [date]);
17465 findCell : function(dt) {
17466 dt = dt.clearTime().getTime();
17468 this.cells.each(function(c){
17469 //Roo.log("check " +c.dateValue + '?=' + dt);
17470 if(c.dateValue == dt){
17480 findCells : function(ev) {
17481 var s = ev.start.clone().clearTime().getTime();
17483 var e= ev.end.clone().clearTime().getTime();
17486 this.cells.each(function(c){
17487 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
17489 if(c.dateValue > e){
17492 if(c.dateValue < s){
17501 // findBestRow: function(cells)
17505 // for (var i =0 ; i < cells.length;i++) {
17506 // ret = Math.max(cells[i].rows || 0,ret);
17513 addItem : function(ev)
17515 // look for vertical location slot in
17516 var cells = this.findCells(ev);
17518 // ev.row = this.findBestRow(cells);
17520 // work out the location.
17524 for(var i =0; i < cells.length; i++) {
17526 cells[i].row = cells[0].row;
17529 cells[i].row = cells[i].row + 1;
17539 if (crow.start.getY() == cells[i].getY()) {
17541 crow.end = cells[i];
17558 cells[0].events.push(ev);
17560 this.calevents.push(ev);
17563 clearEvents: function() {
17565 if(!this.calevents){
17569 Roo.each(this.cells.elements, function(c){
17575 Roo.each(this.calevents, function(e) {
17576 Roo.each(e.els, function(el) {
17577 el.un('mouseenter' ,this.onEventEnter, this);
17578 el.un('mouseleave' ,this.onEventLeave, this);
17583 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
17589 renderEvents: function()
17593 this.cells.each(function(c) {
17602 if(c.row != c.events.length){
17603 r = 4 - (4 - (c.row - c.events.length));
17606 c.events = ev.slice(0, r);
17607 c.more = ev.slice(r);
17609 if(c.more.length && c.more.length == 1){
17610 c.events.push(c.more.pop());
17613 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
17617 this.cells.each(function(c) {
17619 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
17622 for (var e = 0; e < c.events.length; e++){
17623 var ev = c.events[e];
17624 var rows = ev.rows;
17626 for(var i = 0; i < rows.length; i++) {
17628 // how many rows should it span..
17631 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
17632 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
17634 unselectable : "on",
17637 cls: 'fc-event-inner',
17641 // cls: 'fc-event-time',
17642 // html : cells.length > 1 ? '' : ev.time
17646 cls: 'fc-event-title',
17647 html : String.format('{0}', ev.title)
17654 cls: 'ui-resizable-handle ui-resizable-e',
17655 html : '  '
17662 cfg.cls += ' fc-event-start';
17664 if ((i+1) == rows.length) {
17665 cfg.cls += ' fc-event-end';
17668 var ctr = _this.el.select('.fc-event-container',true).first();
17669 var cg = ctr.createChild(cfg);
17671 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
17672 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
17674 var r = (c.more.length) ? 1 : 0;
17675 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
17676 cg.setWidth(ebox.right - sbox.x -2);
17678 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
17679 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
17680 cg.on('click', _this.onEventClick, _this, ev);
17691 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
17692 style : 'position: absolute',
17693 unselectable : "on",
17696 cls: 'fc-event-inner',
17700 cls: 'fc-event-title',
17708 cls: 'ui-resizable-handle ui-resizable-e',
17709 html : '  '
17715 var ctr = _this.el.select('.fc-event-container',true).first();
17716 var cg = ctr.createChild(cfg);
17718 var sbox = c.select('.fc-day-content',true).first().getBox();
17719 var ebox = c.select('.fc-day-content',true).first().getBox();
17721 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
17722 cg.setWidth(ebox.right - sbox.x -2);
17724 cg.on('click', _this.onMoreEventClick, _this, c.more);
17734 onEventEnter: function (e, el,event,d) {
17735 this.fireEvent('evententer', this, el, event);
17738 onEventLeave: function (e, el,event,d) {
17739 this.fireEvent('eventleave', this, el, event);
17742 onEventClick: function (e, el,event,d) {
17743 this.fireEvent('eventclick', this, el, event);
17746 onMonthChange: function () {
17750 onMoreEventClick: function(e, el, more)
17754 this.calpopover.placement = 'right';
17755 this.calpopover.setTitle('More');
17757 this.calpopover.setContent('');
17759 var ctr = this.calpopover.el.select('.popover-content', true).first();
17761 Roo.each(more, function(m){
17763 cls : 'fc-event-hori fc-event-draggable',
17766 var cg = ctr.createChild(cfg);
17768 cg.on('click', _this.onEventClick, _this, m);
17771 this.calpopover.show(el);
17776 onLoad: function ()
17778 this.calevents = [];
17781 if(this.store.getCount() > 0){
17782 this.store.data.each(function(d){
17785 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
17786 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
17787 time : d.data.start_time,
17788 title : d.data.title,
17789 description : d.data.description,
17790 venue : d.data.venue
17795 this.renderEvents();
17797 if(this.calevents.length && this.loadMask){
17798 this.maskEl.hide();
17802 onBeforeLoad: function()
17804 this.clearEvents();
17806 this.maskEl.show();
17820 * @class Roo.bootstrap.Popover
17821 * @extends Roo.bootstrap.Component
17822 * Bootstrap Popover class
17823 * @cfg {String} html contents of the popover (or false to use children..)
17824 * @cfg {String} title of popover (or false to hide)
17825 * @cfg {String} placement how it is placed
17826 * @cfg {String} trigger click || hover (or false to trigger manually)
17827 * @cfg {String} over what (parent or false to trigger manually.)
17828 * @cfg {Number} delay - delay before showing
17831 * Create a new Popover
17832 * @param {Object} config The config object
17835 Roo.bootstrap.Popover = function(config){
17836 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
17842 * After the popover show
17844 * @param {Roo.bootstrap.Popover} this
17849 * After the popover hide
17851 * @param {Roo.bootstrap.Popover} this
17857 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
17859 title: 'Fill in a title',
17862 placement : 'right',
17863 trigger : 'hover', // hover
17869 can_build_overlaid : false,
17871 getChildContainer : function()
17873 return this.el.select('.popover-content',true).first();
17876 getAutoCreate : function(){
17879 cls : 'popover roo-dynamic',
17880 style: 'display:block',
17886 cls : 'popover-inner',
17890 cls: 'popover-title popover-header',
17894 cls : 'popover-content popover-body',
17905 setTitle: function(str)
17908 this.el.select('.popover-title',true).first().dom.innerHTML = str;
17910 setContent: function(str)
17913 this.el.select('.popover-content',true).first().dom.innerHTML = str;
17915 // as it get's added to the bottom of the page.
17916 onRender : function(ct, position)
17918 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17920 var cfg = Roo.apply({}, this.getAutoCreate());
17924 cfg.cls += ' ' + this.cls;
17927 cfg.style = this.style;
17929 //Roo.log("adding to ");
17930 this.el = Roo.get(document.body).createChild(cfg, position);
17931 // Roo.log(this.el);
17936 initEvents : function()
17938 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
17939 this.el.enableDisplayMode('block');
17941 if (this.over === false) {
17944 if (this.triggers === false) {
17947 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17948 var triggers = this.trigger ? this.trigger.split(' ') : [];
17949 Roo.each(triggers, function(trigger) {
17951 if (trigger == 'click') {
17952 on_el.on('click', this.toggle, this);
17953 } else if (trigger != 'manual') {
17954 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
17955 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
17957 on_el.on(eventIn ,this.enter, this);
17958 on_el.on(eventOut, this.leave, this);
17969 toggle : function () {
17970 this.hoverState == 'in' ? this.leave() : this.enter();
17973 enter : function () {
17975 clearTimeout(this.timeout);
17977 this.hoverState = 'in';
17979 if (!this.delay || !this.delay.show) {
17984 this.timeout = setTimeout(function () {
17985 if (_t.hoverState == 'in') {
17988 }, this.delay.show)
17991 leave : function() {
17992 clearTimeout(this.timeout);
17994 this.hoverState = 'out';
17996 if (!this.delay || !this.delay.hide) {
18001 this.timeout = setTimeout(function () {
18002 if (_t.hoverState == 'out') {
18005 }, this.delay.hide)
18008 show : function (on_el)
18011 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
18015 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
18016 if (this.html !== false) {
18017 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
18019 this.el.removeClass([
18020 'fade','top','bottom', 'left', 'right','in',
18021 'bs-popover-top','bs-popover-bottom', 'bs-popover-left', 'bs-popover-right'
18023 if (!this.title.length) {
18024 this.el.select('.popover-title',true).hide();
18027 var placement = typeof this.placement == 'function' ?
18028 this.placement.call(this, this.el, on_el) :
18031 var autoToken = /\s?auto?\s?/i;
18032 var autoPlace = autoToken.test(placement);
18034 placement = placement.replace(autoToken, '') || 'top';
18038 //this.el.setXY([0,0]);
18040 this.el.dom.style.display='block';
18041 this.el.addClass(placement);
18043 //this.el.appendTo(on_el);
18045 var p = this.getPosition();
18046 var box = this.el.getBox();
18051 var align = Roo.bootstrap.Popover.alignment[placement];
18054 this.el.alignTo(on_el, align[0],align[1]);
18055 //var arrow = this.el.select('.arrow',true).first();
18056 //arrow.set(align[2],
18058 this.el.addClass('in');
18061 if (this.el.hasClass('fade')) {
18065 this.hoverState = 'in';
18067 this.fireEvent('show', this);
18072 this.el.setXY([0,0]);
18073 this.el.removeClass('in');
18075 this.hoverState = null;
18077 this.fireEvent('hide', this);
18082 Roo.bootstrap.Popover.alignment = {
18083 'left' : ['r-l', [-10,0], 'right bs-popover-right'],
18084 'right' : ['l-r', [10,0], 'left bs-popover-left'],
18085 'bottom' : ['t-b', [0,10], 'top bs-popover-top'],
18086 'top' : [ 'b-t', [0,-10], 'bottom bs-popover-bottom']
18097 * @class Roo.bootstrap.Progress
18098 * @extends Roo.bootstrap.Component
18099 * Bootstrap Progress class
18100 * @cfg {Boolean} striped striped of the progress bar
18101 * @cfg {Boolean} active animated of the progress bar
18105 * Create a new Progress
18106 * @param {Object} config The config object
18109 Roo.bootstrap.Progress = function(config){
18110 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
18113 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
18118 getAutoCreate : function(){
18126 cfg.cls += ' progress-striped';
18130 cfg.cls += ' active';
18149 * @class Roo.bootstrap.ProgressBar
18150 * @extends Roo.bootstrap.Component
18151 * Bootstrap ProgressBar class
18152 * @cfg {Number} aria_valuenow aria-value now
18153 * @cfg {Number} aria_valuemin aria-value min
18154 * @cfg {Number} aria_valuemax aria-value max
18155 * @cfg {String} label label for the progress bar
18156 * @cfg {String} panel (success | info | warning | danger )
18157 * @cfg {String} role role of the progress bar
18158 * @cfg {String} sr_only text
18162 * Create a new ProgressBar
18163 * @param {Object} config The config object
18166 Roo.bootstrap.ProgressBar = function(config){
18167 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
18170 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
18174 aria_valuemax : 100,
18180 getAutoCreate : function()
18185 cls: 'progress-bar',
18186 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
18198 cfg.role = this.role;
18201 if(this.aria_valuenow){
18202 cfg['aria-valuenow'] = this.aria_valuenow;
18205 if(this.aria_valuemin){
18206 cfg['aria-valuemin'] = this.aria_valuemin;
18209 if(this.aria_valuemax){
18210 cfg['aria-valuemax'] = this.aria_valuemax;
18213 if(this.label && !this.sr_only){
18214 cfg.html = this.label;
18218 cfg.cls += ' progress-bar-' + this.panel;
18224 update : function(aria_valuenow)
18226 this.aria_valuenow = aria_valuenow;
18228 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
18243 * @class Roo.bootstrap.TabGroup
18244 * @extends Roo.bootstrap.Column
18245 * Bootstrap Column class
18246 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
18247 * @cfg {Boolean} carousel true to make the group behave like a carousel
18248 * @cfg {Boolean} bullets show bullets for the panels
18249 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
18250 * @cfg {Number} timer auto slide timer .. default 0 millisecond
18251 * @cfg {Boolean} showarrow (true|false) show arrow default true
18254 * Create a new TabGroup
18255 * @param {Object} config The config object
18258 Roo.bootstrap.TabGroup = function(config){
18259 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
18261 this.navId = Roo.id();
18264 Roo.bootstrap.TabGroup.register(this);
18268 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
18271 transition : false,
18276 slideOnTouch : false,
18279 getAutoCreate : function()
18281 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
18283 cfg.cls += ' tab-content';
18285 if (this.carousel) {
18286 cfg.cls += ' carousel slide';
18289 cls : 'carousel-inner',
18293 if(this.bullets && !Roo.isTouch){
18296 cls : 'carousel-bullets',
18300 if(this.bullets_cls){
18301 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
18308 cfg.cn[0].cn.push(bullets);
18311 if(this.showarrow){
18312 cfg.cn[0].cn.push({
18314 class : 'carousel-arrow',
18318 class : 'carousel-prev',
18322 class : 'fa fa-chevron-left'
18328 class : 'carousel-next',
18332 class : 'fa fa-chevron-right'
18345 initEvents: function()
18347 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
18348 // this.el.on("touchstart", this.onTouchStart, this);
18351 if(this.autoslide){
18354 this.slideFn = window.setInterval(function() {
18355 _this.showPanelNext();
18359 if(this.showarrow){
18360 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
18361 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
18367 // onTouchStart : function(e, el, o)
18369 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
18373 // this.showPanelNext();
18377 getChildContainer : function()
18379 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
18383 * register a Navigation item
18384 * @param {Roo.bootstrap.NavItem} the navitem to add
18386 register : function(item)
18388 this.tabs.push( item);
18389 item.navId = this.navId; // not really needed..
18394 getActivePanel : function()
18397 Roo.each(this.tabs, function(t) {
18407 getPanelByName : function(n)
18410 Roo.each(this.tabs, function(t) {
18411 if (t.tabId == n) {
18419 indexOfPanel : function(p)
18422 Roo.each(this.tabs, function(t,i) {
18423 if (t.tabId == p.tabId) {
18432 * show a specific panel
18433 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
18434 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
18436 showPanel : function (pan)
18438 if(this.transition || typeof(pan) == 'undefined'){
18439 Roo.log("waiting for the transitionend");
18443 if (typeof(pan) == 'number') {
18444 pan = this.tabs[pan];
18447 if (typeof(pan) == 'string') {
18448 pan = this.getPanelByName(pan);
18451 var cur = this.getActivePanel();
18454 Roo.log('pan or acitve pan is undefined');
18458 if (pan.tabId == this.getActivePanel().tabId) {
18462 if (false === cur.fireEvent('beforedeactivate')) {
18466 if(this.bullets > 0 && !Roo.isTouch){
18467 this.setActiveBullet(this.indexOfPanel(pan));
18470 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
18472 //class="carousel-item carousel-item-next carousel-item-left"
18474 this.transition = true;
18475 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
18476 var lr = dir == 'next' ? 'left' : 'right';
18477 pan.el.addClass(dir); // or prev
18478 pan.el.addClass('carousel-item-' + dir); // or prev
18479 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
18480 cur.el.addClass(lr); // or right
18481 pan.el.addClass(lr);
18482 cur.el.addClass('carousel-item-' +lr); // or right
18483 pan.el.addClass('carousel-item-' +lr);
18487 cur.el.on('transitionend', function() {
18488 Roo.log("trans end?");
18490 pan.el.removeClass([lr,dir, 'carousel-item-' + lr, 'carousel-item-' + dir]);
18491 pan.setActive(true);
18493 cur.el.removeClass([lr, 'carousel-item-' + lr]);
18494 cur.setActive(false);
18496 _this.transition = false;
18498 }, this, { single: true } );
18503 cur.setActive(false);
18504 pan.setActive(true);
18509 showPanelNext : function()
18511 var i = this.indexOfPanel(this.getActivePanel());
18513 if (i >= this.tabs.length - 1 && !this.autoslide) {
18517 if (i >= this.tabs.length - 1 && this.autoslide) {
18521 this.showPanel(this.tabs[i+1]);
18524 showPanelPrev : function()
18526 var i = this.indexOfPanel(this.getActivePanel());
18528 if (i < 1 && !this.autoslide) {
18532 if (i < 1 && this.autoslide) {
18533 i = this.tabs.length;
18536 this.showPanel(this.tabs[i-1]);
18540 addBullet: function()
18542 if(!this.bullets || Roo.isTouch){
18545 var ctr = this.el.select('.carousel-bullets',true).first();
18546 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
18547 var bullet = ctr.createChild({
18548 cls : 'bullet bullet-' + i
18549 },ctr.dom.lastChild);
18554 bullet.on('click', (function(e, el, o, ii, t){
18556 e.preventDefault();
18558 this.showPanel(ii);
18560 if(this.autoslide && this.slideFn){
18561 clearInterval(this.slideFn);
18562 this.slideFn = window.setInterval(function() {
18563 _this.showPanelNext();
18567 }).createDelegate(this, [i, bullet], true));
18572 setActiveBullet : function(i)
18578 Roo.each(this.el.select('.bullet', true).elements, function(el){
18579 el.removeClass('selected');
18582 var bullet = this.el.select('.bullet-' + i, true).first();
18588 bullet.addClass('selected');
18599 Roo.apply(Roo.bootstrap.TabGroup, {
18603 * register a Navigation Group
18604 * @param {Roo.bootstrap.NavGroup} the navgroup to add
18606 register : function(navgrp)
18608 this.groups[navgrp.navId] = navgrp;
18612 * fetch a Navigation Group based on the navigation ID
18613 * if one does not exist , it will get created.
18614 * @param {string} the navgroup to add
18615 * @returns {Roo.bootstrap.NavGroup} the navgroup
18617 get: function(navId) {
18618 if (typeof(this.groups[navId]) == 'undefined') {
18619 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
18621 return this.groups[navId] ;
18636 * @class Roo.bootstrap.TabPanel
18637 * @extends Roo.bootstrap.Component
18638 * Bootstrap TabPanel class
18639 * @cfg {Boolean} active panel active
18640 * @cfg {String} html panel content
18641 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
18642 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
18643 * @cfg {String} href click to link..
18647 * Create a new TabPanel
18648 * @param {Object} config The config object
18651 Roo.bootstrap.TabPanel = function(config){
18652 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
18656 * Fires when the active status changes
18657 * @param {Roo.bootstrap.TabPanel} this
18658 * @param {Boolean} state the new state
18663 * @event beforedeactivate
18664 * Fires before a tab is de-activated - can be used to do validation on a form.
18665 * @param {Roo.bootstrap.TabPanel} this
18666 * @return {Boolean} false if there is an error
18669 'beforedeactivate': true
18672 this.tabId = this.tabId || Roo.id();
18676 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
18684 getAutoCreate : function(){
18689 // item is needed for carousel - not sure if it has any effect otherwise
18690 cls: 'carousel-item tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
18691 html: this.html || ''
18695 cfg.cls += ' active';
18699 cfg.tabId = this.tabId;
18707 initEvents: function()
18709 var p = this.parent();
18711 this.navId = this.navId || p.navId;
18713 if (typeof(this.navId) != 'undefined') {
18714 // not really needed.. but just in case.. parent should be a NavGroup.
18715 var tg = Roo.bootstrap.TabGroup.get(this.navId);
18719 var i = tg.tabs.length - 1;
18721 if(this.active && tg.bullets > 0 && i < tg.bullets){
18722 tg.setActiveBullet(i);
18726 this.el.on('click', this.onClick, this);
18729 this.el.on("touchstart", this.onTouchStart, this);
18730 this.el.on("touchmove", this.onTouchMove, this);
18731 this.el.on("touchend", this.onTouchEnd, this);
18736 onRender : function(ct, position)
18738 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
18741 setActive : function(state)
18743 Roo.log("panel - set active " + this.tabId + "=" + state);
18745 this.active = state;
18747 this.el.removeClass('active');
18749 } else if (!this.el.hasClass('active')) {
18750 this.el.addClass('active');
18753 this.fireEvent('changed', this, state);
18756 onClick : function(e)
18758 e.preventDefault();
18760 if(!this.href.length){
18764 window.location.href = this.href;
18773 onTouchStart : function(e)
18775 this.swiping = false;
18777 this.startX = e.browserEvent.touches[0].clientX;
18778 this.startY = e.browserEvent.touches[0].clientY;
18781 onTouchMove : function(e)
18783 this.swiping = true;
18785 this.endX = e.browserEvent.touches[0].clientX;
18786 this.endY = e.browserEvent.touches[0].clientY;
18789 onTouchEnd : function(e)
18796 var tabGroup = this.parent();
18798 if(this.endX > this.startX){ // swiping right
18799 tabGroup.showPanelPrev();
18803 if(this.startX > this.endX){ // swiping left
18804 tabGroup.showPanelNext();
18823 * @class Roo.bootstrap.DateField
18824 * @extends Roo.bootstrap.Input
18825 * Bootstrap DateField class
18826 * @cfg {Number} weekStart default 0
18827 * @cfg {String} viewMode default empty, (months|years)
18828 * @cfg {String} minViewMode default empty, (months|years)
18829 * @cfg {Number} startDate default -Infinity
18830 * @cfg {Number} endDate default Infinity
18831 * @cfg {Boolean} todayHighlight default false
18832 * @cfg {Boolean} todayBtn default false
18833 * @cfg {Boolean} calendarWeeks default false
18834 * @cfg {Object} daysOfWeekDisabled default empty
18835 * @cfg {Boolean} singleMode default false (true | false)
18837 * @cfg {Boolean} keyboardNavigation default true
18838 * @cfg {String} language default en
18841 * Create a new DateField
18842 * @param {Object} config The config object
18845 Roo.bootstrap.DateField = function(config){
18846 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
18850 * Fires when this field show.
18851 * @param {Roo.bootstrap.DateField} this
18852 * @param {Mixed} date The date value
18857 * Fires when this field hide.
18858 * @param {Roo.bootstrap.DateField} this
18859 * @param {Mixed} date The date value
18864 * Fires when select a date.
18865 * @param {Roo.bootstrap.DateField} this
18866 * @param {Mixed} date The date value
18870 * @event beforeselect
18871 * Fires when before select a date.
18872 * @param {Roo.bootstrap.DateField} this
18873 * @param {Mixed} date The date value
18875 beforeselect : true
18879 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
18882 * @cfg {String} format
18883 * The default date format string which can be overriden for localization support. The format must be
18884 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
18888 * @cfg {String} altFormats
18889 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
18890 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
18892 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
18900 todayHighlight : false,
18906 keyboardNavigation: true,
18908 calendarWeeks: false,
18910 startDate: -Infinity,
18914 daysOfWeekDisabled: [],
18918 singleMode : false,
18920 UTCDate: function()
18922 return new Date(Date.UTC.apply(Date, arguments));
18925 UTCToday: function()
18927 var today = new Date();
18928 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
18931 getDate: function() {
18932 var d = this.getUTCDate();
18933 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
18936 getUTCDate: function() {
18940 setDate: function(d) {
18941 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
18944 setUTCDate: function(d) {
18946 this.setValue(this.formatDate(this.date));
18949 onRender: function(ct, position)
18952 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
18954 this.language = this.language || 'en';
18955 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
18956 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
18958 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
18959 this.format = this.format || 'm/d/y';
18960 this.isInline = false;
18961 this.isInput = true;
18962 this.component = this.el.select('.add-on', true).first() || false;
18963 this.component = (this.component && this.component.length === 0) ? false : this.component;
18964 this.hasInput = this.component && this.inputEl().length;
18966 if (typeof(this.minViewMode === 'string')) {
18967 switch (this.minViewMode) {
18969 this.minViewMode = 1;
18972 this.minViewMode = 2;
18975 this.minViewMode = 0;
18980 if (typeof(this.viewMode === 'string')) {
18981 switch (this.viewMode) {
18994 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
18996 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
18998 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19000 this.picker().on('mousedown', this.onMousedown, this);
19001 this.picker().on('click', this.onClick, this);
19003 this.picker().addClass('datepicker-dropdown');
19005 this.startViewMode = this.viewMode;
19007 if(this.singleMode){
19008 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
19009 v.setVisibilityMode(Roo.Element.DISPLAY);
19013 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
19014 v.setStyle('width', '189px');
19018 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
19019 if(!this.calendarWeeks){
19024 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
19025 v.attr('colspan', function(i, val){
19026 return parseInt(val) + 1;
19031 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
19033 this.setStartDate(this.startDate);
19034 this.setEndDate(this.endDate);
19036 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
19043 if(this.isInline) {
19048 picker : function()
19050 return this.pickerEl;
19051 // return this.el.select('.datepicker', true).first();
19054 fillDow: function()
19056 var dowCnt = this.weekStart;
19065 if(this.calendarWeeks){
19073 while (dowCnt < this.weekStart + 7) {
19077 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
19081 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
19084 fillMonths: function()
19087 var months = this.picker().select('>.datepicker-months td', true).first();
19089 months.dom.innerHTML = '';
19095 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
19098 months.createChild(month);
19105 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;
19107 if (this.date < this.startDate) {
19108 this.viewDate = new Date(this.startDate);
19109 } else if (this.date > this.endDate) {
19110 this.viewDate = new Date(this.endDate);
19112 this.viewDate = new Date(this.date);
19120 var d = new Date(this.viewDate),
19121 year = d.getUTCFullYear(),
19122 month = d.getUTCMonth(),
19123 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
19124 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
19125 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
19126 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
19127 currentDate = this.date && this.date.valueOf(),
19128 today = this.UTCToday();
19130 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
19132 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
19134 // this.picker.select('>tfoot th.today').
19135 // .text(dates[this.language].today)
19136 // .toggle(this.todayBtn !== false);
19138 this.updateNavArrows();
19141 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
19143 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
19145 prevMonth.setUTCDate(day);
19147 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
19149 var nextMonth = new Date(prevMonth);
19151 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
19153 nextMonth = nextMonth.valueOf();
19155 var fillMonths = false;
19157 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
19159 while(prevMonth.valueOf() <= nextMonth) {
19162 if (prevMonth.getUTCDay() === this.weekStart) {
19164 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
19172 if(this.calendarWeeks){
19173 // ISO 8601: First week contains first thursday.
19174 // ISO also states week starts on Monday, but we can be more abstract here.
19176 // Start of current week: based on weekstart/current date
19177 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
19178 // Thursday of this week
19179 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
19180 // First Thursday of year, year from thursday
19181 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
19182 // Calendar week: ms between thursdays, div ms per day, div 7 days
19183 calWeek = (th - yth) / 864e5 / 7 + 1;
19185 fillMonths.cn.push({
19193 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
19195 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
19198 if (this.todayHighlight &&
19199 prevMonth.getUTCFullYear() == today.getFullYear() &&
19200 prevMonth.getUTCMonth() == today.getMonth() &&
19201 prevMonth.getUTCDate() == today.getDate()) {
19202 clsName += ' today';
19205 if (currentDate && prevMonth.valueOf() === currentDate) {
19206 clsName += ' active';
19209 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
19210 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
19211 clsName += ' disabled';
19214 fillMonths.cn.push({
19216 cls: 'day ' + clsName,
19217 html: prevMonth.getDate()
19220 prevMonth.setDate(prevMonth.getDate()+1);
19223 var currentYear = this.date && this.date.getUTCFullYear();
19224 var currentMonth = this.date && this.date.getUTCMonth();
19226 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
19228 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
19229 v.removeClass('active');
19231 if(currentYear === year && k === currentMonth){
19232 v.addClass('active');
19235 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
19236 v.addClass('disabled');
19242 year = parseInt(year/10, 10) * 10;
19244 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
19246 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
19249 for (var i = -1; i < 11; i++) {
19250 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
19252 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
19260 showMode: function(dir)
19263 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
19266 Roo.each(this.picker().select('>div',true).elements, function(v){
19267 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19270 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
19275 if(this.isInline) {
19279 this.picker().removeClass(['bottom', 'top']);
19281 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
19283 * place to the top of element!
19287 this.picker().addClass('top');
19288 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
19293 this.picker().addClass('bottom');
19295 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
19298 parseDate : function(value)
19300 if(!value || value instanceof Date){
19303 var v = Date.parseDate(value, this.format);
19304 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
19305 v = Date.parseDate(value, 'Y-m-d');
19307 if(!v && this.altFormats){
19308 if(!this.altFormatsArray){
19309 this.altFormatsArray = this.altFormats.split("|");
19311 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
19312 v = Date.parseDate(value, this.altFormatsArray[i]);
19318 formatDate : function(date, fmt)
19320 return (!date || !(date instanceof Date)) ?
19321 date : date.dateFormat(fmt || this.format);
19324 onFocus : function()
19326 Roo.bootstrap.DateField.superclass.onFocus.call(this);
19330 onBlur : function()
19332 Roo.bootstrap.DateField.superclass.onBlur.call(this);
19334 var d = this.inputEl().getValue();
19341 showPopup : function()
19343 this.picker().show();
19347 this.fireEvent('showpopup', this, this.date);
19350 hidePopup : function()
19352 if(this.isInline) {
19355 this.picker().hide();
19356 this.viewMode = this.startViewMode;
19359 this.fireEvent('hidepopup', this, this.date);
19363 onMousedown: function(e)
19365 e.stopPropagation();
19366 e.preventDefault();
19371 Roo.bootstrap.DateField.superclass.keyup.call(this);
19375 setValue: function(v)
19377 if(this.fireEvent('beforeselect', this, v) !== false){
19378 var d = new Date(this.parseDate(v) ).clearTime();
19380 if(isNaN(d.getTime())){
19381 this.date = this.viewDate = '';
19382 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
19386 v = this.formatDate(d);
19388 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
19390 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
19394 this.fireEvent('select', this, this.date);
19398 getValue: function()
19400 return this.formatDate(this.date);
19403 fireKey: function(e)
19405 if (!this.picker().isVisible()){
19406 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19412 var dateChanged = false,
19414 newDate, newViewDate;
19419 e.preventDefault();
19423 if (!this.keyboardNavigation) {
19426 dir = e.keyCode == 37 ? -1 : 1;
19429 newDate = this.moveYear(this.date, dir);
19430 newViewDate = this.moveYear(this.viewDate, dir);
19431 } else if (e.shiftKey){
19432 newDate = this.moveMonth(this.date, dir);
19433 newViewDate = this.moveMonth(this.viewDate, dir);
19435 newDate = new Date(this.date);
19436 newDate.setUTCDate(this.date.getUTCDate() + dir);
19437 newViewDate = new Date(this.viewDate);
19438 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
19440 if (this.dateWithinRange(newDate)){
19441 this.date = newDate;
19442 this.viewDate = newViewDate;
19443 this.setValue(this.formatDate(this.date));
19445 e.preventDefault();
19446 dateChanged = true;
19451 if (!this.keyboardNavigation) {
19454 dir = e.keyCode == 38 ? -1 : 1;
19456 newDate = this.moveYear(this.date, dir);
19457 newViewDate = this.moveYear(this.viewDate, dir);
19458 } else if (e.shiftKey){
19459 newDate = this.moveMonth(this.date, dir);
19460 newViewDate = this.moveMonth(this.viewDate, dir);
19462 newDate = new Date(this.date);
19463 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
19464 newViewDate = new Date(this.viewDate);
19465 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
19467 if (this.dateWithinRange(newDate)){
19468 this.date = newDate;
19469 this.viewDate = newViewDate;
19470 this.setValue(this.formatDate(this.date));
19472 e.preventDefault();
19473 dateChanged = true;
19477 this.setValue(this.formatDate(this.date));
19479 e.preventDefault();
19482 this.setValue(this.formatDate(this.date));
19496 onClick: function(e)
19498 e.stopPropagation();
19499 e.preventDefault();
19501 var target = e.getTarget();
19503 if(target.nodeName.toLowerCase() === 'i'){
19504 target = Roo.get(target).dom.parentNode;
19507 var nodeName = target.nodeName;
19508 var className = target.className;
19509 var html = target.innerHTML;
19510 //Roo.log(nodeName);
19512 switch(nodeName.toLowerCase()) {
19514 switch(className) {
19520 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
19521 switch(this.viewMode){
19523 this.viewDate = this.moveMonth(this.viewDate, dir);
19527 this.viewDate = this.moveYear(this.viewDate, dir);
19533 var date = new Date();
19534 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
19536 this.setValue(this.formatDate(this.date));
19543 if (className.indexOf('disabled') < 0) {
19544 this.viewDate.setUTCDate(1);
19545 if (className.indexOf('month') > -1) {
19546 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
19548 var year = parseInt(html, 10) || 0;
19549 this.viewDate.setUTCFullYear(year);
19553 if(this.singleMode){
19554 this.setValue(this.formatDate(this.viewDate));
19565 //Roo.log(className);
19566 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
19567 var day = parseInt(html, 10) || 1;
19568 var year = this.viewDate.getUTCFullYear(),
19569 month = this.viewDate.getUTCMonth();
19571 if (className.indexOf('old') > -1) {
19578 } else if (className.indexOf('new') > -1) {
19586 //Roo.log([year,month,day]);
19587 this.date = this.UTCDate(year, month, day,0,0,0,0);
19588 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
19590 //Roo.log(this.formatDate(this.date));
19591 this.setValue(this.formatDate(this.date));
19598 setStartDate: function(startDate)
19600 this.startDate = startDate || -Infinity;
19601 if (this.startDate !== -Infinity) {
19602 this.startDate = this.parseDate(this.startDate);
19605 this.updateNavArrows();
19608 setEndDate: function(endDate)
19610 this.endDate = endDate || Infinity;
19611 if (this.endDate !== Infinity) {
19612 this.endDate = this.parseDate(this.endDate);
19615 this.updateNavArrows();
19618 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
19620 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
19621 if (typeof(this.daysOfWeekDisabled) !== 'object') {
19622 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
19624 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
19625 return parseInt(d, 10);
19628 this.updateNavArrows();
19631 updateNavArrows: function()
19633 if(this.singleMode){
19637 var d = new Date(this.viewDate),
19638 year = d.getUTCFullYear(),
19639 month = d.getUTCMonth();
19641 Roo.each(this.picker().select('.prev', true).elements, function(v){
19643 switch (this.viewMode) {
19646 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
19652 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
19659 Roo.each(this.picker().select('.next', true).elements, function(v){
19661 switch (this.viewMode) {
19664 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
19670 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
19678 moveMonth: function(date, dir)
19683 var new_date = new Date(date.valueOf()),
19684 day = new_date.getUTCDate(),
19685 month = new_date.getUTCMonth(),
19686 mag = Math.abs(dir),
19688 dir = dir > 0 ? 1 : -1;
19691 // If going back one month, make sure month is not current month
19692 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
19694 return new_date.getUTCMonth() == month;
19696 // If going forward one month, make sure month is as expected
19697 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
19699 return new_date.getUTCMonth() != new_month;
19701 new_month = month + dir;
19702 new_date.setUTCMonth(new_month);
19703 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
19704 if (new_month < 0 || new_month > 11) {
19705 new_month = (new_month + 12) % 12;
19708 // For magnitudes >1, move one month at a time...
19709 for (var i=0; i<mag; i++) {
19710 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
19711 new_date = this.moveMonth(new_date, dir);
19713 // ...then reset the day, keeping it in the new month
19714 new_month = new_date.getUTCMonth();
19715 new_date.setUTCDate(day);
19717 return new_month != new_date.getUTCMonth();
19720 // Common date-resetting loop -- if date is beyond end of month, make it
19723 new_date.setUTCDate(--day);
19724 new_date.setUTCMonth(new_month);
19729 moveYear: function(date, dir)
19731 return this.moveMonth(date, dir*12);
19734 dateWithinRange: function(date)
19736 return date >= this.startDate && date <= this.endDate;
19742 this.picker().remove();
19745 validateValue : function(value)
19747 if(this.getVisibilityEl().hasClass('hidden')){
19751 if(value.length < 1) {
19752 if(this.allowBlank){
19758 if(value.length < this.minLength){
19761 if(value.length > this.maxLength){
19765 var vt = Roo.form.VTypes;
19766 if(!vt[this.vtype](value, this)){
19770 if(typeof this.validator == "function"){
19771 var msg = this.validator(value);
19777 if(this.regex && !this.regex.test(value)){
19781 if(typeof(this.parseDate(value)) == 'undefined'){
19785 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
19789 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
19799 this.date = this.viewDate = '';
19801 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
19806 Roo.apply(Roo.bootstrap.DateField, {
19817 html: '<i class="fa fa-arrow-left"/>'
19827 html: '<i class="fa fa-arrow-right"/>'
19869 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
19870 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
19871 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
19872 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19873 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
19886 navFnc: 'FullYear',
19891 navFnc: 'FullYear',
19896 Roo.apply(Roo.bootstrap.DateField, {
19900 cls: 'datepicker dropdown-menu roo-dynamic',
19904 cls: 'datepicker-days',
19908 cls: 'table-condensed',
19910 Roo.bootstrap.DateField.head,
19914 Roo.bootstrap.DateField.footer
19921 cls: 'datepicker-months',
19925 cls: 'table-condensed',
19927 Roo.bootstrap.DateField.head,
19928 Roo.bootstrap.DateField.content,
19929 Roo.bootstrap.DateField.footer
19936 cls: 'datepicker-years',
19940 cls: 'table-condensed',
19942 Roo.bootstrap.DateField.head,
19943 Roo.bootstrap.DateField.content,
19944 Roo.bootstrap.DateField.footer
19963 * @class Roo.bootstrap.TimeField
19964 * @extends Roo.bootstrap.Input
19965 * Bootstrap DateField class
19969 * Create a new TimeField
19970 * @param {Object} config The config object
19973 Roo.bootstrap.TimeField = function(config){
19974 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
19978 * Fires when this field show.
19979 * @param {Roo.bootstrap.DateField} thisthis
19980 * @param {Mixed} date The date value
19985 * Fires when this field hide.
19986 * @param {Roo.bootstrap.DateField} this
19987 * @param {Mixed} date The date value
19992 * Fires when select a date.
19993 * @param {Roo.bootstrap.DateField} this
19994 * @param {Mixed} date The date value
20000 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
20003 * @cfg {String} format
20004 * The default time format string which can be overriden for localization support. The format must be
20005 * valid according to {@link Date#parseDate} (defaults to 'H:i').
20009 onRender: function(ct, position)
20012 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
20014 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
20016 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
20018 this.pop = this.picker().select('>.datepicker-time',true).first();
20019 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
20021 this.picker().on('mousedown', this.onMousedown, this);
20022 this.picker().on('click', this.onClick, this);
20024 this.picker().addClass('datepicker-dropdown');
20029 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
20030 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
20031 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
20032 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
20033 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
20034 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
20038 fireKey: function(e){
20039 if (!this.picker().isVisible()){
20040 if (e.keyCode == 27) { // allow escape to hide and re-show picker
20046 e.preventDefault();
20054 this.onTogglePeriod();
20057 this.onIncrementMinutes();
20060 this.onDecrementMinutes();
20069 onClick: function(e) {
20070 e.stopPropagation();
20071 e.preventDefault();
20074 picker : function()
20076 return this.el.select('.datepicker', true).first();
20079 fillTime: function()
20081 var time = this.pop.select('tbody', true).first();
20083 time.dom.innerHTML = '';
20098 cls: 'hours-up glyphicon glyphicon-chevron-up'
20118 cls: 'minutes-up glyphicon glyphicon-chevron-up'
20139 cls: 'timepicker-hour',
20154 cls: 'timepicker-minute',
20169 cls: 'btn btn-primary period',
20191 cls: 'hours-down glyphicon glyphicon-chevron-down'
20211 cls: 'minutes-down glyphicon glyphicon-chevron-down'
20229 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
20236 var hours = this.time.getHours();
20237 var minutes = this.time.getMinutes();
20250 hours = hours - 12;
20254 hours = '0' + hours;
20258 minutes = '0' + minutes;
20261 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
20262 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
20263 this.pop.select('button', true).first().dom.innerHTML = period;
20269 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
20271 var cls = ['bottom'];
20273 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
20280 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
20285 this.picker().addClass(cls.join('-'));
20289 Roo.each(cls, function(c){
20291 _this.picker().setTop(_this.inputEl().getHeight());
20295 _this.picker().setTop(0 - _this.picker().getHeight());
20300 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
20304 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
20311 onFocus : function()
20313 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
20317 onBlur : function()
20319 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
20325 this.picker().show();
20330 this.fireEvent('show', this, this.date);
20335 this.picker().hide();
20338 this.fireEvent('hide', this, this.date);
20341 setTime : function()
20344 this.setValue(this.time.format(this.format));
20346 this.fireEvent('select', this, this.date);
20351 onMousedown: function(e){
20352 e.stopPropagation();
20353 e.preventDefault();
20356 onIncrementHours: function()
20358 Roo.log('onIncrementHours');
20359 this.time = this.time.add(Date.HOUR, 1);
20364 onDecrementHours: function()
20366 Roo.log('onDecrementHours');
20367 this.time = this.time.add(Date.HOUR, -1);
20371 onIncrementMinutes: function()
20373 Roo.log('onIncrementMinutes');
20374 this.time = this.time.add(Date.MINUTE, 1);
20378 onDecrementMinutes: function()
20380 Roo.log('onDecrementMinutes');
20381 this.time = this.time.add(Date.MINUTE, -1);
20385 onTogglePeriod: function()
20387 Roo.log('onTogglePeriod');
20388 this.time = this.time.add(Date.HOUR, 12);
20395 Roo.apply(Roo.bootstrap.TimeField, {
20425 cls: 'btn btn-info ok',
20437 Roo.apply(Roo.bootstrap.TimeField, {
20441 cls: 'datepicker dropdown-menu',
20445 cls: 'datepicker-time',
20449 cls: 'table-condensed',
20451 Roo.bootstrap.TimeField.content,
20452 Roo.bootstrap.TimeField.footer
20471 * @class Roo.bootstrap.MonthField
20472 * @extends Roo.bootstrap.Input
20473 * Bootstrap MonthField class
20475 * @cfg {String} language default en
20478 * Create a new MonthField
20479 * @param {Object} config The config object
20482 Roo.bootstrap.MonthField = function(config){
20483 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
20488 * Fires when this field show.
20489 * @param {Roo.bootstrap.MonthField} this
20490 * @param {Mixed} date The date value
20495 * Fires when this field hide.
20496 * @param {Roo.bootstrap.MonthField} this
20497 * @param {Mixed} date The date value
20502 * Fires when select a date.
20503 * @param {Roo.bootstrap.MonthField} this
20504 * @param {String} oldvalue The old value
20505 * @param {String} newvalue The new value
20511 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
20513 onRender: function(ct, position)
20516 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
20518 this.language = this.language || 'en';
20519 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
20520 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
20522 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
20523 this.isInline = false;
20524 this.isInput = true;
20525 this.component = this.el.select('.add-on', true).first() || false;
20526 this.component = (this.component && this.component.length === 0) ? false : this.component;
20527 this.hasInput = this.component && this.inputEL().length;
20529 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
20531 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
20533 this.picker().on('mousedown', this.onMousedown, this);
20534 this.picker().on('click', this.onClick, this);
20536 this.picker().addClass('datepicker-dropdown');
20538 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
20539 v.setStyle('width', '189px');
20546 if(this.isInline) {
20552 setValue: function(v, suppressEvent)
20554 var o = this.getValue();
20556 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
20560 if(suppressEvent !== true){
20561 this.fireEvent('select', this, o, v);
20566 getValue: function()
20571 onClick: function(e)
20573 e.stopPropagation();
20574 e.preventDefault();
20576 var target = e.getTarget();
20578 if(target.nodeName.toLowerCase() === 'i'){
20579 target = Roo.get(target).dom.parentNode;
20582 var nodeName = target.nodeName;
20583 var className = target.className;
20584 var html = target.innerHTML;
20586 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
20590 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
20592 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20598 picker : function()
20600 return this.pickerEl;
20603 fillMonths: function()
20606 var months = this.picker().select('>.datepicker-months td', true).first();
20608 months.dom.innerHTML = '';
20614 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
20617 months.createChild(month);
20626 if(typeof(this.vIndex) == 'undefined' && this.value.length){
20627 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
20630 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
20631 e.removeClass('active');
20633 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
20634 e.addClass('active');
20641 if(this.isInline) {
20645 this.picker().removeClass(['bottom', 'top']);
20647 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
20649 * place to the top of element!
20653 this.picker().addClass('top');
20654 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
20659 this.picker().addClass('bottom');
20661 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
20664 onFocus : function()
20666 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
20670 onBlur : function()
20672 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
20674 var d = this.inputEl().getValue();
20683 this.picker().show();
20684 this.picker().select('>.datepicker-months', true).first().show();
20688 this.fireEvent('show', this, this.date);
20693 if(this.isInline) {
20696 this.picker().hide();
20697 this.fireEvent('hide', this, this.date);
20701 onMousedown: function(e)
20703 e.stopPropagation();
20704 e.preventDefault();
20709 Roo.bootstrap.MonthField.superclass.keyup.call(this);
20713 fireKey: function(e)
20715 if (!this.picker().isVisible()){
20716 if (e.keyCode == 27) {// allow escape to hide and re-show picker
20727 e.preventDefault();
20731 dir = e.keyCode == 37 ? -1 : 1;
20733 this.vIndex = this.vIndex + dir;
20735 if(this.vIndex < 0){
20739 if(this.vIndex > 11){
20743 if(isNaN(this.vIndex)){
20747 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20753 dir = e.keyCode == 38 ? -1 : 1;
20755 this.vIndex = this.vIndex + dir * 4;
20757 if(this.vIndex < 0){
20761 if(this.vIndex > 11){
20765 if(isNaN(this.vIndex)){
20769 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20774 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20775 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20779 e.preventDefault();
20782 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20783 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20799 this.picker().remove();
20804 Roo.apply(Roo.bootstrap.MonthField, {
20823 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
20824 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
20829 Roo.apply(Roo.bootstrap.MonthField, {
20833 cls: 'datepicker dropdown-menu roo-dynamic',
20837 cls: 'datepicker-months',
20841 cls: 'table-condensed',
20843 Roo.bootstrap.DateField.content
20863 * @class Roo.bootstrap.CheckBox
20864 * @extends Roo.bootstrap.Input
20865 * Bootstrap CheckBox class
20867 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
20868 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
20869 * @cfg {String} boxLabel The text that appears beside the checkbox
20870 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
20871 * @cfg {Boolean} checked initnal the element
20872 * @cfg {Boolean} inline inline the element (default false)
20873 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
20874 * @cfg {String} tooltip label tooltip
20877 * Create a new CheckBox
20878 * @param {Object} config The config object
20881 Roo.bootstrap.CheckBox = function(config){
20882 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
20887 * Fires when the element is checked or unchecked.
20888 * @param {Roo.bootstrap.CheckBox} this This input
20889 * @param {Boolean} checked The new checked value
20894 * Fires when the element is click.
20895 * @param {Roo.bootstrap.CheckBox} this This input
20902 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
20904 inputType: 'checkbox',
20913 getAutoCreate : function()
20915 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20921 cfg.cls = 'form-group ' + this.inputType; //input-group
20924 cfg.cls += ' ' + this.inputType + '-inline';
20930 type : this.inputType,
20931 value : this.inputValue,
20932 cls : 'roo-' + this.inputType, //'form-box',
20933 placeholder : this.placeholder || ''
20937 if(this.inputType != 'radio'){
20941 cls : 'roo-hidden-value',
20942 value : this.checked ? this.inputValue : this.valueOff
20947 if (this.weight) { // Validity check?
20948 cfg.cls += " " + this.inputType + "-" + this.weight;
20951 if (this.disabled) {
20952 input.disabled=true;
20956 input.checked = this.checked;
20961 input.name = this.name;
20963 if(this.inputType != 'radio'){
20964 hidden.name = this.name;
20965 input.name = '_hidden_' + this.name;
20970 input.cls += ' input-' + this.size;
20975 ['xs','sm','md','lg'].map(function(size){
20976 if (settings[size]) {
20977 cfg.cls += ' col-' + size + '-' + settings[size];
20981 var inputblock = input;
20983 if (this.before || this.after) {
20986 cls : 'input-group',
20991 inputblock.cn.push({
20993 cls : 'input-group-addon',
20998 inputblock.cn.push(input);
21000 if(this.inputType != 'radio'){
21001 inputblock.cn.push(hidden);
21005 inputblock.cn.push({
21007 cls : 'input-group-addon',
21014 if (align ==='left' && this.fieldLabel.length) {
21015 // Roo.log("left and has label");
21020 cls : 'control-label',
21021 html : this.fieldLabel
21031 if(this.labelWidth > 12){
21032 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
21035 if(this.labelWidth < 13 && this.labelmd == 0){
21036 this.labelmd = this.labelWidth;
21039 if(this.labellg > 0){
21040 cfg.cn[0].cls += ' col-lg-' + this.labellg;
21041 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
21044 if(this.labelmd > 0){
21045 cfg.cn[0].cls += ' col-md-' + this.labelmd;
21046 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
21049 if(this.labelsm > 0){
21050 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
21051 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
21054 if(this.labelxs > 0){
21055 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
21056 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
21059 } else if ( this.fieldLabel.length) {
21060 // Roo.log(" label");
21064 tag: this.boxLabel ? 'span' : 'label',
21066 cls: 'control-label box-input-label',
21067 //cls : 'input-group-addon',
21068 html : this.fieldLabel
21077 // Roo.log(" no label && no align");
21078 cfg.cn = [ inputblock ] ;
21084 var boxLabelCfg = {
21086 //'for': id, // box label is handled by onclick - so no for...
21088 html: this.boxLabel
21092 boxLabelCfg.tooltip = this.tooltip;
21095 cfg.cn.push(boxLabelCfg);
21098 if(this.inputType != 'radio'){
21099 cfg.cn.push(hidden);
21107 * return the real input element.
21109 inputEl: function ()
21111 return this.el.select('input.roo-' + this.inputType,true).first();
21113 hiddenEl: function ()
21115 return this.el.select('input.roo-hidden-value',true).first();
21118 labelEl: function()
21120 return this.el.select('label.control-label',true).first();
21122 /* depricated... */
21126 return this.labelEl();
21129 boxLabelEl: function()
21131 return this.el.select('label.box-label',true).first();
21134 initEvents : function()
21136 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
21138 this.inputEl().on('click', this.onClick, this);
21140 if (this.boxLabel) {
21141 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
21144 this.startValue = this.getValue();
21147 Roo.bootstrap.CheckBox.register(this);
21151 onClick : function(e)
21153 if(this.fireEvent('click', this, e) !== false){
21154 this.setChecked(!this.checked);
21159 setChecked : function(state,suppressEvent)
21161 this.startValue = this.getValue();
21163 if(this.inputType == 'radio'){
21165 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21166 e.dom.checked = false;
21169 this.inputEl().dom.checked = true;
21171 this.inputEl().dom.value = this.inputValue;
21173 if(suppressEvent !== true){
21174 this.fireEvent('check', this, true);
21182 this.checked = state;
21184 this.inputEl().dom.checked = state;
21187 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
21189 if(suppressEvent !== true){
21190 this.fireEvent('check', this, state);
21196 getValue : function()
21198 if(this.inputType == 'radio'){
21199 return this.getGroupValue();
21202 return this.hiddenEl().dom.value;
21206 getGroupValue : function()
21208 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
21212 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
21215 setValue : function(v,suppressEvent)
21217 if(this.inputType == 'radio'){
21218 this.setGroupValue(v, suppressEvent);
21222 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
21227 setGroupValue : function(v, suppressEvent)
21229 this.startValue = this.getValue();
21231 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21232 e.dom.checked = false;
21234 if(e.dom.value == v){
21235 e.dom.checked = true;
21239 if(suppressEvent !== true){
21240 this.fireEvent('check', this, true);
21248 validate : function()
21250 if(this.getVisibilityEl().hasClass('hidden')){
21256 (this.inputType == 'radio' && this.validateRadio()) ||
21257 (this.inputType == 'checkbox' && this.validateCheckbox())
21263 this.markInvalid();
21267 validateRadio : function()
21269 if(this.getVisibilityEl().hasClass('hidden')){
21273 if(this.allowBlank){
21279 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21280 if(!e.dom.checked){
21292 validateCheckbox : function()
21295 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
21296 //return (this.getValue() == this.inputValue) ? true : false;
21299 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21307 for(var i in group){
21308 if(group[i].el.isVisible(true)){
21316 for(var i in group){
21321 r = (group[i].getValue() == group[i].inputValue) ? true : false;
21328 * Mark this field as valid
21330 markValid : function()
21334 this.fireEvent('valid', this);
21336 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21339 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
21346 if(this.inputType == 'radio'){
21347 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21348 var fg = e.findParent('.form-group', false, true);
21349 if (Roo.bootstrap.version == 3) {
21350 fg.removeClass([_this.invalidClass, _this.validClass]);
21351 fg.addClass(_this.validClass);
21353 fg.removeClass(['is-valid', 'is-invalid']);
21354 fg.addClass('is-valid');
21362 var fg = this.el.findParent('.form-group', false, true);
21363 if (Roo.bootstrap.version == 3) {
21364 fg.removeClass([this.invalidClass, this.validClass]);
21365 fg.addClass(this.validClass);
21367 fg.removeClass(['is-valid', 'is-invalid']);
21368 fg.addClass('is-valid');
21373 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21379 for(var i in group){
21380 var fg = group[i].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');
21392 * Mark this field as invalid
21393 * @param {String} msg The validation message
21395 markInvalid : function(msg)
21397 if(this.allowBlank){
21403 this.fireEvent('invalid', this, msg);
21405 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21408 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
21412 label.markInvalid();
21415 if(this.inputType == 'radio'){
21417 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21418 var fg = e.findParent('.form-group', false, true);
21419 if (Roo.bootstrap.version == 3) {
21420 fg.removeClass([_this.invalidClass, _this.validClass]);
21421 fg.addClass(_this.invalidClass);
21423 fg.removeClass(['is-invalid', 'is-valid']);
21424 fg.addClass('is-invalid');
21432 var fg = this.el.findParent('.form-group', false, true);
21433 if (Roo.bootstrap.version == 3) {
21434 fg.removeClass([_this.invalidClass, _this.validClass]);
21435 fg.addClass(_this.invalidClass);
21437 fg.removeClass(['is-invalid', 'is-valid']);
21438 fg.addClass('is-invalid');
21443 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21449 for(var i in group){
21450 var fg = group[i].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');
21462 clearInvalid : function()
21464 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
21466 // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21468 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21470 if (label && label.iconEl) {
21471 label.iconEl.removeClass([ label.validClass, label.invalidClass ]);
21472 label.iconEl.removeClass(['is-invalid', 'is-valid']);
21476 disable : function()
21478 if(this.inputType != 'radio'){
21479 Roo.bootstrap.CheckBox.superclass.disable.call(this);
21486 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21487 _this.getActionEl().addClass(this.disabledClass);
21488 e.dom.disabled = true;
21492 this.disabled = true;
21493 this.fireEvent("disable", this);
21497 enable : function()
21499 if(this.inputType != 'radio'){
21500 Roo.bootstrap.CheckBox.superclass.enable.call(this);
21507 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21508 _this.getActionEl().removeClass(this.disabledClass);
21509 e.dom.disabled = false;
21513 this.disabled = false;
21514 this.fireEvent("enable", this);
21518 setBoxLabel : function(v)
21523 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21529 Roo.apply(Roo.bootstrap.CheckBox, {
21534 * register a CheckBox Group
21535 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
21537 register : function(checkbox)
21539 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
21540 this.groups[checkbox.groupId] = {};
21543 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
21547 this.groups[checkbox.groupId][checkbox.name] = checkbox;
21551 * fetch a CheckBox Group based on the group ID
21552 * @param {string} the group ID
21553 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
21555 get: function(groupId) {
21556 if (typeof(this.groups[groupId]) == 'undefined') {
21560 return this.groups[groupId] ;
21573 * @class Roo.bootstrap.Radio
21574 * @extends Roo.bootstrap.Component
21575 * Bootstrap Radio class
21576 * @cfg {String} boxLabel - the label associated
21577 * @cfg {String} value - the value of radio
21580 * Create a new Radio
21581 * @param {Object} config The config object
21583 Roo.bootstrap.Radio = function(config){
21584 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
21588 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
21594 getAutoCreate : function()
21598 cls : 'form-group radio',
21603 html : this.boxLabel
21611 initEvents : function()
21613 this.parent().register(this);
21615 this.el.on('click', this.onClick, this);
21619 onClick : function(e)
21621 if(this.parent().fireEvent('click', this.parent(), this, e) !== false){
21622 this.setChecked(true);
21626 setChecked : function(state, suppressEvent)
21628 this.parent().setValue(this.value, suppressEvent);
21632 setBoxLabel : function(v)
21637 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21652 * @class Roo.bootstrap.SecurePass
21653 * @extends Roo.bootstrap.Input
21654 * Bootstrap SecurePass class
21658 * Create a new SecurePass
21659 * @param {Object} config The config object
21662 Roo.bootstrap.SecurePass = function (config) {
21663 // these go here, so the translation tool can replace them..
21665 PwdEmpty: "Please type a password, and then retype it to confirm.",
21666 PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21667 PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21668 PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21669 IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21670 FNInPwd: "Your password can't contain your first name. Please type a different password.",
21671 LNInPwd: "Your password can't contain your last name. Please type a different password.",
21672 TooWeak: "Your password is Too Weak."
21674 this.meterLabel = "Password strength:";
21675 this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
21676 this.meterClass = [
21677 "roo-password-meter-tooweak",
21678 "roo-password-meter-weak",
21679 "roo-password-meter-medium",
21680 "roo-password-meter-strong",
21681 "roo-password-meter-grey"
21686 Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
21689 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
21691 * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
21693 * PwdEmpty: "Please type a password, and then retype it to confirm.",
21694 * PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21695 * PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21696 * PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21697 * IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21698 * FNInPwd: "Your password can't contain your first name. Please type a different password.",
21699 * LNInPwd: "Your password can't contain your last name. Please type a different password."
21709 * @cfg {String/Object} Label for the strength meter (defaults to
21710 * 'Password strength:')
21715 * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
21716 * ['Weak', 'Medium', 'Strong'])
21719 pwdStrengths: false,
21732 initEvents: function ()
21734 Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
21736 if (this.el.is('input[type=password]') && Roo.isSafari) {
21737 this.el.on('keydown', this.SafariOnKeyDown, this);
21740 this.el.on('keyup', this.checkStrength, this, {buffer: 50});
21743 onRender: function (ct, position)
21745 Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
21746 this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
21747 this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
21749 this.trigger.createChild({
21754 cls: 'roo-password-meter-grey col-xs-12',
21757 //width: this.meterWidth + 'px'
21761 cls: 'roo-password-meter-text'
21767 if (this.hideTrigger) {
21768 this.trigger.setDisplayed(false);
21770 this.setSize(this.width || '', this.height || '');
21773 onDestroy: function ()
21775 if (this.trigger) {
21776 this.trigger.removeAllListeners();
21777 this.trigger.remove();
21780 this.wrap.remove();
21782 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
21785 checkStrength: function ()
21787 var pwd = this.inputEl().getValue();
21788 if (pwd == this._lastPwd) {
21793 if (this.ClientSideStrongPassword(pwd)) {
21795 } else if (this.ClientSideMediumPassword(pwd)) {
21797 } else if (this.ClientSideWeakPassword(pwd)) {
21803 Roo.log('strength1: ' + strength);
21805 //var pm = this.trigger.child('div/div/div').dom;
21806 var pm = this.trigger.child('div/div');
21807 pm.removeClass(this.meterClass);
21808 pm.addClass(this.meterClass[strength]);
21811 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21813 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21815 this._lastPwd = pwd;
21819 Roo.bootstrap.SecurePass.superclass.reset.call(this);
21821 this._lastPwd = '';
21823 var pm = this.trigger.child('div/div');
21824 pm.removeClass(this.meterClass);
21825 pm.addClass('roo-password-meter-grey');
21828 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21831 this.inputEl().dom.type='password';
21834 validateValue: function (value)
21837 if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
21840 if (value.length == 0) {
21841 if (this.allowBlank) {
21842 this.clearInvalid();
21846 this.markInvalid(this.errors.PwdEmpty);
21847 this.errorMsg = this.errors.PwdEmpty;
21855 if ('[\x21-\x7e]*'.match(value)) {
21856 this.markInvalid(this.errors.PwdBadChar);
21857 this.errorMsg = this.errors.PwdBadChar;
21860 if (value.length < 6) {
21861 this.markInvalid(this.errors.PwdShort);
21862 this.errorMsg = this.errors.PwdShort;
21865 if (value.length > 16) {
21866 this.markInvalid(this.errors.PwdLong);
21867 this.errorMsg = this.errors.PwdLong;
21871 if (this.ClientSideStrongPassword(value)) {
21873 } else if (this.ClientSideMediumPassword(value)) {
21875 } else if (this.ClientSideWeakPassword(value)) {
21882 if (strength < 2) {
21883 //this.markInvalid(this.errors.TooWeak);
21884 this.errorMsg = this.errors.TooWeak;
21889 console.log('strength2: ' + strength);
21891 //var pm = this.trigger.child('div/div/div').dom;
21893 var pm = this.trigger.child('div/div');
21894 pm.removeClass(this.meterClass);
21895 pm.addClass(this.meterClass[strength]);
21897 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21899 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21901 this.errorMsg = '';
21905 CharacterSetChecks: function (type)
21908 this.fResult = false;
21911 isctype: function (character, type)
21914 case this.kCapitalLetter:
21915 if (character >= 'A' && character <= 'Z') {
21920 case this.kSmallLetter:
21921 if (character >= 'a' && character <= 'z') {
21927 if (character >= '0' && character <= '9') {
21932 case this.kPunctuation:
21933 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
21944 IsLongEnough: function (pwd, size)
21946 return !(pwd == null || isNaN(size) || pwd.length < size);
21949 SpansEnoughCharacterSets: function (word, nb)
21951 if (!this.IsLongEnough(word, nb))
21956 var characterSetChecks = new Array(
21957 new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
21958 new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
21961 for (var index = 0; index < word.length; ++index) {
21962 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21963 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
21964 characterSetChecks[nCharSet].fResult = true;
21971 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21972 if (characterSetChecks[nCharSet].fResult) {
21977 if (nCharSets < nb) {
21983 ClientSideStrongPassword: function (pwd)
21985 return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
21988 ClientSideMediumPassword: function (pwd)
21990 return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
21993 ClientSideWeakPassword: function (pwd)
21995 return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
21998 })//<script type="text/javascript">
22001 * Based Ext JS Library 1.1.1
22002 * Copyright(c) 2006-2007, Ext JS, LLC.
22008 * @class Roo.HtmlEditorCore
22009 * @extends Roo.Component
22010 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
22012 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
22015 Roo.HtmlEditorCore = function(config){
22018 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
22023 * @event initialize
22024 * Fires when the editor is fully initialized (including the iframe)
22025 * @param {Roo.HtmlEditorCore} this
22030 * Fires when the editor is first receives the focus. Any insertion must wait
22031 * until after this event.
22032 * @param {Roo.HtmlEditorCore} this
22036 * @event beforesync
22037 * Fires before the textarea is updated with content from the editor iframe. Return false
22038 * to cancel the sync.
22039 * @param {Roo.HtmlEditorCore} this
22040 * @param {String} html
22044 * @event beforepush
22045 * Fires before the iframe editor is updated with content from the textarea. Return false
22046 * to cancel the push.
22047 * @param {Roo.HtmlEditorCore} this
22048 * @param {String} html
22053 * Fires when the textarea is updated with content from the editor iframe.
22054 * @param {Roo.HtmlEditorCore} this
22055 * @param {String} html
22060 * Fires when the iframe editor is updated with content from the textarea.
22061 * @param {Roo.HtmlEditorCore} this
22062 * @param {String} html
22067 * @event editorevent
22068 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
22069 * @param {Roo.HtmlEditorCore} this
22075 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
22077 // defaults : white / black...
22078 this.applyBlacklists();
22085 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
22089 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
22095 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
22100 * @cfg {Number} height (in pixels)
22104 * @cfg {Number} width (in pixels)
22109 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
22112 stylesheets: false,
22117 // private properties
22118 validationEvent : false,
22120 initialized : false,
22122 sourceEditMode : false,
22123 onFocus : Roo.emptyFn,
22125 hideMode:'offsets',
22129 // blacklist + whitelisted elements..
22136 * Protected method that will not generally be called directly. It
22137 * is called when the editor initializes the iframe with HTML contents. Override this method if you
22138 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
22140 getDocMarkup : function(){
22144 // inherit styels from page...??
22145 if (this.stylesheets === false) {
22147 Roo.get(document.head).select('style').each(function(node) {
22148 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
22151 Roo.get(document.head).select('link').each(function(node) {
22152 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
22155 } else if (!this.stylesheets.length) {
22157 st = '<style type="text/css">' +
22158 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
22161 st = '<style type="text/css">' +
22166 st += '<style type="text/css">' +
22167 'IMG { cursor: pointer } ' +
22170 var cls = 'roo-htmleditor-body';
22172 if(this.bodyCls.length){
22173 cls += ' ' + this.bodyCls;
22176 return '<html><head>' + st +
22177 //<style type="text/css">' +
22178 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
22180 ' </head><body class="' + cls + '"></body></html>';
22184 onRender : function(ct, position)
22187 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
22188 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
22191 this.el.dom.style.border = '0 none';
22192 this.el.dom.setAttribute('tabIndex', -1);
22193 this.el.addClass('x-hidden hide');
22197 if(Roo.isIE){ // fix IE 1px bogus margin
22198 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
22202 this.frameId = Roo.id();
22206 var iframe = this.owner.wrap.createChild({
22208 cls: 'form-control', // bootstrap..
22210 name: this.frameId,
22211 frameBorder : 'no',
22212 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
22217 this.iframe = iframe.dom;
22219 this.assignDocWin();
22221 this.doc.designMode = 'on';
22224 this.doc.write(this.getDocMarkup());
22228 var task = { // must defer to wait for browser to be ready
22230 //console.log("run task?" + this.doc.readyState);
22231 this.assignDocWin();
22232 if(this.doc.body || this.doc.readyState == 'complete'){
22234 this.doc.designMode="on";
22238 Roo.TaskMgr.stop(task);
22239 this.initEditor.defer(10, this);
22246 Roo.TaskMgr.start(task);
22251 onResize : function(w, h)
22253 Roo.log('resize: ' +w + ',' + h );
22254 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
22258 if(typeof w == 'number'){
22260 this.iframe.style.width = w + 'px';
22262 if(typeof h == 'number'){
22264 this.iframe.style.height = h + 'px';
22266 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
22273 * Toggles the editor between standard and source edit mode.
22274 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
22276 toggleSourceEdit : function(sourceEditMode){
22278 this.sourceEditMode = sourceEditMode === true;
22280 if(this.sourceEditMode){
22282 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
22285 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
22286 //this.iframe.className = '';
22289 //this.setSize(this.owner.wrap.getSize());
22290 //this.fireEvent('editmodechange', this, this.sourceEditMode);
22297 * Protected method that will not generally be called directly. If you need/want
22298 * custom HTML cleanup, this is the method you should override.
22299 * @param {String} html The HTML to be cleaned
22300 * return {String} The cleaned HTML
22302 cleanHtml : function(html){
22303 html = String(html);
22304 if(html.length > 5){
22305 if(Roo.isSafari){ // strip safari nonsense
22306 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
22309 if(html == ' '){
22316 * HTML Editor -> Textarea
22317 * Protected method that will not generally be called directly. Syncs the contents
22318 * of the editor iframe with the textarea.
22320 syncValue : function(){
22321 if(this.initialized){
22322 var bd = (this.doc.body || this.doc.documentElement);
22323 //this.cleanUpPaste(); -- this is done else where and causes havoc..
22324 var html = bd.innerHTML;
22326 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
22327 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
22329 html = '<div style="'+m[0]+'">' + html + '</div>';
22332 html = this.cleanHtml(html);
22333 // fix up the special chars.. normaly like back quotes in word...
22334 // however we do not want to do this with chinese..
22335 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
22336 var cc = b.charCodeAt();
22338 (cc >= 0x4E00 && cc < 0xA000 ) ||
22339 (cc >= 0x3400 && cc < 0x4E00 ) ||
22340 (cc >= 0xf900 && cc < 0xfb00 )
22346 if(this.owner.fireEvent('beforesync', this, html) !== false){
22347 this.el.dom.value = html;
22348 this.owner.fireEvent('sync', this, html);
22354 * Protected method that will not generally be called directly. Pushes the value of the textarea
22355 * into the iframe editor.
22357 pushValue : function(){
22358 if(this.initialized){
22359 var v = this.el.dom.value.trim();
22361 // if(v.length < 1){
22365 if(this.owner.fireEvent('beforepush', this, v) !== false){
22366 var d = (this.doc.body || this.doc.documentElement);
22368 this.cleanUpPaste();
22369 this.el.dom.value = d.innerHTML;
22370 this.owner.fireEvent('push', this, v);
22376 deferFocus : function(){
22377 this.focus.defer(10, this);
22381 focus : function(){
22382 if(this.win && !this.sourceEditMode){
22389 assignDocWin: function()
22391 var iframe = this.iframe;
22394 this.doc = iframe.contentWindow.document;
22395 this.win = iframe.contentWindow;
22397 // if (!Roo.get(this.frameId)) {
22400 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
22401 // this.win = Roo.get(this.frameId).dom.contentWindow;
22403 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
22407 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
22408 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
22413 initEditor : function(){
22414 //console.log("INIT EDITOR");
22415 this.assignDocWin();
22419 this.doc.designMode="on";
22421 this.doc.write(this.getDocMarkup());
22424 var dbody = (this.doc.body || this.doc.documentElement);
22425 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
22426 // this copies styles from the containing element into thsi one..
22427 // not sure why we need all of this..
22428 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
22430 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
22431 //ss['background-attachment'] = 'fixed'; // w3c
22432 dbody.bgProperties = 'fixed'; // ie
22433 //Roo.DomHelper.applyStyles(dbody, ss);
22434 Roo.EventManager.on(this.doc, {
22435 //'mousedown': this.onEditorEvent,
22436 'mouseup': this.onEditorEvent,
22437 'dblclick': this.onEditorEvent,
22438 'click': this.onEditorEvent,
22439 'keyup': this.onEditorEvent,
22444 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
22446 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
22447 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
22449 this.initialized = true;
22451 this.owner.fireEvent('initialize', this);
22456 onDestroy : function(){
22462 //for (var i =0; i < this.toolbars.length;i++) {
22463 // // fixme - ask toolbars for heights?
22464 // this.toolbars[i].onDestroy();
22467 //this.wrap.dom.innerHTML = '';
22468 //this.wrap.remove();
22473 onFirstFocus : function(){
22475 this.assignDocWin();
22478 this.activated = true;
22481 if(Roo.isGecko){ // prevent silly gecko errors
22483 var s = this.win.getSelection();
22484 if(!s.focusNode || s.focusNode.nodeType != 3){
22485 var r = s.getRangeAt(0);
22486 r.selectNodeContents((this.doc.body || this.doc.documentElement));
22491 this.execCmd('useCSS', true);
22492 this.execCmd('styleWithCSS', false);
22495 this.owner.fireEvent('activate', this);
22499 adjustFont: function(btn){
22500 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
22501 //if(Roo.isSafari){ // safari
22504 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
22505 if(Roo.isSafari){ // safari
22506 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
22507 v = (v < 10) ? 10 : v;
22508 v = (v > 48) ? 48 : v;
22509 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
22514 v = Math.max(1, v+adjust);
22516 this.execCmd('FontSize', v );
22519 onEditorEvent : function(e)
22521 this.owner.fireEvent('editorevent', this, e);
22522 // this.updateToolbar();
22523 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
22526 insertTag : function(tg)
22528 // could be a bit smarter... -> wrap the current selected tRoo..
22529 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
22531 range = this.createRange(this.getSelection());
22532 var wrappingNode = this.doc.createElement(tg.toLowerCase());
22533 wrappingNode.appendChild(range.extractContents());
22534 range.insertNode(wrappingNode);
22541 this.execCmd("formatblock", tg);
22545 insertText : function(txt)
22549 var range = this.createRange();
22550 range.deleteContents();
22551 //alert(Sender.getAttribute('label'));
22553 range.insertNode(this.doc.createTextNode(txt));
22559 * Executes a Midas editor command on the editor document and performs necessary focus and
22560 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
22561 * @param {String} cmd The Midas command
22562 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22564 relayCmd : function(cmd, value){
22566 this.execCmd(cmd, value);
22567 this.owner.fireEvent('editorevent', this);
22568 //this.updateToolbar();
22569 this.owner.deferFocus();
22573 * Executes a Midas editor command directly on the editor document.
22574 * For visual commands, you should use {@link #relayCmd} instead.
22575 * <b>This should only be called after the editor is initialized.</b>
22576 * @param {String} cmd The Midas command
22577 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22579 execCmd : function(cmd, value){
22580 this.doc.execCommand(cmd, false, value === undefined ? null : value);
22587 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
22589 * @param {String} text | dom node..
22591 insertAtCursor : function(text)
22594 if(!this.activated){
22600 var r = this.doc.selection.createRange();
22611 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
22615 // from jquery ui (MIT licenced)
22617 var win = this.win;
22619 if (win.getSelection && win.getSelection().getRangeAt) {
22620 range = win.getSelection().getRangeAt(0);
22621 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
22622 range.insertNode(node);
22623 } else if (win.document.selection && win.document.selection.createRange) {
22624 // no firefox support
22625 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22626 win.document.selection.createRange().pasteHTML(txt);
22628 // no firefox support
22629 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22630 this.execCmd('InsertHTML', txt);
22639 mozKeyPress : function(e){
22641 var c = e.getCharCode(), cmd;
22644 c = String.fromCharCode(c).toLowerCase();
22658 this.cleanUpPaste.defer(100, this);
22666 e.preventDefault();
22674 fixKeys : function(){ // load time branching for fastest keydown performance
22676 return function(e){
22677 var k = e.getKey(), r;
22680 r = this.doc.selection.createRange();
22683 r.pasteHTML('    ');
22690 r = this.doc.selection.createRange();
22692 var target = r.parentElement();
22693 if(!target || target.tagName.toLowerCase() != 'li'){
22695 r.pasteHTML('<br />');
22701 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22702 this.cleanUpPaste.defer(100, this);
22708 }else if(Roo.isOpera){
22709 return function(e){
22710 var k = e.getKey();
22714 this.execCmd('InsertHTML','    ');
22717 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22718 this.cleanUpPaste.defer(100, this);
22723 }else if(Roo.isSafari){
22724 return function(e){
22725 var k = e.getKey();
22729 this.execCmd('InsertText','\t');
22733 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22734 this.cleanUpPaste.defer(100, this);
22742 getAllAncestors: function()
22744 var p = this.getSelectedNode();
22747 a.push(p); // push blank onto stack..
22748 p = this.getParentElement();
22752 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
22756 a.push(this.doc.body);
22760 lastSelNode : false,
22763 getSelection : function()
22765 this.assignDocWin();
22766 return Roo.isIE ? this.doc.selection : this.win.getSelection();
22769 getSelectedNode: function()
22771 // this may only work on Gecko!!!
22773 // should we cache this!!!!
22778 var range = this.createRange(this.getSelection()).cloneRange();
22781 var parent = range.parentElement();
22783 var testRange = range.duplicate();
22784 testRange.moveToElementText(parent);
22785 if (testRange.inRange(range)) {
22788 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
22791 parent = parent.parentElement;
22796 // is ancestor a text element.
22797 var ac = range.commonAncestorContainer;
22798 if (ac.nodeType == 3) {
22799 ac = ac.parentNode;
22802 var ar = ac.childNodes;
22805 var other_nodes = [];
22806 var has_other_nodes = false;
22807 for (var i=0;i<ar.length;i++) {
22808 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
22811 // fullly contained node.
22813 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
22818 // probably selected..
22819 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
22820 other_nodes.push(ar[i]);
22824 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
22829 has_other_nodes = true;
22831 if (!nodes.length && other_nodes.length) {
22832 nodes= other_nodes;
22834 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
22840 createRange: function(sel)
22842 // this has strange effects when using with
22843 // top toolbar - not sure if it's a great idea.
22844 //this.editor.contentWindow.focus();
22845 if (typeof sel != "undefined") {
22847 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
22849 return this.doc.createRange();
22852 return this.doc.createRange();
22855 getParentElement: function()
22858 this.assignDocWin();
22859 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
22861 var range = this.createRange(sel);
22864 var p = range.commonAncestorContainer;
22865 while (p.nodeType == 3) { // text node
22876 * Range intersection.. the hard stuff...
22880 * [ -- selected range --- ]
22884 * if end is before start or hits it. fail.
22885 * if start is after end or hits it fail.
22887 * if either hits (but other is outside. - then it's not
22893 // @see http://www.thismuchiknow.co.uk/?p=64.
22894 rangeIntersectsNode : function(range, node)
22896 var nodeRange = node.ownerDocument.createRange();
22898 nodeRange.selectNode(node);
22900 nodeRange.selectNodeContents(node);
22903 var rangeStartRange = range.cloneRange();
22904 rangeStartRange.collapse(true);
22906 var rangeEndRange = range.cloneRange();
22907 rangeEndRange.collapse(false);
22909 var nodeStartRange = nodeRange.cloneRange();
22910 nodeStartRange.collapse(true);
22912 var nodeEndRange = nodeRange.cloneRange();
22913 nodeEndRange.collapse(false);
22915 return rangeStartRange.compareBoundaryPoints(
22916 Range.START_TO_START, nodeEndRange) == -1 &&
22917 rangeEndRange.compareBoundaryPoints(
22918 Range.START_TO_START, nodeStartRange) == 1;
22922 rangeCompareNode : function(range, node)
22924 var nodeRange = node.ownerDocument.createRange();
22926 nodeRange.selectNode(node);
22928 nodeRange.selectNodeContents(node);
22932 range.collapse(true);
22934 nodeRange.collapse(true);
22936 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
22937 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
22939 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
22941 var nodeIsBefore = ss == 1;
22942 var nodeIsAfter = ee == -1;
22944 if (nodeIsBefore && nodeIsAfter) {
22947 if (!nodeIsBefore && nodeIsAfter) {
22948 return 1; //right trailed.
22951 if (nodeIsBefore && !nodeIsAfter) {
22952 return 2; // left trailed.
22958 // private? - in a new class?
22959 cleanUpPaste : function()
22961 // cleans up the whole document..
22962 Roo.log('cleanuppaste');
22964 this.cleanUpChildren(this.doc.body);
22965 var clean = this.cleanWordChars(this.doc.body.innerHTML);
22966 if (clean != this.doc.body.innerHTML) {
22967 this.doc.body.innerHTML = clean;
22972 cleanWordChars : function(input) {// change the chars to hex code
22973 var he = Roo.HtmlEditorCore;
22975 var output = input;
22976 Roo.each(he.swapCodes, function(sw) {
22977 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
22979 output = output.replace(swapper, sw[1]);
22986 cleanUpChildren : function (n)
22988 if (!n.childNodes.length) {
22991 for (var i = n.childNodes.length-1; i > -1 ; i--) {
22992 this.cleanUpChild(n.childNodes[i]);
22999 cleanUpChild : function (node)
23002 //console.log(node);
23003 if (node.nodeName == "#text") {
23004 // clean up silly Windows -- stuff?
23007 if (node.nodeName == "#comment") {
23008 node.parentNode.removeChild(node);
23009 // clean up silly Windows -- stuff?
23012 var lcname = node.tagName.toLowerCase();
23013 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
23014 // whitelist of tags..
23016 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
23018 node.parentNode.removeChild(node);
23023 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
23025 // remove <a name=....> as rendering on yahoo mailer is borked with this.
23026 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
23028 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
23029 // remove_keep_children = true;
23032 if (remove_keep_children) {
23033 this.cleanUpChildren(node);
23034 // inserts everything just before this node...
23035 while (node.childNodes.length) {
23036 var cn = node.childNodes[0];
23037 node.removeChild(cn);
23038 node.parentNode.insertBefore(cn, node);
23040 node.parentNode.removeChild(node);
23044 if (!node.attributes || !node.attributes.length) {
23045 this.cleanUpChildren(node);
23049 function cleanAttr(n,v)
23052 if (v.match(/^\./) || v.match(/^\//)) {
23055 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/) || v.match(/^ftp:/)) {
23058 if (v.match(/^#/)) {
23061 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
23062 node.removeAttribute(n);
23066 var cwhite = this.cwhite;
23067 var cblack = this.cblack;
23069 function cleanStyle(n,v)
23071 if (v.match(/expression/)) { //XSS?? should we even bother..
23072 node.removeAttribute(n);
23076 var parts = v.split(/;/);
23079 Roo.each(parts, function(p) {
23080 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
23084 var l = p.split(':').shift().replace(/\s+/g,'');
23085 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
23087 if ( cwhite.length && cblack.indexOf(l) > -1) {
23088 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
23089 //node.removeAttribute(n);
23093 // only allow 'c whitelisted system attributes'
23094 if ( cwhite.length && cwhite.indexOf(l) < 0) {
23095 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
23096 //node.removeAttribute(n);
23106 if (clean.length) {
23107 node.setAttribute(n, clean.join(';'));
23109 node.removeAttribute(n);
23115 for (var i = node.attributes.length-1; i > -1 ; i--) {
23116 var a = node.attributes[i];
23119 if (a.name.toLowerCase().substr(0,2)=='on') {
23120 node.removeAttribute(a.name);
23123 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
23124 node.removeAttribute(a.name);
23127 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
23128 cleanAttr(a.name,a.value); // fixme..
23131 if (a.name == 'style') {
23132 cleanStyle(a.name,a.value);
23135 /// clean up MS crap..
23136 // tecnically this should be a list of valid class'es..
23139 if (a.name == 'class') {
23140 if (a.value.match(/^Mso/)) {
23141 node.className = '';
23144 if (a.value.match(/^body$/)) {
23145 node.className = '';
23156 this.cleanUpChildren(node);
23162 * Clean up MS wordisms...
23164 cleanWord : function(node)
23169 this.cleanWord(this.doc.body);
23172 if (node.nodeName == "#text") {
23173 // clean up silly Windows -- stuff?
23176 if (node.nodeName == "#comment") {
23177 node.parentNode.removeChild(node);
23178 // clean up silly Windows -- stuff?
23182 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
23183 node.parentNode.removeChild(node);
23187 // remove - but keep children..
23188 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
23189 while (node.childNodes.length) {
23190 var cn = node.childNodes[0];
23191 node.removeChild(cn);
23192 node.parentNode.insertBefore(cn, node);
23194 node.parentNode.removeChild(node);
23195 this.iterateChildren(node, this.cleanWord);
23199 if (node.className.length) {
23201 var cn = node.className.split(/\W+/);
23203 Roo.each(cn, function(cls) {
23204 if (cls.match(/Mso[a-zA-Z]+/)) {
23209 node.className = cna.length ? cna.join(' ') : '';
23211 node.removeAttribute("class");
23215 if (node.hasAttribute("lang")) {
23216 node.removeAttribute("lang");
23219 if (node.hasAttribute("style")) {
23221 var styles = node.getAttribute("style").split(";");
23223 Roo.each(styles, function(s) {
23224 if (!s.match(/:/)) {
23227 var kv = s.split(":");
23228 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
23231 // what ever is left... we allow.
23234 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
23235 if (!nstyle.length) {
23236 node.removeAttribute('style');
23239 this.iterateChildren(node, this.cleanWord);
23245 * iterateChildren of a Node, calling fn each time, using this as the scole..
23246 * @param {DomNode} node node to iterate children of.
23247 * @param {Function} fn method of this class to call on each item.
23249 iterateChildren : function(node, fn)
23251 if (!node.childNodes.length) {
23254 for (var i = node.childNodes.length-1; i > -1 ; i--) {
23255 fn.call(this, node.childNodes[i])
23261 * cleanTableWidths.
23263 * Quite often pasting from word etc.. results in tables with column and widths.
23264 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
23267 cleanTableWidths : function(node)
23272 this.cleanTableWidths(this.doc.body);
23277 if (node.nodeName == "#text" || node.nodeName == "#comment") {
23280 Roo.log(node.tagName);
23281 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
23282 this.iterateChildren(node, this.cleanTableWidths);
23285 if (node.hasAttribute('width')) {
23286 node.removeAttribute('width');
23290 if (node.hasAttribute("style")) {
23293 var styles = node.getAttribute("style").split(";");
23295 Roo.each(styles, function(s) {
23296 if (!s.match(/:/)) {
23299 var kv = s.split(":");
23300 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
23303 // what ever is left... we allow.
23306 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
23307 if (!nstyle.length) {
23308 node.removeAttribute('style');
23312 this.iterateChildren(node, this.cleanTableWidths);
23320 domToHTML : function(currentElement, depth, nopadtext) {
23322 depth = depth || 0;
23323 nopadtext = nopadtext || false;
23325 if (!currentElement) {
23326 return this.domToHTML(this.doc.body);
23329 //Roo.log(currentElement);
23331 var allText = false;
23332 var nodeName = currentElement.nodeName;
23333 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
23335 if (nodeName == '#text') {
23337 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
23342 if (nodeName != 'BODY') {
23345 // Prints the node tagName, such as <A>, <IMG>, etc
23348 for(i = 0; i < currentElement.attributes.length;i++) {
23350 var aname = currentElement.attributes.item(i).name;
23351 if (!currentElement.attributes.item(i).value.length) {
23354 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
23357 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
23366 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
23369 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
23374 // Traverse the tree
23376 var currentElementChild = currentElement.childNodes.item(i);
23377 var allText = true;
23378 var innerHTML = '';
23380 while (currentElementChild) {
23381 // Formatting code (indent the tree so it looks nice on the screen)
23382 var nopad = nopadtext;
23383 if (lastnode == 'SPAN') {
23387 if (currentElementChild.nodeName == '#text') {
23388 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
23389 toadd = nopadtext ? toadd : toadd.trim();
23390 if (!nopad && toadd.length > 80) {
23391 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
23393 innerHTML += toadd;
23396 currentElementChild = currentElement.childNodes.item(i);
23402 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
23404 // Recursively traverse the tree structure of the child node
23405 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
23406 lastnode = currentElementChild.nodeName;
23408 currentElementChild=currentElement.childNodes.item(i);
23414 // The remaining code is mostly for formatting the tree
23415 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
23420 ret+= "</"+tagName+">";
23426 applyBlacklists : function()
23428 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
23429 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
23433 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
23434 if (b.indexOf(tag) > -1) {
23437 this.white.push(tag);
23441 Roo.each(w, function(tag) {
23442 if (b.indexOf(tag) > -1) {
23445 if (this.white.indexOf(tag) > -1) {
23448 this.white.push(tag);
23453 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
23454 if (w.indexOf(tag) > -1) {
23457 this.black.push(tag);
23461 Roo.each(b, function(tag) {
23462 if (w.indexOf(tag) > -1) {
23465 if (this.black.indexOf(tag) > -1) {
23468 this.black.push(tag);
23473 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
23474 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
23478 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
23479 if (b.indexOf(tag) > -1) {
23482 this.cwhite.push(tag);
23486 Roo.each(w, function(tag) {
23487 if (b.indexOf(tag) > -1) {
23490 if (this.cwhite.indexOf(tag) > -1) {
23493 this.cwhite.push(tag);
23498 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
23499 if (w.indexOf(tag) > -1) {
23502 this.cblack.push(tag);
23506 Roo.each(b, function(tag) {
23507 if (w.indexOf(tag) > -1) {
23510 if (this.cblack.indexOf(tag) > -1) {
23513 this.cblack.push(tag);
23518 setStylesheets : function(stylesheets)
23520 if(typeof(stylesheets) == 'string'){
23521 Roo.get(this.iframe.contentDocument.head).createChild({
23523 rel : 'stylesheet',
23532 Roo.each(stylesheets, function(s) {
23537 Roo.get(_this.iframe.contentDocument.head).createChild({
23539 rel : 'stylesheet',
23548 removeStylesheets : function()
23552 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
23557 setStyle : function(style)
23559 Roo.get(this.iframe.contentDocument.head).createChild({
23568 // hide stuff that is not compatible
23582 * @event specialkey
23586 * @cfg {String} fieldClass @hide
23589 * @cfg {String} focusClass @hide
23592 * @cfg {String} autoCreate @hide
23595 * @cfg {String} inputType @hide
23598 * @cfg {String} invalidClass @hide
23601 * @cfg {String} invalidText @hide
23604 * @cfg {String} msgFx @hide
23607 * @cfg {String} validateOnBlur @hide
23611 Roo.HtmlEditorCore.white = [
23612 'area', 'br', 'img', 'input', 'hr', 'wbr',
23614 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
23615 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
23616 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
23617 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
23618 'table', 'ul', 'xmp',
23620 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
23623 'dir', 'menu', 'ol', 'ul', 'dl',
23629 Roo.HtmlEditorCore.black = [
23630 // 'embed', 'object', // enable - backend responsiblity to clean thiese
23632 'base', 'basefont', 'bgsound', 'blink', 'body',
23633 'frame', 'frameset', 'head', 'html', 'ilayer',
23634 'iframe', 'layer', 'link', 'meta', 'object',
23635 'script', 'style' ,'title', 'xml' // clean later..
23637 Roo.HtmlEditorCore.clean = [
23638 'script', 'style', 'title', 'xml'
23640 Roo.HtmlEditorCore.remove = [
23645 Roo.HtmlEditorCore.ablack = [
23649 Roo.HtmlEditorCore.aclean = [
23650 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
23654 Roo.HtmlEditorCore.pwhite= [
23655 'http', 'https', 'mailto'
23658 // white listed style attributes.
23659 Roo.HtmlEditorCore.cwhite= [
23660 // 'text-align', /// default is to allow most things..
23666 // black listed style attributes.
23667 Roo.HtmlEditorCore.cblack= [
23668 // 'font-size' -- this can be set by the project
23672 Roo.HtmlEditorCore.swapCodes =[
23691 * @class Roo.bootstrap.HtmlEditor
23692 * @extends Roo.bootstrap.TextArea
23693 * Bootstrap HtmlEditor class
23696 * Create a new HtmlEditor
23697 * @param {Object} config The config object
23700 Roo.bootstrap.HtmlEditor = function(config){
23701 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
23702 if (!this.toolbars) {
23703 this.toolbars = [];
23706 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
23709 * @event initialize
23710 * Fires when the editor is fully initialized (including the iframe)
23711 * @param {HtmlEditor} this
23716 * Fires when the editor is first receives the focus. Any insertion must wait
23717 * until after this event.
23718 * @param {HtmlEditor} this
23722 * @event beforesync
23723 * Fires before the textarea is updated with content from the editor iframe. Return false
23724 * to cancel the sync.
23725 * @param {HtmlEditor} this
23726 * @param {String} html
23730 * @event beforepush
23731 * Fires before the iframe editor is updated with content from the textarea. Return false
23732 * to cancel the push.
23733 * @param {HtmlEditor} this
23734 * @param {String} html
23739 * Fires when the textarea is updated with content from the editor iframe.
23740 * @param {HtmlEditor} this
23741 * @param {String} html
23746 * Fires when the iframe editor is updated with content from the textarea.
23747 * @param {HtmlEditor} this
23748 * @param {String} html
23752 * @event editmodechange
23753 * Fires when the editor switches edit modes
23754 * @param {HtmlEditor} this
23755 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
23757 editmodechange: true,
23759 * @event editorevent
23760 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
23761 * @param {HtmlEditor} this
23765 * @event firstfocus
23766 * Fires when on first focus - needed by toolbars..
23767 * @param {HtmlEditor} this
23772 * Auto save the htmlEditor value as a file into Events
23773 * @param {HtmlEditor} this
23777 * @event savedpreview
23778 * preview the saved version of htmlEditor
23779 * @param {HtmlEditor} this
23786 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
23790 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
23795 * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
23800 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
23805 * @cfg {Number} height (in pixels)
23809 * @cfg {Number} width (in pixels)
23814 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
23817 stylesheets: false,
23822 // private properties
23823 validationEvent : false,
23825 initialized : false,
23828 onFocus : Roo.emptyFn,
23830 hideMode:'offsets',
23832 tbContainer : false,
23836 toolbarContainer :function() {
23837 return this.wrap.select('.x-html-editor-tb',true).first();
23841 * Protected method that will not generally be called directly. It
23842 * is called when the editor creates its toolbar. Override this method if you need to
23843 * add custom toolbar buttons.
23844 * @param {HtmlEditor} editor
23846 createToolbar : function(){
23847 Roo.log('renewing');
23848 Roo.log("create toolbars");
23850 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
23851 this.toolbars[0].render(this.toolbarContainer());
23855 // if (!editor.toolbars || !editor.toolbars.length) {
23856 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
23859 // for (var i =0 ; i < editor.toolbars.length;i++) {
23860 // editor.toolbars[i] = Roo.factory(
23861 // typeof(editor.toolbars[i]) == 'string' ?
23862 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
23863 // Roo.bootstrap.HtmlEditor);
23864 // editor.toolbars[i].init(editor);
23870 onRender : function(ct, position)
23872 // Roo.log("Call onRender: " + this.xtype);
23874 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
23876 this.wrap = this.inputEl().wrap({
23877 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
23880 this.editorcore.onRender(ct, position);
23882 if (this.resizable) {
23883 this.resizeEl = new Roo.Resizable(this.wrap, {
23887 minHeight : this.height,
23888 height: this.height,
23889 handles : this.resizable,
23892 resize : function(r, w, h) {
23893 _t.onResize(w,h); // -something
23899 this.createToolbar(this);
23902 if(!this.width && this.resizable){
23903 this.setSize(this.wrap.getSize());
23905 if (this.resizeEl) {
23906 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
23907 // should trigger onReize..
23913 onResize : function(w, h)
23915 Roo.log('resize: ' +w + ',' + h );
23916 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
23920 if(this.inputEl() ){
23921 if(typeof w == 'number'){
23922 var aw = w - this.wrap.getFrameWidth('lr');
23923 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
23926 if(typeof h == 'number'){
23927 var tbh = -11; // fixme it needs to tool bar size!
23928 for (var i =0; i < this.toolbars.length;i++) {
23929 // fixme - ask toolbars for heights?
23930 tbh += this.toolbars[i].el.getHeight();
23931 //if (this.toolbars[i].footer) {
23932 // tbh += this.toolbars[i].footer.el.getHeight();
23940 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
23941 ah -= 5; // knock a few pixes off for look..
23942 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
23946 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
23947 this.editorcore.onResize(ew,eh);
23952 * Toggles the editor between standard and source edit mode.
23953 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
23955 toggleSourceEdit : function(sourceEditMode)
23957 this.editorcore.toggleSourceEdit(sourceEditMode);
23959 if(this.editorcore.sourceEditMode){
23960 Roo.log('editor - showing textarea');
23963 // Roo.log(this.syncValue());
23965 this.inputEl().removeClass(['hide', 'x-hidden']);
23966 this.inputEl().dom.removeAttribute('tabIndex');
23967 this.inputEl().focus();
23969 Roo.log('editor - hiding textarea');
23971 // Roo.log(this.pushValue());
23974 this.inputEl().addClass(['hide', 'x-hidden']);
23975 this.inputEl().dom.setAttribute('tabIndex', -1);
23976 //this.deferFocus();
23979 if(this.resizable){
23980 this.setSize(this.wrap.getSize());
23983 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
23986 // private (for BoxComponent)
23987 adjustSize : Roo.BoxComponent.prototype.adjustSize,
23989 // private (for BoxComponent)
23990 getResizeEl : function(){
23994 // private (for BoxComponent)
23995 getPositionEl : function(){
24000 initEvents : function(){
24001 this.originalValue = this.getValue();
24005 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
24008 // markInvalid : Roo.emptyFn,
24010 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
24013 // clearInvalid : Roo.emptyFn,
24015 setValue : function(v){
24016 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
24017 this.editorcore.pushValue();
24022 deferFocus : function(){
24023 this.focus.defer(10, this);
24027 focus : function(){
24028 this.editorcore.focus();
24034 onDestroy : function(){
24040 for (var i =0; i < this.toolbars.length;i++) {
24041 // fixme - ask toolbars for heights?
24042 this.toolbars[i].onDestroy();
24045 this.wrap.dom.innerHTML = '';
24046 this.wrap.remove();
24051 onFirstFocus : function(){
24052 //Roo.log("onFirstFocus");
24053 this.editorcore.onFirstFocus();
24054 for (var i =0; i < this.toolbars.length;i++) {
24055 this.toolbars[i].onFirstFocus();
24061 syncValue : function()
24063 this.editorcore.syncValue();
24066 pushValue : function()
24068 this.editorcore.pushValue();
24072 // hide stuff that is not compatible
24086 * @event specialkey
24090 * @cfg {String} fieldClass @hide
24093 * @cfg {String} focusClass @hide
24096 * @cfg {String} autoCreate @hide
24099 * @cfg {String} inputType @hide
24103 * @cfg {String} invalidText @hide
24106 * @cfg {String} msgFx @hide
24109 * @cfg {String} validateOnBlur @hide
24118 Roo.namespace('Roo.bootstrap.htmleditor');
24120 * @class Roo.bootstrap.HtmlEditorToolbar1
24126 new Roo.bootstrap.HtmlEditor({
24129 new Roo.bootstrap.HtmlEditorToolbar1({
24130 disable : { fonts: 1 , format: 1, ..., ... , ...],
24136 * @cfg {Object} disable List of elements to disable..
24137 * @cfg {Array} btns List of additional buttons.
24141 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
24144 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
24147 Roo.apply(this, config);
24149 // default disabled, based on 'good practice'..
24150 this.disable = this.disable || {};
24151 Roo.applyIf(this.disable, {
24154 specialElements : true
24156 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
24158 this.editor = config.editor;
24159 this.editorcore = config.editor.editorcore;
24161 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
24163 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
24164 // dont call parent... till later.
24166 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
24171 editorcore : false,
24176 "h1","h2","h3","h4","h5","h6",
24178 "abbr", "acronym", "address", "cite", "samp", "var",
24182 onRender : function(ct, position)
24184 // Roo.log("Call onRender: " + this.xtype);
24186 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
24188 this.el.dom.style.marginBottom = '0';
24190 var editorcore = this.editorcore;
24191 var editor= this.editor;
24194 var btn = function(id,cmd , toggle, handler, html){
24196 var event = toggle ? 'toggle' : 'click';
24201 xns: Roo.bootstrap,
24205 enableToggle:toggle !== false,
24207 pressed : toggle ? false : null,
24210 a.listeners[toggle ? 'toggle' : 'click'] = function() {
24211 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
24217 // var cb_box = function...
24222 xns: Roo.bootstrap,
24227 xns: Roo.bootstrap,
24231 Roo.each(this.formats, function(f) {
24232 style.menu.items.push({
24234 xns: Roo.bootstrap,
24235 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
24240 editorcore.insertTag(this.tagname);
24247 children.push(style);
24249 btn('bold',false,true);
24250 btn('italic',false,true);
24251 btn('align-left', 'justifyleft',true);
24252 btn('align-center', 'justifycenter',true);
24253 btn('align-right' , 'justifyright',true);
24254 btn('link', false, false, function(btn) {
24255 //Roo.log("create link?");
24256 var url = prompt(this.createLinkText, this.defaultLinkValue);
24257 if(url && url != 'http:/'+'/'){
24258 this.editorcore.relayCmd('createlink', url);
24261 btn('list','insertunorderedlist',true);
24262 btn('pencil', false,true, function(btn){
24264 this.toggleSourceEdit(btn.pressed);
24267 if (this.editor.btns.length > 0) {
24268 for (var i = 0; i<this.editor.btns.length; i++) {
24269 children.push(this.editor.btns[i]);
24277 xns: Roo.bootstrap,
24282 xns: Roo.bootstrap,
24287 cog.menu.items.push({
24289 xns: Roo.bootstrap,
24290 html : Clean styles,
24295 editorcore.insertTag(this.tagname);
24304 this.xtype = 'NavSimplebar';
24306 for(var i=0;i< children.length;i++) {
24308 this.buttons.add(this.addxtypeChild(children[i]));
24312 editor.on('editorevent', this.updateToolbar, this);
24314 onBtnClick : function(id)
24316 this.editorcore.relayCmd(id);
24317 this.editorcore.focus();
24321 * Protected method that will not generally be called directly. It triggers
24322 * a toolbar update by reading the markup state of the current selection in the editor.
24324 updateToolbar: function(){
24326 if(!this.editorcore.activated){
24327 this.editor.onFirstFocus(); // is this neeed?
24331 var btns = this.buttons;
24332 var doc = this.editorcore.doc;
24333 btns.get('bold').setActive(doc.queryCommandState('bold'));
24334 btns.get('italic').setActive(doc.queryCommandState('italic'));
24335 //btns.get('underline').setActive(doc.queryCommandState('underline'));
24337 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
24338 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
24339 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
24341 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
24342 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
24345 var ans = this.editorcore.getAllAncestors();
24346 if (this.formatCombo) {
24349 var store = this.formatCombo.store;
24350 this.formatCombo.setValue("");
24351 for (var i =0; i < ans.length;i++) {
24352 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
24354 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
24362 // hides menus... - so this cant be on a menu...
24363 Roo.bootstrap.MenuMgr.hideAll();
24365 Roo.bootstrap.MenuMgr.hideAll();
24366 //this.editorsyncValue();
24368 onFirstFocus: function() {
24369 this.buttons.each(function(item){
24373 toggleSourceEdit : function(sourceEditMode){
24376 if(sourceEditMode){
24377 Roo.log("disabling buttons");
24378 this.buttons.each( function(item){
24379 if(item.cmd != 'pencil'){
24385 Roo.log("enabling buttons");
24386 if(this.editorcore.initialized){
24387 this.buttons.each( function(item){
24393 Roo.log("calling toggole on editor");
24394 // tell the editor that it's been pressed..
24395 this.editor.toggleSourceEdit(sourceEditMode);
24405 * @class Roo.bootstrap.Table.AbstractSelectionModel
24406 * @extends Roo.util.Observable
24407 * Abstract base class for grid SelectionModels. It provides the interface that should be
24408 * implemented by descendant classes. This class should not be directly instantiated.
24411 Roo.bootstrap.Table.AbstractSelectionModel = function(){
24412 this.locked = false;
24413 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
24417 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
24418 /** @ignore Called by the grid automatically. Do not call directly. */
24419 init : function(grid){
24425 * Locks the selections.
24428 this.locked = true;
24432 * Unlocks the selections.
24434 unlock : function(){
24435 this.locked = false;
24439 * Returns true if the selections are locked.
24440 * @return {Boolean}
24442 isLocked : function(){
24443 return this.locked;
24447 * @extends Roo.bootstrap.Table.AbstractSelectionModel
24448 * @class Roo.bootstrap.Table.RowSelectionModel
24449 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
24450 * It supports multiple selections and keyboard selection/navigation.
24452 * @param {Object} config
24455 Roo.bootstrap.Table.RowSelectionModel = function(config){
24456 Roo.apply(this, config);
24457 this.selections = new Roo.util.MixedCollection(false, function(o){
24462 this.lastActive = false;
24466 * @event selectionchange
24467 * Fires when the selection changes
24468 * @param {SelectionModel} this
24470 "selectionchange" : true,
24472 * @event afterselectionchange
24473 * Fires after the selection changes (eg. by key press or clicking)
24474 * @param {SelectionModel} this
24476 "afterselectionchange" : true,
24478 * @event beforerowselect
24479 * Fires when a row is selected being selected, return false to cancel.
24480 * @param {SelectionModel} this
24481 * @param {Number} rowIndex The selected index
24482 * @param {Boolean} keepExisting False if other selections will be cleared
24484 "beforerowselect" : true,
24487 * Fires when a row is selected.
24488 * @param {SelectionModel} this
24489 * @param {Number} rowIndex The selected index
24490 * @param {Roo.data.Record} r The record
24492 "rowselect" : true,
24494 * @event rowdeselect
24495 * Fires when a row is deselected.
24496 * @param {SelectionModel} this
24497 * @param {Number} rowIndex The selected index
24499 "rowdeselect" : true
24501 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
24502 this.locked = false;
24505 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
24507 * @cfg {Boolean} singleSelect
24508 * True to allow selection of only one row at a time (defaults to false)
24510 singleSelect : false,
24513 initEvents : function()
24516 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
24517 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
24518 //}else{ // allow click to work like normal
24519 // this.grid.on("rowclick", this.handleDragableRowClick, this);
24521 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
24522 this.grid.on("rowclick", this.handleMouseDown, this);
24524 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
24525 "up" : function(e){
24527 this.selectPrevious(e.shiftKey);
24528 }else if(this.last !== false && this.lastActive !== false){
24529 var last = this.last;
24530 this.selectRange(this.last, this.lastActive-1);
24531 this.grid.getView().focusRow(this.lastActive);
24532 if(last !== false){
24536 this.selectFirstRow();
24538 this.fireEvent("afterselectionchange", this);
24540 "down" : function(e){
24542 this.selectNext(e.shiftKey);
24543 }else if(this.last !== false && this.lastActive !== false){
24544 var last = this.last;
24545 this.selectRange(this.last, this.lastActive+1);
24546 this.grid.getView().focusRow(this.lastActive);
24547 if(last !== false){
24551 this.selectFirstRow();
24553 this.fireEvent("afterselectionchange", this);
24557 this.grid.store.on('load', function(){
24558 this.selections.clear();
24561 var view = this.grid.view;
24562 view.on("refresh", this.onRefresh, this);
24563 view.on("rowupdated", this.onRowUpdated, this);
24564 view.on("rowremoved", this.onRemove, this);
24569 onRefresh : function()
24571 var ds = this.grid.store, i, v = this.grid.view;
24572 var s = this.selections;
24573 s.each(function(r){
24574 if((i = ds.indexOfId(r.id)) != -1){
24583 onRemove : function(v, index, r){
24584 this.selections.remove(r);
24588 onRowUpdated : function(v, index, r){
24589 if(this.isSelected(r)){
24590 v.onRowSelect(index);
24596 * @param {Array} records The records to select
24597 * @param {Boolean} keepExisting (optional) True to keep existing selections
24599 selectRecords : function(records, keepExisting)
24602 this.clearSelections();
24604 var ds = this.grid.store;
24605 for(var i = 0, len = records.length; i < len; i++){
24606 this.selectRow(ds.indexOf(records[i]), true);
24611 * Gets the number of selected rows.
24614 getCount : function(){
24615 return this.selections.length;
24619 * Selects the first row in the grid.
24621 selectFirstRow : function(){
24626 * Select the last row.
24627 * @param {Boolean} keepExisting (optional) True to keep existing selections
24629 selectLastRow : function(keepExisting){
24630 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
24631 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
24635 * Selects the row immediately following the last selected row.
24636 * @param {Boolean} keepExisting (optional) True to keep existing selections
24638 selectNext : function(keepExisting)
24640 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
24641 this.selectRow(this.last+1, keepExisting);
24642 this.grid.getView().focusRow(this.last);
24647 * Selects the row that precedes the last selected row.
24648 * @param {Boolean} keepExisting (optional) True to keep existing selections
24650 selectPrevious : function(keepExisting){
24652 this.selectRow(this.last-1, keepExisting);
24653 this.grid.getView().focusRow(this.last);
24658 * Returns the selected records
24659 * @return {Array} Array of selected records
24661 getSelections : function(){
24662 return [].concat(this.selections.items);
24666 * Returns the first selected record.
24669 getSelected : function(){
24670 return this.selections.itemAt(0);
24675 * Clears all selections.
24677 clearSelections : function(fast)
24683 var ds = this.grid.store;
24684 var s = this.selections;
24685 s.each(function(r){
24686 this.deselectRow(ds.indexOfId(r.id));
24690 this.selections.clear();
24697 * Selects all rows.
24699 selectAll : function(){
24703 this.selections.clear();
24704 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
24705 this.selectRow(i, true);
24710 * Returns True if there is a selection.
24711 * @return {Boolean}
24713 hasSelection : function(){
24714 return this.selections.length > 0;
24718 * Returns True if the specified row is selected.
24719 * @param {Number/Record} record The record or index of the record to check
24720 * @return {Boolean}
24722 isSelected : function(index){
24723 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
24724 return (r && this.selections.key(r.id) ? true : false);
24728 * Returns True if the specified record id is selected.
24729 * @param {String} id The id of record to check
24730 * @return {Boolean}
24732 isIdSelected : function(id){
24733 return (this.selections.key(id) ? true : false);
24738 handleMouseDBClick : function(e, t){
24742 handleMouseDown : function(e, t)
24744 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
24745 if(this.isLocked() || rowIndex < 0 ){
24748 if(e.shiftKey && this.last !== false){
24749 var last = this.last;
24750 this.selectRange(last, rowIndex, e.ctrlKey);
24751 this.last = last; // reset the last
24755 var isSelected = this.isSelected(rowIndex);
24756 //Roo.log("select row:" + rowIndex);
24758 this.deselectRow(rowIndex);
24760 this.selectRow(rowIndex, true);
24764 if(e.button !== 0 && isSelected){
24765 alert('rowIndex 2: ' + rowIndex);
24766 view.focusRow(rowIndex);
24767 }else if(e.ctrlKey && isSelected){
24768 this.deselectRow(rowIndex);
24769 }else if(!isSelected){
24770 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
24771 view.focusRow(rowIndex);
24775 this.fireEvent("afterselectionchange", this);
24778 handleDragableRowClick : function(grid, rowIndex, e)
24780 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
24781 this.selectRow(rowIndex, false);
24782 grid.view.focusRow(rowIndex);
24783 this.fireEvent("afterselectionchange", this);
24788 * Selects multiple rows.
24789 * @param {Array} rows Array of the indexes of the row to select
24790 * @param {Boolean} keepExisting (optional) True to keep existing selections
24792 selectRows : function(rows, keepExisting){
24794 this.clearSelections();
24796 for(var i = 0, len = rows.length; i < len; i++){
24797 this.selectRow(rows[i], true);
24802 * Selects a range of rows. All rows in between startRow and endRow are also selected.
24803 * @param {Number} startRow The index of the first row in the range
24804 * @param {Number} endRow The index of the last row in the range
24805 * @param {Boolean} keepExisting (optional) True to retain existing selections
24807 selectRange : function(startRow, endRow, keepExisting){
24812 this.clearSelections();
24814 if(startRow <= endRow){
24815 for(var i = startRow; i <= endRow; i++){
24816 this.selectRow(i, true);
24819 for(var i = startRow; i >= endRow; i--){
24820 this.selectRow(i, true);
24826 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
24827 * @param {Number} startRow The index of the first row in the range
24828 * @param {Number} endRow The index of the last row in the range
24830 deselectRange : function(startRow, endRow, preventViewNotify){
24834 for(var i = startRow; i <= endRow; i++){
24835 this.deselectRow(i, preventViewNotify);
24841 * @param {Number} row The index of the row to select
24842 * @param {Boolean} keepExisting (optional) True to keep existing selections
24844 selectRow : function(index, keepExisting, preventViewNotify)
24846 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
24849 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
24850 if(!keepExisting || this.singleSelect){
24851 this.clearSelections();
24854 var r = this.grid.store.getAt(index);
24855 //console.log('selectRow - record id :' + r.id);
24857 this.selections.add(r);
24858 this.last = this.lastActive = index;
24859 if(!preventViewNotify){
24860 var proxy = new Roo.Element(
24861 this.grid.getRowDom(index)
24863 proxy.addClass('bg-info info');
24865 this.fireEvent("rowselect", this, index, r);
24866 this.fireEvent("selectionchange", this);
24872 * @param {Number} row The index of the row to deselect
24874 deselectRow : function(index, preventViewNotify)
24879 if(this.last == index){
24882 if(this.lastActive == index){
24883 this.lastActive = false;
24886 var r = this.grid.store.getAt(index);
24891 this.selections.remove(r);
24892 //.console.log('deselectRow - record id :' + r.id);
24893 if(!preventViewNotify){
24895 var proxy = new Roo.Element(
24896 this.grid.getRowDom(index)
24898 proxy.removeClass('bg-info info');
24900 this.fireEvent("rowdeselect", this, index);
24901 this.fireEvent("selectionchange", this);
24905 restoreLast : function(){
24907 this.last = this._last;
24912 acceptsNav : function(row, col, cm){
24913 return !cm.isHidden(col) && cm.isCellEditable(col, row);
24917 onEditorKey : function(field, e){
24918 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
24923 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
24925 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
24927 }else if(k == e.ENTER && !e.ctrlKey){
24931 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
24933 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
24935 }else if(k == e.ESC){
24939 g.startEditing(newCell[0], newCell[1]);
24945 * Ext JS Library 1.1.1
24946 * Copyright(c) 2006-2007, Ext JS, LLC.
24948 * Originally Released Under LGPL - original licence link has changed is not relivant.
24951 * <script type="text/javascript">
24955 * @class Roo.bootstrap.PagingToolbar
24956 * @extends Roo.bootstrap.NavSimplebar
24957 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
24959 * Create a new PagingToolbar
24960 * @param {Object} config The config object
24961 * @param {Roo.data.Store} store
24963 Roo.bootstrap.PagingToolbar = function(config)
24965 // old args format still supported... - xtype is prefered..
24966 // created from xtype...
24968 this.ds = config.dataSource;
24970 if (config.store && !this.ds) {
24971 this.store= Roo.factory(config.store, Roo.data);
24972 this.ds = this.store;
24973 this.ds.xmodule = this.xmodule || false;
24976 this.toolbarItems = [];
24977 if (config.items) {
24978 this.toolbarItems = config.items;
24981 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
24986 this.bind(this.ds);
24989 if (Roo.bootstrap.version == 4) {
24990 this.navgroup = new Roo.bootstrap.ButtonGroup({ cls: 'pagination' });
24992 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
24997 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
24999 * @cfg {Roo.data.Store} dataSource
25000 * The underlying data store providing the paged data
25003 * @cfg {String/HTMLElement/Element} container
25004 * container The id or element that will contain the toolbar
25007 * @cfg {Boolean} displayInfo
25008 * True to display the displayMsg (defaults to false)
25011 * @cfg {Number} pageSize
25012 * The number of records to display per page (defaults to 20)
25016 * @cfg {String} displayMsg
25017 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
25019 displayMsg : 'Displaying {0} - {1} of {2}',
25021 * @cfg {String} emptyMsg
25022 * The message to display when no records are found (defaults to "No data to display")
25024 emptyMsg : 'No data to display',
25026 * Customizable piece of the default paging text (defaults to "Page")
25029 beforePageText : "Page",
25031 * Customizable piece of the default paging text (defaults to "of %0")
25034 afterPageText : "of {0}",
25036 * Customizable piece of the default paging text (defaults to "First Page")
25039 firstText : "First Page",
25041 * Customizable piece of the default paging text (defaults to "Previous Page")
25044 prevText : "Previous Page",
25046 * Customizable piece of the default paging text (defaults to "Next Page")
25049 nextText : "Next Page",
25051 * Customizable piece of the default paging text (defaults to "Last Page")
25054 lastText : "Last Page",
25056 * Customizable piece of the default paging text (defaults to "Refresh")
25059 refreshText : "Refresh",
25063 onRender : function(ct, position)
25065 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
25066 this.navgroup.parentId = this.id;
25067 this.navgroup.onRender(this.el, null);
25068 // add the buttons to the navgroup
25070 if(this.displayInfo){
25071 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
25072 this.displayEl = this.el.select('.x-paging-info', true).first();
25073 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
25074 // this.displayEl = navel.el.select('span',true).first();
25080 Roo.each(_this.buttons, function(e){ // this might need to use render????
25081 Roo.factory(e).render(_this.el);
25085 Roo.each(_this.toolbarItems, function(e) {
25086 _this.navgroup.addItem(e);
25090 this.first = this.navgroup.addItem({
25091 tooltip: this.firstText,
25092 cls: "prev btn-outline-secondary",
25093 html : ' <i class="fa fa-step-backward"></i>',
25095 preventDefault: true,
25096 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
25099 this.prev = this.navgroup.addItem({
25100 tooltip: this.prevText,
25101 cls: "prev btn-outline-secondary",
25102 html : ' <i class="fa fa-backward"></i>',
25104 preventDefault: true,
25105 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
25107 //this.addSeparator();
25110 var field = this.navgroup.addItem( {
25112 cls : 'x-paging-position btn-outline-secondary',
25114 html : this.beforePageText +
25115 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
25116 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
25119 this.field = field.el.select('input', true).first();
25120 this.field.on("keydown", this.onPagingKeydown, this);
25121 this.field.on("focus", function(){this.dom.select();});
25124 this.afterTextEl = field.el.select('.x-paging-after',true).first();
25125 //this.field.setHeight(18);
25126 //this.addSeparator();
25127 this.next = this.navgroup.addItem({
25128 tooltip: this.nextText,
25129 cls: "next btn-outline-secondary",
25130 html : ' <i class="fa fa-forward"></i>',
25132 preventDefault: true,
25133 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
25135 this.last = this.navgroup.addItem({
25136 tooltip: this.lastText,
25137 html : ' <i class="fa fa-step-forward"></i>',
25138 cls: "next btn-outline-secondary",
25140 preventDefault: true,
25141 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
25143 //this.addSeparator();
25144 this.loading = this.navgroup.addItem({
25145 tooltip: this.refreshText,
25146 cls: "btn-outline-secondary",
25147 html : ' <i class="fa fa-refresh"></i>',
25148 preventDefault: true,
25149 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
25155 updateInfo : function(){
25156 if(this.displayEl){
25157 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
25158 var msg = count == 0 ?
25162 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
25164 this.displayEl.update(msg);
25169 onLoad : function(ds, r, o)
25171 this.cursor = o.params.start ? o.params.start : 0;
25173 var d = this.getPageData(),
25178 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
25179 this.field.dom.value = ap;
25180 this.first.setDisabled(ap == 1);
25181 this.prev.setDisabled(ap == 1);
25182 this.next.setDisabled(ap == ps);
25183 this.last.setDisabled(ap == ps);
25184 this.loading.enable();
25189 getPageData : function(){
25190 var total = this.ds.getTotalCount();
25193 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
25194 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
25199 onLoadError : function(){
25200 this.loading.enable();
25204 onPagingKeydown : function(e){
25205 var k = e.getKey();
25206 var d = this.getPageData();
25208 var v = this.field.dom.value, pageNum;
25209 if(!v || isNaN(pageNum = parseInt(v, 10))){
25210 this.field.dom.value = d.activePage;
25213 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
25214 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
25217 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))
25219 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
25220 this.field.dom.value = pageNum;
25221 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
25224 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
25226 var v = this.field.dom.value, pageNum;
25227 var increment = (e.shiftKey) ? 10 : 1;
25228 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
25231 if(!v || isNaN(pageNum = parseInt(v, 10))) {
25232 this.field.dom.value = d.activePage;
25235 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
25237 this.field.dom.value = parseInt(v, 10) + increment;
25238 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
25239 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
25246 beforeLoad : function(){
25248 this.loading.disable();
25253 onClick : function(which){
25262 ds.load({params:{start: 0, limit: this.pageSize}});
25265 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
25268 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
25271 var total = ds.getTotalCount();
25272 var extra = total % this.pageSize;
25273 var lastStart = extra ? (total - extra) : total-this.pageSize;
25274 ds.load({params:{start: lastStart, limit: this.pageSize}});
25277 ds.load({params:{start: this.cursor, limit: this.pageSize}});
25283 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
25284 * @param {Roo.data.Store} store The data store to unbind
25286 unbind : function(ds){
25287 ds.un("beforeload", this.beforeLoad, this);
25288 ds.un("load", this.onLoad, this);
25289 ds.un("loadexception", this.onLoadError, this);
25290 ds.un("remove", this.updateInfo, this);
25291 ds.un("add", this.updateInfo, this);
25292 this.ds = undefined;
25296 * Binds the paging toolbar to the specified {@link Roo.data.Store}
25297 * @param {Roo.data.Store} store The data store to bind
25299 bind : function(ds){
25300 ds.on("beforeload", this.beforeLoad, this);
25301 ds.on("load", this.onLoad, this);
25302 ds.on("loadexception", this.onLoadError, this);
25303 ds.on("remove", this.updateInfo, this);
25304 ds.on("add", this.updateInfo, this);
25315 * @class Roo.bootstrap.MessageBar
25316 * @extends Roo.bootstrap.Component
25317 * Bootstrap MessageBar class
25318 * @cfg {String} html contents of the MessageBar
25319 * @cfg {String} weight (info | success | warning | danger) default info
25320 * @cfg {String} beforeClass insert the bar before the given class
25321 * @cfg {Boolean} closable (true | false) default false
25322 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
25325 * Create a new Element
25326 * @param {Object} config The config object
25329 Roo.bootstrap.MessageBar = function(config){
25330 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
25333 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
25339 beforeClass: 'bootstrap-sticky-wrap',
25341 getAutoCreate : function(){
25345 cls: 'alert alert-dismissable alert-' + this.weight,
25350 html: this.html || ''
25356 cfg.cls += ' alert-messages-fixed';
25370 onRender : function(ct, position)
25372 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
25375 var cfg = Roo.apply({}, this.getAutoCreate());
25379 cfg.cls += ' ' + this.cls;
25382 cfg.style = this.style;
25384 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
25386 this.el.setVisibilityMode(Roo.Element.DISPLAY);
25389 this.el.select('>button.close').on('click', this.hide, this);
25395 if (!this.rendered) {
25401 this.fireEvent('show', this);
25407 if (!this.rendered) {
25413 this.fireEvent('hide', this);
25416 update : function()
25418 // var e = this.el.dom.firstChild;
25420 // if(this.closable){
25421 // e = e.nextSibling;
25424 // e.data = this.html || '';
25426 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
25442 * @class Roo.bootstrap.Graph
25443 * @extends Roo.bootstrap.Component
25444 * Bootstrap Graph class
25448 @cfg {String} graphtype bar | vbar | pie
25449 @cfg {number} g_x coodinator | centre x (pie)
25450 @cfg {number} g_y coodinator | centre y (pie)
25451 @cfg {number} g_r radius (pie)
25452 @cfg {number} g_height height of the chart (respected by all elements in the set)
25453 @cfg {number} g_width width of the chart (respected by all elements in the set)
25454 @cfg {Object} title The title of the chart
25457 -opts (object) options for the chart
25459 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
25460 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
25462 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.
25463 o stacked (boolean) whether or not to tread values as in a stacked bar chart
25465 o stretch (boolean)
25467 -opts (object) options for the pie
25470 o startAngle (number)
25471 o endAngle (number)
25475 * Create a new Input
25476 * @param {Object} config The config object
25479 Roo.bootstrap.Graph = function(config){
25480 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
25486 * The img click event for the img.
25487 * @param {Roo.EventObject} e
25493 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
25504 //g_colors: this.colors,
25511 getAutoCreate : function(){
25522 onRender : function(ct,position){
25525 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
25527 if (typeof(Raphael) == 'undefined') {
25528 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
25532 this.raphael = Raphael(this.el.dom);
25534 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25535 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25536 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25537 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
25539 r.text(160, 10, "Single Series Chart").attr(txtattr);
25540 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
25541 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
25542 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
25544 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
25545 r.barchart(330, 10, 300, 220, data1);
25546 r.barchart(10, 250, 300, 220, data2, {stacked: true});
25547 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
25550 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25551 // r.barchart(30, 30, 560, 250, xdata, {
25552 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
25553 // axis : "0 0 1 1",
25554 // axisxlabels : xdata
25555 // //yvalues : cols,
25558 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25560 // this.load(null,xdata,{
25561 // axis : "0 0 1 1",
25562 // axisxlabels : xdata
25567 load : function(graphtype,xdata,opts)
25569 this.raphael.clear();
25571 graphtype = this.graphtype;
25576 var r = this.raphael,
25577 fin = function () {
25578 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
25580 fout = function () {
25581 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
25583 pfin = function() {
25584 this.sector.stop();
25585 this.sector.scale(1.1, 1.1, this.cx, this.cy);
25588 this.label[0].stop();
25589 this.label[0].attr({ r: 7.5 });
25590 this.label[1].attr({ "font-weight": 800 });
25593 pfout = function() {
25594 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
25597 this.label[0].animate({ r: 5 }, 500, "bounce");
25598 this.label[1].attr({ "font-weight": 400 });
25604 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25607 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25610 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
25611 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
25613 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
25620 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
25625 setTitle: function(o)
25630 initEvents: function() {
25633 this.el.on('click', this.onClick, this);
25637 onClick : function(e)
25639 Roo.log('img onclick');
25640 this.fireEvent('click', this, e);
25652 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25655 * @class Roo.bootstrap.dash.NumberBox
25656 * @extends Roo.bootstrap.Component
25657 * Bootstrap NumberBox class
25658 * @cfg {String} headline Box headline
25659 * @cfg {String} content Box content
25660 * @cfg {String} icon Box icon
25661 * @cfg {String} footer Footer text
25662 * @cfg {String} fhref Footer href
25665 * Create a new NumberBox
25666 * @param {Object} config The config object
25670 Roo.bootstrap.dash.NumberBox = function(config){
25671 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
25675 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
25684 getAutoCreate : function(){
25688 cls : 'small-box ',
25696 cls : 'roo-headline',
25697 html : this.headline
25701 cls : 'roo-content',
25702 html : this.content
25716 cls : 'ion ' + this.icon
25725 cls : 'small-box-footer',
25726 href : this.fhref || '#',
25730 cfg.cn.push(footer);
25737 onRender : function(ct,position){
25738 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
25745 setHeadline: function (value)
25747 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
25750 setFooter: function (value, href)
25752 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
25755 this.el.select('a.small-box-footer',true).first().attr('href', href);
25760 setContent: function (value)
25762 this.el.select('.roo-content',true).first().dom.innerHTML = value;
25765 initEvents: function()
25779 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25782 * @class Roo.bootstrap.dash.TabBox
25783 * @extends Roo.bootstrap.Component
25784 * Bootstrap TabBox class
25785 * @cfg {String} title Title of the TabBox
25786 * @cfg {String} icon Icon of the TabBox
25787 * @cfg {Boolean} showtabs (true|false) show the tabs default true
25788 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
25791 * Create a new TabBox
25792 * @param {Object} config The config object
25796 Roo.bootstrap.dash.TabBox = function(config){
25797 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
25802 * When a pane is added
25803 * @param {Roo.bootstrap.dash.TabPane} pane
25807 * @event activatepane
25808 * When a pane is activated
25809 * @param {Roo.bootstrap.dash.TabPane} pane
25811 "activatepane" : true
25819 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
25824 tabScrollable : false,
25826 getChildContainer : function()
25828 return this.el.select('.tab-content', true).first();
25831 getAutoCreate : function(){
25835 cls: 'pull-left header',
25843 cls: 'fa ' + this.icon
25849 cls: 'nav nav-tabs pull-right',
25855 if(this.tabScrollable){
25862 cls: 'nav nav-tabs pull-right',
25873 cls: 'nav-tabs-custom',
25878 cls: 'tab-content no-padding',
25886 initEvents : function()
25888 //Roo.log('add add pane handler');
25889 this.on('addpane', this.onAddPane, this);
25892 * Updates the box title
25893 * @param {String} html to set the title to.
25895 setTitle : function(value)
25897 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
25899 onAddPane : function(pane)
25901 this.panes.push(pane);
25902 //Roo.log('addpane');
25904 // tabs are rendere left to right..
25905 if(!this.showtabs){
25909 var ctr = this.el.select('.nav-tabs', true).first();
25912 var existing = ctr.select('.nav-tab',true);
25913 var qty = existing.getCount();;
25916 var tab = ctr.createChild({
25918 cls : 'nav-tab' + (qty ? '' : ' active'),
25926 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
25929 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
25931 pane.el.addClass('active');
25936 onTabClick : function(ev,un,ob,pane)
25938 //Roo.log('tab - prev default');
25939 ev.preventDefault();
25942 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
25943 pane.tab.addClass('active');
25944 //Roo.log(pane.title);
25945 this.getChildContainer().select('.tab-pane',true).removeClass('active');
25946 // technically we should have a deactivate event.. but maybe add later.
25947 // and it should not de-activate the selected tab...
25948 this.fireEvent('activatepane', pane);
25949 pane.el.addClass('active');
25950 pane.fireEvent('activate');
25955 getActivePane : function()
25958 Roo.each(this.panes, function(p) {
25959 if(p.el.hasClass('active')){
25980 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25982 * @class Roo.bootstrap.TabPane
25983 * @extends Roo.bootstrap.Component
25984 * Bootstrap TabPane class
25985 * @cfg {Boolean} active (false | true) Default false
25986 * @cfg {String} title title of panel
25990 * Create a new TabPane
25991 * @param {Object} config The config object
25994 Roo.bootstrap.dash.TabPane = function(config){
25995 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
26001 * When a pane is activated
26002 * @param {Roo.bootstrap.dash.TabPane} pane
26009 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
26014 // the tabBox that this is attached to.
26017 getAutoCreate : function()
26025 cfg.cls += ' active';
26030 initEvents : function()
26032 //Roo.log('trigger add pane handler');
26033 this.parent().fireEvent('addpane', this)
26037 * Updates the tab title
26038 * @param {String} html to set the title to.
26040 setTitle: function(str)
26046 this.tab.select('a', true).first().dom.innerHTML = str;
26063 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
26066 * @class Roo.bootstrap.menu.Menu
26067 * @extends Roo.bootstrap.Component
26068 * Bootstrap Menu class - container for Menu
26069 * @cfg {String} html Text of the menu
26070 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
26071 * @cfg {String} icon Font awesome icon
26072 * @cfg {String} pos Menu align to (top | bottom) default bottom
26076 * Create a new Menu
26077 * @param {Object} config The config object
26081 Roo.bootstrap.menu.Menu = function(config){
26082 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
26086 * @event beforeshow
26087 * Fires before this menu is displayed
26088 * @param {Roo.bootstrap.menu.Menu} this
26092 * @event beforehide
26093 * Fires before this menu is hidden
26094 * @param {Roo.bootstrap.menu.Menu} this
26099 * Fires after this menu is displayed
26100 * @param {Roo.bootstrap.menu.Menu} this
26105 * Fires after this menu is hidden
26106 * @param {Roo.bootstrap.menu.Menu} this
26111 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
26112 * @param {Roo.bootstrap.menu.Menu} this
26113 * @param {Roo.EventObject} e
26120 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
26124 weight : 'default',
26129 getChildContainer : function() {
26130 if(this.isSubMenu){
26134 return this.el.select('ul.dropdown-menu', true).first();
26137 getAutoCreate : function()
26142 cls : 'roo-menu-text',
26150 cls : 'fa ' + this.icon
26161 cls : 'dropdown-button btn btn-' + this.weight,
26166 cls : 'dropdown-toggle btn btn-' + this.weight,
26176 cls : 'dropdown-menu'
26182 if(this.pos == 'top'){
26183 cfg.cls += ' dropup';
26186 if(this.isSubMenu){
26189 cls : 'dropdown-menu'
26196 onRender : function(ct, position)
26198 this.isSubMenu = ct.hasClass('dropdown-submenu');
26200 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
26203 initEvents : function()
26205 if(this.isSubMenu){
26209 this.hidden = true;
26211 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
26212 this.triggerEl.on('click', this.onTriggerPress, this);
26214 this.buttonEl = this.el.select('button.dropdown-button', true).first();
26215 this.buttonEl.on('click', this.onClick, this);
26221 if(this.isSubMenu){
26225 return this.el.select('ul.dropdown-menu', true).first();
26228 onClick : function(e)
26230 this.fireEvent("click", this, e);
26233 onTriggerPress : function(e)
26235 if (this.isVisible()) {
26242 isVisible : function(){
26243 return !this.hidden;
26248 this.fireEvent("beforeshow", this);
26250 this.hidden = false;
26251 this.el.addClass('open');
26253 Roo.get(document).on("mouseup", this.onMouseUp, this);
26255 this.fireEvent("show", this);
26262 this.fireEvent("beforehide", this);
26264 this.hidden = true;
26265 this.el.removeClass('open');
26267 Roo.get(document).un("mouseup", this.onMouseUp);
26269 this.fireEvent("hide", this);
26272 onMouseUp : function()
26286 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
26289 * @class Roo.bootstrap.menu.Item
26290 * @extends Roo.bootstrap.Component
26291 * Bootstrap MenuItem class
26292 * @cfg {Boolean} submenu (true | false) default false
26293 * @cfg {String} html text of the item
26294 * @cfg {String} href the link
26295 * @cfg {Boolean} disable (true | false) default false
26296 * @cfg {Boolean} preventDefault (true | false) default true
26297 * @cfg {String} icon Font awesome icon
26298 * @cfg {String} pos Submenu align to (left | right) default right
26302 * Create a new Item
26303 * @param {Object} config The config object
26307 Roo.bootstrap.menu.Item = function(config){
26308 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
26312 * Fires when the mouse is hovering over this menu
26313 * @param {Roo.bootstrap.menu.Item} this
26314 * @param {Roo.EventObject} e
26319 * Fires when the mouse exits this menu
26320 * @param {Roo.bootstrap.menu.Item} this
26321 * @param {Roo.EventObject} e
26327 * The raw click event for the entire grid.
26328 * @param {Roo.EventObject} e
26334 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
26339 preventDefault: true,
26344 getAutoCreate : function()
26349 cls : 'roo-menu-item-text',
26357 cls : 'fa ' + this.icon
26366 href : this.href || '#',
26373 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
26377 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
26379 if(this.pos == 'left'){
26380 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
26387 initEvents : function()
26389 this.el.on('mouseover', this.onMouseOver, this);
26390 this.el.on('mouseout', this.onMouseOut, this);
26392 this.el.select('a', true).first().on('click', this.onClick, this);
26396 onClick : function(e)
26398 if(this.preventDefault){
26399 e.preventDefault();
26402 this.fireEvent("click", this, e);
26405 onMouseOver : function(e)
26407 if(this.submenu && this.pos == 'left'){
26408 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
26411 this.fireEvent("mouseover", this, e);
26414 onMouseOut : function(e)
26416 this.fireEvent("mouseout", this, e);
26428 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
26431 * @class Roo.bootstrap.menu.Separator
26432 * @extends Roo.bootstrap.Component
26433 * Bootstrap Separator class
26436 * Create a new Separator
26437 * @param {Object} config The config object
26441 Roo.bootstrap.menu.Separator = function(config){
26442 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
26445 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
26447 getAutoCreate : function(){
26468 * @class Roo.bootstrap.Tooltip
26469 * Bootstrap Tooltip class
26470 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
26471 * to determine which dom element triggers the tooltip.
26473 * It needs to add support for additional attributes like tooltip-position
26476 * Create a new Toolti
26477 * @param {Object} config The config object
26480 Roo.bootstrap.Tooltip = function(config){
26481 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
26483 this.alignment = Roo.bootstrap.Tooltip.alignment;
26485 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
26486 this.alignment = config.alignment;
26491 Roo.apply(Roo.bootstrap.Tooltip, {
26493 * @function init initialize tooltip monitoring.
26497 currentTip : false,
26498 currentRegion : false,
26504 Roo.get(document).on('mouseover', this.enter ,this);
26505 Roo.get(document).on('mouseout', this.leave, this);
26508 this.currentTip = new Roo.bootstrap.Tooltip();
26511 enter : function(ev)
26513 var dom = ev.getTarget();
26515 //Roo.log(['enter',dom]);
26516 var el = Roo.fly(dom);
26517 if (this.currentEl) {
26519 //Roo.log(this.currentEl);
26520 //Roo.log(this.currentEl.contains(dom));
26521 if (this.currentEl == el) {
26524 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
26530 if (this.currentTip.el) {
26531 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
26535 if(!el || el.dom == document){
26541 // you can not look for children, as if el is the body.. then everythign is the child..
26542 if (!el.attr('tooltip')) { //
26543 if (!el.select("[tooltip]").elements.length) {
26546 // is the mouse over this child...?
26547 bindEl = el.select("[tooltip]").first();
26548 var xy = ev.getXY();
26549 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
26550 //Roo.log("not in region.");
26553 //Roo.log("child element over..");
26556 this.currentEl = bindEl;
26557 this.currentTip.bind(bindEl);
26558 this.currentRegion = Roo.lib.Region.getRegion(dom);
26559 this.currentTip.enter();
26562 leave : function(ev)
26564 var dom = ev.getTarget();
26565 //Roo.log(['leave',dom]);
26566 if (!this.currentEl) {
26571 if (dom != this.currentEl.dom) {
26574 var xy = ev.getXY();
26575 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
26578 // only activate leave if mouse cursor is outside... bounding box..
26583 if (this.currentTip) {
26584 this.currentTip.leave();
26586 //Roo.log('clear currentEl');
26587 this.currentEl = false;
26592 'left' : ['r-l', [-2,0], 'right'],
26593 'right' : ['l-r', [2,0], 'left'],
26594 'bottom' : ['t-b', [0,2], 'top'],
26595 'top' : [ 'b-t', [0,-2], 'bottom']
26601 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
26606 delay : null, // can be { show : 300 , hide: 500}
26610 hoverState : null, //???
26612 placement : 'bottom',
26616 getAutoCreate : function(){
26623 cls : 'tooltip-arrow'
26626 cls : 'tooltip-inner'
26633 bind : function(el)
26639 enter : function () {
26641 if (this.timeout != null) {
26642 clearTimeout(this.timeout);
26645 this.hoverState = 'in';
26646 //Roo.log("enter - show");
26647 if (!this.delay || !this.delay.show) {
26652 this.timeout = setTimeout(function () {
26653 if (_t.hoverState == 'in') {
26656 }, this.delay.show);
26660 clearTimeout(this.timeout);
26662 this.hoverState = 'out';
26663 if (!this.delay || !this.delay.hide) {
26669 this.timeout = setTimeout(function () {
26670 //Roo.log("leave - timeout");
26672 if (_t.hoverState == 'out') {
26674 Roo.bootstrap.Tooltip.currentEl = false;
26679 show : function (msg)
26682 this.render(document.body);
26685 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
26687 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
26689 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
26691 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
26693 var placement = typeof this.placement == 'function' ?
26694 this.placement.call(this, this.el, on_el) :
26697 var autoToken = /\s?auto?\s?/i;
26698 var autoPlace = autoToken.test(placement);
26700 placement = placement.replace(autoToken, '') || 'top';
26704 //this.el.setXY([0,0]);
26706 //this.el.dom.style.display='block';
26708 //this.el.appendTo(on_el);
26710 var p = this.getPosition();
26711 var box = this.el.getBox();
26717 var align = this.alignment[placement];
26719 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
26721 if(placement == 'top' || placement == 'bottom'){
26723 placement = 'right';
26726 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
26727 placement = 'left';
26730 var scroll = Roo.select('body', true).first().getScroll();
26732 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
26736 align = this.alignment[placement];
26739 this.el.alignTo(this.bindEl, align[0],align[1]);
26740 //var arrow = this.el.select('.arrow',true).first();
26741 //arrow.set(align[2],
26743 this.el.addClass(placement);
26745 this.el.addClass('in fade');
26747 this.hoverState = null;
26749 if (this.el.hasClass('fade')) {
26760 //this.el.setXY([0,0]);
26761 this.el.removeClass('in');
26777 * @class Roo.bootstrap.LocationPicker
26778 * @extends Roo.bootstrap.Component
26779 * Bootstrap LocationPicker class
26780 * @cfg {Number} latitude Position when init default 0
26781 * @cfg {Number} longitude Position when init default 0
26782 * @cfg {Number} zoom default 15
26783 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
26784 * @cfg {Boolean} mapTypeControl default false
26785 * @cfg {Boolean} disableDoubleClickZoom default false
26786 * @cfg {Boolean} scrollwheel default true
26787 * @cfg {Boolean} streetViewControl default false
26788 * @cfg {Number} radius default 0
26789 * @cfg {String} locationName
26790 * @cfg {Boolean} draggable default true
26791 * @cfg {Boolean} enableAutocomplete default false
26792 * @cfg {Boolean} enableReverseGeocode default true
26793 * @cfg {String} markerTitle
26796 * Create a new LocationPicker
26797 * @param {Object} config The config object
26801 Roo.bootstrap.LocationPicker = function(config){
26803 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
26808 * Fires when the picker initialized.
26809 * @param {Roo.bootstrap.LocationPicker} this
26810 * @param {Google Location} location
26814 * @event positionchanged
26815 * Fires when the picker position changed.
26816 * @param {Roo.bootstrap.LocationPicker} this
26817 * @param {Google Location} location
26819 positionchanged : true,
26822 * Fires when the map resize.
26823 * @param {Roo.bootstrap.LocationPicker} this
26828 * Fires when the map show.
26829 * @param {Roo.bootstrap.LocationPicker} this
26834 * Fires when the map hide.
26835 * @param {Roo.bootstrap.LocationPicker} this
26840 * Fires when click the map.
26841 * @param {Roo.bootstrap.LocationPicker} this
26842 * @param {Map event} e
26846 * @event mapRightClick
26847 * Fires when right click the map.
26848 * @param {Roo.bootstrap.LocationPicker} this
26849 * @param {Map event} e
26851 mapRightClick : true,
26853 * @event markerClick
26854 * Fires when click the marker.
26855 * @param {Roo.bootstrap.LocationPicker} this
26856 * @param {Map event} e
26858 markerClick : true,
26860 * @event markerRightClick
26861 * Fires when right click the marker.
26862 * @param {Roo.bootstrap.LocationPicker} this
26863 * @param {Map event} e
26865 markerRightClick : true,
26867 * @event OverlayViewDraw
26868 * Fires when OverlayView Draw
26869 * @param {Roo.bootstrap.LocationPicker} this
26871 OverlayViewDraw : true,
26873 * @event OverlayViewOnAdd
26874 * Fires when OverlayView Draw
26875 * @param {Roo.bootstrap.LocationPicker} this
26877 OverlayViewOnAdd : true,
26879 * @event OverlayViewOnRemove
26880 * Fires when OverlayView Draw
26881 * @param {Roo.bootstrap.LocationPicker} this
26883 OverlayViewOnRemove : true,
26885 * @event OverlayViewShow
26886 * Fires when OverlayView Draw
26887 * @param {Roo.bootstrap.LocationPicker} this
26888 * @param {Pixel} cpx
26890 OverlayViewShow : true,
26892 * @event OverlayViewHide
26893 * Fires when OverlayView Draw
26894 * @param {Roo.bootstrap.LocationPicker} this
26896 OverlayViewHide : true,
26898 * @event loadexception
26899 * Fires when load google lib failed.
26900 * @param {Roo.bootstrap.LocationPicker} this
26902 loadexception : true
26907 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
26909 gMapContext: false,
26915 mapTypeControl: false,
26916 disableDoubleClickZoom: false,
26918 streetViewControl: false,
26922 enableAutocomplete: false,
26923 enableReverseGeocode: true,
26926 getAutoCreate: function()
26931 cls: 'roo-location-picker'
26937 initEvents: function(ct, position)
26939 if(!this.el.getWidth() || this.isApplied()){
26943 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26948 initial: function()
26950 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
26951 this.fireEvent('loadexception', this);
26955 if(!this.mapTypeId){
26956 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
26959 this.gMapContext = this.GMapContext();
26961 this.initOverlayView();
26963 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
26967 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
26968 _this.setPosition(_this.gMapContext.marker.position);
26971 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
26972 _this.fireEvent('mapClick', this, event);
26976 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
26977 _this.fireEvent('mapRightClick', this, event);
26981 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
26982 _this.fireEvent('markerClick', this, event);
26986 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
26987 _this.fireEvent('markerRightClick', this, event);
26991 this.setPosition(this.gMapContext.location);
26993 this.fireEvent('initial', this, this.gMapContext.location);
26996 initOverlayView: function()
27000 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
27004 _this.fireEvent('OverlayViewDraw', _this);
27009 _this.fireEvent('OverlayViewOnAdd', _this);
27012 onRemove: function()
27014 _this.fireEvent('OverlayViewOnRemove', _this);
27017 show: function(cpx)
27019 _this.fireEvent('OverlayViewShow', _this, cpx);
27024 _this.fireEvent('OverlayViewHide', _this);
27030 fromLatLngToContainerPixel: function(event)
27032 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
27035 isApplied: function()
27037 return this.getGmapContext() == false ? false : true;
27040 getGmapContext: function()
27042 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
27045 GMapContext: function()
27047 var position = new google.maps.LatLng(this.latitude, this.longitude);
27049 var _map = new google.maps.Map(this.el.dom, {
27052 mapTypeId: this.mapTypeId,
27053 mapTypeControl: this.mapTypeControl,
27054 disableDoubleClickZoom: this.disableDoubleClickZoom,
27055 scrollwheel: this.scrollwheel,
27056 streetViewControl: this.streetViewControl,
27057 locationName: this.locationName,
27058 draggable: this.draggable,
27059 enableAutocomplete: this.enableAutocomplete,
27060 enableReverseGeocode: this.enableReverseGeocode
27063 var _marker = new google.maps.Marker({
27064 position: position,
27066 title: this.markerTitle,
27067 draggable: this.draggable
27074 location: position,
27075 radius: this.radius,
27076 locationName: this.locationName,
27077 addressComponents: {
27078 formatted_address: null,
27079 addressLine1: null,
27080 addressLine2: null,
27082 streetNumber: null,
27086 stateOrProvince: null
27089 domContainer: this.el.dom,
27090 geodecoder: new google.maps.Geocoder()
27094 drawCircle: function(center, radius, options)
27096 if (this.gMapContext.circle != null) {
27097 this.gMapContext.circle.setMap(null);
27101 options = Roo.apply({}, options, {
27102 strokeColor: "#0000FF",
27103 strokeOpacity: .35,
27105 fillColor: "#0000FF",
27109 options.map = this.gMapContext.map;
27110 options.radius = radius;
27111 options.center = center;
27112 this.gMapContext.circle = new google.maps.Circle(options);
27113 return this.gMapContext.circle;
27119 setPosition: function(location)
27121 this.gMapContext.location = location;
27122 this.gMapContext.marker.setPosition(location);
27123 this.gMapContext.map.panTo(location);
27124 this.drawCircle(location, this.gMapContext.radius, {});
27128 if (this.gMapContext.settings.enableReverseGeocode) {
27129 this.gMapContext.geodecoder.geocode({
27130 latLng: this.gMapContext.location
27131 }, function(results, status) {
27133 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
27134 _this.gMapContext.locationName = results[0].formatted_address;
27135 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
27137 _this.fireEvent('positionchanged', this, location);
27144 this.fireEvent('positionchanged', this, location);
27149 google.maps.event.trigger(this.gMapContext.map, "resize");
27151 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
27153 this.fireEvent('resize', this);
27156 setPositionByLatLng: function(latitude, longitude)
27158 this.setPosition(new google.maps.LatLng(latitude, longitude));
27161 getCurrentPosition: function()
27164 latitude: this.gMapContext.location.lat(),
27165 longitude: this.gMapContext.location.lng()
27169 getAddressName: function()
27171 return this.gMapContext.locationName;
27174 getAddressComponents: function()
27176 return this.gMapContext.addressComponents;
27179 address_component_from_google_geocode: function(address_components)
27183 for (var i = 0; i < address_components.length; i++) {
27184 var component = address_components[i];
27185 if (component.types.indexOf("postal_code") >= 0) {
27186 result.postalCode = component.short_name;
27187 } else if (component.types.indexOf("street_number") >= 0) {
27188 result.streetNumber = component.short_name;
27189 } else if (component.types.indexOf("route") >= 0) {
27190 result.streetName = component.short_name;
27191 } else if (component.types.indexOf("neighborhood") >= 0) {
27192 result.city = component.short_name;
27193 } else if (component.types.indexOf("locality") >= 0) {
27194 result.city = component.short_name;
27195 } else if (component.types.indexOf("sublocality") >= 0) {
27196 result.district = component.short_name;
27197 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
27198 result.stateOrProvince = component.short_name;
27199 } else if (component.types.indexOf("country") >= 0) {
27200 result.country = component.short_name;
27204 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
27205 result.addressLine2 = "";
27209 setZoomLevel: function(zoom)
27211 this.gMapContext.map.setZoom(zoom);
27224 this.fireEvent('show', this);
27235 this.fireEvent('hide', this);
27240 Roo.apply(Roo.bootstrap.LocationPicker, {
27242 OverlayView : function(map, options)
27244 options = options || {};
27251 * @class Roo.bootstrap.Alert
27252 * @extends Roo.bootstrap.Component
27253 * Bootstrap Alert class - shows an alert area box
27255 * <div class="alert alert-danger" role="alert"><span class="fa fa-exclamation-triangle"></span><span class="sr-only">Error:</span>
27256 Enter a valid email address
27259 * @cfg {String} title The title of alert
27260 * @cfg {String} html The content of alert
27261 * @cfg {String} weight ( success | info | warning | danger )
27262 * @cfg {String} faicon font-awesomeicon
27265 * Create a new alert
27266 * @param {Object} config The config object
27270 Roo.bootstrap.Alert = function(config){
27271 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
27275 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
27282 getAutoCreate : function()
27291 cls : 'roo-alert-icon'
27296 cls : 'roo-alert-title',
27301 cls : 'roo-alert-text',
27308 cfg.cn[0].cls += ' fa ' + this.faicon;
27312 cfg.cls += ' alert-' + this.weight;
27318 initEvents: function()
27320 this.el.setVisibilityMode(Roo.Element.DISPLAY);
27323 setTitle : function(str)
27325 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
27328 setText : function(str)
27330 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
27333 setWeight : function(weight)
27336 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
27339 this.weight = weight;
27341 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
27344 setIcon : function(icon)
27347 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
27350 this.faicon = icon;
27352 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
27373 * @class Roo.bootstrap.UploadCropbox
27374 * @extends Roo.bootstrap.Component
27375 * Bootstrap UploadCropbox class
27376 * @cfg {String} emptyText show when image has been loaded
27377 * @cfg {String} rotateNotify show when image too small to rotate
27378 * @cfg {Number} errorTimeout default 3000
27379 * @cfg {Number} minWidth default 300
27380 * @cfg {Number} minHeight default 300
27381 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
27382 * @cfg {Boolean} isDocument (true|false) default false
27383 * @cfg {String} url action url
27384 * @cfg {String} paramName default 'imageUpload'
27385 * @cfg {String} method default POST
27386 * @cfg {Boolean} loadMask (true|false) default true
27387 * @cfg {Boolean} loadingText default 'Loading...'
27390 * Create a new UploadCropbox
27391 * @param {Object} config The config object
27394 Roo.bootstrap.UploadCropbox = function(config){
27395 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
27399 * @event beforeselectfile
27400 * Fire before select file
27401 * @param {Roo.bootstrap.UploadCropbox} this
27403 "beforeselectfile" : true,
27406 * Fire after initEvent
27407 * @param {Roo.bootstrap.UploadCropbox} this
27412 * Fire after initEvent
27413 * @param {Roo.bootstrap.UploadCropbox} this
27414 * @param {String} data
27419 * Fire when preparing the file data
27420 * @param {Roo.bootstrap.UploadCropbox} this
27421 * @param {Object} file
27426 * Fire when get exception
27427 * @param {Roo.bootstrap.UploadCropbox} this
27428 * @param {XMLHttpRequest} xhr
27430 "exception" : true,
27432 * @event beforeloadcanvas
27433 * Fire before load the canvas
27434 * @param {Roo.bootstrap.UploadCropbox} this
27435 * @param {String} src
27437 "beforeloadcanvas" : true,
27440 * Fire when trash image
27441 * @param {Roo.bootstrap.UploadCropbox} this
27446 * Fire when download the image
27447 * @param {Roo.bootstrap.UploadCropbox} this
27451 * @event footerbuttonclick
27452 * Fire when footerbuttonclick
27453 * @param {Roo.bootstrap.UploadCropbox} this
27454 * @param {String} type
27456 "footerbuttonclick" : true,
27460 * @param {Roo.bootstrap.UploadCropbox} this
27465 * Fire when rotate the image
27466 * @param {Roo.bootstrap.UploadCropbox} this
27467 * @param {String} pos
27472 * Fire when inspect the file
27473 * @param {Roo.bootstrap.UploadCropbox} this
27474 * @param {Object} file
27479 * Fire when xhr upload the file
27480 * @param {Roo.bootstrap.UploadCropbox} this
27481 * @param {Object} data
27486 * Fire when arrange the file data
27487 * @param {Roo.bootstrap.UploadCropbox} this
27488 * @param {Object} formData
27493 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
27496 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
27498 emptyText : 'Click to upload image',
27499 rotateNotify : 'Image is too small to rotate',
27500 errorTimeout : 3000,
27514 cropType : 'image/jpeg',
27516 canvasLoaded : false,
27517 isDocument : false,
27519 paramName : 'imageUpload',
27521 loadingText : 'Loading...',
27524 getAutoCreate : function()
27528 cls : 'roo-upload-cropbox',
27532 cls : 'roo-upload-cropbox-selector',
27537 cls : 'roo-upload-cropbox-body',
27538 style : 'cursor:pointer',
27542 cls : 'roo-upload-cropbox-preview'
27546 cls : 'roo-upload-cropbox-thumb'
27550 cls : 'roo-upload-cropbox-empty-notify',
27551 html : this.emptyText
27555 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
27556 html : this.rotateNotify
27562 cls : 'roo-upload-cropbox-footer',
27565 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
27575 onRender : function(ct, position)
27577 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
27579 if (this.buttons.length) {
27581 Roo.each(this.buttons, function(bb) {
27583 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
27585 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
27591 this.maskEl = this.el;
27595 initEvents : function()
27597 this.urlAPI = (window.createObjectURL && window) ||
27598 (window.URL && URL.revokeObjectURL && URL) ||
27599 (window.webkitURL && webkitURL);
27601 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
27602 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27604 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
27605 this.selectorEl.hide();
27607 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
27608 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27610 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
27611 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27612 this.thumbEl.hide();
27614 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
27615 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27617 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
27618 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27619 this.errorEl.hide();
27621 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
27622 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27623 this.footerEl.hide();
27625 this.setThumbBoxSize();
27631 this.fireEvent('initial', this);
27638 window.addEventListener("resize", function() { _this.resize(); } );
27640 this.bodyEl.on('click', this.beforeSelectFile, this);
27643 this.bodyEl.on('touchstart', this.onTouchStart, this);
27644 this.bodyEl.on('touchmove', this.onTouchMove, this);
27645 this.bodyEl.on('touchend', this.onTouchEnd, this);
27649 this.bodyEl.on('mousedown', this.onMouseDown, this);
27650 this.bodyEl.on('mousemove', this.onMouseMove, this);
27651 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
27652 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
27653 Roo.get(document).on('mouseup', this.onMouseUp, this);
27656 this.selectorEl.on('change', this.onFileSelected, this);
27662 this.baseScale = 1;
27664 this.baseRotate = 1;
27665 this.dragable = false;
27666 this.pinching = false;
27669 this.cropData = false;
27670 this.notifyEl.dom.innerHTML = this.emptyText;
27672 this.selectorEl.dom.value = '';
27676 resize : function()
27678 if(this.fireEvent('resize', this) != false){
27679 this.setThumbBoxPosition();
27680 this.setCanvasPosition();
27684 onFooterButtonClick : function(e, el, o, type)
27687 case 'rotate-left' :
27688 this.onRotateLeft(e);
27690 case 'rotate-right' :
27691 this.onRotateRight(e);
27694 this.beforeSelectFile(e);
27709 this.fireEvent('footerbuttonclick', this, type);
27712 beforeSelectFile : function(e)
27714 e.preventDefault();
27716 if(this.fireEvent('beforeselectfile', this) != false){
27717 this.selectorEl.dom.click();
27721 onFileSelected : function(e)
27723 e.preventDefault();
27725 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
27729 var file = this.selectorEl.dom.files[0];
27731 if(this.fireEvent('inspect', this, file) != false){
27732 this.prepare(file);
27737 trash : function(e)
27739 this.fireEvent('trash', this);
27742 download : function(e)
27744 this.fireEvent('download', this);
27747 loadCanvas : function(src)
27749 if(this.fireEvent('beforeloadcanvas', this, src) != false){
27753 this.imageEl = document.createElement('img');
27757 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
27759 this.imageEl.src = src;
27763 onLoadCanvas : function()
27765 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
27766 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
27768 this.bodyEl.un('click', this.beforeSelectFile, this);
27770 this.notifyEl.hide();
27771 this.thumbEl.show();
27772 this.footerEl.show();
27774 this.baseRotateLevel();
27776 if(this.isDocument){
27777 this.setThumbBoxSize();
27780 this.setThumbBoxPosition();
27782 this.baseScaleLevel();
27788 this.canvasLoaded = true;
27791 this.maskEl.unmask();
27796 setCanvasPosition : function()
27798 if(!this.canvasEl){
27802 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
27803 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
27805 this.previewEl.setLeft(pw);
27806 this.previewEl.setTop(ph);
27810 onMouseDown : function(e)
27814 this.dragable = true;
27815 this.pinching = false;
27817 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
27818 this.dragable = false;
27822 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27823 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27827 onMouseMove : function(e)
27831 if(!this.canvasLoaded){
27835 if (!this.dragable){
27839 var minX = Math.ceil(this.thumbEl.getLeft(true));
27840 var minY = Math.ceil(this.thumbEl.getTop(true));
27842 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
27843 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
27845 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27846 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27848 x = x - this.mouseX;
27849 y = y - this.mouseY;
27851 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
27852 var bgY = Math.ceil(y + this.previewEl.getTop(true));
27854 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
27855 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
27857 this.previewEl.setLeft(bgX);
27858 this.previewEl.setTop(bgY);
27860 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27861 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27864 onMouseUp : function(e)
27868 this.dragable = false;
27871 onMouseWheel : function(e)
27875 this.startScale = this.scale;
27877 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
27879 if(!this.zoomable()){
27880 this.scale = this.startScale;
27889 zoomable : function()
27891 var minScale = this.thumbEl.getWidth() / this.minWidth;
27893 if(this.minWidth < this.minHeight){
27894 minScale = this.thumbEl.getHeight() / this.minHeight;
27897 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
27898 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
27902 (this.rotate == 0 || this.rotate == 180) &&
27904 width > this.imageEl.OriginWidth ||
27905 height > this.imageEl.OriginHeight ||
27906 (width < this.minWidth && height < this.minHeight)
27914 (this.rotate == 90 || this.rotate == 270) &&
27916 width > this.imageEl.OriginWidth ||
27917 height > this.imageEl.OriginHeight ||
27918 (width < this.minHeight && height < this.minWidth)
27925 !this.isDocument &&
27926 (this.rotate == 0 || this.rotate == 180) &&
27928 width < this.minWidth ||
27929 width > this.imageEl.OriginWidth ||
27930 height < this.minHeight ||
27931 height > this.imageEl.OriginHeight
27938 !this.isDocument &&
27939 (this.rotate == 90 || this.rotate == 270) &&
27941 width < this.minHeight ||
27942 width > this.imageEl.OriginWidth ||
27943 height < this.minWidth ||
27944 height > this.imageEl.OriginHeight
27954 onRotateLeft : function(e)
27956 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27958 var minScale = this.thumbEl.getWidth() / this.minWidth;
27960 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27961 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27963 this.startScale = this.scale;
27965 while (this.getScaleLevel() < minScale){
27967 this.scale = this.scale + 1;
27969 if(!this.zoomable()){
27974 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27975 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27980 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27987 this.scale = this.startScale;
27989 this.onRotateFail();
27994 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27996 if(this.isDocument){
27997 this.setThumbBoxSize();
27998 this.setThumbBoxPosition();
27999 this.setCanvasPosition();
28004 this.fireEvent('rotate', this, 'left');
28008 onRotateRight : function(e)
28010 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
28012 var minScale = this.thumbEl.getWidth() / this.minWidth;
28014 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
28015 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
28017 this.startScale = this.scale;
28019 while (this.getScaleLevel() < minScale){
28021 this.scale = this.scale + 1;
28023 if(!this.zoomable()){
28028 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
28029 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
28034 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
28041 this.scale = this.startScale;
28043 this.onRotateFail();
28048 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
28050 if(this.isDocument){
28051 this.setThumbBoxSize();
28052 this.setThumbBoxPosition();
28053 this.setCanvasPosition();
28058 this.fireEvent('rotate', this, 'right');
28061 onRotateFail : function()
28063 this.errorEl.show(true);
28067 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
28072 this.previewEl.dom.innerHTML = '';
28074 var canvasEl = document.createElement("canvas");
28076 var contextEl = canvasEl.getContext("2d");
28078 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
28079 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
28080 var center = this.imageEl.OriginWidth / 2;
28082 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
28083 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
28084 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
28085 center = this.imageEl.OriginHeight / 2;
28088 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
28090 contextEl.translate(center, center);
28091 contextEl.rotate(this.rotate * Math.PI / 180);
28093 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
28095 this.canvasEl = document.createElement("canvas");
28097 this.contextEl = this.canvasEl.getContext("2d");
28099 switch (this.rotate) {
28102 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
28103 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
28105 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
28110 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
28111 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
28113 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28114 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);
28118 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
28123 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
28124 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
28126 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28127 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);
28131 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.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
28137 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
28139 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28140 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
28144 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);
28151 this.previewEl.appendChild(this.canvasEl);
28153 this.setCanvasPosition();
28158 if(!this.canvasLoaded){
28162 var imageCanvas = document.createElement("canvas");
28164 var imageContext = imageCanvas.getContext("2d");
28166 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
28167 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
28169 var center = imageCanvas.width / 2;
28171 imageContext.translate(center, center);
28173 imageContext.rotate(this.rotate * Math.PI / 180);
28175 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
28177 var canvas = document.createElement("canvas");
28179 var context = canvas.getContext("2d");
28181 canvas.width = this.minWidth;
28182 canvas.height = this.minHeight;
28184 switch (this.rotate) {
28187 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
28188 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
28190 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28191 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28193 var targetWidth = this.minWidth - 2 * x;
28194 var targetHeight = this.minHeight - 2 * y;
28198 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28199 scale = targetWidth / width;
28202 if(x > 0 && y == 0){
28203 scale = targetHeight / height;
28206 if(x > 0 && y > 0){
28207 scale = targetWidth / width;
28209 if(width < height){
28210 scale = targetHeight / height;
28214 context.scale(scale, scale);
28216 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28217 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28219 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28220 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28222 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28227 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
28228 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
28230 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28231 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28233 var targetWidth = this.minWidth - 2 * x;
28234 var targetHeight = this.minHeight - 2 * y;
28238 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28239 scale = targetWidth / width;
28242 if(x > 0 && y == 0){
28243 scale = targetHeight / height;
28246 if(x > 0 && y > 0){
28247 scale = targetWidth / width;
28249 if(width < height){
28250 scale = targetHeight / height;
28254 context.scale(scale, scale);
28256 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28257 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28259 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28260 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28262 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
28264 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28269 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
28270 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
28272 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28273 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28275 var targetWidth = this.minWidth - 2 * x;
28276 var targetHeight = this.minHeight - 2 * y;
28280 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28281 scale = targetWidth / width;
28284 if(x > 0 && y == 0){
28285 scale = targetHeight / height;
28288 if(x > 0 && y > 0){
28289 scale = targetWidth / width;
28291 if(width < height){
28292 scale = targetHeight / height;
28296 context.scale(scale, scale);
28298 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28299 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28301 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28302 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28304 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
28305 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
28307 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28312 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
28313 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
28315 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28316 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28318 var targetWidth = this.minWidth - 2 * x;
28319 var targetHeight = this.minHeight - 2 * y;
28323 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28324 scale = targetWidth / width;
28327 if(x > 0 && y == 0){
28328 scale = targetHeight / height;
28331 if(x > 0 && y > 0){
28332 scale = targetWidth / width;
28334 if(width < height){
28335 scale = targetHeight / height;
28339 context.scale(scale, scale);
28341 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28342 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28344 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28345 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28347 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
28349 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28356 this.cropData = canvas.toDataURL(this.cropType);
28358 if(this.fireEvent('crop', this, this.cropData) !== false){
28359 this.process(this.file, this.cropData);
28366 setThumbBoxSize : function()
28370 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
28371 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
28372 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
28374 this.minWidth = width;
28375 this.minHeight = height;
28377 if(this.rotate == 90 || this.rotate == 270){
28378 this.minWidth = height;
28379 this.minHeight = width;
28384 width = Math.ceil(this.minWidth * height / this.minHeight);
28386 if(this.minWidth > this.minHeight){
28388 height = Math.ceil(this.minHeight * width / this.minWidth);
28391 this.thumbEl.setStyle({
28392 width : width + 'px',
28393 height : height + 'px'
28400 setThumbBoxPosition : function()
28402 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
28403 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
28405 this.thumbEl.setLeft(x);
28406 this.thumbEl.setTop(y);
28410 baseRotateLevel : function()
28412 this.baseRotate = 1;
28415 typeof(this.exif) != 'undefined' &&
28416 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
28417 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
28419 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
28422 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
28426 baseScaleLevel : function()
28430 if(this.isDocument){
28432 if(this.baseRotate == 6 || this.baseRotate == 8){
28434 height = this.thumbEl.getHeight();
28435 this.baseScale = height / this.imageEl.OriginWidth;
28437 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
28438 width = this.thumbEl.getWidth();
28439 this.baseScale = width / this.imageEl.OriginHeight;
28445 height = this.thumbEl.getHeight();
28446 this.baseScale = height / this.imageEl.OriginHeight;
28448 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
28449 width = this.thumbEl.getWidth();
28450 this.baseScale = width / this.imageEl.OriginWidth;
28456 if(this.baseRotate == 6 || this.baseRotate == 8){
28458 width = this.thumbEl.getHeight();
28459 this.baseScale = width / this.imageEl.OriginHeight;
28461 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
28462 height = this.thumbEl.getWidth();
28463 this.baseScale = height / this.imageEl.OriginHeight;
28466 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28467 height = this.thumbEl.getWidth();
28468 this.baseScale = height / this.imageEl.OriginHeight;
28470 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
28471 width = this.thumbEl.getHeight();
28472 this.baseScale = width / this.imageEl.OriginWidth;
28479 width = this.thumbEl.getWidth();
28480 this.baseScale = width / this.imageEl.OriginWidth;
28482 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
28483 height = this.thumbEl.getHeight();
28484 this.baseScale = height / this.imageEl.OriginHeight;
28487 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28489 height = this.thumbEl.getHeight();
28490 this.baseScale = height / this.imageEl.OriginHeight;
28492 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
28493 width = this.thumbEl.getWidth();
28494 this.baseScale = width / this.imageEl.OriginWidth;
28502 getScaleLevel : function()
28504 return this.baseScale * Math.pow(1.1, this.scale);
28507 onTouchStart : function(e)
28509 if(!this.canvasLoaded){
28510 this.beforeSelectFile(e);
28514 var touches = e.browserEvent.touches;
28520 if(touches.length == 1){
28521 this.onMouseDown(e);
28525 if(touches.length != 2){
28531 for(var i = 0, finger; finger = touches[i]; i++){
28532 coords.push(finger.pageX, finger.pageY);
28535 var x = Math.pow(coords[0] - coords[2], 2);
28536 var y = Math.pow(coords[1] - coords[3], 2);
28538 this.startDistance = Math.sqrt(x + y);
28540 this.startScale = this.scale;
28542 this.pinching = true;
28543 this.dragable = false;
28547 onTouchMove : function(e)
28549 if(!this.pinching && !this.dragable){
28553 var touches = e.browserEvent.touches;
28560 this.onMouseMove(e);
28566 for(var i = 0, finger; finger = touches[i]; i++){
28567 coords.push(finger.pageX, finger.pageY);
28570 var x = Math.pow(coords[0] - coords[2], 2);
28571 var y = Math.pow(coords[1] - coords[3], 2);
28573 this.endDistance = Math.sqrt(x + y);
28575 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
28577 if(!this.zoomable()){
28578 this.scale = this.startScale;
28586 onTouchEnd : function(e)
28588 this.pinching = false;
28589 this.dragable = false;
28593 process : function(file, crop)
28596 this.maskEl.mask(this.loadingText);
28599 this.xhr = new XMLHttpRequest();
28601 file.xhr = this.xhr;
28603 this.xhr.open(this.method, this.url, true);
28606 "Accept": "application/json",
28607 "Cache-Control": "no-cache",
28608 "X-Requested-With": "XMLHttpRequest"
28611 for (var headerName in headers) {
28612 var headerValue = headers[headerName];
28614 this.xhr.setRequestHeader(headerName, headerValue);
28620 this.xhr.onload = function()
28622 _this.xhrOnLoad(_this.xhr);
28625 this.xhr.onerror = function()
28627 _this.xhrOnError(_this.xhr);
28630 var formData = new FormData();
28632 formData.append('returnHTML', 'NO');
28635 formData.append('crop', crop);
28638 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
28639 formData.append(this.paramName, file, file.name);
28642 if(typeof(file.filename) != 'undefined'){
28643 formData.append('filename', file.filename);
28646 if(typeof(file.mimetype) != 'undefined'){
28647 formData.append('mimetype', file.mimetype);
28650 if(this.fireEvent('arrange', this, formData) != false){
28651 this.xhr.send(formData);
28655 xhrOnLoad : function(xhr)
28658 this.maskEl.unmask();
28661 if (xhr.readyState !== 4) {
28662 this.fireEvent('exception', this, xhr);
28666 var response = Roo.decode(xhr.responseText);
28668 if(!response.success){
28669 this.fireEvent('exception', this, xhr);
28673 var response = Roo.decode(xhr.responseText);
28675 this.fireEvent('upload', this, response);
28679 xhrOnError : function()
28682 this.maskEl.unmask();
28685 Roo.log('xhr on error');
28687 var response = Roo.decode(xhr.responseText);
28693 prepare : function(file)
28696 this.maskEl.mask(this.loadingText);
28702 if(typeof(file) === 'string'){
28703 this.loadCanvas(file);
28707 if(!file || !this.urlAPI){
28712 this.cropType = file.type;
28716 if(this.fireEvent('prepare', this, this.file) != false){
28718 var reader = new FileReader();
28720 reader.onload = function (e) {
28721 if (e.target.error) {
28722 Roo.log(e.target.error);
28726 var buffer = e.target.result,
28727 dataView = new DataView(buffer),
28729 maxOffset = dataView.byteLength - 4,
28733 if (dataView.getUint16(0) === 0xffd8) {
28734 while (offset < maxOffset) {
28735 markerBytes = dataView.getUint16(offset);
28737 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
28738 markerLength = dataView.getUint16(offset + 2) + 2;
28739 if (offset + markerLength > dataView.byteLength) {
28740 Roo.log('Invalid meta data: Invalid segment size.');
28744 if(markerBytes == 0xffe1){
28745 _this.parseExifData(
28752 offset += markerLength;
28762 var url = _this.urlAPI.createObjectURL(_this.file);
28764 _this.loadCanvas(url);
28769 reader.readAsArrayBuffer(this.file);
28775 parseExifData : function(dataView, offset, length)
28777 var tiffOffset = offset + 10,
28781 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28782 // No Exif data, might be XMP data instead
28786 // Check for the ASCII code for "Exif" (0x45786966):
28787 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28788 // No Exif data, might be XMP data instead
28791 if (tiffOffset + 8 > dataView.byteLength) {
28792 Roo.log('Invalid Exif data: Invalid segment size.');
28795 // Check for the two null bytes:
28796 if (dataView.getUint16(offset + 8) !== 0x0000) {
28797 Roo.log('Invalid Exif data: Missing byte alignment offset.');
28800 // Check the byte alignment:
28801 switch (dataView.getUint16(tiffOffset)) {
28803 littleEndian = true;
28806 littleEndian = false;
28809 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
28812 // Check for the TIFF tag marker (0x002A):
28813 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
28814 Roo.log('Invalid Exif data: Missing TIFF marker.');
28817 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
28818 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
28820 this.parseExifTags(
28823 tiffOffset + dirOffset,
28828 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
28833 if (dirOffset + 6 > dataView.byteLength) {
28834 Roo.log('Invalid Exif data: Invalid directory offset.');
28837 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
28838 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
28839 if (dirEndOffset + 4 > dataView.byteLength) {
28840 Roo.log('Invalid Exif data: Invalid directory size.');
28843 for (i = 0; i < tagsNumber; i += 1) {
28847 dirOffset + 2 + 12 * i, // tag offset
28851 // Return the offset to the next directory:
28852 return dataView.getUint32(dirEndOffset, littleEndian);
28855 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
28857 var tag = dataView.getUint16(offset, littleEndian);
28859 this.exif[tag] = this.getExifValue(
28863 dataView.getUint16(offset + 2, littleEndian), // tag type
28864 dataView.getUint32(offset + 4, littleEndian), // tag length
28869 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
28871 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
28880 Roo.log('Invalid Exif data: Invalid tag type.');
28884 tagSize = tagType.size * length;
28885 // Determine if the value is contained in the dataOffset bytes,
28886 // or if the value at the dataOffset is a pointer to the actual data:
28887 dataOffset = tagSize > 4 ?
28888 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
28889 if (dataOffset + tagSize > dataView.byteLength) {
28890 Roo.log('Invalid Exif data: Invalid data offset.');
28893 if (length === 1) {
28894 return tagType.getValue(dataView, dataOffset, littleEndian);
28897 for (i = 0; i < length; i += 1) {
28898 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
28901 if (tagType.ascii) {
28903 // Concatenate the chars:
28904 for (i = 0; i < values.length; i += 1) {
28906 // Ignore the terminating NULL byte(s):
28907 if (c === '\u0000') {
28919 Roo.apply(Roo.bootstrap.UploadCropbox, {
28921 'Orientation': 0x0112
28925 1: 0, //'top-left',
28927 3: 180, //'bottom-right',
28928 // 4: 'bottom-left',
28930 6: 90, //'right-top',
28931 // 7: 'right-bottom',
28932 8: 270 //'left-bottom'
28936 // byte, 8-bit unsigned int:
28938 getValue: function (dataView, dataOffset) {
28939 return dataView.getUint8(dataOffset);
28943 // ascii, 8-bit byte:
28945 getValue: function (dataView, dataOffset) {
28946 return String.fromCharCode(dataView.getUint8(dataOffset));
28951 // short, 16 bit int:
28953 getValue: function (dataView, dataOffset, littleEndian) {
28954 return dataView.getUint16(dataOffset, littleEndian);
28958 // long, 32 bit int:
28960 getValue: function (dataView, dataOffset, littleEndian) {
28961 return dataView.getUint32(dataOffset, littleEndian);
28965 // rational = two long values, first is numerator, second is denominator:
28967 getValue: function (dataView, dataOffset, littleEndian) {
28968 return dataView.getUint32(dataOffset, littleEndian) /
28969 dataView.getUint32(dataOffset + 4, littleEndian);
28973 // slong, 32 bit signed int:
28975 getValue: function (dataView, dataOffset, littleEndian) {
28976 return dataView.getInt32(dataOffset, littleEndian);
28980 // srational, two slongs, first is numerator, second is denominator:
28982 getValue: function (dataView, dataOffset, littleEndian) {
28983 return dataView.getInt32(dataOffset, littleEndian) /
28984 dataView.getInt32(dataOffset + 4, littleEndian);
28994 cls : 'btn-group roo-upload-cropbox-rotate-left',
28995 action : 'rotate-left',
28999 cls : 'btn btn-default',
29000 html : '<i class="fa fa-undo"></i>'
29006 cls : 'btn-group roo-upload-cropbox-picture',
29007 action : 'picture',
29011 cls : 'btn btn-default',
29012 html : '<i class="fa fa-picture-o"></i>'
29018 cls : 'btn-group roo-upload-cropbox-rotate-right',
29019 action : 'rotate-right',
29023 cls : 'btn btn-default',
29024 html : '<i class="fa fa-repeat"></i>'
29032 cls : 'btn-group roo-upload-cropbox-rotate-left',
29033 action : 'rotate-left',
29037 cls : 'btn btn-default',
29038 html : '<i class="fa fa-undo"></i>'
29044 cls : 'btn-group roo-upload-cropbox-download',
29045 action : 'download',
29049 cls : 'btn btn-default',
29050 html : '<i class="fa fa-download"></i>'
29056 cls : 'btn-group roo-upload-cropbox-crop',
29061 cls : 'btn btn-default',
29062 html : '<i class="fa fa-crop"></i>'
29068 cls : 'btn-group roo-upload-cropbox-trash',
29073 cls : 'btn btn-default',
29074 html : '<i class="fa fa-trash"></i>'
29080 cls : 'btn-group roo-upload-cropbox-rotate-right',
29081 action : 'rotate-right',
29085 cls : 'btn btn-default',
29086 html : '<i class="fa fa-repeat"></i>'
29094 cls : 'btn-group roo-upload-cropbox-rotate-left',
29095 action : 'rotate-left',
29099 cls : 'btn btn-default',
29100 html : '<i class="fa fa-undo"></i>'
29106 cls : 'btn-group roo-upload-cropbox-rotate-right',
29107 action : 'rotate-right',
29111 cls : 'btn btn-default',
29112 html : '<i class="fa fa-repeat"></i>'
29125 * @class Roo.bootstrap.DocumentManager
29126 * @extends Roo.bootstrap.Component
29127 * Bootstrap DocumentManager class
29128 * @cfg {String} paramName default 'imageUpload'
29129 * @cfg {String} toolTipName default 'filename'
29130 * @cfg {String} method default POST
29131 * @cfg {String} url action url
29132 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
29133 * @cfg {Boolean} multiple multiple upload default true
29134 * @cfg {Number} thumbSize default 300
29135 * @cfg {String} fieldLabel
29136 * @cfg {Number} labelWidth default 4
29137 * @cfg {String} labelAlign (left|top) default left
29138 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
29139 * @cfg {Number} labellg set the width of label (1-12)
29140 * @cfg {Number} labelmd set the width of label (1-12)
29141 * @cfg {Number} labelsm set the width of label (1-12)
29142 * @cfg {Number} labelxs set the width of label (1-12)
29145 * Create a new DocumentManager
29146 * @param {Object} config The config object
29149 Roo.bootstrap.DocumentManager = function(config){
29150 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
29153 this.delegates = [];
29158 * Fire when initial the DocumentManager
29159 * @param {Roo.bootstrap.DocumentManager} this
29164 * inspect selected file
29165 * @param {Roo.bootstrap.DocumentManager} this
29166 * @param {File} file
29171 * Fire when xhr load exception
29172 * @param {Roo.bootstrap.DocumentManager} this
29173 * @param {XMLHttpRequest} xhr
29175 "exception" : true,
29177 * @event afterupload
29178 * Fire when xhr load exception
29179 * @param {Roo.bootstrap.DocumentManager} this
29180 * @param {XMLHttpRequest} xhr
29182 "afterupload" : true,
29185 * prepare the form data
29186 * @param {Roo.bootstrap.DocumentManager} this
29187 * @param {Object} formData
29192 * Fire when remove the file
29193 * @param {Roo.bootstrap.DocumentManager} this
29194 * @param {Object} file
29199 * Fire after refresh the file
29200 * @param {Roo.bootstrap.DocumentManager} this
29205 * Fire after click the image
29206 * @param {Roo.bootstrap.DocumentManager} this
29207 * @param {Object} file
29212 * Fire when upload a image and editable set to true
29213 * @param {Roo.bootstrap.DocumentManager} this
29214 * @param {Object} file
29218 * @event beforeselectfile
29219 * Fire before select file
29220 * @param {Roo.bootstrap.DocumentManager} this
29222 "beforeselectfile" : true,
29225 * Fire before process file
29226 * @param {Roo.bootstrap.DocumentManager} this
29227 * @param {Object} file
29231 * @event previewrendered
29232 * Fire when preview rendered
29233 * @param {Roo.bootstrap.DocumentManager} this
29234 * @param {Object} file
29236 "previewrendered" : true,
29239 "previewResize" : true
29244 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
29253 paramName : 'imageUpload',
29254 toolTipName : 'filename',
29257 labelAlign : 'left',
29267 getAutoCreate : function()
29269 var managerWidget = {
29271 cls : 'roo-document-manager',
29275 cls : 'roo-document-manager-selector',
29280 cls : 'roo-document-manager-uploader',
29284 cls : 'roo-document-manager-upload-btn',
29285 html : '<i class="fa fa-plus"></i>'
29296 cls : 'column col-md-12',
29301 if(this.fieldLabel.length){
29306 cls : 'column col-md-12',
29307 html : this.fieldLabel
29311 cls : 'column col-md-12',
29316 if(this.labelAlign == 'left'){
29321 html : this.fieldLabel
29330 if(this.labelWidth > 12){
29331 content[0].style = "width: " + this.labelWidth + 'px';
29334 if(this.labelWidth < 13 && this.labelmd == 0){
29335 this.labelmd = this.labelWidth;
29338 if(this.labellg > 0){
29339 content[0].cls += ' col-lg-' + this.labellg;
29340 content[1].cls += ' col-lg-' + (12 - this.labellg);
29343 if(this.labelmd > 0){
29344 content[0].cls += ' col-md-' + this.labelmd;
29345 content[1].cls += ' col-md-' + (12 - this.labelmd);
29348 if(this.labelsm > 0){
29349 content[0].cls += ' col-sm-' + this.labelsm;
29350 content[1].cls += ' col-sm-' + (12 - this.labelsm);
29353 if(this.labelxs > 0){
29354 content[0].cls += ' col-xs-' + this.labelxs;
29355 content[1].cls += ' col-xs-' + (12 - this.labelxs);
29363 cls : 'row clearfix',
29371 initEvents : function()
29373 this.managerEl = this.el.select('.roo-document-manager', true).first();
29374 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29376 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
29377 this.selectorEl.hide();
29380 this.selectorEl.attr('multiple', 'multiple');
29383 this.selectorEl.on('change', this.onFileSelected, this);
29385 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
29386 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29388 this.uploader.on('click', this.onUploaderClick, this);
29390 this.renderProgressDialog();
29394 window.addEventListener("resize", function() { _this.refresh(); } );
29396 this.fireEvent('initial', this);
29399 renderProgressDialog : function()
29403 this.progressDialog = new Roo.bootstrap.Modal({
29404 cls : 'roo-document-manager-progress-dialog',
29405 allow_close : false,
29416 btnclick : function() {
29417 _this.uploadCancel();
29423 this.progressDialog.render(Roo.get(document.body));
29425 this.progress = new Roo.bootstrap.Progress({
29426 cls : 'roo-document-manager-progress',
29431 this.progress.render(this.progressDialog.getChildContainer());
29433 this.progressBar = new Roo.bootstrap.ProgressBar({
29434 cls : 'roo-document-manager-progress-bar',
29437 aria_valuemax : 12,
29441 this.progressBar.render(this.progress.getChildContainer());
29444 onUploaderClick : function(e)
29446 e.preventDefault();
29448 if(this.fireEvent('beforeselectfile', this) != false){
29449 this.selectorEl.dom.click();
29454 onFileSelected : function(e)
29456 e.preventDefault();
29458 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
29462 Roo.each(this.selectorEl.dom.files, function(file){
29463 if(this.fireEvent('inspect', this, file) != false){
29464 this.files.push(file);
29474 this.selectorEl.dom.value = '';
29476 if(!this.files || !this.files.length){
29480 if(this.boxes > 0 && this.files.length > this.boxes){
29481 this.files = this.files.slice(0, this.boxes);
29484 this.uploader.show();
29486 if(this.boxes > 0 && this.files.length > this.boxes - 1){
29487 this.uploader.hide();
29496 Roo.each(this.files, function(file){
29498 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29499 var f = this.renderPreview(file);
29504 if(file.type.indexOf('image') != -1){
29505 this.delegates.push(
29507 _this.process(file);
29508 }).createDelegate(this)
29516 _this.process(file);
29517 }).createDelegate(this)
29522 this.files = files;
29524 this.delegates = this.delegates.concat(docs);
29526 if(!this.delegates.length){
29531 this.progressBar.aria_valuemax = this.delegates.length;
29538 arrange : function()
29540 if(!this.delegates.length){
29541 this.progressDialog.hide();
29546 var delegate = this.delegates.shift();
29548 this.progressDialog.show();
29550 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
29552 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
29557 refresh : function()
29559 this.uploader.show();
29561 if(this.boxes > 0 && this.files.length > this.boxes - 1){
29562 this.uploader.hide();
29565 Roo.isTouch ? this.closable(false) : this.closable(true);
29567 this.fireEvent('refresh', this);
29570 onRemove : function(e, el, o)
29572 e.preventDefault();
29574 this.fireEvent('remove', this, o);
29578 remove : function(o)
29582 Roo.each(this.files, function(file){
29583 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
29592 this.files = files;
29599 Roo.each(this.files, function(file){
29604 file.target.remove();
29613 onClick : function(e, el, o)
29615 e.preventDefault();
29617 this.fireEvent('click', this, o);
29621 closable : function(closable)
29623 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
29625 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29637 xhrOnLoad : function(xhr)
29639 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29643 if (xhr.readyState !== 4) {
29645 this.fireEvent('exception', this, xhr);
29649 var response = Roo.decode(xhr.responseText);
29651 if(!response.success){
29653 this.fireEvent('exception', this, xhr);
29657 var file = this.renderPreview(response.data);
29659 this.files.push(file);
29663 this.fireEvent('afterupload', this, xhr);
29667 xhrOnError : function(xhr)
29669 Roo.log('xhr on error');
29671 var response = Roo.decode(xhr.responseText);
29678 process : function(file)
29680 if(this.fireEvent('process', this, file) !== false){
29681 if(this.editable && file.type.indexOf('image') != -1){
29682 this.fireEvent('edit', this, file);
29686 this.uploadStart(file, false);
29693 uploadStart : function(file, crop)
29695 this.xhr = new XMLHttpRequest();
29697 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29702 file.xhr = this.xhr;
29704 this.managerEl.createChild({
29706 cls : 'roo-document-manager-loading',
29710 tooltip : file.name,
29711 cls : 'roo-document-manager-thumb',
29712 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29718 this.xhr.open(this.method, this.url, true);
29721 "Accept": "application/json",
29722 "Cache-Control": "no-cache",
29723 "X-Requested-With": "XMLHttpRequest"
29726 for (var headerName in headers) {
29727 var headerValue = headers[headerName];
29729 this.xhr.setRequestHeader(headerName, headerValue);
29735 this.xhr.onload = function()
29737 _this.xhrOnLoad(_this.xhr);
29740 this.xhr.onerror = function()
29742 _this.xhrOnError(_this.xhr);
29745 var formData = new FormData();
29747 formData.append('returnHTML', 'NO');
29750 formData.append('crop', crop);
29753 formData.append(this.paramName, file, file.name);
29760 if(this.fireEvent('prepare', this, formData, options) != false){
29762 if(options.manually){
29766 this.xhr.send(formData);
29770 this.uploadCancel();
29773 uploadCancel : function()
29779 this.delegates = [];
29781 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29788 renderPreview : function(file)
29790 if(typeof(file.target) != 'undefined' && file.target){
29794 var img_src = encodeURI(baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename);
29796 var previewEl = this.managerEl.createChild({
29798 cls : 'roo-document-manager-preview',
29802 tooltip : file[this.toolTipName],
29803 cls : 'roo-document-manager-thumb',
29804 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + img_src + '">'
29809 html : '<i class="fa fa-times-circle"></i>'
29814 var close = previewEl.select('button.close', true).first();
29816 close.on('click', this.onRemove, this, file);
29818 file.target = previewEl;
29820 var image = previewEl.select('img', true).first();
29824 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
29826 image.on('click', this.onClick, this, file);
29828 this.fireEvent('previewrendered', this, file);
29834 onPreviewLoad : function(file, image)
29836 if(typeof(file.target) == 'undefined' || !file.target){
29840 var width = image.dom.naturalWidth || image.dom.width;
29841 var height = image.dom.naturalHeight || image.dom.height;
29843 if(!this.previewResize) {
29847 if(width > height){
29848 file.target.addClass('wide');
29852 file.target.addClass('tall');
29857 uploadFromSource : function(file, crop)
29859 this.xhr = new XMLHttpRequest();
29861 this.managerEl.createChild({
29863 cls : 'roo-document-manager-loading',
29867 tooltip : file.name,
29868 cls : 'roo-document-manager-thumb',
29869 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29875 this.xhr.open(this.method, this.url, true);
29878 "Accept": "application/json",
29879 "Cache-Control": "no-cache",
29880 "X-Requested-With": "XMLHttpRequest"
29883 for (var headerName in headers) {
29884 var headerValue = headers[headerName];
29886 this.xhr.setRequestHeader(headerName, headerValue);
29892 this.xhr.onload = function()
29894 _this.xhrOnLoad(_this.xhr);
29897 this.xhr.onerror = function()
29899 _this.xhrOnError(_this.xhr);
29902 var formData = new FormData();
29904 formData.append('returnHTML', 'NO');
29906 formData.append('crop', crop);
29908 if(typeof(file.filename) != 'undefined'){
29909 formData.append('filename', file.filename);
29912 if(typeof(file.mimetype) != 'undefined'){
29913 formData.append('mimetype', file.mimetype);
29918 if(this.fireEvent('prepare', this, formData) != false){
29919 this.xhr.send(formData);
29929 * @class Roo.bootstrap.DocumentViewer
29930 * @extends Roo.bootstrap.Component
29931 * Bootstrap DocumentViewer class
29932 * @cfg {Boolean} showDownload (true|false) show download button (default true)
29933 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
29936 * Create a new DocumentViewer
29937 * @param {Object} config The config object
29940 Roo.bootstrap.DocumentViewer = function(config){
29941 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
29946 * Fire after initEvent
29947 * @param {Roo.bootstrap.DocumentViewer} this
29953 * @param {Roo.bootstrap.DocumentViewer} this
29958 * Fire after download button
29959 * @param {Roo.bootstrap.DocumentViewer} this
29964 * Fire after trash button
29965 * @param {Roo.bootstrap.DocumentViewer} this
29972 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
29974 showDownload : true,
29978 getAutoCreate : function()
29982 cls : 'roo-document-viewer',
29986 cls : 'roo-document-viewer-body',
29990 cls : 'roo-document-viewer-thumb',
29994 cls : 'roo-document-viewer-image'
30002 cls : 'roo-document-viewer-footer',
30005 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
30009 cls : 'btn-group roo-document-viewer-download',
30013 cls : 'btn btn-default',
30014 html : '<i class="fa fa-download"></i>'
30020 cls : 'btn-group roo-document-viewer-trash',
30024 cls : 'btn btn-default',
30025 html : '<i class="fa fa-trash"></i>'
30038 initEvents : function()
30040 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
30041 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
30043 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
30044 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
30046 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
30047 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
30049 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
30050 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
30052 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
30053 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
30055 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
30056 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
30058 this.bodyEl.on('click', this.onClick, this);
30059 this.downloadBtn.on('click', this.onDownload, this);
30060 this.trashBtn.on('click', this.onTrash, this);
30062 this.downloadBtn.hide();
30063 this.trashBtn.hide();
30065 if(this.showDownload){
30066 this.downloadBtn.show();
30069 if(this.showTrash){
30070 this.trashBtn.show();
30073 if(!this.showDownload && !this.showTrash) {
30074 this.footerEl.hide();
30079 initial : function()
30081 this.fireEvent('initial', this);
30085 onClick : function(e)
30087 e.preventDefault();
30089 this.fireEvent('click', this);
30092 onDownload : function(e)
30094 e.preventDefault();
30096 this.fireEvent('download', this);
30099 onTrash : function(e)
30101 e.preventDefault();
30103 this.fireEvent('trash', this);
30115 * @class Roo.bootstrap.NavProgressBar
30116 * @extends Roo.bootstrap.Component
30117 * Bootstrap NavProgressBar class
30120 * Create a new nav progress bar
30121 * @param {Object} config The config object
30124 Roo.bootstrap.NavProgressBar = function(config){
30125 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
30127 this.bullets = this.bullets || [];
30129 // Roo.bootstrap.NavProgressBar.register(this);
30133 * Fires when the active item changes
30134 * @param {Roo.bootstrap.NavProgressBar} this
30135 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
30136 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
30143 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
30148 getAutoCreate : function()
30150 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
30154 cls : 'roo-navigation-bar-group',
30158 cls : 'roo-navigation-top-bar'
30162 cls : 'roo-navigation-bullets-bar',
30166 cls : 'roo-navigation-bar'
30173 cls : 'roo-navigation-bottom-bar'
30183 initEvents: function()
30188 onRender : function(ct, position)
30190 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30192 if(this.bullets.length){
30193 Roo.each(this.bullets, function(b){
30202 addItem : function(cfg)
30204 var item = new Roo.bootstrap.NavProgressItem(cfg);
30206 item.parentId = this.id;
30207 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
30210 var top = new Roo.bootstrap.Element({
30212 cls : 'roo-navigation-bar-text'
30215 var bottom = new Roo.bootstrap.Element({
30217 cls : 'roo-navigation-bar-text'
30220 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
30221 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
30223 var topText = new Roo.bootstrap.Element({
30225 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
30228 var bottomText = new Roo.bootstrap.Element({
30230 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
30233 topText.onRender(top.el, null);
30234 bottomText.onRender(bottom.el, null);
30237 item.bottomEl = bottom;
30240 this.barItems.push(item);
30245 getActive : function()
30247 var active = false;
30249 Roo.each(this.barItems, function(v){
30251 if (!v.isActive()) {
30263 setActiveItem : function(item)
30267 Roo.each(this.barItems, function(v){
30268 if (v.rid == item.rid) {
30272 if (v.isActive()) {
30273 v.setActive(false);
30278 item.setActive(true);
30280 this.fireEvent('changed', this, item, prev);
30283 getBarItem: function(rid)
30287 Roo.each(this.barItems, function(e) {
30288 if (e.rid != rid) {
30299 indexOfItem : function(item)
30303 Roo.each(this.barItems, function(v, i){
30305 if (v.rid != item.rid) {
30316 setActiveNext : function()
30318 var i = this.indexOfItem(this.getActive());
30320 if (i > this.barItems.length) {
30324 this.setActiveItem(this.barItems[i+1]);
30327 setActivePrev : function()
30329 var i = this.indexOfItem(this.getActive());
30335 this.setActiveItem(this.barItems[i-1]);
30338 format : function()
30340 if(!this.barItems.length){
30344 var width = 100 / this.barItems.length;
30346 Roo.each(this.barItems, function(i){
30347 i.el.setStyle('width', width + '%');
30348 i.topEl.el.setStyle('width', width + '%');
30349 i.bottomEl.el.setStyle('width', width + '%');
30358 * Nav Progress Item
30363 * @class Roo.bootstrap.NavProgressItem
30364 * @extends Roo.bootstrap.Component
30365 * Bootstrap NavProgressItem class
30366 * @cfg {String} rid the reference id
30367 * @cfg {Boolean} active (true|false) Is item active default false
30368 * @cfg {Boolean} disabled (true|false) Is item active default false
30369 * @cfg {String} html
30370 * @cfg {String} position (top|bottom) text position default bottom
30371 * @cfg {String} icon show icon instead of number
30374 * Create a new NavProgressItem
30375 * @param {Object} config The config object
30377 Roo.bootstrap.NavProgressItem = function(config){
30378 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
30383 * The raw click event for the entire grid.
30384 * @param {Roo.bootstrap.NavProgressItem} this
30385 * @param {Roo.EventObject} e
30392 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
30398 position : 'bottom',
30401 getAutoCreate : function()
30403 var iconCls = 'roo-navigation-bar-item-icon';
30405 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
30409 cls: 'roo-navigation-bar-item',
30419 cfg.cls += ' active';
30422 cfg.cls += ' disabled';
30428 disable : function()
30430 this.setDisabled(true);
30433 enable : function()
30435 this.setDisabled(false);
30438 initEvents: function()
30440 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
30442 this.iconEl.on('click', this.onClick, this);
30445 onClick : function(e)
30447 e.preventDefault();
30453 if(this.fireEvent('click', this, e) === false){
30457 this.parent().setActiveItem(this);
30460 isActive: function ()
30462 return this.active;
30465 setActive : function(state)
30467 if(this.active == state){
30471 this.active = state;
30474 this.el.addClass('active');
30478 this.el.removeClass('active');
30483 setDisabled : function(state)
30485 if(this.disabled == state){
30489 this.disabled = state;
30492 this.el.addClass('disabled');
30496 this.el.removeClass('disabled');
30499 tooltipEl : function()
30501 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
30514 * @class Roo.bootstrap.FieldLabel
30515 * @extends Roo.bootstrap.Component
30516 * Bootstrap FieldLabel class
30517 * @cfg {String} html contents of the element
30518 * @cfg {String} tag tag of the element default label
30519 * @cfg {String} cls class of the element
30520 * @cfg {String} target label target
30521 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
30522 * @cfg {String} invalidClass DEPRICATED - BS4 uses is-invalid
30523 * @cfg {String} validClass DEPRICATED - BS4 uses is-valid
30524 * @cfg {String} iconTooltip default "This field is required"
30525 * @cfg {String} indicatorpos (left|right) default left
30528 * Create a new FieldLabel
30529 * @param {Object} config The config object
30532 Roo.bootstrap.FieldLabel = function(config){
30533 Roo.bootstrap.Element.superclass.constructor.call(this, config);
30538 * Fires after the field has been marked as invalid.
30539 * @param {Roo.form.FieldLabel} this
30540 * @param {String} msg The validation message
30545 * Fires after the field has been validated with no errors.
30546 * @param {Roo.form.FieldLabel} this
30552 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
30559 invalidClass : 'has-warning',
30560 validClass : 'has-success',
30561 iconTooltip : 'This field is required',
30562 indicatorpos : 'left',
30564 getAutoCreate : function(){
30567 if (!this.allowBlank) {
30573 cls : 'roo-bootstrap-field-label ' + this.cls,
30578 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star ' + cls,
30579 tooltip : this.iconTooltip
30588 if(this.indicatorpos == 'right'){
30591 cls : 'roo-bootstrap-field-label ' + this.cls,
30600 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star '+ cls,
30601 tooltip : this.iconTooltip
30610 initEvents: function()
30612 Roo.bootstrap.Element.superclass.initEvents.call(this);
30614 this.indicator = this.indicatorEl();
30616 if(this.indicator){
30617 this.indicator.removeClass('visible');
30618 this.indicator.addClass('invisible');
30621 Roo.bootstrap.FieldLabel.register(this);
30624 indicatorEl : function()
30626 var indicator = this.el.select('i.roo-required-indicator',true).first();
30637 * Mark this field as valid
30639 markValid : function()
30641 if(this.indicator){
30642 this.indicator.removeClass('visible');
30643 this.indicator.addClass('invisible');
30645 if (Roo.bootstrap.version == 3) {
30646 this.el.removeClass(this.invalidClass);
30647 this.el.addClass(this.validClass);
30649 this.el.removeClass('is-invalid');
30650 this.el.addClass('is-valid');
30654 this.fireEvent('valid', this);
30658 * Mark this field as invalid
30659 * @param {String} msg The validation message
30661 markInvalid : function(msg)
30663 if(this.indicator){
30664 this.indicator.removeClass('invisible');
30665 this.indicator.addClass('visible');
30667 if (Roo.bootstrap.version == 3) {
30668 this.el.removeClass(this.validClass);
30669 this.el.addClass(this.invalidClass);
30671 this.el.removeClass('is-valid');
30672 this.el.addClass('is-invalid');
30676 this.fireEvent('invalid', this, msg);
30682 Roo.apply(Roo.bootstrap.FieldLabel, {
30687 * register a FieldLabel Group
30688 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
30690 register : function(label)
30692 if(this.groups.hasOwnProperty(label.target)){
30696 this.groups[label.target] = label;
30700 * fetch a FieldLabel Group based on the target
30701 * @param {string} target
30702 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
30704 get: function(target) {
30705 if (typeof(this.groups[target]) == 'undefined') {
30709 return this.groups[target] ;
30718 * page DateSplitField.
30724 * @class Roo.bootstrap.DateSplitField
30725 * @extends Roo.bootstrap.Component
30726 * Bootstrap DateSplitField class
30727 * @cfg {string} fieldLabel - the label associated
30728 * @cfg {Number} labelWidth set the width of label (0-12)
30729 * @cfg {String} labelAlign (top|left)
30730 * @cfg {Boolean} dayAllowBlank (true|false) default false
30731 * @cfg {Boolean} monthAllowBlank (true|false) default false
30732 * @cfg {Boolean} yearAllowBlank (true|false) default false
30733 * @cfg {string} dayPlaceholder
30734 * @cfg {string} monthPlaceholder
30735 * @cfg {string} yearPlaceholder
30736 * @cfg {string} dayFormat default 'd'
30737 * @cfg {string} monthFormat default 'm'
30738 * @cfg {string} yearFormat default 'Y'
30739 * @cfg {Number} labellg set the width of label (1-12)
30740 * @cfg {Number} labelmd set the width of label (1-12)
30741 * @cfg {Number} labelsm set the width of label (1-12)
30742 * @cfg {Number} labelxs set the width of label (1-12)
30746 * Create a new DateSplitField
30747 * @param {Object} config The config object
30750 Roo.bootstrap.DateSplitField = function(config){
30751 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
30757 * getting the data of years
30758 * @param {Roo.bootstrap.DateSplitField} this
30759 * @param {Object} years
30764 * getting the data of days
30765 * @param {Roo.bootstrap.DateSplitField} this
30766 * @param {Object} days
30771 * Fires after the field has been marked as invalid.
30772 * @param {Roo.form.Field} this
30773 * @param {String} msg The validation message
30778 * Fires after the field has been validated with no errors.
30779 * @param {Roo.form.Field} this
30785 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
30788 labelAlign : 'top',
30790 dayAllowBlank : false,
30791 monthAllowBlank : false,
30792 yearAllowBlank : false,
30793 dayPlaceholder : '',
30794 monthPlaceholder : '',
30795 yearPlaceholder : '',
30799 isFormField : true,
30805 getAutoCreate : function()
30809 cls : 'row roo-date-split-field-group',
30814 cls : 'form-hidden-field roo-date-split-field-group-value',
30820 var labelCls = 'col-md-12';
30821 var contentCls = 'col-md-4';
30823 if(this.fieldLabel){
30827 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
30831 html : this.fieldLabel
30836 if(this.labelAlign == 'left'){
30838 if(this.labelWidth > 12){
30839 label.style = "width: " + this.labelWidth + 'px';
30842 if(this.labelWidth < 13 && this.labelmd == 0){
30843 this.labelmd = this.labelWidth;
30846 if(this.labellg > 0){
30847 labelCls = ' col-lg-' + this.labellg;
30848 contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
30851 if(this.labelmd > 0){
30852 labelCls = ' col-md-' + this.labelmd;
30853 contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
30856 if(this.labelsm > 0){
30857 labelCls = ' col-sm-' + this.labelsm;
30858 contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
30861 if(this.labelxs > 0){
30862 labelCls = ' col-xs-' + this.labelxs;
30863 contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
30867 label.cls += ' ' + labelCls;
30869 cfg.cn.push(label);
30872 Roo.each(['day', 'month', 'year'], function(t){
30875 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
30882 inputEl: function ()
30884 return this.el.select('.roo-date-split-field-group-value', true).first();
30887 onRender : function(ct, position)
30891 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30893 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
30895 this.dayField = new Roo.bootstrap.ComboBox({
30896 allowBlank : this.dayAllowBlank,
30897 alwaysQuery : true,
30898 displayField : 'value',
30901 forceSelection : true,
30903 placeholder : this.dayPlaceholder,
30904 selectOnFocus : true,
30905 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30906 triggerAction : 'all',
30908 valueField : 'value',
30909 store : new Roo.data.SimpleStore({
30910 data : (function() {
30912 _this.fireEvent('days', _this, days);
30915 fields : [ 'value' ]
30918 select : function (_self, record, index)
30920 _this.setValue(_this.getValue());
30925 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
30927 this.monthField = new Roo.bootstrap.MonthField({
30928 after : '<i class=\"fa fa-calendar\"></i>',
30929 allowBlank : this.monthAllowBlank,
30930 placeholder : this.monthPlaceholder,
30933 render : function (_self)
30935 this.el.select('span.input-group-addon', true).first().on('click', function(e){
30936 e.preventDefault();
30940 select : function (_self, oldvalue, newvalue)
30942 _this.setValue(_this.getValue());
30947 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
30949 this.yearField = new Roo.bootstrap.ComboBox({
30950 allowBlank : this.yearAllowBlank,
30951 alwaysQuery : true,
30952 displayField : 'value',
30955 forceSelection : true,
30957 placeholder : this.yearPlaceholder,
30958 selectOnFocus : true,
30959 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30960 triggerAction : 'all',
30962 valueField : 'value',
30963 store : new Roo.data.SimpleStore({
30964 data : (function() {
30966 _this.fireEvent('years', _this, years);
30969 fields : [ 'value' ]
30972 select : function (_self, record, index)
30974 _this.setValue(_this.getValue());
30979 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
30982 setValue : function(v, format)
30984 this.inputEl.dom.value = v;
30986 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
30988 var d = Date.parseDate(v, f);
30995 this.setDay(d.format(this.dayFormat));
30996 this.setMonth(d.format(this.monthFormat));
30997 this.setYear(d.format(this.yearFormat));
31004 setDay : function(v)
31006 this.dayField.setValue(v);
31007 this.inputEl.dom.value = this.getValue();
31012 setMonth : function(v)
31014 this.monthField.setValue(v, true);
31015 this.inputEl.dom.value = this.getValue();
31020 setYear : function(v)
31022 this.yearField.setValue(v);
31023 this.inputEl.dom.value = this.getValue();
31028 getDay : function()
31030 return this.dayField.getValue();
31033 getMonth : function()
31035 return this.monthField.getValue();
31038 getYear : function()
31040 return this.yearField.getValue();
31043 getValue : function()
31045 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
31047 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
31057 this.inputEl.dom.value = '';
31062 validate : function()
31064 var d = this.dayField.validate();
31065 var m = this.monthField.validate();
31066 var y = this.yearField.validate();
31071 (!this.dayAllowBlank && !d) ||
31072 (!this.monthAllowBlank && !m) ||
31073 (!this.yearAllowBlank && !y)
31078 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
31087 this.markInvalid();
31092 markValid : function()
31095 var label = this.el.select('label', true).first();
31096 var icon = this.el.select('i.fa-star', true).first();
31102 this.fireEvent('valid', this);
31106 * Mark this field as invalid
31107 * @param {String} msg The validation message
31109 markInvalid : function(msg)
31112 var label = this.el.select('label', true).first();
31113 var icon = this.el.select('i.fa-star', true).first();
31115 if(label && !icon){
31116 this.el.select('.roo-date-split-field-label', true).createChild({
31118 cls : 'text-danger fa fa-lg fa-star',
31119 tooltip : 'This field is required',
31120 style : 'margin-right:5px;'
31124 this.fireEvent('invalid', this, msg);
31127 clearInvalid : function()
31129 var label = this.el.select('label', true).first();
31130 var icon = this.el.select('i.fa-star', true).first();
31136 this.fireEvent('valid', this);
31139 getName: function()
31149 * http://masonry.desandro.com
31151 * The idea is to render all the bricks based on vertical width...
31153 * The original code extends 'outlayer' - we might need to use that....
31159 * @class Roo.bootstrap.LayoutMasonry
31160 * @extends Roo.bootstrap.Component
31161 * Bootstrap Layout Masonry class
31164 * Create a new Element
31165 * @param {Object} config The config object
31168 Roo.bootstrap.LayoutMasonry = function(config){
31170 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
31174 Roo.bootstrap.LayoutMasonry.register(this);
31180 * Fire after layout the items
31181 * @param {Roo.bootstrap.LayoutMasonry} this
31182 * @param {Roo.EventObject} e
31189 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
31192 * @cfg {Boolean} isLayoutInstant = no animation?
31194 isLayoutInstant : false, // needed?
31197 * @cfg {Number} boxWidth width of the columns
31202 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
31207 * @cfg {Number} padWidth padding below box..
31212 * @cfg {Number} gutter gutter width..
31217 * @cfg {Number} maxCols maximum number of columns
31223 * @cfg {Boolean} isAutoInitial defalut true
31225 isAutoInitial : true,
31230 * @cfg {Boolean} isHorizontal defalut false
31232 isHorizontal : false,
31234 currentSize : null,
31240 bricks: null, //CompositeElement
31244 _isLayoutInited : false,
31246 // isAlternative : false, // only use for vertical layout...
31249 * @cfg {Number} alternativePadWidth padding below box..
31251 alternativePadWidth : 50,
31253 selectedBrick : [],
31255 getAutoCreate : function(){
31257 var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
31261 cls: 'blog-masonary-wrapper ' + this.cls,
31263 cls : 'mas-boxes masonary'
31270 getChildContainer: function( )
31272 if (this.boxesEl) {
31273 return this.boxesEl;
31276 this.boxesEl = this.el.select('.mas-boxes').first();
31278 return this.boxesEl;
31282 initEvents : function()
31286 if(this.isAutoInitial){
31287 Roo.log('hook children rendered');
31288 this.on('childrenrendered', function() {
31289 Roo.log('children rendered');
31295 initial : function()
31297 this.selectedBrick = [];
31299 this.currentSize = this.el.getBox(true);
31301 Roo.EventManager.onWindowResize(this.resize, this);
31303 if(!this.isAutoInitial){
31311 //this.layout.defer(500,this);
31315 resize : function()
31317 var cs = this.el.getBox(true);
31320 this.currentSize.width == cs.width &&
31321 this.currentSize.x == cs.x &&
31322 this.currentSize.height == cs.height &&
31323 this.currentSize.y == cs.y
31325 Roo.log("no change in with or X or Y");
31329 this.currentSize = cs;
31335 layout : function()
31337 this._resetLayout();
31339 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
31341 this.layoutItems( isInstant );
31343 this._isLayoutInited = true;
31345 this.fireEvent('layout', this);
31349 _resetLayout : function()
31351 if(this.isHorizontal){
31352 this.horizontalMeasureColumns();
31356 this.verticalMeasureColumns();
31360 verticalMeasureColumns : function()
31362 this.getContainerWidth();
31364 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
31365 // this.colWidth = Math.floor(this.containerWidth * 0.8);
31369 var boxWidth = this.boxWidth + this.padWidth;
31371 if(this.containerWidth < this.boxWidth){
31372 boxWidth = this.containerWidth
31375 var containerWidth = this.containerWidth;
31377 var cols = Math.floor(containerWidth / boxWidth);
31379 this.cols = Math.max( cols, 1 );
31381 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
31383 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
31385 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
31387 this.colWidth = boxWidth + avail - this.padWidth;
31389 this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
31390 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
31393 horizontalMeasureColumns : function()
31395 this.getContainerWidth();
31397 var boxWidth = this.boxWidth;
31399 if(this.containerWidth < boxWidth){
31400 boxWidth = this.containerWidth;
31403 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
31405 this.el.setHeight(boxWidth);
31409 getContainerWidth : function()
31411 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
31414 layoutItems : function( isInstant )
31416 Roo.log(this.bricks);
31418 var items = Roo.apply([], this.bricks);
31420 if(this.isHorizontal){
31421 this._horizontalLayoutItems( items , isInstant );
31425 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
31426 // this._verticalAlternativeLayoutItems( items , isInstant );
31430 this._verticalLayoutItems( items , isInstant );
31434 _verticalLayoutItems : function ( items , isInstant)
31436 if ( !items || !items.length ) {
31441 ['xs', 'xs', 'xs', 'tall'],
31442 ['xs', 'xs', 'tall'],
31443 ['xs', 'xs', 'sm'],
31444 ['xs', 'xs', 'xs'],
31450 ['sm', 'xs', 'xs'],
31454 ['tall', 'xs', 'xs', 'xs'],
31455 ['tall', 'xs', 'xs'],
31467 Roo.each(items, function(item, k){
31469 switch (item.size) {
31470 // these layouts take up a full box,
31481 boxes.push([item]);
31504 var filterPattern = function(box, length)
31512 var pattern = box.slice(0, length);
31516 Roo.each(pattern, function(i){
31517 format.push(i.size);
31520 Roo.each(standard, function(s){
31522 if(String(s) != String(format)){
31531 if(!match && length == 1){
31536 filterPattern(box, length - 1);
31540 queue.push(pattern);
31542 box = box.slice(length, box.length);
31544 filterPattern(box, 4);
31550 Roo.each(boxes, function(box, k){
31556 if(box.length == 1){
31561 filterPattern(box, 4);
31565 this._processVerticalLayoutQueue( queue, isInstant );
31569 // _verticalAlternativeLayoutItems : function( items , isInstant )
31571 // if ( !items || !items.length ) {
31575 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
31579 _horizontalLayoutItems : function ( items , isInstant)
31581 if ( !items || !items.length || items.length < 3) {
31587 var eItems = items.slice(0, 3);
31589 items = items.slice(3, items.length);
31592 ['xs', 'xs', 'xs', 'wide'],
31593 ['xs', 'xs', 'wide'],
31594 ['xs', 'xs', 'sm'],
31595 ['xs', 'xs', 'xs'],
31601 ['sm', 'xs', 'xs'],
31605 ['wide', 'xs', 'xs', 'xs'],
31606 ['wide', 'xs', 'xs'],
31619 Roo.each(items, function(item, k){
31621 switch (item.size) {
31632 boxes.push([item]);
31656 var filterPattern = function(box, length)
31664 var pattern = box.slice(0, length);
31668 Roo.each(pattern, function(i){
31669 format.push(i.size);
31672 Roo.each(standard, function(s){
31674 if(String(s) != String(format)){
31683 if(!match && length == 1){
31688 filterPattern(box, length - 1);
31692 queue.push(pattern);
31694 box = box.slice(length, box.length);
31696 filterPattern(box, 4);
31702 Roo.each(boxes, function(box, k){
31708 if(box.length == 1){
31713 filterPattern(box, 4);
31720 var pos = this.el.getBox(true);
31724 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31726 var hit_end = false;
31728 Roo.each(queue, function(box){
31732 Roo.each(box, function(b){
31734 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31744 Roo.each(box, function(b){
31746 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31749 mx = Math.max(mx, b.x);
31753 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
31757 Roo.each(box, function(b){
31759 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31773 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
31776 /** Sets position of item in DOM
31777 * @param {Element} item
31778 * @param {Number} x - horizontal position
31779 * @param {Number} y - vertical position
31780 * @param {Boolean} isInstant - disables transitions
31782 _processVerticalLayoutQueue : function( queue, isInstant )
31784 var pos = this.el.getBox(true);
31789 for (var i = 0; i < this.cols; i++){
31793 Roo.each(queue, function(box, k){
31795 var col = k % this.cols;
31797 Roo.each(box, function(b,kk){
31799 b.el.position('absolute');
31801 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31802 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31804 if(b.size == 'md-left' || b.size == 'md-right'){
31805 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31806 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31809 b.el.setWidth(width);
31810 b.el.setHeight(height);
31812 b.el.select('iframe',true).setSize(width,height);
31816 for (var i = 0; i < this.cols; i++){
31818 if(maxY[i] < maxY[col]){
31823 col = Math.min(col, i);
31827 x = pos.x + col * (this.colWidth + this.padWidth);
31831 var positions = [];
31833 switch (box.length){
31835 positions = this.getVerticalOneBoxColPositions(x, y, box);
31838 positions = this.getVerticalTwoBoxColPositions(x, y, box);
31841 positions = this.getVerticalThreeBoxColPositions(x, y, box);
31844 positions = this.getVerticalFourBoxColPositions(x, y, box);
31850 Roo.each(box, function(b,kk){
31852 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31854 var sz = b.el.getSize();
31856 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
31864 for (var i = 0; i < this.cols; i++){
31865 mY = Math.max(mY, maxY[i]);
31868 this.el.setHeight(mY - pos.y);
31872 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
31874 // var pos = this.el.getBox(true);
31877 // var maxX = pos.right;
31879 // var maxHeight = 0;
31881 // Roo.each(items, function(item, k){
31885 // item.el.position('absolute');
31887 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
31889 // item.el.setWidth(width);
31891 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
31893 // item.el.setHeight(height);
31896 // item.el.setXY([x, y], isInstant ? false : true);
31898 // item.el.setXY([maxX - width, y], isInstant ? false : true);
31901 // y = y + height + this.alternativePadWidth;
31903 // maxHeight = maxHeight + height + this.alternativePadWidth;
31907 // this.el.setHeight(maxHeight);
31911 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
31913 var pos = this.el.getBox(true);
31918 var maxX = pos.right;
31920 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
31922 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31924 Roo.each(queue, function(box, k){
31926 Roo.each(box, function(b, kk){
31928 b.el.position('absolute');
31930 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31931 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31933 if(b.size == 'md-left' || b.size == 'md-right'){
31934 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31935 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31938 b.el.setWidth(width);
31939 b.el.setHeight(height);
31947 var positions = [];
31949 switch (box.length){
31951 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
31954 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
31957 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
31960 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
31966 Roo.each(box, function(b,kk){
31968 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31970 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
31978 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
31980 Roo.each(eItems, function(b,k){
31982 b.size = (k == 0) ? 'sm' : 'xs';
31983 b.x = (k == 0) ? 2 : 1;
31984 b.y = (k == 0) ? 2 : 1;
31986 b.el.position('absolute');
31988 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31990 b.el.setWidth(width);
31992 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31994 b.el.setHeight(height);
31998 var positions = [];
32001 x : maxX - this.unitWidth * 2 - this.gutter,
32006 x : maxX - this.unitWidth,
32007 y : minY + (this.unitWidth + this.gutter) * 2
32011 x : maxX - this.unitWidth * 3 - this.gutter * 2,
32015 Roo.each(eItems, function(b,k){
32017 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
32023 getVerticalOneBoxColPositions : function(x, y, box)
32027 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
32029 if(box[0].size == 'md-left'){
32033 if(box[0].size == 'md-right'){
32038 x : x + (this.unitWidth + this.gutter) * rand,
32045 getVerticalTwoBoxColPositions : function(x, y, box)
32049 if(box[0].size == 'xs'){
32053 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
32057 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
32071 x : x + (this.unitWidth + this.gutter) * 2,
32072 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
32079 getVerticalThreeBoxColPositions : function(x, y, box)
32083 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
32091 x : x + (this.unitWidth + this.gutter) * 1,
32096 x : x + (this.unitWidth + this.gutter) * 2,
32104 if(box[0].size == 'xs' && box[1].size == 'xs'){
32113 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
32117 x : x + (this.unitWidth + this.gutter) * 1,
32131 x : x + (this.unitWidth + this.gutter) * 2,
32136 x : x + (this.unitWidth + this.gutter) * 2,
32137 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
32144 getVerticalFourBoxColPositions : function(x, y, box)
32148 if(box[0].size == 'xs'){
32157 y : y + (this.unitHeight + this.gutter) * 1
32162 y : y + (this.unitHeight + this.gutter) * 2
32166 x : x + (this.unitWidth + this.gutter) * 1,
32180 x : x + (this.unitWidth + this.gutter) * 2,
32185 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
32186 y : y + (this.unitHeight + this.gutter) * 1
32190 x : x + (this.unitWidth + this.gutter) * 2,
32191 y : y + (this.unitWidth + this.gutter) * 2
32198 getHorizontalOneBoxColPositions : function(maxX, minY, box)
32202 if(box[0].size == 'md-left'){
32204 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
32211 if(box[0].size == 'md-right'){
32213 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
32214 y : minY + (this.unitWidth + this.gutter) * 1
32220 var rand = Math.floor(Math.random() * (4 - box[0].y));
32223 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32224 y : minY + (this.unitWidth + this.gutter) * rand
32231 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
32235 if(box[0].size == 'xs'){
32238 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32243 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32244 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
32252 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32257 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32258 y : minY + (this.unitWidth + this.gutter) * 2
32265 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
32269 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
32272 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32277 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32278 y : minY + (this.unitWidth + this.gutter) * 1
32282 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32283 y : minY + (this.unitWidth + this.gutter) * 2
32290 if(box[0].size == 'xs' && box[1].size == 'xs'){
32293 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32298 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32303 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32304 y : minY + (this.unitWidth + this.gutter) * 1
32312 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32317 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32318 y : minY + (this.unitWidth + this.gutter) * 2
32322 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32323 y : minY + (this.unitWidth + this.gutter) * 2
32330 getHorizontalFourBoxColPositions : function(maxX, minY, box)
32334 if(box[0].size == 'xs'){
32337 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32342 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32347 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),
32352 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
32353 y : minY + (this.unitWidth + this.gutter) * 1
32361 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32366 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32367 y : minY + (this.unitWidth + this.gutter) * 2
32371 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32372 y : minY + (this.unitWidth + this.gutter) * 2
32376 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),
32377 y : minY + (this.unitWidth + this.gutter) * 2
32385 * remove a Masonry Brick
32386 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
32388 removeBrick : function(brick_id)
32394 for (var i = 0; i<this.bricks.length; i++) {
32395 if (this.bricks[i].id == brick_id) {
32396 this.bricks.splice(i,1);
32397 this.el.dom.removeChild(Roo.get(brick_id).dom);
32404 * adds a Masonry Brick
32405 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32407 addBrick : function(cfg)
32409 var cn = new Roo.bootstrap.MasonryBrick(cfg);
32410 //this.register(cn);
32411 cn.parentId = this.id;
32412 cn.render(this.el);
32417 * register a Masonry Brick
32418 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32421 register : function(brick)
32423 this.bricks.push(brick);
32424 brick.masonryId = this.id;
32428 * clear all the Masonry Brick
32430 clearAll : function()
32433 //this.getChildContainer().dom.innerHTML = "";
32434 this.el.dom.innerHTML = '';
32437 getSelected : function()
32439 if (!this.selectedBrick) {
32443 return this.selectedBrick;
32447 Roo.apply(Roo.bootstrap.LayoutMasonry, {
32451 * register a Masonry Layout
32452 * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
32455 register : function(layout)
32457 this.groups[layout.id] = layout;
32460 * fetch a Masonry Layout based on the masonry layout ID
32461 * @param {string} the masonry layout to add
32462 * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
32465 get: function(layout_id) {
32466 if (typeof(this.groups[layout_id]) == 'undefined') {
32469 return this.groups[layout_id] ;
32481 * http://masonry.desandro.com
32483 * The idea is to render all the bricks based on vertical width...
32485 * The original code extends 'outlayer' - we might need to use that....
32491 * @class Roo.bootstrap.LayoutMasonryAuto
32492 * @extends Roo.bootstrap.Component
32493 * Bootstrap Layout Masonry class
32496 * Create a new Element
32497 * @param {Object} config The config object
32500 Roo.bootstrap.LayoutMasonryAuto = function(config){
32501 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
32504 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
32507 * @cfg {Boolean} isFitWidth - resize the width..
32509 isFitWidth : false, // options..
32511 * @cfg {Boolean} isOriginLeft = left align?
32513 isOriginLeft : true,
32515 * @cfg {Boolean} isOriginTop = top align?
32517 isOriginTop : false,
32519 * @cfg {Boolean} isLayoutInstant = no animation?
32521 isLayoutInstant : false, // needed?
32523 * @cfg {Boolean} isResizingContainer = not sure if this is used..
32525 isResizingContainer : true,
32527 * @cfg {Number} columnWidth width of the columns
32533 * @cfg {Number} maxCols maximum number of columns
32538 * @cfg {Number} padHeight padding below box..
32544 * @cfg {Boolean} isAutoInitial defalut true
32547 isAutoInitial : true,
32553 initialColumnWidth : 0,
32554 currentSize : null,
32556 colYs : null, // array.
32563 bricks: null, //CompositeElement
32564 cols : 0, // array?
32565 // element : null, // wrapped now this.el
32566 _isLayoutInited : null,
32569 getAutoCreate : function(){
32573 cls: 'blog-masonary-wrapper ' + this.cls,
32575 cls : 'mas-boxes masonary'
32582 getChildContainer: function( )
32584 if (this.boxesEl) {
32585 return this.boxesEl;
32588 this.boxesEl = this.el.select('.mas-boxes').first();
32590 return this.boxesEl;
32594 initEvents : function()
32598 if(this.isAutoInitial){
32599 Roo.log('hook children rendered');
32600 this.on('childrenrendered', function() {
32601 Roo.log('children rendered');
32608 initial : function()
32610 this.reloadItems();
32612 this.currentSize = this.el.getBox(true);
32614 /// was window resize... - let's see if this works..
32615 Roo.EventManager.onWindowResize(this.resize, this);
32617 if(!this.isAutoInitial){
32622 this.layout.defer(500,this);
32625 reloadItems: function()
32627 this.bricks = this.el.select('.masonry-brick', true);
32629 this.bricks.each(function(b) {
32630 //Roo.log(b.getSize());
32631 if (!b.attr('originalwidth')) {
32632 b.attr('originalwidth', b.getSize().width);
32637 Roo.log(this.bricks.elements.length);
32640 resize : function()
32643 var cs = this.el.getBox(true);
32645 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
32646 Roo.log("no change in with or X");
32649 this.currentSize = cs;
32653 layout : function()
32656 this._resetLayout();
32657 //this._manageStamps();
32659 // don't animate first layout
32660 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
32661 this.layoutItems( isInstant );
32663 // flag for initalized
32664 this._isLayoutInited = true;
32667 layoutItems : function( isInstant )
32669 //var items = this._getItemsForLayout( this.items );
32670 // original code supports filtering layout items.. we just ignore it..
32672 this._layoutItems( this.bricks , isInstant );
32674 this._postLayout();
32676 _layoutItems : function ( items , isInstant)
32678 //this.fireEvent( 'layout', this, items );
32681 if ( !items || !items.elements.length ) {
32682 // no items, emit event with empty array
32687 items.each(function(item) {
32688 Roo.log("layout item");
32690 // get x/y object from method
32691 var position = this._getItemLayoutPosition( item );
32693 position.item = item;
32694 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
32695 queue.push( position );
32698 this._processLayoutQueue( queue );
32700 /** Sets position of item in DOM
32701 * @param {Element} item
32702 * @param {Number} x - horizontal position
32703 * @param {Number} y - vertical position
32704 * @param {Boolean} isInstant - disables transitions
32706 _processLayoutQueue : function( queue )
32708 for ( var i=0, len = queue.length; i < len; i++ ) {
32709 var obj = queue[i];
32710 obj.item.position('absolute');
32711 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
32717 * Any logic you want to do after each layout,
32718 * i.e. size the container
32720 _postLayout : function()
32722 this.resizeContainer();
32725 resizeContainer : function()
32727 if ( !this.isResizingContainer ) {
32730 var size = this._getContainerSize();
32732 this.el.setSize(size.width,size.height);
32733 this.boxesEl.setSize(size.width,size.height);
32739 _resetLayout : function()
32741 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
32742 this.colWidth = this.el.getWidth();
32743 //this.gutter = this.el.getWidth();
32745 this.measureColumns();
32751 this.colYs.push( 0 );
32757 measureColumns : function()
32759 this.getContainerWidth();
32760 // if columnWidth is 0, default to outerWidth of first item
32761 if ( !this.columnWidth ) {
32762 var firstItem = this.bricks.first();
32763 Roo.log(firstItem);
32764 this.columnWidth = this.containerWidth;
32765 if (firstItem && firstItem.attr('originalwidth') ) {
32766 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
32768 // columnWidth fall back to item of first element
32769 Roo.log("set column width?");
32770 this.initialColumnWidth = this.columnWidth ;
32772 // if first elem has no width, default to size of container
32777 if (this.initialColumnWidth) {
32778 this.columnWidth = this.initialColumnWidth;
32783 // column width is fixed at the top - however if container width get's smaller we should
32786 // this bit calcs how man columns..
32788 var columnWidth = this.columnWidth += this.gutter;
32790 // calculate columns
32791 var containerWidth = this.containerWidth + this.gutter;
32793 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
32794 // fix rounding errors, typically with gutters
32795 var excess = columnWidth - containerWidth % columnWidth;
32798 // if overshoot is less than a pixel, round up, otherwise floor it
32799 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
32800 cols = Math[ mathMethod ]( cols );
32801 this.cols = Math.max( cols, 1 );
32802 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
32804 // padding positioning..
32805 var totalColWidth = this.cols * this.columnWidth;
32806 var padavail = this.containerWidth - totalColWidth;
32807 // so for 2 columns - we need 3 'pads'
32809 var padNeeded = (1+this.cols) * this.padWidth;
32811 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
32813 this.columnWidth += padExtra
32814 //this.padWidth = Math.floor(padavail / ( this.cols));
32816 // adjust colum width so that padding is fixed??
32818 // we have 3 columns ... total = width * 3
32819 // we have X left over... that should be used by
32821 //if (this.expandC) {
32829 getContainerWidth : function()
32831 /* // container is parent if fit width
32832 var container = this.isFitWidth ? this.element.parentNode : this.element;
32833 // check that this.size and size are there
32834 // IE8 triggers resize on body size change, so they might not be
32836 var size = getSize( container ); //FIXME
32837 this.containerWidth = size && size.innerWidth; //FIXME
32840 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
32844 _getItemLayoutPosition : function( item ) // what is item?
32846 // we resize the item to our columnWidth..
32848 item.setWidth(this.columnWidth);
32849 item.autoBoxAdjust = false;
32851 var sz = item.getSize();
32853 // how many columns does this brick span
32854 var remainder = this.containerWidth % this.columnWidth;
32856 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
32857 // round if off by 1 pixel, otherwise use ceil
32858 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
32859 colSpan = Math.min( colSpan, this.cols );
32861 // normally this should be '1' as we dont' currently allow multi width columns..
32863 var colGroup = this._getColGroup( colSpan );
32864 // get the minimum Y value from the columns
32865 var minimumY = Math.min.apply( Math, colGroup );
32866 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32868 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
32870 // position the brick
32872 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
32873 y: this.currentSize.y + minimumY + this.padHeight
32877 // apply setHeight to necessary columns
32878 var setHeight = minimumY + sz.height + this.padHeight;
32879 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32881 var setSpan = this.cols + 1 - colGroup.length;
32882 for ( var i = 0; i < setSpan; i++ ) {
32883 this.colYs[ shortColIndex + i ] = setHeight ;
32890 * @param {Number} colSpan - number of columns the element spans
32891 * @returns {Array} colGroup
32893 _getColGroup : function( colSpan )
32895 if ( colSpan < 2 ) {
32896 // if brick spans only one column, use all the column Ys
32901 // how many different places could this brick fit horizontally
32902 var groupCount = this.cols + 1 - colSpan;
32903 // for each group potential horizontal position
32904 for ( var i = 0; i < groupCount; i++ ) {
32905 // make an array of colY values for that one group
32906 var groupColYs = this.colYs.slice( i, i + colSpan );
32907 // and get the max value of the array
32908 colGroup[i] = Math.max.apply( Math, groupColYs );
32913 _manageStamp : function( stamp )
32915 var stampSize = stamp.getSize();
32916 var offset = stamp.getBox();
32917 // get the columns that this stamp affects
32918 var firstX = this.isOriginLeft ? offset.x : offset.right;
32919 var lastX = firstX + stampSize.width;
32920 var firstCol = Math.floor( firstX / this.columnWidth );
32921 firstCol = Math.max( 0, firstCol );
32923 var lastCol = Math.floor( lastX / this.columnWidth );
32924 // lastCol should not go over if multiple of columnWidth #425
32925 lastCol -= lastX % this.columnWidth ? 0 : 1;
32926 lastCol = Math.min( this.cols - 1, lastCol );
32928 // set colYs to bottom of the stamp
32929 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
32932 for ( var i = firstCol; i <= lastCol; i++ ) {
32933 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
32938 _getContainerSize : function()
32940 this.maxY = Math.max.apply( Math, this.colYs );
32945 if ( this.isFitWidth ) {
32946 size.width = this._getContainerFitWidth();
32952 _getContainerFitWidth : function()
32954 var unusedCols = 0;
32955 // count unused columns
32958 if ( this.colYs[i] !== 0 ) {
32963 // fit container to columns that have been used
32964 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
32967 needsResizeLayout : function()
32969 var previousWidth = this.containerWidth;
32970 this.getContainerWidth();
32971 return previousWidth !== this.containerWidth;
32986 * @class Roo.bootstrap.MasonryBrick
32987 * @extends Roo.bootstrap.Component
32988 * Bootstrap MasonryBrick class
32991 * Create a new MasonryBrick
32992 * @param {Object} config The config object
32995 Roo.bootstrap.MasonryBrick = function(config){
32997 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
32999 Roo.bootstrap.MasonryBrick.register(this);
33005 * When a MasonryBrick is clcik
33006 * @param {Roo.bootstrap.MasonryBrick} this
33007 * @param {Roo.EventObject} e
33013 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
33016 * @cfg {String} title
33020 * @cfg {String} html
33024 * @cfg {String} bgimage
33028 * @cfg {String} videourl
33032 * @cfg {String} cls
33036 * @cfg {String} href
33040 * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
33045 * @cfg {String} placetitle (center|bottom)
33050 * @cfg {Boolean} isFitContainer defalut true
33052 isFitContainer : true,
33055 * @cfg {Boolean} preventDefault defalut false
33057 preventDefault : false,
33060 * @cfg {Boolean} inverse defalut false
33062 maskInverse : false,
33064 getAutoCreate : function()
33066 if(!this.isFitContainer){
33067 return this.getSplitAutoCreate();
33070 var cls = 'masonry-brick masonry-brick-full';
33072 if(this.href.length){
33073 cls += ' masonry-brick-link';
33076 if(this.bgimage.length){
33077 cls += ' masonry-brick-image';
33080 if(this.maskInverse){
33081 cls += ' mask-inverse';
33084 if(!this.html.length && !this.maskInverse && !this.videourl.length){
33085 cls += ' enable-mask';
33089 cls += ' masonry-' + this.size + '-brick';
33092 if(this.placetitle.length){
33094 switch (this.placetitle) {
33096 cls += ' masonry-center-title';
33099 cls += ' masonry-bottom-title';
33106 if(!this.html.length && !this.bgimage.length){
33107 cls += ' masonry-center-title';
33110 if(!this.html.length && this.bgimage.length){
33111 cls += ' masonry-bottom-title';
33116 cls += ' ' + this.cls;
33120 tag: (this.href.length) ? 'a' : 'div',
33125 cls: 'masonry-brick-mask'
33129 cls: 'masonry-brick-paragraph',
33135 if(this.href.length){
33136 cfg.href = this.href;
33139 var cn = cfg.cn[1].cn;
33141 if(this.title.length){
33144 cls: 'masonry-brick-title',
33149 if(this.html.length){
33152 cls: 'masonry-brick-text',
33157 if (!this.title.length && !this.html.length) {
33158 cfg.cn[1].cls += ' hide';
33161 if(this.bgimage.length){
33164 cls: 'masonry-brick-image-view',
33169 if(this.videourl.length){
33170 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
33171 // youtube support only?
33174 cls: 'masonry-brick-image-view',
33177 allowfullscreen : true
33185 getSplitAutoCreate : function()
33187 var cls = 'masonry-brick masonry-brick-split';
33189 if(this.href.length){
33190 cls += ' masonry-brick-link';
33193 if(this.bgimage.length){
33194 cls += ' masonry-brick-image';
33198 cls += ' masonry-' + this.size + '-brick';
33201 switch (this.placetitle) {
33203 cls += ' masonry-center-title';
33206 cls += ' masonry-bottom-title';
33209 if(!this.bgimage.length){
33210 cls += ' masonry-center-title';
33213 if(this.bgimage.length){
33214 cls += ' masonry-bottom-title';
33220 cls += ' ' + this.cls;
33224 tag: (this.href.length) ? 'a' : 'div',
33229 cls: 'masonry-brick-split-head',
33233 cls: 'masonry-brick-paragraph',
33240 cls: 'masonry-brick-split-body',
33246 if(this.href.length){
33247 cfg.href = this.href;
33250 if(this.title.length){
33251 cfg.cn[0].cn[0].cn.push({
33253 cls: 'masonry-brick-title',
33258 if(this.html.length){
33259 cfg.cn[1].cn.push({
33261 cls: 'masonry-brick-text',
33266 if(this.bgimage.length){
33267 cfg.cn[0].cn.push({
33269 cls: 'masonry-brick-image-view',
33274 if(this.videourl.length){
33275 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
33276 // youtube support only?
33277 cfg.cn[0].cn.cn.push({
33279 cls: 'masonry-brick-image-view',
33282 allowfullscreen : true
33289 initEvents: function()
33291 switch (this.size) {
33324 this.el.on('touchstart', this.onTouchStart, this);
33325 this.el.on('touchmove', this.onTouchMove, this);
33326 this.el.on('touchend', this.onTouchEnd, this);
33327 this.el.on('contextmenu', this.onContextMenu, this);
33329 this.el.on('mouseenter' ,this.enter, this);
33330 this.el.on('mouseleave', this.leave, this);
33331 this.el.on('click', this.onClick, this);
33334 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
33335 this.parent().bricks.push(this);
33340 onClick: function(e, el)
33342 var time = this.endTimer - this.startTimer;
33343 // Roo.log(e.preventDefault());
33346 e.preventDefault();
33351 if(!this.preventDefault){
33355 e.preventDefault();
33357 if (this.activeClass != '') {
33358 this.selectBrick();
33361 this.fireEvent('click', this, e);
33364 enter: function(e, el)
33366 e.preventDefault();
33368 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
33372 if(this.bgimage.length && this.html.length){
33373 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
33377 leave: function(e, el)
33379 e.preventDefault();
33381 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
33385 if(this.bgimage.length && this.html.length){
33386 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
33390 onTouchStart: function(e, el)
33392 // e.preventDefault();
33394 this.touchmoved = false;
33396 if(!this.isFitContainer){
33400 if(!this.bgimage.length || !this.html.length){
33404 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
33406 this.timer = new Date().getTime();
33410 onTouchMove: function(e, el)
33412 this.touchmoved = true;
33415 onContextMenu : function(e,el)
33417 e.preventDefault();
33418 e.stopPropagation();
33422 onTouchEnd: function(e, el)
33424 // e.preventDefault();
33426 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
33433 if(!this.bgimage.length || !this.html.length){
33435 if(this.href.length){
33436 window.location.href = this.href;
33442 if(!this.isFitContainer){
33446 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
33448 window.location.href = this.href;
33451 //selection on single brick only
33452 selectBrick : function() {
33454 if (!this.parentId) {
33458 var m = Roo.bootstrap.LayoutMasonry.get(this.parentId);
33459 var index = m.selectedBrick.indexOf(this.id);
33462 m.selectedBrick.splice(index,1);
33463 this.el.removeClass(this.activeClass);
33467 for(var i = 0; i < m.selectedBrick.length; i++) {
33468 var b = Roo.bootstrap.MasonryBrick.get(m.selectedBrick[i]);
33469 b.el.removeClass(b.activeClass);
33472 m.selectedBrick = [];
33474 m.selectedBrick.push(this.id);
33475 this.el.addClass(this.activeClass);
33479 isSelected : function(){
33480 return this.el.hasClass(this.activeClass);
33485 Roo.apply(Roo.bootstrap.MasonryBrick, {
33488 groups : new Roo.util.MixedCollection(false, function(o) { return o.el.id; }),
33490 * register a Masonry Brick
33491 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
33494 register : function(brick)
33496 //this.groups[brick.id] = brick;
33497 this.groups.add(brick.id, brick);
33500 * fetch a masonry brick based on the masonry brick ID
33501 * @param {string} the masonry brick to add
33502 * @returns {Roo.bootstrap.MasonryBrick} the masonry brick
33505 get: function(brick_id)
33507 // if (typeof(this.groups[brick_id]) == 'undefined') {
33510 // return this.groups[brick_id] ;
33512 if(this.groups.key(brick_id)) {
33513 return this.groups.key(brick_id);
33531 * @class Roo.bootstrap.Brick
33532 * @extends Roo.bootstrap.Component
33533 * Bootstrap Brick class
33536 * Create a new Brick
33537 * @param {Object} config The config object
33540 Roo.bootstrap.Brick = function(config){
33541 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
33547 * When a Brick is click
33548 * @param {Roo.bootstrap.Brick} this
33549 * @param {Roo.EventObject} e
33555 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
33558 * @cfg {String} title
33562 * @cfg {String} html
33566 * @cfg {String} bgimage
33570 * @cfg {String} cls
33574 * @cfg {String} href
33578 * @cfg {String} video
33582 * @cfg {Boolean} square
33586 getAutoCreate : function()
33588 var cls = 'roo-brick';
33590 if(this.href.length){
33591 cls += ' roo-brick-link';
33594 if(this.bgimage.length){
33595 cls += ' roo-brick-image';
33598 if(!this.html.length && !this.bgimage.length){
33599 cls += ' roo-brick-center-title';
33602 if(!this.html.length && this.bgimage.length){
33603 cls += ' roo-brick-bottom-title';
33607 cls += ' ' + this.cls;
33611 tag: (this.href.length) ? 'a' : 'div',
33616 cls: 'roo-brick-paragraph',
33622 if(this.href.length){
33623 cfg.href = this.href;
33626 var cn = cfg.cn[0].cn;
33628 if(this.title.length){
33631 cls: 'roo-brick-title',
33636 if(this.html.length){
33639 cls: 'roo-brick-text',
33646 if(this.bgimage.length){
33649 cls: 'roo-brick-image-view',
33657 initEvents: function()
33659 if(this.title.length || this.html.length){
33660 this.el.on('mouseenter' ,this.enter, this);
33661 this.el.on('mouseleave', this.leave, this);
33664 Roo.EventManager.onWindowResize(this.resize, this);
33666 if(this.bgimage.length){
33667 this.imageEl = this.el.select('.roo-brick-image-view', true).first();
33668 this.imageEl.on('load', this.onImageLoad, this);
33675 onImageLoad : function()
33680 resize : function()
33682 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
33684 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
33686 if(this.bgimage.length){
33687 var image = this.el.select('.roo-brick-image-view', true).first();
33689 image.setWidth(paragraph.getWidth());
33692 image.setHeight(paragraph.getWidth());
33695 this.el.setHeight(image.getHeight());
33696 paragraph.setHeight(image.getHeight());
33702 enter: function(e, el)
33704 e.preventDefault();
33706 if(this.bgimage.length){
33707 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
33708 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
33712 leave: function(e, el)
33714 e.preventDefault();
33716 if(this.bgimage.length){
33717 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
33718 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
33733 * @class Roo.bootstrap.NumberField
33734 * @extends Roo.bootstrap.Input
33735 * Bootstrap NumberField class
33741 * Create a new NumberField
33742 * @param {Object} config The config object
33745 Roo.bootstrap.NumberField = function(config){
33746 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
33749 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
33752 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
33754 allowDecimals : true,
33756 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
33758 decimalSeparator : ".",
33760 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
33762 decimalPrecision : 2,
33764 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
33766 allowNegative : true,
33769 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
33773 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
33775 minValue : Number.NEGATIVE_INFINITY,
33777 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
33779 maxValue : Number.MAX_VALUE,
33781 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
33783 minText : "The minimum value for this field is {0}",
33785 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
33787 maxText : "The maximum value for this field is {0}",
33789 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
33790 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
33792 nanText : "{0} is not a valid number",
33794 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
33796 thousandsDelimiter : false,
33798 * @cfg {String} valueAlign alignment of value
33800 valueAlign : "left",
33802 getAutoCreate : function()
33804 var hiddenInput = {
33808 cls: 'hidden-number-input'
33812 hiddenInput.name = this.name;
33817 var cfg = Roo.bootstrap.NumberField.superclass.getAutoCreate.call(this);
33819 this.name = hiddenInput.name;
33821 if(cfg.cn.length > 0) {
33822 cfg.cn.push(hiddenInput);
33829 initEvents : function()
33831 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
33833 var allowed = "0123456789";
33835 if(this.allowDecimals){
33836 allowed += this.decimalSeparator;
33839 if(this.allowNegative){
33843 if(this.thousandsDelimiter) {
33847 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
33849 var keyPress = function(e){
33851 var k = e.getKey();
33853 var c = e.getCharCode();
33856 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
33857 allowed.indexOf(String.fromCharCode(c)) === -1
33863 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
33867 if(allowed.indexOf(String.fromCharCode(c)) === -1){
33872 this.el.on("keypress", keyPress, this);
33875 validateValue : function(value)
33878 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
33882 var num = this.parseValue(value);
33885 this.markInvalid(String.format(this.nanText, value));
33889 if(num < this.minValue){
33890 this.markInvalid(String.format(this.minText, this.minValue));
33894 if(num > this.maxValue){
33895 this.markInvalid(String.format(this.maxText, this.maxValue));
33902 getValue : function()
33904 var v = this.hiddenEl().getValue();
33906 return this.fixPrecision(this.parseValue(v));
33909 parseValue : function(value)
33911 if(this.thousandsDelimiter) {
33913 r = new RegExp(",", "g");
33914 value = value.replace(r, "");
33917 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
33918 return isNaN(value) ? '' : value;
33921 fixPrecision : function(value)
33923 if(this.thousandsDelimiter) {
33925 r = new RegExp(",", "g");
33926 value = value.replace(r, "");
33929 var nan = isNaN(value);
33931 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
33932 return nan ? '' : value;
33934 return parseFloat(value).toFixed(this.decimalPrecision);
33937 setValue : function(v)
33939 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
33945 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
33947 this.inputEl().dom.value = (v == '') ? '' :
33948 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
33950 if(!this.allowZero && v === '0') {
33951 this.hiddenEl().dom.value = '';
33952 this.inputEl().dom.value = '';
33959 decimalPrecisionFcn : function(v)
33961 return Math.floor(v);
33964 beforeBlur : function()
33966 var v = this.parseValue(this.getRawValue());
33968 if(v || v === 0 || v === ''){
33973 hiddenEl : function()
33975 return this.el.select('input.hidden-number-input',true).first();
33987 * @class Roo.bootstrap.DocumentSlider
33988 * @extends Roo.bootstrap.Component
33989 * Bootstrap DocumentSlider class
33992 * Create a new DocumentViewer
33993 * @param {Object} config The config object
33996 Roo.bootstrap.DocumentSlider = function(config){
33997 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
34004 * Fire after initEvent
34005 * @param {Roo.bootstrap.DocumentSlider} this
34010 * Fire after update
34011 * @param {Roo.bootstrap.DocumentSlider} this
34017 * @param {Roo.bootstrap.DocumentSlider} this
34023 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
34029 getAutoCreate : function()
34033 cls : 'roo-document-slider',
34037 cls : 'roo-document-slider-header',
34041 cls : 'roo-document-slider-header-title'
34047 cls : 'roo-document-slider-body',
34051 cls : 'roo-document-slider-prev',
34055 cls : 'fa fa-chevron-left'
34061 cls : 'roo-document-slider-thumb',
34065 cls : 'roo-document-slider-image'
34071 cls : 'roo-document-slider-next',
34075 cls : 'fa fa-chevron-right'
34087 initEvents : function()
34089 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
34090 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
34092 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
34093 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
34095 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
34096 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
34098 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
34099 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
34101 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
34102 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
34104 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
34105 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
34107 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
34108 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
34110 this.thumbEl.on('click', this.onClick, this);
34112 this.prevIndicator.on('click', this.prev, this);
34114 this.nextIndicator.on('click', this.next, this);
34118 initial : function()
34120 if(this.files.length){
34121 this.indicator = 1;
34125 this.fireEvent('initial', this);
34128 update : function()
34130 this.imageEl.attr('src', this.files[this.indicator - 1]);
34132 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
34134 this.prevIndicator.show();
34136 if(this.indicator == 1){
34137 this.prevIndicator.hide();
34140 this.nextIndicator.show();
34142 if(this.indicator == this.files.length){
34143 this.nextIndicator.hide();
34146 this.thumbEl.scrollTo('top');
34148 this.fireEvent('update', this);
34151 onClick : function(e)
34153 e.preventDefault();
34155 this.fireEvent('click', this);
34160 e.preventDefault();
34162 this.indicator = Math.max(1, this.indicator - 1);
34169 e.preventDefault();
34171 this.indicator = Math.min(this.files.length, this.indicator + 1);
34185 * @class Roo.bootstrap.RadioSet
34186 * @extends Roo.bootstrap.Input
34187 * Bootstrap RadioSet class
34188 * @cfg {String} indicatorpos (left|right) default left
34189 * @cfg {Boolean} inline (true|false) inline the element (default true)
34190 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
34192 * Create a new RadioSet
34193 * @param {Object} config The config object
34196 Roo.bootstrap.RadioSet = function(config){
34198 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
34202 Roo.bootstrap.RadioSet.register(this);
34207 * Fires when the element is checked or unchecked.
34208 * @param {Roo.bootstrap.RadioSet} this This radio
34209 * @param {Roo.bootstrap.Radio} item The checked item
34214 * Fires when the element is click.
34215 * @param {Roo.bootstrap.RadioSet} this This radio set
34216 * @param {Roo.bootstrap.Radio} item The checked item
34217 * @param {Roo.EventObject} e The event object
34224 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
34232 indicatorpos : 'left',
34234 getAutoCreate : function()
34238 cls : 'roo-radio-set-label',
34242 html : this.fieldLabel
34246 if (Roo.bootstrap.version == 3) {
34249 if(this.indicatorpos == 'left'){
34252 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
34253 tooltip : 'This field is required'
34258 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
34259 tooltip : 'This field is required'
34265 cls : 'roo-radio-set-items'
34268 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
34270 if (align === 'left' && this.fieldLabel.length) {
34273 cls : "roo-radio-set-right",
34279 if(this.labelWidth > 12){
34280 label.style = "width: " + this.labelWidth + 'px';
34283 if(this.labelWidth < 13 && this.labelmd == 0){
34284 this.labelmd = this.labelWidth;
34287 if(this.labellg > 0){
34288 label.cls += ' col-lg-' + this.labellg;
34289 items.cls += ' col-lg-' + (12 - this.labellg);
34292 if(this.labelmd > 0){
34293 label.cls += ' col-md-' + this.labelmd;
34294 items.cls += ' col-md-' + (12 - this.labelmd);
34297 if(this.labelsm > 0){
34298 label.cls += ' col-sm-' + this.labelsm;
34299 items.cls += ' col-sm-' + (12 - this.labelsm);
34302 if(this.labelxs > 0){
34303 label.cls += ' col-xs-' + this.labelxs;
34304 items.cls += ' col-xs-' + (12 - this.labelxs);
34310 cls : 'roo-radio-set',
34314 cls : 'roo-radio-set-input',
34317 value : this.value ? this.value : ''
34324 if(this.weight.length){
34325 cfg.cls += ' roo-radio-' + this.weight;
34329 cfg.cls += ' roo-radio-set-inline';
34333 ['xs','sm','md','lg'].map(function(size){
34334 if (settings[size]) {
34335 cfg.cls += ' col-' + size + '-' + settings[size];
34343 initEvents : function()
34345 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
34346 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
34348 if(!this.fieldLabel.length){
34349 this.labelEl.hide();
34352 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
34353 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
34355 this.indicator = this.indicatorEl();
34357 if(this.indicator){
34358 this.indicator.addClass('invisible');
34361 this.originalValue = this.getValue();
34365 inputEl: function ()
34367 return this.el.select('.roo-radio-set-input', true).first();
34370 getChildContainer : function()
34372 return this.itemsEl;
34375 register : function(item)
34377 this.radioes.push(item);
34381 validate : function()
34383 if(this.getVisibilityEl().hasClass('hidden')){
34389 Roo.each(this.radioes, function(i){
34398 if(this.allowBlank) {
34402 if(this.disabled || valid){
34407 this.markInvalid();
34412 markValid : function()
34414 if(this.labelEl.isVisible(true) && this.indicatorEl()){
34415 this.indicatorEl().removeClass('visible');
34416 this.indicatorEl().addClass('invisible');
34420 if (Roo.bootstrap.version == 3) {
34421 this.el.removeClass([this.invalidClass, this.validClass]);
34422 this.el.addClass(this.validClass);
34424 this.el.removeClass(['is-invalid','is-valid']);
34425 this.el.addClass(['is-valid']);
34427 this.fireEvent('valid', this);
34430 markInvalid : function(msg)
34432 if(this.allowBlank || this.disabled){
34436 if(this.labelEl.isVisible(true) && this.indicatorEl()){
34437 this.indicatorEl().removeClass('invisible');
34438 this.indicatorEl().addClass('visible');
34440 if (Roo.bootstrap.version == 3) {
34441 this.el.removeClass([this.invalidClass, this.validClass]);
34442 this.el.addClass(this.invalidClass);
34444 this.el.removeClass(['is-invalid','is-valid']);
34445 this.el.addClass(['is-invalid']);
34448 this.fireEvent('invalid', this, msg);
34452 setValue : function(v, suppressEvent)
34454 if(this.value === v){
34461 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
34464 Roo.each(this.radioes, function(i){
34466 i.el.removeClass('checked');
34469 Roo.each(this.radioes, function(i){
34471 if(i.value === v || i.value.toString() === v.toString()){
34473 i.el.addClass('checked');
34475 if(suppressEvent !== true){
34476 this.fireEvent('check', this, i);
34487 clearInvalid : function(){
34489 if(!this.el || this.preventMark){
34493 this.el.removeClass([this.invalidClass]);
34495 this.fireEvent('valid', this);
34500 Roo.apply(Roo.bootstrap.RadioSet, {
34504 register : function(set)
34506 this.groups[set.name] = set;
34509 get: function(name)
34511 if (typeof(this.groups[name]) == 'undefined') {
34515 return this.groups[name] ;
34521 * Ext JS Library 1.1.1
34522 * Copyright(c) 2006-2007, Ext JS, LLC.
34524 * Originally Released Under LGPL - original licence link has changed is not relivant.
34527 * <script type="text/javascript">
34532 * @class Roo.bootstrap.SplitBar
34533 * @extends Roo.util.Observable
34534 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
34538 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
34539 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
34540 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
34541 split.minSize = 100;
34542 split.maxSize = 600;
34543 split.animate = true;
34544 split.on('moved', splitterMoved);
34547 * Create a new SplitBar
34548 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
34549 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
34550 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34551 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
34552 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
34553 position of the SplitBar).
34555 Roo.bootstrap.SplitBar = function(cfg){
34560 // dragElement : elm
34561 // resizingElement: el,
34563 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
34564 // placement : Roo.bootstrap.SplitBar.LEFT ,
34565 // existingProxy ???
34568 this.el = Roo.get(cfg.dragElement, true);
34569 this.el.dom.unselectable = "on";
34571 this.resizingEl = Roo.get(cfg.resizingElement, true);
34575 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34576 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
34579 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
34582 * The minimum size of the resizing element. (Defaults to 0)
34588 * The maximum size of the resizing element. (Defaults to 2000)
34591 this.maxSize = 2000;
34594 * Whether to animate the transition to the new size
34597 this.animate = false;
34600 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
34603 this.useShim = false;
34608 if(!cfg.existingProxy){
34610 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
34612 this.proxy = Roo.get(cfg.existingProxy).dom;
34615 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
34618 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
34621 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
34624 this.dragSpecs = {};
34627 * @private The adapter to use to positon and resize elements
34629 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34630 this.adapter.init(this);
34632 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34634 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
34635 this.el.addClass("roo-splitbar-h");
34638 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
34639 this.el.addClass("roo-splitbar-v");
34645 * Fires when the splitter is moved (alias for {@link #event-moved})
34646 * @param {Roo.bootstrap.SplitBar} this
34647 * @param {Number} newSize the new width or height
34652 * Fires when the splitter is moved
34653 * @param {Roo.bootstrap.SplitBar} this
34654 * @param {Number} newSize the new width or height
34658 * @event beforeresize
34659 * Fires before the splitter is dragged
34660 * @param {Roo.bootstrap.SplitBar} this
34662 "beforeresize" : true,
34664 "beforeapply" : true
34667 Roo.util.Observable.call(this);
34670 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
34671 onStartProxyDrag : function(x, y){
34672 this.fireEvent("beforeresize", this);
34674 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
34676 o.enableDisplayMode("block");
34677 // all splitbars share the same overlay
34678 Roo.bootstrap.SplitBar.prototype.overlay = o;
34680 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
34681 this.overlay.show();
34682 Roo.get(this.proxy).setDisplayed("block");
34683 var size = this.adapter.getElementSize(this);
34684 this.activeMinSize = this.getMinimumSize();;
34685 this.activeMaxSize = this.getMaximumSize();;
34686 var c1 = size - this.activeMinSize;
34687 var c2 = Math.max(this.activeMaxSize - size, 0);
34688 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34689 this.dd.resetConstraints();
34690 this.dd.setXConstraint(
34691 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
34692 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
34694 this.dd.setYConstraint(0, 0);
34696 this.dd.resetConstraints();
34697 this.dd.setXConstraint(0, 0);
34698 this.dd.setYConstraint(
34699 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
34700 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
34703 this.dragSpecs.startSize = size;
34704 this.dragSpecs.startPoint = [x, y];
34705 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
34709 * @private Called after the drag operation by the DDProxy
34711 onEndProxyDrag : function(e){
34712 Roo.get(this.proxy).setDisplayed(false);
34713 var endPoint = Roo.lib.Event.getXY(e);
34715 this.overlay.hide();
34718 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34719 newSize = this.dragSpecs.startSize +
34720 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
34721 endPoint[0] - this.dragSpecs.startPoint[0] :
34722 this.dragSpecs.startPoint[0] - endPoint[0]
34725 newSize = this.dragSpecs.startSize +
34726 (this.placement == Roo.bootstrap.SplitBar.TOP ?
34727 endPoint[1] - this.dragSpecs.startPoint[1] :
34728 this.dragSpecs.startPoint[1] - endPoint[1]
34731 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
34732 if(newSize != this.dragSpecs.startSize){
34733 if(this.fireEvent('beforeapply', this, newSize) !== false){
34734 this.adapter.setElementSize(this, newSize);
34735 this.fireEvent("moved", this, newSize);
34736 this.fireEvent("resize", this, newSize);
34742 * Get the adapter this SplitBar uses
34743 * @return The adapter object
34745 getAdapter : function(){
34746 return this.adapter;
34750 * Set the adapter this SplitBar uses
34751 * @param {Object} adapter A SplitBar adapter object
34753 setAdapter : function(adapter){
34754 this.adapter = adapter;
34755 this.adapter.init(this);
34759 * Gets the minimum size for the resizing element
34760 * @return {Number} The minimum size
34762 getMinimumSize : function(){
34763 return this.minSize;
34767 * Sets the minimum size for the resizing element
34768 * @param {Number} minSize The minimum size
34770 setMinimumSize : function(minSize){
34771 this.minSize = minSize;
34775 * Gets the maximum size for the resizing element
34776 * @return {Number} The maximum size
34778 getMaximumSize : function(){
34779 return this.maxSize;
34783 * Sets the maximum size for the resizing element
34784 * @param {Number} maxSize The maximum size
34786 setMaximumSize : function(maxSize){
34787 this.maxSize = maxSize;
34791 * Sets the initialize size for the resizing element
34792 * @param {Number} size The initial size
34794 setCurrentSize : function(size){
34795 var oldAnimate = this.animate;
34796 this.animate = false;
34797 this.adapter.setElementSize(this, size);
34798 this.animate = oldAnimate;
34802 * Destroy this splitbar.
34803 * @param {Boolean} removeEl True to remove the element
34805 destroy : function(removeEl){
34807 this.shim.remove();
34810 this.proxy.parentNode.removeChild(this.proxy);
34818 * @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.
34820 Roo.bootstrap.SplitBar.createProxy = function(dir){
34821 var proxy = new Roo.Element(document.createElement("div"));
34822 proxy.unselectable();
34823 var cls = 'roo-splitbar-proxy';
34824 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
34825 document.body.appendChild(proxy.dom);
34830 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
34831 * Default Adapter. It assumes the splitter and resizing element are not positioned
34832 * elements and only gets/sets the width of the element. Generally used for table based layouts.
34834 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
34837 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
34838 // do nothing for now
34839 init : function(s){
34843 * Called before drag operations to get the current size of the resizing element.
34844 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34846 getElementSize : function(s){
34847 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34848 return s.resizingEl.getWidth();
34850 return s.resizingEl.getHeight();
34855 * Called after drag operations to set the size of the resizing element.
34856 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34857 * @param {Number} newSize The new size to set
34858 * @param {Function} onComplete A function to be invoked when resizing is complete
34860 setElementSize : function(s, newSize, onComplete){
34861 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34863 s.resizingEl.setWidth(newSize);
34865 onComplete(s, newSize);
34868 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
34873 s.resizingEl.setHeight(newSize);
34875 onComplete(s, newSize);
34878 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
34885 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
34886 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
34887 * Adapter that moves the splitter element to align with the resized sizing element.
34888 * Used with an absolute positioned SplitBar.
34889 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
34890 * document.body, make sure you assign an id to the body element.
34892 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
34893 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34894 this.container = Roo.get(container);
34897 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
34898 init : function(s){
34899 this.basic.init(s);
34902 getElementSize : function(s){
34903 return this.basic.getElementSize(s);
34906 setElementSize : function(s, newSize, onComplete){
34907 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
34910 moveSplitter : function(s){
34911 var yes = Roo.bootstrap.SplitBar;
34912 switch(s.placement){
34914 s.el.setX(s.resizingEl.getRight());
34917 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
34920 s.el.setY(s.resizingEl.getBottom());
34923 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
34930 * Orientation constant - Create a vertical SplitBar
34934 Roo.bootstrap.SplitBar.VERTICAL = 1;
34937 * Orientation constant - Create a horizontal SplitBar
34941 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
34944 * Placement constant - The resizing element is to the left of the splitter element
34948 Roo.bootstrap.SplitBar.LEFT = 1;
34951 * Placement constant - The resizing element is to the right of the splitter element
34955 Roo.bootstrap.SplitBar.RIGHT = 2;
34958 * Placement constant - The resizing element is positioned above the splitter element
34962 Roo.bootstrap.SplitBar.TOP = 3;
34965 * Placement constant - The resizing element is positioned under splitter element
34969 Roo.bootstrap.SplitBar.BOTTOM = 4;
34970 Roo.namespace("Roo.bootstrap.layout");/*
34972 * Ext JS Library 1.1.1
34973 * Copyright(c) 2006-2007, Ext JS, LLC.
34975 * Originally Released Under LGPL - original licence link has changed is not relivant.
34978 * <script type="text/javascript">
34982 * @class Roo.bootstrap.layout.Manager
34983 * @extends Roo.bootstrap.Component
34984 * Base class for layout managers.
34986 Roo.bootstrap.layout.Manager = function(config)
34988 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
34994 /** false to disable window resize monitoring @type Boolean */
34995 this.monitorWindowResize = true;
35000 * Fires when a layout is performed.
35001 * @param {Roo.LayoutManager} this
35005 * @event regionresized
35006 * Fires when the user resizes a region.
35007 * @param {Roo.LayoutRegion} region The resized region
35008 * @param {Number} newSize The new size (width for east/west, height for north/south)
35010 "regionresized" : true,
35012 * @event regioncollapsed
35013 * Fires when a region is collapsed.
35014 * @param {Roo.LayoutRegion} region The collapsed region
35016 "regioncollapsed" : true,
35018 * @event regionexpanded
35019 * Fires when a region is expanded.
35020 * @param {Roo.LayoutRegion} region The expanded region
35022 "regionexpanded" : true
35024 this.updating = false;
35027 this.el = Roo.get(config.el);
35033 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
35038 monitorWindowResize : true,
35044 onRender : function(ct, position)
35047 this.el = Roo.get(ct);
35050 //this.fireEvent('render',this);
35054 initEvents: function()
35058 // ie scrollbar fix
35059 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
35060 document.body.scroll = "no";
35061 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
35062 this.el.position('relative');
35064 this.id = this.el.id;
35065 this.el.addClass("roo-layout-container");
35066 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
35067 if(this.el.dom != document.body ) {
35068 this.el.on('resize', this.layout,this);
35069 this.el.on('show', this.layout,this);
35075 * Returns true if this layout is currently being updated
35076 * @return {Boolean}
35078 isUpdating : function(){
35079 return this.updating;
35083 * Suspend the LayoutManager from doing auto-layouts while
35084 * making multiple add or remove calls
35086 beginUpdate : function(){
35087 this.updating = true;
35091 * Restore auto-layouts and optionally disable the manager from performing a layout
35092 * @param {Boolean} noLayout true to disable a layout update
35094 endUpdate : function(noLayout){
35095 this.updating = false;
35101 layout: function(){
35105 onRegionResized : function(region, newSize){
35106 this.fireEvent("regionresized", region, newSize);
35110 onRegionCollapsed : function(region){
35111 this.fireEvent("regioncollapsed", region);
35114 onRegionExpanded : function(region){
35115 this.fireEvent("regionexpanded", region);
35119 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
35120 * performs box-model adjustments.
35121 * @return {Object} The size as an object {width: (the width), height: (the height)}
35123 getViewSize : function()
35126 if(this.el.dom != document.body){
35127 size = this.el.getSize();
35129 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
35131 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
35132 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
35137 * Returns the Element this layout is bound to.
35138 * @return {Roo.Element}
35140 getEl : function(){
35145 * Returns the specified region.
35146 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
35147 * @return {Roo.LayoutRegion}
35149 getRegion : function(target){
35150 return this.regions[target.toLowerCase()];
35153 onWindowResize : function(){
35154 if(this.monitorWindowResize){
35161 * Ext JS Library 1.1.1
35162 * Copyright(c) 2006-2007, Ext JS, LLC.
35164 * Originally Released Under LGPL - original licence link has changed is not relivant.
35167 * <script type="text/javascript">
35170 * @class Roo.bootstrap.layout.Border
35171 * @extends Roo.bootstrap.layout.Manager
35172 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
35173 * please see: examples/bootstrap/nested.html<br><br>
35175 <b>The container the layout is rendered into can be either the body element or any other element.
35176 If it is not the body element, the container needs to either be an absolute positioned element,
35177 or you will need to add "position:relative" to the css of the container. You will also need to specify
35178 the container size if it is not the body element.</b>
35181 * Create a new Border
35182 * @param {Object} config Configuration options
35184 Roo.bootstrap.layout.Border = function(config){
35185 config = config || {};
35186 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
35190 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
35191 if(config[region]){
35192 config[region].region = region;
35193 this.addRegion(config[region]);
35199 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
35201 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
35203 parent : false, // this might point to a 'nest' or a ???
35206 * Creates and adds a new region if it doesn't already exist.
35207 * @param {String} target The target region key (north, south, east, west or center).
35208 * @param {Object} config The regions config object
35209 * @return {BorderLayoutRegion} The new region
35211 addRegion : function(config)
35213 if(!this.regions[config.region]){
35214 var r = this.factory(config);
35215 this.bindRegion(r);
35217 return this.regions[config.region];
35221 bindRegion : function(r){
35222 this.regions[r.config.region] = r;
35224 r.on("visibilitychange", this.layout, this);
35225 r.on("paneladded", this.layout, this);
35226 r.on("panelremoved", this.layout, this);
35227 r.on("invalidated", this.layout, this);
35228 r.on("resized", this.onRegionResized, this);
35229 r.on("collapsed", this.onRegionCollapsed, this);
35230 r.on("expanded", this.onRegionExpanded, this);
35234 * Performs a layout update.
35236 layout : function()
35238 if(this.updating) {
35242 // render all the rebions if they have not been done alreayd?
35243 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
35244 if(this.regions[region] && !this.regions[region].bodyEl){
35245 this.regions[region].onRender(this.el)
35249 var size = this.getViewSize();
35250 var w = size.width;
35251 var h = size.height;
35256 //var x = 0, y = 0;
35258 var rs = this.regions;
35259 var north = rs["north"];
35260 var south = rs["south"];
35261 var west = rs["west"];
35262 var east = rs["east"];
35263 var center = rs["center"];
35264 //if(this.hideOnLayout){ // not supported anymore
35265 //c.el.setStyle("display", "none");
35267 if(north && north.isVisible()){
35268 var b = north.getBox();
35269 var m = north.getMargins();
35270 b.width = w - (m.left+m.right);
35273 centerY = b.height + b.y + m.bottom;
35274 centerH -= centerY;
35275 north.updateBox(this.safeBox(b));
35277 if(south && south.isVisible()){
35278 var b = south.getBox();
35279 var m = south.getMargins();
35280 b.width = w - (m.left+m.right);
35282 var totalHeight = (b.height + m.top + m.bottom);
35283 b.y = h - totalHeight + m.top;
35284 centerH -= totalHeight;
35285 south.updateBox(this.safeBox(b));
35287 if(west && west.isVisible()){
35288 var b = west.getBox();
35289 var m = west.getMargins();
35290 b.height = centerH - (m.top+m.bottom);
35292 b.y = centerY + m.top;
35293 var totalWidth = (b.width + m.left + m.right);
35294 centerX += totalWidth;
35295 centerW -= totalWidth;
35296 west.updateBox(this.safeBox(b));
35298 if(east && east.isVisible()){
35299 var b = east.getBox();
35300 var m = east.getMargins();
35301 b.height = centerH - (m.top+m.bottom);
35302 var totalWidth = (b.width + m.left + m.right);
35303 b.x = w - totalWidth + m.left;
35304 b.y = centerY + m.top;
35305 centerW -= totalWidth;
35306 east.updateBox(this.safeBox(b));
35309 var m = center.getMargins();
35311 x: centerX + m.left,
35312 y: centerY + m.top,
35313 width: centerW - (m.left+m.right),
35314 height: centerH - (m.top+m.bottom)
35316 //if(this.hideOnLayout){
35317 //center.el.setStyle("display", "block");
35319 center.updateBox(this.safeBox(centerBox));
35322 this.fireEvent("layout", this);
35326 safeBox : function(box){
35327 box.width = Math.max(0, box.width);
35328 box.height = Math.max(0, box.height);
35333 * Adds a ContentPanel (or subclass) to this layout.
35334 * @param {String} target The target region key (north, south, east, west or center).
35335 * @param {Roo.ContentPanel} panel The panel to add
35336 * @return {Roo.ContentPanel} The added panel
35338 add : function(target, panel){
35340 target = target.toLowerCase();
35341 return this.regions[target].add(panel);
35345 * Remove a ContentPanel (or subclass) to this layout.
35346 * @param {String} target The target region key (north, south, east, west or center).
35347 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
35348 * @return {Roo.ContentPanel} The removed panel
35350 remove : function(target, panel){
35351 target = target.toLowerCase();
35352 return this.regions[target].remove(panel);
35356 * Searches all regions for a panel with the specified id
35357 * @param {String} panelId
35358 * @return {Roo.ContentPanel} The panel or null if it wasn't found
35360 findPanel : function(panelId){
35361 var rs = this.regions;
35362 for(var target in rs){
35363 if(typeof rs[target] != "function"){
35364 var p = rs[target].getPanel(panelId);
35374 * Searches all regions for a panel with the specified id and activates (shows) it.
35375 * @param {String/ContentPanel} panelId The panels id or the panel itself
35376 * @return {Roo.ContentPanel} The shown panel or null
35378 showPanel : function(panelId) {
35379 var rs = this.regions;
35380 for(var target in rs){
35381 var r = rs[target];
35382 if(typeof r != "function"){
35383 if(r.hasPanel(panelId)){
35384 return r.showPanel(panelId);
35392 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
35393 * @param {Roo.state.Provider} provider (optional) An alternate state provider
35396 restoreState : function(provider){
35398 provider = Roo.state.Manager;
35400 var sm = new Roo.LayoutStateManager();
35401 sm.init(this, provider);
35407 * Adds a xtype elements to the layout.
35411 xtype : 'ContentPanel',
35418 xtype : 'NestedLayoutPanel',
35424 items : [ ... list of content panels or nested layout panels.. ]
35428 * @param {Object} cfg Xtype definition of item to add.
35430 addxtype : function(cfg)
35432 // basically accepts a pannel...
35433 // can accept a layout region..!?!?
35434 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
35437 // theory? children can only be panels??
35439 //if (!cfg.xtype.match(/Panel$/)) {
35444 if (typeof(cfg.region) == 'undefined') {
35445 Roo.log("Failed to add Panel, region was not set");
35449 var region = cfg.region;
35455 xitems = cfg.items;
35460 if ( region == 'center') {
35461 Roo.log("Center: " + cfg.title);
35467 case 'Content': // ContentPanel (el, cfg)
35468 case 'Scroll': // ContentPanel (el, cfg)
35470 cfg.autoCreate = cfg.autoCreate || true;
35471 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35473 // var el = this.el.createChild();
35474 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
35477 this.add(region, ret);
35481 case 'TreePanel': // our new panel!
35482 cfg.el = this.el.createChild();
35483 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
35484 this.add(region, ret);
35489 // create a new Layout (which is a Border Layout...
35491 var clayout = cfg.layout;
35492 clayout.el = this.el.createChild();
35493 clayout.items = clayout.items || [];
35497 // replace this exitems with the clayout ones..
35498 xitems = clayout.items;
35500 // force background off if it's in center...
35501 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
35502 cfg.background = false;
35504 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
35507 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35508 //console.log('adding nested layout panel ' + cfg.toSource());
35509 this.add(region, ret);
35510 nb = {}; /// find first...
35515 // needs grid and region
35517 //var el = this.getRegion(region).el.createChild();
35519 *var el = this.el.createChild();
35520 // create the grid first...
35521 cfg.grid.container = el;
35522 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
35525 if (region == 'center' && this.active ) {
35526 cfg.background = false;
35529 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35531 this.add(region, ret);
35533 if (cfg.background) {
35534 // render grid on panel activation (if panel background)
35535 ret.on('activate', function(gp) {
35536 if (!gp.grid.rendered) {
35537 // gp.grid.render(el);
35541 // cfg.grid.render(el);
35547 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
35548 // it was the old xcomponent building that caused this before.
35549 // espeically if border is the top element in the tree.
35559 if (typeof(Roo[cfg.xtype]) != 'undefined') {
35561 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
35562 this.add(region, ret);
35566 throw "Can not add '" + cfg.xtype + "' to Border";
35572 this.beginUpdate();
35576 Roo.each(xitems, function(i) {
35577 region = nb && i.region ? i.region : false;
35579 var add = ret.addxtype(i);
35582 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
35583 if (!i.background) {
35584 abn[region] = nb[region] ;
35591 // make the last non-background panel active..
35592 //if (nb) { Roo.log(abn); }
35595 for(var r in abn) {
35596 region = this.getRegion(r);
35598 // tried using nb[r], but it does not work..
35600 region.showPanel(abn[r]);
35611 factory : function(cfg)
35614 var validRegions = Roo.bootstrap.layout.Border.regions;
35616 var target = cfg.region;
35619 var r = Roo.bootstrap.layout;
35623 return new r.North(cfg);
35625 return new r.South(cfg);
35627 return new r.East(cfg);
35629 return new r.West(cfg);
35631 return new r.Center(cfg);
35633 throw 'Layout region "'+target+'" not supported.';
35640 * Ext JS Library 1.1.1
35641 * Copyright(c) 2006-2007, Ext JS, LLC.
35643 * Originally Released Under LGPL - original licence link has changed is not relivant.
35646 * <script type="text/javascript">
35650 * @class Roo.bootstrap.layout.Basic
35651 * @extends Roo.util.Observable
35652 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
35653 * and does not have a titlebar, tabs or any other features. All it does is size and position
35654 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
35655 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35656 * @cfg {string} region the region that it inhabits..
35657 * @cfg {bool} skipConfig skip config?
35661 Roo.bootstrap.layout.Basic = function(config){
35663 this.mgr = config.mgr;
35665 this.position = config.region;
35667 var skipConfig = config.skipConfig;
35671 * @scope Roo.BasicLayoutRegion
35675 * @event beforeremove
35676 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
35677 * @param {Roo.LayoutRegion} this
35678 * @param {Roo.ContentPanel} panel The panel
35679 * @param {Object} e The cancel event object
35681 "beforeremove" : true,
35683 * @event invalidated
35684 * Fires when the layout for this region is changed.
35685 * @param {Roo.LayoutRegion} this
35687 "invalidated" : true,
35689 * @event visibilitychange
35690 * Fires when this region is shown or hidden
35691 * @param {Roo.LayoutRegion} this
35692 * @param {Boolean} visibility true or false
35694 "visibilitychange" : true,
35696 * @event paneladded
35697 * Fires when a panel is added.
35698 * @param {Roo.LayoutRegion} this
35699 * @param {Roo.ContentPanel} panel The panel
35701 "paneladded" : true,
35703 * @event panelremoved
35704 * Fires when a panel is removed.
35705 * @param {Roo.LayoutRegion} this
35706 * @param {Roo.ContentPanel} panel The panel
35708 "panelremoved" : true,
35710 * @event beforecollapse
35711 * Fires when this region before collapse.
35712 * @param {Roo.LayoutRegion} this
35714 "beforecollapse" : true,
35717 * Fires when this region is collapsed.
35718 * @param {Roo.LayoutRegion} this
35720 "collapsed" : true,
35723 * Fires when this region is expanded.
35724 * @param {Roo.LayoutRegion} this
35729 * Fires when this region is slid into view.
35730 * @param {Roo.LayoutRegion} this
35732 "slideshow" : true,
35735 * Fires when this region slides out of view.
35736 * @param {Roo.LayoutRegion} this
35738 "slidehide" : true,
35740 * @event panelactivated
35741 * Fires when a panel is activated.
35742 * @param {Roo.LayoutRegion} this
35743 * @param {Roo.ContentPanel} panel The activated panel
35745 "panelactivated" : true,
35748 * Fires when the user resizes this region.
35749 * @param {Roo.LayoutRegion} this
35750 * @param {Number} newSize The new size (width for east/west, height for north/south)
35754 /** A collection of panels in this region. @type Roo.util.MixedCollection */
35755 this.panels = new Roo.util.MixedCollection();
35756 this.panels.getKey = this.getPanelId.createDelegate(this);
35758 this.activePanel = null;
35759 // ensure listeners are added...
35761 if (config.listeners || config.events) {
35762 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
35763 listeners : config.listeners || {},
35764 events : config.events || {}
35768 if(skipConfig !== true){
35769 this.applyConfig(config);
35773 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
35775 getPanelId : function(p){
35779 applyConfig : function(config){
35780 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35781 this.config = config;
35786 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
35787 * the width, for horizontal (north, south) the height.
35788 * @param {Number} newSize The new width or height
35790 resizeTo : function(newSize){
35791 var el = this.el ? this.el :
35792 (this.activePanel ? this.activePanel.getEl() : null);
35794 switch(this.position){
35797 el.setWidth(newSize);
35798 this.fireEvent("resized", this, newSize);
35802 el.setHeight(newSize);
35803 this.fireEvent("resized", this, newSize);
35809 getBox : function(){
35810 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
35813 getMargins : function(){
35814 return this.margins;
35817 updateBox : function(box){
35819 var el = this.activePanel.getEl();
35820 el.dom.style.left = box.x + "px";
35821 el.dom.style.top = box.y + "px";
35822 this.activePanel.setSize(box.width, box.height);
35826 * Returns the container element for this region.
35827 * @return {Roo.Element}
35829 getEl : function(){
35830 return this.activePanel;
35834 * Returns true if this region is currently visible.
35835 * @return {Boolean}
35837 isVisible : function(){
35838 return this.activePanel ? true : false;
35841 setActivePanel : function(panel){
35842 panel = this.getPanel(panel);
35843 if(this.activePanel && this.activePanel != panel){
35844 this.activePanel.setActiveState(false);
35845 this.activePanel.getEl().setLeftTop(-10000,-10000);
35847 this.activePanel = panel;
35848 panel.setActiveState(true);
35850 panel.setSize(this.box.width, this.box.height);
35852 this.fireEvent("panelactivated", this, panel);
35853 this.fireEvent("invalidated");
35857 * Show the specified panel.
35858 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
35859 * @return {Roo.ContentPanel} The shown panel or null
35861 showPanel : function(panel){
35862 panel = this.getPanel(panel);
35864 this.setActivePanel(panel);
35870 * Get the active panel for this region.
35871 * @return {Roo.ContentPanel} The active panel or null
35873 getActivePanel : function(){
35874 return this.activePanel;
35878 * Add the passed ContentPanel(s)
35879 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35880 * @return {Roo.ContentPanel} The panel added (if only one was added)
35882 add : function(panel){
35883 if(arguments.length > 1){
35884 for(var i = 0, len = arguments.length; i < len; i++) {
35885 this.add(arguments[i]);
35889 if(this.hasPanel(panel)){
35890 this.showPanel(panel);
35893 var el = panel.getEl();
35894 if(el.dom.parentNode != this.mgr.el.dom){
35895 this.mgr.el.dom.appendChild(el.dom);
35897 if(panel.setRegion){
35898 panel.setRegion(this);
35900 this.panels.add(panel);
35901 el.setStyle("position", "absolute");
35902 if(!panel.background){
35903 this.setActivePanel(panel);
35904 if(this.config.initialSize && this.panels.getCount()==1){
35905 this.resizeTo(this.config.initialSize);
35908 this.fireEvent("paneladded", this, panel);
35913 * Returns true if the panel is in this region.
35914 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35915 * @return {Boolean}
35917 hasPanel : function(panel){
35918 if(typeof panel == "object"){ // must be panel obj
35919 panel = panel.getId();
35921 return this.getPanel(panel) ? true : false;
35925 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35926 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35927 * @param {Boolean} preservePanel Overrides the config preservePanel option
35928 * @return {Roo.ContentPanel} The panel that was removed
35930 remove : function(panel, preservePanel){
35931 panel = this.getPanel(panel);
35936 this.fireEvent("beforeremove", this, panel, e);
35937 if(e.cancel === true){
35940 var panelId = panel.getId();
35941 this.panels.removeKey(panelId);
35946 * Returns the panel specified or null if it's not in this region.
35947 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35948 * @return {Roo.ContentPanel}
35950 getPanel : function(id){
35951 if(typeof id == "object"){ // must be panel obj
35954 return this.panels.get(id);
35958 * Returns this regions position (north/south/east/west/center).
35961 getPosition: function(){
35962 return this.position;
35966 * Ext JS Library 1.1.1
35967 * Copyright(c) 2006-2007, Ext JS, LLC.
35969 * Originally Released Under LGPL - original licence link has changed is not relivant.
35972 * <script type="text/javascript">
35976 * @class Roo.bootstrap.layout.Region
35977 * @extends Roo.bootstrap.layout.Basic
35978 * This class represents a region in a layout manager.
35980 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
35981 * @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})
35982 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
35983 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
35984 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
35985 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
35986 * @cfg {String} title The title for the region (overrides panel titles)
35987 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
35988 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
35989 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
35990 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
35991 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
35992 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
35993 * the space available, similar to FireFox 1.5 tabs (defaults to false)
35994 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
35995 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
35996 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
35998 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
35999 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
36000 * @cfg {Boolean} disableTabTips True to disable tab tooltips
36001 * @cfg {Number} width For East/West panels
36002 * @cfg {Number} height For North/South panels
36003 * @cfg {Boolean} split To show the splitter
36004 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
36006 * @cfg {string} cls Extra CSS classes to add to region
36008 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
36009 * @cfg {string} region the region that it inhabits..
36012 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
36013 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
36015 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
36016 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
36017 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
36019 Roo.bootstrap.layout.Region = function(config)
36021 this.applyConfig(config);
36023 var mgr = config.mgr;
36024 var pos = config.region;
36025 config.skipConfig = true;
36026 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
36029 this.onRender(mgr.el);
36032 this.visible = true;
36033 this.collapsed = false;
36034 this.unrendered_panels = [];
36037 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
36039 position: '', // set by wrapper (eg. north/south etc..)
36040 unrendered_panels : null, // unrendered panels.
36042 tabPosition : false,
36044 mgr: false, // points to 'Border'
36047 createBody : function(){
36048 /** This region's body element
36049 * @type Roo.Element */
36050 this.bodyEl = this.el.createChild({
36052 cls: "roo-layout-panel-body tab-content" // bootstrap added...
36056 onRender: function(ctr, pos)
36058 var dh = Roo.DomHelper;
36059 /** This region's container element
36060 * @type Roo.Element */
36061 this.el = dh.append(ctr.dom, {
36063 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
36065 /** This region's title element
36066 * @type Roo.Element */
36068 this.titleEl = dh.append(this.el.dom, {
36070 unselectable: "on",
36071 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
36073 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
36074 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
36078 this.titleEl.enableDisplayMode();
36079 /** This region's title text element
36080 * @type HTMLElement */
36081 this.titleTextEl = this.titleEl.dom.firstChild;
36082 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
36084 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
36085 this.closeBtn.enableDisplayMode();
36086 this.closeBtn.on("click", this.closeClicked, this);
36087 this.closeBtn.hide();
36089 this.createBody(this.config);
36090 if(this.config.hideWhenEmpty){
36092 this.on("paneladded", this.validateVisibility, this);
36093 this.on("panelremoved", this.validateVisibility, this);
36095 if(this.autoScroll){
36096 this.bodyEl.setStyle("overflow", "auto");
36098 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
36100 //if(c.titlebar !== false){
36101 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
36102 this.titleEl.hide();
36104 this.titleEl.show();
36105 if(this.config.title){
36106 this.titleTextEl.innerHTML = this.config.title;
36110 if(this.config.collapsed){
36111 this.collapse(true);
36113 if(this.config.hidden){
36117 if (this.unrendered_panels && this.unrendered_panels.length) {
36118 for (var i =0;i< this.unrendered_panels.length; i++) {
36119 this.add(this.unrendered_panels[i]);
36121 this.unrendered_panels = null;
36127 applyConfig : function(c)
36130 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
36131 var dh = Roo.DomHelper;
36132 if(c.titlebar !== false){
36133 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
36134 this.collapseBtn.on("click", this.collapse, this);
36135 this.collapseBtn.enableDisplayMode();
36137 if(c.showPin === true || this.showPin){
36138 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
36139 this.stickBtn.enableDisplayMode();
36140 this.stickBtn.on("click", this.expand, this);
36141 this.stickBtn.hide();
36146 /** This region's collapsed element
36147 * @type Roo.Element */
36150 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
36151 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
36154 if(c.floatable !== false){
36155 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
36156 this.collapsedEl.on("click", this.collapseClick, this);
36159 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
36160 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
36161 id: "message", unselectable: "on", style:{"float":"left"}});
36162 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
36164 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
36165 this.expandBtn.on("click", this.expand, this);
36169 if(this.collapseBtn){
36170 this.collapseBtn.setVisible(c.collapsible == true);
36173 this.cmargins = c.cmargins || this.cmargins ||
36174 (this.position == "west" || this.position == "east" ?
36175 {top: 0, left: 2, right:2, bottom: 0} :
36176 {top: 2, left: 0, right:0, bottom: 2});
36178 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
36181 this.tabPosition = [ 'top','bottom', 'west'].indexOf(c.tabPosition) > -1 ? c.tabPosition : "top";
36183 this.autoScroll = c.autoScroll || false;
36188 this.duration = c.duration || .30;
36189 this.slideDuration = c.slideDuration || .45;
36194 * Returns true if this region is currently visible.
36195 * @return {Boolean}
36197 isVisible : function(){
36198 return this.visible;
36202 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
36203 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
36205 //setCollapsedTitle : function(title){
36206 // title = title || " ";
36207 // if(this.collapsedTitleTextEl){
36208 // this.collapsedTitleTextEl.innerHTML = title;
36212 getBox : function(){
36214 // if(!this.collapsed){
36215 b = this.el.getBox(false, true);
36217 // b = this.collapsedEl.getBox(false, true);
36222 getMargins : function(){
36223 return this.margins;
36224 //return this.collapsed ? this.cmargins : this.margins;
36227 highlight : function(){
36228 this.el.addClass("x-layout-panel-dragover");
36231 unhighlight : function(){
36232 this.el.removeClass("x-layout-panel-dragover");
36235 updateBox : function(box)
36237 if (!this.bodyEl) {
36238 return; // not rendered yet..
36242 if(!this.collapsed){
36243 this.el.dom.style.left = box.x + "px";
36244 this.el.dom.style.top = box.y + "px";
36245 this.updateBody(box.width, box.height);
36247 this.collapsedEl.dom.style.left = box.x + "px";
36248 this.collapsedEl.dom.style.top = box.y + "px";
36249 this.collapsedEl.setSize(box.width, box.height);
36252 this.tabs.autoSizeTabs();
36256 updateBody : function(w, h)
36259 this.el.setWidth(w);
36260 w -= this.el.getBorderWidth("rl");
36261 if(this.config.adjustments){
36262 w += this.config.adjustments[0];
36265 if(h !== null && h > 0){
36266 this.el.setHeight(h);
36267 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
36268 h -= this.el.getBorderWidth("tb");
36269 if(this.config.adjustments){
36270 h += this.config.adjustments[1];
36272 this.bodyEl.setHeight(h);
36274 h = this.tabs.syncHeight(h);
36277 if(this.panelSize){
36278 w = w !== null ? w : this.panelSize.width;
36279 h = h !== null ? h : this.panelSize.height;
36281 if(this.activePanel){
36282 var el = this.activePanel.getEl();
36283 w = w !== null ? w : el.getWidth();
36284 h = h !== null ? h : el.getHeight();
36285 this.panelSize = {width: w, height: h};
36286 this.activePanel.setSize(w, h);
36288 if(Roo.isIE && this.tabs){
36289 this.tabs.el.repaint();
36294 * Returns the container element for this region.
36295 * @return {Roo.Element}
36297 getEl : function(){
36302 * Hides this region.
36305 //if(!this.collapsed){
36306 this.el.dom.style.left = "-2000px";
36309 // this.collapsedEl.dom.style.left = "-2000px";
36310 // this.collapsedEl.hide();
36312 this.visible = false;
36313 this.fireEvent("visibilitychange", this, false);
36317 * Shows this region if it was previously hidden.
36320 //if(!this.collapsed){
36323 // this.collapsedEl.show();
36325 this.visible = true;
36326 this.fireEvent("visibilitychange", this, true);
36329 closeClicked : function(){
36330 if(this.activePanel){
36331 this.remove(this.activePanel);
36335 collapseClick : function(e){
36337 e.stopPropagation();
36340 e.stopPropagation();
36346 * Collapses this region.
36347 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
36350 collapse : function(skipAnim, skipCheck = false){
36351 if(this.collapsed) {
36355 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
36357 this.collapsed = true;
36359 this.split.el.hide();
36361 if(this.config.animate && skipAnim !== true){
36362 this.fireEvent("invalidated", this);
36363 this.animateCollapse();
36365 this.el.setLocation(-20000,-20000);
36367 this.collapsedEl.show();
36368 this.fireEvent("collapsed", this);
36369 this.fireEvent("invalidated", this);
36375 animateCollapse : function(){
36380 * Expands this region if it was previously collapsed.
36381 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
36382 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
36385 expand : function(e, skipAnim){
36387 e.stopPropagation();
36389 if(!this.collapsed || this.el.hasActiveFx()) {
36393 this.afterSlideIn();
36396 this.collapsed = false;
36397 if(this.config.animate && skipAnim !== true){
36398 this.animateExpand();
36402 this.split.el.show();
36404 this.collapsedEl.setLocation(-2000,-2000);
36405 this.collapsedEl.hide();
36406 this.fireEvent("invalidated", this);
36407 this.fireEvent("expanded", this);
36411 animateExpand : function(){
36415 initTabs : function()
36417 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
36419 var ts = new Roo.bootstrap.panel.Tabs({
36420 el: this.bodyEl.dom,
36422 tabPosition: this.tabPosition ? this.tabPosition : 'top',
36423 disableTooltips: this.config.disableTabTips,
36424 toolbar : this.config.toolbar
36427 if(this.config.hideTabs){
36428 ts.stripWrap.setDisplayed(false);
36431 ts.resizeTabs = this.config.resizeTabs === true;
36432 ts.minTabWidth = this.config.minTabWidth || 40;
36433 ts.maxTabWidth = this.config.maxTabWidth || 250;
36434 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
36435 ts.monitorResize = false;
36436 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
36437 ts.bodyEl.addClass('roo-layout-tabs-body');
36438 this.panels.each(this.initPanelAsTab, this);
36441 initPanelAsTab : function(panel){
36442 var ti = this.tabs.addTab(
36446 this.config.closeOnTab && panel.isClosable(),
36449 if(panel.tabTip !== undefined){
36450 ti.setTooltip(panel.tabTip);
36452 ti.on("activate", function(){
36453 this.setActivePanel(panel);
36456 if(this.config.closeOnTab){
36457 ti.on("beforeclose", function(t, e){
36459 this.remove(panel);
36463 panel.tabItem = ti;
36468 updatePanelTitle : function(panel, title)
36470 if(this.activePanel == panel){
36471 this.updateTitle(title);
36474 var ti = this.tabs.getTab(panel.getEl().id);
36476 if(panel.tabTip !== undefined){
36477 ti.setTooltip(panel.tabTip);
36482 updateTitle : function(title){
36483 if(this.titleTextEl && !this.config.title){
36484 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
36488 setActivePanel : function(panel)
36490 panel = this.getPanel(panel);
36491 if(this.activePanel && this.activePanel != panel){
36492 if(this.activePanel.setActiveState(false) === false){
36496 this.activePanel = panel;
36497 panel.setActiveState(true);
36498 if(this.panelSize){
36499 panel.setSize(this.panelSize.width, this.panelSize.height);
36502 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
36504 this.updateTitle(panel.getTitle());
36506 this.fireEvent("invalidated", this);
36508 this.fireEvent("panelactivated", this, panel);
36512 * Shows the specified panel.
36513 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
36514 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
36516 showPanel : function(panel)
36518 panel = this.getPanel(panel);
36521 var tab = this.tabs.getTab(panel.getEl().id);
36522 if(tab.isHidden()){
36523 this.tabs.unhideTab(tab.id);
36527 this.setActivePanel(panel);
36534 * Get the active panel for this region.
36535 * @return {Roo.ContentPanel} The active panel or null
36537 getActivePanel : function(){
36538 return this.activePanel;
36541 validateVisibility : function(){
36542 if(this.panels.getCount() < 1){
36543 this.updateTitle(" ");
36544 this.closeBtn.hide();
36547 if(!this.isVisible()){
36554 * Adds the passed ContentPanel(s) to this region.
36555 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
36556 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
36558 add : function(panel)
36560 if(arguments.length > 1){
36561 for(var i = 0, len = arguments.length; i < len; i++) {
36562 this.add(arguments[i]);
36567 // if we have not been rendered yet, then we can not really do much of this..
36568 if (!this.bodyEl) {
36569 this.unrendered_panels.push(panel);
36576 if(this.hasPanel(panel)){
36577 this.showPanel(panel);
36580 panel.setRegion(this);
36581 this.panels.add(panel);
36582 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
36583 // sinle panel - no tab...?? would it not be better to render it with the tabs,
36584 // and hide them... ???
36585 this.bodyEl.dom.appendChild(panel.getEl().dom);
36586 if(panel.background !== true){
36587 this.setActivePanel(panel);
36589 this.fireEvent("paneladded", this, panel);
36596 this.initPanelAsTab(panel);
36600 if(panel.background !== true){
36601 this.tabs.activate(panel.getEl().id);
36603 this.fireEvent("paneladded", this, panel);
36608 * Hides the tab for the specified panel.
36609 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36611 hidePanel : function(panel){
36612 if(this.tabs && (panel = this.getPanel(panel))){
36613 this.tabs.hideTab(panel.getEl().id);
36618 * Unhides the tab for a previously hidden panel.
36619 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36621 unhidePanel : function(panel){
36622 if(this.tabs && (panel = this.getPanel(panel))){
36623 this.tabs.unhideTab(panel.getEl().id);
36627 clearPanels : function(){
36628 while(this.panels.getCount() > 0){
36629 this.remove(this.panels.first());
36634 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
36635 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36636 * @param {Boolean} preservePanel Overrides the config preservePanel option
36637 * @return {Roo.ContentPanel} The panel that was removed
36639 remove : function(panel, preservePanel)
36641 panel = this.getPanel(panel);
36646 this.fireEvent("beforeremove", this, panel, e);
36647 if(e.cancel === true){
36650 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
36651 var panelId = panel.getId();
36652 this.panels.removeKey(panelId);
36654 document.body.appendChild(panel.getEl().dom);
36657 this.tabs.removeTab(panel.getEl().id);
36658 }else if (!preservePanel){
36659 this.bodyEl.dom.removeChild(panel.getEl().dom);
36661 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
36662 var p = this.panels.first();
36663 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
36664 tempEl.appendChild(p.getEl().dom);
36665 this.bodyEl.update("");
36666 this.bodyEl.dom.appendChild(p.getEl().dom);
36668 this.updateTitle(p.getTitle());
36670 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
36671 this.setActivePanel(p);
36673 panel.setRegion(null);
36674 if(this.activePanel == panel){
36675 this.activePanel = null;
36677 if(this.config.autoDestroy !== false && preservePanel !== true){
36678 try{panel.destroy();}catch(e){}
36680 this.fireEvent("panelremoved", this, panel);
36685 * Returns the TabPanel component used by this region
36686 * @return {Roo.TabPanel}
36688 getTabs : function(){
36692 createTool : function(parentEl, className){
36693 var btn = Roo.DomHelper.append(parentEl, {
36695 cls: "x-layout-tools-button",
36698 cls: "roo-layout-tools-button-inner " + className,
36702 btn.addClassOnOver("roo-layout-tools-button-over");
36707 * Ext JS Library 1.1.1
36708 * Copyright(c) 2006-2007, Ext JS, LLC.
36710 * Originally Released Under LGPL - original licence link has changed is not relivant.
36713 * <script type="text/javascript">
36719 * @class Roo.SplitLayoutRegion
36720 * @extends Roo.LayoutRegion
36721 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
36723 Roo.bootstrap.layout.Split = function(config){
36724 this.cursor = config.cursor;
36725 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
36728 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
36730 splitTip : "Drag to resize.",
36731 collapsibleSplitTip : "Drag to resize. Double click to hide.",
36732 useSplitTips : false,
36734 applyConfig : function(config){
36735 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
36738 onRender : function(ctr,pos) {
36740 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
36741 if(!this.config.split){
36746 var splitEl = Roo.DomHelper.append(ctr.dom, {
36748 id: this.el.id + "-split",
36749 cls: "roo-layout-split roo-layout-split-"+this.position,
36752 /** The SplitBar for this region
36753 * @type Roo.SplitBar */
36754 // does not exist yet...
36755 Roo.log([this.position, this.orientation]);
36757 this.split = new Roo.bootstrap.SplitBar({
36758 dragElement : splitEl,
36759 resizingElement: this.el,
36760 orientation : this.orientation
36763 this.split.on("moved", this.onSplitMove, this);
36764 this.split.useShim = this.config.useShim === true;
36765 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
36766 if(this.useSplitTips){
36767 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
36769 //if(config.collapsible){
36770 // this.split.el.on("dblclick", this.collapse, this);
36773 if(typeof this.config.minSize != "undefined"){
36774 this.split.minSize = this.config.minSize;
36776 if(typeof this.config.maxSize != "undefined"){
36777 this.split.maxSize = this.config.maxSize;
36779 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
36780 this.hideSplitter();
36785 getHMaxSize : function(){
36786 var cmax = this.config.maxSize || 10000;
36787 var center = this.mgr.getRegion("center");
36788 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
36791 getVMaxSize : function(){
36792 var cmax = this.config.maxSize || 10000;
36793 var center = this.mgr.getRegion("center");
36794 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
36797 onSplitMove : function(split, newSize){
36798 this.fireEvent("resized", this, newSize);
36802 * Returns the {@link Roo.SplitBar} for this region.
36803 * @return {Roo.SplitBar}
36805 getSplitBar : function(){
36810 this.hideSplitter();
36811 Roo.bootstrap.layout.Split.superclass.hide.call(this);
36814 hideSplitter : function(){
36816 this.split.el.setLocation(-2000,-2000);
36817 this.split.el.hide();
36823 this.split.el.show();
36825 Roo.bootstrap.layout.Split.superclass.show.call(this);
36828 beforeSlide: function(){
36829 if(Roo.isGecko){// firefox overflow auto bug workaround
36830 this.bodyEl.clip();
36832 this.tabs.bodyEl.clip();
36834 if(this.activePanel){
36835 this.activePanel.getEl().clip();
36837 if(this.activePanel.beforeSlide){
36838 this.activePanel.beforeSlide();
36844 afterSlide : function(){
36845 if(Roo.isGecko){// firefox overflow auto bug workaround
36846 this.bodyEl.unclip();
36848 this.tabs.bodyEl.unclip();
36850 if(this.activePanel){
36851 this.activePanel.getEl().unclip();
36852 if(this.activePanel.afterSlide){
36853 this.activePanel.afterSlide();
36859 initAutoHide : function(){
36860 if(this.autoHide !== false){
36861 if(!this.autoHideHd){
36862 var st = new Roo.util.DelayedTask(this.slideIn, this);
36863 this.autoHideHd = {
36864 "mouseout": function(e){
36865 if(!e.within(this.el, true)){
36869 "mouseover" : function(e){
36875 this.el.on(this.autoHideHd);
36879 clearAutoHide : function(){
36880 if(this.autoHide !== false){
36881 this.el.un("mouseout", this.autoHideHd.mouseout);
36882 this.el.un("mouseover", this.autoHideHd.mouseover);
36886 clearMonitor : function(){
36887 Roo.get(document).un("click", this.slideInIf, this);
36890 // these names are backwards but not changed for compat
36891 slideOut : function(){
36892 if(this.isSlid || this.el.hasActiveFx()){
36895 this.isSlid = true;
36896 if(this.collapseBtn){
36897 this.collapseBtn.hide();
36899 this.closeBtnState = this.closeBtn.getStyle('display');
36900 this.closeBtn.hide();
36902 this.stickBtn.show();
36905 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
36906 this.beforeSlide();
36907 this.el.setStyle("z-index", 10001);
36908 this.el.slideIn(this.getSlideAnchor(), {
36909 callback: function(){
36911 this.initAutoHide();
36912 Roo.get(document).on("click", this.slideInIf, this);
36913 this.fireEvent("slideshow", this);
36920 afterSlideIn : function(){
36921 this.clearAutoHide();
36922 this.isSlid = false;
36923 this.clearMonitor();
36924 this.el.setStyle("z-index", "");
36925 if(this.collapseBtn){
36926 this.collapseBtn.show();
36928 this.closeBtn.setStyle('display', this.closeBtnState);
36930 this.stickBtn.hide();
36932 this.fireEvent("slidehide", this);
36935 slideIn : function(cb){
36936 if(!this.isSlid || this.el.hasActiveFx()){
36940 this.isSlid = false;
36941 this.beforeSlide();
36942 this.el.slideOut(this.getSlideAnchor(), {
36943 callback: function(){
36944 this.el.setLeftTop(-10000, -10000);
36946 this.afterSlideIn();
36954 slideInIf : function(e){
36955 if(!e.within(this.el)){
36960 animateCollapse : function(){
36961 this.beforeSlide();
36962 this.el.setStyle("z-index", 20000);
36963 var anchor = this.getSlideAnchor();
36964 this.el.slideOut(anchor, {
36965 callback : function(){
36966 this.el.setStyle("z-index", "");
36967 this.collapsedEl.slideIn(anchor, {duration:.3});
36969 this.el.setLocation(-10000,-10000);
36971 this.fireEvent("collapsed", this);
36978 animateExpand : function(){
36979 this.beforeSlide();
36980 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
36981 this.el.setStyle("z-index", 20000);
36982 this.collapsedEl.hide({
36985 this.el.slideIn(this.getSlideAnchor(), {
36986 callback : function(){
36987 this.el.setStyle("z-index", "");
36990 this.split.el.show();
36992 this.fireEvent("invalidated", this);
36993 this.fireEvent("expanded", this);
37021 getAnchor : function(){
37022 return this.anchors[this.position];
37025 getCollapseAnchor : function(){
37026 return this.canchors[this.position];
37029 getSlideAnchor : function(){
37030 return this.sanchors[this.position];
37033 getAlignAdj : function(){
37034 var cm = this.cmargins;
37035 switch(this.position){
37051 getExpandAdj : function(){
37052 var c = this.collapsedEl, cm = this.cmargins;
37053 switch(this.position){
37055 return [-(cm.right+c.getWidth()+cm.left), 0];
37058 return [cm.right+c.getWidth()+cm.left, 0];
37061 return [0, -(cm.top+cm.bottom+c.getHeight())];
37064 return [0, cm.top+cm.bottom+c.getHeight()];
37070 * Ext JS Library 1.1.1
37071 * Copyright(c) 2006-2007, Ext JS, LLC.
37073 * Originally Released Under LGPL - original licence link has changed is not relivant.
37076 * <script type="text/javascript">
37079 * These classes are private internal classes
37081 Roo.bootstrap.layout.Center = function(config){
37082 config.region = "center";
37083 Roo.bootstrap.layout.Region.call(this, config);
37084 this.visible = true;
37085 this.minWidth = config.minWidth || 20;
37086 this.minHeight = config.minHeight || 20;
37089 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
37091 // center panel can't be hidden
37095 // center panel can't be hidden
37098 getMinWidth: function(){
37099 return this.minWidth;
37102 getMinHeight: function(){
37103 return this.minHeight;
37117 Roo.bootstrap.layout.North = function(config)
37119 config.region = 'north';
37120 config.cursor = 'n-resize';
37122 Roo.bootstrap.layout.Split.call(this, config);
37126 this.split.placement = Roo.bootstrap.SplitBar.TOP;
37127 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
37128 this.split.el.addClass("roo-layout-split-v");
37130 var size = config.initialSize || config.height;
37131 if(typeof size != "undefined"){
37132 this.el.setHeight(size);
37135 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
37137 orientation: Roo.bootstrap.SplitBar.VERTICAL,
37141 getBox : function(){
37142 if(this.collapsed){
37143 return this.collapsedEl.getBox();
37145 var box = this.el.getBox();
37147 box.height += this.split.el.getHeight();
37152 updateBox : function(box){
37153 if(this.split && !this.collapsed){
37154 box.height -= this.split.el.getHeight();
37155 this.split.el.setLeft(box.x);
37156 this.split.el.setTop(box.y+box.height);
37157 this.split.el.setWidth(box.width);
37159 if(this.collapsed){
37160 this.updateBody(box.width, null);
37162 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37170 Roo.bootstrap.layout.South = function(config){
37171 config.region = 'south';
37172 config.cursor = 's-resize';
37173 Roo.bootstrap.layout.Split.call(this, config);
37175 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
37176 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
37177 this.split.el.addClass("roo-layout-split-v");
37179 var size = config.initialSize || config.height;
37180 if(typeof size != "undefined"){
37181 this.el.setHeight(size);
37185 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
37186 orientation: Roo.bootstrap.SplitBar.VERTICAL,
37187 getBox : function(){
37188 if(this.collapsed){
37189 return this.collapsedEl.getBox();
37191 var box = this.el.getBox();
37193 var sh = this.split.el.getHeight();
37200 updateBox : function(box){
37201 if(this.split && !this.collapsed){
37202 var sh = this.split.el.getHeight();
37205 this.split.el.setLeft(box.x);
37206 this.split.el.setTop(box.y-sh);
37207 this.split.el.setWidth(box.width);
37209 if(this.collapsed){
37210 this.updateBody(box.width, null);
37212 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37216 Roo.bootstrap.layout.East = function(config){
37217 config.region = "east";
37218 config.cursor = "e-resize";
37219 Roo.bootstrap.layout.Split.call(this, config);
37221 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
37222 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
37223 this.split.el.addClass("roo-layout-split-h");
37225 var size = config.initialSize || config.width;
37226 if(typeof size != "undefined"){
37227 this.el.setWidth(size);
37230 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
37231 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
37232 getBox : function(){
37233 if(this.collapsed){
37234 return this.collapsedEl.getBox();
37236 var box = this.el.getBox();
37238 var sw = this.split.el.getWidth();
37245 updateBox : function(box){
37246 if(this.split && !this.collapsed){
37247 var sw = this.split.el.getWidth();
37249 this.split.el.setLeft(box.x);
37250 this.split.el.setTop(box.y);
37251 this.split.el.setHeight(box.height);
37254 if(this.collapsed){
37255 this.updateBody(null, box.height);
37257 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37261 Roo.bootstrap.layout.West = function(config){
37262 config.region = "west";
37263 config.cursor = "w-resize";
37265 Roo.bootstrap.layout.Split.call(this, config);
37267 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
37268 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
37269 this.split.el.addClass("roo-layout-split-h");
37273 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
37274 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
37276 onRender: function(ctr, pos)
37278 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
37279 var size = this.config.initialSize || this.config.width;
37280 if(typeof size != "undefined"){
37281 this.el.setWidth(size);
37285 getBox : function(){
37286 if(this.collapsed){
37287 return this.collapsedEl.getBox();
37289 var box = this.el.getBox();
37291 box.width += this.split.el.getWidth();
37296 updateBox : function(box){
37297 if(this.split && !this.collapsed){
37298 var sw = this.split.el.getWidth();
37300 this.split.el.setLeft(box.x+box.width);
37301 this.split.el.setTop(box.y);
37302 this.split.el.setHeight(box.height);
37304 if(this.collapsed){
37305 this.updateBody(null, box.height);
37307 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37309 });Roo.namespace("Roo.bootstrap.panel");/*
37311 * Ext JS Library 1.1.1
37312 * Copyright(c) 2006-2007, Ext JS, LLC.
37314 * Originally Released Under LGPL - original licence link has changed is not relivant.
37317 * <script type="text/javascript">
37320 * @class Roo.ContentPanel
37321 * @extends Roo.util.Observable
37322 * A basic ContentPanel element.
37323 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
37324 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
37325 * @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
37326 * @cfg {Boolean} closable True if the panel can be closed/removed
37327 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
37328 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
37329 * @cfg {Toolbar} toolbar A toolbar for this panel
37330 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
37331 * @cfg {String} title The title for this panel
37332 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
37333 * @cfg {String} url Calls {@link #setUrl} with this value
37334 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
37335 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
37336 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
37337 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
37338 * @cfg {Boolean} badges render the badges
37341 * Create a new ContentPanel.
37342 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
37343 * @param {String/Object} config A string to set only the title or a config object
37344 * @param {String} content (optional) Set the HTML content for this panel
37345 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
37347 Roo.bootstrap.panel.Content = function( config){
37349 this.tpl = config.tpl || false;
37351 var el = config.el;
37352 var content = config.content;
37354 if(config.autoCreate){ // xtype is available if this is called from factory
37357 this.el = Roo.get(el);
37358 if(!this.el && config && config.autoCreate){
37359 if(typeof config.autoCreate == "object"){
37360 if(!config.autoCreate.id){
37361 config.autoCreate.id = config.id||el;
37363 this.el = Roo.DomHelper.append(document.body,
37364 config.autoCreate, true);
37366 var elcfg = { tag: "div",
37367 cls: "roo-layout-inactive-content",
37371 elcfg.html = config.html;
37375 this.el = Roo.DomHelper.append(document.body, elcfg , true);
37378 this.closable = false;
37379 this.loaded = false;
37380 this.active = false;
37383 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
37385 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
37387 this.wrapEl = this.el; //this.el.wrap();
37389 if (config.toolbar.items) {
37390 ti = config.toolbar.items ;
37391 delete config.toolbar.items ;
37395 this.toolbar.render(this.wrapEl, 'before');
37396 for(var i =0;i < ti.length;i++) {
37397 // Roo.log(['add child', items[i]]);
37398 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37400 this.toolbar.items = nitems;
37401 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
37402 delete config.toolbar;
37406 // xtype created footer. - not sure if will work as we normally have to render first..
37407 if (this.footer && !this.footer.el && this.footer.xtype) {
37408 if (!this.wrapEl) {
37409 this.wrapEl = this.el.wrap();
37412 this.footer.container = this.wrapEl.createChild();
37414 this.footer = Roo.factory(this.footer, Roo);
37419 if(typeof config == "string"){
37420 this.title = config;
37422 Roo.apply(this, config);
37426 this.resizeEl = Roo.get(this.resizeEl, true);
37428 this.resizeEl = this.el;
37430 // handle view.xtype
37438 * Fires when this panel is activated.
37439 * @param {Roo.ContentPanel} this
37443 * @event deactivate
37444 * Fires when this panel is activated.
37445 * @param {Roo.ContentPanel} this
37447 "deactivate" : true,
37451 * Fires when this panel is resized if fitToFrame is true.
37452 * @param {Roo.ContentPanel} this
37453 * @param {Number} width The width after any component adjustments
37454 * @param {Number} height The height after any component adjustments
37460 * Fires when this tab is created
37461 * @param {Roo.ContentPanel} this
37472 if(this.autoScroll){
37473 this.resizeEl.setStyle("overflow", "auto");
37475 // fix randome scrolling
37476 //this.el.on('scroll', function() {
37477 // Roo.log('fix random scolling');
37478 // this.scrollTo('top',0);
37481 content = content || this.content;
37483 this.setContent(content);
37485 if(config && config.url){
37486 this.setUrl(this.url, this.params, this.loadOnce);
37491 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
37493 if (this.view && typeof(this.view.xtype) != 'undefined') {
37494 this.view.el = this.el.appendChild(document.createElement("div"));
37495 this.view = Roo.factory(this.view);
37496 this.view.render && this.view.render(false, '');
37500 this.fireEvent('render', this);
37503 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
37507 setRegion : function(region){
37508 this.region = region;
37509 this.setActiveClass(region && !this.background);
37513 setActiveClass: function(state)
37516 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
37517 this.el.setStyle('position','relative');
37519 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
37520 this.el.setStyle('position', 'absolute');
37525 * Returns the toolbar for this Panel if one was configured.
37526 * @return {Roo.Toolbar}
37528 getToolbar : function(){
37529 return this.toolbar;
37532 setActiveState : function(active)
37534 this.active = active;
37535 this.setActiveClass(active);
37537 if(this.fireEvent("deactivate", this) === false){
37542 this.fireEvent("activate", this);
37546 * Updates this panel's element
37547 * @param {String} content The new content
37548 * @param {Boolean} loadScripts (optional) true to look for and process scripts
37550 setContent : function(content, loadScripts){
37551 this.el.update(content, loadScripts);
37554 ignoreResize : function(w, h){
37555 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
37558 this.lastSize = {width: w, height: h};
37563 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
37564 * @return {Roo.UpdateManager} The UpdateManager
37566 getUpdateManager : function(){
37567 return this.el.getUpdateManager();
37570 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
37571 * @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:
37574 url: "your-url.php",
37575 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
37576 callback: yourFunction,
37577 scope: yourObject, //(optional scope)
37580 text: "Loading...",
37585 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
37586 * 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.
37587 * @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}
37588 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
37589 * @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.
37590 * @return {Roo.ContentPanel} this
37593 var um = this.el.getUpdateManager();
37594 um.update.apply(um, arguments);
37600 * 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.
37601 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
37602 * @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)
37603 * @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)
37604 * @return {Roo.UpdateManager} The UpdateManager
37606 setUrl : function(url, params, loadOnce){
37607 if(this.refreshDelegate){
37608 this.removeListener("activate", this.refreshDelegate);
37610 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
37611 this.on("activate", this.refreshDelegate);
37612 return this.el.getUpdateManager();
37615 _handleRefresh : function(url, params, loadOnce){
37616 if(!loadOnce || !this.loaded){
37617 var updater = this.el.getUpdateManager();
37618 updater.update(url, params, this._setLoaded.createDelegate(this));
37622 _setLoaded : function(){
37623 this.loaded = true;
37627 * Returns this panel's id
37630 getId : function(){
37635 * Returns this panel's element - used by regiosn to add.
37636 * @return {Roo.Element}
37638 getEl : function(){
37639 return this.wrapEl || this.el;
37644 adjustForComponents : function(width, height)
37646 //Roo.log('adjustForComponents ');
37647 if(this.resizeEl != this.el){
37648 width -= this.el.getFrameWidth('lr');
37649 height -= this.el.getFrameWidth('tb');
37652 var te = this.toolbar.getEl();
37653 te.setWidth(width);
37654 height -= te.getHeight();
37657 var te = this.footer.getEl();
37658 te.setWidth(width);
37659 height -= te.getHeight();
37663 if(this.adjustments){
37664 width += this.adjustments[0];
37665 height += this.adjustments[1];
37667 return {"width": width, "height": height};
37670 setSize : function(width, height){
37671 if(this.fitToFrame && !this.ignoreResize(width, height)){
37672 if(this.fitContainer && this.resizeEl != this.el){
37673 this.el.setSize(width, height);
37675 var size = this.adjustForComponents(width, height);
37676 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
37677 this.fireEvent('resize', this, size.width, size.height);
37682 * Returns this panel's title
37685 getTitle : function(){
37687 if (typeof(this.title) != 'object') {
37692 for (var k in this.title) {
37693 if (!this.title.hasOwnProperty(k)) {
37697 if (k.indexOf('-') >= 0) {
37698 var s = k.split('-');
37699 for (var i = 0; i<s.length; i++) {
37700 t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
37703 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
37710 * Set this panel's title
37711 * @param {String} title
37713 setTitle : function(title){
37714 this.title = title;
37716 this.region.updatePanelTitle(this, title);
37721 * Returns true is this panel was configured to be closable
37722 * @return {Boolean}
37724 isClosable : function(){
37725 return this.closable;
37728 beforeSlide : function(){
37730 this.resizeEl.clip();
37733 afterSlide : function(){
37735 this.resizeEl.unclip();
37739 * Force a content refresh from the URL specified in the {@link #setUrl} method.
37740 * Will fail silently if the {@link #setUrl} method has not been called.
37741 * This does not activate the panel, just updates its content.
37743 refresh : function(){
37744 if(this.refreshDelegate){
37745 this.loaded = false;
37746 this.refreshDelegate();
37751 * Destroys this panel
37753 destroy : function(){
37754 this.el.removeAllListeners();
37755 var tempEl = document.createElement("span");
37756 tempEl.appendChild(this.el.dom);
37757 tempEl.innerHTML = "";
37763 * form - if the content panel contains a form - this is a reference to it.
37764 * @type {Roo.form.Form}
37768 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
37769 * This contains a reference to it.
37775 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
37785 * @param {Object} cfg Xtype definition of item to add.
37789 getChildContainer: function () {
37790 return this.getEl();
37795 var ret = new Roo.factory(cfg);
37800 if (cfg.xtype.match(/^Form$/)) {
37803 //if (this.footer) {
37804 // el = this.footer.container.insertSibling(false, 'before');
37806 el = this.el.createChild();
37809 this.form = new Roo.form.Form(cfg);
37812 if ( this.form.allItems.length) {
37813 this.form.render(el.dom);
37817 // should only have one of theses..
37818 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
37819 // views.. should not be just added - used named prop 'view''
37821 cfg.el = this.el.appendChild(document.createElement("div"));
37824 var ret = new Roo.factory(cfg);
37826 ret.render && ret.render(false, ''); // render blank..
37836 * @class Roo.bootstrap.panel.Grid
37837 * @extends Roo.bootstrap.panel.Content
37839 * Create a new GridPanel.
37840 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
37841 * @param {Object} config A the config object
37847 Roo.bootstrap.panel.Grid = function(config)
37851 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
37852 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
37854 config.el = this.wrapper;
37855 //this.el = this.wrapper;
37857 if (config.container) {
37858 // ctor'ed from a Border/panel.grid
37861 this.wrapper.setStyle("overflow", "hidden");
37862 this.wrapper.addClass('roo-grid-container');
37867 if(config.toolbar){
37868 var tool_el = this.wrapper.createChild();
37869 this.toolbar = Roo.factory(config.toolbar);
37871 if (config.toolbar.items) {
37872 ti = config.toolbar.items ;
37873 delete config.toolbar.items ;
37877 this.toolbar.render(tool_el);
37878 for(var i =0;i < ti.length;i++) {
37879 // Roo.log(['add child', items[i]]);
37880 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37882 this.toolbar.items = nitems;
37884 delete config.toolbar;
37887 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
37888 config.grid.scrollBody = true;;
37889 config.grid.monitorWindowResize = false; // turn off autosizing
37890 config.grid.autoHeight = false;
37891 config.grid.autoWidth = false;
37893 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
37895 if (config.background) {
37896 // render grid on panel activation (if panel background)
37897 this.on('activate', function(gp) {
37898 if (!gp.grid.rendered) {
37899 gp.grid.render(this.wrapper);
37900 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37905 this.grid.render(this.wrapper);
37906 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37909 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
37910 // ??? needed ??? config.el = this.wrapper;
37915 // xtype created footer. - not sure if will work as we normally have to render first..
37916 if (this.footer && !this.footer.el && this.footer.xtype) {
37918 var ctr = this.grid.getView().getFooterPanel(true);
37919 this.footer.dataSource = this.grid.dataSource;
37920 this.footer = Roo.factory(this.footer, Roo);
37921 this.footer.render(ctr);
37931 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
37932 getId : function(){
37933 return this.grid.id;
37937 * Returns the grid for this panel
37938 * @return {Roo.bootstrap.Table}
37940 getGrid : function(){
37944 setSize : function(width, height){
37945 if(!this.ignoreResize(width, height)){
37946 var grid = this.grid;
37947 var size = this.adjustForComponents(width, height);
37948 var gridel = grid.getGridEl();
37949 gridel.setSize(size.width, size.height);
37951 var thd = grid.getGridEl().select('thead',true).first();
37952 var tbd = grid.getGridEl().select('tbody', true).first();
37954 tbd.setSize(width, height - thd.getHeight());
37963 beforeSlide : function(){
37964 this.grid.getView().scroller.clip();
37967 afterSlide : function(){
37968 this.grid.getView().scroller.unclip();
37971 destroy : function(){
37972 this.grid.destroy();
37974 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
37979 * @class Roo.bootstrap.panel.Nest
37980 * @extends Roo.bootstrap.panel.Content
37982 * Create a new Panel, that can contain a layout.Border.
37985 * @param {Roo.BorderLayout} layout The layout for this panel
37986 * @param {String/Object} config A string to set only the title or a config object
37988 Roo.bootstrap.panel.Nest = function(config)
37990 // construct with only one argument..
37991 /* FIXME - implement nicer consturctors
37992 if (layout.layout) {
37994 layout = config.layout;
37995 delete config.layout;
37997 if (layout.xtype && !layout.getEl) {
37998 // then layout needs constructing..
37999 layout = Roo.factory(layout, Roo);
38003 config.el = config.layout.getEl();
38005 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
38007 config.layout.monitorWindowResize = false; // turn off autosizing
38008 this.layout = config.layout;
38009 this.layout.getEl().addClass("roo-layout-nested-layout");
38010 this.layout.parent = this;
38017 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
38019 setSize : function(width, height){
38020 if(!this.ignoreResize(width, height)){
38021 var size = this.adjustForComponents(width, height);
38022 var el = this.layout.getEl();
38023 if (size.height < 1) {
38024 el.setWidth(size.width);
38026 el.setSize(size.width, size.height);
38028 var touch = el.dom.offsetWidth;
38029 this.layout.layout();
38030 // ie requires a double layout on the first pass
38031 if(Roo.isIE && !this.initialized){
38032 this.initialized = true;
38033 this.layout.layout();
38038 // activate all subpanels if not currently active..
38040 setActiveState : function(active){
38041 this.active = active;
38042 this.setActiveClass(active);
38045 this.fireEvent("deactivate", this);
38049 this.fireEvent("activate", this);
38050 // not sure if this should happen before or after..
38051 if (!this.layout) {
38052 return; // should not happen..
38055 for (var r in this.layout.regions) {
38056 reg = this.layout.getRegion(r);
38057 if (reg.getActivePanel()) {
38058 //reg.showPanel(reg.getActivePanel()); // force it to activate..
38059 reg.setActivePanel(reg.getActivePanel());
38062 if (!reg.panels.length) {
38065 reg.showPanel(reg.getPanel(0));
38074 * Returns the nested BorderLayout for this panel
38075 * @return {Roo.BorderLayout}
38077 getLayout : function(){
38078 return this.layout;
38082 * Adds a xtype elements to the layout of the nested panel
38086 xtype : 'ContentPanel',
38093 xtype : 'NestedLayoutPanel',
38099 items : [ ... list of content panels or nested layout panels.. ]
38103 * @param {Object} cfg Xtype definition of item to add.
38105 addxtype : function(cfg) {
38106 return this.layout.addxtype(cfg);
38111 * Ext JS Library 1.1.1
38112 * Copyright(c) 2006-2007, Ext JS, LLC.
38114 * Originally Released Under LGPL - original licence link has changed is not relivant.
38117 * <script type="text/javascript">
38120 * @class Roo.TabPanel
38121 * @extends Roo.util.Observable
38122 * A lightweight tab container.
38126 // basic tabs 1, built from existing content
38127 var tabs = new Roo.TabPanel("tabs1");
38128 tabs.addTab("script", "View Script");
38129 tabs.addTab("markup", "View Markup");
38130 tabs.activate("script");
38132 // more advanced tabs, built from javascript
38133 var jtabs = new Roo.TabPanel("jtabs");
38134 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
38136 // set up the UpdateManager
38137 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
38138 var updater = tab2.getUpdateManager();
38139 updater.setDefaultUrl("ajax1.htm");
38140 tab2.on('activate', updater.refresh, updater, true);
38142 // Use setUrl for Ajax loading
38143 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
38144 tab3.setUrl("ajax2.htm", null, true);
38147 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
38150 jtabs.activate("jtabs-1");
38153 * Create a new TabPanel.
38154 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
38155 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
38157 Roo.bootstrap.panel.Tabs = function(config){
38159 * The container element for this TabPanel.
38160 * @type Roo.Element
38162 this.el = Roo.get(config.el);
38165 if(typeof config == "boolean"){
38166 this.tabPosition = config ? "bottom" : "top";
38168 Roo.apply(this, config);
38172 if(this.tabPosition == "bottom"){
38173 // if tabs are at the bottom = create the body first.
38174 this.bodyEl = Roo.get(this.createBody(this.el.dom));
38175 this.el.addClass("roo-tabs-bottom");
38177 // next create the tabs holders
38179 if (this.tabPosition == "west"){
38181 var reg = this.region; // fake it..
38183 if (!reg.mgr.parent) {
38186 reg = reg.mgr.parent.region;
38188 Roo.log("got nest?");
38190 if (reg.mgr.getRegion('west')) {
38191 var ctrdom = reg.mgr.getRegion('west').bodyEl.dom;
38192 this.stripWrap = Roo.get(this.createStrip(ctrdom ), true);
38193 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
38194 this.stripEl.setVisibilityMode(Roo.Element.DISPLAY);
38195 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
38203 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
38204 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
38205 this.stripEl.setVisibilityMode(Roo.Element.DISPLAY);
38206 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
38211 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
38214 // finally - if tabs are at the top, then create the body last..
38215 if(this.tabPosition != "bottom"){
38216 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
38217 * @type Roo.Element
38219 this.bodyEl = Roo.get(this.createBody(this.el.dom));
38220 this.el.addClass("roo-tabs-top");
38224 this.bodyEl.setStyle("position", "relative");
38226 this.active = null;
38227 this.activateDelegate = this.activate.createDelegate(this);
38232 * Fires when the active tab changes
38233 * @param {Roo.TabPanel} this
38234 * @param {Roo.TabPanelItem} activePanel The new active tab
38238 * @event beforetabchange
38239 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
38240 * @param {Roo.TabPanel} this
38241 * @param {Object} e Set cancel to true on this object to cancel the tab change
38242 * @param {Roo.TabPanelItem} tab The tab being changed to
38244 "beforetabchange" : true
38247 Roo.EventManager.onWindowResize(this.onResize, this);
38248 this.cpad = this.el.getPadding("lr");
38249 this.hiddenCount = 0;
38252 // toolbar on the tabbar support...
38253 if (this.toolbar) {
38254 alert("no toolbar support yet");
38255 this.toolbar = false;
38257 var tcfg = this.toolbar;
38258 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
38259 this.toolbar = new Roo.Toolbar(tcfg);
38260 if (Roo.isSafari) {
38261 var tbl = tcfg.container.child('table', true);
38262 tbl.setAttribute('width', '100%');
38270 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
38273 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
38275 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
38277 tabPosition : "top",
38279 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
38281 currentTabWidth : 0,
38283 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
38287 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
38291 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
38293 preferredTabWidth : 175,
38295 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
38297 resizeTabs : false,
38299 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
38301 monitorResize : true,
38303 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
38305 toolbar : false, // set by caller..
38307 region : false, /// set by caller
38309 disableTooltips : true, // not used yet...
38312 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
38313 * @param {String} id The id of the div to use <b>or create</b>
38314 * @param {String} text The text for the tab
38315 * @param {String} content (optional) Content to put in the TabPanelItem body
38316 * @param {Boolean} closable (optional) True to create a close icon on the tab
38317 * @return {Roo.TabPanelItem} The created TabPanelItem
38319 addTab : function(id, text, content, closable, tpl)
38321 var item = new Roo.bootstrap.panel.TabItem({
38325 closable : closable,
38328 this.addTabItem(item);
38330 item.setContent(content);
38336 * Returns the {@link Roo.TabPanelItem} with the specified id/index
38337 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
38338 * @return {Roo.TabPanelItem}
38340 getTab : function(id){
38341 return this.items[id];
38345 * Hides the {@link Roo.TabPanelItem} with the specified id/index
38346 * @param {String/Number} id The id or index of the TabPanelItem to hide.
38348 hideTab : function(id){
38349 var t = this.items[id];
38352 this.hiddenCount++;
38353 this.autoSizeTabs();
38358 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
38359 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
38361 unhideTab : function(id){
38362 var t = this.items[id];
38364 t.setHidden(false);
38365 this.hiddenCount--;
38366 this.autoSizeTabs();
38371 * Adds an existing {@link Roo.TabPanelItem}.
38372 * @param {Roo.TabPanelItem} item The TabPanelItem to add
38374 addTabItem : function(item)
38376 this.items[item.id] = item;
38377 this.items.push(item);
38378 this.autoSizeTabs();
38379 // if(this.resizeTabs){
38380 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
38381 // this.autoSizeTabs();
38383 // item.autoSize();
38388 * Removes a {@link Roo.TabPanelItem}.
38389 * @param {String/Number} id The id or index of the TabPanelItem to remove.
38391 removeTab : function(id){
38392 var items = this.items;
38393 var tab = items[id];
38394 if(!tab) { return; }
38395 var index = items.indexOf(tab);
38396 if(this.active == tab && items.length > 1){
38397 var newTab = this.getNextAvailable(index);
38402 this.stripEl.dom.removeChild(tab.pnode.dom);
38403 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
38404 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
38406 items.splice(index, 1);
38407 delete this.items[tab.id];
38408 tab.fireEvent("close", tab);
38409 tab.purgeListeners();
38410 this.autoSizeTabs();
38413 getNextAvailable : function(start){
38414 var items = this.items;
38416 // look for a next tab that will slide over to
38417 // replace the one being removed
38418 while(index < items.length){
38419 var item = items[++index];
38420 if(item && !item.isHidden()){
38424 // if one isn't found select the previous tab (on the left)
38427 var item = items[--index];
38428 if(item && !item.isHidden()){
38436 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
38437 * @param {String/Number} id The id or index of the TabPanelItem to disable.
38439 disableTab : function(id){
38440 var tab = this.items[id];
38441 if(tab && this.active != tab){
38447 * Enables a {@link Roo.TabPanelItem} that is disabled.
38448 * @param {String/Number} id The id or index of the TabPanelItem to enable.
38450 enableTab : function(id){
38451 var tab = this.items[id];
38456 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
38457 * @param {String/Number} id The id or index of the TabPanelItem to activate.
38458 * @return {Roo.TabPanelItem} The TabPanelItem.
38460 activate : function(id)
38462 //Roo.log('activite:' + id);
38464 var tab = this.items[id];
38468 if(tab == this.active || tab.disabled){
38472 this.fireEvent("beforetabchange", this, e, tab);
38473 if(e.cancel !== true && !tab.disabled){
38475 this.active.hide();
38477 this.active = this.items[id];
38478 this.active.show();
38479 this.fireEvent("tabchange", this, this.active);
38485 * Gets the active {@link Roo.TabPanelItem}.
38486 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
38488 getActiveTab : function(){
38489 return this.active;
38493 * Updates the tab body element to fit the height of the container element
38494 * for overflow scrolling
38495 * @param {Number} targetHeight (optional) Override the starting height from the elements height
38497 syncHeight : function(targetHeight){
38498 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
38499 var bm = this.bodyEl.getMargins();
38500 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
38501 this.bodyEl.setHeight(newHeight);
38505 onResize : function(){
38506 if(this.monitorResize){
38507 this.autoSizeTabs();
38512 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
38514 beginUpdate : function(){
38515 this.updating = true;
38519 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
38521 endUpdate : function(){
38522 this.updating = false;
38523 this.autoSizeTabs();
38527 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
38529 autoSizeTabs : function()
38531 var count = this.items.length;
38532 var vcount = count - this.hiddenCount;
38535 this.stripEl.hide();
38537 this.stripEl.show();
38540 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
38545 var w = Math.max(this.el.getWidth() - this.cpad, 10);
38546 var availWidth = Math.floor(w / vcount);
38547 var b = this.stripBody;
38548 if(b.getWidth() > w){
38549 var tabs = this.items;
38550 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
38551 if(availWidth < this.minTabWidth){
38552 /*if(!this.sleft){ // incomplete scrolling code
38553 this.createScrollButtons();
38556 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
38559 if(this.currentTabWidth < this.preferredTabWidth){
38560 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
38566 * Returns the number of tabs in this TabPanel.
38569 getCount : function(){
38570 return this.items.length;
38574 * Resizes all the tabs to the passed width
38575 * @param {Number} The new width
38577 setTabWidth : function(width){
38578 this.currentTabWidth = width;
38579 for(var i = 0, len = this.items.length; i < len; i++) {
38580 if(!this.items[i].isHidden()) {
38581 this.items[i].setWidth(width);
38587 * Destroys this TabPanel
38588 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
38590 destroy : function(removeEl){
38591 Roo.EventManager.removeResizeListener(this.onResize, this);
38592 for(var i = 0, len = this.items.length; i < len; i++){
38593 this.items[i].purgeListeners();
38595 if(removeEl === true){
38596 this.el.update("");
38601 createStrip : function(container)
38603 var strip = document.createElement("nav");
38604 strip.className = Roo.bootstrap.version == 4 ?
38605 "navbar-light bg-light" :
38606 "navbar navbar-default"; //"x-tabs-wrap";
38607 container.appendChild(strip);
38611 createStripList : function(strip)
38613 // div wrapper for retard IE
38614 // returns the "tr" element.
38615 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
38616 //'<div class="x-tabs-strip-wrap">'+
38617 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
38618 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
38619 return strip.firstChild; //.firstChild.firstChild.firstChild;
38621 createBody : function(container)
38623 var body = document.createElement("div");
38624 Roo.id(body, "tab-body");
38625 //Roo.fly(body).addClass("x-tabs-body");
38626 Roo.fly(body).addClass("tab-content");
38627 container.appendChild(body);
38630 createItemBody :function(bodyEl, id){
38631 var body = Roo.getDom(id);
38633 body = document.createElement("div");
38636 //Roo.fly(body).addClass("x-tabs-item-body");
38637 Roo.fly(body).addClass("tab-pane");
38638 bodyEl.insertBefore(body, bodyEl.firstChild);
38642 createStripElements : function(stripEl, text, closable, tpl)
38644 var td = document.createElement("li"); // was td..
38645 td.className = 'nav-item';
38647 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
38650 stripEl.appendChild(td);
38652 td.className = "x-tabs-closable";
38653 if(!this.closeTpl){
38654 this.closeTpl = new Roo.Template(
38655 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38656 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
38657 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
38660 var el = this.closeTpl.overwrite(td, {"text": text});
38661 var close = el.getElementsByTagName("div")[0];
38662 var inner = el.getElementsByTagName("em")[0];
38663 return {"el": el, "close": close, "inner": inner};
38666 // not sure what this is..
38667 // if(!this.tabTpl){
38668 //this.tabTpl = new Roo.Template(
38669 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38670 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
38672 // this.tabTpl = new Roo.Template(
38673 // '<a href="#">' +
38674 // '<span unselectable="on"' +
38675 // (this.disableTooltips ? '' : ' title="{text}"') +
38676 // ' >{text}</span></a>'
38682 var template = tpl || this.tabTpl || false;
38685 template = new Roo.Template(
38686 Roo.bootstrap.version == 4 ?
38688 '<a class="nav-link" href="#" unselectable="on"' +
38689 (this.disableTooltips ? '' : ' title="{text}"') +
38692 '<a class="nav-link" href="#">' +
38693 '<span unselectable="on"' +
38694 (this.disableTooltips ? '' : ' title="{text}"') +
38695 ' >{text}</span></a>'
38700 switch (typeof(template)) {
38704 template = new Roo.Template(template);
38710 var el = template.overwrite(td, {"text": text});
38712 var inner = el.getElementsByTagName("span")[0];
38714 return {"el": el, "inner": inner};
38722 * @class Roo.TabPanelItem
38723 * @extends Roo.util.Observable
38724 * Represents an individual item (tab plus body) in a TabPanel.
38725 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
38726 * @param {String} id The id of this TabPanelItem
38727 * @param {String} text The text for the tab of this TabPanelItem
38728 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
38730 Roo.bootstrap.panel.TabItem = function(config){
38732 * The {@link Roo.TabPanel} this TabPanelItem belongs to
38733 * @type Roo.TabPanel
38735 this.tabPanel = config.panel;
38737 * The id for this TabPanelItem
38740 this.id = config.id;
38742 this.disabled = false;
38744 this.text = config.text;
38746 this.loaded = false;
38747 this.closable = config.closable;
38750 * The body element for this TabPanelItem.
38751 * @type Roo.Element
38753 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
38754 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
38755 this.bodyEl.setStyle("display", "block");
38756 this.bodyEl.setStyle("zoom", "1");
38757 //this.hideAction();
38759 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
38761 this.el = Roo.get(els.el);
38762 this.inner = Roo.get(els.inner, true);
38763 this.textEl = Roo.bootstrap.version == 4 ?
38764 this.el : Roo.get(this.el.dom.firstChild, true);
38766 this.pnode = this.linode = Roo.get(els.el.parentNode, true);
38767 this.status_node = Roo.bootstrap.version == 4 ? this.el : this.linode;
38770 // this.el.on("mousedown", this.onTabMouseDown, this);
38771 this.el.on("click", this.onTabClick, this);
38773 if(config.closable){
38774 var c = Roo.get(els.close, true);
38775 c.dom.title = this.closeText;
38776 c.addClassOnOver("close-over");
38777 c.on("click", this.closeClick, this);
38783 * Fires when this tab becomes the active tab.
38784 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38785 * @param {Roo.TabPanelItem} this
38789 * @event beforeclose
38790 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
38791 * @param {Roo.TabPanelItem} this
38792 * @param {Object} e Set cancel to true on this object to cancel the close.
38794 "beforeclose": true,
38797 * Fires when this tab is closed.
38798 * @param {Roo.TabPanelItem} this
38802 * @event deactivate
38803 * Fires when this tab is no longer the active tab.
38804 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38805 * @param {Roo.TabPanelItem} this
38807 "deactivate" : true
38809 this.hidden = false;
38811 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
38814 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
38816 purgeListeners : function(){
38817 Roo.util.Observable.prototype.purgeListeners.call(this);
38818 this.el.removeAllListeners();
38821 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
38824 this.status_node.addClass("active");
38827 this.tabPanel.stripWrap.repaint();
38829 this.fireEvent("activate", this.tabPanel, this);
38833 * Returns true if this tab is the active tab.
38834 * @return {Boolean}
38836 isActive : function(){
38837 return this.tabPanel.getActiveTab() == this;
38841 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
38844 this.status_node.removeClass("active");
38846 this.fireEvent("deactivate", this.tabPanel, this);
38849 hideAction : function(){
38850 this.bodyEl.hide();
38851 this.bodyEl.setStyle("position", "absolute");
38852 this.bodyEl.setLeft("-20000px");
38853 this.bodyEl.setTop("-20000px");
38856 showAction : function(){
38857 this.bodyEl.setStyle("position", "relative");
38858 this.bodyEl.setTop("");
38859 this.bodyEl.setLeft("");
38860 this.bodyEl.show();
38864 * Set the tooltip for the tab.
38865 * @param {String} tooltip The tab's tooltip
38867 setTooltip : function(text){
38868 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
38869 this.textEl.dom.qtip = text;
38870 this.textEl.dom.removeAttribute('title');
38872 this.textEl.dom.title = text;
38876 onTabClick : function(e){
38877 e.preventDefault();
38878 this.tabPanel.activate(this.id);
38881 onTabMouseDown : function(e){
38882 e.preventDefault();
38883 this.tabPanel.activate(this.id);
38886 getWidth : function(){
38887 return this.inner.getWidth();
38890 setWidth : function(width){
38891 var iwidth = width - this.linode.getPadding("lr");
38892 this.inner.setWidth(iwidth);
38893 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
38894 this.linode.setWidth(width);
38898 * Show or hide the tab
38899 * @param {Boolean} hidden True to hide or false to show.
38901 setHidden : function(hidden){
38902 this.hidden = hidden;
38903 this.linode.setStyle("display", hidden ? "none" : "");
38907 * Returns true if this tab is "hidden"
38908 * @return {Boolean}
38910 isHidden : function(){
38911 return this.hidden;
38915 * Returns the text for this tab
38918 getText : function(){
38922 autoSize : function(){
38923 //this.el.beginMeasure();
38924 this.textEl.setWidth(1);
38926 * #2804 [new] Tabs in Roojs
38927 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
38929 //this.setWidth(this.textEl.dom.scrollWidth+this.linode.getPadding("lr")+this.inner.getPadding("lr") + 2);
38930 //this.el.endMeasure();
38934 * Sets the text for the tab (Note: this also sets the tooltip text)
38935 * @param {String} text The tab's text and tooltip
38937 setText : function(text){
38939 this.textEl.update(text);
38940 this.setTooltip(text);
38941 //if(!this.tabPanel.resizeTabs){
38942 // this.autoSize();
38946 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
38948 activate : function(){
38949 this.tabPanel.activate(this.id);
38953 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
38955 disable : function(){
38956 if(this.tabPanel.active != this){
38957 this.disabled = true;
38958 this.status_node.addClass("disabled");
38963 * Enables this TabPanelItem if it was previously disabled.
38965 enable : function(){
38966 this.disabled = false;
38967 this.status_node.removeClass("disabled");
38971 * Sets the content for this TabPanelItem.
38972 * @param {String} content The content
38973 * @param {Boolean} loadScripts true to look for and load scripts
38975 setContent : function(content, loadScripts){
38976 this.bodyEl.update(content, loadScripts);
38980 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
38981 * @return {Roo.UpdateManager} The UpdateManager
38983 getUpdateManager : function(){
38984 return this.bodyEl.getUpdateManager();
38988 * Set a URL to be used to load the content for this TabPanelItem.
38989 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
38990 * @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)
38991 * @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)
38992 * @return {Roo.UpdateManager} The UpdateManager
38994 setUrl : function(url, params, loadOnce){
38995 if(this.refreshDelegate){
38996 this.un('activate', this.refreshDelegate);
38998 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
38999 this.on("activate", this.refreshDelegate);
39000 return this.bodyEl.getUpdateManager();
39004 _handleRefresh : function(url, params, loadOnce){
39005 if(!loadOnce || !this.loaded){
39006 var updater = this.bodyEl.getUpdateManager();
39007 updater.update(url, params, this._setLoaded.createDelegate(this));
39012 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
39013 * Will fail silently if the setUrl method has not been called.
39014 * This does not activate the panel, just updates its content.
39016 refresh : function(){
39017 if(this.refreshDelegate){
39018 this.loaded = false;
39019 this.refreshDelegate();
39024 _setLoaded : function(){
39025 this.loaded = true;
39029 closeClick : function(e){
39032 this.fireEvent("beforeclose", this, o);
39033 if(o.cancel !== true){
39034 this.tabPanel.removeTab(this.id);
39038 * The text displayed in the tooltip for the close icon.
39041 closeText : "Close this tab"
39044 * This script refer to:
39045 * Title: International Telephone Input
39046 * Author: Jack O'Connor
39047 * Code version: v12.1.12
39048 * Availability: https://github.com/jackocnr/intl-tel-input.git
39051 Roo.bootstrap.PhoneInputData = function() {
39054 "Afghanistan (افغانستان)",
39059 "Albania (Shqipëri)",
39064 "Algeria (الجزائر)",
39089 "Antigua and Barbuda",
39099 "Armenia (Հայաստան)",
39115 "Austria (Österreich)",
39120 "Azerbaijan (Azərbaycan)",
39130 "Bahrain (البحرين)",
39135 "Bangladesh (বাংলাদেশ)",
39145 "Belarus (Беларусь)",
39150 "Belgium (België)",
39180 "Bosnia and Herzegovina (Босна и Херцеговина)",
39195 "British Indian Ocean Territory",
39200 "British Virgin Islands",
39210 "Bulgaria (България)",
39220 "Burundi (Uburundi)",
39225 "Cambodia (កម្ពុជា)",
39230 "Cameroon (Cameroun)",
39239 ["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"]
39242 "Cape Verde (Kabu Verdi)",
39247 "Caribbean Netherlands",
39258 "Central African Republic (République centrafricaine)",
39278 "Christmas Island",
39284 "Cocos (Keeling) Islands",
39295 "Comoros (جزر القمر)",
39300 "Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)",
39305 "Congo (Republic) (Congo-Brazzaville)",
39325 "Croatia (Hrvatska)",
39346 "Czech Republic (Česká republika)",
39351 "Denmark (Danmark)",
39366 "Dominican Republic (República Dominicana)",
39370 ["809", "829", "849"]
39388 "Equatorial Guinea (Guinea Ecuatorial)",
39408 "Falkland Islands (Islas Malvinas)",
39413 "Faroe Islands (Føroyar)",
39434 "French Guiana (Guyane française)",
39439 "French Polynesia (Polynésie française)",
39454 "Georgia (საქართველო)",
39459 "Germany (Deutschland)",
39479 "Greenland (Kalaallit Nunaat)",
39516 "Guinea-Bissau (Guiné Bissau)",
39541 "Hungary (Magyarország)",
39546 "Iceland (Ísland)",
39566 "Iraq (العراق)",
39582 "Israel (ישראל)",
39609 "Jordan (الأردن)",
39614 "Kazakhstan (Казахстан)",
39635 "Kuwait (الكويت)",
39640 "Kyrgyzstan (Кыргызстан)",
39650 "Latvia (Latvija)",
39655 "Lebanon (لبنان)",
39670 "Libya (ليبيا)",
39680 "Lithuania (Lietuva)",
39695 "Macedonia (FYROM) (Македонија)",
39700 "Madagascar (Madagasikara)",
39730 "Marshall Islands",
39740 "Mauritania (موريتانيا)",
39745 "Mauritius (Moris)",
39766 "Moldova (Republica Moldova)",
39776 "Mongolia (Монгол)",
39781 "Montenegro (Crna Gora)",
39791 "Morocco (المغرب)",
39797 "Mozambique (Moçambique)",
39802 "Myanmar (Burma) (မြန်မာ)",
39807 "Namibia (Namibië)",
39822 "Netherlands (Nederland)",
39827 "New Caledonia (Nouvelle-Calédonie)",
39862 "North Korea (조선 민주주의 인민 공화국)",
39867 "Northern Mariana Islands",
39883 "Pakistan (پاکستان)",
39893 "Palestine (فلسطين)",
39903 "Papua New Guinea",
39945 "Réunion (La Réunion)",
39951 "Romania (România)",
39967 "Saint Barthélemy",
39978 "Saint Kitts and Nevis",
39988 "Saint Martin (Saint-Martin (partie française))",
39994 "Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)",
39999 "Saint Vincent and the Grenadines",
40014 "São Tomé and Príncipe (São Tomé e Príncipe)",
40019 "Saudi Arabia (المملكة العربية السعودية)",
40024 "Senegal (Sénégal)",
40054 "Slovakia (Slovensko)",
40059 "Slovenia (Slovenija)",
40069 "Somalia (Soomaaliya)",
40079 "South Korea (대한민국)",
40084 "South Sudan (جنوب السودان)",
40094 "Sri Lanka (ශ්රී ලංකාව)",
40099 "Sudan (السودان)",
40109 "Svalbard and Jan Mayen",
40120 "Sweden (Sverige)",
40125 "Switzerland (Schweiz)",
40130 "Syria (سوريا)",
40175 "Trinidad and Tobago",
40180 "Tunisia (تونس)",
40185 "Turkey (Türkiye)",
40195 "Turks and Caicos Islands",
40205 "U.S. Virgin Islands",
40215 "Ukraine (Україна)",
40220 "United Arab Emirates (الإمارات العربية المتحدة)",
40242 "Uzbekistan (Oʻzbekiston)",
40252 "Vatican City (Città del Vaticano)",
40263 "Vietnam (Việt Nam)",
40268 "Wallis and Futuna (Wallis-et-Futuna)",
40273 "Western Sahara (الصحراء الغربية)",
40279 "Yemen (اليمن)",
40303 * This script refer to:
40304 * Title: International Telephone Input
40305 * Author: Jack O'Connor
40306 * Code version: v12.1.12
40307 * Availability: https://github.com/jackocnr/intl-tel-input.git
40311 * @class Roo.bootstrap.PhoneInput
40312 * @extends Roo.bootstrap.TriggerField
40313 * An input with International dial-code selection
40315 * @cfg {String} defaultDialCode default '+852'
40316 * @cfg {Array} preferedCountries default []
40319 * Create a new PhoneInput.
40320 * @param {Object} config Configuration options
40323 Roo.bootstrap.PhoneInput = function(config) {
40324 Roo.bootstrap.PhoneInput.superclass.constructor.call(this, config);
40327 Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
40329 listWidth: undefined,
40331 selectedClass: 'active',
40333 invalidClass : "has-warning",
40335 validClass: 'has-success',
40337 allowed: '0123456789',
40342 * @cfg {String} defaultDialCode The default dial code when initializing the input
40344 defaultDialCode: '+852',
40347 * @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
40349 preferedCountries: false,
40351 getAutoCreate : function()
40353 var data = Roo.bootstrap.PhoneInputData();
40354 var align = this.labelAlign || this.parentLabelAlign();
40357 this.allCountries = [];
40358 this.dialCodeMapping = [];
40360 for (var i = 0; i < data.length; i++) {
40362 this.allCountries[i] = {
40366 priority: c[3] || 0,
40367 areaCodes: c[4] || null
40369 this.dialCodeMapping[c[2]] = {
40372 priority: c[3] || 0,
40373 areaCodes: c[4] || null
40385 // type: 'number', -- do not use number - we get the flaky up/down arrows.
40386 maxlength: this.max_length,
40387 cls : 'form-control tel-input',
40388 autocomplete: 'new-password'
40391 var hiddenInput = {
40394 cls: 'hidden-tel-input'
40398 hiddenInput.name = this.name;
40401 if (this.disabled) {
40402 input.disabled = true;
40405 var flag_container = {
40422 cls: this.hasFeedback ? 'has-feedback' : '',
40428 cls: 'dial-code-holder',
40435 cls: 'roo-select2-container input-group',
40442 if (this.fieldLabel.length) {
40445 tooltip: 'This field is required'
40451 cls: 'control-label',
40457 html: this.fieldLabel
40460 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40466 if(this.indicatorpos == 'right') {
40467 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40474 if(align == 'left') {
40482 if(this.labelWidth > 12){
40483 label.style = "width: " + this.labelWidth + 'px';
40485 if(this.labelWidth < 13 && this.labelmd == 0){
40486 this.labelmd = this.labelWidth;
40488 if(this.labellg > 0){
40489 label.cls += ' col-lg-' + this.labellg;
40490 input.cls += ' col-lg-' + (12 - this.labellg);
40492 if(this.labelmd > 0){
40493 label.cls += ' col-md-' + this.labelmd;
40494 container.cls += ' col-md-' + (12 - this.labelmd);
40496 if(this.labelsm > 0){
40497 label.cls += ' col-sm-' + this.labelsm;
40498 container.cls += ' col-sm-' + (12 - this.labelsm);
40500 if(this.labelxs > 0){
40501 label.cls += ' col-xs-' + this.labelxs;
40502 container.cls += ' col-xs-' + (12 - this.labelxs);
40512 var settings = this;
40514 ['xs','sm','md','lg'].map(function(size){
40515 if (settings[size]) {
40516 cfg.cls += ' col-' + size + '-' + settings[size];
40520 this.store = new Roo.data.Store({
40521 proxy : new Roo.data.MemoryProxy({}),
40522 reader : new Roo.data.JsonReader({
40533 'name' : 'dialCode',
40537 'name' : 'priority',
40541 'name' : 'areaCodes',
40548 if(!this.preferedCountries) {
40549 this.preferedCountries = [
40556 var p = this.preferedCountries.reverse();
40559 for (var i = 0; i < p.length; i++) {
40560 for (var j = 0; j < this.allCountries.length; j++) {
40561 if(this.allCountries[j].iso2 == p[i]) {
40562 var t = this.allCountries[j];
40563 this.allCountries.splice(j,1);
40564 this.allCountries.unshift(t);
40570 this.store.proxy.data = {
40572 data: this.allCountries
40578 initEvents : function()
40581 Roo.bootstrap.PhoneInput.superclass.initEvents.call(this);
40583 this.indicator = this.indicatorEl();
40584 this.flag = this.flagEl();
40585 this.dialCodeHolder = this.dialCodeHolderEl();
40587 this.trigger = this.el.select('div.flag-box',true).first();
40588 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
40593 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40594 _this.list.setWidth(lw);
40597 this.list.on('mouseover', this.onViewOver, this);
40598 this.list.on('mousemove', this.onViewMove, this);
40599 this.inputEl().on("keyup", this.onKeyUp, this);
40600 this.inputEl().on("keypress", this.onKeyPress, this);
40602 this.tpl = '<li><a href="#"><div class="flag {iso2}"></div>{name} <span class="dial-code">+{dialCode}</span></a></li>';
40604 this.view = new Roo.View(this.list, this.tpl, {
40605 singleSelect:true, store: this.store, selectedClass: this.selectedClass
40608 this.view.on('click', this.onViewClick, this);
40609 this.setValue(this.defaultDialCode);
40612 onTriggerClick : function(e)
40614 Roo.log('trigger click');
40619 if(this.isExpanded()){
40621 this.hasFocus = false;
40623 this.store.load({});
40624 this.hasFocus = true;
40629 isExpanded : function()
40631 return this.list.isVisible();
40634 collapse : function()
40636 if(!this.isExpanded()){
40640 Roo.get(document).un('mousedown', this.collapseIf, this);
40641 Roo.get(document).un('mousewheel', this.collapseIf, this);
40642 this.fireEvent('collapse', this);
40646 expand : function()
40650 if(this.isExpanded() || !this.hasFocus){
40654 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
40655 this.list.setWidth(lw);
40658 this.restrictHeight();
40660 Roo.get(document).on('mousedown', this.collapseIf, this);
40661 Roo.get(document).on('mousewheel', this.collapseIf, this);
40663 this.fireEvent('expand', this);
40666 restrictHeight : function()
40668 this.list.alignTo(this.inputEl(), this.listAlign);
40669 this.list.alignTo(this.inputEl(), this.listAlign);
40672 onViewOver : function(e, t)
40674 if(this.inKeyMode){
40677 var item = this.view.findItemFromChild(t);
40680 var index = this.view.indexOf(item);
40681 this.select(index, false);
40686 onViewClick : function(view, doFocus, el, e)
40688 var index = this.view.getSelectedIndexes()[0];
40690 var r = this.store.getAt(index);
40693 this.onSelect(r, index);
40695 if(doFocus !== false && !this.blockFocus){
40696 this.inputEl().focus();
40700 onViewMove : function(e, t)
40702 this.inKeyMode = false;
40705 select : function(index, scrollIntoView)
40707 this.selectedIndex = index;
40708 this.view.select(index);
40709 if(scrollIntoView !== false){
40710 var el = this.view.getNode(index);
40712 this.list.scrollChildIntoView(el, false);
40717 createList : function()
40719 this.list = Roo.get(document.body).createChild({
40721 cls: 'typeahead typeahead-long dropdown-menu tel-list',
40722 style: 'display:none'
40725 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
40728 collapseIf : function(e)
40730 var in_combo = e.within(this.el);
40731 var in_list = e.within(this.list);
40732 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
40734 if (in_combo || in_list || is_list) {
40740 onSelect : function(record, index)
40742 if(this.fireEvent('beforeselect', this, record, index) !== false){
40744 this.setFlagClass(record.data.iso2);
40745 this.setDialCode(record.data.dialCode);
40746 this.hasFocus = false;
40748 this.fireEvent('select', this, record, index);
40752 flagEl : function()
40754 var flag = this.el.select('div.flag',true).first();
40761 dialCodeHolderEl : function()
40763 var d = this.el.select('input.dial-code-holder',true).first();
40770 setDialCode : function(v)
40772 this.dialCodeHolder.dom.value = '+'+v;
40775 setFlagClass : function(n)
40777 this.flag.dom.className = 'flag '+n;
40780 getValue : function()
40782 var v = this.inputEl().getValue();
40783 if(this.dialCodeHolder) {
40784 v = this.dialCodeHolder.dom.value+this.inputEl().getValue();
40789 setValue : function(v)
40791 var d = this.getDialCode(v);
40793 //invalid dial code
40794 if(v.length == 0 || !d || d.length == 0) {
40796 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
40797 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
40803 this.setFlagClass(this.dialCodeMapping[d].iso2);
40804 this.setDialCode(d);
40805 this.inputEl().dom.value = v.replace('+'+d,'');
40806 this.hiddenEl().dom.value = this.getValue();
40811 getDialCode : function(v)
40815 if (v.length == 0) {
40816 return this.dialCodeHolder.dom.value;
40820 if (v.charAt(0) != "+") {
40823 var numericChars = "";
40824 for (var i = 1; i < v.length; i++) {
40825 var c = v.charAt(i);
40828 if (this.dialCodeMapping[numericChars]) {
40829 dialCode = v.substr(1, i);
40831 if (numericChars.length == 4) {
40841 this.setValue(this.defaultDialCode);
40845 hiddenEl : function()
40847 return this.el.select('input.hidden-tel-input',true).first();
40850 // after setting val
40851 onKeyUp : function(e){
40852 this.setValue(this.getValue());
40855 onKeyPress : function(e){
40856 if(this.allowed.indexOf(String.fromCharCode(e.getCharCode())) === -1){
40863 * @class Roo.bootstrap.MoneyField
40864 * @extends Roo.bootstrap.ComboBox
40865 * Bootstrap MoneyField class
40868 * Create a new MoneyField.
40869 * @param {Object} config Configuration options
40872 Roo.bootstrap.MoneyField = function(config) {
40874 Roo.bootstrap.MoneyField.superclass.constructor.call(this, config);
40878 Roo.extend(Roo.bootstrap.MoneyField, Roo.bootstrap.ComboBox, {
40881 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
40883 allowDecimals : true,
40885 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
40887 decimalSeparator : ".",
40889 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
40891 decimalPrecision : 0,
40893 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
40895 allowNegative : true,
40897 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
40901 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
40903 minValue : Number.NEGATIVE_INFINITY,
40905 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
40907 maxValue : Number.MAX_VALUE,
40909 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
40911 minText : "The minimum value for this field is {0}",
40913 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
40915 maxText : "The maximum value for this field is {0}",
40917 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
40918 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
40920 nanText : "{0} is not a valid number",
40922 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
40926 * @cfg {String} defaults currency of the MoneyField
40927 * value should be in lkey
40929 defaultCurrency : false,
40931 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
40933 thousandsDelimiter : false,
40935 * @cfg {Number} max_length Maximum input field length allowed (defaults to Number.MAX_VALUE)
40946 getAutoCreate : function()
40948 var align = this.labelAlign || this.parentLabelAlign();
40960 cls : 'form-control roo-money-amount-input',
40961 autocomplete: 'new-password'
40964 var hiddenInput = {
40968 cls: 'hidden-number-input'
40971 if(this.max_length) {
40972 input.maxlength = this.max_length;
40976 hiddenInput.name = this.name;
40979 if (this.disabled) {
40980 input.disabled = true;
40983 var clg = 12 - this.inputlg;
40984 var cmd = 12 - this.inputmd;
40985 var csm = 12 - this.inputsm;
40986 var cxs = 12 - this.inputxs;
40990 cls : 'row roo-money-field',
40994 cls : 'roo-money-currency column col-lg-' + clg + ' col-md-' + cmd + ' col-sm-' + csm + ' col-xs-' + cxs,
40998 cls: 'roo-select2-container input-group',
41002 cls : 'form-control roo-money-currency-input',
41003 autocomplete: 'new-password',
41005 name : this.currencyName
41009 cls : 'input-group-addon',
41023 cls : 'roo-money-amount column col-lg-' + this.inputlg + ' col-md-' + this.inputmd + ' col-sm-' + this.inputsm + ' col-xs-' + this.inputxs,
41027 cls: this.hasFeedback ? 'has-feedback' : '',
41038 if (this.fieldLabel.length) {
41041 tooltip: 'This field is required'
41047 cls: 'control-label',
41053 html: this.fieldLabel
41056 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
41062 if(this.indicatorpos == 'right') {
41063 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
41070 if(align == 'left') {
41078 if(this.labelWidth > 12){
41079 label.style = "width: " + this.labelWidth + 'px';
41081 if(this.labelWidth < 13 && this.labelmd == 0){
41082 this.labelmd = this.labelWidth;
41084 if(this.labellg > 0){
41085 label.cls += ' col-lg-' + this.labellg;
41086 input.cls += ' col-lg-' + (12 - this.labellg);
41088 if(this.labelmd > 0){
41089 label.cls += ' col-md-' + this.labelmd;
41090 container.cls += ' col-md-' + (12 - this.labelmd);
41092 if(this.labelsm > 0){
41093 label.cls += ' col-sm-' + this.labelsm;
41094 container.cls += ' col-sm-' + (12 - this.labelsm);
41096 if(this.labelxs > 0){
41097 label.cls += ' col-xs-' + this.labelxs;
41098 container.cls += ' col-xs-' + (12 - this.labelxs);
41109 var settings = this;
41111 ['xs','sm','md','lg'].map(function(size){
41112 if (settings[size]) {
41113 cfg.cls += ' col-' + size + '-' + settings[size];
41120 initEvents : function()
41122 this.indicator = this.indicatorEl();
41124 this.initCurrencyEvent();
41126 this.initNumberEvent();
41129 initCurrencyEvent : function()
41132 throw "can not find store for combo";
41135 this.store = Roo.factory(this.store, Roo.data);
41136 this.store.parent = this;
41140 this.triggerEl = this.el.select('.input-group-addon', true).first();
41142 this.triggerEl.on("click", this.onTriggerClick, this, { preventDefault : true });
41147 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
41148 _this.list.setWidth(lw);
41151 this.list.on('mouseover', this.onViewOver, this);
41152 this.list.on('mousemove', this.onViewMove, this);
41153 this.list.on('scroll', this.onViewScroll, this);
41156 this.tpl = '<li><a href="#">{' + this.currencyField + '}</a></li>';
41159 this.view = new Roo.View(this.list, this.tpl, {
41160 singleSelect:true, store: this.store, selectedClass: this.selectedClass
41163 this.view.on('click', this.onViewClick, this);
41165 this.store.on('beforeload', this.onBeforeLoad, this);
41166 this.store.on('load', this.onLoad, this);
41167 this.store.on('loadexception', this.onLoadException, this);
41169 this.keyNav = new Roo.KeyNav(this.currencyEl(), {
41170 "up" : function(e){
41171 this.inKeyMode = true;
41175 "down" : function(e){
41176 if(!this.isExpanded()){
41177 this.onTriggerClick();
41179 this.inKeyMode = true;
41184 "enter" : function(e){
41187 if(this.fireEvent("specialkey", this, e)){
41188 this.onViewClick(false);
41194 "esc" : function(e){
41198 "tab" : function(e){
41201 if(this.fireEvent("specialkey", this, e)){
41202 this.onViewClick(false);
41210 doRelay : function(foo, bar, hname){
41211 if(hname == 'down' || this.scope.isExpanded()){
41212 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
41220 this.currencyEl().on("click", this.onTriggerClick, this, { preventDefault : true });
41224 initNumberEvent : function(e)
41226 this.inputEl().on("keydown" , this.fireKey, this);
41227 this.inputEl().on("focus", this.onFocus, this);
41228 this.inputEl().on("blur", this.onBlur, this);
41230 this.inputEl().relayEvent('keyup', this);
41232 if(this.indicator){
41233 this.indicator.addClass('invisible');
41236 this.originalValue = this.getValue();
41238 if(this.validationEvent == 'keyup'){
41239 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
41240 this.inputEl().on('keyup', this.filterValidation, this);
41242 else if(this.validationEvent !== false){
41243 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
41246 if(this.selectOnFocus){
41247 this.on("focus", this.preFocus, this);
41250 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
41251 this.inputEl().on("keypress", this.filterKeys, this);
41253 this.inputEl().relayEvent('keypress', this);
41256 var allowed = "0123456789";
41258 if(this.allowDecimals){
41259 allowed += this.decimalSeparator;
41262 if(this.allowNegative){
41266 if(this.thousandsDelimiter) {
41270 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
41272 var keyPress = function(e){
41274 var k = e.getKey();
41276 var c = e.getCharCode();
41279 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
41280 allowed.indexOf(String.fromCharCode(c)) === -1
41286 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
41290 if(allowed.indexOf(String.fromCharCode(c)) === -1){
41295 this.inputEl().on("keypress", keyPress, this);
41299 onTriggerClick : function(e)
41306 this.loadNext = false;
41308 if(this.isExpanded()){
41313 this.hasFocus = true;
41315 if(this.triggerAction == 'all') {
41316 this.doQuery(this.allQuery, true);
41320 this.doQuery(this.getRawValue());
41323 getCurrency : function()
41325 var v = this.currencyEl().getValue();
41330 restrictHeight : function()
41332 this.list.alignTo(this.currencyEl(), this.listAlign);
41333 this.list.alignTo(this.currencyEl(), this.listAlign);
41336 onViewClick : function(view, doFocus, el, e)
41338 var index = this.view.getSelectedIndexes()[0];
41340 var r = this.store.getAt(index);
41343 this.onSelect(r, index);
41347 onSelect : function(record, index){
41349 if(this.fireEvent('beforeselect', this, record, index) !== false){
41351 this.setFromCurrencyData(index > -1 ? record.data : false);
41355 this.fireEvent('select', this, record, index);
41359 setFromCurrencyData : function(o)
41363 this.lastCurrency = o;
41365 if (this.currencyField) {
41366 currency = !o || typeof(o[this.currencyField]) == 'undefined' ? '' : o[this.currencyField];
41368 Roo.log('no currencyField value set for '+ (this.name ? this.name : this.id));
41371 this.lastSelectionText = currency;
41373 //setting default currency
41374 if(o[this.currencyField] * 1 == 0 && this.defaultCurrency) {
41375 this.setCurrency(this.defaultCurrency);
41379 this.setCurrency(currency);
41382 setFromData : function(o)
41386 c[this.currencyField] = !o || typeof(o[this.currencyName]) == 'undefined' ? '' : o[this.currencyName];
41388 this.setFromCurrencyData(c);
41393 value = !o || typeof(o[this.name]) == 'undefined' ? '' : o[this.name];
41395 Roo.log('no value set for '+ (this.name ? this.name : this.id));
41398 this.setValue(value);
41402 setCurrency : function(v)
41404 this.currencyValue = v;
41407 this.currencyEl().dom.value = (v === null || v === undefined ? '' : v);
41412 setValue : function(v)
41414 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
41420 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
41422 this.inputEl().dom.value = (v == '') ? '' :
41423 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
41425 if(!this.allowZero && v === '0') {
41426 this.hiddenEl().dom.value = '';
41427 this.inputEl().dom.value = '';
41434 getRawValue : function()
41436 var v = this.inputEl().getValue();
41441 getValue : function()
41443 return this.fixPrecision(this.parseValue(this.getRawValue()));
41446 parseValue : function(value)
41448 if(this.thousandsDelimiter) {
41450 r = new RegExp(",", "g");
41451 value = value.replace(r, "");
41454 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
41455 return isNaN(value) ? '' : value;
41459 fixPrecision : function(value)
41461 if(this.thousandsDelimiter) {
41463 r = new RegExp(",", "g");
41464 value = value.replace(r, "");
41467 var nan = isNaN(value);
41469 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
41470 return nan ? '' : value;
41472 return parseFloat(value).toFixed(this.decimalPrecision);
41475 decimalPrecisionFcn : function(v)
41477 return Math.floor(v);
41480 validateValue : function(value)
41482 if(!Roo.bootstrap.MoneyField.superclass.validateValue.call(this, value)){
41486 var num = this.parseValue(value);
41489 this.markInvalid(String.format(this.nanText, value));
41493 if(num < this.minValue){
41494 this.markInvalid(String.format(this.minText, this.minValue));
41498 if(num > this.maxValue){
41499 this.markInvalid(String.format(this.maxText, this.maxValue));
41506 validate : function()
41508 if(this.disabled || this.allowBlank){
41513 var currency = this.getCurrency();
41515 if(this.validateValue(this.getRawValue()) && currency.length){
41520 this.markInvalid();
41524 getName: function()
41529 beforeBlur : function()
41535 var v = this.parseValue(this.getRawValue());
41542 onBlur : function()
41546 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
41547 //this.el.removeClass(this.focusClass);
41550 this.hasFocus = false;
41552 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
41556 var v = this.getValue();
41558 if(String(v) !== String(this.startValue)){
41559 this.fireEvent('change', this, v, this.startValue);
41562 this.fireEvent("blur", this);
41565 inputEl : function()
41567 return this.el.select('.roo-money-amount-input', true).first();
41570 currencyEl : function()
41572 return this.el.select('.roo-money-currency-input', true).first();
41575 hiddenEl : function()
41577 return this.el.select('input.hidden-number-input',true).first();
41581 * @class Roo.bootstrap.BezierSignature
41582 * @extends Roo.bootstrap.Component
41583 * Bootstrap BezierSignature class
41584 * This script refer to:
41585 * Title: Signature Pad
41587 * Availability: https://github.com/szimek/signature_pad
41590 * Create a new BezierSignature
41591 * @param {Object} config The config object
41594 Roo.bootstrap.BezierSignature = function(config){
41595 Roo.bootstrap.BezierSignature.superclass.constructor.call(this, config);
41601 Roo.extend(Roo.bootstrap.BezierSignature, Roo.bootstrap.Component,
41608 mouse_btn_down: true,
41611 * @cfg {int} canvas height
41613 canvas_height: '200px',
41616 * @cfg {float|function} Radius of a single dot.
41621 * @cfg {float} Minimum width of a line. Defaults to 0.5.
41626 * @cfg {float} Maximum width of a line. Defaults to 2.5.
41631 * @cfg {integer} Draw the next point at most once per every x milliseconds. Set it to 0 to turn off throttling. Defaults to 16.
41636 * @cfg {integer} Add the next point only if the previous one is farther than x pixels. Defaults to 5.
41641 * @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.
41643 bg_color: 'rgba(0, 0, 0, 0)',
41646 * @cfg {string} Color used to draw the lines. Can be any color format accepted by context.fillStyle. Defaults to "black".
41648 dot_color: 'black',
41651 * @cfg {float} Weight used to modify new velocity based on the previous velocity. Defaults to 0.7.
41653 velocity_filter_weight: 0.7,
41656 * @cfg {function} Callback when stroke begin.
41661 * @cfg {function} Callback when stroke end.
41665 getAutoCreate : function()
41667 var cls = 'roo-signature column';
41670 cls += ' ' + this.cls;
41680 for(var i = 0; i < col_sizes.length; i++) {
41681 if(this[col_sizes[i]]) {
41682 cls += " col-"+col_sizes[i]+"-"+this[col_sizes[i]];
41692 cls: 'roo-signature-body',
41696 cls: 'roo-signature-body-canvas',
41697 height: this.canvas_height,
41698 width: this.canvas_width
41705 style: 'display: none'
41713 initEvents: function()
41715 Roo.bootstrap.BezierSignature.superclass.initEvents.call(this);
41717 var canvas = this.canvasEl();
41719 // mouse && touch event swapping...
41720 canvas.dom.style.touchAction = 'none';
41721 canvas.dom.style.msTouchAction = 'none';
41723 this.mouse_btn_down = false;
41724 canvas.on('mousedown', this._handleMouseDown, this);
41725 canvas.on('mousemove', this._handleMouseMove, this);
41726 Roo.select('html').first().on('mouseup', this._handleMouseUp, this);
41728 if (window.PointerEvent) {
41729 canvas.on('pointerdown', this._handleMouseDown, this);
41730 canvas.on('pointermove', this._handleMouseMove, this);
41731 Roo.select('html').first().on('pointerup', this._handleMouseUp, this);
41734 if ('ontouchstart' in window) {
41735 canvas.on('touchstart', this._handleTouchStart, this);
41736 canvas.on('touchmove', this._handleTouchMove, this);
41737 canvas.on('touchend', this._handleTouchEnd, this);
41740 Roo.EventManager.onWindowResize(this.resize, this, true);
41742 // file input event
41743 this.fileEl().on('change', this.uploadImage, this);
41750 resize: function(){
41752 var canvas = this.canvasEl().dom;
41753 var ctx = this.canvasElCtx();
41754 var img_data = false;
41756 if(canvas.width > 0) {
41757 var img_data = ctx.getImageData(0, 0, canvas.width, canvas.height);
41759 // setting canvas width will clean img data
41762 var style = window.getComputedStyle ?
41763 getComputedStyle(this.el.dom, null) : this.el.dom.currentStyle;
41765 var padding_left = parseInt(style.paddingLeft) || 0;
41766 var padding_right = parseInt(style.paddingRight) || 0;
41768 canvas.width = this.el.dom.clientWidth - padding_left - padding_right;
41771 ctx.putImageData(img_data, 0, 0);
41775 _handleMouseDown: function(e)
41777 if (e.browserEvent.which === 1) {
41778 this.mouse_btn_down = true;
41779 this.strokeBegin(e);
41783 _handleMouseMove: function (e)
41785 if (this.mouse_btn_down) {
41786 this.strokeMoveUpdate(e);
41790 _handleMouseUp: function (e)
41792 if (e.browserEvent.which === 1 && this.mouse_btn_down) {
41793 this.mouse_btn_down = false;
41798 _handleTouchStart: function (e) {
41800 e.preventDefault();
41801 if (e.browserEvent.targetTouches.length === 1) {
41802 // var touch = e.browserEvent.changedTouches[0];
41803 // this.strokeBegin(touch);
41805 this.strokeBegin(e); // assume e catching the correct xy...
41809 _handleTouchMove: function (e) {
41810 e.preventDefault();
41811 // var touch = event.targetTouches[0];
41812 // _this._strokeMoveUpdate(touch);
41813 this.strokeMoveUpdate(e);
41816 _handleTouchEnd: function (e) {
41817 var wasCanvasTouched = e.target === this.canvasEl().dom;
41818 if (wasCanvasTouched) {
41819 e.preventDefault();
41820 // var touch = event.changedTouches[0];
41821 // _this._strokeEnd(touch);
41826 reset: function () {
41827 this._lastPoints = [];
41828 this._lastVelocity = 0;
41829 this._lastWidth = (this.min_width + this.max_width) / 2;
41830 this.canvasElCtx().fillStyle = this.dot_color;
41833 strokeMoveUpdate: function(e)
41835 this.strokeUpdate(e);
41837 if (this.throttle) {
41838 this.throttleStroke(this.strokeUpdate, this.throttle);
41841 this.strokeUpdate(e);
41845 strokeBegin: function(e)
41847 var newPointGroup = {
41848 color: this.dot_color,
41852 if (typeof this.onBegin === 'function') {
41856 this.curve_data.push(newPointGroup);
41858 this.strokeUpdate(e);
41861 strokeUpdate: function(e)
41863 var rect = this.canvasEl().dom.getBoundingClientRect();
41864 var point = new this.Point(e.xy[0] - rect.left, e.xy[1] - rect.top, new Date().getTime());
41865 var lastPointGroup = this.curve_data[this.curve_data.length - 1];
41866 var lastPoints = lastPointGroup.points;
41867 var lastPoint = lastPoints.length > 0 && lastPoints[lastPoints.length - 1];
41868 var isLastPointTooClose = lastPoint
41869 ? point.distanceTo(lastPoint) <= this.min_distance
41871 var color = lastPointGroup.color;
41872 if (!lastPoint || !(lastPoint && isLastPointTooClose)) {
41873 var curve = this.addPoint(point);
41875 this.drawDot({color: color, point: point});
41878 this.drawCurve({color: color, curve: curve});
41888 strokeEnd: function(e)
41890 this.strokeUpdate(e);
41891 if (typeof this.onEnd === 'function') {
41896 addPoint: function (point) {
41897 var _lastPoints = this._lastPoints;
41898 _lastPoints.push(point);
41899 if (_lastPoints.length > 2) {
41900 if (_lastPoints.length === 3) {
41901 _lastPoints.unshift(_lastPoints[0]);
41903 var widths = this.calculateCurveWidths(_lastPoints[1], _lastPoints[2]);
41904 var curve = this.Bezier.fromPoints(_lastPoints, widths, this);
41905 _lastPoints.shift();
41911 calculateCurveWidths: function (startPoint, endPoint) {
41912 var velocity = this.velocity_filter_weight * endPoint.velocityFrom(startPoint) +
41913 (1 - this.velocity_filter_weight) * this._lastVelocity;
41915 var newWidth = Math.max(this.max_width / (velocity + 1), this.min_width);
41918 start: this._lastWidth
41921 this._lastVelocity = velocity;
41922 this._lastWidth = newWidth;
41926 drawDot: function (_a) {
41927 var color = _a.color, point = _a.point;
41928 var ctx = this.canvasElCtx();
41929 var width = typeof this.dot_size === 'function' ? this.dot_size() : this.dot_size;
41931 this.drawCurveSegment(point.x, point.y, width);
41933 ctx.fillStyle = color;
41937 drawCurve: function (_a) {
41938 var color = _a.color, curve = _a.curve;
41939 var ctx = this.canvasElCtx();
41940 var widthDelta = curve.endWidth - curve.startWidth;
41941 var drawSteps = Math.floor(curve.length()) * 2;
41943 ctx.fillStyle = color;
41944 for (var i = 0; i < drawSteps; i += 1) {
41945 var t = i / drawSteps;
41951 var x = uuu * curve.startPoint.x;
41952 x += 3 * uu * t * curve.control1.x;
41953 x += 3 * u * tt * curve.control2.x;
41954 x += ttt * curve.endPoint.x;
41955 var y = uuu * curve.startPoint.y;
41956 y += 3 * uu * t * curve.control1.y;
41957 y += 3 * u * tt * curve.control2.y;
41958 y += ttt * curve.endPoint.y;
41959 var width = curve.startWidth + ttt * widthDelta;
41960 this.drawCurveSegment(x, y, width);
41966 drawCurveSegment: function (x, y, width) {
41967 var ctx = this.canvasElCtx();
41969 ctx.arc(x, y, width, 0, 2 * Math.PI, false);
41970 this.is_empty = false;
41975 var ctx = this.canvasElCtx();
41976 var canvas = this.canvasEl().dom;
41977 ctx.fillStyle = this.bg_color;
41978 ctx.clearRect(0, 0, canvas.width, canvas.height);
41979 ctx.fillRect(0, 0, canvas.width, canvas.height);
41980 this.curve_data = [];
41982 this.is_empty = true;
41987 return this.el.select('input',true).first();
41990 canvasEl: function()
41992 return this.el.select('canvas',true).first();
41995 canvasElCtx: function()
41997 return this.el.select('canvas',true).first().dom.getContext('2d');
42000 getImage: function(type)
42002 if(this.is_empty) {
42007 return this.canvasEl().dom.toDataURL('image/'+type, 1);
42010 drawFromImage: function(img_src)
42012 var img = new Image();
42014 img.onload = function(){
42015 this.canvasElCtx().drawImage(img, 0, 0);
42020 this.is_empty = false;
42023 selectImage: function()
42025 this.fileEl().dom.click();
42028 uploadImage: function(e)
42030 var reader = new FileReader();
42032 reader.onload = function(e){
42033 var img = new Image();
42034 img.onload = function(){
42036 this.canvasElCtx().drawImage(img, 0, 0);
42038 img.src = e.target.result;
42041 reader.readAsDataURL(e.target.files[0]);
42044 // Bezier Point Constructor
42045 Point: (function () {
42046 function Point(x, y, time) {
42049 this.time = time || Date.now();
42051 Point.prototype.distanceTo = function (start) {
42052 return Math.sqrt(Math.pow(this.x - start.x, 2) + Math.pow(this.y - start.y, 2));
42054 Point.prototype.equals = function (other) {
42055 return this.x === other.x && this.y === other.y && this.time === other.time;
42057 Point.prototype.velocityFrom = function (start) {
42058 return this.time !== start.time
42059 ? this.distanceTo(start) / (this.time - start.time)
42066 // Bezier Constructor
42067 Bezier: (function () {
42068 function Bezier(startPoint, control2, control1, endPoint, startWidth, endWidth) {
42069 this.startPoint = startPoint;
42070 this.control2 = control2;
42071 this.control1 = control1;
42072 this.endPoint = endPoint;
42073 this.startWidth = startWidth;
42074 this.endWidth = endWidth;
42076 Bezier.fromPoints = function (points, widths, scope) {
42077 var c2 = this.calculateControlPoints(points[0], points[1], points[2], scope).c2;
42078 var c3 = this.calculateControlPoints(points[1], points[2], points[3], scope).c1;
42079 return new Bezier(points[1], c2, c3, points[2], widths.start, widths.end);
42081 Bezier.calculateControlPoints = function (s1, s2, s3, scope) {
42082 var dx1 = s1.x - s2.x;
42083 var dy1 = s1.y - s2.y;
42084 var dx2 = s2.x - s3.x;
42085 var dy2 = s2.y - s3.y;
42086 var m1 = { x: (s1.x + s2.x) / 2.0, y: (s1.y + s2.y) / 2.0 };
42087 var m2 = { x: (s2.x + s3.x) / 2.0, y: (s2.y + s3.y) / 2.0 };
42088 var l1 = Math.sqrt(dx1 * dx1 + dy1 * dy1);
42089 var l2 = Math.sqrt(dx2 * dx2 + dy2 * dy2);
42090 var dxm = m1.x - m2.x;
42091 var dym = m1.y - m2.y;
42092 var k = l2 / (l1 + l2);
42093 var cm = { x: m2.x + dxm * k, y: m2.y + dym * k };
42094 var tx = s2.x - cm.x;
42095 var ty = s2.y - cm.y;
42097 c1: new scope.Point(m1.x + tx, m1.y + ty),
42098 c2: new scope.Point(m2.x + tx, m2.y + ty)
42101 Bezier.prototype.length = function () {
42106 for (var i = 0; i <= steps; i += 1) {
42108 var cx = this.point(t, this.startPoint.x, this.control1.x, this.control2.x, this.endPoint.x);
42109 var cy = this.point(t, this.startPoint.y, this.control1.y, this.control2.y, this.endPoint.y);
42111 var xdiff = cx - px;
42112 var ydiff = cy - py;
42113 length += Math.sqrt(xdiff * xdiff + ydiff * ydiff);
42120 Bezier.prototype.point = function (t, start, c1, c2, end) {
42121 return (start * (1.0 - t) * (1.0 - t) * (1.0 - t))
42122 + (3.0 * c1 * (1.0 - t) * (1.0 - t) * t)
42123 + (3.0 * c2 * (1.0 - t) * t * t)
42124 + (end * t * t * t);
42129 throttleStroke: function(fn, wait) {
42130 if (wait === void 0) { wait = 250; }
42132 var timeout = null;
42136 var later = function () {
42137 previous = Date.now();
42139 result = fn.apply(storedContext, storedArgs);
42141 storedContext = null;
42145 return function wrapper() {
42147 for (var _i = 0; _i < arguments.length; _i++) {
42148 args[_i] = arguments[_i];
42150 var now = Date.now();
42151 var remaining = wait - (now - previous);
42152 storedContext = this;
42154 if (remaining <= 0 || remaining > wait) {
42156 clearTimeout(timeout);
42160 result = fn.apply(storedContext, storedArgs);
42162 storedContext = null;
42166 else if (!timeout) {
42167 timeout = window.setTimeout(later, remaining);