2 * set the version of bootstrap based on the stylesheet...
6 Roo.bootstrap.version = (
9 Roo.each(document.styleSheets, function(s) {
10 if (s.href.match(/css-bootstrap4/)) {
18 * base class for bootstrap elements.
22 Roo.bootstrap = Roo.bootstrap || {};
24 * @class Roo.bootstrap.Component
25 * @extends Roo.Component
26 * Bootstrap Component base class
27 * @cfg {String} cls css class
28 * @cfg {String} style any extra css
29 * @cfg {Object} xattr extra attributes to add to 'element' (used by builder to store stuff.)
30 * @cfg {Boolean} can_build_overlaid True if element can be rebuild from a HTML page
31 * @cfg {string} dataId cutomer id
32 * @cfg {string} name Specifies name attribute
33 * @cfg {string} tooltip Text for the tooltip
34 * @cfg {string} container_method method to fetch parents container element (used by NavHeaderbar - getHeaderChildContainer)
35 * @cfg {string|object} visibilityEl (el|parent) What element to use for visibility (@see getVisibilityEl())
38 * Do not use directly - it does not do anything..
39 * @param {Object} config The config object
44 Roo.bootstrap.Component = function(config){
45 Roo.bootstrap.Component.superclass.constructor.call(this, config);
49 * @event childrenrendered
50 * Fires when the children have been rendered..
51 * @param {Roo.bootstrap.Component} this
53 "childrenrendered" : true
62 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent, {
65 allowDomMove : false, // to stop relocations in parent onRender...
75 * Initialize Events for the element
77 initEvents : function() { },
83 can_build_overlaid : true,
85 container_method : false,
92 // returns the parent component..
93 return Roo.ComponentMgr.get(this.parentId)
99 onRender : function(ct, position)
101 // Roo.log("Call onRender: " + this.xtype);
103 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
106 if (this.el.attr('xtype')) {
107 this.el.attr('xtypex', this.el.attr('xtype'));
108 this.el.dom.removeAttribute('xtype');
118 var cfg = Roo.apply({}, this.getAutoCreate());
120 cfg.id = this.id || Roo.id();
122 // fill in the extra attributes
123 if (this.xattr && typeof(this.xattr) =='object') {
124 for (var i in this.xattr) {
125 cfg[i] = this.xattr[i];
130 cfg.dataId = this.dataId;
134 cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
137 if (this.style) { // fixme needs to support more complex style data.
138 cfg.style = this.style;
142 cfg.name = this.name;
145 this.el = ct.createChild(cfg, position);
148 this.tooltipEl().attr('tooltip', this.tooltip);
151 if(this.tabIndex !== undefined){
152 this.el.dom.setAttribute('tabIndex', this.tabIndex);
159 * Fetch the element to add children to
160 * @return {Roo.Element} defaults to this.el
162 getChildContainer : function()
167 * Fetch the element to display the tooltip on.
168 * @return {Roo.Element} defaults to this.el
170 tooltipEl : function()
175 * This is really a wrapper for addxtypeChild
176 * it handles stuff relating to flexy:foreach / flexy:if
177 * = some of our projects use a flat rendering of the output, and try and overlay it with dynamic data.
178 * -- this is a bit of a nightmare... and is even more confusing to debug..
183 addxtype : function(tree,cntr)
187 cn = Roo.factory(tree);
188 //Roo.log(['addxtype', cn]);
190 cn.parentType = this.xtype; //??
191 cn.parentId = this.id;
193 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
194 if (typeof(cn.container_method) == 'string') {
195 cntr = cn.container_method;
199 var has_flexy_each = (typeof(tree['flexy:foreach']) != 'undefined');
201 var has_flexy_if = (typeof(tree['flexy:if']) != 'undefined');
203 var build_from_html = Roo.XComponent.build_from_html;
205 var is_body = (tree.xtype == 'Body') ;
207 var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
209 var self_cntr_el = Roo.get(this[cntr](false));
211 // do not try and build conditional elements
212 if ((has_flexy_each || has_flexy_if || this.can_build_overlaid == false ) && build_from_html) {
216 if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
217 if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
218 return this.addxtypeChild(tree,cntr, is_body);
221 var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
224 return this.addxtypeChild(Roo.apply({}, tree),cntr);
227 Roo.log('skipping render');
233 if (!build_from_html) {
237 // this i think handles overlaying multiple children of the same type
238 // with the sam eelement.. - which might be buggy..
240 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
246 if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
250 ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
256 * add a child to this element
257 * - turn the child.cfg into a child_instance
258 * - call child_instance.render( this { getContainerMethod()} )
259 * - loop through the children, and call addxtype.. (reall this) on newly created child.
263 addxtypeChild : function (tree, cntr, is_body)
265 Roo.debug && Roo.log('addxtypeChild:' + cntr);
267 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
270 var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
271 (typeof(tree['flexy:foreach']) != 'undefined');
275 skip_children = false;
276 // render the element if it's not BODY.
279 // if parent was disabled, then do not try and create the children..
280 if(!this[cntr](true)){
285 cn = Roo.factory(tree);
287 cn.parentType = this.xtype; //??
288 cn.parentId = this.id;
290 var build_from_html = Roo.XComponent.build_from_html;
293 // does the container contain child eleemnts with 'xtype' attributes.
294 // that match this xtype..
295 // note - when we render we create these as well..
296 // so we should check to see if body has xtype set.
297 if (build_from_html && Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
299 var self_cntr_el = Roo.get(this[cntr](false));
300 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
302 //Roo.log(Roo.XComponent.build_from_html);
303 //Roo.log("got echild:");
306 // there is a scenario where some of the child elements are flexy:if (and all of the same type)
307 // and are not displayed -this causes this to use up the wrong element when matching.
308 // at present the only work around for this is to nest flexy:if elements in another element that is always rendered.
311 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
312 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
318 //echild.dom.removeAttribute('xtype');
320 Roo.debug && Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
321 Roo.debug && Roo.log(self_cntr_el);
322 Roo.debug && Roo.log(echild);
323 Roo.debug && Roo.log(cn);
329 // if object has flexy:if - then it may or may not be rendered.
330 if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) {
331 // skip a flexy if element.
332 Roo.debug && Roo.log('skipping render');
333 Roo.debug && Roo.log(tree);
335 Roo.debug && Roo.log('skipping all children');
336 skip_children = true;
341 // actually if flexy:foreach is found, we really want to create
342 // multiple copies here...
344 //Roo.log(this[cntr]());
345 // some elements do not have render methods.. like the layouts...
347 if(this[cntr](true) === false){
352 cn.render && cn.render(this[cntr](true));
355 // then add the element..
362 if (typeof (tree.menu) != 'undefined') {
363 tree.menu.parentType = cn.xtype;
364 tree.menu.triggerEl = cn.el;
365 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
369 if (!tree.items || !tree.items.length) {
371 //Roo.log(["no children", this]);
376 var items = tree.items;
379 //Roo.log(items.length);
381 if (!skip_children) {
382 for(var i =0;i < items.length;i++) {
383 // Roo.log(['add child', items[i]]);
384 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
390 //Roo.log("fire childrenrendered");
392 cn.fireEvent('childrenrendered', this);
398 addxtypeChildren: function(child_array)
401 if (!tree.items || !tree.items.length) {
403 //Roo.log(["no children", this]);
413 * Set the element that will be used to show or hide
415 setVisibilityEl : function(el)
417 this.visibilityEl = el;
421 * Get the element that will be used to show or hide
423 getVisibilityEl : function()
425 if (typeof(this.visibilityEl) == 'object') {
426 return this.visibilityEl;
429 if (typeof(this.visibilityEl) == 'string') {
430 return this.visibilityEl == 'parent' ? this.parent().getEl() : this.getEl();
437 * Show a component - removes 'hidden' class
441 if(!this.getVisibilityEl()){
445 this.getVisibilityEl().removeClass(['hidden','d-none']);
447 this.fireEvent('show', this);
452 * Hide a component - adds 'hidden' class
456 if(!this.getVisibilityEl()){
460 this.getVisibilityEl().addClass(['hidden','d-none']);
462 this.fireEvent('hide', this);
475 * @class Roo.bootstrap.Body
476 * @extends Roo.bootstrap.Component
477 * Bootstrap Body class
481 * @param {Object} config The config object
484 Roo.bootstrap.Body = function(config){
486 config = config || {};
488 Roo.bootstrap.Body.superclass.constructor.call(this, config);
489 this.el = Roo.get(config.el ? config.el : document.body );
490 if (this.cls && this.cls.length) {
491 Roo.get(document.body).addClass(this.cls);
495 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
497 is_body : true,// just to make sure it's constructed?
502 onRender : function(ct, position)
504 /* Roo.log("Roo.bootstrap.Body - onRender");
505 if (this.cls && this.cls.length) {
506 Roo.get(document.body).addClass(this.cls);
525 * @class Roo.bootstrap.ButtonGroup
526 * @extends Roo.bootstrap.Component
527 * Bootstrap ButtonGroup class
528 * @cfg {String} size lg | sm | xs (default empty normal)
529 * @cfg {String} align vertical | justified (default none)
530 * @cfg {String} direction up | down (default down)
531 * @cfg {Boolean} toolbar false | true
532 * @cfg {Boolean} btn true | false
537 * @param {Object} config The config object
540 Roo.bootstrap.ButtonGroup = function(config){
541 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
544 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
552 getAutoCreate : function(){
558 cfg.html = this.html || cfg.html;
569 if (['vertical','justified'].indexOf(this.align)!==-1) {
570 cfg.cls = 'btn-group-' + this.align;
572 if (this.align == 'justified') {
573 console.log(this.items);
577 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
578 cfg.cls += ' btn-group-' + this.size;
581 if (this.direction == 'up') {
582 cfg.cls += ' dropup' ;
588 * Add a button to the group (similar to NavItem API.)
590 addItem : function(cfg)
592 var cn = new Roo.bootstrap.Button(cfg);
594 cn.parentId = this.id;
595 cn.onRender(this.el, null);
609 * @class Roo.bootstrap.Button
610 * @extends Roo.bootstrap.Component
611 * Bootstrap Button class
612 * @cfg {String} html The button content
613 * @cfg {String} weight (default | primary | secondary | success | info | warning | danger | link ) default
614 * @cfg {String} badge_weight (default | primary | secondary | success | info | warning | danger | link ) default (same as button)
615 * @cfg {Boolean} outline default false (except for weight=default which emulates old behaveiour with an outline)
616 * @cfg {String} size ( lg | sm | xs)
617 * @cfg {String} tag ( a | input | submit)
618 * @cfg {String} href empty or href
619 * @cfg {Boolean} disabled default false;
620 * @cfg {Boolean} isClose default false;
621 * @cfg {String} glyphicon depricated - use fa
622 * @cfg {String} fa fontawesome icon - eg. 'comment' - without the fa/fas etc..
623 * @cfg {String} badge text for badge
624 * @cfg {String} theme (default|glow)
625 * @cfg {Boolean} inverse dark themed version
626 * @cfg {Boolean} toggle is it a slidy toggle button
627 * @cfg {Boolean} pressed (true|false) default null - if the button ahs active state
628 * @cfg {String} ontext text for on slidy toggle state
629 * @cfg {String} offtext text for off slidy toggle state
630 * @cfg {Boolean} preventDefault default true (stop click event triggering the URL if it's a link.)
631 * @cfg {Boolean} removeClass remove the standard class..
632 * @cfg {String} target target for a href. (_self|_blank|_parent|_top| other)
635 * Create a new button
636 * @param {Object} config The config object
640 Roo.bootstrap.Button = function(config){
641 Roo.bootstrap.Button.superclass.constructor.call(this, config);
642 this.weightClass = ["btn-default btn-outline-secondary",
654 * When a butotn is pressed
655 * @param {Roo.bootstrap.Button} btn
656 * @param {Roo.EventObject} e
661 * After the button has been toggles
662 * @param {Roo.bootstrap.Button} btn
663 * @param {Roo.EventObject} e
664 * @param {boolean} pressed (also available as button.pressed)
670 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
691 preventDefault: true,
699 getAutoCreate : function(){
707 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
708 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
713 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
715 if (this.toggle == true) {
718 cls: 'slider-frame roo-button',
723 'data-off-text':'OFF',
724 cls: 'slider-button',
730 if (['default', 'secondary' , 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
731 cfg.cls += ' '+this.weight;
740 cfg["aria-hidden"] = true;
742 cfg.html = "×";
748 if (this.theme==='default') {
749 cfg.cls = 'btn roo-button';
751 //if (this.parentType != 'Navbar') {
752 this.weight = this.weight.length ? this.weight : 'default';
754 if (['default', 'primary', 'secondary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
756 var outline = this.outline || this.weight == 'default' ? 'outline-' : '';
757 var weight = this.weight == 'default' ? 'secondary' : this.weight;
758 cfg.cls += ' btn-' + outline + weight;
759 if (this.weight == 'default') {
761 cfg.cls += ' btn-' + this.weight;
764 } else if (this.theme==='glow') {
767 cfg.cls = 'btn-glow roo-button';
769 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
771 cfg.cls += ' ' + this.weight;
777 this.cls += ' inverse';
781 if (this.active || this.pressed === true) {
782 cfg.cls += ' active';
786 cfg.disabled = 'disabled';
790 Roo.log('changing to ul' );
792 this.glyphicon = 'caret';
793 if (Roo.bootstrap.version == 4) {
794 this.fa = 'caret-down';
799 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
801 //gsRoo.log(this.parentType);
802 if (this.parentType === 'Navbar' && !this.parent().bar) {
803 Roo.log('changing to li?');
812 href : this.href || '#'
815 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
816 cfg.cls += ' dropdown';
823 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
825 if (this.glyphicon) {
826 cfg.html = ' ' + cfg.html;
831 cls: 'glyphicon glyphicon-' + this.glyphicon
836 cfg.html = ' ' + cfg.html;
841 cls: 'fa fas fa-' + this.fa
851 // cfg.cls='btn roo-button';
855 var value = cfg.html;
860 cls: 'glyphicon glyphicon-' + this.glyphicon,
867 cls: 'fa fas fa-' + this.fa,
872 var bw = this.badge_weight.length ? this.badge_weight :
873 (this.weight.length ? this.weight : 'secondary');
874 bw = bw == 'default' ? 'secondary' : bw;
880 cls: 'badge badge-' + bw,
889 cfg.cls += ' dropdown';
890 cfg.html = typeof(cfg.html) != 'undefined' ?
891 cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
894 if (cfg.tag !== 'a' && this.href !== '') {
895 throw "Tag must be a to set href.";
896 } else if (this.href.length > 0) {
897 cfg.href = this.href;
900 if(this.removeClass){
905 cfg.target = this.target;
910 initEvents: function() {
911 // Roo.log('init events?');
912 // Roo.log(this.el.dom);
915 if (typeof (this.menu) != 'undefined') {
916 this.menu.parentType = this.xtype;
917 this.menu.triggerEl = this.el;
918 this.addxtype(Roo.apply({}, this.menu));
922 if (this.el.hasClass('roo-button')) {
923 this.el.on('click', this.onClick, this);
925 this.el.select('.roo-button').on('click', this.onClick, this);
928 if(this.removeClass){
929 this.el.on('click', this.onClick, this);
932 this.el.enableDisplayMode();
935 onClick : function(e)
941 Roo.log('button on click ');
942 if(this.preventDefault){
946 if (this.pressed === true || this.pressed === false) {
947 this.toggleActive(e);
951 this.fireEvent('click', this, e);
955 * Enables this button
959 this.disabled = false;
960 this.el.removeClass('disabled');
964 * Disable this button
968 this.disabled = true;
969 this.el.addClass('disabled');
972 * sets the active state on/off,
973 * @param {Boolean} state (optional) Force a particular state
975 setActive : function(v) {
977 this.el[v ? 'addClass' : 'removeClass']('active');
981 * toggles the current active state
983 toggleActive : function(e)
985 this.setActive(!this.pressed);
986 this.fireEvent('toggle', this, e, !this.pressed);
989 * get the current active state
990 * @return {boolean} true if it's active
992 isActive : function()
994 return this.el.hasClass('active');
997 * set the text of the first selected button
999 setText : function(str)
1001 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
1004 * get the text of the first selected button
1006 getText : function()
1008 return this.el.select('.roo-button-text',true).first().dom.innerHTML;
1011 setWeight : function(str)
1013 this.el.removeClass(this.weightClass);
1015 var outline = this.outline ? 'outline-' : '';
1016 if (str == 'default') {
1017 this.el.addClass('btn-default btn-outline-secondary');
1020 this.el.addClass('btn-' + outline + str);
1034 * @class Roo.bootstrap.Column
1035 * @extends Roo.bootstrap.Component
1036 * Bootstrap Column class
1037 * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
1038 * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
1039 * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
1040 * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
1041 * @cfg {Number} xsoff colspan offset out of 12 for mobile-sized screens or 0 for hidden
1042 * @cfg {Number} smoff colspan offset out of 12 for tablet-sized screens or 0 for hidden
1043 * @cfg {Number} mdoff colspan offset out of 12 for computer-sized screens or 0 for hidden
1044 * @cfg {Number} lgoff colspan offset out of 12 for large computer-sized screens or 0 for hidden
1047 * @cfg {Boolean} hidden (true|false) hide the element
1048 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
1049 * @cfg {String} fa (ban|check|...) font awesome icon
1050 * @cfg {Number} fasize (1|2|....) font awsome size
1052 * @cfg {String} icon (info-sign|check|...) glyphicon name
1054 * @cfg {String} html content of column.
1057 * Create a new Column
1058 * @param {Object} config The config object
1061 Roo.bootstrap.Column = function(config){
1062 Roo.bootstrap.Column.superclass.constructor.call(this, config);
1065 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
1083 getAutoCreate : function(){
1084 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
1092 ['xs','sm','md','lg'].map(function(size){
1093 //Roo.log( size + ':' + settings[size]);
1095 if (settings[size+'off'] !== false) {
1096 cfg.cls += ' col-' + size + '-offset-' + settings[size+'off'] ;
1099 if (settings[size] === false) {
1103 if (!settings[size]) { // 0 = hidden
1104 cfg.cls += ' hidden-' + size + ' hidden' + size + '-down';;
1107 cfg.cls += ' col-' + size + '-' + settings[size] + (
1108 size == 'xs' ? (' col-' + settings[size] ) : '' // bs4 col-{num} replaces col-xs
1114 cfg.cls += ' hidden';
1117 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1118 cfg.cls +=' alert alert-' + this.alert;
1122 if (this.html.length) {
1123 cfg.html = this.html;
1127 if (this.fasize > 1) {
1128 fasize = ' fa-' + this.fasize + 'x';
1130 cfg.html = '<i class="fa fa-'+this.fa + fasize + '"></i>' + (cfg.html || '');
1135 cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + (cfg.html || '');
1154 * @class Roo.bootstrap.Container
1155 * @extends Roo.bootstrap.Component
1156 * Bootstrap Container class
1157 * @cfg {Boolean} jumbotron is it a jumbotron element
1158 * @cfg {String} html content of element
1159 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
1160 * @cfg {String} panel (default|primary|success|info|warning|danger) render as panel - type - primary/success.....
1161 * @cfg {String} header content of header (for panel)
1162 * @cfg {String} footer content of footer (for panel)
1163 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
1164 * @cfg {String} tag (header|aside|section) type of HTML tag.
1165 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
1166 * @cfg {String} fa font awesome icon
1167 * @cfg {String} icon (info-sign|check|...) glyphicon name
1168 * @cfg {Boolean} hidden (true|false) hide the element
1169 * @cfg {Boolean} expandable (true|false) default false
1170 * @cfg {Boolean} expanded (true|false) default true
1171 * @cfg {String} rheader contet on the right of header
1172 * @cfg {Boolean} clickable (true|false) default false
1176 * Create a new Container
1177 * @param {Object} config The config object
1180 Roo.bootstrap.Container = function(config){
1181 Roo.bootstrap.Container.superclass.constructor.call(this, config);
1187 * After the panel has been expand
1189 * @param {Roo.bootstrap.Container} this
1194 * After the panel has been collapsed
1196 * @param {Roo.bootstrap.Container} this
1201 * When a element is chick
1202 * @param {Roo.bootstrap.Container} this
1203 * @param {Roo.EventObject} e
1209 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
1227 getChildContainer : function() {
1233 if (this.panel.length) {
1234 return this.el.select('.panel-body',true).first();
1241 getAutoCreate : function(){
1244 tag : this.tag || 'div',
1248 if (this.jumbotron) {
1249 cfg.cls = 'jumbotron';
1254 // - this is applied by the parent..
1256 // cfg.cls = this.cls + '';
1259 if (this.sticky.length) {
1261 var bd = Roo.get(document.body);
1262 if (!bd.hasClass('bootstrap-sticky')) {
1263 bd.addClass('bootstrap-sticky');
1264 Roo.select('html',true).setStyle('height', '100%');
1267 cfg.cls += 'bootstrap-sticky-' + this.sticky;
1271 if (this.well.length) {
1272 switch (this.well) {
1275 cfg.cls +=' well well-' +this.well;
1284 cfg.cls += ' hidden';
1288 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1289 cfg.cls +=' alert alert-' + this.alert;
1294 if (this.panel.length) {
1295 cfg.cls += ' panel panel-' + this.panel;
1297 if (this.header.length) {
1301 if(this.expandable){
1303 cfg.cls = cfg.cls + ' expandable';
1307 cls: (this.expanded ? 'fa fa-minus' : 'fa fa-plus')
1315 cls : 'panel-title',
1316 html : (this.expandable ? ' ' : '') + this.header
1320 cls: 'panel-header-right',
1326 cls : 'panel-heading',
1327 style : this.expandable ? 'cursor: pointer' : '',
1335 cls : 'panel-body' + (this.expanded ? '' : ' hide'),
1340 if (this.footer.length) {
1342 cls : 'panel-footer',
1351 body.html = this.html || cfg.html;
1352 // prefix with the icons..
1354 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1357 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1362 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1363 cfg.cls = 'container';
1369 initEvents: function()
1371 if(this.expandable){
1372 var headerEl = this.headerEl();
1375 headerEl.on('click', this.onToggleClick, this);
1380 this.el.on('click', this.onClick, this);
1385 onToggleClick : function()
1387 var headerEl = this.headerEl();
1403 if(this.fireEvent('expand', this)) {
1405 this.expanded = true;
1407 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).show();
1409 this.el.select('.panel-body',true).first().removeClass('hide');
1411 var toggleEl = this.toggleEl();
1417 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-minus']);
1422 collapse : function()
1424 if(this.fireEvent('collapse', this)) {
1426 this.expanded = false;
1428 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).hide();
1429 this.el.select('.panel-body',true).first().addClass('hide');
1431 var toggleEl = this.toggleEl();
1437 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-plus']);
1441 toggleEl : function()
1443 if(!this.el || !this.panel.length || !this.header.length || !this.expandable){
1447 return this.el.select('.panel-heading .fa',true).first();
1450 headerEl : function()
1452 if(!this.el || !this.panel.length || !this.header.length){
1456 return this.el.select('.panel-heading',true).first()
1461 if(!this.el || !this.panel.length){
1465 return this.el.select('.panel-body',true).first()
1468 titleEl : function()
1470 if(!this.el || !this.panel.length || !this.header.length){
1474 return this.el.select('.panel-title',true).first();
1477 setTitle : function(v)
1479 var titleEl = this.titleEl();
1485 titleEl.dom.innerHTML = v;
1488 getTitle : function()
1491 var titleEl = this.titleEl();
1497 return titleEl.dom.innerHTML;
1500 setRightTitle : function(v)
1502 var t = this.el.select('.panel-header-right',true).first();
1508 t.dom.innerHTML = v;
1511 onClick : function(e)
1515 this.fireEvent('click', this, e);
1528 * @class Roo.bootstrap.Img
1529 * @extends Roo.bootstrap.Component
1530 * Bootstrap Img class
1531 * @cfg {Boolean} imgResponsive false | true
1532 * @cfg {String} border rounded | circle | thumbnail
1533 * @cfg {String} src image source
1534 * @cfg {String} alt image alternative text
1535 * @cfg {String} href a tag href
1536 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1537 * @cfg {String} xsUrl xs image source
1538 * @cfg {String} smUrl sm image source
1539 * @cfg {String} mdUrl md image source
1540 * @cfg {String} lgUrl lg image source
1543 * Create a new Input
1544 * @param {Object} config The config object
1547 Roo.bootstrap.Img = function(config){
1548 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1554 * The img click event for the img.
1555 * @param {Roo.EventObject} e
1561 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1563 imgResponsive: true,
1573 getAutoCreate : function()
1575 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1576 return this.createSingleImg();
1581 cls: 'roo-image-responsive-group',
1586 Roo.each(['xs', 'sm', 'md', 'lg'], function(size){
1588 if(!_this[size + 'Url']){
1594 cls: (_this.imgResponsive) ? 'img-responsive' : '',
1595 html: _this.html || cfg.html,
1596 src: _this[size + 'Url']
1599 img.cls += ' roo-image-responsive-' + size;
1601 var s = ['xs', 'sm', 'md', 'lg'];
1603 s.splice(s.indexOf(size), 1);
1605 Roo.each(s, function(ss){
1606 img.cls += ' hidden-' + ss;
1609 if (['rounded','circle','thumbnail'].indexOf(_this.border)>-1) {
1610 cfg.cls += ' img-' + _this.border;
1614 cfg.alt = _this.alt;
1627 a.target = _this.target;
1631 cfg.cn.push((_this.href) ? a : img);
1638 createSingleImg : function()
1642 cls: (this.imgResponsive) ? 'img-responsive' : '',
1644 src : 'about:blank' // just incase src get's set to undefined?!?
1647 cfg.html = this.html || cfg.html;
1649 cfg.src = this.src || cfg.src;
1651 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1652 cfg.cls += ' img-' + this.border;
1669 a.target = this.target;
1674 return (this.href) ? a : cfg;
1677 initEvents: function()
1680 this.el.on('click', this.onClick, this);
1685 onClick : function(e)
1687 Roo.log('img onclick');
1688 this.fireEvent('click', this, e);
1691 * Sets the url of the image - used to update it
1692 * @param {String} url the url of the image
1695 setSrc : function(url)
1699 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1700 this.el.dom.src = url;
1704 this.el.select('img', true).first().dom.src = url;
1720 * @class Roo.bootstrap.Link
1721 * @extends Roo.bootstrap.Component
1722 * Bootstrap Link Class
1723 * @cfg {String} alt image alternative text
1724 * @cfg {String} href a tag href
1725 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1726 * @cfg {String} html the content of the link.
1727 * @cfg {String} anchor name for the anchor link
1728 * @cfg {String} fa - favicon
1730 * @cfg {Boolean} preventDefault (true | false) default false
1734 * Create a new Input
1735 * @param {Object} config The config object
1738 Roo.bootstrap.Link = function(config){
1739 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1745 * The img click event for the img.
1746 * @param {Roo.EventObject} e
1752 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1756 preventDefault: false,
1762 getAutoCreate : function()
1764 var html = this.html || '';
1766 if (this.fa !== false) {
1767 html = '<i class="fa fa-' + this.fa + '"></i>';
1772 // anchor's do not require html/href...
1773 if (this.anchor === false) {
1775 cfg.href = this.href || '#';
1777 cfg.name = this.anchor;
1778 if (this.html !== false || this.fa !== false) {
1781 if (this.href !== false) {
1782 cfg.href = this.href;
1786 if(this.alt !== false){
1791 if(this.target !== false) {
1792 cfg.target = this.target;
1798 initEvents: function() {
1800 if(!this.href || this.preventDefault){
1801 this.el.on('click', this.onClick, this);
1805 onClick : function(e)
1807 if(this.preventDefault){
1810 //Roo.log('img onclick');
1811 this.fireEvent('click', this, e);
1824 * @class Roo.bootstrap.Header
1825 * @extends Roo.bootstrap.Component
1826 * Bootstrap Header class
1827 * @cfg {String} html content of header
1828 * @cfg {Number} level (1|2|3|4|5|6) default 1
1831 * Create a new Header
1832 * @param {Object} config The config object
1836 Roo.bootstrap.Header = function(config){
1837 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1840 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1848 getAutoCreate : function(){
1853 tag: 'h' + (1 *this.level),
1854 html: this.html || ''
1866 * Ext JS Library 1.1.1
1867 * Copyright(c) 2006-2007, Ext JS, LLC.
1869 * Originally Released Under LGPL - original licence link has changed is not relivant.
1872 * <script type="text/javascript">
1876 * @class Roo.bootstrap.MenuMgr
1877 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1880 Roo.bootstrap.MenuMgr = function(){
1881 var menus, active, groups = {}, attached = false, lastShow = new Date();
1883 // private - called when first menu is created
1886 active = new Roo.util.MixedCollection();
1887 Roo.get(document).addKeyListener(27, function(){
1888 if(active.length > 0){
1896 if(active && active.length > 0){
1897 var c = active.clone();
1907 if(active.length < 1){
1908 Roo.get(document).un("mouseup", onMouseDown);
1916 var last = active.last();
1917 lastShow = new Date();
1920 Roo.get(document).on("mouseup", onMouseDown);
1925 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1926 m.parentMenu.activeChild = m;
1927 }else if(last && last.isVisible()){
1928 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1933 function onBeforeHide(m){
1935 m.activeChild.hide();
1937 if(m.autoHideTimer){
1938 clearTimeout(m.autoHideTimer);
1939 delete m.autoHideTimer;
1944 function onBeforeShow(m){
1945 var pm = m.parentMenu;
1946 if(!pm && !m.allowOtherMenus){
1948 }else if(pm && pm.activeChild && active != m){
1949 pm.activeChild.hide();
1953 // private this should really trigger on mouseup..
1954 function onMouseDown(e){
1955 Roo.log("on Mouse Up");
1957 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".dropdown-menu") && !e.getTarget('.user-menu')){
1958 Roo.log("MenuManager hideAll");
1967 function onBeforeCheck(mi, state){
1969 var g = groups[mi.group];
1970 for(var i = 0, l = g.length; i < l; i++){
1972 g[i].setChecked(false);
1981 * Hides all menus that are currently visible
1983 hideAll : function(){
1988 register : function(menu){
1992 menus[menu.id] = menu;
1993 menu.on("beforehide", onBeforeHide);
1994 menu.on("hide", onHide);
1995 menu.on("beforeshow", onBeforeShow);
1996 menu.on("show", onShow);
1998 if(g && menu.events["checkchange"]){
2002 groups[g].push(menu);
2003 menu.on("checkchange", onCheck);
2008 * Returns a {@link Roo.menu.Menu} object
2009 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
2010 * be used to generate and return a new Menu instance.
2012 get : function(menu){
2013 if(typeof menu == "string"){ // menu id
2015 }else if(menu.events){ // menu instance
2018 /*else if(typeof menu.length == 'number'){ // array of menu items?
2019 return new Roo.bootstrap.Menu({items:menu});
2020 }else{ // otherwise, must be a config
2021 return new Roo.bootstrap.Menu(menu);
2028 unregister : function(menu){
2029 delete menus[menu.id];
2030 menu.un("beforehide", onBeforeHide);
2031 menu.un("hide", onHide);
2032 menu.un("beforeshow", onBeforeShow);
2033 menu.un("show", onShow);
2035 if(g && menu.events["checkchange"]){
2036 groups[g].remove(menu);
2037 menu.un("checkchange", onCheck);
2042 registerCheckable : function(menuItem){
2043 var g = menuItem.group;
2048 groups[g].push(menuItem);
2049 menuItem.on("beforecheckchange", onBeforeCheck);
2054 unregisterCheckable : function(menuItem){
2055 var g = menuItem.group;
2057 groups[g].remove(menuItem);
2058 menuItem.un("beforecheckchange", onBeforeCheck);
2070 * @class Roo.bootstrap.Menu
2071 * @extends Roo.bootstrap.Component
2072 * Bootstrap Menu class - container for MenuItems
2073 * @cfg {String} type (dropdown|treeview|submenu) type of menu
2074 * @cfg {bool} hidden if the menu should be hidden when rendered.
2075 * @cfg {bool} stopEvent (true|false) Stop event after trigger press (default true)
2076 * @cfg {bool} isLink (true|false) the menu has link disable auto expand and collaspe (default false)
2080 * @param {Object} config The config object
2084 Roo.bootstrap.Menu = function(config){
2085 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
2086 if (this.registerMenu && this.type != 'treeview') {
2087 Roo.bootstrap.MenuMgr.register(this);
2094 * Fires before this menu is displayed (return false to block)
2095 * @param {Roo.menu.Menu} this
2100 * Fires before this menu is hidden (return false to block)
2101 * @param {Roo.menu.Menu} this
2106 * Fires after this menu is displayed
2107 * @param {Roo.menu.Menu} this
2112 * Fires after this menu is hidden
2113 * @param {Roo.menu.Menu} this
2118 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
2119 * @param {Roo.menu.Menu} this
2120 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2121 * @param {Roo.EventObject} e
2126 * Fires when the mouse is hovering over this menu
2127 * @param {Roo.menu.Menu} this
2128 * @param {Roo.EventObject} e
2129 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2134 * Fires when the mouse exits this menu
2135 * @param {Roo.menu.Menu} this
2136 * @param {Roo.EventObject} e
2137 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2142 * Fires when a menu item contained in this menu is clicked
2143 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
2144 * @param {Roo.EventObject} e
2148 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
2151 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
2155 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
2158 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
2160 registerMenu : true,
2162 menuItems :false, // stores the menu items..
2172 getChildContainer : function() {
2176 getAutoCreate : function(){
2178 //if (['right'].indexOf(this.align)!==-1) {
2179 // cfg.cn[1].cls += ' pull-right'
2185 cls : 'dropdown-menu' ,
2186 style : 'z-index:1000'
2190 if (this.type === 'submenu') {
2191 cfg.cls = 'submenu active';
2193 if (this.type === 'treeview') {
2194 cfg.cls = 'treeview-menu';
2199 initEvents : function() {
2201 // Roo.log("ADD event");
2202 // Roo.log(this.triggerEl.dom);
2204 this.triggerEl.on('click', this.onTriggerClick, this);
2206 this.triggerEl.on(Roo.isTouch ? 'touchstart' : 'mouseup', this.onTriggerPress, this);
2209 if (this.triggerEl.hasClass('nav-item')) {
2210 // dropdown toggle on the 'a' in BS4?
2211 this.triggerEl.select('.nav-link',true).first().addClass('dropdown-toggle');
2213 this.triggerEl.addClass('dropdown-toggle');
2216 this.el.on('touchstart' , this.onTouch, this);
2218 this.el.on('click' , this.onClick, this);
2220 this.el.on("mouseover", this.onMouseOver, this);
2221 this.el.on("mouseout", this.onMouseOut, this);
2225 findTargetItem : function(e)
2227 var t = e.getTarget(".dropdown-menu-item", this.el, true);
2231 //Roo.log(t); Roo.log(t.id);
2233 //Roo.log(this.menuitems);
2234 return this.menuitems.get(t.id);
2236 //return this.items.get(t.menuItemId);
2242 onTouch : function(e)
2244 Roo.log("menu.onTouch");
2245 //e.stopEvent(); this make the user popdown broken
2249 onClick : function(e)
2251 Roo.log("menu.onClick");
2253 var t = this.findTargetItem(e);
2254 if(!t || t.isContainer){
2259 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
2260 if(t == this.activeItem && t.shouldDeactivate(e)){
2261 this.activeItem.deactivate();
2262 delete this.activeItem;
2266 this.setActiveItem(t, true);
2274 Roo.log('pass click event');
2278 this.fireEvent("click", this, t, e);
2282 if(!t.href.length || t.href == '#'){
2283 (function() { _this.hide(); }).defer(100);
2288 onMouseOver : function(e){
2289 var t = this.findTargetItem(e);
2292 // if(t.canActivate && !t.disabled){
2293 // this.setActiveItem(t, true);
2297 this.fireEvent("mouseover", this, e, t);
2299 isVisible : function(){
2300 return !this.hidden;
2302 onMouseOut : function(e){
2303 var t = this.findTargetItem(e);
2306 // if(t == this.activeItem && t.shouldDeactivate(e)){
2307 // this.activeItem.deactivate();
2308 // delete this.activeItem;
2311 this.fireEvent("mouseout", this, e, t);
2316 * Displays this menu relative to another element
2317 * @param {String/HTMLElement/Roo.Element} element The element to align to
2318 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
2319 * the element (defaults to this.defaultAlign)
2320 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2322 show : function(el, pos, parentMenu)
2324 if (false === this.fireEvent("beforeshow", this)) {
2325 Roo.log("show canceled");
2328 this.parentMenu = parentMenu;
2333 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
2336 * Displays this menu at a specific xy position
2337 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
2338 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2340 showAt : function(xy, parentMenu, /* private: */_e){
2341 this.parentMenu = parentMenu;
2346 this.fireEvent("beforeshow", this);
2347 //xy = this.el.adjustForConstraints(xy);
2351 this.hideMenuItems();
2352 this.hidden = false;
2353 this.triggerEl.addClass('open');
2354 this.el.addClass('show');
2356 // reassign x when hitting right
2357 if(this.el.getWidth() + xy[0] >= Roo.lib.Dom.getViewWidth()){
2358 xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
2361 // reassign y when hitting bottom
2362 if(this.el.getHeight() + xy[1] >= Roo.lib.Dom.getViewHeight()){
2363 xy[1] = xy[1] - this.el.getHeight() - this.triggerEl.getHeight();
2366 // but the list may align on trigger left or trigger top... should it be a properity?
2368 if(this.el.getStyle('top') != 'auto' && this.el.getStyle('top').slice(-1) != "%"){
2373 this.fireEvent("show", this);
2379 this.doFocus.defer(50, this);
2383 doFocus : function(){
2385 this.focusEl.focus();
2390 * Hides this menu and optionally all parent menus
2391 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
2393 hide : function(deep)
2395 if (false === this.fireEvent("beforehide", this)) {
2396 Roo.log("hide canceled");
2399 this.hideMenuItems();
2400 if(this.el && this.isVisible()){
2402 if(this.activeItem){
2403 this.activeItem.deactivate();
2404 this.activeItem = null;
2406 this.triggerEl.removeClass('open');;
2407 this.el.removeClass('show');
2409 this.fireEvent("hide", this);
2411 if(deep === true && this.parentMenu){
2412 this.parentMenu.hide(true);
2416 onTriggerClick : function(e)
2418 Roo.log('trigger click');
2420 var target = e.getTarget();
2422 Roo.log(target.nodeName.toLowerCase());
2424 if(target.nodeName.toLowerCase() === 'i'){
2430 onTriggerPress : function(e)
2432 Roo.log('trigger press');
2433 //Roo.log(e.getTarget());
2434 // Roo.log(this.triggerEl.dom);
2436 // trigger only occurs on normal menu's -- if it's a treeview or dropdown... do not hide/show..
2437 var pel = Roo.get(e.getTarget());
2438 if (pel.findParent('.dropdown-menu') || pel.findParent('.treeview-menu') ) {
2439 Roo.log('is treeview or dropdown?');
2443 if(e.getTarget().nodeName.toLowerCase() !== 'i' && this.isLink){
2447 if (this.isVisible()) {
2452 this.show(this.triggerEl, '?', false);
2455 if(this.stopEvent || e.getTarget().nodeName.toLowerCase() === 'i'){
2462 hideMenuItems : function()
2464 Roo.log("hide Menu Items");
2469 this.el.select('.open',true).each(function(aa) {
2471 aa.removeClass('open');
2475 addxtypeChild : function (tree, cntr) {
2476 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
2478 this.menuitems.add(comp);
2490 this.getEl().dom.innerHTML = '';
2491 this.menuitems.clear();
2505 * @class Roo.bootstrap.MenuItem
2506 * @extends Roo.bootstrap.Component
2507 * Bootstrap MenuItem class
2508 * @cfg {String} html the menu label
2509 * @cfg {String} href the link
2510 * @cfg {Boolean} preventDefault do not trigger A href on clicks (default false).
2511 * @cfg {Boolean} isContainer is it a container - just returns a drop down item..
2512 * @cfg {Boolean} active used on sidebars to highlight active itesm
2513 * @cfg {String} fa favicon to show on left of menu item.
2514 * @cfg {Roo.bootsrap.Menu} menu the child menu.
2518 * Create a new MenuItem
2519 * @param {Object} config The config object
2523 Roo.bootstrap.MenuItem = function(config){
2524 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
2529 * The raw click event for the entire grid.
2530 * @param {Roo.bootstrap.MenuItem} this
2531 * @param {Roo.EventObject} e
2537 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
2541 preventDefault: false,
2542 isContainer : false,
2546 getAutoCreate : function(){
2548 if(this.isContainer){
2551 cls: 'dropdown-menu-item '
2561 cls : 'dropdown-item',
2566 if (this.fa !== false) {
2569 cls : 'fa fa-' + this.fa
2578 cls: 'dropdown-menu-item',
2581 if (this.parent().type == 'treeview') {
2582 cfg.cls = 'treeview-menu';
2585 cfg.cls += ' active';
2590 anc.href = this.href || cfg.cn[0].href ;
2591 ctag.html = this.html || cfg.cn[0].html ;
2595 initEvents: function()
2597 if (this.parent().type == 'treeview') {
2598 this.el.select('a').on('click', this.onClick, this);
2602 this.menu.parentType = this.xtype;
2603 this.menu.triggerEl = this.el;
2604 this.menu = this.addxtype(Roo.apply({}, this.menu));
2608 onClick : function(e)
2610 Roo.log('item on click ');
2612 if(this.preventDefault){
2615 //this.parent().hideMenuItems();
2617 this.fireEvent('click', this, e);
2636 * @class Roo.bootstrap.MenuSeparator
2637 * @extends Roo.bootstrap.Component
2638 * Bootstrap MenuSeparator class
2641 * Create a new MenuItem
2642 * @param {Object} config The config object
2646 Roo.bootstrap.MenuSeparator = function(config){
2647 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2650 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2652 getAutoCreate : function(){
2671 * @class Roo.bootstrap.Modal
2672 * @extends Roo.bootstrap.Component
2673 * Bootstrap Modal class
2674 * @cfg {String} title Title of dialog
2675 * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2676 * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method adn
2677 * @cfg {Boolean} specificTitle default false
2678 * @cfg {Array} buttons Array of buttons or standard button set..
2679 * @cfg {String} buttonPosition (left|right|center) default right (DEPRICATED) - use mr-auto on buttons to put them on the left
2680 * @cfg {Boolean} animate default true
2681 * @cfg {Boolean} allow_close default true
2682 * @cfg {Boolean} fitwindow default false
2683 * @cfg {String} size (sm|lg) default empty
2684 * @cfg {Number} max_width set the max width of modal
2688 * Create a new Modal Dialog
2689 * @param {Object} config The config object
2692 Roo.bootstrap.Modal = function(config){
2693 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2698 * The raw btnclick event for the button
2699 * @param {Roo.EventObject} e
2704 * Fire when dialog resize
2705 * @param {Roo.bootstrap.Modal} this
2706 * @param {Roo.EventObject} e
2710 this.buttons = this.buttons || [];
2713 this.tmpl = Roo.factory(this.tmpl);
2718 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2720 title : 'test dialog',
2730 specificTitle: false,
2732 buttonPosition: 'right',
2755 onRender : function(ct, position)
2757 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2760 var cfg = Roo.apply({}, this.getAutoCreate());
2763 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2765 //if (!cfg.name.length) {
2769 cfg.cls += ' ' + this.cls;
2772 cfg.style = this.style;
2774 this.el = Roo.get(document.body).createChild(cfg, position);
2776 //var type = this.el.dom.type;
2779 if(this.tabIndex !== undefined){
2780 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2783 this.dialogEl = this.el.select('.modal-dialog',true).first();
2784 this.bodyEl = this.el.select('.modal-body',true).first();
2785 this.closeEl = this.el.select('.modal-header .close', true).first();
2786 this.headerEl = this.el.select('.modal-header',true).first();
2787 this.titleEl = this.el.select('.modal-title',true).first();
2788 this.footerEl = this.el.select('.modal-footer',true).first();
2790 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2792 //this.el.addClass("x-dlg-modal");
2794 if (this.buttons.length) {
2795 Roo.each(this.buttons, function(bb) {
2796 var b = Roo.apply({}, bb);
2797 b.xns = b.xns || Roo.bootstrap;
2798 b.xtype = b.xtype || 'Button';
2799 if (typeof(b.listeners) == 'undefined') {
2800 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2803 var btn = Roo.factory(b);
2805 btn.render(this.getButtonContainer());
2809 // render the children.
2812 if(typeof(this.items) != 'undefined'){
2813 var items = this.items;
2816 for(var i =0;i < items.length;i++) {
2817 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2821 this.items = nitems;
2823 // where are these used - they used to be body/close/footer
2827 //this.el.addClass([this.fieldClass, this.cls]);
2831 getAutoCreate : function()
2835 html : this.html || ''
2840 cls : 'modal-title',
2844 if(this.specificTitle){
2850 if (this.allow_close && Roo.bootstrap.version == 3) {
2860 if (this.allow_close && Roo.bootstrap.version == 4) {
2870 if(this.size.length){
2871 size = 'modal-' + this.size;
2874 var footer = Roo.bootstrap.version == 3 ?
2876 cls : 'modal-footer',
2880 cls: 'btn-' + this.buttonPosition
2885 { // BS4 uses mr-auto on left buttons....
2886 cls : 'modal-footer'
2897 cls: "modal-dialog " + size,
2900 cls : "modal-content",
2903 cls : 'modal-header',
2918 modal.cls += ' fade';
2924 getChildContainer : function() {
2929 getButtonContainer : function() {
2931 return Roo.bootstrap.version == 4 ?
2932 this.el.select('.modal-footer',true).first()
2933 : this.el.select('.modal-footer div',true).first();
2936 initEvents : function()
2938 if (this.allow_close) {
2939 this.closeEl.on('click', this.hide, this);
2941 Roo.EventManager.onWindowResize(this.resize, this, true);
2949 this.maskEl.setSize(
2950 Roo.lib.Dom.getViewWidth(true),
2951 Roo.lib.Dom.getViewHeight(true)
2954 if (this.fitwindow) {
2958 this.width || Roo.lib.Dom.getViewportWidth(true) - 30,
2959 this.height || Roo.lib.Dom.getViewportHeight(true) // catering margin-top 30 margin-bottom 30
2964 if(this.max_width !== 0) {
2966 var w = Math.min(this.max_width, Roo.lib.Dom.getViewportWidth(true) - 30);
2969 this.setSize(w, this.height);
2973 if(this.max_height) {
2974 this.setSize(w,Math.min(
2976 Roo.lib.Dom.getViewportHeight(true) - 60
2982 if(!this.fit_content) {
2983 this.setSize(w, Roo.lib.Dom.getViewportHeight(true) - 60);
2987 this.setSize(w, Math.min(
2989 this.headerEl.getHeight() +
2990 this.footerEl.getHeight() +
2991 this.getChildHeight(this.bodyEl.dom.childNodes),
2992 Roo.lib.Dom.getViewportHeight(true) - 60)
2998 setSize : function(w,h)
3009 if (!this.rendered) {
3013 //this.el.setStyle('display', 'block');
3014 this.el.removeClass('hideing');
3015 this.el.dom.style.display='block';
3017 Roo.get(document.body).addClass('modal-open');
3019 if(this.animate){ // element has 'fade' - so stuff happens after .3s ?- not sure why the delay?
3022 this.el.addClass('show');
3023 this.el.addClass('in');
3026 this.el.addClass('show');
3027 this.el.addClass('in');
3030 // not sure how we can show data in here..
3032 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
3035 Roo.get(document.body).addClass("x-body-masked");
3037 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
3038 this.maskEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
3039 this.maskEl.dom.style.display = 'block';
3040 this.maskEl.addClass('show');
3045 this.fireEvent('show', this);
3047 // set zindex here - otherwise it appears to be ignored...
3048 this.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
3051 this.items.forEach( function(e) {
3052 e.layout ? e.layout() : false;
3060 if(this.fireEvent("beforehide", this) !== false){
3062 this.maskEl.removeClass('show');
3064 this.maskEl.dom.style.display = '';
3065 Roo.get(document.body).removeClass("x-body-masked");
3066 this.el.removeClass('in');
3067 this.el.select('.modal-dialog', true).first().setStyle('transform','');
3069 if(this.animate){ // why
3070 this.el.addClass('hideing');
3071 this.el.removeClass('show');
3073 if (!this.el.hasClass('hideing')) {
3074 return; // it's been shown again...
3077 this.el.dom.style.display='';
3079 Roo.get(document.body).removeClass('modal-open');
3080 this.el.removeClass('hideing');
3084 this.el.removeClass('show');
3085 this.el.dom.style.display='';
3086 Roo.get(document.body).removeClass('modal-open');
3089 this.fireEvent('hide', this);
3092 isVisible : function()
3095 return this.el.hasClass('show') && !this.el.hasClass('hideing');
3099 addButton : function(str, cb)
3103 var b = Roo.apply({}, { html : str } );
3104 b.xns = b.xns || Roo.bootstrap;
3105 b.xtype = b.xtype || 'Button';
3106 if (typeof(b.listeners) == 'undefined') {
3107 b.listeners = { click : cb.createDelegate(this) };
3110 var btn = Roo.factory(b);
3112 btn.render(this.getButtonContainer());
3118 setDefaultButton : function(btn)
3120 //this.el.select('.modal-footer').()
3123 resizeTo: function(w,h)
3125 this.dialogEl.setWidth(w);
3127 var diff = this.headerEl.getHeight() + this.footerEl.getHeight() + 60; // dialog margin-bottom: 30
3129 this.bodyEl.setHeight(h - diff);
3131 this.fireEvent('resize', this);
3134 setContentSize : function(w, h)
3138 onButtonClick: function(btn,e)
3141 this.fireEvent('btnclick', btn.name, e);
3144 * Set the title of the Dialog
3145 * @param {String} str new Title
3147 setTitle: function(str) {
3148 this.titleEl.dom.innerHTML = str;
3151 * Set the body of the Dialog
3152 * @param {String} str new Title
3154 setBody: function(str) {
3155 this.bodyEl.dom.innerHTML = str;
3158 * Set the body of the Dialog using the template
3159 * @param {Obj} data - apply this data to the template and replace the body contents.
3161 applyBody: function(obj)
3164 Roo.log("Error - using apply Body without a template");
3167 this.tmpl.overwrite(this.bodyEl, obj);
3170 getChildHeight : function(child_nodes)
3174 child_nodes.length == 0
3179 var child_height = 0;
3181 for(var i = 0; i < child_nodes.length; i++) {
3184 * for modal with tabs...
3185 if(child_nodes[i].classList.contains('roo-layout-panel')) {
3187 var layout_childs = child_nodes[i].childNodes;
3189 for(var j = 0; j < layout_childs.length; j++) {
3191 if(layout_childs[j].classList.contains('roo-layout-panel-body')) {
3193 var layout_body_childs = layout_childs[j].childNodes;
3195 for(var k = 0; k < layout_body_childs.length; k++) {
3197 if(layout_body_childs[k].classList.contains('navbar')) {
3198 child_height += layout_body_childs[k].offsetHeight;
3202 if(layout_body_childs[k].classList.contains('roo-layout-tabs-body')) {
3204 var layout_body_tab_childs = layout_body_childs[k].childNodes;
3206 for(var m = 0; m < layout_body_tab_childs.length; m++) {
3208 if(layout_body_tab_childs[m].classList.contains('roo-layout-active-content')) {
3209 child_height += this.getChildHeight(layout_body_tab_childs[m].childNodes);
3224 child_height += child_nodes[i].offsetHeight;
3225 // Roo.log(child_nodes[i].offsetHeight);
3228 return child_height;
3234 Roo.apply(Roo.bootstrap.Modal, {
3236 * Button config that displays a single OK button
3245 * Button config that displays Yes and No buttons
3261 * Button config that displays OK and Cancel buttons
3276 * Button config that displays Yes, No and Cancel buttons
3300 * messagebox - can be used as a replace
3304 * @class Roo.MessageBox
3305 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
3309 Roo.Msg.alert('Status', 'Changes saved successfully.');
3311 // Prompt for user data:
3312 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
3314 // process text value...
3318 // Show a dialog using config options:
3320 title:'Save Changes?',
3321 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
3322 buttons: Roo.Msg.YESNOCANCEL,
3329 Roo.bootstrap.MessageBox = function(){
3330 var dlg, opt, mask, waitTimer;
3331 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
3332 var buttons, activeTextEl, bwidth;
3336 var handleButton = function(button){
3338 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
3342 var handleHide = function(){
3344 dlg.el.removeClass(opt.cls);
3347 // Roo.TaskMgr.stop(waitTimer);
3348 // waitTimer = null;
3353 var updateButtons = function(b){
3356 buttons["ok"].hide();
3357 buttons["cancel"].hide();
3358 buttons["yes"].hide();
3359 buttons["no"].hide();
3360 dlg.footerEl.hide();
3364 dlg.footerEl.show();
3365 for(var k in buttons){
3366 if(typeof buttons[k] != "function"){
3369 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
3370 width += buttons[k].el.getWidth()+15;
3380 var handleEsc = function(d, k, e){
3381 if(opt && opt.closable !== false){
3391 * Returns a reference to the underlying {@link Roo.BasicDialog} element
3392 * @return {Roo.BasicDialog} The BasicDialog element
3394 getDialog : function(){
3396 dlg = new Roo.bootstrap.Modal( {
3399 //constraintoviewport:false,
3401 //collapsible : false,
3406 //buttonAlign:"center",
3407 closeClick : function(){
3408 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
3411 handleButton("cancel");
3416 dlg.on("hide", handleHide);
3418 //dlg.addKeyListener(27, handleEsc);
3420 this.buttons = buttons;
3421 var bt = this.buttonText;
3422 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
3423 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
3424 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
3425 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
3427 bodyEl = dlg.bodyEl.createChild({
3429 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
3430 '<textarea class="roo-mb-textarea"></textarea>' +
3431 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
3433 msgEl = bodyEl.dom.firstChild;
3434 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
3435 textboxEl.enableDisplayMode();
3436 textboxEl.addKeyListener([10,13], function(){
3437 if(dlg.isVisible() && opt && opt.buttons){
3440 }else if(opt.buttons.yes){
3441 handleButton("yes");
3445 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
3446 textareaEl.enableDisplayMode();
3447 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
3448 progressEl.enableDisplayMode();
3450 // This is supposed to be the progessElement.. but I think it's controlling the height of everything..
3451 var pf = progressEl.dom.firstChild;
3453 pp = Roo.get(pf.firstChild);
3454 pp.setHeight(pf.offsetHeight);
3462 * Updates the message box body text
3463 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
3464 * the XHTML-compliant non-breaking space character '&#160;')
3465 * @return {Roo.MessageBox} This message box
3467 updateText : function(text)
3469 if(!dlg.isVisible() && !opt.width){
3470 dlg.dialogEl.setStyle({ 'max-width' : this.maxWidth});
3471 // dlg.resizeTo(this.maxWidth, 100); // forcing the height breaks long alerts()
3473 msgEl.innerHTML = text || ' ';
3475 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
3476 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
3478 Math.min(opt.width || cw , this.maxWidth),
3479 Math.max(opt.minWidth || this.minWidth, bwidth)
3482 activeTextEl.setWidth(w);
3484 if(dlg.isVisible()){
3485 dlg.fixedcenter = false;
3487 // to big, make it scroll. = But as usual stupid IE does not support
3490 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
3491 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
3492 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
3494 bodyEl.dom.style.height = '';
3495 bodyEl.dom.style.overflowY = '';
3498 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
3500 bodyEl.dom.style.overflowX = '';
3503 dlg.setContentSize(w, bodyEl.getHeight());
3504 if(dlg.isVisible()){
3505 dlg.fixedcenter = true;
3511 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
3512 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
3513 * @param {Number} value Any number between 0 and 1 (e.g., .5)
3514 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
3515 * @return {Roo.MessageBox} This message box
3517 updateProgress : function(value, text){
3519 this.updateText(text);
3522 if (pp) { // weird bug on my firefox - for some reason this is not defined
3523 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
3524 pp.setHeight(Math.floor(progressEl.dom.firstChild.offsetHeight));
3530 * Returns true if the message box is currently displayed
3531 * @return {Boolean} True if the message box is visible, else false
3533 isVisible : function(){
3534 return dlg && dlg.isVisible();
3538 * Hides the message box if it is displayed
3541 if(this.isVisible()){
3547 * Displays a new message box, or reinitializes an existing message box, based on the config options
3548 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
3549 * The following config object properties are supported:
3551 Property Type Description
3552 ---------- --------------- ------------------------------------------------------------------------------------
3553 animEl String/Element An id or Element from which the message box should animate as it opens and
3554 closes (defaults to undefined)
3555 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
3556 cancel:'Bar'}), or false to not show any buttons (defaults to false)
3557 closable Boolean False to hide the top-right close button (defaults to true). Note that
3558 progress and wait dialogs will ignore this property and always hide the
3559 close button as they can only be closed programmatically.
3560 cls String A custom CSS class to apply to the message box element
3561 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
3562 displayed (defaults to 75)
3563 fn Function A callback function to execute after closing the dialog. The arguments to the
3564 function will be btn (the name of the button that was clicked, if applicable,
3565 e.g. "ok"), and text (the value of the active text field, if applicable).
3566 Progress and wait dialogs will ignore this option since they do not respond to
3567 user actions and can only be closed programmatically, so any required function
3568 should be called by the same code after it closes the dialog.
3569 icon String A CSS class that provides a background image to be used as an icon for
3570 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
3571 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
3572 minWidth Number The minimum width in pixels of the message box (defaults to 100)
3573 modal Boolean False to allow user interaction with the page while the message box is
3574 displayed (defaults to true)
3575 msg String A string that will replace the existing message box body text (defaults
3576 to the XHTML-compliant non-breaking space character ' ')
3577 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
3578 progress Boolean True to display a progress bar (defaults to false)
3579 progressText String The text to display inside the progress bar if progress = true (defaults to '')
3580 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
3581 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
3582 title String The title text
3583 value String The string value to set into the active textbox element if displayed
3584 wait Boolean True to display a progress bar (defaults to false)
3585 width Number The width of the dialog in pixels
3592 msg: 'Please enter your address:',
3594 buttons: Roo.MessageBox.OKCANCEL,
3597 animEl: 'addAddressBtn'
3600 * @param {Object} config Configuration options
3601 * @return {Roo.MessageBox} This message box
3603 show : function(options)
3606 // this causes nightmares if you show one dialog after another
3607 // especially on callbacks..
3609 if(this.isVisible()){
3612 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
3613 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
3614 Roo.log("New Dialog Message:" + options.msg )
3615 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
3616 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
3619 var d = this.getDialog();
3621 d.setTitle(opt.title || " ");
3622 d.closeEl.setDisplayed(opt.closable !== false);
3623 activeTextEl = textboxEl;
3624 opt.prompt = opt.prompt || (opt.multiline ? true : false);
3629 textareaEl.setHeight(typeof opt.multiline == "number" ?
3630 opt.multiline : this.defaultTextHeight);
3631 activeTextEl = textareaEl;
3640 progressEl.setDisplayed(opt.progress === true);
3642 d.animate = false; // do not animate progress, as it may not have finished animating before we close it..
3644 this.updateProgress(0);
3645 activeTextEl.dom.value = opt.value || "";
3647 dlg.setDefaultButton(activeTextEl);
3649 var bs = opt.buttons;
3653 }else if(bs && bs.yes){
3654 db = buttons["yes"];
3656 dlg.setDefaultButton(db);
3658 bwidth = updateButtons(opt.buttons);
3659 this.updateText(opt.msg);
3661 d.el.addClass(opt.cls);
3663 d.proxyDrag = opt.proxyDrag === true;
3664 d.modal = opt.modal !== false;
3665 d.mask = opt.modal !== false ? mask : false;
3667 // force it to the end of the z-index stack so it gets a cursor in FF
3668 document.body.appendChild(dlg.el.dom);
3669 d.animateTarget = null;
3670 d.show(options.animEl);
3676 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
3677 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
3678 * and closing the message box when the process is complete.
3679 * @param {String} title The title bar text
3680 * @param {String} msg The message box body text
3681 * @return {Roo.MessageBox} This message box
3683 progress : function(title, msg){
3690 minWidth: this.minProgressWidth,
3697 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
3698 * If a callback function is passed it will be called after the user clicks the button, and the
3699 * id of the button that was clicked will be passed as the only parameter to the callback
3700 * (could also be the top-right close button).
3701 * @param {String} title The title bar text
3702 * @param {String} msg The message box body text
3703 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3704 * @param {Object} scope (optional) The scope of the callback function
3705 * @return {Roo.MessageBox} This message box
3707 alert : function(title, msg, fn, scope)
3722 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
3723 * interaction while waiting for a long-running process to complete that does not have defined intervals.
3724 * You are responsible for closing the message box when the process is complete.
3725 * @param {String} msg The message box body text
3726 * @param {String} title (optional) The title bar text
3727 * @return {Roo.MessageBox} This message box
3729 wait : function(msg, title){
3740 waitTimer = Roo.TaskMgr.start({
3742 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
3750 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
3751 * If a callback function is passed it will be called after the user clicks either button, and the id of the
3752 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
3753 * @param {String} title The title bar text
3754 * @param {String} msg The message box body text
3755 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3756 * @param {Object} scope (optional) The scope of the callback function
3757 * @return {Roo.MessageBox} This message box
3759 confirm : function(title, msg, fn, scope){
3763 buttons: this.YESNO,
3772 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
3773 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
3774 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
3775 * (could also be the top-right close button) and the text that was entered will be passed as the two
3776 * parameters to the callback.
3777 * @param {String} title The title bar text
3778 * @param {String} msg The message box body text
3779 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3780 * @param {Object} scope (optional) The scope of the callback function
3781 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
3782 * property, or the height in pixels to create the textbox (defaults to false / single-line)
3783 * @return {Roo.MessageBox} This message box
3785 prompt : function(title, msg, fn, scope, multiline){
3789 buttons: this.OKCANCEL,
3794 multiline: multiline,
3801 * Button config that displays a single OK button
3806 * Button config that displays Yes and No buttons
3809 YESNO : {yes:true, no:true},
3811 * Button config that displays OK and Cancel buttons
3814 OKCANCEL : {ok:true, cancel:true},
3816 * Button config that displays Yes, No and Cancel buttons
3819 YESNOCANCEL : {yes:true, no:true, cancel:true},
3822 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3825 defaultTextHeight : 75,
3827 * The maximum width in pixels of the message box (defaults to 600)
3832 * The minimum width in pixels of the message box (defaults to 100)
3837 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3838 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3841 minProgressWidth : 250,
3843 * An object containing the default button text strings that can be overriden for localized language support.
3844 * Supported properties are: ok, cancel, yes and no.
3845 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3858 * Shorthand for {@link Roo.MessageBox}
3860 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3861 Roo.Msg = Roo.Msg || Roo.MessageBox;
3870 * @class Roo.bootstrap.Navbar
3871 * @extends Roo.bootstrap.Component
3872 * Bootstrap Navbar class
3875 * Create a new Navbar
3876 * @param {Object} config The config object
3880 Roo.bootstrap.Navbar = function(config){
3881 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3885 * @event beforetoggle
3886 * Fire before toggle the menu
3887 * @param {Roo.EventObject} e
3889 "beforetoggle" : true
3893 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3902 getAutoCreate : function(){
3905 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3909 initEvents :function ()
3911 //Roo.log(this.el.select('.navbar-toggle',true));
3912 this.el.select('.navbar-toggle',true).on('click', this.onToggle , this);
3919 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3921 var size = this.el.getSize();
3922 this.maskEl.setSize(size.width, size.height);
3923 this.maskEl.enableDisplayMode("block");
3932 getChildContainer : function()
3934 if (this.el && this.el.select('.collapse').getCount()) {
3935 return this.el.select('.collapse',true).first();
3950 onToggle : function()
3953 if(this.fireEvent('beforetoggle', this) === false){
3956 var ce = this.el.select('.navbar-collapse',true).first();
3958 if (!ce.hasClass('show')) {
3968 * Expand the navbar pulldown
3970 expand : function ()
3973 var ce = this.el.select('.navbar-collapse',true).first();
3974 if (ce.hasClass('collapsing')) {
3977 ce.dom.style.height = '';
3979 ce.addClass('in'); // old...
3980 ce.removeClass('collapse');
3981 ce.addClass('show');
3982 var h = ce.getHeight();
3984 ce.removeClass('show');
3985 // at this point we should be able to see it..
3986 ce.addClass('collapsing');
3988 ce.setHeight(0); // resize it ...
3989 ce.on('transitionend', function() {
3990 //Roo.log('done transition');
3991 ce.removeClass('collapsing');
3992 ce.addClass('show');
3993 ce.removeClass('collapse');
3995 ce.dom.style.height = '';
3996 }, this, { single: true} );
3998 ce.dom.scrollTop = 0;
4001 * Collapse the navbar pulldown
4003 collapse : function()
4005 var ce = this.el.select('.navbar-collapse',true).first();
4007 if (ce.hasClass('collapsing') || ce.hasClass('collapse') ) {
4008 // it's collapsed or collapsing..
4011 ce.removeClass('in'); // old...
4012 ce.setHeight(ce.getHeight());
4013 ce.removeClass('show');
4014 ce.addClass('collapsing');
4016 ce.on('transitionend', function() {
4017 ce.dom.style.height = '';
4018 ce.removeClass('collapsing');
4019 ce.addClass('collapse');
4020 }, this, { single: true} );
4040 * @class Roo.bootstrap.NavSimplebar
4041 * @extends Roo.bootstrap.Navbar
4042 * Bootstrap Sidebar class
4044 * @cfg {Boolean} inverse is inverted color
4046 * @cfg {String} type (nav | pills | tabs)
4047 * @cfg {Boolean} arrangement stacked | justified
4048 * @cfg {String} align (left | right) alignment
4050 * @cfg {Boolean} main (true|false) main nav bar? default false
4051 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
4053 * @cfg {String} tag (header|footer|nav|div) default is nav
4055 * @cfg {String} weight (light|primary|secondary|success|danger|warning|info|dark|white) default is light.
4059 * Create a new Sidebar
4060 * @param {Object} config The config object
4064 Roo.bootstrap.NavSimplebar = function(config){
4065 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
4068 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
4084 getAutoCreate : function(){
4088 tag : this.tag || 'div',
4089 cls : 'navbar roo-navbar-simple' //navbar-expand-lg ??
4091 if (['light','white'].indexOf(this.weight) > -1) {
4092 cfg.cls += ['light','white'].indexOf(this.weight) > -1 ? ' navbar-light' : ' navbar-dark';
4094 cfg.cls += ' bg-' + this.weight;
4097 cfg.cls += ' navbar-inverse';
4101 // i'm not actually sure these are really used - normally we add a navGroup to a navbar
4103 if (Roo.bootstrap.version == 4 && this.xtype == 'NavSimplebar') {
4112 cls: 'nav nav-' + this.xtype,
4118 this.type = this.type || 'nav';
4119 if (['tabs','pills'].indexOf(this.type) != -1) {
4120 cfg.cn[0].cls += ' nav-' + this.type
4124 if (this.type!=='nav') {
4125 Roo.log('nav type must be nav/tabs/pills')
4127 cfg.cn[0].cls += ' navbar-nav'
4133 if (['stacked','justified'].indexOf(this.arrangement) != -1) {
4134 cfg.cn[0].cls += ' nav-' + this.arrangement;
4138 if (this.align === 'right') {
4139 cfg.cn[0].cls += ' navbar-right';
4164 * navbar-expand-md fixed-top
4168 * @class Roo.bootstrap.NavHeaderbar
4169 * @extends Roo.bootstrap.NavSimplebar
4170 * Bootstrap Sidebar class
4172 * @cfg {String} brand what is brand
4173 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
4174 * @cfg {String} brand_href href of the brand
4175 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
4176 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
4177 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
4178 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
4181 * Create a new Sidebar
4182 * @param {Object} config The config object
4186 Roo.bootstrap.NavHeaderbar = function(config){
4187 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
4191 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
4198 desktopCenter : false,
4201 getAutoCreate : function(){
4204 tag: this.nav || 'nav',
4205 cls: 'navbar navbar-expand-md',
4211 if (this.desktopCenter) {
4212 cn.push({cls : 'container', cn : []});
4220 cls: 'navbar-toggle navbar-toggler',
4221 'data-toggle': 'collapse',
4226 html: 'Toggle navigation'
4230 cls: 'icon-bar navbar-toggler-icon'
4243 cn.push( Roo.bootstrap.version == 4 ? btn : {
4245 cls: 'navbar-header',
4254 cls: Roo.bootstrap.version == 4 ? 'nav flex-row roo-navbar-collapse' : 'collapse navbar-collapse roo-navbar-collapse',
4258 cfg.cls += this.inverse ? ' navbar-inverse navbar-dark bg-dark' : ' navbar-default';
4260 if (['light','white'].indexOf(this.weight) > -1) {
4261 cfg.cls += ['light','white'].indexOf(this.weight) > -1 ? ' navbar-light' : ' navbar-dark';
4263 cfg.cls += ' bg-' + this.weight;
4266 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
4267 cfg.cls += ' navbar-' + this.position + ' ' + this.position ;
4269 // tag can override this..
4271 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
4274 if (this.brand !== '') {
4275 var cp = Roo.bootstrap.version == 4 ? cn : cn[0].cn;
4276 cp.unshift({ // changed from push ?? BS4 needs it at the start? - does this break or exsiting?
4278 href: this.brand_href ? this.brand_href : '#',
4279 cls: 'navbar-brand',
4287 cfg.cls += ' main-nav';
4295 getHeaderChildContainer : function()
4297 if (this.srButton && this.el.select('.navbar-header').getCount()) {
4298 return this.el.select('.navbar-header',true).first();
4301 return this.getChildContainer();
4305 initEvents : function()
4307 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
4309 if (this.autohide) {
4314 Roo.get(document).on('scroll',function(e) {
4315 var ns = Roo.get(document).getScroll().top;
4316 var os = prevScroll;
4320 ft.removeClass('slideDown');
4321 ft.addClass('slideUp');
4324 ft.removeClass('slideUp');
4325 ft.addClass('slideDown');
4346 * @class Roo.bootstrap.NavSidebar
4347 * @extends Roo.bootstrap.Navbar
4348 * Bootstrap Sidebar class
4351 * Create a new Sidebar
4352 * @param {Object} config The config object
4356 Roo.bootstrap.NavSidebar = function(config){
4357 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
4360 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
4362 sidebar : true, // used by Navbar Item and NavbarGroup at present...
4364 getAutoCreate : function(){
4369 cls: 'sidebar sidebar-nav'
4391 * @class Roo.bootstrap.NavGroup
4392 * @extends Roo.bootstrap.Component
4393 * Bootstrap NavGroup class
4394 * @cfg {String} align (left|right)
4395 * @cfg {Boolean} inverse
4396 * @cfg {String} type (nav|pills|tab) default nav
4397 * @cfg {String} navId - reference Id for navbar.
4401 * Create a new nav group
4402 * @param {Object} config The config object
4405 Roo.bootstrap.NavGroup = function(config){
4406 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
4409 Roo.bootstrap.NavGroup.register(this);
4413 * Fires when the active item changes
4414 * @param {Roo.bootstrap.NavGroup} this
4415 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
4416 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
4423 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
4434 getAutoCreate : function()
4436 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
4442 if (Roo.bootstrap.version == 4) {
4443 if (['tabs','pills'].indexOf(this.type) != -1) {
4444 cfg.cls += ' nav-' + this.type;
4446 // trying to remove so header bar can right align top?
4447 if (this.parent() && this.parent().xtype != 'NavHeaderbar') {
4448 // do not use on header bar...
4449 cfg.cls += ' navbar-nav';
4454 if (['tabs','pills'].indexOf(this.type) != -1) {
4455 cfg.cls += ' nav-' + this.type
4457 if (this.type !== 'nav') {
4458 Roo.log('nav type must be nav/tabs/pills')
4460 cfg.cls += ' navbar-nav'
4464 if (this.parent() && this.parent().sidebar) {
4467 cls: 'dashboard-menu sidebar-menu'
4473 if (this.form === true) {
4476 cls: 'navbar-form form-inline'
4478 //nav navbar-right ml-md-auto
4479 if (this.align === 'right') {
4480 cfg.cls += ' navbar-right ml-md-auto';
4482 cfg.cls += ' navbar-left';
4486 if (this.align === 'right') {
4487 cfg.cls += ' navbar-right ml-md-auto';
4489 cfg.cls += ' mr-auto';
4493 cfg.cls += ' navbar-inverse';
4501 * sets the active Navigation item
4502 * @param {Roo.bootstrap.NavItem} the new current navitem
4504 setActiveItem : function(item)
4507 Roo.each(this.navItems, function(v){
4512 v.setActive(false, true);
4519 item.setActive(true, true);
4520 this.fireEvent('changed', this, item, prev);
4525 * gets the active Navigation item
4526 * @return {Roo.bootstrap.NavItem} the current navitem
4528 getActive : function()
4532 Roo.each(this.navItems, function(v){
4543 indexOfNav : function()
4547 Roo.each(this.navItems, function(v,i){
4558 * adds a Navigation item
4559 * @param {Roo.bootstrap.NavItem} the navitem to add
4561 addItem : function(cfg)
4563 if (this.form && Roo.bootstrap.version == 4) {
4566 var cn = new Roo.bootstrap.NavItem(cfg);
4568 cn.parentId = this.id;
4569 cn.onRender(this.el, null);
4573 * register a Navigation item
4574 * @param {Roo.bootstrap.NavItem} the navitem to add
4576 register : function(item)
4578 this.navItems.push( item);
4579 item.navId = this.navId;
4584 * clear all the Navigation item
4587 clearAll : function()
4590 this.el.dom.innerHTML = '';
4593 getNavItem: function(tabId)
4596 Roo.each(this.navItems, function(e) {
4597 if (e.tabId == tabId) {
4607 setActiveNext : function()
4609 var i = this.indexOfNav(this.getActive());
4610 if (i > this.navItems.length) {
4613 this.setActiveItem(this.navItems[i+1]);
4615 setActivePrev : function()
4617 var i = this.indexOfNav(this.getActive());
4621 this.setActiveItem(this.navItems[i-1]);
4623 clearWasActive : function(except) {
4624 Roo.each(this.navItems, function(e) {
4625 if (e.tabId != except.tabId && e.was_active) {
4626 e.was_active = false;
4633 getWasActive : function ()
4636 Roo.each(this.navItems, function(e) {
4651 Roo.apply(Roo.bootstrap.NavGroup, {
4655 * register a Navigation Group
4656 * @param {Roo.bootstrap.NavGroup} the navgroup to add
4658 register : function(navgrp)
4660 this.groups[navgrp.navId] = navgrp;
4664 * fetch a Navigation Group based on the navigation ID
4665 * @param {string} the navgroup to add
4666 * @returns {Roo.bootstrap.NavGroup} the navgroup
4668 get: function(navId) {
4669 if (typeof(this.groups[navId]) == 'undefined') {
4671 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
4673 return this.groups[navId] ;
4688 * @class Roo.bootstrap.NavItem
4689 * @extends Roo.bootstrap.Component
4690 * Bootstrap Navbar.NavItem class
4691 * @cfg {String} href link to
4692 * @cfg {String} button_weight (default | primary | secondary | success | info | warning | danger | link ) default none
4694 * @cfg {String} html content of button
4695 * @cfg {String} badge text inside badge
4696 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
4697 * @cfg {String} glyphicon DEPRICATED - use fa
4698 * @cfg {String} icon DEPRICATED - use fa
4699 * @cfg {String} fa - Fontawsome icon name (can add stuff to it like fa-2x)
4700 * @cfg {Boolean} active Is item active
4701 * @cfg {Boolean} disabled Is item disabled
4703 * @cfg {Boolean} preventDefault (true | false) default false
4704 * @cfg {String} tabId the tab that this item activates.
4705 * @cfg {String} tagtype (a|span) render as a href or span?
4706 * @cfg {Boolean} animateRef (true|false) link to element default false
4709 * Create a new Navbar Item
4710 * @param {Object} config The config object
4712 Roo.bootstrap.NavItem = function(config){
4713 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
4718 * The raw click event for the entire grid.
4719 * @param {Roo.EventObject} e
4724 * Fires when the active item active state changes
4725 * @param {Roo.bootstrap.NavItem} this
4726 * @param {boolean} state the new state
4732 * Fires when scroll to element
4733 * @param {Roo.bootstrap.NavItem} this
4734 * @param {Object} options
4735 * @param {Roo.EventObject} e
4743 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
4752 preventDefault : false,
4760 button_outline : false,
4764 getAutoCreate : function(){
4772 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
4774 if (this.disabled) {
4775 cfg.cls += ' disabled';
4779 if (this.button_weight.length) {
4780 cfg.tag = this.href ? 'a' : 'button';
4781 cfg.html = this.html || '';
4782 cfg.cls += ' btn btn' + (this.button_outline ? '-outline' : '') + '-' + this.button_weight;
4784 cfg.href = this.href;
4787 cfg.html = '<i class="fa fas fa-'+this.fa+'"></i> <span>' + this.html + '</span>';
4790 // menu .. should add dropdown-menu class - so no need for carat..
4792 if (this.badge !== '') {
4794 cfg.html += ' <span class="badge badge-secondary">' + this.badge + '</span>';
4799 if (this.href || this.html || this.glyphicon || this.icon || this.fa) {
4803 href : this.href || "#",
4804 html: this.html || ''
4807 if (this.tagtype == 'a') {
4808 cfg.cn[0].cls = 'nav-link';
4811 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>';
4814 cfg.cn[0].html = '<i class="fa fas fa-'+this.fa+'"></i> <span>' + cfg.cn[0].html + '</span>';
4816 if(this.glyphicon) {
4817 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
4822 cfg.cn[0].html += " <span class='caret'></span>";
4826 if (this.badge !== '') {
4828 cfg.cn[0].html += ' <span class="badge badge-secondary">' + this.badge + '</span>';
4836 onRender : function(ct, position)
4838 // Roo.log("Call onRender: " + this.xtype);
4839 if (Roo.bootstrap.version == 4 && ct.dom.type != 'ul') {
4843 var ret = Roo.bootstrap.NavItem.superclass.onRender.call(this, ct, position);
4844 this.navLink = this.el.select('.nav-link',true).first();
4849 initEvents: function()
4851 if (typeof (this.menu) != 'undefined') {
4852 this.menu.parentType = this.xtype;
4853 this.menu.triggerEl = this.el;
4854 this.menu = this.addxtype(Roo.apply({}, this.menu));
4857 this.el.select('a',true).on('click', this.onClick, this);
4859 if(this.tagtype == 'span'){
4860 this.el.select('span',true).on('click', this.onClick, this);
4863 // at this point parent should be available..
4864 this.parent().register(this);
4867 onClick : function(e)
4869 if (e.getTarget('.dropdown-menu-item')) {
4870 // did you click on a menu itemm.... - then don't trigger onclick..
4875 this.preventDefault ||
4878 Roo.log("NavItem - prevent Default?");
4882 if (this.disabled) {
4886 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4887 if (tg && tg.transition) {
4888 Roo.log("waiting for the transitionend");
4894 //Roo.log("fire event clicked");
4895 if(this.fireEvent('click', this, e) === false){
4899 if(this.tagtype == 'span'){
4903 //Roo.log(this.href);
4904 var ael = this.el.select('a',true).first();
4907 if(ael && this.animateRef && this.href.indexOf('#') > -1){
4908 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4909 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4910 return; // ignore... - it's a 'hash' to another page.
4912 Roo.log("NavItem - prevent Default?");
4914 this.scrollToElement(e);
4918 var p = this.parent();
4920 if (['tabs','pills'].indexOf(p.type)!==-1) {
4921 if (typeof(p.setActiveItem) !== 'undefined') {
4922 p.setActiveItem(this);
4926 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4927 if (p.parentType == 'NavHeaderbar' && !this.menu) {
4928 // remove the collapsed menu expand...
4929 p.parent().el.select('.roo-navbar-collapse',true).removeClass('in');
4933 isActive: function () {
4936 setActive : function(state, fire, is_was_active)
4938 if (this.active && !state && this.navId) {
4939 this.was_active = true;
4940 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4942 nv.clearWasActive(this);
4946 this.active = state;
4949 this.el.removeClass('active');
4950 this.navLink ? this.navLink.removeClass('active') : false;
4951 } else if (!this.el.hasClass('active')) {
4953 this.el.addClass('active');
4954 if (Roo.bootstrap.version == 4 && this.navLink ) {
4955 this.navLink.addClass('active');
4960 this.fireEvent('changed', this, state);
4963 // show a panel if it's registered and related..
4965 if (!this.navId || !this.tabId || !state || is_was_active) {
4969 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4973 var pan = tg.getPanelByName(this.tabId);
4977 // if we can not flip to new panel - go back to old nav highlight..
4978 if (false == tg.showPanel(pan)) {
4979 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4981 var onav = nv.getWasActive();
4983 onav.setActive(true, false, true);
4992 // this should not be here...
4993 setDisabled : function(state)
4995 this.disabled = state;
4997 this.el.removeClass('disabled');
4998 } else if (!this.el.hasClass('disabled')) {
4999 this.el.addClass('disabled');
5005 * Fetch the element to display the tooltip on.
5006 * @return {Roo.Element} defaults to this.el
5008 tooltipEl : function()
5010 return this.el.select('' + this.tagtype + '', true).first();
5013 scrollToElement : function(e)
5015 var c = document.body;
5018 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
5020 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
5021 c = document.documentElement;
5024 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
5030 var o = target.calcOffsetsTo(c);
5037 this.fireEvent('scrollto', this, options, e);
5039 Roo.get(c).scrollTo('top', options.value, true);
5052 * <span> icon </span>
5053 * <span> text </span>
5054 * <span>badge </span>
5058 * @class Roo.bootstrap.NavSidebarItem
5059 * @extends Roo.bootstrap.NavItem
5060 * Bootstrap Navbar.NavSidebarItem class
5061 * {String} badgeWeight (default|primary|success|info|warning|danger)the extra classes for the badge
5062 * {Boolean} open is the menu open
5063 * {Boolean} buttonView use button as the tigger el rather that a (default false)
5064 * {String} buttonWeight (default|primary|success|info|warning|danger)the extra classes for the button
5065 * {String} buttonSize (sm|md|lg)the extra classes for the button
5066 * {Boolean} showArrow show arrow next to the text (default true)
5068 * Create a new Navbar Button
5069 * @param {Object} config The config object
5071 Roo.bootstrap.NavSidebarItem = function(config){
5072 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
5077 * The raw click event for the entire grid.
5078 * @param {Roo.EventObject} e
5083 * Fires when the active item active state changes
5084 * @param {Roo.bootstrap.NavSidebarItem} this
5085 * @param {boolean} state the new state
5093 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
5095 badgeWeight : 'default',
5101 buttonWeight : 'default',
5107 getAutoCreate : function(){
5112 href : this.href || '#',
5118 if(this.buttonView){
5121 href : this.href || '#',
5122 cls: 'btn btn-' + this.buttonWeight + ' btn-' + this.buttonSize + 'roo-button-dropdown-toggle',
5135 cfg.cls += ' active';
5138 if (this.disabled) {
5139 cfg.cls += ' disabled';
5142 cfg.cls += ' open x-open';
5145 if (this.glyphicon || this.icon) {
5146 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
5147 a.cn.push({ tag : 'i', cls : c }) ;
5150 if(!this.buttonView){
5153 html : this.html || ''
5160 if (this.badge !== '') {
5161 a.cn.push({ tag: 'span', cls : 'badge pull-right badge-' + this.badgeWeight, html: this.badge });
5167 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
5170 a.cls += ' dropdown-toggle treeview' ;
5176 initEvents : function()
5178 if (typeof (this.menu) != 'undefined') {
5179 this.menu.parentType = this.xtype;
5180 this.menu.triggerEl = this.el;
5181 this.menu = this.addxtype(Roo.apply({}, this.menu));
5184 this.el.on('click', this.onClick, this);
5186 if(this.badge !== ''){
5187 this.badgeEl = this.el.select('.badge', true).first().setVisibilityMode(Roo.Element.DISPLAY);
5192 onClick : function(e)
5199 if(this.preventDefault){
5203 this.fireEvent('click', this, e);
5206 disable : function()
5208 this.setDisabled(true);
5213 this.setDisabled(false);
5216 setDisabled : function(state)
5218 if(this.disabled == state){
5222 this.disabled = state;
5225 this.el.addClass('disabled');
5229 this.el.removeClass('disabled');
5234 setActive : function(state)
5236 if(this.active == state){
5240 this.active = state;
5243 this.el.addClass('active');
5247 this.el.removeClass('active');
5252 isActive: function ()
5257 setBadge : function(str)
5263 this.badgeEl.dom.innerHTML = str;
5280 * @class Roo.bootstrap.Row
5281 * @extends Roo.bootstrap.Component
5282 * Bootstrap Row class (contains columns...)
5286 * @param {Object} config The config object
5289 Roo.bootstrap.Row = function(config){
5290 Roo.bootstrap.Row.superclass.constructor.call(this, config);
5293 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
5295 getAutoCreate : function(){
5314 * @class Roo.bootstrap.Element
5315 * @extends Roo.bootstrap.Component
5316 * Bootstrap Element class
5317 * @cfg {String} html contents of the element
5318 * @cfg {String} tag tag of the element
5319 * @cfg {String} cls class of the element
5320 * @cfg {Boolean} preventDefault (true|false) default false
5321 * @cfg {Boolean} clickable (true|false) default false
5324 * Create a new Element
5325 * @param {Object} config The config object
5328 Roo.bootstrap.Element = function(config){
5329 Roo.bootstrap.Element.superclass.constructor.call(this, config);
5335 * When a element is chick
5336 * @param {Roo.bootstrap.Element} this
5337 * @param {Roo.EventObject} e
5343 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
5348 preventDefault: false,
5351 getAutoCreate : function(){
5355 // cls: this.cls, double assign in parent class Component.js :: onRender
5362 initEvents: function()
5364 Roo.bootstrap.Element.superclass.initEvents.call(this);
5367 this.el.on('click', this.onClick, this);
5372 onClick : function(e)
5374 if(this.preventDefault){
5378 this.fireEvent('click', this, e);
5381 getValue : function()
5383 return this.el.dom.innerHTML;
5386 setValue : function(value)
5388 this.el.dom.innerHTML = value;
5403 * @class Roo.bootstrap.Pagination
5404 * @extends Roo.bootstrap.Component
5405 * Bootstrap Pagination class
5406 * @cfg {String} size xs | sm | md | lg
5407 * @cfg {Boolean} inverse false | true
5410 * Create a new Pagination
5411 * @param {Object} config The config object
5414 Roo.bootstrap.Pagination = function(config){
5415 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
5418 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
5424 getAutoCreate : function(){
5430 cfg.cls += ' inverse';
5436 cfg.cls += " " + this.cls;
5454 * @class Roo.bootstrap.PaginationItem
5455 * @extends Roo.bootstrap.Component
5456 * Bootstrap PaginationItem class
5457 * @cfg {String} html text
5458 * @cfg {String} href the link
5459 * @cfg {Boolean} preventDefault (true | false) default true
5460 * @cfg {Boolean} active (true | false) default false
5461 * @cfg {Boolean} disabled default false
5465 * Create a new PaginationItem
5466 * @param {Object} config The config object
5470 Roo.bootstrap.PaginationItem = function(config){
5471 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
5476 * The raw click event for the entire grid.
5477 * @param {Roo.EventObject} e
5483 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
5487 preventDefault: true,
5492 getAutoCreate : function(){
5498 href : this.href ? this.href : '#',
5499 html : this.html ? this.html : ''
5509 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
5513 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
5519 initEvents: function() {
5521 this.el.on('click', this.onClick, this);
5524 onClick : function(e)
5526 Roo.log('PaginationItem on click ');
5527 if(this.preventDefault){
5535 this.fireEvent('click', this, e);
5551 * @class Roo.bootstrap.Slider
5552 * @extends Roo.bootstrap.Component
5553 * Bootstrap Slider class
5556 * Create a new Slider
5557 * @param {Object} config The config object
5560 Roo.bootstrap.Slider = function(config){
5561 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
5564 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
5566 getAutoCreate : function(){
5570 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
5574 cls: 'ui-slider-handle ui-state-default ui-corner-all'
5586 * Ext JS Library 1.1.1
5587 * Copyright(c) 2006-2007, Ext JS, LLC.
5589 * Originally Released Under LGPL - original licence link has changed is not relivant.
5592 * <script type="text/javascript">
5597 * @class Roo.grid.ColumnModel
5598 * @extends Roo.util.Observable
5599 * This is the default implementation of a ColumnModel used by the Grid. It defines
5600 * the columns in the grid.
5603 var colModel = new Roo.grid.ColumnModel([
5604 {header: "Ticker", width: 60, sortable: true, locked: true},
5605 {header: "Company Name", width: 150, sortable: true},
5606 {header: "Market Cap.", width: 100, sortable: true},
5607 {header: "$ Sales", width: 100, sortable: true, renderer: money},
5608 {header: "Employees", width: 100, sortable: true, resizable: false}
5613 * The config options listed for this class are options which may appear in each
5614 * individual column definition.
5615 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
5617 * @param {Object} config An Array of column config objects. See this class's
5618 * config objects for details.
5620 Roo.grid.ColumnModel = function(config){
5622 * The config passed into the constructor
5624 this.config = config;
5627 // if no id, create one
5628 // if the column does not have a dataIndex mapping,
5629 // map it to the order it is in the config
5630 for(var i = 0, len = config.length; i < len; i++){
5632 if(typeof c.dataIndex == "undefined"){
5635 if(typeof c.renderer == "string"){
5636 c.renderer = Roo.util.Format[c.renderer];
5638 if(typeof c.id == "undefined"){
5641 if(c.editor && c.editor.xtype){
5642 c.editor = Roo.factory(c.editor, Roo.grid);
5644 if(c.editor && c.editor.isFormField){
5645 c.editor = new Roo.grid.GridEditor(c.editor);
5647 this.lookup[c.id] = c;
5651 * The width of columns which have no width specified (defaults to 100)
5654 this.defaultWidth = 100;
5657 * Default sortable of columns which have no sortable specified (defaults to false)
5660 this.defaultSortable = false;
5664 * @event widthchange
5665 * Fires when the width of a column changes.
5666 * @param {ColumnModel} this
5667 * @param {Number} columnIndex The column index
5668 * @param {Number} newWidth The new width
5670 "widthchange": true,
5672 * @event headerchange
5673 * Fires when the text of a header changes.
5674 * @param {ColumnModel} this
5675 * @param {Number} columnIndex The column index
5676 * @param {Number} newText The new header text
5678 "headerchange": true,
5680 * @event hiddenchange
5681 * Fires when a column is hidden or "unhidden".
5682 * @param {ColumnModel} this
5683 * @param {Number} columnIndex The column index
5684 * @param {Boolean} hidden true if hidden, false otherwise
5686 "hiddenchange": true,
5688 * @event columnmoved
5689 * Fires when a column is moved.
5690 * @param {ColumnModel} this
5691 * @param {Number} oldIndex
5692 * @param {Number} newIndex
5694 "columnmoved" : true,
5696 * @event columlockchange
5697 * Fires when a column's locked state is changed
5698 * @param {ColumnModel} this
5699 * @param {Number} colIndex
5700 * @param {Boolean} locked true if locked
5702 "columnlockchange" : true
5704 Roo.grid.ColumnModel.superclass.constructor.call(this);
5706 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
5708 * @cfg {String} header The header text to display in the Grid view.
5711 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
5712 * {@link Roo.data.Record} definition from which to draw the column's value. If not
5713 * specified, the column's index is used as an index into the Record's data Array.
5716 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
5717 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
5720 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
5721 * Defaults to the value of the {@link #defaultSortable} property.
5722 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
5725 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
5728 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
5731 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
5734 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
5737 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
5738 * given the cell's data value. See {@link #setRenderer}. If not specified, the
5739 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
5740 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
5743 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
5746 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
5749 * @cfg {String} valign (Optional) Set the CSS vertical-align property of the column (eg. middle, top, bottom etc). Defaults to undefined.
5752 * @cfg {String} cursor (Optional)
5755 * @cfg {String} tooltip (Optional)
5758 * @cfg {Number} xs (Optional)
5761 * @cfg {Number} sm (Optional)
5764 * @cfg {Number} md (Optional)
5767 * @cfg {Number} lg (Optional)
5770 * Returns the id of the column at the specified index.
5771 * @param {Number} index The column index
5772 * @return {String} the id
5774 getColumnId : function(index){
5775 return this.config[index].id;
5779 * Returns the column for a specified id.
5780 * @param {String} id The column id
5781 * @return {Object} the column
5783 getColumnById : function(id){
5784 return this.lookup[id];
5789 * Returns the column for a specified dataIndex.
5790 * @param {String} dataIndex The column dataIndex
5791 * @return {Object|Boolean} the column or false if not found
5793 getColumnByDataIndex: function(dataIndex){
5794 var index = this.findColumnIndex(dataIndex);
5795 return index > -1 ? this.config[index] : false;
5799 * Returns the index for a specified column id.
5800 * @param {String} id The column id
5801 * @return {Number} the index, or -1 if not found
5803 getIndexById : function(id){
5804 for(var i = 0, len = this.config.length; i < len; i++){
5805 if(this.config[i].id == id){
5813 * Returns the index for a specified column dataIndex.
5814 * @param {String} dataIndex The column dataIndex
5815 * @return {Number} the index, or -1 if not found
5818 findColumnIndex : function(dataIndex){
5819 for(var i = 0, len = this.config.length; i < len; i++){
5820 if(this.config[i].dataIndex == dataIndex){
5828 moveColumn : function(oldIndex, newIndex){
5829 var c = this.config[oldIndex];
5830 this.config.splice(oldIndex, 1);
5831 this.config.splice(newIndex, 0, c);
5832 this.dataMap = null;
5833 this.fireEvent("columnmoved", this, oldIndex, newIndex);
5836 isLocked : function(colIndex){
5837 return this.config[colIndex].locked === true;
5840 setLocked : function(colIndex, value, suppressEvent){
5841 if(this.isLocked(colIndex) == value){
5844 this.config[colIndex].locked = value;
5846 this.fireEvent("columnlockchange", this, colIndex, value);
5850 getTotalLockedWidth : function(){
5852 for(var i = 0; i < this.config.length; i++){
5853 if(this.isLocked(i) && !this.isHidden(i)){
5854 this.totalWidth += this.getColumnWidth(i);
5860 getLockedCount : function(){
5861 for(var i = 0, len = this.config.length; i < len; i++){
5862 if(!this.isLocked(i)){
5867 return this.config.length;
5871 * Returns the number of columns.
5874 getColumnCount : function(visibleOnly){
5875 if(visibleOnly === true){
5877 for(var i = 0, len = this.config.length; i < len; i++){
5878 if(!this.isHidden(i)){
5884 return this.config.length;
5888 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
5889 * @param {Function} fn
5890 * @param {Object} scope (optional)
5891 * @return {Array} result
5893 getColumnsBy : function(fn, scope){
5895 for(var i = 0, len = this.config.length; i < len; i++){
5896 var c = this.config[i];
5897 if(fn.call(scope||this, c, i) === true){
5905 * Returns true if the specified column is sortable.
5906 * @param {Number} col The column index
5909 isSortable : function(col){
5910 if(typeof this.config[col].sortable == "undefined"){
5911 return this.defaultSortable;
5913 return this.config[col].sortable;
5917 * Returns the rendering (formatting) function defined for the column.
5918 * @param {Number} col The column index.
5919 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
5921 getRenderer : function(col){
5922 if(!this.config[col].renderer){
5923 return Roo.grid.ColumnModel.defaultRenderer;
5925 return this.config[col].renderer;
5929 * Sets the rendering (formatting) function for a column.
5930 * @param {Number} col The column index
5931 * @param {Function} fn The function to use to process the cell's raw data
5932 * to return HTML markup for the grid view. The render function is called with
5933 * the following parameters:<ul>
5934 * <li>Data value.</li>
5935 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
5936 * <li>css A CSS style string to apply to the table cell.</li>
5937 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
5938 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
5939 * <li>Row index</li>
5940 * <li>Column index</li>
5941 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
5943 setRenderer : function(col, fn){
5944 this.config[col].renderer = fn;
5948 * Returns the width for the specified column.
5949 * @param {Number} col The column index
5952 getColumnWidth : function(col){
5953 return this.config[col].width * 1 || this.defaultWidth;
5957 * Sets the width for a column.
5958 * @param {Number} col The column index
5959 * @param {Number} width The new width
5961 setColumnWidth : function(col, width, suppressEvent){
5962 this.config[col].width = width;
5963 this.totalWidth = null;
5965 this.fireEvent("widthchange", this, col, width);
5970 * Returns the total width of all columns.
5971 * @param {Boolean} includeHidden True to include hidden column widths
5974 getTotalWidth : function(includeHidden){
5975 if(!this.totalWidth){
5976 this.totalWidth = 0;
5977 for(var i = 0, len = this.config.length; i < len; i++){
5978 if(includeHidden || !this.isHidden(i)){
5979 this.totalWidth += this.getColumnWidth(i);
5983 return this.totalWidth;
5987 * Returns the header for the specified column.
5988 * @param {Number} col The column index
5991 getColumnHeader : function(col){
5992 return this.config[col].header;
5996 * Sets the header for a column.
5997 * @param {Number} col The column index
5998 * @param {String} header The new header
6000 setColumnHeader : function(col, header){
6001 this.config[col].header = header;
6002 this.fireEvent("headerchange", this, col, header);
6006 * Returns the tooltip for the specified column.
6007 * @param {Number} col The column index
6010 getColumnTooltip : function(col){
6011 return this.config[col].tooltip;
6014 * Sets the tooltip for a column.
6015 * @param {Number} col The column index
6016 * @param {String} tooltip The new tooltip
6018 setColumnTooltip : function(col, tooltip){
6019 this.config[col].tooltip = tooltip;
6023 * Returns the dataIndex for the specified column.
6024 * @param {Number} col The column index
6027 getDataIndex : function(col){
6028 return this.config[col].dataIndex;
6032 * Sets the dataIndex for a column.
6033 * @param {Number} col The column index
6034 * @param {Number} dataIndex The new dataIndex
6036 setDataIndex : function(col, dataIndex){
6037 this.config[col].dataIndex = dataIndex;
6043 * Returns true if the cell is editable.
6044 * @param {Number} colIndex The column index
6045 * @param {Number} rowIndex The row index - this is nto actually used..?
6048 isCellEditable : function(colIndex, rowIndex){
6049 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
6053 * Returns the editor defined for the cell/column.
6054 * return false or null to disable editing.
6055 * @param {Number} colIndex The column index
6056 * @param {Number} rowIndex The row index
6059 getCellEditor : function(colIndex, rowIndex){
6060 return this.config[colIndex].editor;
6064 * Sets if a column is editable.
6065 * @param {Number} col The column index
6066 * @param {Boolean} editable True if the column is editable
6068 setEditable : function(col, editable){
6069 this.config[col].editable = editable;
6074 * Returns true if the column is hidden.
6075 * @param {Number} colIndex The column index
6078 isHidden : function(colIndex){
6079 return this.config[colIndex].hidden;
6084 * Returns true if the column width cannot be changed
6086 isFixed : function(colIndex){
6087 return this.config[colIndex].fixed;
6091 * Returns true if the column can be resized
6094 isResizable : function(colIndex){
6095 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
6098 * Sets if a column is hidden.
6099 * @param {Number} colIndex The column index
6100 * @param {Boolean} hidden True if the column is hidden
6102 setHidden : function(colIndex, hidden){
6103 this.config[colIndex].hidden = hidden;
6104 this.totalWidth = null;
6105 this.fireEvent("hiddenchange", this, colIndex, hidden);
6109 * Sets the editor for a column.
6110 * @param {Number} col The column index
6111 * @param {Object} editor The editor object
6113 setEditor : function(col, editor){
6114 this.config[col].editor = editor;
6118 Roo.grid.ColumnModel.defaultRenderer = function(value)
6120 if(typeof value == "object") {
6123 if(typeof value == "string" && value.length < 1){
6127 return String.format("{0}", value);
6130 // Alias for backwards compatibility
6131 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
6134 * Ext JS Library 1.1.1
6135 * Copyright(c) 2006-2007, Ext JS, LLC.
6137 * Originally Released Under LGPL - original licence link has changed is not relivant.
6140 * <script type="text/javascript">
6144 * @class Roo.LoadMask
6145 * A simple utility class for generically masking elements while loading data. If the element being masked has
6146 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
6147 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
6148 * element's UpdateManager load indicator and will be destroyed after the initial load.
6150 * Create a new LoadMask
6151 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
6152 * @param {Object} config The config object
6154 Roo.LoadMask = function(el, config){
6155 this.el = Roo.get(el);
6156 Roo.apply(this, config);
6158 this.store.on('beforeload', this.onBeforeLoad, this);
6159 this.store.on('load', this.onLoad, this);
6160 this.store.on('loadexception', this.onLoadException, this);
6161 this.removeMask = false;
6163 var um = this.el.getUpdateManager();
6164 um.showLoadIndicator = false; // disable the default indicator
6165 um.on('beforeupdate', this.onBeforeLoad, this);
6166 um.on('update', this.onLoad, this);
6167 um.on('failure', this.onLoad, this);
6168 this.removeMask = true;
6172 Roo.LoadMask.prototype = {
6174 * @cfg {Boolean} removeMask
6175 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
6176 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
6180 * The text to display in a centered loading message box (defaults to 'Loading...')
6184 * @cfg {String} msgCls
6185 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
6187 msgCls : 'x-mask-loading',
6190 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
6196 * Disables the mask to prevent it from being displayed
6198 disable : function(){
6199 this.disabled = true;
6203 * Enables the mask so that it can be displayed
6205 enable : function(){
6206 this.disabled = false;
6209 onLoadException : function()
6213 if (typeof(arguments[3]) != 'undefined') {
6214 Roo.MessageBox.alert("Error loading",arguments[3]);
6218 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
6219 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
6226 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
6231 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
6235 onBeforeLoad : function(){
6237 (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
6242 destroy : function(){
6244 this.store.un('beforeload', this.onBeforeLoad, this);
6245 this.store.un('load', this.onLoad, this);
6246 this.store.un('loadexception', this.onLoadException, this);
6248 var um = this.el.getUpdateManager();
6249 um.un('beforeupdate', this.onBeforeLoad, this);
6250 um.un('update', this.onLoad, this);
6251 um.un('failure', this.onLoad, this);
6262 * @class Roo.bootstrap.Table
6263 * @extends Roo.bootstrap.Component
6264 * Bootstrap Table class
6265 * @cfg {String} cls table class
6266 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
6267 * @cfg {String} bgcolor Specifies the background color for a table
6268 * @cfg {Number} border Specifies whether the table cells should have borders or not
6269 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
6270 * @cfg {Number} cellspacing Specifies the space between cells
6271 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
6272 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
6273 * @cfg {String} sortable Specifies that the table should be sortable
6274 * @cfg {String} summary Specifies a summary of the content of a table
6275 * @cfg {Number} width Specifies the width of a table
6276 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
6278 * @cfg {boolean} striped Should the rows be alternative striped
6279 * @cfg {boolean} bordered Add borders to the table
6280 * @cfg {boolean} hover Add hover highlighting
6281 * @cfg {boolean} condensed Format condensed
6282 * @cfg {boolean} responsive Format condensed
6283 * @cfg {Boolean} loadMask (true|false) default false
6284 * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
6285 * @cfg {Boolean} headerShow (true|false) generate thead, default true
6286 * @cfg {Boolean} rowSelection (true|false) default false
6287 * @cfg {Boolean} cellSelection (true|false) default false
6288 * @cfg {Boolean} scrollBody (true|false) default false - body scrolled / fixed header
6289 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
6290 * @cfg {Boolean} lazyLoad auto load data while scrolling to the end (default false)
6291 * @cfg {Boolean} auto_hide_footer auto hide footer if only one page (default false)
6295 * Create a new Table
6296 * @param {Object} config The config object
6299 Roo.bootstrap.Table = function(config){
6300 Roo.bootstrap.Table.superclass.constructor.call(this, config);
6305 this.rowSelection = (typeof(config.rowSelection) != 'undefined') ? config.rowSelection : this.rowSelection;
6306 this.cellSelection = (typeof(config.cellSelection) != 'undefined') ? config.cellSelection : this.cellSelection;
6307 this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
6308 this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
6310 this.sm = this.sm || {xtype: 'RowSelectionModel'};
6312 this.sm.grid = this;
6313 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
6314 this.sm = this.selModel;
6315 this.sm.xmodule = this.xmodule || false;
6318 if (this.cm && typeof(this.cm.config) == 'undefined') {
6319 this.colModel = new Roo.grid.ColumnModel(this.cm);
6320 this.cm = this.colModel;
6321 this.cm.xmodule = this.xmodule || false;
6324 this.store= Roo.factory(this.store, Roo.data);
6325 this.ds = this.store;
6326 this.ds.xmodule = this.xmodule || false;
6329 if (this.footer && this.store) {
6330 this.footer.dataSource = this.ds;
6331 this.footer = Roo.factory(this.footer);
6338 * Fires when a cell is clicked
6339 * @param {Roo.bootstrap.Table} this
6340 * @param {Roo.Element} el
6341 * @param {Number} rowIndex
6342 * @param {Number} columnIndex
6343 * @param {Roo.EventObject} e
6347 * @event celldblclick
6348 * Fires when a cell is double clicked
6349 * @param {Roo.bootstrap.Table} this
6350 * @param {Roo.Element} el
6351 * @param {Number} rowIndex
6352 * @param {Number} columnIndex
6353 * @param {Roo.EventObject} e
6355 "celldblclick" : true,
6358 * Fires when a row is clicked
6359 * @param {Roo.bootstrap.Table} this
6360 * @param {Roo.Element} el
6361 * @param {Number} rowIndex
6362 * @param {Roo.EventObject} e
6366 * @event rowdblclick
6367 * Fires when a row is double clicked
6368 * @param {Roo.bootstrap.Table} this
6369 * @param {Roo.Element} el
6370 * @param {Number} rowIndex
6371 * @param {Roo.EventObject} e
6373 "rowdblclick" : true,
6376 * Fires when a mouseover occur
6377 * @param {Roo.bootstrap.Table} this
6378 * @param {Roo.Element} el
6379 * @param {Number} rowIndex
6380 * @param {Number} columnIndex
6381 * @param {Roo.EventObject} e
6386 * Fires when a mouseout occur
6387 * @param {Roo.bootstrap.Table} this
6388 * @param {Roo.Element} el
6389 * @param {Number} rowIndex
6390 * @param {Number} columnIndex
6391 * @param {Roo.EventObject} e
6396 * Fires when a row is rendered, so you can change add a style to it.
6397 * @param {Roo.bootstrap.Table} this
6398 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
6402 * @event rowsrendered
6403 * Fires when all the rows have been rendered
6404 * @param {Roo.bootstrap.Table} this
6406 'rowsrendered' : true,
6408 * @event contextmenu
6409 * The raw contextmenu event for the entire grid.
6410 * @param {Roo.EventObject} e
6412 "contextmenu" : true,
6414 * @event rowcontextmenu
6415 * Fires when a row is right clicked
6416 * @param {Roo.bootstrap.Table} this
6417 * @param {Number} rowIndex
6418 * @param {Roo.EventObject} e
6420 "rowcontextmenu" : true,
6422 * @event cellcontextmenu
6423 * Fires when a cell is right clicked
6424 * @param {Roo.bootstrap.Table} this
6425 * @param {Number} rowIndex
6426 * @param {Number} cellIndex
6427 * @param {Roo.EventObject} e
6429 "cellcontextmenu" : true,
6431 * @event headercontextmenu
6432 * Fires when a header is right clicked
6433 * @param {Roo.bootstrap.Table} this
6434 * @param {Number} columnIndex
6435 * @param {Roo.EventObject} e
6437 "headercontextmenu" : true
6441 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
6467 rowSelection : false,
6468 cellSelection : false,
6471 // Roo.Element - the tbody
6473 // Roo.Element - thead element
6476 container: false, // used by gridpanel...
6482 auto_hide_footer : false,
6484 getAutoCreate : function()
6486 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
6493 if (this.scrollBody) {
6494 cfg.cls += ' table-body-fixed';
6497 cfg.cls += ' table-striped';
6501 cfg.cls += ' table-hover';
6503 if (this.bordered) {
6504 cfg.cls += ' table-bordered';
6506 if (this.condensed) {
6507 cfg.cls += ' table-condensed';
6509 if (this.responsive) {
6510 cfg.cls += ' table-responsive';
6514 cfg.cls+= ' ' +this.cls;
6517 // this lot should be simplifed...
6530 ].forEach(function(k) {
6538 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
6541 if(this.store || this.cm){
6542 if(this.headerShow){
6543 cfg.cn.push(this.renderHeader());
6546 cfg.cn.push(this.renderBody());
6548 if(this.footerShow){
6549 cfg.cn.push(this.renderFooter());
6551 // where does this come from?
6552 //cfg.cls+= ' TableGrid';
6555 return { cn : [ cfg ] };
6558 initEvents : function()
6560 if(!this.store || !this.cm){
6563 if (this.selModel) {
6564 this.selModel.initEvents();
6568 //Roo.log('initEvents with ds!!!!');
6570 this.mainBody = this.el.select('tbody', true).first();
6571 this.mainHead = this.el.select('thead', true).first();
6572 this.mainFoot = this.el.select('tfoot', true).first();
6578 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6579 e.on('click', _this.sort, _this);
6582 this.mainBody.on("click", this.onClick, this);
6583 this.mainBody.on("dblclick", this.onDblClick, this);
6585 // why is this done????? = it breaks dialogs??
6586 //this.parent().el.setStyle('position', 'relative');
6590 this.footer.parentId = this.id;
6591 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
6594 this.el.select('tfoot tr td').first().addClass('hide');
6599 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
6602 this.store.on('load', this.onLoad, this);
6603 this.store.on('beforeload', this.onBeforeLoad, this);
6604 this.store.on('update', this.onUpdate, this);
6605 this.store.on('add', this.onAdd, this);
6606 this.store.on("clear", this.clear, this);
6608 this.el.on("contextmenu", this.onContextMenu, this);
6610 this.mainBody.on('scroll', this.onBodyScroll, this);
6612 this.cm.on("headerchange", this.onHeaderChange, this);
6614 this.cm.on("hiddenchange", this.onHiddenChange, this, arguments);
6618 onContextMenu : function(e, t)
6620 this.processEvent("contextmenu", e);
6623 processEvent : function(name, e)
6625 if (name != 'touchstart' ) {
6626 this.fireEvent(name, e);
6629 var t = e.getTarget();
6631 var cell = Roo.get(t);
6637 if(cell.findParent('tfoot', false, true)){
6641 if(cell.findParent('thead', false, true)){
6643 if(e.getTarget().nodeName.toLowerCase() != 'th'){
6644 cell = Roo.get(t).findParent('th', false, true);
6646 Roo.log("failed to find th in thead?");
6647 Roo.log(e.getTarget());
6652 var cellIndex = cell.dom.cellIndex;
6654 var ename = name == 'touchstart' ? 'click' : name;
6655 this.fireEvent("header" + ename, this, cellIndex, e);
6660 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6661 cell = Roo.get(t).findParent('td', false, true);
6663 Roo.log("failed to find th in tbody?");
6664 Roo.log(e.getTarget());
6669 var row = cell.findParent('tr', false, true);
6670 var cellIndex = cell.dom.cellIndex;
6671 var rowIndex = row.dom.rowIndex - 1;
6675 this.fireEvent("row" + name, this, rowIndex, e);
6679 this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
6685 onMouseover : function(e, el)
6687 var cell = Roo.get(el);
6693 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6694 cell = cell.findParent('td', false, true);
6697 var row = cell.findParent('tr', false, true);
6698 var cellIndex = cell.dom.cellIndex;
6699 var rowIndex = row.dom.rowIndex - 1; // start from 0
6701 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
6705 onMouseout : function(e, el)
6707 var cell = Roo.get(el);
6713 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6714 cell = cell.findParent('td', false, true);
6717 var row = cell.findParent('tr', false, true);
6718 var cellIndex = cell.dom.cellIndex;
6719 var rowIndex = row.dom.rowIndex - 1; // start from 0
6721 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
6725 onClick : function(e, el)
6727 var cell = Roo.get(el);
6729 if(!cell || (!this.cellSelection && !this.rowSelection)){
6733 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6734 cell = cell.findParent('td', false, true);
6737 if(!cell || typeof(cell) == 'undefined'){
6741 var row = cell.findParent('tr', false, true);
6743 if(!row || typeof(row) == 'undefined'){
6747 var cellIndex = cell.dom.cellIndex;
6748 var rowIndex = this.getRowIndex(row);
6750 // why??? - should these not be based on SelectionModel?
6751 if(this.cellSelection){
6752 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
6755 if(this.rowSelection){
6756 this.fireEvent('rowclick', this, row, rowIndex, e);
6762 onDblClick : function(e,el)
6764 var cell = Roo.get(el);
6766 if(!cell || (!this.cellSelection && !this.rowSelection)){
6770 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6771 cell = cell.findParent('td', false, true);
6774 if(!cell || typeof(cell) == 'undefined'){
6778 var row = cell.findParent('tr', false, true);
6780 if(!row || typeof(row) == 'undefined'){
6784 var cellIndex = cell.dom.cellIndex;
6785 var rowIndex = this.getRowIndex(row);
6787 if(this.cellSelection){
6788 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
6791 if(this.rowSelection){
6792 this.fireEvent('rowdblclick', this, row, rowIndex, e);
6796 sort : function(e,el)
6798 var col = Roo.get(el);
6800 if(!col.hasClass('sortable')){
6804 var sort = col.attr('sort');
6807 if(col.select('i', true).first().hasClass('glyphicon-arrow-up')){
6811 this.store.sortInfo = {field : sort, direction : dir};
6814 Roo.log("calling footer first");
6815 this.footer.onClick('first');
6818 this.store.load({ params : { start : 0 } });
6822 renderHeader : function()
6830 this.totalWidth = 0;
6832 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6834 var config = cm.config[i];
6838 cls : 'x-hcol-' + i,
6840 html: cm.getColumnHeader(i)
6845 if(typeof(config.sortable) != 'undefined' && config.sortable){
6847 c.html = '<i class="glyphicon"></i>' + c.html;
6850 // could use BS4 hidden-..-down
6852 if(typeof(config.lgHeader) != 'undefined'){
6853 hh += '<span class="hidden-xs hidden-sm hidden-md ">' + config.lgHeader + '</span>';
6856 if(typeof(config.mdHeader) != 'undefined'){
6857 hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
6860 if(typeof(config.smHeader) != 'undefined'){
6861 hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
6864 if(typeof(config.xsHeader) != 'undefined'){
6865 hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
6872 if(typeof(config.tooltip) != 'undefined'){
6873 c.tooltip = config.tooltip;
6876 if(typeof(config.colspan) != 'undefined'){
6877 c.colspan = config.colspan;
6880 if(typeof(config.hidden) != 'undefined' && config.hidden){
6881 c.style += ' display:none;';
6884 if(typeof(config.dataIndex) != 'undefined'){
6885 c.sort = config.dataIndex;
6890 if(typeof(config.align) != 'undefined' && config.align.length){
6891 c.style += ' text-align:' + config.align + ';';
6894 if(typeof(config.width) != 'undefined'){
6895 c.style += ' width:' + config.width + 'px;';
6896 this.totalWidth += config.width;
6898 this.totalWidth += 100; // assume minimum of 100 per column?
6901 if(typeof(config.cls) != 'undefined'){
6902 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
6905 ['xs','sm','md','lg'].map(function(size){
6907 if(typeof(config[size]) == 'undefined'){
6911 if (!config[size]) { // 0 = hidden
6912 // BS 4 '0' is treated as hide that column and below.
6913 c.cls += ' hidden-' + size + ' hidden' + size + '-down';
6917 c.cls += ' col-' + size + '-' + config[size] + (
6918 size == 'xs' ? (' col-' + config[size] ) : '' // bs4 col-{num} replaces col-xs
6930 renderBody : function()
6940 colspan : this.cm.getColumnCount()
6950 renderFooter : function()
6960 colspan : this.cm.getColumnCount()
6974 // Roo.log('ds onload');
6979 var ds = this.store;
6981 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6982 e.select('i', true).removeClass(['glyphicon-arrow-up', 'glyphicon-arrow-down']);
6983 if (_this.store.sortInfo) {
6985 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
6986 e.select('i', true).addClass(['glyphicon-arrow-up']);
6989 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
6990 e.select('i', true).addClass(['glyphicon-arrow-down']);
6995 var tbody = this.mainBody;
6997 if(ds.getCount() > 0){
6998 ds.data.each(function(d,rowIndex){
6999 var row = this.renderRow(cm, ds, rowIndex);
7001 tbody.createChild(row);
7005 if(row.cellObjects.length){
7006 Roo.each(row.cellObjects, function(r){
7007 _this.renderCellObject(r);
7014 var tfoot = this.el.select('tfoot', true).first();
7016 if(this.footerShow && this.auto_hide_footer && this.mainFoot){
7018 this.mainFoot.setVisibilityMode(Roo.Element.DISPLAY).hide();
7020 var total = this.ds.getTotalCount();
7022 if(this.footer.pageSize < total){
7023 this.mainFoot.show();
7027 Roo.each(this.el.select('tbody td', true).elements, function(e){
7028 e.on('mouseover', _this.onMouseover, _this);
7031 Roo.each(this.el.select('tbody td', true).elements, function(e){
7032 e.on('mouseout', _this.onMouseout, _this);
7034 this.fireEvent('rowsrendered', this);
7040 onUpdate : function(ds,record)
7042 this.refreshRow(record);
7046 onRemove : function(ds, record, index, isUpdate){
7047 if(isUpdate !== true){
7048 this.fireEvent("beforerowremoved", this, index, record);
7050 var bt = this.mainBody.dom;
7052 var rows = this.el.select('tbody > tr', true).elements;
7054 if(typeof(rows[index]) != 'undefined'){
7055 bt.removeChild(rows[index].dom);
7058 // if(bt.rows[index]){
7059 // bt.removeChild(bt.rows[index]);
7062 if(isUpdate !== true){
7063 //this.stripeRows(index);
7064 //this.syncRowHeights(index, index);
7066 this.fireEvent("rowremoved", this, index, record);
7070 onAdd : function(ds, records, rowIndex)
7072 //Roo.log('on Add called');
7073 // - note this does not handle multiple adding very well..
7074 var bt = this.mainBody.dom;
7075 for (var i =0 ; i < records.length;i++) {
7076 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
7077 //Roo.log(records[i]);
7078 //Roo.log(this.store.getAt(rowIndex+i));
7079 this.insertRow(this.store, rowIndex + i, false);
7086 refreshRow : function(record){
7087 var ds = this.store, index;
7088 if(typeof record == 'number'){
7090 record = ds.getAt(index);
7092 index = ds.indexOf(record);
7094 this.insertRow(ds, index, true);
7096 this.onRemove(ds, record, index+1, true);
7098 //this.syncRowHeights(index, index);
7100 this.fireEvent("rowupdated", this, index, record);
7103 insertRow : function(dm, rowIndex, isUpdate){
7106 this.fireEvent("beforerowsinserted", this, rowIndex);
7108 //var s = this.getScrollState();
7109 var row = this.renderRow(this.cm, this.store, rowIndex);
7110 // insert before rowIndex..
7111 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
7115 if(row.cellObjects.length){
7116 Roo.each(row.cellObjects, function(r){
7117 _this.renderCellObject(r);
7122 this.fireEvent("rowsinserted", this, rowIndex);
7123 //this.syncRowHeights(firstRow, lastRow);
7124 //this.stripeRows(firstRow);
7131 getRowDom : function(rowIndex)
7133 var rows = this.el.select('tbody > tr', true).elements;
7135 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
7138 // returns the object tree for a tr..
7141 renderRow : function(cm, ds, rowIndex)
7143 var d = ds.getAt(rowIndex);
7147 cls : 'x-row-' + rowIndex,
7151 var cellObjects = [];
7153 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
7154 var config = cm.config[i];
7156 var renderer = cm.getRenderer(i);
7160 if(typeof(renderer) !== 'undefined'){
7161 value = renderer(d.data[cm.getDataIndex(i)], false, d);
7163 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
7164 // and are rendered into the cells after the row is rendered - using the id for the element.
7166 if(typeof(value) === 'object'){
7176 rowIndex : rowIndex,
7181 this.fireEvent('rowclass', this, rowcfg);
7185 cls : rowcfg.rowClass + ' x-col-' + i,
7187 html: (typeof(value) === 'object') ? '' : value
7194 if(typeof(config.colspan) != 'undefined'){
7195 td.colspan = config.colspan;
7198 if(typeof(config.hidden) != 'undefined' && config.hidden){
7199 td.style += ' display:none;';
7202 if(typeof(config.align) != 'undefined' && config.align.length){
7203 td.style += ' text-align:' + config.align + ';';
7205 if(typeof(config.valign) != 'undefined' && config.valign.length){
7206 td.style += ' vertical-align:' + config.valign + ';';
7209 if(typeof(config.width) != 'undefined'){
7210 td.style += ' width:' + config.width + 'px;';
7213 if(typeof(config.cursor) != 'undefined'){
7214 td.style += ' cursor:' + config.cursor + ';';
7217 if(typeof(config.cls) != 'undefined'){
7218 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
7221 ['xs','sm','md','lg'].map(function(size){
7223 if(typeof(config[size]) == 'undefined'){
7229 if (!config[size]) { // 0 = hidden
7230 // BS 4 '0' is treated as hide that column and below.
7231 td.cls += ' hidden-' + size + ' hidden' + size + '-down';
7235 td.cls += ' col-' + size + '-' + config[size] + (
7236 size == 'xs' ? (' col-' + config[size] ) : '' // bs4 col-{num} replaces col-xs
7246 row.cellObjects = cellObjects;
7254 onBeforeLoad : function()
7263 this.el.select('tbody', true).first().dom.innerHTML = '';
7266 * Show or hide a row.
7267 * @param {Number} rowIndex to show or hide
7268 * @param {Boolean} state hide
7270 setRowVisibility : function(rowIndex, state)
7272 var bt = this.mainBody.dom;
7274 var rows = this.el.select('tbody > tr', true).elements;
7276 if(typeof(rows[rowIndex]) == 'undefined'){
7279 rows[rowIndex].dom.style.display = state ? '' : 'none';
7283 getSelectionModel : function(){
7285 this.selModel = new Roo.bootstrap.Table.RowSelectionModel({grid: this});
7287 return this.selModel;
7290 * Render the Roo.bootstrap object from renderder
7292 renderCellObject : function(r)
7296 r.cfg.parentId = (typeof(r.container) == 'string') ? r.container : r.container.id;
7298 var t = r.cfg.render(r.container);
7301 Roo.each(r.cfg.cn, function(c){
7303 container: t.getChildContainer(),
7306 _this.renderCellObject(child);
7311 getRowIndex : function(row)
7315 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
7326 * Returns the grid's underlying element = used by panel.Grid
7327 * @return {Element} The element
7329 getGridEl : function(){
7333 * Forces a resize - used by panel.Grid
7334 * @return {Element} The element
7336 autoSize : function()
7338 //var ctr = Roo.get(this.container.dom.parentElement);
7339 var ctr = Roo.get(this.el.dom);
7341 var thd = this.getGridEl().select('thead',true).first();
7342 var tbd = this.getGridEl().select('tbody', true).first();
7343 var tfd = this.getGridEl().select('tfoot', true).first();
7345 var cw = ctr.getWidth();
7349 tbd.setSize(ctr.getWidth(),
7350 ctr.getHeight() - ((thd ? thd.getHeight() : 0) + (tfd ? tfd.getHeight() : 0))
7352 var barsize = (tbd.dom.offsetWidth - tbd.dom.clientWidth);
7355 cw = Math.max(cw, this.totalWidth);
7356 this.getGridEl().select('tr',true).setWidth(cw);
7357 // resize 'expandable coloumn?
7359 return; // we doe not have a view in this design..
7362 onBodyScroll: function()
7364 //Roo.log("body scrolled');" + this.mainBody.dom.scrollLeft);
7366 this.mainHead.setStyle({
7367 'position' : 'relative',
7368 'left': (-1* this.mainBody.dom.scrollLeft) + 'px'
7374 var scrollHeight = this.mainBody.dom.scrollHeight;
7376 var scrollTop = Math.ceil(this.mainBody.getScroll().top);
7378 var height = this.mainBody.getHeight();
7380 if(scrollHeight - height == scrollTop) {
7382 var total = this.ds.getTotalCount();
7384 if(this.footer.cursor + this.footer.pageSize < total){
7386 this.footer.ds.load({
7388 start : this.footer.cursor + this.footer.pageSize,
7389 limit : this.footer.pageSize
7399 onHeaderChange : function()
7401 var header = this.renderHeader();
7402 var table = this.el.select('table', true).first();
7404 this.mainHead.remove();
7405 this.mainHead = table.createChild(header, this.mainBody, false);
7408 onHiddenChange : function(colModel, colIndex, hidden)
7410 var thSelector = '#' + this.id + ' .x-hcol-' + colIndex;
7411 var tdSelector = '#' + this.id + ' .x-col-' + colIndex;
7413 this.CSS.updateRule(thSelector, "display", "");
7414 this.CSS.updateRule(tdSelector, "display", "");
7417 this.CSS.updateRule(thSelector, "display", "none");
7418 this.CSS.updateRule(tdSelector, "display", "none");
7421 this.onHeaderChange();
7425 setColumnWidth: function(col_index, width)
7427 // width = "md-2 xs-2..."
7428 if(!this.colModel.config[col_index]) {
7432 var w = width.split(" ");
7434 var rows = this.el.dom.getElementsByClassName("x-col-"+col_index);
7436 var h_row = this.el.dom.getElementsByClassName("x-hcol-"+col_index);
7439 for(var j = 0; j < w.length; j++) {
7445 var size_cls = w[j].split("-");
7447 if(!Number.isInteger(size_cls[1] * 1)) {
7451 if(!this.colModel.config[col_index][size_cls[0]]) {
7455 if(!h_row[0].classList.contains("col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]])) {
7459 h_row[0].classList.replace(
7460 "col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]],
7461 "col-"+size_cls[0]+"-"+size_cls[1]
7464 for(var i = 0; i < rows.length; i++) {
7466 var size_cls = w[j].split("-");
7468 if(!Number.isInteger(size_cls[1] * 1)) {
7472 if(!this.colModel.config[col_index][size_cls[0]]) {
7476 if(!rows[i].classList.contains("col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]])) {
7480 rows[i].classList.replace(
7481 "col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]],
7482 "col-"+size_cls[0]+"-"+size_cls[1]
7486 this.colModel.config[col_index][size_cls[0]] = size_cls[1];
7501 * @class Roo.bootstrap.TableCell
7502 * @extends Roo.bootstrap.Component
7503 * Bootstrap TableCell class
7504 * @cfg {String} html cell contain text
7505 * @cfg {String} cls cell class
7506 * @cfg {String} tag cell tag (td|th) default td
7507 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
7508 * @cfg {String} align Aligns the content in a cell
7509 * @cfg {String} axis Categorizes cells
7510 * @cfg {String} bgcolor Specifies the background color of a cell
7511 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7512 * @cfg {Number} colspan Specifies the number of columns a cell should span
7513 * @cfg {String} headers Specifies one or more header cells a cell is related to
7514 * @cfg {Number} height Sets the height of a cell
7515 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
7516 * @cfg {Number} rowspan Sets the number of rows a cell should span
7517 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
7518 * @cfg {String} valign Vertical aligns the content in a cell
7519 * @cfg {Number} width Specifies the width of a cell
7522 * Create a new TableCell
7523 * @param {Object} config The config object
7526 Roo.bootstrap.TableCell = function(config){
7527 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
7530 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
7550 getAutoCreate : function(){
7551 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
7571 cfg.align=this.align
7577 cfg.bgcolor=this.bgcolor
7580 cfg.charoff=this.charoff
7583 cfg.colspan=this.colspan
7586 cfg.headers=this.headers
7589 cfg.height=this.height
7592 cfg.nowrap=this.nowrap
7595 cfg.rowspan=this.rowspan
7598 cfg.scope=this.scope
7601 cfg.valign=this.valign
7604 cfg.width=this.width
7623 * @class Roo.bootstrap.TableRow
7624 * @extends Roo.bootstrap.Component
7625 * Bootstrap TableRow class
7626 * @cfg {String} cls row class
7627 * @cfg {String} align Aligns the content in a table row
7628 * @cfg {String} bgcolor Specifies a background color for a table row
7629 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7630 * @cfg {String} valign Vertical aligns the content in a table row
7633 * Create a new TableRow
7634 * @param {Object} config The config object
7637 Roo.bootstrap.TableRow = function(config){
7638 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
7641 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
7649 getAutoCreate : function(){
7650 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
7660 cfg.align = this.align;
7663 cfg.bgcolor = this.bgcolor;
7666 cfg.charoff = this.charoff;
7669 cfg.valign = this.valign;
7687 * @class Roo.bootstrap.TableBody
7688 * @extends Roo.bootstrap.Component
7689 * Bootstrap TableBody class
7690 * @cfg {String} cls element class
7691 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
7692 * @cfg {String} align Aligns the content inside the element
7693 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
7694 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
7697 * Create a new TableBody
7698 * @param {Object} config The config object
7701 Roo.bootstrap.TableBody = function(config){
7702 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
7705 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
7713 getAutoCreate : function(){
7714 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
7728 cfg.align = this.align;
7731 cfg.charoff = this.charoff;
7734 cfg.valign = this.valign;
7741 // initEvents : function()
7748 // this.store = Roo.factory(this.store, Roo.data);
7749 // this.store.on('load', this.onLoad, this);
7751 // this.store.load();
7755 // onLoad: function ()
7757 // this.fireEvent('load', this);
7767 * Ext JS Library 1.1.1
7768 * Copyright(c) 2006-2007, Ext JS, LLC.
7770 * Originally Released Under LGPL - original licence link has changed is not relivant.
7773 * <script type="text/javascript">
7776 // as we use this in bootstrap.
7777 Roo.namespace('Roo.form');
7779 * @class Roo.form.Action
7780 * Internal Class used to handle form actions
7782 * @param {Roo.form.BasicForm} el The form element or its id
7783 * @param {Object} config Configuration options
7788 // define the action interface
7789 Roo.form.Action = function(form, options){
7791 this.options = options || {};
7794 * Client Validation Failed
7797 Roo.form.Action.CLIENT_INVALID = 'client';
7799 * Server Validation Failed
7802 Roo.form.Action.SERVER_INVALID = 'server';
7804 * Connect to Server Failed
7807 Roo.form.Action.CONNECT_FAILURE = 'connect';
7809 * Reading Data from Server Failed
7812 Roo.form.Action.LOAD_FAILURE = 'load';
7814 Roo.form.Action.prototype = {
7816 failureType : undefined,
7817 response : undefined,
7821 run : function(options){
7826 success : function(response){
7831 handleResponse : function(response){
7835 // default connection failure
7836 failure : function(response){
7838 this.response = response;
7839 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7840 this.form.afterAction(this, false);
7843 processResponse : function(response){
7844 this.response = response;
7845 if(!response.responseText){
7848 this.result = this.handleResponse(response);
7852 // utility functions used internally
7853 getUrl : function(appendParams){
7854 var url = this.options.url || this.form.url || this.form.el.dom.action;
7856 var p = this.getParams();
7858 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
7864 getMethod : function(){
7865 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
7868 getParams : function(){
7869 var bp = this.form.baseParams;
7870 var p = this.options.params;
7872 if(typeof p == "object"){
7873 p = Roo.urlEncode(Roo.applyIf(p, bp));
7874 }else if(typeof p == 'string' && bp){
7875 p += '&' + Roo.urlEncode(bp);
7878 p = Roo.urlEncode(bp);
7883 createCallback : function(){
7885 success: this.success,
7886 failure: this.failure,
7888 timeout: (this.form.timeout*1000),
7889 upload: this.form.fileUpload ? this.success : undefined
7894 Roo.form.Action.Submit = function(form, options){
7895 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
7898 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
7901 haveProgress : false,
7902 uploadComplete : false,
7904 // uploadProgress indicator.
7905 uploadProgress : function()
7907 if (!this.form.progressUrl) {
7911 if (!this.haveProgress) {
7912 Roo.MessageBox.progress("Uploading", "Uploading");
7914 if (this.uploadComplete) {
7915 Roo.MessageBox.hide();
7919 this.haveProgress = true;
7921 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
7923 var c = new Roo.data.Connection();
7925 url : this.form.progressUrl,
7930 success : function(req){
7931 //console.log(data);
7935 rdata = Roo.decode(req.responseText)
7937 Roo.log("Invalid data from server..");
7941 if (!rdata || !rdata.success) {
7943 Roo.MessageBox.alert(Roo.encode(rdata));
7946 var data = rdata.data;
7948 if (this.uploadComplete) {
7949 Roo.MessageBox.hide();
7954 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
7955 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
7958 this.uploadProgress.defer(2000,this);
7961 failure: function(data) {
7962 Roo.log('progress url failed ');
7973 // run get Values on the form, so it syncs any secondary forms.
7974 this.form.getValues();
7976 var o = this.options;
7977 var method = this.getMethod();
7978 var isPost = method == 'POST';
7979 if(o.clientValidation === false || this.form.isValid()){
7981 if (this.form.progressUrl) {
7982 this.form.findField('UPLOAD_IDENTIFIER').setValue(
7983 (new Date() * 1) + '' + Math.random());
7988 Roo.Ajax.request(Roo.apply(this.createCallback(), {
7989 form:this.form.el.dom,
7990 url:this.getUrl(!isPost),
7992 params:isPost ? this.getParams() : null,
7993 isUpload: this.form.fileUpload,
7994 formData : this.form.formData
7997 this.uploadProgress();
7999 }else if (o.clientValidation !== false){ // client validation failed
8000 this.failureType = Roo.form.Action.CLIENT_INVALID;
8001 this.form.afterAction(this, false);
8005 success : function(response)
8007 this.uploadComplete= true;
8008 if (this.haveProgress) {
8009 Roo.MessageBox.hide();
8013 var result = this.processResponse(response);
8014 if(result === true || result.success){
8015 this.form.afterAction(this, true);
8019 this.form.markInvalid(result.errors);
8020 this.failureType = Roo.form.Action.SERVER_INVALID;
8022 this.form.afterAction(this, false);
8024 failure : function(response)
8026 this.uploadComplete= true;
8027 if (this.haveProgress) {
8028 Roo.MessageBox.hide();
8031 this.response = response;
8032 this.failureType = Roo.form.Action.CONNECT_FAILURE;
8033 this.form.afterAction(this, false);
8036 handleResponse : function(response){
8037 if(this.form.errorReader){
8038 var rs = this.form.errorReader.read(response);
8041 for(var i = 0, len = rs.records.length; i < len; i++) {
8042 var r = rs.records[i];
8046 if(errors.length < 1){
8050 success : rs.success,
8056 ret = Roo.decode(response.responseText);
8060 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
8070 Roo.form.Action.Load = function(form, options){
8071 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
8072 this.reader = this.form.reader;
8075 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
8080 Roo.Ajax.request(Roo.apply(
8081 this.createCallback(), {
8082 method:this.getMethod(),
8083 url:this.getUrl(false),
8084 params:this.getParams()
8088 success : function(response){
8090 var result = this.processResponse(response);
8091 if(result === true || !result.success || !result.data){
8092 this.failureType = Roo.form.Action.LOAD_FAILURE;
8093 this.form.afterAction(this, false);
8096 this.form.clearInvalid();
8097 this.form.setValues(result.data);
8098 this.form.afterAction(this, true);
8101 handleResponse : function(response){
8102 if(this.form.reader){
8103 var rs = this.form.reader.read(response);
8104 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
8106 success : rs.success,
8110 return Roo.decode(response.responseText);
8114 Roo.form.Action.ACTION_TYPES = {
8115 'load' : Roo.form.Action.Load,
8116 'submit' : Roo.form.Action.Submit
8125 * @class Roo.bootstrap.Form
8126 * @extends Roo.bootstrap.Component
8127 * Bootstrap Form class
8128 * @cfg {String} method GET | POST (default POST)
8129 * @cfg {String} labelAlign top | left (default top)
8130 * @cfg {String} align left | right - for navbars
8131 * @cfg {Boolean} loadMask load mask when submit (default true)
8136 * @param {Object} config The config object
8140 Roo.bootstrap.Form = function(config){
8142 Roo.bootstrap.Form.superclass.constructor.call(this, config);
8144 Roo.bootstrap.Form.popover.apply();
8148 * @event clientvalidation
8149 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
8150 * @param {Form} this
8151 * @param {Boolean} valid true if the form has passed client-side validation
8153 clientvalidation: true,
8155 * @event beforeaction
8156 * Fires before any action is performed. Return false to cancel the action.
8157 * @param {Form} this
8158 * @param {Action} action The action to be performed
8162 * @event actionfailed
8163 * Fires when an action fails.
8164 * @param {Form} this
8165 * @param {Action} action The action that failed
8167 actionfailed : true,
8169 * @event actioncomplete
8170 * Fires when an action is completed.
8171 * @param {Form} this
8172 * @param {Action} action The action that completed
8174 actioncomplete : true
8178 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
8181 * @cfg {String} method
8182 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
8187 * The URL to use for form actions if one isn't supplied in the action options.
8190 * @cfg {Boolean} fileUpload
8191 * Set to true if this form is a file upload.
8195 * @cfg {Object} baseParams
8196 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
8200 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
8204 * @cfg {Sting} align (left|right) for navbar forms
8209 activeAction : null,
8212 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
8213 * element by passing it or its id or mask the form itself by passing in true.
8216 waitMsgTarget : false,
8221 * @cfg {Boolean} errorMask (true|false) default false
8226 * @cfg {Number} maskOffset Default 100
8231 * @cfg {Boolean} maskBody
8235 getAutoCreate : function(){
8239 method : this.method || 'POST',
8240 id : this.id || Roo.id(),
8243 if (this.parent().xtype.match(/^Nav/)) {
8244 cfg.cls = 'navbar-form form-inline navbar-' + this.align;
8248 if (this.labelAlign == 'left' ) {
8249 cfg.cls += ' form-horizontal';
8255 initEvents : function()
8257 this.el.on('submit', this.onSubmit, this);
8258 // this was added as random key presses on the form where triggering form submit.
8259 this.el.on('keypress', function(e) {
8260 if (e.getCharCode() != 13) {
8263 // we might need to allow it for textareas.. and some other items.
8264 // check e.getTarget().
8266 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
8270 Roo.log("keypress blocked");
8278 onSubmit : function(e){
8283 * Returns true if client-side validation on the form is successful.
8286 isValid : function(){
8287 var items = this.getItems();
8291 items.each(function(f){
8297 Roo.log('invalid field: ' + f.name);
8301 if(!target && f.el.isVisible(true)){
8307 if(this.errorMask && !valid){
8308 Roo.bootstrap.Form.popover.mask(this, target);
8315 * Returns true if any fields in this form have changed since their original load.
8318 isDirty : function(){
8320 var items = this.getItems();
8321 items.each(function(f){
8331 * Performs a predefined action (submit or load) or custom actions you define on this form.
8332 * @param {String} actionName The name of the action type
8333 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
8334 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
8335 * accept other config options):
8337 Property Type Description
8338 ---------------- --------------- ----------------------------------------------------------------------------------
8339 url String The url for the action (defaults to the form's url)
8340 method String The form method to use (defaults to the form's method, or POST if not defined)
8341 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
8342 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
8343 validate the form on the client (defaults to false)
8345 * @return {BasicForm} this
8347 doAction : function(action, options){
8348 if(typeof action == 'string'){
8349 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
8351 if(this.fireEvent('beforeaction', this, action) !== false){
8352 this.beforeAction(action);
8353 action.run.defer(100, action);
8359 beforeAction : function(action){
8360 var o = action.options;
8365 Roo.get(document.body).mask(o.waitMsg || "Sending", 'x-mask-loading')
8367 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
8370 // not really supported yet.. ??
8372 //if(this.waitMsgTarget === true){
8373 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
8374 //}else if(this.waitMsgTarget){
8375 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
8376 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
8378 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
8384 afterAction : function(action, success){
8385 this.activeAction = null;
8386 var o = action.options;
8391 Roo.get(document.body).unmask();
8397 //if(this.waitMsgTarget === true){
8398 // this.el.unmask();
8399 //}else if(this.waitMsgTarget){
8400 // this.waitMsgTarget.unmask();
8402 // Roo.MessageBox.updateProgress(1);
8403 // Roo.MessageBox.hide();
8410 Roo.callback(o.success, o.scope, [this, action]);
8411 this.fireEvent('actioncomplete', this, action);
8415 // failure condition..
8416 // we have a scenario where updates need confirming.
8417 // eg. if a locking scenario exists..
8418 // we look for { errors : { needs_confirm : true }} in the response.
8420 (typeof(action.result) != 'undefined') &&
8421 (typeof(action.result.errors) != 'undefined') &&
8422 (typeof(action.result.errors.needs_confirm) != 'undefined')
8425 Roo.log("not supported yet");
8428 Roo.MessageBox.confirm(
8429 "Change requires confirmation",
8430 action.result.errorMsg,
8435 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
8445 Roo.callback(o.failure, o.scope, [this, action]);
8446 // show an error message if no failed handler is set..
8447 if (!this.hasListener('actionfailed')) {
8448 Roo.log("need to add dialog support");
8450 Roo.MessageBox.alert("Error",
8451 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
8452 action.result.errorMsg :
8453 "Saving Failed, please check your entries or try again"
8458 this.fireEvent('actionfailed', this, action);
8463 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
8464 * @param {String} id The value to search for
8467 findField : function(id){
8468 var items = this.getItems();
8469 var field = items.get(id);
8471 items.each(function(f){
8472 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
8479 return field || null;
8482 * Mark fields in this form invalid in bulk.
8483 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
8484 * @return {BasicForm} this
8486 markInvalid : function(errors){
8487 if(errors instanceof Array){
8488 for(var i = 0, len = errors.length; i < len; i++){
8489 var fieldError = errors[i];
8490 var f = this.findField(fieldError.id);
8492 f.markInvalid(fieldError.msg);
8498 if(typeof errors[id] != 'function' && (field = this.findField(id))){
8499 field.markInvalid(errors[id]);
8503 //Roo.each(this.childForms || [], function (f) {
8504 // f.markInvalid(errors);
8511 * Set values for fields in this form in bulk.
8512 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
8513 * @return {BasicForm} this
8515 setValues : function(values){
8516 if(values instanceof Array){ // array of objects
8517 for(var i = 0, len = values.length; i < len; i++){
8519 var f = this.findField(v.id);
8521 f.setValue(v.value);
8522 if(this.trackResetOnLoad){
8523 f.originalValue = f.getValue();
8527 }else{ // object hash
8530 if(typeof values[id] != 'function' && (field = this.findField(id))){
8532 if (field.setFromData &&
8534 field.displayField &&
8535 // combos' with local stores can
8536 // be queried via setValue()
8537 // to set their value..
8538 (field.store && !field.store.isLocal)
8542 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
8543 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
8544 field.setFromData(sd);
8546 } else if(field.setFromData && (field.store && !field.store.isLocal)) {
8548 field.setFromData(values);
8551 field.setValue(values[id]);
8555 if(this.trackResetOnLoad){
8556 field.originalValue = field.getValue();
8562 //Roo.each(this.childForms || [], function (f) {
8563 // f.setValues(values);
8570 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
8571 * they are returned as an array.
8572 * @param {Boolean} asString
8575 getValues : function(asString){
8576 //if (this.childForms) {
8577 // copy values from the child forms
8578 // Roo.each(this.childForms, function (f) {
8579 // this.setValues(f.getValues());
8585 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
8586 if(asString === true){
8589 return Roo.urlDecode(fs);
8593 * Returns the fields in this form as an object with key/value pairs.
8594 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
8597 getFieldValues : function(with_hidden)
8599 var items = this.getItems();
8601 items.each(function(f){
8607 var v = f.getValue();
8609 if (f.inputType =='radio') {
8610 if (typeof(ret[f.getName()]) == 'undefined') {
8611 ret[f.getName()] = ''; // empty..
8614 if (!f.el.dom.checked) {
8622 if(f.xtype == 'MoneyField'){
8623 ret[f.currencyName] = f.getCurrency();
8626 // not sure if this supported any more..
8627 if ((typeof(v) == 'object') && f.getRawValue) {
8628 v = f.getRawValue() ; // dates..
8630 // combo boxes where name != hiddenName...
8631 if (f.name !== false && f.name != '' && f.name != f.getName()) {
8632 ret[f.name] = f.getRawValue();
8634 ret[f.getName()] = v;
8641 * Clears all invalid messages in this form.
8642 * @return {BasicForm} this
8644 clearInvalid : function(){
8645 var items = this.getItems();
8647 items.each(function(f){
8656 * @return {BasicForm} this
8659 var items = this.getItems();
8660 items.each(function(f){
8664 Roo.each(this.childForms || [], function (f) {
8672 getItems : function()
8674 var r=new Roo.util.MixedCollection(false, function(o){
8675 return o.id || (o.id = Roo.id());
8677 var iter = function(el) {
8684 Roo.each(el.items,function(e) {
8693 hideFields : function(items)
8695 Roo.each(items, function(i){
8697 var f = this.findField(i);
8708 showFields : function(items)
8710 Roo.each(items, function(i){
8712 var f = this.findField(i);
8725 Roo.apply(Roo.bootstrap.Form, {
8752 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
8753 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
8754 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
8755 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
8758 this.maskEl.top.enableDisplayMode("block");
8759 this.maskEl.left.enableDisplayMode("block");
8760 this.maskEl.bottom.enableDisplayMode("block");
8761 this.maskEl.right.enableDisplayMode("block");
8763 this.toolTip = new Roo.bootstrap.Tooltip({
8764 cls : 'roo-form-error-popover',
8766 'left' : ['r-l', [-2,0], 'right'],
8767 'right' : ['l-r', [2,0], 'left'],
8768 'bottom' : ['tl-bl', [0,2], 'top'],
8769 'top' : [ 'bl-tl', [0,-2], 'bottom']
8773 this.toolTip.render(Roo.get(document.body));
8775 this.toolTip.el.enableDisplayMode("block");
8777 Roo.get(document.body).on('click', function(){
8781 Roo.get(document.body).on('touchstart', function(){
8785 this.isApplied = true
8788 mask : function(form, target)
8792 this.target = target;
8794 if(!this.form.errorMask || !target.el){
8798 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.modal', 100, true) || Roo.get(document.body);
8800 Roo.log(scrollable);
8802 var ot = this.target.el.calcOffsetsTo(scrollable);
8804 var scrollTo = ot[1] - this.form.maskOffset;
8806 scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
8808 scrollable.scrollTo('top', scrollTo);
8810 var box = this.target.el.getBox();
8812 var zIndex = Roo.bootstrap.Modal.zIndex++;
8815 this.maskEl.top.setStyle('position', 'absolute');
8816 this.maskEl.top.setStyle('z-index', zIndex);
8817 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
8818 this.maskEl.top.setLeft(0);
8819 this.maskEl.top.setTop(0);
8820 this.maskEl.top.show();
8822 this.maskEl.left.setStyle('position', 'absolute');
8823 this.maskEl.left.setStyle('z-index', zIndex);
8824 this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
8825 this.maskEl.left.setLeft(0);
8826 this.maskEl.left.setTop(box.y - this.padding);
8827 this.maskEl.left.show();
8829 this.maskEl.bottom.setStyle('position', 'absolute');
8830 this.maskEl.bottom.setStyle('z-index', zIndex);
8831 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
8832 this.maskEl.bottom.setLeft(0);
8833 this.maskEl.bottom.setTop(box.bottom + this.padding);
8834 this.maskEl.bottom.show();
8836 this.maskEl.right.setStyle('position', 'absolute');
8837 this.maskEl.right.setStyle('z-index', zIndex);
8838 this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
8839 this.maskEl.right.setLeft(box.right + this.padding);
8840 this.maskEl.right.setTop(box.y - this.padding);
8841 this.maskEl.right.show();
8843 this.toolTip.bindEl = this.target.el;
8845 this.toolTip.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
8847 var tip = this.target.blankText;
8849 if(this.target.getValue() !== '' ) {
8851 if (this.target.invalidText.length) {
8852 tip = this.target.invalidText;
8853 } else if (this.target.regexText.length){
8854 tip = this.target.regexText;
8858 this.toolTip.show(tip);
8860 this.intervalID = window.setInterval(function() {
8861 Roo.bootstrap.Form.popover.unmask();
8864 window.onwheel = function(){ return false;};
8866 (function(){ this.isMasked = true; }).defer(500, this);
8872 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
8876 this.maskEl.top.setStyle('position', 'absolute');
8877 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
8878 this.maskEl.top.hide();
8880 this.maskEl.left.setStyle('position', 'absolute');
8881 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
8882 this.maskEl.left.hide();
8884 this.maskEl.bottom.setStyle('position', 'absolute');
8885 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
8886 this.maskEl.bottom.hide();
8888 this.maskEl.right.setStyle('position', 'absolute');
8889 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
8890 this.maskEl.right.hide();
8892 this.toolTip.hide();
8894 this.toolTip.el.hide();
8896 window.onwheel = function(){ return true;};
8898 if(this.intervalID){
8899 window.clearInterval(this.intervalID);
8900 this.intervalID = false;
8903 this.isMasked = false;
8913 * Ext JS Library 1.1.1
8914 * Copyright(c) 2006-2007, Ext JS, LLC.
8916 * Originally Released Under LGPL - original licence link has changed is not relivant.
8919 * <script type="text/javascript">
8922 * @class Roo.form.VTypes
8923 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
8926 Roo.form.VTypes = function(){
8927 // closure these in so they are only created once.
8928 var alpha = /^[a-zA-Z_]+$/;
8929 var alphanum = /^[a-zA-Z0-9_]+$/;
8930 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
8931 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
8933 // All these messages and functions are configurable
8936 * The function used to validate email addresses
8937 * @param {String} value The email address
8939 'email' : function(v){
8940 return email.test(v);
8943 * The error text to display when the email validation function returns false
8946 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
8948 * The keystroke filter mask to be applied on email input
8951 'emailMask' : /[a-z0-9_\.\-@]/i,
8954 * The function used to validate URLs
8955 * @param {String} value The URL
8957 'url' : function(v){
8961 * The error text to display when the url validation function returns false
8964 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
8967 * The function used to validate alpha values
8968 * @param {String} value The value
8970 'alpha' : function(v){
8971 return alpha.test(v);
8974 * The error text to display when the alpha validation function returns false
8977 'alphaText' : 'This field should only contain letters and _',
8979 * The keystroke filter mask to be applied on alpha input
8982 'alphaMask' : /[a-z_]/i,
8985 * The function used to validate alphanumeric values
8986 * @param {String} value The value
8988 'alphanum' : function(v){
8989 return alphanum.test(v);
8992 * The error text to display when the alphanumeric validation function returns false
8995 'alphanumText' : 'This field should only contain letters, numbers and _',
8997 * The keystroke filter mask to be applied on alphanumeric input
9000 'alphanumMask' : /[a-z0-9_]/i
9010 * @class Roo.bootstrap.Input
9011 * @extends Roo.bootstrap.Component
9012 * Bootstrap Input class
9013 * @cfg {Boolean} disabled is it disabled
9014 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
9015 * @cfg {String} name name of the input
9016 * @cfg {string} fieldLabel - the label associated
9017 * @cfg {string} placeholder - placeholder to put in text.
9018 * @cfg {string} before - input group add on before
9019 * @cfg {string} after - input group add on after
9020 * @cfg {string} size - (lg|sm) or leave empty..
9021 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
9022 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
9023 * @cfg {Number} md colspan out of 12 for computer-sized screens
9024 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
9025 * @cfg {string} value default value of the input
9026 * @cfg {Number} labelWidth set the width of label
9027 * @cfg {Number} labellg set the width of label (1-12)
9028 * @cfg {Number} labelmd set the width of label (1-12)
9029 * @cfg {Number} labelsm set the width of label (1-12)
9030 * @cfg {Number} labelxs set the width of label (1-12)
9031 * @cfg {String} labelAlign (top|left)
9032 * @cfg {Boolean} readOnly Specifies that the field should be read-only
9033 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
9034 * @cfg {String} indicatorpos (left|right) default left
9035 * @cfg {String} capture (user|camera) use for file input only. (default empty)
9036 * @cfg {String} accept (image|video|audio) use for file input only. (default empty)
9038 * @cfg {String} align (left|center|right) Default left
9039 * @cfg {Boolean} forceFeedback (true|false) Default false
9042 * Create a new Input
9043 * @param {Object} config The config object
9046 Roo.bootstrap.Input = function(config){
9048 Roo.bootstrap.Input.superclass.constructor.call(this, config);
9053 * Fires when this field receives input focus.
9054 * @param {Roo.form.Field} this
9059 * Fires when this field loses input focus.
9060 * @param {Roo.form.Field} this
9065 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
9066 * {@link Roo.EventObject#getKey} to determine which key was pressed.
9067 * @param {Roo.form.Field} this
9068 * @param {Roo.EventObject} e The event object
9073 * Fires just before the field blurs if the field value has changed.
9074 * @param {Roo.form.Field} this
9075 * @param {Mixed} newValue The new value
9076 * @param {Mixed} oldValue The original value
9081 * Fires after the field has been marked as invalid.
9082 * @param {Roo.form.Field} this
9083 * @param {String} msg The validation message
9088 * Fires after the field has been validated with no errors.
9089 * @param {Roo.form.Field} this
9094 * Fires after the key up
9095 * @param {Roo.form.Field} this
9096 * @param {Roo.EventObject} e The event Object
9102 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
9104 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
9105 automatic validation (defaults to "keyup").
9107 validationEvent : "keyup",
9109 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
9111 validateOnBlur : true,
9113 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
9115 validationDelay : 250,
9117 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
9119 focusClass : "x-form-focus", // not needed???
9123 * @cfg {String} invalidClass DEPRICATED - code uses BS4 - is-valid / is-invalid
9125 invalidClass : "has-warning",
9128 * @cfg {String} validClass DEPRICATED - code uses BS4 - is-valid / is-invalid
9130 validClass : "has-success",
9133 * @cfg {Boolean} hasFeedback (true|false) default true
9138 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
9140 invalidFeedbackClass : "glyphicon-warning-sign",
9143 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
9145 validFeedbackClass : "glyphicon-ok",
9148 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
9150 selectOnFocus : false,
9153 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
9157 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
9162 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
9164 disableKeyFilter : false,
9167 * @cfg {Boolean} disabled True to disable the field (defaults to false).
9171 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
9175 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
9177 blankText : "Please complete this mandatory field",
9180 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
9184 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
9186 maxLength : Number.MAX_VALUE,
9188 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
9190 minLengthText : "The minimum length for this field is {0}",
9192 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
9194 maxLengthText : "The maximum length for this field is {0}",
9198 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
9199 * If available, this function will be called only after the basic validators all return true, and will be passed the
9200 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
9204 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
9205 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
9206 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
9210 * @cfg {String} regexText -- Depricated - use Invalid Text
9215 * @cfg {String} invalidText The error text to display if {@link #validator} test fails during validation (defaults to "")
9221 autocomplete: false,
9240 formatedValue : false,
9241 forceFeedback : false,
9243 indicatorpos : 'left',
9253 parentLabelAlign : function()
9256 while (parent.parent()) {
9257 parent = parent.parent();
9258 if (typeof(parent.labelAlign) !='undefined') {
9259 return parent.labelAlign;
9266 getAutoCreate : function()
9268 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9274 if(this.inputType != 'hidden'){
9275 cfg.cls = 'form-group' //input-group
9281 type : this.inputType,
9283 cls : 'form-control',
9284 placeholder : this.placeholder || '',
9285 autocomplete : this.autocomplete || 'new-password'
9288 if(this.capture.length){
9289 input.capture = this.capture;
9292 if(this.accept.length){
9293 input.accept = this.accept + "/*";
9297 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
9300 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9301 input.maxLength = this.maxLength;
9304 if (this.disabled) {
9305 input.disabled=true;
9308 if (this.readOnly) {
9309 input.readonly=true;
9313 input.name = this.name;
9317 input.cls += ' input-' + this.size;
9321 ['xs','sm','md','lg'].map(function(size){
9322 if (settings[size]) {
9323 cfg.cls += ' col-' + size + '-' + settings[size];
9327 var inputblock = input;
9331 cls: 'glyphicon form-control-feedback'
9334 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9337 cls : 'has-feedback',
9345 if (this.before || this.after) {
9348 cls : 'input-group',
9352 if (this.before && typeof(this.before) == 'string') {
9354 inputblock.cn.push({
9356 cls : 'roo-input-before input-group-addon input-group-prepend input-group-text',
9360 if (this.before && typeof(this.before) == 'object') {
9361 this.before = Roo.factory(this.before);
9363 inputblock.cn.push({
9365 cls : 'roo-input-before input-group-prepend input-group-text input-group-' +
9366 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
9370 inputblock.cn.push(input);
9372 if (this.after && typeof(this.after) == 'string') {
9373 inputblock.cn.push({
9375 cls : 'roo-input-after input-group-append input-group-text input-group-addon',
9379 if (this.after && typeof(this.after) == 'object') {
9380 this.after = Roo.factory(this.after);
9382 inputblock.cn.push({
9384 cls : 'roo-input-after input-group-append input-group-text input-group-' +
9385 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
9389 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9390 inputblock.cls += ' has-feedback';
9391 inputblock.cn.push(feedback);
9396 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
9397 tooltip : 'This field is required'
9399 if (Roo.bootstrap.version == 4) {
9402 style : 'display-none'
9405 if (align ==='left' && this.fieldLabel.length) {
9407 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
9414 cls : 'control-label col-form-label',
9415 html : this.fieldLabel
9426 var labelCfg = cfg.cn[1];
9427 var contentCfg = cfg.cn[2];
9429 if(this.indicatorpos == 'right'){
9434 cls : 'control-label col-form-label',
9438 html : this.fieldLabel
9452 labelCfg = cfg.cn[0];
9453 contentCfg = cfg.cn[1];
9457 if(this.labelWidth > 12){
9458 labelCfg.style = "width: " + this.labelWidth + 'px';
9461 if(this.labelWidth < 13 && this.labelmd == 0){
9462 this.labelmd = this.labelWidth;
9465 if(this.labellg > 0){
9466 labelCfg.cls += ' col-lg-' + this.labellg;
9467 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
9470 if(this.labelmd > 0){
9471 labelCfg.cls += ' col-md-' + this.labelmd;
9472 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
9475 if(this.labelsm > 0){
9476 labelCfg.cls += ' col-sm-' + this.labelsm;
9477 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
9480 if(this.labelxs > 0){
9481 labelCfg.cls += ' col-xs-' + this.labelxs;
9482 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
9486 } else if ( this.fieldLabel.length) {
9491 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
9492 tooltip : 'This field is required'
9496 //cls : 'input-group-addon',
9497 html : this.fieldLabel
9505 if(this.indicatorpos == 'right'){
9510 //cls : 'input-group-addon',
9511 html : this.fieldLabel
9516 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9517 tooltip : 'This field is required'
9537 if (this.parentType === 'Navbar' && this.parent().bar) {
9538 cfg.cls += ' navbar-form';
9541 if (this.parentType === 'NavGroup' && !(Roo.bootstrap.version == 4 && this.parent().form)) {
9542 // on BS4 we do this only if not form
9543 cfg.cls += ' navbar-form';
9551 * return the real input element.
9553 inputEl: function ()
9555 return this.el.select('input.form-control',true).first();
9558 tooltipEl : function()
9560 return this.inputEl();
9563 indicatorEl : function()
9565 if (Roo.bootstrap.version == 4) {
9566 return false; // not enabled in v4 yet.
9569 var indicator = this.el.select('i.roo-required-indicator',true).first();
9579 setDisabled : function(v)
9581 var i = this.inputEl().dom;
9583 i.removeAttribute('disabled');
9587 i.setAttribute('disabled','true');
9589 initEvents : function()
9592 this.inputEl().on("keydown" , this.fireKey, this);
9593 this.inputEl().on("focus", this.onFocus, this);
9594 this.inputEl().on("blur", this.onBlur, this);
9596 this.inputEl().relayEvent('keyup', this);
9598 this.indicator = this.indicatorEl();
9601 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible'); // changed from invisible??? -
9604 // reference to original value for reset
9605 this.originalValue = this.getValue();
9606 //Roo.form.TextField.superclass.initEvents.call(this);
9607 if(this.validationEvent == 'keyup'){
9608 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
9609 this.inputEl().on('keyup', this.filterValidation, this);
9611 else if(this.validationEvent !== false){
9612 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
9615 if(this.selectOnFocus){
9616 this.on("focus", this.preFocus, this);
9619 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
9620 this.inputEl().on("keypress", this.filterKeys, this);
9622 this.inputEl().relayEvent('keypress', this);
9625 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
9626 this.el.on("click", this.autoSize, this);
9629 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
9630 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
9633 if (typeof(this.before) == 'object') {
9634 this.before.render(this.el.select('.roo-input-before',true).first());
9636 if (typeof(this.after) == 'object') {
9637 this.after.render(this.el.select('.roo-input-after',true).first());
9640 this.inputEl().on('change', this.onChange, this);
9643 filterValidation : function(e){
9644 if(!e.isNavKeyPress()){
9645 this.validationTask.delay(this.validationDelay);
9649 * Validates the field value
9650 * @return {Boolean} True if the value is valid, else false
9652 validate : function(){
9653 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
9654 if(this.disabled || this.validateValue(this.getRawValue())){
9665 * Validates a value according to the field's validation rules and marks the field as invalid
9666 * if the validation fails
9667 * @param {Mixed} value The value to validate
9668 * @return {Boolean} True if the value is valid, else false
9670 validateValue : function(value)
9672 if(this.getVisibilityEl().hasClass('hidden')){
9676 if(value.length < 1) { // if it's blank
9677 if(this.allowBlank){
9683 if(value.length < this.minLength){
9686 if(value.length > this.maxLength){
9690 var vt = Roo.form.VTypes;
9691 if(!vt[this.vtype](value, this)){
9695 if(typeof this.validator == "function"){
9696 var msg = this.validator(value);
9700 if (typeof(msg) == 'string') {
9701 this.invalidText = msg;
9705 if(this.regex && !this.regex.test(value)){
9713 fireKey : function(e){
9714 //Roo.log('field ' + e.getKey());
9715 if(e.isNavKeyPress()){
9716 this.fireEvent("specialkey", this, e);
9719 focus : function (selectText){
9721 this.inputEl().focus();
9722 if(selectText === true){
9723 this.inputEl().dom.select();
9729 onFocus : function(){
9730 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9731 // this.el.addClass(this.focusClass);
9734 this.hasFocus = true;
9735 this.startValue = this.getValue();
9736 this.fireEvent("focus", this);
9740 beforeBlur : Roo.emptyFn,
9744 onBlur : function(){
9746 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9747 //this.el.removeClass(this.focusClass);
9749 this.hasFocus = false;
9750 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
9753 var v = this.getValue();
9754 if(String(v) !== String(this.startValue)){
9755 this.fireEvent('change', this, v, this.startValue);
9757 this.fireEvent("blur", this);
9760 onChange : function(e)
9762 var v = this.getValue();
9763 if(String(v) !== String(this.startValue)){
9764 this.fireEvent('change', this, v, this.startValue);
9770 * Resets the current field value to the originally loaded value and clears any validation messages
9773 this.setValue(this.originalValue);
9777 * Returns the name of the field
9778 * @return {Mixed} name The name field
9780 getName: function(){
9784 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
9785 * @return {Mixed} value The field value
9787 getValue : function(){
9789 var v = this.inputEl().getValue();
9794 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
9795 * @return {Mixed} value The field value
9797 getRawValue : function(){
9798 var v = this.inputEl().getValue();
9804 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
9805 * @param {Mixed} value The value to set
9807 setRawValue : function(v){
9808 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9811 selectText : function(start, end){
9812 var v = this.getRawValue();
9814 start = start === undefined ? 0 : start;
9815 end = end === undefined ? v.length : end;
9816 var d = this.inputEl().dom;
9817 if(d.setSelectionRange){
9818 d.setSelectionRange(start, end);
9819 }else if(d.createTextRange){
9820 var range = d.createTextRange();
9821 range.moveStart("character", start);
9822 range.moveEnd("character", v.length-end);
9829 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
9830 * @param {Mixed} value The value to set
9832 setValue : function(v){
9835 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9841 processValue : function(value){
9842 if(this.stripCharsRe){
9843 var newValue = value.replace(this.stripCharsRe, '');
9844 if(newValue !== value){
9845 this.setRawValue(newValue);
9852 preFocus : function(){
9854 if(this.selectOnFocus){
9855 this.inputEl().dom.select();
9858 filterKeys : function(e){
9860 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
9863 var c = e.getCharCode(), cc = String.fromCharCode(c);
9864 if(Roo.isIE && (e.isSpecialKey() || !cc)){
9867 if(!this.maskRe.test(cc)){
9872 * Clear any invalid styles/messages for this field
9874 clearInvalid : function(){
9876 if(!this.el || this.preventMark){ // not rendered
9881 this.el.removeClass([this.invalidClass, 'is-invalid']);
9883 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9885 var feedback = this.el.select('.form-control-feedback', true).first();
9888 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9894 this.indicator.removeClass('visible');
9895 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9898 this.fireEvent('valid', this);
9902 * Mark this field as valid
9904 markValid : function()
9906 if(!this.el || this.preventMark){ // not rendered...
9910 this.el.removeClass([this.invalidClass, this.validClass]);
9911 this.inputEl().removeClass(['is-valid', 'is-invalid']);
9913 var feedback = this.el.select('.form-control-feedback', true).first();
9916 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9920 this.indicator.removeClass('visible');
9921 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9928 if(this.allowBlank && !this.getRawValue().length){
9931 if (Roo.bootstrap.version == 3) {
9932 this.el.addClass(this.validClass);
9934 this.inputEl().addClass('is-valid');
9937 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9939 var feedback = this.el.select('.form-control-feedback', true).first();
9942 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9943 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9948 this.fireEvent('valid', this);
9952 * Mark this field as invalid
9953 * @param {String} msg The validation message
9955 markInvalid : function(msg)
9957 if(!this.el || this.preventMark){ // not rendered
9961 this.el.removeClass([this.invalidClass, this.validClass]);
9962 this.inputEl().removeClass(['is-valid', 'is-invalid']);
9964 var feedback = this.el.select('.form-control-feedback', true).first();
9967 this.el.select('.form-control-feedback', true).first().removeClass(
9968 [this.invalidFeedbackClass, this.validFeedbackClass]);
9975 if(this.allowBlank && !this.getRawValue().length){
9980 this.indicator.removeClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9981 this.indicator.addClass('visible');
9983 if (Roo.bootstrap.version == 3) {
9984 this.el.addClass(this.invalidClass);
9986 this.inputEl().addClass('is-invalid');
9991 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9993 var feedback = this.el.select('.form-control-feedback', true).first();
9996 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9998 if(this.getValue().length || this.forceFeedback){
9999 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
10006 this.fireEvent('invalid', this, msg);
10009 SafariOnKeyDown : function(event)
10011 // this is a workaround for a password hang bug on chrome/ webkit.
10012 if (this.inputEl().dom.type != 'password') {
10016 var isSelectAll = false;
10018 if(this.inputEl().dom.selectionEnd > 0){
10019 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
10021 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
10022 event.preventDefault();
10027 if(isSelectAll && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
10029 event.preventDefault();
10030 // this is very hacky as keydown always get's upper case.
10032 var cc = String.fromCharCode(event.getCharCode());
10033 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
10037 adjustWidth : function(tag, w){
10038 tag = tag.toLowerCase();
10039 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
10040 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
10041 if(tag == 'input'){
10044 if(tag == 'textarea'){
10047 }else if(Roo.isOpera){
10048 if(tag == 'input'){
10051 if(tag == 'textarea'){
10059 setFieldLabel : function(v)
10061 if(!this.rendered){
10065 if(this.indicatorEl()){
10066 var ar = this.el.select('label > span',true);
10068 if (ar.elements.length) {
10069 this.el.select('label > span',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
10070 this.fieldLabel = v;
10074 var br = this.el.select('label',true);
10076 if(br.elements.length) {
10077 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
10078 this.fieldLabel = v;
10082 Roo.log('Cannot Found any of label > span || label in input');
10086 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
10087 this.fieldLabel = v;
10102 * @class Roo.bootstrap.TextArea
10103 * @extends Roo.bootstrap.Input
10104 * Bootstrap TextArea class
10105 * @cfg {Number} cols Specifies the visible width of a text area
10106 * @cfg {Number} rows Specifies the visible number of lines in a text area
10107 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
10108 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
10109 * @cfg {string} html text
10112 * Create a new TextArea
10113 * @param {Object} config The config object
10116 Roo.bootstrap.TextArea = function(config){
10117 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
10121 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
10131 getAutoCreate : function(){
10133 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
10139 if(this.inputType != 'hidden'){
10140 cfg.cls = 'form-group' //input-group
10148 value : this.value || '',
10149 html: this.html || '',
10150 cls : 'form-control',
10151 placeholder : this.placeholder || ''
10155 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
10156 input.maxLength = this.maxLength;
10160 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
10164 input.cols = this.cols;
10167 if (this.readOnly) {
10168 input.readonly = true;
10172 input.name = this.name;
10176 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
10180 ['xs','sm','md','lg'].map(function(size){
10181 if (settings[size]) {
10182 cfg.cls += ' col-' + size + '-' + settings[size];
10186 var inputblock = input;
10188 if(this.hasFeedback && !this.allowBlank){
10192 cls: 'glyphicon form-control-feedback'
10196 cls : 'has-feedback',
10205 if (this.before || this.after) {
10208 cls : 'input-group',
10212 inputblock.cn.push({
10214 cls : 'input-group-addon',
10219 inputblock.cn.push(input);
10221 if(this.hasFeedback && !this.allowBlank){
10222 inputblock.cls += ' has-feedback';
10223 inputblock.cn.push(feedback);
10227 inputblock.cn.push({
10229 cls : 'input-group-addon',
10236 if (align ==='left' && this.fieldLabel.length) {
10241 cls : 'control-label',
10242 html : this.fieldLabel
10253 if(this.labelWidth > 12){
10254 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
10257 if(this.labelWidth < 13 && this.labelmd == 0){
10258 this.labelmd = this.labelWidth;
10261 if(this.labellg > 0){
10262 cfg.cn[0].cls += ' col-lg-' + this.labellg;
10263 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
10266 if(this.labelmd > 0){
10267 cfg.cn[0].cls += ' col-md-' + this.labelmd;
10268 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
10271 if(this.labelsm > 0){
10272 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
10273 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
10276 if(this.labelxs > 0){
10277 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
10278 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
10281 } else if ( this.fieldLabel.length) {
10286 //cls : 'input-group-addon',
10287 html : this.fieldLabel
10305 if (this.disabled) {
10306 input.disabled=true;
10313 * return the real textarea element.
10315 inputEl: function ()
10317 return this.el.select('textarea.form-control',true).first();
10321 * Clear any invalid styles/messages for this field
10323 clearInvalid : function()
10326 if(!this.el || this.preventMark){ // not rendered
10330 var label = this.el.select('label', true).first();
10331 var icon = this.el.select('i.fa-star', true).first();
10336 this.el.removeClass( this.validClass);
10337 this.inputEl().removeClass('is-invalid');
10339 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10341 var feedback = this.el.select('.form-control-feedback', true).first();
10344 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
10349 this.fireEvent('valid', this);
10353 * Mark this field as valid
10355 markValid : function()
10357 if(!this.el || this.preventMark){ // not rendered
10361 this.el.removeClass([this.invalidClass, this.validClass]);
10362 this.inputEl().removeClass(['is-valid', 'is-invalid']);
10364 var feedback = this.el.select('.form-control-feedback', true).first();
10367 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10370 if(this.disabled || this.allowBlank){
10374 var label = this.el.select('label', true).first();
10375 var icon = this.el.select('i.fa-star', true).first();
10380 if (Roo.bootstrap.version == 3) {
10381 this.el.addClass(this.validClass);
10383 this.inputEl().addClass('is-valid');
10387 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
10389 var feedback = this.el.select('.form-control-feedback', true).first();
10392 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10393 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
10398 this.fireEvent('valid', this);
10402 * Mark this field as invalid
10403 * @param {String} msg The validation message
10405 markInvalid : function(msg)
10407 if(!this.el || this.preventMark){ // not rendered
10411 this.el.removeClass([this.invalidClass, this.validClass]);
10412 this.inputEl().removeClass(['is-valid', 'is-invalid']);
10414 var feedback = this.el.select('.form-control-feedback', true).first();
10417 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10420 if(this.disabled || this.allowBlank){
10424 var label = this.el.select('label', true).first();
10425 var icon = this.el.select('i.fa-star', true).first();
10427 if(!this.getValue().length && label && !icon){
10428 this.el.createChild({
10430 cls : 'text-danger fa fa-lg fa-star',
10431 tooltip : 'This field is required',
10432 style : 'margin-right:5px;'
10436 if (Roo.bootstrap.version == 3) {
10437 this.el.addClass(this.invalidClass);
10439 this.inputEl().addClass('is-invalid');
10442 // fixme ... this may be depricated need to test..
10443 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10445 var feedback = this.el.select('.form-control-feedback', true).first();
10448 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10450 if(this.getValue().length || this.forceFeedback){
10451 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
10458 this.fireEvent('invalid', this, msg);
10466 * trigger field - base class for combo..
10471 * @class Roo.bootstrap.TriggerField
10472 * @extends Roo.bootstrap.Input
10473 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
10474 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
10475 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
10476 * for which you can provide a custom implementation. For example:
10478 var trigger = new Roo.bootstrap.TriggerField();
10479 trigger.onTriggerClick = myTriggerFn;
10480 trigger.applyTo('my-field');
10483 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
10484 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
10485 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
10486 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
10487 * @cfg {String} caret (search|calendar) BS3 only - carat fa name
10490 * Create a new TriggerField.
10491 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
10492 * to the base TextField)
10494 Roo.bootstrap.TriggerField = function(config){
10495 this.mimicing = false;
10496 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
10499 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
10501 * @cfg {String} triggerClass A CSS class to apply to the trigger
10504 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
10509 * @cfg {Boolean} removable (true|false) special filter default false
10513 /** @cfg {Boolean} grow @hide */
10514 /** @cfg {Number} growMin @hide */
10515 /** @cfg {Number} growMax @hide */
10521 autoSize: Roo.emptyFn,
10525 deferHeight : true,
10528 actionMode : 'wrap',
10533 getAutoCreate : function(){
10535 var align = this.labelAlign || this.parentLabelAlign();
10540 cls: 'form-group' //input-group
10547 type : this.inputType,
10548 cls : 'form-control',
10549 autocomplete: 'new-password',
10550 placeholder : this.placeholder || ''
10554 input.name = this.name;
10557 input.cls += ' input-' + this.size;
10560 if (this.disabled) {
10561 input.disabled=true;
10564 var inputblock = input;
10566 if(this.hasFeedback && !this.allowBlank){
10570 cls: 'glyphicon form-control-feedback'
10573 if(this.removable && !this.editable && !this.tickable){
10575 cls : 'has-feedback',
10581 cls : 'roo-combo-removable-btn close'
10588 cls : 'has-feedback',
10597 if(this.removable && !this.editable && !this.tickable){
10599 cls : 'roo-removable',
10605 cls : 'roo-combo-removable-btn close'
10612 if (this.before || this.after) {
10615 cls : 'input-group',
10619 inputblock.cn.push({
10621 cls : 'input-group-addon input-group-prepend input-group-text',
10626 inputblock.cn.push(input);
10628 if(this.hasFeedback && !this.allowBlank){
10629 inputblock.cls += ' has-feedback';
10630 inputblock.cn.push(feedback);
10634 inputblock.cn.push({
10636 cls : 'input-group-addon input-group-append input-group-text',
10645 var ibwrap = inputblock;
10650 cls: 'roo-select2-choices',
10654 cls: 'roo-select2-search-field',
10666 cls: 'roo-select2-container input-group',
10671 cls: 'form-hidden-field'
10677 if(!this.multiple && this.showToggleBtn){
10683 if (this.caret != false) {
10686 cls: 'fa fa-' + this.caret
10693 cls : 'input-group-addon input-group-append input-group-text btn dropdown-toggle',
10695 Roo.bootstrap.version == 3 ? caret : '',
10698 cls: 'combobox-clear',
10712 combobox.cls += ' roo-select2-container-multi';
10716 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
10717 tooltip : 'This field is required'
10719 if (Roo.bootstrap.version == 4) {
10722 style : 'display:none'
10727 if (align ==='left' && this.fieldLabel.length) {
10729 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
10736 cls : 'control-label',
10737 html : this.fieldLabel
10749 var labelCfg = cfg.cn[1];
10750 var contentCfg = cfg.cn[2];
10752 if(this.indicatorpos == 'right'){
10757 cls : 'control-label',
10761 html : this.fieldLabel
10775 labelCfg = cfg.cn[0];
10776 contentCfg = cfg.cn[1];
10779 if(this.labelWidth > 12){
10780 labelCfg.style = "width: " + this.labelWidth + 'px';
10783 if(this.labelWidth < 13 && this.labelmd == 0){
10784 this.labelmd = this.labelWidth;
10787 if(this.labellg > 0){
10788 labelCfg.cls += ' col-lg-' + this.labellg;
10789 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
10792 if(this.labelmd > 0){
10793 labelCfg.cls += ' col-md-' + this.labelmd;
10794 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
10797 if(this.labelsm > 0){
10798 labelCfg.cls += ' col-sm-' + this.labelsm;
10799 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
10802 if(this.labelxs > 0){
10803 labelCfg.cls += ' col-xs-' + this.labelxs;
10804 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
10807 } else if ( this.fieldLabel.length) {
10808 // Roo.log(" label");
10813 //cls : 'input-group-addon',
10814 html : this.fieldLabel
10822 if(this.indicatorpos == 'right'){
10830 html : this.fieldLabel
10844 // Roo.log(" no label && no align");
10851 ['xs','sm','md','lg'].map(function(size){
10852 if (settings[size]) {
10853 cfg.cls += ' col-' + size + '-' + settings[size];
10864 onResize : function(w, h){
10865 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
10866 // if(typeof w == 'number'){
10867 // var x = w - this.trigger.getWidth();
10868 // this.inputEl().setWidth(this.adjustWidth('input', x));
10869 // this.trigger.setStyle('left', x+'px');
10874 adjustSize : Roo.BoxComponent.prototype.adjustSize,
10877 getResizeEl : function(){
10878 return this.inputEl();
10882 getPositionEl : function(){
10883 return this.inputEl();
10887 alignErrorIcon : function(){
10888 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
10892 initEvents : function(){
10896 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
10897 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
10898 if(!this.multiple && this.showToggleBtn){
10899 this.trigger = this.el.select('span.dropdown-toggle',true).first();
10900 if(this.hideTrigger){
10901 this.trigger.setDisplayed(false);
10903 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10907 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
10910 if(this.removable && !this.editable && !this.tickable){
10911 var close = this.closeTriggerEl();
10914 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
10915 close.on('click', this.removeBtnClick, this, close);
10919 //this.trigger.addClassOnOver('x-form-trigger-over');
10920 //this.trigger.addClassOnClick('x-form-trigger-click');
10923 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
10927 closeTriggerEl : function()
10929 var close = this.el.select('.roo-combo-removable-btn', true).first();
10930 return close ? close : false;
10933 removeBtnClick : function(e, h, el)
10935 e.preventDefault();
10937 if(this.fireEvent("remove", this) !== false){
10939 this.fireEvent("afterremove", this)
10943 createList : function()
10945 this.list = Roo.get(document.body).createChild({
10946 tag: Roo.bootstrap.version == 4 ? 'div' : 'ul',
10947 cls: 'typeahead typeahead-long dropdown-menu',
10948 style: 'display:none'
10951 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
10956 initTrigger : function(){
10961 onDestroy : function(){
10963 this.trigger.removeAllListeners();
10964 // this.trigger.remove();
10967 // this.wrap.remove();
10969 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
10973 onFocus : function(){
10974 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
10976 if(!this.mimicing){
10977 this.wrap.addClass('x-trigger-wrap-focus');
10978 this.mimicing = true;
10979 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
10980 if(this.monitorTab){
10981 this.el.on("keydown", this.checkTab, this);
10988 checkTab : function(e){
10989 if(e.getKey() == e.TAB){
10990 this.triggerBlur();
10995 onBlur : function(){
11000 mimicBlur : function(e, t){
11002 if(!this.wrap.contains(t) && this.validateBlur()){
11003 this.triggerBlur();
11009 triggerBlur : function(){
11010 this.mimicing = false;
11011 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
11012 if(this.monitorTab){
11013 this.el.un("keydown", this.checkTab, this);
11015 //this.wrap.removeClass('x-trigger-wrap-focus');
11016 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
11020 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
11021 validateBlur : function(e, t){
11026 onDisable : function(){
11027 this.inputEl().dom.disabled = true;
11028 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
11030 // this.wrap.addClass('x-item-disabled');
11035 onEnable : function(){
11036 this.inputEl().dom.disabled = false;
11037 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
11039 // this.el.removeClass('x-item-disabled');
11044 onShow : function(){
11045 var ae = this.getActionEl();
11048 ae.dom.style.display = '';
11049 ae.dom.style.visibility = 'visible';
11055 onHide : function(){
11056 var ae = this.getActionEl();
11057 ae.dom.style.display = 'none';
11061 * The function that should handle the trigger's click event. This method does nothing by default until overridden
11062 * by an implementing function.
11064 * @param {EventObject} e
11066 onTriggerClick : Roo.emptyFn
11070 * Ext JS Library 1.1.1
11071 * Copyright(c) 2006-2007, Ext JS, LLC.
11073 * Originally Released Under LGPL - original licence link has changed is not relivant.
11076 * <script type="text/javascript">
11081 * @class Roo.data.SortTypes
11083 * Defines the default sorting (casting?) comparison functions used when sorting data.
11085 Roo.data.SortTypes = {
11087 * Default sort that does nothing
11088 * @param {Mixed} s The value being converted
11089 * @return {Mixed} The comparison value
11091 none : function(s){
11096 * The regular expression used to strip tags
11100 stripTagsRE : /<\/?[^>]+>/gi,
11103 * Strips all HTML tags to sort on text only
11104 * @param {Mixed} s The value being converted
11105 * @return {String} The comparison value
11107 asText : function(s){
11108 return String(s).replace(this.stripTagsRE, "");
11112 * Strips all HTML tags to sort on text only - Case insensitive
11113 * @param {Mixed} s The value being converted
11114 * @return {String} The comparison value
11116 asUCText : function(s){
11117 return String(s).toUpperCase().replace(this.stripTagsRE, "");
11121 * Case insensitive string
11122 * @param {Mixed} s The value being converted
11123 * @return {String} The comparison value
11125 asUCString : function(s) {
11126 return String(s).toUpperCase();
11131 * @param {Mixed} s The value being converted
11132 * @return {Number} The comparison value
11134 asDate : function(s) {
11138 if(s instanceof Date){
11139 return s.getTime();
11141 return Date.parse(String(s));
11146 * @param {Mixed} s The value being converted
11147 * @return {Float} The comparison value
11149 asFloat : function(s) {
11150 var val = parseFloat(String(s).replace(/,/g, ""));
11159 * @param {Mixed} s The value being converted
11160 * @return {Number} The comparison value
11162 asInt : function(s) {
11163 var val = parseInt(String(s).replace(/,/g, ""));
11171 * Ext JS Library 1.1.1
11172 * Copyright(c) 2006-2007, Ext JS, LLC.
11174 * Originally Released Under LGPL - original licence link has changed is not relivant.
11177 * <script type="text/javascript">
11181 * @class Roo.data.Record
11182 * Instances of this class encapsulate both record <em>definition</em> information, and record
11183 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
11184 * to access Records cached in an {@link Roo.data.Store} object.<br>
11186 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
11187 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
11190 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
11192 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
11193 * {@link #create}. The parameters are the same.
11194 * @param {Array} data An associative Array of data values keyed by the field name.
11195 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
11196 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
11197 * not specified an integer id is generated.
11199 Roo.data.Record = function(data, id){
11200 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
11205 * Generate a constructor for a specific record layout.
11206 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
11207 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
11208 * Each field definition object may contain the following properties: <ul>
11209 * <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,
11210 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
11211 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
11212 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
11213 * is being used, then this is a string containing the javascript expression to reference the data relative to
11214 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
11215 * to the data item relative to the record element. If the mapping expression is the same as the field name,
11216 * this may be omitted.</p></li>
11217 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
11218 * <ul><li>auto (Default, implies no conversion)</li>
11223 * <li>date</li></ul></p></li>
11224 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
11225 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
11226 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
11227 * by the Reader into an object that will be stored in the Record. It is passed the
11228 * following parameters:<ul>
11229 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
11231 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
11233 * <br>usage:<br><pre><code>
11234 var TopicRecord = Roo.data.Record.create(
11235 {name: 'title', mapping: 'topic_title'},
11236 {name: 'author', mapping: 'username'},
11237 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
11238 {name: 'lastPost', mapping: 'post_time', type: 'date'},
11239 {name: 'lastPoster', mapping: 'user2'},
11240 {name: 'excerpt', mapping: 'post_text'}
11243 var myNewRecord = new TopicRecord({
11244 title: 'Do my job please',
11247 lastPost: new Date(),
11248 lastPoster: 'Animal',
11249 excerpt: 'No way dude!'
11251 myStore.add(myNewRecord);
11256 Roo.data.Record.create = function(o){
11257 var f = function(){
11258 f.superclass.constructor.apply(this, arguments);
11260 Roo.extend(f, Roo.data.Record);
11261 var p = f.prototype;
11262 p.fields = new Roo.util.MixedCollection(false, function(field){
11265 for(var i = 0, len = o.length; i < len; i++){
11266 p.fields.add(new Roo.data.Field(o[i]));
11268 f.getField = function(name){
11269 return p.fields.get(name);
11274 Roo.data.Record.AUTO_ID = 1000;
11275 Roo.data.Record.EDIT = 'edit';
11276 Roo.data.Record.REJECT = 'reject';
11277 Roo.data.Record.COMMIT = 'commit';
11279 Roo.data.Record.prototype = {
11281 * Readonly flag - true if this record has been modified.
11290 join : function(store){
11291 this.store = store;
11295 * Set the named field to the specified value.
11296 * @param {String} name The name of the field to set.
11297 * @param {Object} value The value to set the field to.
11299 set : function(name, value){
11300 if(this.data[name] == value){
11304 if(!this.modified){
11305 this.modified = {};
11307 if(typeof this.modified[name] == 'undefined'){
11308 this.modified[name] = this.data[name];
11310 this.data[name] = value;
11311 if(!this.editing && this.store){
11312 this.store.afterEdit(this);
11317 * Get the value of the named field.
11318 * @param {String} name The name of the field to get the value of.
11319 * @return {Object} The value of the field.
11321 get : function(name){
11322 return this.data[name];
11326 beginEdit : function(){
11327 this.editing = true;
11328 this.modified = {};
11332 cancelEdit : function(){
11333 this.editing = false;
11334 delete this.modified;
11338 endEdit : function(){
11339 this.editing = false;
11340 if(this.dirty && this.store){
11341 this.store.afterEdit(this);
11346 * Usually called by the {@link Roo.data.Store} which owns the Record.
11347 * Rejects all changes made to the Record since either creation, or the last commit operation.
11348 * Modified fields are reverted to their original values.
11350 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
11351 * of reject operations.
11353 reject : function(){
11354 var m = this.modified;
11356 if(typeof m[n] != "function"){
11357 this.data[n] = m[n];
11360 this.dirty = false;
11361 delete this.modified;
11362 this.editing = false;
11364 this.store.afterReject(this);
11369 * Usually called by the {@link Roo.data.Store} which owns the Record.
11370 * Commits all changes made to the Record since either creation, or the last commit operation.
11372 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
11373 * of commit operations.
11375 commit : function(){
11376 this.dirty = false;
11377 delete this.modified;
11378 this.editing = false;
11380 this.store.afterCommit(this);
11385 hasError : function(){
11386 return this.error != null;
11390 clearError : function(){
11395 * Creates a copy of this record.
11396 * @param {String} id (optional) A new record id if you don't want to use this record's id
11399 copy : function(newId) {
11400 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
11404 * Ext JS Library 1.1.1
11405 * Copyright(c) 2006-2007, Ext JS, LLC.
11407 * Originally Released Under LGPL - original licence link has changed is not relivant.
11410 * <script type="text/javascript">
11416 * @class Roo.data.Store
11417 * @extends Roo.util.Observable
11418 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
11419 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
11421 * 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
11422 * has no knowledge of the format of the data returned by the Proxy.<br>
11424 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
11425 * instances from the data object. These records are cached and made available through accessor functions.
11427 * Creates a new Store.
11428 * @param {Object} config A config object containing the objects needed for the Store to access data,
11429 * and read the data into Records.
11431 Roo.data.Store = function(config){
11432 this.data = new Roo.util.MixedCollection(false);
11433 this.data.getKey = function(o){
11436 this.baseParams = {};
11438 this.paramNames = {
11443 "multisort" : "_multisort"
11446 if(config && config.data){
11447 this.inlineData = config.data;
11448 delete config.data;
11451 Roo.apply(this, config);
11453 if(this.reader){ // reader passed
11454 this.reader = Roo.factory(this.reader, Roo.data);
11455 this.reader.xmodule = this.xmodule || false;
11456 if(!this.recordType){
11457 this.recordType = this.reader.recordType;
11459 if(this.reader.onMetaChange){
11460 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
11464 if(this.recordType){
11465 this.fields = this.recordType.prototype.fields;
11467 this.modified = [];
11471 * @event datachanged
11472 * Fires when the data cache has changed, and a widget which is using this Store
11473 * as a Record cache should refresh its view.
11474 * @param {Store} this
11476 datachanged : true,
11478 * @event metachange
11479 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
11480 * @param {Store} this
11481 * @param {Object} meta The JSON metadata
11486 * Fires when Records have been added to the Store
11487 * @param {Store} this
11488 * @param {Roo.data.Record[]} records The array of Records added
11489 * @param {Number} index The index at which the record(s) were added
11494 * Fires when a Record has been removed from the Store
11495 * @param {Store} this
11496 * @param {Roo.data.Record} record The Record that was removed
11497 * @param {Number} index The index at which the record was removed
11502 * Fires when a Record has been updated
11503 * @param {Store} this
11504 * @param {Roo.data.Record} record The Record that was updated
11505 * @param {String} operation The update operation being performed. Value may be one of:
11507 Roo.data.Record.EDIT
11508 Roo.data.Record.REJECT
11509 Roo.data.Record.COMMIT
11515 * Fires when the data cache has been cleared.
11516 * @param {Store} this
11520 * @event beforeload
11521 * Fires before a request is made for a new data object. If the beforeload handler returns false
11522 * the load action will be canceled.
11523 * @param {Store} this
11524 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11528 * @event beforeloadadd
11529 * Fires after a new set of Records has been loaded.
11530 * @param {Store} this
11531 * @param {Roo.data.Record[]} records The Records that were loaded
11532 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11534 beforeloadadd : true,
11537 * Fires after a new set of Records has been loaded, before they are added to the store.
11538 * @param {Store} this
11539 * @param {Roo.data.Record[]} records The Records that were loaded
11540 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11541 * @params {Object} return from reader
11545 * @event loadexception
11546 * Fires if an exception occurs in the Proxy during loading.
11547 * Called with the signature of the Proxy's "loadexception" event.
11548 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
11551 * @param {Object} return from JsonData.reader() - success, totalRecords, records
11552 * @param {Object} load options
11553 * @param {Object} jsonData from your request (normally this contains the Exception)
11555 loadexception : true
11559 this.proxy = Roo.factory(this.proxy, Roo.data);
11560 this.proxy.xmodule = this.xmodule || false;
11561 this.relayEvents(this.proxy, ["loadexception"]);
11563 this.sortToggle = {};
11564 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
11566 Roo.data.Store.superclass.constructor.call(this);
11568 if(this.inlineData){
11569 this.loadData(this.inlineData);
11570 delete this.inlineData;
11574 Roo.extend(Roo.data.Store, Roo.util.Observable, {
11576 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
11577 * without a remote query - used by combo/forms at present.
11581 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
11584 * @cfg {Array} data Inline data to be loaded when the store is initialized.
11587 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
11588 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
11591 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
11592 * on any HTTP request
11595 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
11598 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
11602 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
11603 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
11605 remoteSort : false,
11608 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
11609 * loaded or when a record is removed. (defaults to false).
11611 pruneModifiedRecords : false,
11614 lastOptions : null,
11617 * Add Records to the Store and fires the add event.
11618 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11620 add : function(records){
11621 records = [].concat(records);
11622 for(var i = 0, len = records.length; i < len; i++){
11623 records[i].join(this);
11625 var index = this.data.length;
11626 this.data.addAll(records);
11627 this.fireEvent("add", this, records, index);
11631 * Remove a Record from the Store and fires the remove event.
11632 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
11634 remove : function(record){
11635 var index = this.data.indexOf(record);
11636 this.data.removeAt(index);
11638 if(this.pruneModifiedRecords){
11639 this.modified.remove(record);
11641 this.fireEvent("remove", this, record, index);
11645 * Remove all Records from the Store and fires the clear event.
11647 removeAll : function(){
11649 if(this.pruneModifiedRecords){
11650 this.modified = [];
11652 this.fireEvent("clear", this);
11656 * Inserts Records to the Store at the given index and fires the add event.
11657 * @param {Number} index The start index at which to insert the passed Records.
11658 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11660 insert : function(index, records){
11661 records = [].concat(records);
11662 for(var i = 0, len = records.length; i < len; i++){
11663 this.data.insert(index, records[i]);
11664 records[i].join(this);
11666 this.fireEvent("add", this, records, index);
11670 * Get the index within the cache of the passed Record.
11671 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
11672 * @return {Number} The index of the passed Record. Returns -1 if not found.
11674 indexOf : function(record){
11675 return this.data.indexOf(record);
11679 * Get the index within the cache of the Record with the passed id.
11680 * @param {String} id The id of the Record to find.
11681 * @return {Number} The index of the Record. Returns -1 if not found.
11683 indexOfId : function(id){
11684 return this.data.indexOfKey(id);
11688 * Get the Record with the specified id.
11689 * @param {String} id The id of the Record to find.
11690 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
11692 getById : function(id){
11693 return this.data.key(id);
11697 * Get the Record at the specified index.
11698 * @param {Number} index The index of the Record to find.
11699 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
11701 getAt : function(index){
11702 return this.data.itemAt(index);
11706 * Returns a range of Records between specified indices.
11707 * @param {Number} startIndex (optional) The starting index (defaults to 0)
11708 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
11709 * @return {Roo.data.Record[]} An array of Records
11711 getRange : function(start, end){
11712 return this.data.getRange(start, end);
11716 storeOptions : function(o){
11717 o = Roo.apply({}, o);
11720 this.lastOptions = o;
11724 * Loads the Record cache from the configured Proxy using the configured Reader.
11726 * If using remote paging, then the first load call must specify the <em>start</em>
11727 * and <em>limit</em> properties in the options.params property to establish the initial
11728 * position within the dataset, and the number of Records to cache on each read from the Proxy.
11730 * <strong>It is important to note that for remote data sources, loading is asynchronous,
11731 * and this call will return before the new data has been loaded. Perform any post-processing
11732 * in a callback function, or in a "load" event handler.</strong>
11734 * @param {Object} options An object containing properties which control loading options:<ul>
11735 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
11736 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
11737 * passed the following arguments:<ul>
11738 * <li>r : Roo.data.Record[]</li>
11739 * <li>options: Options object from the load call</li>
11740 * <li>success: Boolean success indicator</li></ul></li>
11741 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
11742 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
11745 load : function(options){
11746 options = options || {};
11747 if(this.fireEvent("beforeload", this, options) !== false){
11748 this.storeOptions(options);
11749 var p = Roo.apply(options.params || {}, this.baseParams);
11750 // if meta was not loaded from remote source.. try requesting it.
11751 if (!this.reader.metaFromRemote) {
11752 p._requestMeta = 1;
11754 if(this.sortInfo && this.remoteSort){
11755 var pn = this.paramNames;
11756 p[pn["sort"]] = this.sortInfo.field;
11757 p[pn["dir"]] = this.sortInfo.direction;
11759 if (this.multiSort) {
11760 var pn = this.paramNames;
11761 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
11764 this.proxy.load(p, this.reader, this.loadRecords, this, options);
11769 * Reloads the Record cache from the configured Proxy using the configured Reader and
11770 * the options from the last load operation performed.
11771 * @param {Object} options (optional) An object containing properties which may override the options
11772 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
11773 * the most recently used options are reused).
11775 reload : function(options){
11776 this.load(Roo.applyIf(options||{}, this.lastOptions));
11780 // Called as a callback by the Reader during a load operation.
11781 loadRecords : function(o, options, success){
11782 if(!o || success === false){
11783 if(success !== false){
11784 this.fireEvent("load", this, [], options, o);
11786 if(options.callback){
11787 options.callback.call(options.scope || this, [], options, false);
11791 // if data returned failure - throw an exception.
11792 if (o.success === false) {
11793 // show a message if no listener is registered.
11794 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
11795 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
11797 // loadmask wil be hooked into this..
11798 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
11801 var r = o.records, t = o.totalRecords || r.length;
11803 this.fireEvent("beforeloadadd", this, r, options, o);
11805 if(!options || options.add !== true){
11806 if(this.pruneModifiedRecords){
11807 this.modified = [];
11809 for(var i = 0, len = r.length; i < len; i++){
11813 this.data = this.snapshot;
11814 delete this.snapshot;
11817 this.data.addAll(r);
11818 this.totalLength = t;
11820 this.fireEvent("datachanged", this);
11822 this.totalLength = Math.max(t, this.data.length+r.length);
11826 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
11828 var e = new Roo.data.Record({});
11830 e.set(this.parent.displayField, this.parent.emptyTitle);
11831 e.set(this.parent.valueField, '');
11836 this.fireEvent("load", this, r, options, o);
11837 if(options.callback){
11838 options.callback.call(options.scope || this, r, options, true);
11844 * Loads data from a passed data block. A Reader which understands the format of the data
11845 * must have been configured in the constructor.
11846 * @param {Object} data The data block from which to read the Records. The format of the data expected
11847 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
11848 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
11850 loadData : function(o, append){
11851 var r = this.reader.readRecords(o);
11852 this.loadRecords(r, {add: append}, true);
11856 * Gets the number of cached records.
11858 * <em>If using paging, this may not be the total size of the dataset. If the data object
11859 * used by the Reader contains the dataset size, then the getTotalCount() function returns
11860 * the data set size</em>
11862 getCount : function(){
11863 return this.data.length || 0;
11867 * Gets the total number of records in the dataset as returned by the server.
11869 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
11870 * the dataset size</em>
11872 getTotalCount : function(){
11873 return this.totalLength || 0;
11877 * Returns the sort state of the Store as an object with two properties:
11879 field {String} The name of the field by which the Records are sorted
11880 direction {String} The sort order, "ASC" or "DESC"
11883 getSortState : function(){
11884 return this.sortInfo;
11888 applySort : function(){
11889 if(this.sortInfo && !this.remoteSort){
11890 var s = this.sortInfo, f = s.field;
11891 var st = this.fields.get(f).sortType;
11892 var fn = function(r1, r2){
11893 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
11894 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
11896 this.data.sort(s.direction, fn);
11897 if(this.snapshot && this.snapshot != this.data){
11898 this.snapshot.sort(s.direction, fn);
11904 * Sets the default sort column and order to be used by the next load operation.
11905 * @param {String} fieldName The name of the field to sort by.
11906 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11908 setDefaultSort : function(field, dir){
11909 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
11913 * Sort the Records.
11914 * If remote sorting is used, the sort is performed on the server, and the cache is
11915 * reloaded. If local sorting is used, the cache is sorted internally.
11916 * @param {String} fieldName The name of the field to sort by.
11917 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11919 sort : function(fieldName, dir){
11920 var f = this.fields.get(fieldName);
11922 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
11924 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
11925 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
11930 this.sortToggle[f.name] = dir;
11931 this.sortInfo = {field: f.name, direction: dir};
11932 if(!this.remoteSort){
11934 this.fireEvent("datachanged", this);
11936 this.load(this.lastOptions);
11941 * Calls the specified function for each of the Records in the cache.
11942 * @param {Function} fn The function to call. The Record is passed as the first parameter.
11943 * Returning <em>false</em> aborts and exits the iteration.
11944 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
11946 each : function(fn, scope){
11947 this.data.each(fn, scope);
11951 * Gets all records modified since the last commit. Modified records are persisted across load operations
11952 * (e.g., during paging).
11953 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
11955 getModifiedRecords : function(){
11956 return this.modified;
11960 createFilterFn : function(property, value, anyMatch){
11961 if(!value.exec){ // not a regex
11962 value = String(value);
11963 if(value.length == 0){
11966 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
11968 return function(r){
11969 return value.test(r.data[property]);
11974 * Sums the value of <i>property</i> for each record between start and end and returns the result.
11975 * @param {String} property A field on your records
11976 * @param {Number} start The record index to start at (defaults to 0)
11977 * @param {Number} end The last record index to include (defaults to length - 1)
11978 * @return {Number} The sum
11980 sum : function(property, start, end){
11981 var rs = this.data.items, v = 0;
11982 start = start || 0;
11983 end = (end || end === 0) ? end : rs.length-1;
11985 for(var i = start; i <= end; i++){
11986 v += (rs[i].data[property] || 0);
11992 * Filter the records by a specified property.
11993 * @param {String} field A field on your records
11994 * @param {String/RegExp} value Either a string that the field
11995 * should start with or a RegExp to test against the field
11996 * @param {Boolean} anyMatch True to match any part not just the beginning
11998 filter : function(property, value, anyMatch){
11999 var fn = this.createFilterFn(property, value, anyMatch);
12000 return fn ? this.filterBy(fn) : this.clearFilter();
12004 * Filter by a function. The specified function will be called with each
12005 * record in this data source. If the function returns true the record is included,
12006 * otherwise it is filtered.
12007 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
12008 * @param {Object} scope (optional) The scope of the function (defaults to this)
12010 filterBy : function(fn, scope){
12011 this.snapshot = this.snapshot || this.data;
12012 this.data = this.queryBy(fn, scope||this);
12013 this.fireEvent("datachanged", this);
12017 * Query the records by a specified property.
12018 * @param {String} field A field on your records
12019 * @param {String/RegExp} value Either a string that the field
12020 * should start with or a RegExp to test against the field
12021 * @param {Boolean} anyMatch True to match any part not just the beginning
12022 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
12024 query : function(property, value, anyMatch){
12025 var fn = this.createFilterFn(property, value, anyMatch);
12026 return fn ? this.queryBy(fn) : this.data.clone();
12030 * Query by a function. The specified function will be called with each
12031 * record in this data source. If the function returns true the record is included
12033 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
12034 * @param {Object} scope (optional) The scope of the function (defaults to this)
12035 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
12037 queryBy : function(fn, scope){
12038 var data = this.snapshot || this.data;
12039 return data.filterBy(fn, scope||this);
12043 * Collects unique values for a particular dataIndex from this store.
12044 * @param {String} dataIndex The property to collect
12045 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
12046 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
12047 * @return {Array} An array of the unique values
12049 collect : function(dataIndex, allowNull, bypassFilter){
12050 var d = (bypassFilter === true && this.snapshot) ?
12051 this.snapshot.items : this.data.items;
12052 var v, sv, r = [], l = {};
12053 for(var i = 0, len = d.length; i < len; i++){
12054 v = d[i].data[dataIndex];
12056 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
12065 * Revert to a view of the Record cache with no filtering applied.
12066 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
12068 clearFilter : function(suppressEvent){
12069 if(this.snapshot && this.snapshot != this.data){
12070 this.data = this.snapshot;
12071 delete this.snapshot;
12072 if(suppressEvent !== true){
12073 this.fireEvent("datachanged", this);
12079 afterEdit : function(record){
12080 if(this.modified.indexOf(record) == -1){
12081 this.modified.push(record);
12083 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
12087 afterReject : function(record){
12088 this.modified.remove(record);
12089 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
12093 afterCommit : function(record){
12094 this.modified.remove(record);
12095 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
12099 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
12100 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
12102 commitChanges : function(){
12103 var m = this.modified.slice(0);
12104 this.modified = [];
12105 for(var i = 0, len = m.length; i < len; i++){
12111 * Cancel outstanding changes on all changed records.
12113 rejectChanges : function(){
12114 var m = this.modified.slice(0);
12115 this.modified = [];
12116 for(var i = 0, len = m.length; i < len; i++){
12121 onMetaChange : function(meta, rtype, o){
12122 this.recordType = rtype;
12123 this.fields = rtype.prototype.fields;
12124 delete this.snapshot;
12125 this.sortInfo = meta.sortInfo || this.sortInfo;
12126 this.modified = [];
12127 this.fireEvent('metachange', this, this.reader.meta);
12130 moveIndex : function(data, type)
12132 var index = this.indexOf(data);
12134 var newIndex = index + type;
12138 this.insert(newIndex, data);
12143 * Ext JS Library 1.1.1
12144 * Copyright(c) 2006-2007, Ext JS, LLC.
12146 * Originally Released Under LGPL - original licence link has changed is not relivant.
12149 * <script type="text/javascript">
12153 * @class Roo.data.SimpleStore
12154 * @extends Roo.data.Store
12155 * Small helper class to make creating Stores from Array data easier.
12156 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
12157 * @cfg {Array} fields An array of field definition objects, or field name strings.
12158 * @cfg {Array} data The multi-dimensional array of data
12160 * @param {Object} config
12162 Roo.data.SimpleStore = function(config){
12163 Roo.data.SimpleStore.superclass.constructor.call(this, {
12165 reader: new Roo.data.ArrayReader({
12168 Roo.data.Record.create(config.fields)
12170 proxy : new Roo.data.MemoryProxy(config.data)
12174 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
12176 * Ext JS Library 1.1.1
12177 * Copyright(c) 2006-2007, Ext JS, LLC.
12179 * Originally Released Under LGPL - original licence link has changed is not relivant.
12182 * <script type="text/javascript">
12187 * @extends Roo.data.Store
12188 * @class Roo.data.JsonStore
12189 * Small helper class to make creating Stores for JSON data easier. <br/>
12191 var store = new Roo.data.JsonStore({
12192 url: 'get-images.php',
12194 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
12197 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
12198 * JsonReader and HttpProxy (unless inline data is provided).</b>
12199 * @cfg {Array} fields An array of field definition objects, or field name strings.
12201 * @param {Object} config
12203 Roo.data.JsonStore = function(c){
12204 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
12205 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
12206 reader: new Roo.data.JsonReader(c, c.fields)
12209 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
12211 * Ext JS Library 1.1.1
12212 * Copyright(c) 2006-2007, Ext JS, LLC.
12214 * Originally Released Under LGPL - original licence link has changed is not relivant.
12217 * <script type="text/javascript">
12221 Roo.data.Field = function(config){
12222 if(typeof config == "string"){
12223 config = {name: config};
12225 Roo.apply(this, config);
12228 this.type = "auto";
12231 var st = Roo.data.SortTypes;
12232 // named sortTypes are supported, here we look them up
12233 if(typeof this.sortType == "string"){
12234 this.sortType = st[this.sortType];
12237 // set default sortType for strings and dates
12238 if(!this.sortType){
12241 this.sortType = st.asUCString;
12244 this.sortType = st.asDate;
12247 this.sortType = st.none;
12252 var stripRe = /[\$,%]/g;
12254 // prebuilt conversion function for this field, instead of
12255 // switching every time we're reading a value
12257 var cv, dateFormat = this.dateFormat;
12262 cv = function(v){ return v; };
12265 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
12269 return v !== undefined && v !== null && v !== '' ?
12270 parseInt(String(v).replace(stripRe, ""), 10) : '';
12275 return v !== undefined && v !== null && v !== '' ?
12276 parseFloat(String(v).replace(stripRe, ""), 10) : '';
12281 cv = function(v){ return v === true || v === "true" || v == 1; };
12288 if(v instanceof Date){
12292 if(dateFormat == "timestamp"){
12293 return new Date(v*1000);
12295 return Date.parseDate(v, dateFormat);
12297 var parsed = Date.parse(v);
12298 return parsed ? new Date(parsed) : null;
12307 Roo.data.Field.prototype = {
12315 * Ext JS Library 1.1.1
12316 * Copyright(c) 2006-2007, Ext JS, LLC.
12318 * Originally Released Under LGPL - original licence link has changed is not relivant.
12321 * <script type="text/javascript">
12324 // Base class for reading structured data from a data source. This class is intended to be
12325 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
12328 * @class Roo.data.DataReader
12329 * Base class for reading structured data from a data source. This class is intended to be
12330 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
12333 Roo.data.DataReader = function(meta, recordType){
12337 this.recordType = recordType instanceof Array ?
12338 Roo.data.Record.create(recordType) : recordType;
12341 Roo.data.DataReader.prototype = {
12343 * Create an empty record
12344 * @param {Object} data (optional) - overlay some values
12345 * @return {Roo.data.Record} record created.
12347 newRow : function(d) {
12349 this.recordType.prototype.fields.each(function(c) {
12351 case 'int' : da[c.name] = 0; break;
12352 case 'date' : da[c.name] = new Date(); break;
12353 case 'float' : da[c.name] = 0.0; break;
12354 case 'boolean' : da[c.name] = false; break;
12355 default : da[c.name] = ""; break;
12359 return new this.recordType(Roo.apply(da, d));
12364 * Ext JS Library 1.1.1
12365 * Copyright(c) 2006-2007, Ext JS, LLC.
12367 * Originally Released Under LGPL - original licence link has changed is not relivant.
12370 * <script type="text/javascript">
12374 * @class Roo.data.DataProxy
12375 * @extends Roo.data.Observable
12376 * This class is an abstract base class for implementations which provide retrieval of
12377 * unformatted data objects.<br>
12379 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
12380 * (of the appropriate type which knows how to parse the data object) to provide a block of
12381 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
12383 * Custom implementations must implement the load method as described in
12384 * {@link Roo.data.HttpProxy#load}.
12386 Roo.data.DataProxy = function(){
12389 * @event beforeload
12390 * Fires before a network request is made to retrieve a data object.
12391 * @param {Object} This DataProxy object.
12392 * @param {Object} params The params parameter to the load function.
12397 * Fires before the load method's callback is called.
12398 * @param {Object} This DataProxy object.
12399 * @param {Object} o The data object.
12400 * @param {Object} arg The callback argument object passed to the load function.
12404 * @event loadexception
12405 * Fires if an Exception occurs during data retrieval.
12406 * @param {Object} This DataProxy object.
12407 * @param {Object} o The data object.
12408 * @param {Object} arg The callback argument object passed to the load function.
12409 * @param {Object} e The Exception.
12411 loadexception : true
12413 Roo.data.DataProxy.superclass.constructor.call(this);
12416 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
12419 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
12423 * Ext JS Library 1.1.1
12424 * Copyright(c) 2006-2007, Ext JS, LLC.
12426 * Originally Released Under LGPL - original licence link has changed is not relivant.
12429 * <script type="text/javascript">
12432 * @class Roo.data.MemoryProxy
12433 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
12434 * to the Reader when its load method is called.
12436 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
12438 Roo.data.MemoryProxy = function(data){
12442 Roo.data.MemoryProxy.superclass.constructor.call(this);
12446 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
12449 * Load data from the requested source (in this case an in-memory
12450 * data object passed to the constructor), read the data object into
12451 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12452 * process that block using the passed callback.
12453 * @param {Object} params This parameter is not used by the MemoryProxy class.
12454 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12455 * object into a block of Roo.data.Records.
12456 * @param {Function} callback The function into which to pass the block of Roo.data.records.
12457 * The function must be passed <ul>
12458 * <li>The Record block object</li>
12459 * <li>The "arg" argument from the load function</li>
12460 * <li>A boolean success indicator</li>
12462 * @param {Object} scope The scope in which to call the callback
12463 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12465 load : function(params, reader, callback, scope, arg){
12466 params = params || {};
12469 result = reader.readRecords(params.data ? params.data :this.data);
12471 this.fireEvent("loadexception", this, arg, null, e);
12472 callback.call(scope, null, arg, false);
12475 callback.call(scope, result, arg, true);
12479 update : function(params, records){
12484 * Ext JS Library 1.1.1
12485 * Copyright(c) 2006-2007, Ext JS, LLC.
12487 * Originally Released Under LGPL - original licence link has changed is not relivant.
12490 * <script type="text/javascript">
12493 * @class Roo.data.HttpProxy
12494 * @extends Roo.data.DataProxy
12495 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
12496 * configured to reference a certain URL.<br><br>
12498 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
12499 * from which the running page was served.<br><br>
12501 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
12503 * Be aware that to enable the browser to parse an XML document, the server must set
12504 * the Content-Type header in the HTTP response to "text/xml".
12506 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
12507 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
12508 * will be used to make the request.
12510 Roo.data.HttpProxy = function(conn){
12511 Roo.data.HttpProxy.superclass.constructor.call(this);
12512 // is conn a conn config or a real conn?
12514 this.useAjax = !conn || !conn.events;
12518 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
12519 // thse are take from connection...
12522 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
12525 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
12526 * extra parameters to each request made by this object. (defaults to undefined)
12529 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
12530 * to each request made by this object. (defaults to undefined)
12533 * @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)
12536 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
12539 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
12545 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
12549 * Return the {@link Roo.data.Connection} object being used by this Proxy.
12550 * @return {Connection} The Connection object. This object may be used to subscribe to events on
12551 * a finer-grained basis than the DataProxy events.
12553 getConnection : function(){
12554 return this.useAjax ? Roo.Ajax : this.conn;
12558 * Load data from the configured {@link Roo.data.Connection}, read the data object into
12559 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
12560 * process that block using the passed callback.
12561 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12562 * for the request to the remote server.
12563 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12564 * object into a block of Roo.data.Records.
12565 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12566 * The function must be passed <ul>
12567 * <li>The Record block object</li>
12568 * <li>The "arg" argument from the load function</li>
12569 * <li>A boolean success indicator</li>
12571 * @param {Object} scope The scope in which to call the callback
12572 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12574 load : function(params, reader, callback, scope, arg){
12575 if(this.fireEvent("beforeload", this, params) !== false){
12577 params : params || {},
12579 callback : callback,
12584 callback : this.loadResponse,
12588 Roo.applyIf(o, this.conn);
12589 if(this.activeRequest){
12590 Roo.Ajax.abort(this.activeRequest);
12592 this.activeRequest = Roo.Ajax.request(o);
12594 this.conn.request(o);
12597 callback.call(scope||this, null, arg, false);
12602 loadResponse : function(o, success, response){
12603 delete this.activeRequest;
12605 this.fireEvent("loadexception", this, o, response);
12606 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12611 result = o.reader.read(response);
12613 this.fireEvent("loadexception", this, o, response, e);
12614 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12618 this.fireEvent("load", this, o, o.request.arg);
12619 o.request.callback.call(o.request.scope, result, o.request.arg, true);
12623 update : function(dataSet){
12628 updateResponse : function(dataSet){
12633 * Ext JS Library 1.1.1
12634 * Copyright(c) 2006-2007, Ext JS, LLC.
12636 * Originally Released Under LGPL - original licence link has changed is not relivant.
12639 * <script type="text/javascript">
12643 * @class Roo.data.ScriptTagProxy
12644 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
12645 * other than the originating domain of the running page.<br><br>
12647 * <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
12648 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
12650 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
12651 * source code that is used as the source inside a <script> tag.<br><br>
12653 * In order for the browser to process the returned data, the server must wrap the data object
12654 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
12655 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
12656 * depending on whether the callback name was passed:
12659 boolean scriptTag = false;
12660 String cb = request.getParameter("callback");
12663 response.setContentType("text/javascript");
12665 response.setContentType("application/x-json");
12667 Writer out = response.getWriter();
12669 out.write(cb + "(");
12671 out.print(dataBlock.toJsonString());
12678 * @param {Object} config A configuration object.
12680 Roo.data.ScriptTagProxy = function(config){
12681 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
12682 Roo.apply(this, config);
12683 this.head = document.getElementsByTagName("head")[0];
12686 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
12688 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
12690 * @cfg {String} url The URL from which to request the data object.
12693 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
12697 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
12698 * the server the name of the callback function set up by the load call to process the returned data object.
12699 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
12700 * javascript output which calls this named function passing the data object as its only parameter.
12702 callbackParam : "callback",
12704 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
12705 * name to the request.
12710 * Load data from the configured URL, read the data object into
12711 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12712 * process that block using the passed callback.
12713 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12714 * for the request to the remote server.
12715 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12716 * object into a block of Roo.data.Records.
12717 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12718 * The function must be passed <ul>
12719 * <li>The Record block object</li>
12720 * <li>The "arg" argument from the load function</li>
12721 * <li>A boolean success indicator</li>
12723 * @param {Object} scope The scope in which to call the callback
12724 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12726 load : function(params, reader, callback, scope, arg){
12727 if(this.fireEvent("beforeload", this, params) !== false){
12729 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
12731 var url = this.url;
12732 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
12734 url += "&_dc=" + (new Date().getTime());
12736 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
12739 cb : "stcCallback"+transId,
12740 scriptId : "stcScript"+transId,
12744 callback : callback,
12750 window[trans.cb] = function(o){
12751 conn.handleResponse(o, trans);
12754 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
12756 if(this.autoAbort !== false){
12760 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
12762 var script = document.createElement("script");
12763 script.setAttribute("src", url);
12764 script.setAttribute("type", "text/javascript");
12765 script.setAttribute("id", trans.scriptId);
12766 this.head.appendChild(script);
12768 this.trans = trans;
12770 callback.call(scope||this, null, arg, false);
12775 isLoading : function(){
12776 return this.trans ? true : false;
12780 * Abort the current server request.
12782 abort : function(){
12783 if(this.isLoading()){
12784 this.destroyTrans(this.trans);
12789 destroyTrans : function(trans, isLoaded){
12790 this.head.removeChild(document.getElementById(trans.scriptId));
12791 clearTimeout(trans.timeoutId);
12793 window[trans.cb] = undefined;
12795 delete window[trans.cb];
12798 // if hasn't been loaded, wait for load to remove it to prevent script error
12799 window[trans.cb] = function(){
12800 window[trans.cb] = undefined;
12802 delete window[trans.cb];
12809 handleResponse : function(o, trans){
12810 this.trans = false;
12811 this.destroyTrans(trans, true);
12814 result = trans.reader.readRecords(o);
12816 this.fireEvent("loadexception", this, o, trans.arg, e);
12817 trans.callback.call(trans.scope||window, null, trans.arg, false);
12820 this.fireEvent("load", this, o, trans.arg);
12821 trans.callback.call(trans.scope||window, result, trans.arg, true);
12825 handleFailure : function(trans){
12826 this.trans = false;
12827 this.destroyTrans(trans, false);
12828 this.fireEvent("loadexception", this, null, trans.arg);
12829 trans.callback.call(trans.scope||window, null, trans.arg, false);
12833 * Ext JS Library 1.1.1
12834 * Copyright(c) 2006-2007, Ext JS, LLC.
12836 * Originally Released Under LGPL - original licence link has changed is not relivant.
12839 * <script type="text/javascript">
12843 * @class Roo.data.JsonReader
12844 * @extends Roo.data.DataReader
12845 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
12846 * based on mappings in a provided Roo.data.Record constructor.
12848 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
12849 * in the reply previously.
12854 var RecordDef = Roo.data.Record.create([
12855 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
12856 {name: 'occupation'} // This field will use "occupation" as the mapping.
12858 var myReader = new Roo.data.JsonReader({
12859 totalProperty: "results", // The property which contains the total dataset size (optional)
12860 root: "rows", // The property which contains an Array of row objects
12861 id: "id" // The property within each row object that provides an ID for the record (optional)
12865 * This would consume a JSON file like this:
12867 { 'results': 2, 'rows': [
12868 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
12869 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
12872 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
12873 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
12874 * paged from the remote server.
12875 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
12876 * @cfg {String} root name of the property which contains the Array of row objects.
12877 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
12878 * @cfg {Array} fields Array of field definition objects
12880 * Create a new JsonReader
12881 * @param {Object} meta Metadata configuration options
12882 * @param {Object} recordType Either an Array of field definition objects,
12883 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
12885 Roo.data.JsonReader = function(meta, recordType){
12888 // set some defaults:
12889 Roo.applyIf(meta, {
12890 totalProperty: 'total',
12891 successProperty : 'success',
12896 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
12898 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
12901 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
12902 * Used by Store query builder to append _requestMeta to params.
12905 metaFromRemote : false,
12907 * This method is only used by a DataProxy which has retrieved data from a remote server.
12908 * @param {Object} response The XHR object which contains the JSON data in its responseText.
12909 * @return {Object} data A data block which is used by an Roo.data.Store object as
12910 * a cache of Roo.data.Records.
12912 read : function(response){
12913 var json = response.responseText;
12915 var o = /* eval:var:o */ eval("("+json+")");
12917 throw {message: "JsonReader.read: Json object not found"};
12923 this.metaFromRemote = true;
12924 this.meta = o.metaData;
12925 this.recordType = Roo.data.Record.create(o.metaData.fields);
12926 this.onMetaChange(this.meta, this.recordType, o);
12928 return this.readRecords(o);
12931 // private function a store will implement
12932 onMetaChange : function(meta, recordType, o){
12939 simpleAccess: function(obj, subsc) {
12946 getJsonAccessor: function(){
12948 return function(expr) {
12950 return(re.test(expr))
12951 ? new Function("obj", "return obj." + expr)
12956 return Roo.emptyFn;
12961 * Create a data block containing Roo.data.Records from an XML document.
12962 * @param {Object} o An object which contains an Array of row objects in the property specified
12963 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
12964 * which contains the total size of the dataset.
12965 * @return {Object} data A data block which is used by an Roo.data.Store object as
12966 * a cache of Roo.data.Records.
12968 readRecords : function(o){
12970 * After any data loads, the raw JSON data is available for further custom processing.
12974 var s = this.meta, Record = this.recordType,
12975 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
12977 // Generate extraction functions for the totalProperty, the root, the id, and for each field
12979 if(s.totalProperty) {
12980 this.getTotal = this.getJsonAccessor(s.totalProperty);
12982 if(s.successProperty) {
12983 this.getSuccess = this.getJsonAccessor(s.successProperty);
12985 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
12987 var g = this.getJsonAccessor(s.id);
12988 this.getId = function(rec) {
12990 return (r === undefined || r === "") ? null : r;
12993 this.getId = function(){return null;};
12996 for(var jj = 0; jj < fl; jj++){
12998 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
12999 this.ef[jj] = this.getJsonAccessor(map);
13003 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
13004 if(s.totalProperty){
13005 var vt = parseInt(this.getTotal(o), 10);
13010 if(s.successProperty){
13011 var vs = this.getSuccess(o);
13012 if(vs === false || vs === 'false'){
13017 for(var i = 0; i < c; i++){
13020 var id = this.getId(n);
13021 for(var j = 0; j < fl; j++){
13023 var v = this.ef[j](n);
13025 Roo.log('missing convert for ' + f.name);
13029 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
13031 var record = new Record(values, id);
13033 records[i] = record;
13039 totalRecords : totalRecords
13044 * Ext JS Library 1.1.1
13045 * Copyright(c) 2006-2007, Ext JS, LLC.
13047 * Originally Released Under LGPL - original licence link has changed is not relivant.
13050 * <script type="text/javascript">
13054 * @class Roo.data.ArrayReader
13055 * @extends Roo.data.DataReader
13056 * Data reader class to create an Array of Roo.data.Record objects from an Array.
13057 * Each element of that Array represents a row of data fields. The
13058 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
13059 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
13063 var RecordDef = Roo.data.Record.create([
13064 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
13065 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
13067 var myReader = new Roo.data.ArrayReader({
13068 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
13072 * This would consume an Array like this:
13074 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
13078 * Create a new JsonReader
13079 * @param {Object} meta Metadata configuration options.
13080 * @param {Object|Array} recordType Either an Array of field definition objects
13082 * @cfg {Array} fields Array of field definition objects
13083 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
13084 * as specified to {@link Roo.data.Record#create},
13085 * or an {@link Roo.data.Record} object
13088 * created using {@link Roo.data.Record#create}.
13090 Roo.data.ArrayReader = function(meta, recordType){
13093 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType||meta.fields);
13096 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
13098 * Create a data block containing Roo.data.Records from an XML document.
13099 * @param {Object} o An Array of row objects which represents the dataset.
13100 * @return {Object} A data block which is used by an {@link Roo.data.Store} object as
13101 * a cache of Roo.data.Records.
13103 readRecords : function(o){
13104 var sid = this.meta ? this.meta.id : null;
13105 var recordType = this.recordType, fields = recordType.prototype.fields;
13108 for(var i = 0; i < root.length; i++){
13111 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
13112 for(var j = 0, jlen = fields.length; j < jlen; j++){
13113 var f = fields.items[j];
13114 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
13115 var v = n[k] !== undefined ? n[k] : f.defaultValue;
13117 values[f.name] = v;
13119 var record = new recordType(values, id);
13121 records[records.length] = record;
13125 totalRecords : records.length
13134 * @class Roo.bootstrap.ComboBox
13135 * @extends Roo.bootstrap.TriggerField
13136 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
13137 * @cfg {Boolean} append (true|false) default false
13138 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
13139 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
13140 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
13141 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
13142 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
13143 * @cfg {Boolean} animate default true
13144 * @cfg {Boolean} emptyResultText only for touch device
13145 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
13146 * @cfg {String} emptyTitle default ''
13148 * Create a new ComboBox.
13149 * @param {Object} config Configuration options
13151 Roo.bootstrap.ComboBox = function(config){
13152 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
13156 * Fires when the dropdown list is expanded
13157 * @param {Roo.bootstrap.ComboBox} combo This combo box
13162 * Fires when the dropdown list is collapsed
13163 * @param {Roo.bootstrap.ComboBox} combo This combo box
13167 * @event beforeselect
13168 * Fires before a list item is selected. Return false to cancel the selection.
13169 * @param {Roo.bootstrap.ComboBox} combo This combo box
13170 * @param {Roo.data.Record} record The data record returned from the underlying store
13171 * @param {Number} index The index of the selected item in the dropdown list
13173 'beforeselect' : true,
13176 * Fires when a list item is selected
13177 * @param {Roo.bootstrap.ComboBox} combo This combo box
13178 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
13179 * @param {Number} index The index of the selected item in the dropdown list
13183 * @event beforequery
13184 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
13185 * The event object passed has these properties:
13186 * @param {Roo.bootstrap.ComboBox} combo This combo box
13187 * @param {String} query The query
13188 * @param {Boolean} forceAll true to force "all" query
13189 * @param {Boolean} cancel true to cancel the query
13190 * @param {Object} e The query event object
13192 'beforequery': true,
13195 * Fires when the 'add' icon is pressed (add a listener to enable add button)
13196 * @param {Roo.bootstrap.ComboBox} combo This combo box
13201 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
13202 * @param {Roo.bootstrap.ComboBox} combo This combo box
13203 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
13208 * Fires when the remove value from the combobox array
13209 * @param {Roo.bootstrap.ComboBox} combo This combo box
13213 * @event afterremove
13214 * Fires when the remove value from the combobox array
13215 * @param {Roo.bootstrap.ComboBox} combo This combo box
13217 'afterremove' : true,
13219 * @event specialfilter
13220 * Fires when specialfilter
13221 * @param {Roo.bootstrap.ComboBox} combo This combo box
13223 'specialfilter' : true,
13226 * Fires when tick the element
13227 * @param {Roo.bootstrap.ComboBox} combo This combo box
13231 * @event touchviewdisplay
13232 * Fires when touch view require special display (default is using displayField)
13233 * @param {Roo.bootstrap.ComboBox} combo This combo box
13234 * @param {Object} cfg set html .
13236 'touchviewdisplay' : true
13241 this.tickItems = [];
13243 this.selectedIndex = -1;
13244 if(this.mode == 'local'){
13245 if(config.queryDelay === undefined){
13246 this.queryDelay = 10;
13248 if(config.minChars === undefined){
13254 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
13257 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
13258 * rendering into an Roo.Editor, defaults to false)
13261 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
13262 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
13265 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
13268 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
13269 * the dropdown list (defaults to undefined, with no header element)
13273 * @cfg {String/Roo.Template} tpl The template to use to render the output
13277 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
13279 listWidth: undefined,
13281 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
13282 * mode = 'remote' or 'text' if mode = 'local')
13284 displayField: undefined,
13287 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
13288 * mode = 'remote' or 'value' if mode = 'local').
13289 * Note: use of a valueField requires the user make a selection
13290 * in order for a value to be mapped.
13292 valueField: undefined,
13294 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
13299 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
13300 * field's data value (defaults to the underlying DOM element's name)
13302 hiddenName: undefined,
13304 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
13308 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
13310 selectedClass: 'active',
13313 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
13317 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
13318 * anchor positions (defaults to 'tl-bl')
13320 listAlign: 'tl-bl?',
13322 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
13326 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
13327 * query specified by the allQuery config option (defaults to 'query')
13329 triggerAction: 'query',
13331 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
13332 * (defaults to 4, does not apply if editable = false)
13336 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
13337 * delay (typeAheadDelay) if it matches a known value (defaults to false)
13341 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
13342 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
13346 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
13347 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
13351 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
13352 * when editable = true (defaults to false)
13354 selectOnFocus:false,
13356 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
13358 queryParam: 'query',
13360 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
13361 * when mode = 'remote' (defaults to 'Loading...')
13363 loadingText: 'Loading...',
13365 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
13369 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
13373 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
13374 * traditional select (defaults to true)
13378 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
13382 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
13386 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
13387 * listWidth has a higher value)
13391 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
13392 * allow the user to set arbitrary text into the field (defaults to false)
13394 forceSelection:false,
13396 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
13397 * if typeAhead = true (defaults to 250)
13399 typeAheadDelay : 250,
13401 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
13402 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
13404 valueNotFoundText : undefined,
13406 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
13408 blockFocus : false,
13411 * @cfg {Boolean} disableClear Disable showing of clear button.
13413 disableClear : false,
13415 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
13417 alwaysQuery : false,
13420 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
13425 * @cfg {String} invalidClass DEPRICATED - uses BS4 is-valid now
13427 invalidClass : "has-warning",
13430 * @cfg {String} validClass DEPRICATED - uses BS4 is-valid now
13432 validClass : "has-success",
13435 * @cfg {Boolean} specialFilter (true|false) special filter default false
13437 specialFilter : false,
13440 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
13442 mobileTouchView : true,
13445 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
13447 useNativeIOS : false,
13450 * @cfg {Boolean} mobile_restrict_height (true|false) restrict height for touch view
13452 mobile_restrict_height : false,
13454 ios_options : false,
13466 btnPosition : 'right',
13467 triggerList : true,
13468 showToggleBtn : true,
13470 emptyResultText: 'Empty',
13471 triggerText : 'Select',
13474 // element that contains real text value.. (when hidden is used..)
13476 getAutoCreate : function()
13481 * Render classic select for iso
13484 if(Roo.isIOS && this.useNativeIOS){
13485 cfg = this.getAutoCreateNativeIOS();
13493 if(Roo.isTouch && this.mobileTouchView){
13494 cfg = this.getAutoCreateTouchView();
13501 if(!this.tickable){
13502 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
13507 * ComboBox with tickable selections
13510 var align = this.labelAlign || this.parentLabelAlign();
13513 cls : 'form-group roo-combobox-tickable' //input-group
13516 var btn_text_select = '';
13517 var btn_text_done = '';
13518 var btn_text_cancel = '';
13520 if (this.btn_text_show) {
13521 btn_text_select = 'Select';
13522 btn_text_done = 'Done';
13523 btn_text_cancel = 'Cancel';
13528 cls : 'tickable-buttons',
13533 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
13534 //html : this.triggerText
13535 html: btn_text_select
13541 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
13543 html: btn_text_done
13549 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
13551 html: btn_text_cancel
13557 buttons.cn.unshift({
13559 cls: 'roo-select2-search-field-input'
13565 Roo.each(buttons.cn, function(c){
13567 c.cls += ' btn-' + _this.size;
13570 if (_this.disabled) {
13577 style : 'display: contents',
13582 cls: 'form-hidden-field'
13586 cls: 'roo-select2-choices',
13590 cls: 'roo-select2-search-field',
13601 cls: 'roo-select2-container input-group roo-select2-container-multi',
13607 // cls: 'typeahead typeahead-long dropdown-menu',
13608 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
13613 if(this.hasFeedback && !this.allowBlank){
13617 cls: 'glyphicon form-control-feedback'
13620 combobox.cn.push(feedback);
13625 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
13626 tooltip : 'This field is required'
13628 if (Roo.bootstrap.version == 4) {
13631 style : 'display:none'
13634 if (align ==='left' && this.fieldLabel.length) {
13636 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
13643 cls : 'control-label col-form-label',
13644 html : this.fieldLabel
13656 var labelCfg = cfg.cn[1];
13657 var contentCfg = cfg.cn[2];
13660 if(this.indicatorpos == 'right'){
13666 cls : 'control-label col-form-label',
13670 html : this.fieldLabel
13686 labelCfg = cfg.cn[0];
13687 contentCfg = cfg.cn[1];
13691 if(this.labelWidth > 12){
13692 labelCfg.style = "width: " + this.labelWidth + 'px';
13695 if(this.labelWidth < 13 && this.labelmd == 0){
13696 this.labelmd = this.labelWidth;
13699 if(this.labellg > 0){
13700 labelCfg.cls += ' col-lg-' + this.labellg;
13701 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
13704 if(this.labelmd > 0){
13705 labelCfg.cls += ' col-md-' + this.labelmd;
13706 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
13709 if(this.labelsm > 0){
13710 labelCfg.cls += ' col-sm-' + this.labelsm;
13711 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
13714 if(this.labelxs > 0){
13715 labelCfg.cls += ' col-xs-' + this.labelxs;
13716 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
13720 } else if ( this.fieldLabel.length) {
13721 // Roo.log(" label");
13726 //cls : 'input-group-addon',
13727 html : this.fieldLabel
13732 if(this.indicatorpos == 'right'){
13736 //cls : 'input-group-addon',
13737 html : this.fieldLabel
13747 // Roo.log(" no label && no align");
13754 ['xs','sm','md','lg'].map(function(size){
13755 if (settings[size]) {
13756 cfg.cls += ' col-' + size + '-' + settings[size];
13764 _initEventsCalled : false,
13767 initEvents: function()
13769 if (this._initEventsCalled) { // as we call render... prevent looping...
13772 this._initEventsCalled = true;
13775 throw "can not find store for combo";
13778 this.indicator = this.indicatorEl();
13780 this.store = Roo.factory(this.store, Roo.data);
13781 this.store.parent = this;
13783 // if we are building from html. then this element is so complex, that we can not really
13784 // use the rendered HTML.
13785 // so we have to trash and replace the previous code.
13786 if (Roo.XComponent.build_from_html) {
13787 // remove this element....
13788 var e = this.el.dom, k=0;
13789 while (e ) { e = e.previousSibling; ++k;}
13794 this.rendered = false;
13796 this.render(this.parent().getChildContainer(true), k);
13799 if(Roo.isIOS && this.useNativeIOS){
13800 this.initIOSView();
13808 if(Roo.isTouch && this.mobileTouchView){
13809 this.initTouchView();
13814 this.initTickableEvents();
13818 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
13820 if(this.hiddenName){
13822 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13824 this.hiddenField.dom.value =
13825 this.hiddenValue !== undefined ? this.hiddenValue :
13826 this.value !== undefined ? this.value : '';
13828 // prevent input submission
13829 this.el.dom.removeAttribute('name');
13830 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13835 // this.el.dom.setAttribute('autocomplete', 'off');
13838 var cls = 'x-combo-list';
13840 //this.list = new Roo.Layer({
13841 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
13847 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13848 _this.list.setWidth(lw);
13851 this.list.on('mouseover', this.onViewOver, this);
13852 this.list.on('mousemove', this.onViewMove, this);
13853 this.list.on('scroll', this.onViewScroll, this);
13856 this.list.swallowEvent('mousewheel');
13857 this.assetHeight = 0;
13860 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
13861 this.assetHeight += this.header.getHeight();
13864 this.innerList = this.list.createChild({cls:cls+'-inner'});
13865 this.innerList.on('mouseover', this.onViewOver, this);
13866 this.innerList.on('mousemove', this.onViewMove, this);
13867 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13869 if(this.allowBlank && !this.pageSize && !this.disableClear){
13870 this.footer = this.list.createChild({cls:cls+'-ft'});
13871 this.pageTb = new Roo.Toolbar(this.footer);
13875 this.footer = this.list.createChild({cls:cls+'-ft'});
13876 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
13877 {pageSize: this.pageSize});
13881 if (this.pageTb && this.allowBlank && !this.disableClear) {
13883 this.pageTb.add(new Roo.Toolbar.Fill(), {
13884 cls: 'x-btn-icon x-btn-clear',
13886 handler: function()
13889 _this.clearValue();
13890 _this.onSelect(false, -1);
13895 this.assetHeight += this.footer.getHeight();
13900 this.tpl = Roo.bootstrap.version == 4 ?
13901 '<a class="dropdown-item" href="#">{' + this.displayField + '}</a>' : // 4 does not need <li> and it get's really confisued.
13902 '<li><a class="dropdown-item" href="#">{' + this.displayField + '}</a></li>';
13905 this.view = new Roo.View(this.list, this.tpl, {
13906 singleSelect:true, store: this.store, selectedClass: this.selectedClass
13908 //this.view.wrapEl.setDisplayed(false);
13909 this.view.on('click', this.onViewClick, this);
13912 this.store.on('beforeload', this.onBeforeLoad, this);
13913 this.store.on('load', this.onLoad, this);
13914 this.store.on('loadexception', this.onLoadException, this);
13916 if(this.resizable){
13917 this.resizer = new Roo.Resizable(this.list, {
13918 pinned:true, handles:'se'
13920 this.resizer.on('resize', function(r, w, h){
13921 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
13922 this.listWidth = w;
13923 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
13924 this.restrictHeight();
13926 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
13929 if(!this.editable){
13930 this.editable = true;
13931 this.setEditable(false);
13936 if (typeof(this.events.add.listeners) != 'undefined') {
13938 this.addicon = this.wrap.createChild(
13939 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
13941 this.addicon.on('click', function(e) {
13942 this.fireEvent('add', this);
13945 if (typeof(this.events.edit.listeners) != 'undefined') {
13947 this.editicon = this.wrap.createChild(
13948 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
13949 if (this.addicon) {
13950 this.editicon.setStyle('margin-left', '40px');
13952 this.editicon.on('click', function(e) {
13954 // we fire even if inothing is selected..
13955 this.fireEvent('edit', this, this.lastData );
13961 this.keyNav = new Roo.KeyNav(this.inputEl(), {
13962 "up" : function(e){
13963 this.inKeyMode = true;
13967 "down" : function(e){
13968 if(!this.isExpanded()){
13969 this.onTriggerClick();
13971 this.inKeyMode = true;
13976 "enter" : function(e){
13977 // this.onViewClick();
13981 if(this.fireEvent("specialkey", this, e)){
13982 this.onViewClick(false);
13988 "esc" : function(e){
13992 "tab" : function(e){
13995 if(this.fireEvent("specialkey", this, e)){
13996 this.onViewClick(false);
14004 doRelay : function(foo, bar, hname){
14005 if(hname == 'down' || this.scope.isExpanded()){
14006 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
14015 this.queryDelay = Math.max(this.queryDelay || 10,
14016 this.mode == 'local' ? 10 : 250);
14019 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
14021 if(this.typeAhead){
14022 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
14024 if(this.editable !== false){
14025 this.inputEl().on("keyup", this.onKeyUp, this);
14027 if(this.forceSelection){
14028 this.inputEl().on('blur', this.doForce, this);
14032 this.choices = this.el.select('ul.roo-select2-choices', true).first();
14033 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
14037 initTickableEvents: function()
14041 if(this.hiddenName){
14043 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
14045 this.hiddenField.dom.value =
14046 this.hiddenValue !== undefined ? this.hiddenValue :
14047 this.value !== undefined ? this.value : '';
14049 // prevent input submission
14050 this.el.dom.removeAttribute('name');
14051 this.hiddenField.dom.setAttribute('name', this.hiddenName);
14056 // this.list = this.el.select('ul.dropdown-menu',true).first();
14058 this.choices = this.el.select('ul.roo-select2-choices', true).first();
14059 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
14060 if(this.triggerList){
14061 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
14064 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
14065 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
14067 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
14068 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
14070 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
14071 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
14073 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
14074 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
14075 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
14078 this.cancelBtn.hide();
14083 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
14084 _this.list.setWidth(lw);
14087 this.list.on('mouseover', this.onViewOver, this);
14088 this.list.on('mousemove', this.onViewMove, this);
14090 this.list.on('scroll', this.onViewScroll, this);
14093 this.tpl = '<li class="roo-select2-result"><div class="checkbox"><input id="{roo-id}"' +
14094 'type="checkbox" {roo-data-checked}><label for="{roo-id}"><b>{' + this.displayField + '}</b></label></div></li>';
14097 this.view = new Roo.View(this.list, this.tpl, {
14102 selectedClass: this.selectedClass
14105 //this.view.wrapEl.setDisplayed(false);
14106 this.view.on('click', this.onViewClick, this);
14110 this.store.on('beforeload', this.onBeforeLoad, this);
14111 this.store.on('load', this.onLoad, this);
14112 this.store.on('loadexception', this.onLoadException, this);
14115 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
14116 "up" : function(e){
14117 this.inKeyMode = true;
14121 "down" : function(e){
14122 this.inKeyMode = true;
14126 "enter" : function(e){
14127 if(this.fireEvent("specialkey", this, e)){
14128 this.onViewClick(false);
14134 "esc" : function(e){
14135 this.onTickableFooterButtonClick(e, false, false);
14138 "tab" : function(e){
14139 this.fireEvent("specialkey", this, e);
14141 this.onTickableFooterButtonClick(e, false, false);
14148 doRelay : function(e, fn, key){
14149 if(this.scope.isExpanded()){
14150 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
14159 this.queryDelay = Math.max(this.queryDelay || 10,
14160 this.mode == 'local' ? 10 : 250);
14163 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
14165 if(this.typeAhead){
14166 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
14169 if(this.editable !== false){
14170 this.tickableInputEl().on("keyup", this.onKeyUp, this);
14173 this.indicator = this.indicatorEl();
14175 if(this.indicator){
14176 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
14177 this.indicator.hide();
14182 onDestroy : function(){
14184 this.view.setStore(null);
14185 this.view.el.removeAllListeners();
14186 this.view.el.remove();
14187 this.view.purgeListeners();
14190 this.list.dom.innerHTML = '';
14194 this.store.un('beforeload', this.onBeforeLoad, this);
14195 this.store.un('load', this.onLoad, this);
14196 this.store.un('loadexception', this.onLoadException, this);
14198 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
14202 fireKey : function(e){
14203 if(e.isNavKeyPress() && !this.list.isVisible()){
14204 this.fireEvent("specialkey", this, e);
14209 onResize: function(w, h){
14210 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
14212 // if(typeof w != 'number'){
14213 // // we do not handle it!?!?
14216 // var tw = this.trigger.getWidth();
14217 // // tw += this.addicon ? this.addicon.getWidth() : 0;
14218 // // tw += this.editicon ? this.editicon.getWidth() : 0;
14220 // this.inputEl().setWidth( this.adjustWidth('input', x));
14222 // //this.trigger.setStyle('left', x+'px');
14224 // if(this.list && this.listWidth === undefined){
14225 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
14226 // this.list.setWidth(lw);
14227 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
14235 * Allow or prevent the user from directly editing the field text. If false is passed,
14236 * the user will only be able to select from the items defined in the dropdown list. This method
14237 * is the runtime equivalent of setting the 'editable' config option at config time.
14238 * @param {Boolean} value True to allow the user to directly edit the field text
14240 setEditable : function(value){
14241 if(value == this.editable){
14244 this.editable = value;
14246 this.inputEl().dom.setAttribute('readOnly', true);
14247 this.inputEl().on('mousedown', this.onTriggerClick, this);
14248 this.inputEl().addClass('x-combo-noedit');
14250 this.inputEl().dom.setAttribute('readOnly', false);
14251 this.inputEl().un('mousedown', this.onTriggerClick, this);
14252 this.inputEl().removeClass('x-combo-noedit');
14258 onBeforeLoad : function(combo,opts){
14259 if(!this.hasFocus){
14263 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
14265 this.restrictHeight();
14266 this.selectedIndex = -1;
14270 onLoad : function(){
14272 this.hasQuery = false;
14274 if(!this.hasFocus){
14278 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
14279 this.loading.hide();
14282 if(this.store.getCount() > 0){
14285 this.restrictHeight();
14286 if(this.lastQuery == this.allQuery){
14287 if(this.editable && !this.tickable){
14288 this.inputEl().dom.select();
14292 !this.selectByValue(this.value, true) &&
14295 !this.store.lastOptions ||
14296 typeof(this.store.lastOptions.add) == 'undefined' ||
14297 this.store.lastOptions.add != true
14300 this.select(0, true);
14303 if(this.autoFocus){
14306 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
14307 this.taTask.delay(this.typeAheadDelay);
14311 this.onEmptyResults();
14317 onLoadException : function()
14319 this.hasQuery = false;
14321 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
14322 this.loading.hide();
14325 if(this.tickable && this.editable){
14330 // only causes errors at present
14331 //Roo.log(this.store.reader.jsonData);
14332 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
14334 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
14340 onTypeAhead : function(){
14341 if(this.store.getCount() > 0){
14342 var r = this.store.getAt(0);
14343 var newValue = r.data[this.displayField];
14344 var len = newValue.length;
14345 var selStart = this.getRawValue().length;
14347 if(selStart != len){
14348 this.setRawValue(newValue);
14349 this.selectText(selStart, newValue.length);
14355 onSelect : function(record, index){
14357 if(this.fireEvent('beforeselect', this, record, index) !== false){
14359 this.setFromData(index > -1 ? record.data : false);
14362 this.fireEvent('select', this, record, index);
14367 * Returns the currently selected field value or empty string if no value is set.
14368 * @return {String} value The selected value
14370 getValue : function()
14372 if(Roo.isIOS && this.useNativeIOS){
14373 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
14377 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
14380 if(this.valueField){
14381 return typeof this.value != 'undefined' ? this.value : '';
14383 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
14387 getRawValue : function()
14389 if(Roo.isIOS && this.useNativeIOS){
14390 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
14393 var v = this.inputEl().getValue();
14399 * Clears any text/value currently set in the field
14401 clearValue : function(){
14403 if(this.hiddenField){
14404 this.hiddenField.dom.value = '';
14407 this.setRawValue('');
14408 this.lastSelectionText = '';
14409 this.lastData = false;
14411 var close = this.closeTriggerEl();
14422 * Sets the specified value into the field. If the value finds a match, the corresponding record text
14423 * will be displayed in the field. If the value does not match the data value of an existing item,
14424 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
14425 * Otherwise the field will be blank (although the value will still be set).
14426 * @param {String} value The value to match
14428 setValue : function(v)
14430 if(Roo.isIOS && this.useNativeIOS){
14431 this.setIOSValue(v);
14441 if(this.valueField){
14442 var r = this.findRecord(this.valueField, v);
14444 text = r.data[this.displayField];
14445 }else if(this.valueNotFoundText !== undefined){
14446 text = this.valueNotFoundText;
14449 this.lastSelectionText = text;
14450 if(this.hiddenField){
14451 this.hiddenField.dom.value = v;
14453 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
14456 var close = this.closeTriggerEl();
14459 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
14465 * @property {Object} the last set data for the element
14470 * Sets the value of the field based on a object which is related to the record format for the store.
14471 * @param {Object} value the value to set as. or false on reset?
14473 setFromData : function(o){
14480 var dv = ''; // display value
14481 var vv = ''; // value value..
14483 if (this.displayField) {
14484 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14486 // this is an error condition!!!
14487 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14490 if(this.valueField){
14491 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
14494 var close = this.closeTriggerEl();
14497 if(dv.length || vv * 1 > 0){
14499 this.blockFocus=true;
14505 if(this.hiddenField){
14506 this.hiddenField.dom.value = vv;
14508 this.lastSelectionText = dv;
14509 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14513 // no hidden field.. - we store the value in 'value', but still display
14514 // display field!!!!
14515 this.lastSelectionText = dv;
14516 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14523 reset : function(){
14524 // overridden so that last data is reset..
14531 this.setValue(this.originalValue);
14532 //this.clearInvalid();
14533 this.lastData = false;
14535 this.view.clearSelections();
14541 findRecord : function(prop, value){
14543 if(this.store.getCount() > 0){
14544 this.store.each(function(r){
14545 if(r.data[prop] == value){
14555 getName: function()
14557 // returns hidden if it's set..
14558 if (!this.rendered) {return ''};
14559 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
14563 onViewMove : function(e, t){
14564 this.inKeyMode = false;
14568 onViewOver : function(e, t){
14569 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
14572 var item = this.view.findItemFromChild(t);
14575 var index = this.view.indexOf(item);
14576 this.select(index, false);
14581 onViewClick : function(view, doFocus, el, e)
14583 var index = this.view.getSelectedIndexes()[0];
14585 var r = this.store.getAt(index);
14589 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
14596 Roo.each(this.tickItems, function(v,k){
14598 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
14600 _this.tickItems.splice(k, 1);
14602 if(typeof(e) == 'undefined' && view == false){
14603 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
14615 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
14616 this.tickItems.push(r.data);
14619 if(typeof(e) == 'undefined' && view == false){
14620 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
14627 this.onSelect(r, index);
14629 if(doFocus !== false && !this.blockFocus){
14630 this.inputEl().focus();
14635 restrictHeight : function(){
14636 //this.innerList.dom.style.height = '';
14637 //var inner = this.innerList.dom;
14638 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
14639 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
14640 //this.list.beginUpdate();
14641 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
14642 this.list.alignTo(this.inputEl(), this.listAlign);
14643 this.list.alignTo(this.inputEl(), this.listAlign);
14644 //this.list.endUpdate();
14648 onEmptyResults : function(){
14650 if(this.tickable && this.editable){
14651 this.hasFocus = false;
14652 this.restrictHeight();
14660 * Returns true if the dropdown list is expanded, else false.
14662 isExpanded : function(){
14663 return this.list.isVisible();
14667 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
14668 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14669 * @param {String} value The data value of the item to select
14670 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14671 * selected item if it is not currently in view (defaults to true)
14672 * @return {Boolean} True if the value matched an item in the list, else false
14674 selectByValue : function(v, scrollIntoView){
14675 if(v !== undefined && v !== null){
14676 var r = this.findRecord(this.valueField || this.displayField, v);
14678 this.select(this.store.indexOf(r), scrollIntoView);
14686 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
14687 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14688 * @param {Number} index The zero-based index of the list item to select
14689 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14690 * selected item if it is not currently in view (defaults to true)
14692 select : function(index, scrollIntoView){
14693 this.selectedIndex = index;
14694 this.view.select(index);
14695 if(scrollIntoView !== false){
14696 var el = this.view.getNode(index);
14698 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
14701 this.list.scrollChildIntoView(el, false);
14707 selectNext : function(){
14708 var ct = this.store.getCount();
14710 if(this.selectedIndex == -1){
14712 }else if(this.selectedIndex < ct-1){
14713 this.select(this.selectedIndex+1);
14719 selectPrev : function(){
14720 var ct = this.store.getCount();
14722 if(this.selectedIndex == -1){
14724 }else if(this.selectedIndex != 0){
14725 this.select(this.selectedIndex-1);
14731 onKeyUp : function(e){
14732 if(this.editable !== false && !e.isSpecialKey()){
14733 this.lastKey = e.getKey();
14734 this.dqTask.delay(this.queryDelay);
14739 validateBlur : function(){
14740 return !this.list || !this.list.isVisible();
14744 initQuery : function(){
14746 var v = this.getRawValue();
14748 if(this.tickable && this.editable){
14749 v = this.tickableInputEl().getValue();
14756 doForce : function(){
14757 if(this.inputEl().dom.value.length > 0){
14758 this.inputEl().dom.value =
14759 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
14765 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
14766 * query allowing the query action to be canceled if needed.
14767 * @param {String} query The SQL query to execute
14768 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
14769 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
14770 * saved in the current store (defaults to false)
14772 doQuery : function(q, forceAll){
14774 if(q === undefined || q === null){
14779 forceAll: forceAll,
14783 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
14788 forceAll = qe.forceAll;
14789 if(forceAll === true || (q.length >= this.minChars)){
14791 this.hasQuery = true;
14793 if(this.lastQuery != q || this.alwaysQuery){
14794 this.lastQuery = q;
14795 if(this.mode == 'local'){
14796 this.selectedIndex = -1;
14798 this.store.clearFilter();
14801 if(this.specialFilter){
14802 this.fireEvent('specialfilter', this);
14807 this.store.filter(this.displayField, q);
14810 this.store.fireEvent("datachanged", this.store);
14817 this.store.baseParams[this.queryParam] = q;
14819 var options = {params : this.getParams(q)};
14822 options.add = true;
14823 options.params.start = this.page * this.pageSize;
14826 this.store.load(options);
14829 * this code will make the page width larger, at the beginning, the list not align correctly,
14830 * we should expand the list on onLoad
14831 * so command out it
14836 this.selectedIndex = -1;
14841 this.loadNext = false;
14845 getParams : function(q){
14847 //p[this.queryParam] = q;
14851 p.limit = this.pageSize;
14857 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
14859 collapse : function(){
14860 if(!this.isExpanded()){
14866 this.hasFocus = false;
14870 this.cancelBtn.hide();
14871 this.trigger.show();
14874 this.tickableInputEl().dom.value = '';
14875 this.tickableInputEl().blur();
14880 Roo.get(document).un('mousedown', this.collapseIf, this);
14881 Roo.get(document).un('mousewheel', this.collapseIf, this);
14882 if (!this.editable) {
14883 Roo.get(document).un('keydown', this.listKeyPress, this);
14885 this.fireEvent('collapse', this);
14891 collapseIf : function(e){
14892 var in_combo = e.within(this.el);
14893 var in_list = e.within(this.list);
14894 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
14896 if (in_combo || in_list || is_list) {
14897 //e.stopPropagation();
14902 this.onTickableFooterButtonClick(e, false, false);
14910 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
14912 expand : function(){
14914 if(this.isExpanded() || !this.hasFocus){
14918 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
14919 this.list.setWidth(lw);
14925 this.restrictHeight();
14929 this.tickItems = Roo.apply([], this.item);
14932 this.cancelBtn.show();
14933 this.trigger.hide();
14936 this.tickableInputEl().focus();
14941 Roo.get(document).on('mousedown', this.collapseIf, this);
14942 Roo.get(document).on('mousewheel', this.collapseIf, this);
14943 if (!this.editable) {
14944 Roo.get(document).on('keydown', this.listKeyPress, this);
14947 this.fireEvent('expand', this);
14951 // Implements the default empty TriggerField.onTriggerClick function
14952 onTriggerClick : function(e)
14954 Roo.log('trigger click');
14956 if(this.disabled || !this.triggerList){
14961 this.loadNext = false;
14963 if(this.isExpanded()){
14965 if (!this.blockFocus) {
14966 this.inputEl().focus();
14970 this.hasFocus = true;
14971 if(this.triggerAction == 'all') {
14972 this.doQuery(this.allQuery, true);
14974 this.doQuery(this.getRawValue());
14976 if (!this.blockFocus) {
14977 this.inputEl().focus();
14982 onTickableTriggerClick : function(e)
14989 this.loadNext = false;
14990 this.hasFocus = true;
14992 if(this.triggerAction == 'all') {
14993 this.doQuery(this.allQuery, true);
14995 this.doQuery(this.getRawValue());
14999 onSearchFieldClick : function(e)
15001 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
15002 this.onTickableFooterButtonClick(e, false, false);
15006 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
15011 this.loadNext = false;
15012 this.hasFocus = true;
15014 if(this.triggerAction == 'all') {
15015 this.doQuery(this.allQuery, true);
15017 this.doQuery(this.getRawValue());
15021 listKeyPress : function(e)
15023 //Roo.log('listkeypress');
15024 // scroll to first matching element based on key pres..
15025 if (e.isSpecialKey()) {
15028 var k = String.fromCharCode(e.getKey()).toUpperCase();
15031 var csel = this.view.getSelectedNodes();
15032 var cselitem = false;
15034 var ix = this.view.indexOf(csel[0]);
15035 cselitem = this.store.getAt(ix);
15036 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
15042 this.store.each(function(v) {
15044 // start at existing selection.
15045 if (cselitem.id == v.id) {
15051 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
15052 match = this.store.indexOf(v);
15058 if (match === false) {
15059 return true; // no more action?
15062 this.view.select(match);
15063 var sn = Roo.get(this.view.getSelectedNodes()[0]);
15064 sn.scrollIntoView(sn.dom.parentNode, false);
15067 onViewScroll : function(e, t){
15069 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){
15073 this.hasQuery = true;
15075 this.loading = this.list.select('.loading', true).first();
15077 if(this.loading === null){
15078 this.list.createChild({
15080 cls: 'loading roo-select2-more-results roo-select2-active',
15081 html: 'Loading more results...'
15084 this.loading = this.list.select('.loading', true).first();
15086 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
15088 this.loading.hide();
15091 this.loading.show();
15096 this.loadNext = true;
15098 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
15103 addItem : function(o)
15105 var dv = ''; // display value
15107 if (this.displayField) {
15108 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
15110 // this is an error condition!!!
15111 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
15118 var choice = this.choices.createChild({
15120 cls: 'roo-select2-search-choice',
15129 cls: 'roo-select2-search-choice-close fa fa-times',
15134 }, this.searchField);
15136 var close = choice.select('a.roo-select2-search-choice-close', true).first();
15138 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
15146 this.inputEl().dom.value = '';
15151 onRemoveItem : function(e, _self, o)
15153 e.preventDefault();
15155 this.lastItem = Roo.apply([], this.item);
15157 var index = this.item.indexOf(o.data) * 1;
15160 Roo.log('not this item?!');
15164 this.item.splice(index, 1);
15169 this.fireEvent('remove', this, e);
15175 syncValue : function()
15177 if(!this.item.length){
15184 Roo.each(this.item, function(i){
15185 if(_this.valueField){
15186 value.push(i[_this.valueField]);
15193 this.value = value.join(',');
15195 if(this.hiddenField){
15196 this.hiddenField.dom.value = this.value;
15199 this.store.fireEvent("datachanged", this.store);
15204 clearItem : function()
15206 if(!this.multiple){
15212 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
15220 if(this.tickable && !Roo.isTouch){
15221 this.view.refresh();
15225 inputEl: function ()
15227 if(Roo.isIOS && this.useNativeIOS){
15228 return this.el.select('select.roo-ios-select', true).first();
15231 if(Roo.isTouch && this.mobileTouchView){
15232 return this.el.select('input.form-control',true).first();
15236 return this.searchField;
15239 return this.el.select('input.form-control',true).first();
15242 onTickableFooterButtonClick : function(e, btn, el)
15244 e.preventDefault();
15246 this.lastItem = Roo.apply([], this.item);
15248 if(btn && btn.name == 'cancel'){
15249 this.tickItems = Roo.apply([], this.item);
15258 Roo.each(this.tickItems, function(o){
15266 validate : function()
15268 if(this.getVisibilityEl().hasClass('hidden')){
15272 var v = this.getRawValue();
15275 v = this.getValue();
15278 if(this.disabled || this.allowBlank || v.length){
15283 this.markInvalid();
15287 tickableInputEl : function()
15289 if(!this.tickable || !this.editable){
15290 return this.inputEl();
15293 return this.inputEl().select('.roo-select2-search-field-input', true).first();
15297 getAutoCreateTouchView : function()
15302 cls: 'form-group' //input-group
15308 type : this.inputType,
15309 cls : 'form-control x-combo-noedit',
15310 autocomplete: 'new-password',
15311 placeholder : this.placeholder || '',
15316 input.name = this.name;
15320 input.cls += ' input-' + this.size;
15323 if (this.disabled) {
15324 input.disabled = true;
15335 inputblock.cls += ' input-group';
15337 inputblock.cn.unshift({
15339 cls : 'input-group-addon input-group-prepend input-group-text',
15344 if(this.removable && !this.multiple){
15345 inputblock.cls += ' roo-removable';
15347 inputblock.cn.push({
15350 cls : 'roo-combo-removable-btn close'
15354 if(this.hasFeedback && !this.allowBlank){
15356 inputblock.cls += ' has-feedback';
15358 inputblock.cn.push({
15360 cls: 'glyphicon form-control-feedback'
15367 inputblock.cls += (this.before) ? '' : ' input-group';
15369 inputblock.cn.push({
15371 cls : 'input-group-addon input-group-append input-group-text',
15377 var ibwrap = inputblock;
15382 cls: 'roo-select2-choices',
15386 cls: 'roo-select2-search-field',
15399 cls: 'roo-select2-container input-group roo-touchview-combobox ',
15404 cls: 'form-hidden-field'
15410 if(!this.multiple && this.showToggleBtn){
15416 if (this.caret != false) {
15419 cls: 'fa fa-' + this.caret
15426 cls : 'input-group-addon input-group-append input-group-text btn dropdown-toggle',
15428 Roo.bootstrap.version == 3 ? caret : '',
15431 cls: 'combobox-clear',
15445 combobox.cls += ' roo-select2-container-multi';
15448 var align = this.labelAlign || this.parentLabelAlign();
15450 if (align ==='left' && this.fieldLabel.length) {
15455 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15456 tooltip : 'This field is required'
15460 cls : 'control-label col-form-label',
15461 html : this.fieldLabel
15472 var labelCfg = cfg.cn[1];
15473 var contentCfg = cfg.cn[2];
15476 if(this.indicatorpos == 'right'){
15481 cls : 'control-label col-form-label',
15485 html : this.fieldLabel
15489 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15490 tooltip : 'This field is required'
15503 labelCfg = cfg.cn[0];
15504 contentCfg = cfg.cn[1];
15509 if(this.labelWidth > 12){
15510 labelCfg.style = "width: " + this.labelWidth + 'px';
15513 if(this.labelWidth < 13 && this.labelmd == 0){
15514 this.labelmd = this.labelWidth;
15517 if(this.labellg > 0){
15518 labelCfg.cls += ' col-lg-' + this.labellg;
15519 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
15522 if(this.labelmd > 0){
15523 labelCfg.cls += ' col-md-' + this.labelmd;
15524 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
15527 if(this.labelsm > 0){
15528 labelCfg.cls += ' col-sm-' + this.labelsm;
15529 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
15532 if(this.labelxs > 0){
15533 labelCfg.cls += ' col-xs-' + this.labelxs;
15534 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
15538 } else if ( this.fieldLabel.length) {
15542 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15543 tooltip : 'This field is required'
15547 cls : 'control-label',
15548 html : this.fieldLabel
15559 if(this.indicatorpos == 'right'){
15563 cls : 'control-label',
15564 html : this.fieldLabel,
15568 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15569 tooltip : 'This field is required'
15586 var settings = this;
15588 ['xs','sm','md','lg'].map(function(size){
15589 if (settings[size]) {
15590 cfg.cls += ' col-' + size + '-' + settings[size];
15597 initTouchView : function()
15599 this.renderTouchView();
15601 this.touchViewEl.on('scroll', function(){
15602 this.el.dom.scrollTop = 0;
15605 this.originalValue = this.getValue();
15607 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
15609 this.inputEl().on("click", this.showTouchView, this);
15610 if (this.triggerEl) {
15611 this.triggerEl.on("click", this.showTouchView, this);
15615 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
15616 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
15618 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
15620 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
15621 this.store.on('load', this.onTouchViewLoad, this);
15622 this.store.on('loadexception', this.onTouchViewLoadException, this);
15624 if(this.hiddenName){
15626 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
15628 this.hiddenField.dom.value =
15629 this.hiddenValue !== undefined ? this.hiddenValue :
15630 this.value !== undefined ? this.value : '';
15632 this.el.dom.removeAttribute('name');
15633 this.hiddenField.dom.setAttribute('name', this.hiddenName);
15637 this.choices = this.el.select('ul.roo-select2-choices', true).first();
15638 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
15641 if(this.removable && !this.multiple){
15642 var close = this.closeTriggerEl();
15644 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
15645 close.on('click', this.removeBtnClick, this, close);
15649 * fix the bug in Safari iOS8
15651 this.inputEl().on("focus", function(e){
15652 document.activeElement.blur();
15655 this._touchViewMask = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
15662 renderTouchView : function()
15664 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
15665 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15667 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
15668 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15670 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
15671 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15672 this.touchViewBodyEl.setStyle('overflow', 'auto');
15674 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
15675 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15677 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
15678 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15682 showTouchView : function()
15688 this.touchViewHeaderEl.hide();
15690 if(this.modalTitle.length){
15691 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
15692 this.touchViewHeaderEl.show();
15695 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
15696 this.touchViewEl.show();
15698 this.touchViewEl.select('.modal-dialog', true).first().setStyle({ margin : '0px', width : '100%'});
15700 //this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
15701 // Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15703 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15705 if(this.modalTitle.length){
15706 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15709 this.touchViewBodyEl.setHeight(bodyHeight);
15713 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
15715 this.touchViewEl.addClass('in');
15718 if(this._touchViewMask){
15719 Roo.get(document.body).addClass("x-body-masked");
15720 this._touchViewMask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15721 this._touchViewMask.setStyle('z-index', 10000);
15722 this._touchViewMask.addClass('show');
15725 this.doTouchViewQuery();
15729 hideTouchView : function()
15731 this.touchViewEl.removeClass('in');
15735 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
15737 this.touchViewEl.setStyle('display', 'none');
15740 if(this._touchViewMask){
15741 this._touchViewMask.removeClass('show');
15742 Roo.get(document.body).removeClass("x-body-masked");
15746 setTouchViewValue : function()
15753 Roo.each(this.tickItems, function(o){
15758 this.hideTouchView();
15761 doTouchViewQuery : function()
15770 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
15774 if(!this.alwaysQuery || this.mode == 'local'){
15775 this.onTouchViewLoad();
15782 onTouchViewBeforeLoad : function(combo,opts)
15788 onTouchViewLoad : function()
15790 if(this.store.getCount() < 1){
15791 this.onTouchViewEmptyResults();
15795 this.clearTouchView();
15797 var rawValue = this.getRawValue();
15799 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
15801 this.tickItems = [];
15803 this.store.data.each(function(d, rowIndex){
15804 var row = this.touchViewListGroup.createChild(template);
15806 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
15807 row.addClass(d.data.cls);
15810 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15813 html : d.data[this.displayField]
15816 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
15817 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
15820 row.removeClass('selected');
15821 if(!this.multiple && this.valueField &&
15822 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
15825 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15826 row.addClass('selected');
15829 if(this.multiple && this.valueField &&
15830 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
15834 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15835 this.tickItems.push(d.data);
15838 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
15842 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
15844 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15846 if(this.modalTitle.length){
15847 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15850 var listHeight = this.touchViewListGroup.getHeight() + this.touchViewBodyEl.getPadding('tb') * 2;
15852 if(this.mobile_restrict_height && listHeight < bodyHeight){
15853 this.touchViewBodyEl.setHeight(listHeight);
15858 if(firstChecked && listHeight > bodyHeight){
15859 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
15864 onTouchViewLoadException : function()
15866 this.hideTouchView();
15869 onTouchViewEmptyResults : function()
15871 this.clearTouchView();
15873 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
15875 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
15879 clearTouchView : function()
15881 this.touchViewListGroup.dom.innerHTML = '';
15884 onTouchViewClick : function(e, el, o)
15886 e.preventDefault();
15889 var rowIndex = o.rowIndex;
15891 var r = this.store.getAt(rowIndex);
15893 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
15895 if(!this.multiple){
15896 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
15897 c.dom.removeAttribute('checked');
15900 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15902 this.setFromData(r.data);
15904 var close = this.closeTriggerEl();
15910 this.hideTouchView();
15912 this.fireEvent('select', this, r, rowIndex);
15917 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
15918 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
15919 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
15923 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15924 this.addItem(r.data);
15925 this.tickItems.push(r.data);
15929 getAutoCreateNativeIOS : function()
15932 cls: 'form-group' //input-group,
15937 cls : 'roo-ios-select'
15941 combobox.name = this.name;
15944 if (this.disabled) {
15945 combobox.disabled = true;
15948 var settings = this;
15950 ['xs','sm','md','lg'].map(function(size){
15951 if (settings[size]) {
15952 cfg.cls += ' col-' + size + '-' + settings[size];
15962 initIOSView : function()
15964 this.store.on('load', this.onIOSViewLoad, this);
15969 onIOSViewLoad : function()
15971 if(this.store.getCount() < 1){
15975 this.clearIOSView();
15977 if(this.allowBlank) {
15979 var default_text = '-- SELECT --';
15981 if(this.placeholder.length){
15982 default_text = this.placeholder;
15985 if(this.emptyTitle.length){
15986 default_text += ' - ' + this.emptyTitle + ' -';
15989 var opt = this.inputEl().createChild({
15992 html : default_text
15996 o[this.valueField] = 0;
15997 o[this.displayField] = default_text;
15999 this.ios_options.push({
16006 this.store.data.each(function(d, rowIndex){
16010 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
16011 html = d.data[this.displayField];
16016 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
16017 value = d.data[this.valueField];
16026 if(this.value == d.data[this.valueField]){
16027 option['selected'] = true;
16030 var opt = this.inputEl().createChild(option);
16032 this.ios_options.push({
16039 this.inputEl().on('change', function(){
16040 this.fireEvent('select', this);
16045 clearIOSView: function()
16047 this.inputEl().dom.innerHTML = '';
16049 this.ios_options = [];
16052 setIOSValue: function(v)
16056 if(!this.ios_options){
16060 Roo.each(this.ios_options, function(opts){
16062 opts.el.dom.removeAttribute('selected');
16064 if(opts.data[this.valueField] != v){
16068 opts.el.dom.setAttribute('selected', true);
16074 * @cfg {Boolean} grow
16078 * @cfg {Number} growMin
16082 * @cfg {Number} growMax
16091 Roo.apply(Roo.bootstrap.ComboBox, {
16095 cls: 'modal-header',
16117 cls: 'list-group-item',
16121 cls: 'roo-combobox-list-group-item-value'
16125 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
16139 listItemCheckbox : {
16141 cls: 'list-group-item',
16145 cls: 'roo-combobox-list-group-item-value'
16149 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
16165 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
16170 cls: 'modal-footer',
16178 cls: 'col-xs-6 text-left',
16181 cls: 'btn btn-danger roo-touch-view-cancel',
16187 cls: 'col-xs-6 text-right',
16190 cls: 'btn btn-success roo-touch-view-ok',
16201 Roo.apply(Roo.bootstrap.ComboBox, {
16203 touchViewTemplate : {
16205 cls: 'modal fade roo-combobox-touch-view',
16209 cls: 'modal-dialog',
16210 style : 'position:fixed', // we have to fix position....
16214 cls: 'modal-content',
16216 Roo.bootstrap.ComboBox.header,
16217 Roo.bootstrap.ComboBox.body,
16218 Roo.bootstrap.ComboBox.footer
16227 * Ext JS Library 1.1.1
16228 * Copyright(c) 2006-2007, Ext JS, LLC.
16230 * Originally Released Under LGPL - original licence link has changed is not relivant.
16233 * <script type="text/javascript">
16238 * @extends Roo.util.Observable
16239 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
16240 * This class also supports single and multi selection modes. <br>
16241 * Create a data model bound view:
16243 var store = new Roo.data.Store(...);
16245 var view = new Roo.View({
16247 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
16249 singleSelect: true,
16250 selectedClass: "ydataview-selected",
16254 // listen for node click?
16255 view.on("click", function(vw, index, node, e){
16256 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
16260 dataModel.load("foobar.xml");
16262 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
16264 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
16265 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
16267 * Note: old style constructor is still suported (container, template, config)
16270 * Create a new View
16271 * @param {Object} config The config object
16274 Roo.View = function(config, depreciated_tpl, depreciated_config){
16276 this.parent = false;
16278 if (typeof(depreciated_tpl) == 'undefined') {
16279 // new way.. - universal constructor.
16280 Roo.apply(this, config);
16281 this.el = Roo.get(this.el);
16284 this.el = Roo.get(config);
16285 this.tpl = depreciated_tpl;
16286 Roo.apply(this, depreciated_config);
16288 this.wrapEl = this.el.wrap().wrap();
16289 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
16292 if(typeof(this.tpl) == "string"){
16293 this.tpl = new Roo.Template(this.tpl);
16295 // support xtype ctors..
16296 this.tpl = new Roo.factory(this.tpl, Roo);
16300 this.tpl.compile();
16305 * @event beforeclick
16306 * Fires before a click is processed. Returns false to cancel the default action.
16307 * @param {Roo.View} this
16308 * @param {Number} index The index of the target node
16309 * @param {HTMLElement} node The target node
16310 * @param {Roo.EventObject} e The raw event object
16312 "beforeclick" : true,
16315 * Fires when a template node is clicked.
16316 * @param {Roo.View} this
16317 * @param {Number} index The index of the target node
16318 * @param {HTMLElement} node The target node
16319 * @param {Roo.EventObject} e The raw event object
16324 * Fires when a template node is double clicked.
16325 * @param {Roo.View} this
16326 * @param {Number} index The index of the target node
16327 * @param {HTMLElement} node The target node
16328 * @param {Roo.EventObject} e The raw event object
16332 * @event contextmenu
16333 * Fires when a template node is right clicked.
16334 * @param {Roo.View} this
16335 * @param {Number} index The index of the target node
16336 * @param {HTMLElement} node The target node
16337 * @param {Roo.EventObject} e The raw event object
16339 "contextmenu" : true,
16341 * @event selectionchange
16342 * Fires when the selected nodes change.
16343 * @param {Roo.View} this
16344 * @param {Array} selections Array of the selected nodes
16346 "selectionchange" : true,
16349 * @event beforeselect
16350 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
16351 * @param {Roo.View} this
16352 * @param {HTMLElement} node The node to be selected
16353 * @param {Array} selections Array of currently selected nodes
16355 "beforeselect" : true,
16357 * @event preparedata
16358 * Fires on every row to render, to allow you to change the data.
16359 * @param {Roo.View} this
16360 * @param {Object} data to be rendered (change this)
16362 "preparedata" : true
16370 "click": this.onClick,
16371 "dblclick": this.onDblClick,
16372 "contextmenu": this.onContextMenu,
16376 this.selections = [];
16378 this.cmp = new Roo.CompositeElementLite([]);
16380 this.store = Roo.factory(this.store, Roo.data);
16381 this.setStore(this.store, true);
16384 if ( this.footer && this.footer.xtype) {
16386 var fctr = this.wrapEl.appendChild(document.createElement("div"));
16388 this.footer.dataSource = this.store;
16389 this.footer.container = fctr;
16390 this.footer = Roo.factory(this.footer, Roo);
16391 fctr.insertFirst(this.el);
16393 // this is a bit insane - as the paging toolbar seems to detach the el..
16394 // dom.parentNode.parentNode.parentNode
16395 // they get detached?
16399 Roo.View.superclass.constructor.call(this);
16404 Roo.extend(Roo.View, Roo.util.Observable, {
16407 * @cfg {Roo.data.Store} store Data store to load data from.
16412 * @cfg {String|Roo.Element} el The container element.
16417 * @cfg {String|Roo.Template} tpl The template used by this View
16421 * @cfg {String} dataName the named area of the template to use as the data area
16422 * Works with domtemplates roo-name="name"
16426 * @cfg {String} selectedClass The css class to add to selected nodes
16428 selectedClass : "x-view-selected",
16430 * @cfg {String} emptyText The empty text to show when nothing is loaded.
16435 * @cfg {String} text to display on mask (default Loading)
16439 * @cfg {Boolean} multiSelect Allow multiple selection
16441 multiSelect : false,
16443 * @cfg {Boolean} singleSelect Allow single selection
16445 singleSelect: false,
16448 * @cfg {Boolean} toggleSelect - selecting
16450 toggleSelect : false,
16453 * @cfg {Boolean} tickable - selecting
16458 * Returns the element this view is bound to.
16459 * @return {Roo.Element}
16461 getEl : function(){
16462 return this.wrapEl;
16468 * Refreshes the view. - called by datachanged on the store. - do not call directly.
16470 refresh : function(){
16471 //Roo.log('refresh');
16474 // if we are using something like 'domtemplate', then
16475 // the what gets used is:
16476 // t.applySubtemplate(NAME, data, wrapping data..)
16477 // the outer template then get' applied with
16478 // the store 'extra data'
16479 // and the body get's added to the
16480 // roo-name="data" node?
16481 // <span class='roo-tpl-{name}'></span> ?????
16485 this.clearSelections();
16486 this.el.update("");
16488 var records = this.store.getRange();
16489 if(records.length < 1) {
16491 // is this valid?? = should it render a template??
16493 this.el.update(this.emptyText);
16497 if (this.dataName) {
16498 this.el.update(t.apply(this.store.meta)); //????
16499 el = this.el.child('.roo-tpl-' + this.dataName);
16502 for(var i = 0, len = records.length; i < len; i++){
16503 var data = this.prepareData(records[i].data, i, records[i]);
16504 this.fireEvent("preparedata", this, data, i, records[i]);
16506 var d = Roo.apply({}, data);
16509 Roo.apply(d, {'roo-id' : Roo.id()});
16513 Roo.each(this.parent.item, function(item){
16514 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
16517 Roo.apply(d, {'roo-data-checked' : 'checked'});
16521 html[html.length] = Roo.util.Format.trim(
16523 t.applySubtemplate(this.dataName, d, this.store.meta) :
16530 el.update(html.join(""));
16531 this.nodes = el.dom.childNodes;
16532 this.updateIndexes(0);
16537 * Function to override to reformat the data that is sent to
16538 * the template for each node.
16539 * DEPRICATED - use the preparedata event handler.
16540 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
16541 * a JSON object for an UpdateManager bound view).
16543 prepareData : function(data, index, record)
16545 this.fireEvent("preparedata", this, data, index, record);
16549 onUpdate : function(ds, record){
16550 // Roo.log('on update');
16551 this.clearSelections();
16552 var index = this.store.indexOf(record);
16553 var n = this.nodes[index];
16554 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
16555 n.parentNode.removeChild(n);
16556 this.updateIndexes(index, index);
16562 onAdd : function(ds, records, index)
16564 //Roo.log(['on Add', ds, records, index] );
16565 this.clearSelections();
16566 if(this.nodes.length == 0){
16570 var n = this.nodes[index];
16571 for(var i = 0, len = records.length; i < len; i++){
16572 var d = this.prepareData(records[i].data, i, records[i]);
16574 this.tpl.insertBefore(n, d);
16577 this.tpl.append(this.el, d);
16580 this.updateIndexes(index);
16583 onRemove : function(ds, record, index){
16584 // Roo.log('onRemove');
16585 this.clearSelections();
16586 var el = this.dataName ?
16587 this.el.child('.roo-tpl-' + this.dataName) :
16590 el.dom.removeChild(this.nodes[index]);
16591 this.updateIndexes(index);
16595 * Refresh an individual node.
16596 * @param {Number} index
16598 refreshNode : function(index){
16599 this.onUpdate(this.store, this.store.getAt(index));
16602 updateIndexes : function(startIndex, endIndex){
16603 var ns = this.nodes;
16604 startIndex = startIndex || 0;
16605 endIndex = endIndex || ns.length - 1;
16606 for(var i = startIndex; i <= endIndex; i++){
16607 ns[i].nodeIndex = i;
16612 * Changes the data store this view uses and refresh the view.
16613 * @param {Store} store
16615 setStore : function(store, initial){
16616 if(!initial && this.store){
16617 this.store.un("datachanged", this.refresh);
16618 this.store.un("add", this.onAdd);
16619 this.store.un("remove", this.onRemove);
16620 this.store.un("update", this.onUpdate);
16621 this.store.un("clear", this.refresh);
16622 this.store.un("beforeload", this.onBeforeLoad);
16623 this.store.un("load", this.onLoad);
16624 this.store.un("loadexception", this.onLoad);
16628 store.on("datachanged", this.refresh, this);
16629 store.on("add", this.onAdd, this);
16630 store.on("remove", this.onRemove, this);
16631 store.on("update", this.onUpdate, this);
16632 store.on("clear", this.refresh, this);
16633 store.on("beforeload", this.onBeforeLoad, this);
16634 store.on("load", this.onLoad, this);
16635 store.on("loadexception", this.onLoad, this);
16643 * onbeforeLoad - masks the loading area.
16646 onBeforeLoad : function(store,opts)
16648 //Roo.log('onBeforeLoad');
16650 this.el.update("");
16652 this.el.mask(this.mask ? this.mask : "Loading" );
16654 onLoad : function ()
16661 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
16662 * @param {HTMLElement} node
16663 * @return {HTMLElement} The template node
16665 findItemFromChild : function(node){
16666 var el = this.dataName ?
16667 this.el.child('.roo-tpl-' + this.dataName,true) :
16670 if(!node || node.parentNode == el){
16673 var p = node.parentNode;
16674 while(p && p != el){
16675 if(p.parentNode == el){
16684 onClick : function(e){
16685 var item = this.findItemFromChild(e.getTarget());
16687 var index = this.indexOf(item);
16688 if(this.onItemClick(item, index, e) !== false){
16689 this.fireEvent("click", this, index, item, e);
16692 this.clearSelections();
16697 onContextMenu : function(e){
16698 var item = this.findItemFromChild(e.getTarget());
16700 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
16705 onDblClick : function(e){
16706 var item = this.findItemFromChild(e.getTarget());
16708 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
16712 onItemClick : function(item, index, e)
16714 if(this.fireEvent("beforeclick", this, index, item, e) === false){
16717 if (this.toggleSelect) {
16718 var m = this.isSelected(item) ? 'unselect' : 'select';
16721 _t[m](item, true, false);
16724 if(this.multiSelect || this.singleSelect){
16725 if(this.multiSelect && e.shiftKey && this.lastSelection){
16726 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
16728 this.select(item, this.multiSelect && e.ctrlKey);
16729 this.lastSelection = item;
16732 if(!this.tickable){
16733 e.preventDefault();
16741 * Get the number of selected nodes.
16744 getSelectionCount : function(){
16745 return this.selections.length;
16749 * Get the currently selected nodes.
16750 * @return {Array} An array of HTMLElements
16752 getSelectedNodes : function(){
16753 return this.selections;
16757 * Get the indexes of the selected nodes.
16760 getSelectedIndexes : function(){
16761 var indexes = [], s = this.selections;
16762 for(var i = 0, len = s.length; i < len; i++){
16763 indexes.push(s[i].nodeIndex);
16769 * Clear all selections
16770 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
16772 clearSelections : function(suppressEvent){
16773 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
16774 this.cmp.elements = this.selections;
16775 this.cmp.removeClass(this.selectedClass);
16776 this.selections = [];
16777 if(!suppressEvent){
16778 this.fireEvent("selectionchange", this, this.selections);
16784 * Returns true if the passed node is selected
16785 * @param {HTMLElement/Number} node The node or node index
16786 * @return {Boolean}
16788 isSelected : function(node){
16789 var s = this.selections;
16793 node = this.getNode(node);
16794 return s.indexOf(node) !== -1;
16799 * @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
16800 * @param {Boolean} keepExisting (optional) true to keep existing selections
16801 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16803 select : function(nodeInfo, keepExisting, suppressEvent){
16804 if(nodeInfo instanceof Array){
16806 this.clearSelections(true);
16808 for(var i = 0, len = nodeInfo.length; i < len; i++){
16809 this.select(nodeInfo[i], true, true);
16813 var node = this.getNode(nodeInfo);
16814 if(!node || this.isSelected(node)){
16815 return; // already selected.
16818 this.clearSelections(true);
16821 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
16822 Roo.fly(node).addClass(this.selectedClass);
16823 this.selections.push(node);
16824 if(!suppressEvent){
16825 this.fireEvent("selectionchange", this, this.selections);
16833 * @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
16834 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
16835 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16837 unselect : function(nodeInfo, keepExisting, suppressEvent)
16839 if(nodeInfo instanceof Array){
16840 Roo.each(this.selections, function(s) {
16841 this.unselect(s, nodeInfo);
16845 var node = this.getNode(nodeInfo);
16846 if(!node || !this.isSelected(node)){
16847 //Roo.log("not selected");
16848 return; // not selected.
16852 Roo.each(this.selections, function(s) {
16854 Roo.fly(node).removeClass(this.selectedClass);
16861 this.selections= ns;
16862 this.fireEvent("selectionchange", this, this.selections);
16866 * Gets a template node.
16867 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16868 * @return {HTMLElement} The node or null if it wasn't found
16870 getNode : function(nodeInfo){
16871 if(typeof nodeInfo == "string"){
16872 return document.getElementById(nodeInfo);
16873 }else if(typeof nodeInfo == "number"){
16874 return this.nodes[nodeInfo];
16880 * Gets a range template nodes.
16881 * @param {Number} startIndex
16882 * @param {Number} endIndex
16883 * @return {Array} An array of nodes
16885 getNodes : function(start, end){
16886 var ns = this.nodes;
16887 start = start || 0;
16888 end = typeof end == "undefined" ? ns.length - 1 : end;
16891 for(var i = start; i <= end; i++){
16895 for(var i = start; i >= end; i--){
16903 * Finds the index of the passed node
16904 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16905 * @return {Number} The index of the node or -1
16907 indexOf : function(node){
16908 node = this.getNode(node);
16909 if(typeof node.nodeIndex == "number"){
16910 return node.nodeIndex;
16912 var ns = this.nodes;
16913 for(var i = 0, len = ns.length; i < len; i++){
16924 * based on jquery fullcalendar
16928 Roo.bootstrap = Roo.bootstrap || {};
16930 * @class Roo.bootstrap.Calendar
16931 * @extends Roo.bootstrap.Component
16932 * Bootstrap Calendar class
16933 * @cfg {Boolean} loadMask (true|false) default false
16934 * @cfg {Object} header generate the user specific header of the calendar, default false
16937 * Create a new Container
16938 * @param {Object} config The config object
16943 Roo.bootstrap.Calendar = function(config){
16944 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
16948 * Fires when a date is selected
16949 * @param {DatePicker} this
16950 * @param {Date} date The selected date
16954 * @event monthchange
16955 * Fires when the displayed month changes
16956 * @param {DatePicker} this
16957 * @param {Date} date The selected month
16959 'monthchange': true,
16961 * @event evententer
16962 * Fires when mouse over an event
16963 * @param {Calendar} this
16964 * @param {event} Event
16966 'evententer': true,
16968 * @event eventleave
16969 * Fires when the mouse leaves an
16970 * @param {Calendar} this
16973 'eventleave': true,
16975 * @event eventclick
16976 * Fires when the mouse click an
16977 * @param {Calendar} this
16986 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
16989 * @cfg {Number} startDay
16990 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16998 getAutoCreate : function(){
17001 var fc_button = function(name, corner, style, content ) {
17002 return Roo.apply({},{
17004 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
17006 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
17009 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
17020 style : 'width:100%',
17027 cls : 'fc-header-left',
17029 fc_button('prev', 'left', 'arrow', '‹' ),
17030 fc_button('next', 'right', 'arrow', '›' ),
17031 { tag: 'span', cls: 'fc-header-space' },
17032 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
17040 cls : 'fc-header-center',
17044 cls: 'fc-header-title',
17047 html : 'month / year'
17055 cls : 'fc-header-right',
17057 /* fc_button('month', 'left', '', 'month' ),
17058 fc_button('week', '', '', 'week' ),
17059 fc_button('day', 'right', '', 'day' )
17071 header = this.header;
17074 var cal_heads = function() {
17076 // fixme - handle this.
17078 for (var i =0; i < Date.dayNames.length; i++) {
17079 var d = Date.dayNames[i];
17082 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
17083 html : d.substring(0,3)
17087 ret[0].cls += ' fc-first';
17088 ret[6].cls += ' fc-last';
17091 var cal_cell = function(n) {
17094 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
17099 cls: 'fc-day-number',
17103 cls: 'fc-day-content',
17107 style: 'position: relative;' // height: 17px;
17119 var cal_rows = function() {
17122 for (var r = 0; r < 6; r++) {
17129 for (var i =0; i < Date.dayNames.length; i++) {
17130 var d = Date.dayNames[i];
17131 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
17134 row.cn[0].cls+=' fc-first';
17135 row.cn[0].cn[0].style = 'min-height:90px';
17136 row.cn[6].cls+=' fc-last';
17140 ret[0].cls += ' fc-first';
17141 ret[4].cls += ' fc-prev-last';
17142 ret[5].cls += ' fc-last';
17149 cls: 'fc-border-separate',
17150 style : 'width:100%',
17158 cls : 'fc-first fc-last',
17176 cls : 'fc-content',
17177 style : "position: relative;",
17180 cls : 'fc-view fc-view-month fc-grid',
17181 style : 'position: relative',
17182 unselectable : 'on',
17185 cls : 'fc-event-container',
17186 style : 'position:absolute;z-index:8;top:0;left:0;'
17204 initEvents : function()
17207 throw "can not find store for calendar";
17213 style: "text-align:center",
17217 style: "background-color:white;width:50%;margin:250 auto",
17221 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
17232 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
17234 var size = this.el.select('.fc-content', true).first().getSize();
17235 this.maskEl.setSize(size.width, size.height);
17236 this.maskEl.enableDisplayMode("block");
17237 if(!this.loadMask){
17238 this.maskEl.hide();
17241 this.store = Roo.factory(this.store, Roo.data);
17242 this.store.on('load', this.onLoad, this);
17243 this.store.on('beforeload', this.onBeforeLoad, this);
17247 this.cells = this.el.select('.fc-day',true);
17248 //Roo.log(this.cells);
17249 this.textNodes = this.el.query('.fc-day-number');
17250 this.cells.addClassOnOver('fc-state-hover');
17252 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
17253 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
17254 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
17255 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
17257 this.on('monthchange', this.onMonthChange, this);
17259 this.update(new Date().clearTime());
17262 resize : function() {
17263 var sz = this.el.getSize();
17265 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
17266 this.el.select('.fc-day-content div',true).setHeight(34);
17271 showPrevMonth : function(e){
17272 this.update(this.activeDate.add("mo", -1));
17274 showToday : function(e){
17275 this.update(new Date().clearTime());
17278 showNextMonth : function(e){
17279 this.update(this.activeDate.add("mo", 1));
17283 showPrevYear : function(){
17284 this.update(this.activeDate.add("y", -1));
17288 showNextYear : function(){
17289 this.update(this.activeDate.add("y", 1));
17294 update : function(date)
17296 var vd = this.activeDate;
17297 this.activeDate = date;
17298 // if(vd && this.el){
17299 // var t = date.getTime();
17300 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
17301 // Roo.log('using add remove');
17303 // this.fireEvent('monthchange', this, date);
17305 // this.cells.removeClass("fc-state-highlight");
17306 // this.cells.each(function(c){
17307 // if(c.dateValue == t){
17308 // c.addClass("fc-state-highlight");
17309 // setTimeout(function(){
17310 // try{c.dom.firstChild.focus();}catch(e){}
17320 var days = date.getDaysInMonth();
17322 var firstOfMonth = date.getFirstDateOfMonth();
17323 var startingPos = firstOfMonth.getDay()-this.startDay;
17325 if(startingPos < this.startDay){
17329 var pm = date.add(Date.MONTH, -1);
17330 var prevStart = pm.getDaysInMonth()-startingPos;
17332 this.cells = this.el.select('.fc-day',true);
17333 this.textNodes = this.el.query('.fc-day-number');
17334 this.cells.addClassOnOver('fc-state-hover');
17336 var cells = this.cells.elements;
17337 var textEls = this.textNodes;
17339 Roo.each(cells, function(cell){
17340 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
17343 days += startingPos;
17345 // convert everything to numbers so it's fast
17346 var day = 86400000;
17347 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
17350 //Roo.log(prevStart);
17352 var today = new Date().clearTime().getTime();
17353 var sel = date.clearTime().getTime();
17354 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
17355 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
17356 var ddMatch = this.disabledDatesRE;
17357 var ddText = this.disabledDatesText;
17358 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
17359 var ddaysText = this.disabledDaysText;
17360 var format = this.format;
17362 var setCellClass = function(cal, cell){
17366 //Roo.log('set Cell Class');
17368 var t = d.getTime();
17372 cell.dateValue = t;
17374 cell.className += " fc-today";
17375 cell.className += " fc-state-highlight";
17376 cell.title = cal.todayText;
17379 // disable highlight in other month..
17380 //cell.className += " fc-state-highlight";
17385 cell.className = " fc-state-disabled";
17386 cell.title = cal.minText;
17390 cell.className = " fc-state-disabled";
17391 cell.title = cal.maxText;
17395 if(ddays.indexOf(d.getDay()) != -1){
17396 cell.title = ddaysText;
17397 cell.className = " fc-state-disabled";
17400 if(ddMatch && format){
17401 var fvalue = d.dateFormat(format);
17402 if(ddMatch.test(fvalue)){
17403 cell.title = ddText.replace("%0", fvalue);
17404 cell.className = " fc-state-disabled";
17408 if (!cell.initialClassName) {
17409 cell.initialClassName = cell.dom.className;
17412 cell.dom.className = cell.initialClassName + ' ' + cell.className;
17417 for(; i < startingPos; i++) {
17418 textEls[i].innerHTML = (++prevStart);
17419 d.setDate(d.getDate()+1);
17421 cells[i].className = "fc-past fc-other-month";
17422 setCellClass(this, cells[i]);
17427 for(; i < days; i++){
17428 intDay = i - startingPos + 1;
17429 textEls[i].innerHTML = (intDay);
17430 d.setDate(d.getDate()+1);
17432 cells[i].className = ''; // "x-date-active";
17433 setCellClass(this, cells[i]);
17437 for(; i < 42; i++) {
17438 textEls[i].innerHTML = (++extraDays);
17439 d.setDate(d.getDate()+1);
17441 cells[i].className = "fc-future fc-other-month";
17442 setCellClass(this, cells[i]);
17445 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
17447 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
17449 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
17450 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
17452 if(totalRows != 6){
17453 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
17454 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
17457 this.fireEvent('monthchange', this, date);
17461 if(!this.internalRender){
17462 var main = this.el.dom.firstChild;
17463 var w = main.offsetWidth;
17464 this.el.setWidth(w + this.el.getBorderWidth("lr"));
17465 Roo.fly(main).setWidth(w);
17466 this.internalRender = true;
17467 // opera does not respect the auto grow header center column
17468 // then, after it gets a width opera refuses to recalculate
17469 // without a second pass
17470 if(Roo.isOpera && !this.secondPass){
17471 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
17472 this.secondPass = true;
17473 this.update.defer(10, this, [date]);
17480 findCell : function(dt) {
17481 dt = dt.clearTime().getTime();
17483 this.cells.each(function(c){
17484 //Roo.log("check " +c.dateValue + '?=' + dt);
17485 if(c.dateValue == dt){
17495 findCells : function(ev) {
17496 var s = ev.start.clone().clearTime().getTime();
17498 var e= ev.end.clone().clearTime().getTime();
17501 this.cells.each(function(c){
17502 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
17504 if(c.dateValue > e){
17507 if(c.dateValue < s){
17516 // findBestRow: function(cells)
17520 // for (var i =0 ; i < cells.length;i++) {
17521 // ret = Math.max(cells[i].rows || 0,ret);
17528 addItem : function(ev)
17530 // look for vertical location slot in
17531 var cells = this.findCells(ev);
17533 // ev.row = this.findBestRow(cells);
17535 // work out the location.
17539 for(var i =0; i < cells.length; i++) {
17541 cells[i].row = cells[0].row;
17544 cells[i].row = cells[i].row + 1;
17554 if (crow.start.getY() == cells[i].getY()) {
17556 crow.end = cells[i];
17573 cells[0].events.push(ev);
17575 this.calevents.push(ev);
17578 clearEvents: function() {
17580 if(!this.calevents){
17584 Roo.each(this.cells.elements, function(c){
17590 Roo.each(this.calevents, function(e) {
17591 Roo.each(e.els, function(el) {
17592 el.un('mouseenter' ,this.onEventEnter, this);
17593 el.un('mouseleave' ,this.onEventLeave, this);
17598 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
17604 renderEvents: function()
17608 this.cells.each(function(c) {
17617 if(c.row != c.events.length){
17618 r = 4 - (4 - (c.row - c.events.length));
17621 c.events = ev.slice(0, r);
17622 c.more = ev.slice(r);
17624 if(c.more.length && c.more.length == 1){
17625 c.events.push(c.more.pop());
17628 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
17632 this.cells.each(function(c) {
17634 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
17637 for (var e = 0; e < c.events.length; e++){
17638 var ev = c.events[e];
17639 var rows = ev.rows;
17641 for(var i = 0; i < rows.length; i++) {
17643 // how many rows should it span..
17646 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
17647 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
17649 unselectable : "on",
17652 cls: 'fc-event-inner',
17656 // cls: 'fc-event-time',
17657 // html : cells.length > 1 ? '' : ev.time
17661 cls: 'fc-event-title',
17662 html : String.format('{0}', ev.title)
17669 cls: 'ui-resizable-handle ui-resizable-e',
17670 html : '  '
17677 cfg.cls += ' fc-event-start';
17679 if ((i+1) == rows.length) {
17680 cfg.cls += ' fc-event-end';
17683 var ctr = _this.el.select('.fc-event-container',true).first();
17684 var cg = ctr.createChild(cfg);
17686 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
17687 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
17689 var r = (c.more.length) ? 1 : 0;
17690 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
17691 cg.setWidth(ebox.right - sbox.x -2);
17693 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
17694 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
17695 cg.on('click', _this.onEventClick, _this, ev);
17706 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
17707 style : 'position: absolute',
17708 unselectable : "on",
17711 cls: 'fc-event-inner',
17715 cls: 'fc-event-title',
17723 cls: 'ui-resizable-handle ui-resizable-e',
17724 html : '  '
17730 var ctr = _this.el.select('.fc-event-container',true).first();
17731 var cg = ctr.createChild(cfg);
17733 var sbox = c.select('.fc-day-content',true).first().getBox();
17734 var ebox = c.select('.fc-day-content',true).first().getBox();
17736 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
17737 cg.setWidth(ebox.right - sbox.x -2);
17739 cg.on('click', _this.onMoreEventClick, _this, c.more);
17749 onEventEnter: function (e, el,event,d) {
17750 this.fireEvent('evententer', this, el, event);
17753 onEventLeave: function (e, el,event,d) {
17754 this.fireEvent('eventleave', this, el, event);
17757 onEventClick: function (e, el,event,d) {
17758 this.fireEvent('eventclick', this, el, event);
17761 onMonthChange: function () {
17765 onMoreEventClick: function(e, el, more)
17769 this.calpopover.placement = 'right';
17770 this.calpopover.setTitle('More');
17772 this.calpopover.setContent('');
17774 var ctr = this.calpopover.el.select('.popover-content', true).first();
17776 Roo.each(more, function(m){
17778 cls : 'fc-event-hori fc-event-draggable',
17781 var cg = ctr.createChild(cfg);
17783 cg.on('click', _this.onEventClick, _this, m);
17786 this.calpopover.show(el);
17791 onLoad: function ()
17793 this.calevents = [];
17796 if(this.store.getCount() > 0){
17797 this.store.data.each(function(d){
17800 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
17801 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
17802 time : d.data.start_time,
17803 title : d.data.title,
17804 description : d.data.description,
17805 venue : d.data.venue
17810 this.renderEvents();
17812 if(this.calevents.length && this.loadMask){
17813 this.maskEl.hide();
17817 onBeforeLoad: function()
17819 this.clearEvents();
17821 this.maskEl.show();
17835 * @class Roo.bootstrap.Popover
17836 * @extends Roo.bootstrap.Component
17837 * Bootstrap Popover class
17838 * @cfg {String} html contents of the popover (or false to use children..)
17839 * @cfg {String} title of popover (or false to hide)
17840 * @cfg {String} placement how it is placed
17841 * @cfg {String} trigger click || hover (or false to trigger manually)
17842 * @cfg {String} over what (parent or false to trigger manually.)
17843 * @cfg {Number} delay - delay before showing
17846 * Create a new Popover
17847 * @param {Object} config The config object
17850 Roo.bootstrap.Popover = function(config){
17851 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
17857 * After the popover show
17859 * @param {Roo.bootstrap.Popover} this
17864 * After the popover hide
17866 * @param {Roo.bootstrap.Popover} this
17872 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
17874 title: 'Fill in a title',
17877 placement : 'right',
17878 trigger : 'hover', // hover
17884 can_build_overlaid : false,
17886 getChildContainer : function()
17888 return this.el.select('.popover-content',true).first();
17891 getAutoCreate : function(){
17894 cls : 'popover roo-dynamic',
17895 style: 'display:block',
17901 cls : 'popover-inner',
17905 cls: 'popover-title popover-header',
17909 cls : 'popover-content popover-body',
17920 setTitle: function(str)
17923 this.el.select('.popover-title',true).first().dom.innerHTML = str;
17925 setContent: function(str)
17928 this.el.select('.popover-content',true).first().dom.innerHTML = str;
17930 // as it get's added to the bottom of the page.
17931 onRender : function(ct, position)
17933 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17935 var cfg = Roo.apply({}, this.getAutoCreate());
17939 cfg.cls += ' ' + this.cls;
17942 cfg.style = this.style;
17944 //Roo.log("adding to ");
17945 this.el = Roo.get(document.body).createChild(cfg, position);
17946 // Roo.log(this.el);
17951 initEvents : function()
17953 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
17954 this.el.enableDisplayMode('block');
17956 if (this.over === false) {
17959 if (this.triggers === false) {
17962 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17963 var triggers = this.trigger ? this.trigger.split(' ') : [];
17964 Roo.each(triggers, function(trigger) {
17966 if (trigger == 'click') {
17967 on_el.on('click', this.toggle, this);
17968 } else if (trigger != 'manual') {
17969 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
17970 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
17972 on_el.on(eventIn ,this.enter, this);
17973 on_el.on(eventOut, this.leave, this);
17984 toggle : function () {
17985 this.hoverState == 'in' ? this.leave() : this.enter();
17988 enter : function () {
17990 clearTimeout(this.timeout);
17992 this.hoverState = 'in';
17994 if (!this.delay || !this.delay.show) {
17999 this.timeout = setTimeout(function () {
18000 if (_t.hoverState == 'in') {
18003 }, this.delay.show)
18006 leave : function() {
18007 clearTimeout(this.timeout);
18009 this.hoverState = 'out';
18011 if (!this.delay || !this.delay.hide) {
18016 this.timeout = setTimeout(function () {
18017 if (_t.hoverState == 'out') {
18020 }, this.delay.hide)
18023 show : function (on_el)
18026 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
18030 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
18031 if (this.html !== false) {
18032 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
18034 this.el.removeClass([
18035 'fade','top','bottom', 'left', 'right','in',
18036 'bs-popover-top','bs-popover-bottom', 'bs-popover-left', 'bs-popover-right'
18038 if (!this.title.length) {
18039 this.el.select('.popover-title',true).hide();
18042 var placement = typeof this.placement == 'function' ?
18043 this.placement.call(this, this.el, on_el) :
18046 var autoToken = /\s?auto?\s?/i;
18047 var autoPlace = autoToken.test(placement);
18049 placement = placement.replace(autoToken, '') || 'top';
18053 //this.el.setXY([0,0]);
18055 this.el.dom.style.display='block';
18056 this.el.addClass(placement);
18058 //this.el.appendTo(on_el);
18060 var p = this.getPosition();
18061 var box = this.el.getBox();
18066 var align = Roo.bootstrap.Popover.alignment[placement];
18069 this.el.alignTo(on_el, align[0],align[1]);
18070 //var arrow = this.el.select('.arrow',true).first();
18071 //arrow.set(align[2],
18073 this.el.addClass('in');
18076 if (this.el.hasClass('fade')) {
18080 this.hoverState = 'in';
18082 this.fireEvent('show', this);
18087 this.el.setXY([0,0]);
18088 this.el.removeClass('in');
18090 this.hoverState = null;
18092 this.fireEvent('hide', this);
18097 Roo.bootstrap.Popover.alignment = {
18098 'left' : ['r-l', [-10,0], 'right bs-popover-right'],
18099 'right' : ['l-r', [10,0], 'left bs-popover-left'],
18100 'bottom' : ['t-b', [0,10], 'top bs-popover-top'],
18101 'top' : [ 'b-t', [0,-10], 'bottom bs-popover-bottom']
18112 * @class Roo.bootstrap.Progress
18113 * @extends Roo.bootstrap.Component
18114 * Bootstrap Progress class
18115 * @cfg {Boolean} striped striped of the progress bar
18116 * @cfg {Boolean} active animated of the progress bar
18120 * Create a new Progress
18121 * @param {Object} config The config object
18124 Roo.bootstrap.Progress = function(config){
18125 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
18128 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
18133 getAutoCreate : function(){
18141 cfg.cls += ' progress-striped';
18145 cfg.cls += ' active';
18164 * @class Roo.bootstrap.ProgressBar
18165 * @extends Roo.bootstrap.Component
18166 * Bootstrap ProgressBar class
18167 * @cfg {Number} aria_valuenow aria-value now
18168 * @cfg {Number} aria_valuemin aria-value min
18169 * @cfg {Number} aria_valuemax aria-value max
18170 * @cfg {String} label label for the progress bar
18171 * @cfg {String} panel (success | info | warning | danger )
18172 * @cfg {String} role role of the progress bar
18173 * @cfg {String} sr_only text
18177 * Create a new ProgressBar
18178 * @param {Object} config The config object
18181 Roo.bootstrap.ProgressBar = function(config){
18182 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
18185 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
18189 aria_valuemax : 100,
18195 getAutoCreate : function()
18200 cls: 'progress-bar',
18201 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
18213 cfg.role = this.role;
18216 if(this.aria_valuenow){
18217 cfg['aria-valuenow'] = this.aria_valuenow;
18220 if(this.aria_valuemin){
18221 cfg['aria-valuemin'] = this.aria_valuemin;
18224 if(this.aria_valuemax){
18225 cfg['aria-valuemax'] = this.aria_valuemax;
18228 if(this.label && !this.sr_only){
18229 cfg.html = this.label;
18233 cfg.cls += ' progress-bar-' + this.panel;
18239 update : function(aria_valuenow)
18241 this.aria_valuenow = aria_valuenow;
18243 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
18258 * @class Roo.bootstrap.TabGroup
18259 * @extends Roo.bootstrap.Column
18260 * Bootstrap Column class
18261 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
18262 * @cfg {Boolean} carousel true to make the group behave like a carousel
18263 * @cfg {Boolean} bullets show bullets for the panels
18264 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
18265 * @cfg {Number} timer auto slide timer .. default 0 millisecond
18266 * @cfg {Boolean} showarrow (true|false) show arrow default true
18269 * Create a new TabGroup
18270 * @param {Object} config The config object
18273 Roo.bootstrap.TabGroup = function(config){
18274 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
18276 this.navId = Roo.id();
18279 Roo.bootstrap.TabGroup.register(this);
18283 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
18286 transition : false,
18291 slideOnTouch : false,
18294 getAutoCreate : function()
18296 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
18298 cfg.cls += ' tab-content';
18300 if (this.carousel) {
18301 cfg.cls += ' carousel slide';
18304 cls : 'carousel-inner',
18308 if(this.bullets && !Roo.isTouch){
18311 cls : 'carousel-bullets',
18315 if(this.bullets_cls){
18316 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
18323 cfg.cn[0].cn.push(bullets);
18326 if(this.showarrow){
18327 cfg.cn[0].cn.push({
18329 class : 'carousel-arrow',
18333 class : 'carousel-prev',
18337 class : 'fa fa-chevron-left'
18343 class : 'carousel-next',
18347 class : 'fa fa-chevron-right'
18360 initEvents: function()
18362 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
18363 // this.el.on("touchstart", this.onTouchStart, this);
18366 if(this.autoslide){
18369 this.slideFn = window.setInterval(function() {
18370 _this.showPanelNext();
18374 if(this.showarrow){
18375 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
18376 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
18382 // onTouchStart : function(e, el, o)
18384 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
18388 // this.showPanelNext();
18392 getChildContainer : function()
18394 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
18398 * register a Navigation item
18399 * @param {Roo.bootstrap.NavItem} the navitem to add
18401 register : function(item)
18403 this.tabs.push( item);
18404 item.navId = this.navId; // not really needed..
18409 getActivePanel : function()
18412 Roo.each(this.tabs, function(t) {
18422 getPanelByName : function(n)
18425 Roo.each(this.tabs, function(t) {
18426 if (t.tabId == n) {
18434 indexOfPanel : function(p)
18437 Roo.each(this.tabs, function(t,i) {
18438 if (t.tabId == p.tabId) {
18447 * show a specific panel
18448 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
18449 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
18451 showPanel : function (pan)
18453 if(this.transition || typeof(pan) == 'undefined'){
18454 Roo.log("waiting for the transitionend");
18458 if (typeof(pan) == 'number') {
18459 pan = this.tabs[pan];
18462 if (typeof(pan) == 'string') {
18463 pan = this.getPanelByName(pan);
18466 var cur = this.getActivePanel();
18469 Roo.log('pan or acitve pan is undefined');
18473 if (pan.tabId == this.getActivePanel().tabId) {
18477 if (false === cur.fireEvent('beforedeactivate')) {
18481 if(this.bullets > 0 && !Roo.isTouch){
18482 this.setActiveBullet(this.indexOfPanel(pan));
18485 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
18487 //class="carousel-item carousel-item-next carousel-item-left"
18489 this.transition = true;
18490 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
18491 var lr = dir == 'next' ? 'left' : 'right';
18492 pan.el.addClass(dir); // or prev
18493 pan.el.addClass('carousel-item-' + dir); // or prev
18494 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
18495 cur.el.addClass(lr); // or right
18496 pan.el.addClass(lr);
18497 cur.el.addClass('carousel-item-' +lr); // or right
18498 pan.el.addClass('carousel-item-' +lr);
18502 cur.el.on('transitionend', function() {
18503 Roo.log("trans end?");
18505 pan.el.removeClass([lr,dir, 'carousel-item-' + lr, 'carousel-item-' + dir]);
18506 pan.setActive(true);
18508 cur.el.removeClass([lr, 'carousel-item-' + lr]);
18509 cur.setActive(false);
18511 _this.transition = false;
18513 }, this, { single: true } );
18518 cur.setActive(false);
18519 pan.setActive(true);
18524 showPanelNext : function()
18526 var i = this.indexOfPanel(this.getActivePanel());
18528 if (i >= this.tabs.length - 1 && !this.autoslide) {
18532 if (i >= this.tabs.length - 1 && this.autoslide) {
18536 this.showPanel(this.tabs[i+1]);
18539 showPanelPrev : function()
18541 var i = this.indexOfPanel(this.getActivePanel());
18543 if (i < 1 && !this.autoslide) {
18547 if (i < 1 && this.autoslide) {
18548 i = this.tabs.length;
18551 this.showPanel(this.tabs[i-1]);
18555 addBullet: function()
18557 if(!this.bullets || Roo.isTouch){
18560 var ctr = this.el.select('.carousel-bullets',true).first();
18561 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
18562 var bullet = ctr.createChild({
18563 cls : 'bullet bullet-' + i
18564 },ctr.dom.lastChild);
18569 bullet.on('click', (function(e, el, o, ii, t){
18571 e.preventDefault();
18573 this.showPanel(ii);
18575 if(this.autoslide && this.slideFn){
18576 clearInterval(this.slideFn);
18577 this.slideFn = window.setInterval(function() {
18578 _this.showPanelNext();
18582 }).createDelegate(this, [i, bullet], true));
18587 setActiveBullet : function(i)
18593 Roo.each(this.el.select('.bullet', true).elements, function(el){
18594 el.removeClass('selected');
18597 var bullet = this.el.select('.bullet-' + i, true).first();
18603 bullet.addClass('selected');
18614 Roo.apply(Roo.bootstrap.TabGroup, {
18618 * register a Navigation Group
18619 * @param {Roo.bootstrap.NavGroup} the navgroup to add
18621 register : function(navgrp)
18623 this.groups[navgrp.navId] = navgrp;
18627 * fetch a Navigation Group based on the navigation ID
18628 * if one does not exist , it will get created.
18629 * @param {string} the navgroup to add
18630 * @returns {Roo.bootstrap.NavGroup} the navgroup
18632 get: function(navId) {
18633 if (typeof(this.groups[navId]) == 'undefined') {
18634 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
18636 return this.groups[navId] ;
18651 * @class Roo.bootstrap.TabPanel
18652 * @extends Roo.bootstrap.Component
18653 * Bootstrap TabPanel class
18654 * @cfg {Boolean} active panel active
18655 * @cfg {String} html panel content
18656 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
18657 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
18658 * @cfg {String} href click to link..
18662 * Create a new TabPanel
18663 * @param {Object} config The config object
18666 Roo.bootstrap.TabPanel = function(config){
18667 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
18671 * Fires when the active status changes
18672 * @param {Roo.bootstrap.TabPanel} this
18673 * @param {Boolean} state the new state
18678 * @event beforedeactivate
18679 * Fires before a tab is de-activated - can be used to do validation on a form.
18680 * @param {Roo.bootstrap.TabPanel} this
18681 * @return {Boolean} false if there is an error
18684 'beforedeactivate': true
18687 this.tabId = this.tabId || Roo.id();
18691 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
18699 getAutoCreate : function(){
18704 // item is needed for carousel - not sure if it has any effect otherwise
18705 cls: 'carousel-item tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
18706 html: this.html || ''
18710 cfg.cls += ' active';
18714 cfg.tabId = this.tabId;
18722 initEvents: function()
18724 var p = this.parent();
18726 this.navId = this.navId || p.navId;
18728 if (typeof(this.navId) != 'undefined') {
18729 // not really needed.. but just in case.. parent should be a NavGroup.
18730 var tg = Roo.bootstrap.TabGroup.get(this.navId);
18734 var i = tg.tabs.length - 1;
18736 if(this.active && tg.bullets > 0 && i < tg.bullets){
18737 tg.setActiveBullet(i);
18741 this.el.on('click', this.onClick, this);
18744 this.el.on("touchstart", this.onTouchStart, this);
18745 this.el.on("touchmove", this.onTouchMove, this);
18746 this.el.on("touchend", this.onTouchEnd, this);
18751 onRender : function(ct, position)
18753 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
18756 setActive : function(state)
18758 Roo.log("panel - set active " + this.tabId + "=" + state);
18760 this.active = state;
18762 this.el.removeClass('active');
18764 } else if (!this.el.hasClass('active')) {
18765 this.el.addClass('active');
18768 this.fireEvent('changed', this, state);
18771 onClick : function(e)
18773 e.preventDefault();
18775 if(!this.href.length){
18779 window.location.href = this.href;
18788 onTouchStart : function(e)
18790 this.swiping = false;
18792 this.startX = e.browserEvent.touches[0].clientX;
18793 this.startY = e.browserEvent.touches[0].clientY;
18796 onTouchMove : function(e)
18798 this.swiping = true;
18800 this.endX = e.browserEvent.touches[0].clientX;
18801 this.endY = e.browserEvent.touches[0].clientY;
18804 onTouchEnd : function(e)
18811 var tabGroup = this.parent();
18813 if(this.endX > this.startX){ // swiping right
18814 tabGroup.showPanelPrev();
18818 if(this.startX > this.endX){ // swiping left
18819 tabGroup.showPanelNext();
18838 * @class Roo.bootstrap.DateField
18839 * @extends Roo.bootstrap.Input
18840 * Bootstrap DateField class
18841 * @cfg {Number} weekStart default 0
18842 * @cfg {String} viewMode default empty, (months|years)
18843 * @cfg {String} minViewMode default empty, (months|years)
18844 * @cfg {Number} startDate default -Infinity
18845 * @cfg {Number} endDate default Infinity
18846 * @cfg {Boolean} todayHighlight default false
18847 * @cfg {Boolean} todayBtn default false
18848 * @cfg {Boolean} calendarWeeks default false
18849 * @cfg {Object} daysOfWeekDisabled default empty
18850 * @cfg {Boolean} singleMode default false (true | false)
18852 * @cfg {Boolean} keyboardNavigation default true
18853 * @cfg {String} language default en
18856 * Create a new DateField
18857 * @param {Object} config The config object
18860 Roo.bootstrap.DateField = function(config){
18861 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
18865 * Fires when this field show.
18866 * @param {Roo.bootstrap.DateField} this
18867 * @param {Mixed} date The date value
18872 * Fires when this field hide.
18873 * @param {Roo.bootstrap.DateField} this
18874 * @param {Mixed} date The date value
18879 * Fires when select a date.
18880 * @param {Roo.bootstrap.DateField} this
18881 * @param {Mixed} date The date value
18885 * @event beforeselect
18886 * Fires when before select a date.
18887 * @param {Roo.bootstrap.DateField} this
18888 * @param {Mixed} date The date value
18890 beforeselect : true
18894 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
18897 * @cfg {String} format
18898 * The default date format string which can be overriden for localization support. The format must be
18899 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
18903 * @cfg {String} altFormats
18904 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
18905 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
18907 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
18915 todayHighlight : false,
18921 keyboardNavigation: true,
18923 calendarWeeks: false,
18925 startDate: -Infinity,
18929 daysOfWeekDisabled: [],
18933 singleMode : false,
18935 UTCDate: function()
18937 return new Date(Date.UTC.apply(Date, arguments));
18940 UTCToday: function()
18942 var today = new Date();
18943 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
18946 getDate: function() {
18947 var d = this.getUTCDate();
18948 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
18951 getUTCDate: function() {
18955 setDate: function(d) {
18956 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
18959 setUTCDate: function(d) {
18961 this.setValue(this.formatDate(this.date));
18964 onRender: function(ct, position)
18967 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
18969 this.language = this.language || 'en';
18970 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
18971 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
18973 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
18974 this.format = this.format || 'm/d/y';
18975 this.isInline = false;
18976 this.isInput = true;
18977 this.component = this.el.select('.add-on', true).first() || false;
18978 this.component = (this.component && this.component.length === 0) ? false : this.component;
18979 this.hasInput = this.component && this.inputEl().length;
18981 if (typeof(this.minViewMode === 'string')) {
18982 switch (this.minViewMode) {
18984 this.minViewMode = 1;
18987 this.minViewMode = 2;
18990 this.minViewMode = 0;
18995 if (typeof(this.viewMode === 'string')) {
18996 switch (this.viewMode) {
19009 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
19011 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
19013 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19015 this.picker().on('mousedown', this.onMousedown, this);
19016 this.picker().on('click', this.onClick, this);
19018 this.picker().addClass('datepicker-dropdown');
19020 this.startViewMode = this.viewMode;
19022 if(this.singleMode){
19023 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
19024 v.setVisibilityMode(Roo.Element.DISPLAY);
19028 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
19029 v.setStyle('width', '189px');
19033 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
19034 if(!this.calendarWeeks){
19039 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
19040 v.attr('colspan', function(i, val){
19041 return parseInt(val) + 1;
19046 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
19048 this.setStartDate(this.startDate);
19049 this.setEndDate(this.endDate);
19051 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
19058 if(this.isInline) {
19063 picker : function()
19065 return this.pickerEl;
19066 // return this.el.select('.datepicker', true).first();
19069 fillDow: function()
19071 var dowCnt = this.weekStart;
19080 if(this.calendarWeeks){
19088 while (dowCnt < this.weekStart + 7) {
19092 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
19096 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
19099 fillMonths: function()
19102 var months = this.picker().select('>.datepicker-months td', true).first();
19104 months.dom.innerHTML = '';
19110 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
19113 months.createChild(month);
19120 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;
19122 if (this.date < this.startDate) {
19123 this.viewDate = new Date(this.startDate);
19124 } else if (this.date > this.endDate) {
19125 this.viewDate = new Date(this.endDate);
19127 this.viewDate = new Date(this.date);
19135 var d = new Date(this.viewDate),
19136 year = d.getUTCFullYear(),
19137 month = d.getUTCMonth(),
19138 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
19139 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
19140 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
19141 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
19142 currentDate = this.date && this.date.valueOf(),
19143 today = this.UTCToday();
19145 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
19147 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
19149 // this.picker.select('>tfoot th.today').
19150 // .text(dates[this.language].today)
19151 // .toggle(this.todayBtn !== false);
19153 this.updateNavArrows();
19156 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
19158 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
19160 prevMonth.setUTCDate(day);
19162 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
19164 var nextMonth = new Date(prevMonth);
19166 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
19168 nextMonth = nextMonth.valueOf();
19170 var fillMonths = false;
19172 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
19174 while(prevMonth.valueOf() <= nextMonth) {
19177 if (prevMonth.getUTCDay() === this.weekStart) {
19179 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
19187 if(this.calendarWeeks){
19188 // ISO 8601: First week contains first thursday.
19189 // ISO also states week starts on Monday, but we can be more abstract here.
19191 // Start of current week: based on weekstart/current date
19192 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
19193 // Thursday of this week
19194 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
19195 // First Thursday of year, year from thursday
19196 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
19197 // Calendar week: ms between thursdays, div ms per day, div 7 days
19198 calWeek = (th - yth) / 864e5 / 7 + 1;
19200 fillMonths.cn.push({
19208 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
19210 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
19213 if (this.todayHighlight &&
19214 prevMonth.getUTCFullYear() == today.getFullYear() &&
19215 prevMonth.getUTCMonth() == today.getMonth() &&
19216 prevMonth.getUTCDate() == today.getDate()) {
19217 clsName += ' today';
19220 if (currentDate && prevMonth.valueOf() === currentDate) {
19221 clsName += ' active';
19224 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
19225 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
19226 clsName += ' disabled';
19229 fillMonths.cn.push({
19231 cls: 'day ' + clsName,
19232 html: prevMonth.getDate()
19235 prevMonth.setDate(prevMonth.getDate()+1);
19238 var currentYear = this.date && this.date.getUTCFullYear();
19239 var currentMonth = this.date && this.date.getUTCMonth();
19241 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
19243 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
19244 v.removeClass('active');
19246 if(currentYear === year && k === currentMonth){
19247 v.addClass('active');
19250 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
19251 v.addClass('disabled');
19257 year = parseInt(year/10, 10) * 10;
19259 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
19261 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
19264 for (var i = -1; i < 11; i++) {
19265 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
19267 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
19275 showMode: function(dir)
19278 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
19281 Roo.each(this.picker().select('>div',true).elements, function(v){
19282 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19285 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
19290 if(this.isInline) {
19294 this.picker().removeClass(['bottom', 'top']);
19296 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
19298 * place to the top of element!
19302 this.picker().addClass('top');
19303 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
19308 this.picker().addClass('bottom');
19310 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
19313 parseDate : function(value)
19315 if(!value || value instanceof Date){
19318 var v = Date.parseDate(value, this.format);
19319 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
19320 v = Date.parseDate(value, 'Y-m-d');
19322 if(!v && this.altFormats){
19323 if(!this.altFormatsArray){
19324 this.altFormatsArray = this.altFormats.split("|");
19326 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
19327 v = Date.parseDate(value, this.altFormatsArray[i]);
19333 formatDate : function(date, fmt)
19335 return (!date || !(date instanceof Date)) ?
19336 date : date.dateFormat(fmt || this.format);
19339 onFocus : function()
19341 Roo.bootstrap.DateField.superclass.onFocus.call(this);
19345 onBlur : function()
19347 Roo.bootstrap.DateField.superclass.onBlur.call(this);
19349 var d = this.inputEl().getValue();
19356 showPopup : function()
19358 this.picker().show();
19362 this.fireEvent('showpopup', this, this.date);
19365 hidePopup : function()
19367 if(this.isInline) {
19370 this.picker().hide();
19371 this.viewMode = this.startViewMode;
19374 this.fireEvent('hidepopup', this, this.date);
19378 onMousedown: function(e)
19380 e.stopPropagation();
19381 e.preventDefault();
19386 Roo.bootstrap.DateField.superclass.keyup.call(this);
19390 setValue: function(v)
19392 if(this.fireEvent('beforeselect', this, v) !== false){
19393 var d = new Date(this.parseDate(v) ).clearTime();
19395 if(isNaN(d.getTime())){
19396 this.date = this.viewDate = '';
19397 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
19401 v = this.formatDate(d);
19403 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
19405 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
19409 this.fireEvent('select', this, this.date);
19413 getValue: function()
19415 return this.formatDate(this.date);
19418 fireKey: function(e)
19420 if (!this.picker().isVisible()){
19421 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19427 var dateChanged = false,
19429 newDate, newViewDate;
19434 e.preventDefault();
19438 if (!this.keyboardNavigation) {
19441 dir = e.keyCode == 37 ? -1 : 1;
19444 newDate = this.moveYear(this.date, dir);
19445 newViewDate = this.moveYear(this.viewDate, dir);
19446 } else if (e.shiftKey){
19447 newDate = this.moveMonth(this.date, dir);
19448 newViewDate = this.moveMonth(this.viewDate, dir);
19450 newDate = new Date(this.date);
19451 newDate.setUTCDate(this.date.getUTCDate() + dir);
19452 newViewDate = new Date(this.viewDate);
19453 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
19455 if (this.dateWithinRange(newDate)){
19456 this.date = newDate;
19457 this.viewDate = newViewDate;
19458 this.setValue(this.formatDate(this.date));
19460 e.preventDefault();
19461 dateChanged = true;
19466 if (!this.keyboardNavigation) {
19469 dir = e.keyCode == 38 ? -1 : 1;
19471 newDate = this.moveYear(this.date, dir);
19472 newViewDate = this.moveYear(this.viewDate, dir);
19473 } else if (e.shiftKey){
19474 newDate = this.moveMonth(this.date, dir);
19475 newViewDate = this.moveMonth(this.viewDate, dir);
19477 newDate = new Date(this.date);
19478 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
19479 newViewDate = new Date(this.viewDate);
19480 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
19482 if (this.dateWithinRange(newDate)){
19483 this.date = newDate;
19484 this.viewDate = newViewDate;
19485 this.setValue(this.formatDate(this.date));
19487 e.preventDefault();
19488 dateChanged = true;
19492 this.setValue(this.formatDate(this.date));
19494 e.preventDefault();
19497 this.setValue(this.formatDate(this.date));
19511 onClick: function(e)
19513 e.stopPropagation();
19514 e.preventDefault();
19516 var target = e.getTarget();
19518 if(target.nodeName.toLowerCase() === 'i'){
19519 target = Roo.get(target).dom.parentNode;
19522 var nodeName = target.nodeName;
19523 var className = target.className;
19524 var html = target.innerHTML;
19525 //Roo.log(nodeName);
19527 switch(nodeName.toLowerCase()) {
19529 switch(className) {
19535 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
19536 switch(this.viewMode){
19538 this.viewDate = this.moveMonth(this.viewDate, dir);
19542 this.viewDate = this.moveYear(this.viewDate, dir);
19548 var date = new Date();
19549 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
19551 this.setValue(this.formatDate(this.date));
19558 if (className.indexOf('disabled') < 0) {
19559 this.viewDate.setUTCDate(1);
19560 if (className.indexOf('month') > -1) {
19561 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
19563 var year = parseInt(html, 10) || 0;
19564 this.viewDate.setUTCFullYear(year);
19568 if(this.singleMode){
19569 this.setValue(this.formatDate(this.viewDate));
19580 //Roo.log(className);
19581 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
19582 var day = parseInt(html, 10) || 1;
19583 var year = this.viewDate.getUTCFullYear(),
19584 month = this.viewDate.getUTCMonth();
19586 if (className.indexOf('old') > -1) {
19593 } else if (className.indexOf('new') > -1) {
19601 //Roo.log([year,month,day]);
19602 this.date = this.UTCDate(year, month, day,0,0,0,0);
19603 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
19605 //Roo.log(this.formatDate(this.date));
19606 this.setValue(this.formatDate(this.date));
19613 setStartDate: function(startDate)
19615 this.startDate = startDate || -Infinity;
19616 if (this.startDate !== -Infinity) {
19617 this.startDate = this.parseDate(this.startDate);
19620 this.updateNavArrows();
19623 setEndDate: function(endDate)
19625 this.endDate = endDate || Infinity;
19626 if (this.endDate !== Infinity) {
19627 this.endDate = this.parseDate(this.endDate);
19630 this.updateNavArrows();
19633 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
19635 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
19636 if (typeof(this.daysOfWeekDisabled) !== 'object') {
19637 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
19639 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
19640 return parseInt(d, 10);
19643 this.updateNavArrows();
19646 updateNavArrows: function()
19648 if(this.singleMode){
19652 var d = new Date(this.viewDate),
19653 year = d.getUTCFullYear(),
19654 month = d.getUTCMonth();
19656 Roo.each(this.picker().select('.prev', true).elements, function(v){
19658 switch (this.viewMode) {
19661 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
19667 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
19674 Roo.each(this.picker().select('.next', true).elements, function(v){
19676 switch (this.viewMode) {
19679 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
19685 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
19693 moveMonth: function(date, dir)
19698 var new_date = new Date(date.valueOf()),
19699 day = new_date.getUTCDate(),
19700 month = new_date.getUTCMonth(),
19701 mag = Math.abs(dir),
19703 dir = dir > 0 ? 1 : -1;
19706 // If going back one month, make sure month is not current month
19707 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
19709 return new_date.getUTCMonth() == month;
19711 // If going forward one month, make sure month is as expected
19712 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
19714 return new_date.getUTCMonth() != new_month;
19716 new_month = month + dir;
19717 new_date.setUTCMonth(new_month);
19718 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
19719 if (new_month < 0 || new_month > 11) {
19720 new_month = (new_month + 12) % 12;
19723 // For magnitudes >1, move one month at a time...
19724 for (var i=0; i<mag; i++) {
19725 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
19726 new_date = this.moveMonth(new_date, dir);
19728 // ...then reset the day, keeping it in the new month
19729 new_month = new_date.getUTCMonth();
19730 new_date.setUTCDate(day);
19732 return new_month != new_date.getUTCMonth();
19735 // Common date-resetting loop -- if date is beyond end of month, make it
19738 new_date.setUTCDate(--day);
19739 new_date.setUTCMonth(new_month);
19744 moveYear: function(date, dir)
19746 return this.moveMonth(date, dir*12);
19749 dateWithinRange: function(date)
19751 return date >= this.startDate && date <= this.endDate;
19757 this.picker().remove();
19760 validateValue : function(value)
19762 if(this.getVisibilityEl().hasClass('hidden')){
19766 if(value.length < 1) {
19767 if(this.allowBlank){
19773 if(value.length < this.minLength){
19776 if(value.length > this.maxLength){
19780 var vt = Roo.form.VTypes;
19781 if(!vt[this.vtype](value, this)){
19785 if(typeof this.validator == "function"){
19786 var msg = this.validator(value);
19792 if(this.regex && !this.regex.test(value)){
19796 if(typeof(this.parseDate(value)) == 'undefined'){
19800 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
19804 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
19814 this.date = this.viewDate = '';
19816 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
19821 Roo.apply(Roo.bootstrap.DateField, {
19832 html: '<i class="fa fa-arrow-left"/>'
19842 html: '<i class="fa fa-arrow-right"/>'
19884 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
19885 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
19886 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
19887 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19888 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
19901 navFnc: 'FullYear',
19906 navFnc: 'FullYear',
19911 Roo.apply(Roo.bootstrap.DateField, {
19915 cls: 'datepicker dropdown-menu roo-dynamic',
19919 cls: 'datepicker-days',
19923 cls: 'table-condensed',
19925 Roo.bootstrap.DateField.head,
19929 Roo.bootstrap.DateField.footer
19936 cls: 'datepicker-months',
19940 cls: 'table-condensed',
19942 Roo.bootstrap.DateField.head,
19943 Roo.bootstrap.DateField.content,
19944 Roo.bootstrap.DateField.footer
19951 cls: 'datepicker-years',
19955 cls: 'table-condensed',
19957 Roo.bootstrap.DateField.head,
19958 Roo.bootstrap.DateField.content,
19959 Roo.bootstrap.DateField.footer
19978 * @class Roo.bootstrap.TimeField
19979 * @extends Roo.bootstrap.Input
19980 * Bootstrap DateField class
19984 * Create a new TimeField
19985 * @param {Object} config The config object
19988 Roo.bootstrap.TimeField = function(config){
19989 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
19993 * Fires when this field show.
19994 * @param {Roo.bootstrap.DateField} thisthis
19995 * @param {Mixed} date The date value
20000 * Fires when this field hide.
20001 * @param {Roo.bootstrap.DateField} this
20002 * @param {Mixed} date The date value
20007 * Fires when select a date.
20008 * @param {Roo.bootstrap.DateField} this
20009 * @param {Mixed} date The date value
20015 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
20018 * @cfg {String} format
20019 * The default time format string which can be overriden for localization support. The format must be
20020 * valid according to {@link Date#parseDate} (defaults to 'H:i').
20024 onRender: function(ct, position)
20027 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
20029 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
20031 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
20033 this.pop = this.picker().select('>.datepicker-time',true).first();
20034 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
20036 this.picker().on('mousedown', this.onMousedown, this);
20037 this.picker().on('click', this.onClick, this);
20039 this.picker().addClass('datepicker-dropdown');
20044 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
20045 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
20046 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
20047 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
20048 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
20049 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
20053 fireKey: function(e){
20054 if (!this.picker().isVisible()){
20055 if (e.keyCode == 27) { // allow escape to hide and re-show picker
20061 e.preventDefault();
20069 this.onTogglePeriod();
20072 this.onIncrementMinutes();
20075 this.onDecrementMinutes();
20084 onClick: function(e) {
20085 e.stopPropagation();
20086 e.preventDefault();
20089 picker : function()
20091 return this.el.select('.datepicker', true).first();
20094 fillTime: function()
20096 var time = this.pop.select('tbody', true).first();
20098 time.dom.innerHTML = '';
20113 cls: 'hours-up glyphicon glyphicon-chevron-up'
20133 cls: 'minutes-up glyphicon glyphicon-chevron-up'
20154 cls: 'timepicker-hour',
20169 cls: 'timepicker-minute',
20184 cls: 'btn btn-primary period',
20206 cls: 'hours-down glyphicon glyphicon-chevron-down'
20226 cls: 'minutes-down glyphicon glyphicon-chevron-down'
20244 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
20251 var hours = this.time.getHours();
20252 var minutes = this.time.getMinutes();
20265 hours = hours - 12;
20269 hours = '0' + hours;
20273 minutes = '0' + minutes;
20276 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
20277 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
20278 this.pop.select('button', true).first().dom.innerHTML = period;
20284 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
20286 var cls = ['bottom'];
20288 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
20295 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
20300 this.picker().addClass(cls.join('-'));
20304 Roo.each(cls, function(c){
20306 _this.picker().setTop(_this.inputEl().getHeight());
20310 _this.picker().setTop(0 - _this.picker().getHeight());
20315 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
20319 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
20326 onFocus : function()
20328 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
20332 onBlur : function()
20334 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
20340 this.picker().show();
20345 this.fireEvent('show', this, this.date);
20350 this.picker().hide();
20353 this.fireEvent('hide', this, this.date);
20356 setTime : function()
20359 this.setValue(this.time.format(this.format));
20361 this.fireEvent('select', this, this.date);
20366 onMousedown: function(e){
20367 e.stopPropagation();
20368 e.preventDefault();
20371 onIncrementHours: function()
20373 Roo.log('onIncrementHours');
20374 this.time = this.time.add(Date.HOUR, 1);
20379 onDecrementHours: function()
20381 Roo.log('onDecrementHours');
20382 this.time = this.time.add(Date.HOUR, -1);
20386 onIncrementMinutes: function()
20388 Roo.log('onIncrementMinutes');
20389 this.time = this.time.add(Date.MINUTE, 1);
20393 onDecrementMinutes: function()
20395 Roo.log('onDecrementMinutes');
20396 this.time = this.time.add(Date.MINUTE, -1);
20400 onTogglePeriod: function()
20402 Roo.log('onTogglePeriod');
20403 this.time = this.time.add(Date.HOUR, 12);
20410 Roo.apply(Roo.bootstrap.TimeField, {
20440 cls: 'btn btn-info ok',
20452 Roo.apply(Roo.bootstrap.TimeField, {
20456 cls: 'datepicker dropdown-menu',
20460 cls: 'datepicker-time',
20464 cls: 'table-condensed',
20466 Roo.bootstrap.TimeField.content,
20467 Roo.bootstrap.TimeField.footer
20486 * @class Roo.bootstrap.MonthField
20487 * @extends Roo.bootstrap.Input
20488 * Bootstrap MonthField class
20490 * @cfg {String} language default en
20493 * Create a new MonthField
20494 * @param {Object} config The config object
20497 Roo.bootstrap.MonthField = function(config){
20498 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
20503 * Fires when this field show.
20504 * @param {Roo.bootstrap.MonthField} this
20505 * @param {Mixed} date The date value
20510 * Fires when this field hide.
20511 * @param {Roo.bootstrap.MonthField} this
20512 * @param {Mixed} date The date value
20517 * Fires when select a date.
20518 * @param {Roo.bootstrap.MonthField} this
20519 * @param {String} oldvalue The old value
20520 * @param {String} newvalue The new value
20526 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
20528 onRender: function(ct, position)
20531 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
20533 this.language = this.language || 'en';
20534 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
20535 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
20537 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
20538 this.isInline = false;
20539 this.isInput = true;
20540 this.component = this.el.select('.add-on', true).first() || false;
20541 this.component = (this.component && this.component.length === 0) ? false : this.component;
20542 this.hasInput = this.component && this.inputEL().length;
20544 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
20546 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
20548 this.picker().on('mousedown', this.onMousedown, this);
20549 this.picker().on('click', this.onClick, this);
20551 this.picker().addClass('datepicker-dropdown');
20553 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
20554 v.setStyle('width', '189px');
20561 if(this.isInline) {
20567 setValue: function(v, suppressEvent)
20569 var o = this.getValue();
20571 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
20575 if(suppressEvent !== true){
20576 this.fireEvent('select', this, o, v);
20581 getValue: function()
20586 onClick: function(e)
20588 e.stopPropagation();
20589 e.preventDefault();
20591 var target = e.getTarget();
20593 if(target.nodeName.toLowerCase() === 'i'){
20594 target = Roo.get(target).dom.parentNode;
20597 var nodeName = target.nodeName;
20598 var className = target.className;
20599 var html = target.innerHTML;
20601 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
20605 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
20607 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20613 picker : function()
20615 return this.pickerEl;
20618 fillMonths: function()
20621 var months = this.picker().select('>.datepicker-months td', true).first();
20623 months.dom.innerHTML = '';
20629 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
20632 months.createChild(month);
20641 if(typeof(this.vIndex) == 'undefined' && this.value.length){
20642 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
20645 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
20646 e.removeClass('active');
20648 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
20649 e.addClass('active');
20656 if(this.isInline) {
20660 this.picker().removeClass(['bottom', 'top']);
20662 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
20664 * place to the top of element!
20668 this.picker().addClass('top');
20669 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
20674 this.picker().addClass('bottom');
20676 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
20679 onFocus : function()
20681 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
20685 onBlur : function()
20687 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
20689 var d = this.inputEl().getValue();
20698 this.picker().show();
20699 this.picker().select('>.datepicker-months', true).first().show();
20703 this.fireEvent('show', this, this.date);
20708 if(this.isInline) {
20711 this.picker().hide();
20712 this.fireEvent('hide', this, this.date);
20716 onMousedown: function(e)
20718 e.stopPropagation();
20719 e.preventDefault();
20724 Roo.bootstrap.MonthField.superclass.keyup.call(this);
20728 fireKey: function(e)
20730 if (!this.picker().isVisible()){
20731 if (e.keyCode == 27) {// allow escape to hide and re-show picker
20742 e.preventDefault();
20746 dir = e.keyCode == 37 ? -1 : 1;
20748 this.vIndex = this.vIndex + dir;
20750 if(this.vIndex < 0){
20754 if(this.vIndex > 11){
20758 if(isNaN(this.vIndex)){
20762 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20768 dir = e.keyCode == 38 ? -1 : 1;
20770 this.vIndex = this.vIndex + dir * 4;
20772 if(this.vIndex < 0){
20776 if(this.vIndex > 11){
20780 if(isNaN(this.vIndex)){
20784 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20789 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20790 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20794 e.preventDefault();
20797 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20798 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20814 this.picker().remove();
20819 Roo.apply(Roo.bootstrap.MonthField, {
20838 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
20839 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
20844 Roo.apply(Roo.bootstrap.MonthField, {
20848 cls: 'datepicker dropdown-menu roo-dynamic',
20852 cls: 'datepicker-months',
20856 cls: 'table-condensed',
20858 Roo.bootstrap.DateField.content
20878 * @class Roo.bootstrap.CheckBox
20879 * @extends Roo.bootstrap.Input
20880 * Bootstrap CheckBox class
20882 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
20883 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
20884 * @cfg {String} boxLabel The text that appears beside the checkbox
20885 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
20886 * @cfg {Boolean} checked initnal the element
20887 * @cfg {Boolean} inline inline the element (default false)
20888 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
20889 * @cfg {String} tooltip label tooltip
20892 * Create a new CheckBox
20893 * @param {Object} config The config object
20896 Roo.bootstrap.CheckBox = function(config){
20897 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
20902 * Fires when the element is checked or unchecked.
20903 * @param {Roo.bootstrap.CheckBox} this This input
20904 * @param {Boolean} checked The new checked value
20909 * Fires when the element is click.
20910 * @param {Roo.bootstrap.CheckBox} this This input
20917 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
20919 inputType: 'checkbox',
20928 getAutoCreate : function()
20930 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20936 cfg.cls = 'form-group ' + this.inputType; //input-group
20939 cfg.cls += ' ' + this.inputType + '-inline';
20945 type : this.inputType,
20946 value : this.inputValue,
20947 cls : 'roo-' + this.inputType, //'form-box',
20948 placeholder : this.placeholder || ''
20952 if(this.inputType != 'radio'){
20956 cls : 'roo-hidden-value',
20957 value : this.checked ? this.inputValue : this.valueOff
20962 if (this.weight) { // Validity check?
20963 cfg.cls += " " + this.inputType + "-" + this.weight;
20966 if (this.disabled) {
20967 input.disabled=true;
20971 input.checked = this.checked;
20976 input.name = this.name;
20978 if(this.inputType != 'radio'){
20979 hidden.name = this.name;
20980 input.name = '_hidden_' + this.name;
20985 input.cls += ' input-' + this.size;
20990 ['xs','sm','md','lg'].map(function(size){
20991 if (settings[size]) {
20992 cfg.cls += ' col-' + size + '-' + settings[size];
20996 var inputblock = input;
20998 if (this.before || this.after) {
21001 cls : 'input-group',
21006 inputblock.cn.push({
21008 cls : 'input-group-addon',
21013 inputblock.cn.push(input);
21015 if(this.inputType != 'radio'){
21016 inputblock.cn.push(hidden);
21020 inputblock.cn.push({
21022 cls : 'input-group-addon',
21029 if (align ==='left' && this.fieldLabel.length) {
21030 // Roo.log("left and has label");
21035 cls : 'control-label',
21036 html : this.fieldLabel
21046 if(this.labelWidth > 12){
21047 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
21050 if(this.labelWidth < 13 && this.labelmd == 0){
21051 this.labelmd = this.labelWidth;
21054 if(this.labellg > 0){
21055 cfg.cn[0].cls += ' col-lg-' + this.labellg;
21056 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
21059 if(this.labelmd > 0){
21060 cfg.cn[0].cls += ' col-md-' + this.labelmd;
21061 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
21064 if(this.labelsm > 0){
21065 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
21066 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
21069 if(this.labelxs > 0){
21070 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
21071 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
21074 } else if ( this.fieldLabel.length) {
21075 // Roo.log(" label");
21079 tag: this.boxLabel ? 'span' : 'label',
21081 cls: 'control-label box-input-label',
21082 //cls : 'input-group-addon',
21083 html : this.fieldLabel
21092 // Roo.log(" no label && no align");
21093 cfg.cn = [ inputblock ] ;
21099 var boxLabelCfg = {
21101 //'for': id, // box label is handled by onclick - so no for...
21103 html: this.boxLabel
21107 boxLabelCfg.tooltip = this.tooltip;
21110 cfg.cn.push(boxLabelCfg);
21113 if(this.inputType != 'radio'){
21114 cfg.cn.push(hidden);
21122 * return the real input element.
21124 inputEl: function ()
21126 return this.el.select('input.roo-' + this.inputType,true).first();
21128 hiddenEl: function ()
21130 return this.el.select('input.roo-hidden-value',true).first();
21133 labelEl: function()
21135 return this.el.select('label.control-label',true).first();
21137 /* depricated... */
21141 return this.labelEl();
21144 boxLabelEl: function()
21146 return this.el.select('label.box-label',true).first();
21149 initEvents : function()
21151 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
21153 this.inputEl().on('click', this.onClick, this);
21155 if (this.boxLabel) {
21156 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
21159 this.startValue = this.getValue();
21162 Roo.bootstrap.CheckBox.register(this);
21166 onClick : function(e)
21168 if(this.fireEvent('click', this, e) !== false){
21169 this.setChecked(!this.checked);
21174 setChecked : function(state,suppressEvent)
21176 this.startValue = this.getValue();
21178 if(this.inputType == 'radio'){
21180 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21181 e.dom.checked = false;
21184 this.inputEl().dom.checked = true;
21186 this.inputEl().dom.value = this.inputValue;
21188 if(suppressEvent !== true){
21189 this.fireEvent('check', this, true);
21197 this.checked = state;
21199 this.inputEl().dom.checked = state;
21202 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
21204 if(suppressEvent !== true){
21205 this.fireEvent('check', this, state);
21211 getValue : function()
21213 if(this.inputType == 'radio'){
21214 return this.getGroupValue();
21217 return this.hiddenEl().dom.value;
21221 getGroupValue : function()
21223 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
21227 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
21230 setValue : function(v,suppressEvent)
21232 if(this.inputType == 'radio'){
21233 this.setGroupValue(v, suppressEvent);
21237 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
21242 setGroupValue : function(v, suppressEvent)
21244 this.startValue = this.getValue();
21246 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21247 e.dom.checked = false;
21249 if(e.dom.value == v){
21250 e.dom.checked = true;
21254 if(suppressEvent !== true){
21255 this.fireEvent('check', this, true);
21263 validate : function()
21265 if(this.getVisibilityEl().hasClass('hidden')){
21271 (this.inputType == 'radio' && this.validateRadio()) ||
21272 (this.inputType == 'checkbox' && this.validateCheckbox())
21278 this.markInvalid();
21282 validateRadio : function()
21284 if(this.getVisibilityEl().hasClass('hidden')){
21288 if(this.allowBlank){
21294 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21295 if(!e.dom.checked){
21307 validateCheckbox : function()
21310 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
21311 //return (this.getValue() == this.inputValue) ? true : false;
21314 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21322 for(var i in group){
21323 if(group[i].el.isVisible(true)){
21331 for(var i in group){
21336 r = (group[i].getValue() == group[i].inputValue) ? true : false;
21343 * Mark this field as valid
21345 markValid : function()
21349 this.fireEvent('valid', this);
21351 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21354 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
21361 if(this.inputType == 'radio'){
21362 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21363 var fg = e.findParent('.form-group', false, true);
21364 if (Roo.bootstrap.version == 3) {
21365 fg.removeClass([_this.invalidClass, _this.validClass]);
21366 fg.addClass(_this.validClass);
21368 fg.removeClass(['is-valid', 'is-invalid']);
21369 fg.addClass('is-valid');
21377 var fg = this.el.findParent('.form-group', false, true);
21378 if (Roo.bootstrap.version == 3) {
21379 fg.removeClass([this.invalidClass, this.validClass]);
21380 fg.addClass(this.validClass);
21382 fg.removeClass(['is-valid', 'is-invalid']);
21383 fg.addClass('is-valid');
21388 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21394 for(var i in group){
21395 var fg = group[i].el.findParent('.form-group', false, true);
21396 if (Roo.bootstrap.version == 3) {
21397 fg.removeClass([this.invalidClass, this.validClass]);
21398 fg.addClass(this.validClass);
21400 fg.removeClass(['is-valid', 'is-invalid']);
21401 fg.addClass('is-valid');
21407 * Mark this field as invalid
21408 * @param {String} msg The validation message
21410 markInvalid : function(msg)
21412 if(this.allowBlank){
21418 this.fireEvent('invalid', this, msg);
21420 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21423 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
21427 label.markInvalid();
21430 if(this.inputType == 'radio'){
21432 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21433 var fg = e.findParent('.form-group', false, true);
21434 if (Roo.bootstrap.version == 3) {
21435 fg.removeClass([_this.invalidClass, _this.validClass]);
21436 fg.addClass(_this.invalidClass);
21438 fg.removeClass(['is-invalid', 'is-valid']);
21439 fg.addClass('is-invalid');
21447 var fg = this.el.findParent('.form-group', false, true);
21448 if (Roo.bootstrap.version == 3) {
21449 fg.removeClass([_this.invalidClass, _this.validClass]);
21450 fg.addClass(_this.invalidClass);
21452 fg.removeClass(['is-invalid', 'is-valid']);
21453 fg.addClass('is-invalid');
21458 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21464 for(var i in group){
21465 var fg = group[i].el.findParent('.form-group', false, true);
21466 if (Roo.bootstrap.version == 3) {
21467 fg.removeClass([_this.invalidClass, _this.validClass]);
21468 fg.addClass(_this.invalidClass);
21470 fg.removeClass(['is-invalid', 'is-valid']);
21471 fg.addClass('is-invalid');
21477 clearInvalid : function()
21479 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
21481 // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21483 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21485 if (label && label.iconEl) {
21486 label.iconEl.removeClass([ label.validClass, label.invalidClass ]);
21487 label.iconEl.removeClass(['is-invalid', 'is-valid']);
21491 disable : function()
21493 if(this.inputType != 'radio'){
21494 Roo.bootstrap.CheckBox.superclass.disable.call(this);
21501 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21502 _this.getActionEl().addClass(this.disabledClass);
21503 e.dom.disabled = true;
21507 this.disabled = true;
21508 this.fireEvent("disable", this);
21512 enable : function()
21514 if(this.inputType != 'radio'){
21515 Roo.bootstrap.CheckBox.superclass.enable.call(this);
21522 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21523 _this.getActionEl().removeClass(this.disabledClass);
21524 e.dom.disabled = false;
21528 this.disabled = false;
21529 this.fireEvent("enable", this);
21533 setBoxLabel : function(v)
21538 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21544 Roo.apply(Roo.bootstrap.CheckBox, {
21549 * register a CheckBox Group
21550 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
21552 register : function(checkbox)
21554 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
21555 this.groups[checkbox.groupId] = {};
21558 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
21562 this.groups[checkbox.groupId][checkbox.name] = checkbox;
21566 * fetch a CheckBox Group based on the group ID
21567 * @param {string} the group ID
21568 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
21570 get: function(groupId) {
21571 if (typeof(this.groups[groupId]) == 'undefined') {
21575 return this.groups[groupId] ;
21588 * @class Roo.bootstrap.Radio
21589 * @extends Roo.bootstrap.Component
21590 * Bootstrap Radio class
21591 * @cfg {String} boxLabel - the label associated
21592 * @cfg {String} value - the value of radio
21595 * Create a new Radio
21596 * @param {Object} config The config object
21598 Roo.bootstrap.Radio = function(config){
21599 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
21603 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
21609 getAutoCreate : function()
21613 cls : 'form-group radio',
21618 html : this.boxLabel
21626 initEvents : function()
21628 this.parent().register(this);
21630 this.el.on('click', this.onClick, this);
21634 onClick : function(e)
21636 if(this.parent().fireEvent('click', this.parent(), this, e) !== false){
21637 this.setChecked(true);
21641 setChecked : function(state, suppressEvent)
21643 this.parent().setValue(this.value, suppressEvent);
21647 setBoxLabel : function(v)
21652 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21667 * @class Roo.bootstrap.SecurePass
21668 * @extends Roo.bootstrap.Input
21669 * Bootstrap SecurePass class
21673 * Create a new SecurePass
21674 * @param {Object} config The config object
21677 Roo.bootstrap.SecurePass = function (config) {
21678 // these go here, so the translation tool can replace them..
21680 PwdEmpty: "Please type a password, and then retype it to confirm.",
21681 PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21682 PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21683 PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21684 IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21685 FNInPwd: "Your password can't contain your first name. Please type a different password.",
21686 LNInPwd: "Your password can't contain your last name. Please type a different password.",
21687 TooWeak: "Your password is Too Weak."
21689 this.meterLabel = "Password strength:";
21690 this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
21691 this.meterClass = [
21692 "roo-password-meter-tooweak",
21693 "roo-password-meter-weak",
21694 "roo-password-meter-medium",
21695 "roo-password-meter-strong",
21696 "roo-password-meter-grey"
21701 Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
21704 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
21706 * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
21708 * PwdEmpty: "Please type a password, and then retype it to confirm.",
21709 * PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21710 * PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21711 * PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21712 * IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21713 * FNInPwd: "Your password can't contain your first name. Please type a different password.",
21714 * LNInPwd: "Your password can't contain your last name. Please type a different password."
21724 * @cfg {String/Object} Label for the strength meter (defaults to
21725 * 'Password strength:')
21730 * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
21731 * ['Weak', 'Medium', 'Strong'])
21734 pwdStrengths: false,
21747 initEvents: function ()
21749 Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
21751 if (this.el.is('input[type=password]') && Roo.isSafari) {
21752 this.el.on('keydown', this.SafariOnKeyDown, this);
21755 this.el.on('keyup', this.checkStrength, this, {buffer: 50});
21758 onRender: function (ct, position)
21760 Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
21761 this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
21762 this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
21764 this.trigger.createChild({
21769 cls: 'roo-password-meter-grey col-xs-12',
21772 //width: this.meterWidth + 'px'
21776 cls: 'roo-password-meter-text'
21782 if (this.hideTrigger) {
21783 this.trigger.setDisplayed(false);
21785 this.setSize(this.width || '', this.height || '');
21788 onDestroy: function ()
21790 if (this.trigger) {
21791 this.trigger.removeAllListeners();
21792 this.trigger.remove();
21795 this.wrap.remove();
21797 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
21800 checkStrength: function ()
21802 var pwd = this.inputEl().getValue();
21803 if (pwd == this._lastPwd) {
21808 if (this.ClientSideStrongPassword(pwd)) {
21810 } else if (this.ClientSideMediumPassword(pwd)) {
21812 } else if (this.ClientSideWeakPassword(pwd)) {
21818 Roo.log('strength1: ' + strength);
21820 //var pm = this.trigger.child('div/div/div').dom;
21821 var pm = this.trigger.child('div/div');
21822 pm.removeClass(this.meterClass);
21823 pm.addClass(this.meterClass[strength]);
21826 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21828 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21830 this._lastPwd = pwd;
21834 Roo.bootstrap.SecurePass.superclass.reset.call(this);
21836 this._lastPwd = '';
21838 var pm = this.trigger.child('div/div');
21839 pm.removeClass(this.meterClass);
21840 pm.addClass('roo-password-meter-grey');
21843 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21846 this.inputEl().dom.type='password';
21849 validateValue: function (value)
21852 if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
21855 if (value.length == 0) {
21856 if (this.allowBlank) {
21857 this.clearInvalid();
21861 this.markInvalid(this.errors.PwdEmpty);
21862 this.errorMsg = this.errors.PwdEmpty;
21870 if ('[\x21-\x7e]*'.match(value)) {
21871 this.markInvalid(this.errors.PwdBadChar);
21872 this.errorMsg = this.errors.PwdBadChar;
21875 if (value.length < 6) {
21876 this.markInvalid(this.errors.PwdShort);
21877 this.errorMsg = this.errors.PwdShort;
21880 if (value.length > 16) {
21881 this.markInvalid(this.errors.PwdLong);
21882 this.errorMsg = this.errors.PwdLong;
21886 if (this.ClientSideStrongPassword(value)) {
21888 } else if (this.ClientSideMediumPassword(value)) {
21890 } else if (this.ClientSideWeakPassword(value)) {
21897 if (strength < 2) {
21898 //this.markInvalid(this.errors.TooWeak);
21899 this.errorMsg = this.errors.TooWeak;
21904 console.log('strength2: ' + strength);
21906 //var pm = this.trigger.child('div/div/div').dom;
21908 var pm = this.trigger.child('div/div');
21909 pm.removeClass(this.meterClass);
21910 pm.addClass(this.meterClass[strength]);
21912 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21914 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21916 this.errorMsg = '';
21920 CharacterSetChecks: function (type)
21923 this.fResult = false;
21926 isctype: function (character, type)
21929 case this.kCapitalLetter:
21930 if (character >= 'A' && character <= 'Z') {
21935 case this.kSmallLetter:
21936 if (character >= 'a' && character <= 'z') {
21942 if (character >= '0' && character <= '9') {
21947 case this.kPunctuation:
21948 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
21959 IsLongEnough: function (pwd, size)
21961 return !(pwd == null || isNaN(size) || pwd.length < size);
21964 SpansEnoughCharacterSets: function (word, nb)
21966 if (!this.IsLongEnough(word, nb))
21971 var characterSetChecks = new Array(
21972 new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
21973 new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
21976 for (var index = 0; index < word.length; ++index) {
21977 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21978 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
21979 characterSetChecks[nCharSet].fResult = true;
21986 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21987 if (characterSetChecks[nCharSet].fResult) {
21992 if (nCharSets < nb) {
21998 ClientSideStrongPassword: function (pwd)
22000 return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
22003 ClientSideMediumPassword: function (pwd)
22005 return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
22008 ClientSideWeakPassword: function (pwd)
22010 return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
22013 })//<script type="text/javascript">
22016 * Based Ext JS Library 1.1.1
22017 * Copyright(c) 2006-2007, Ext JS, LLC.
22023 * @class Roo.HtmlEditorCore
22024 * @extends Roo.Component
22025 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
22027 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
22030 Roo.HtmlEditorCore = function(config){
22033 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
22038 * @event initialize
22039 * Fires when the editor is fully initialized (including the iframe)
22040 * @param {Roo.HtmlEditorCore} this
22045 * Fires when the editor is first receives the focus. Any insertion must wait
22046 * until after this event.
22047 * @param {Roo.HtmlEditorCore} this
22051 * @event beforesync
22052 * Fires before the textarea is updated with content from the editor iframe. Return false
22053 * to cancel the sync.
22054 * @param {Roo.HtmlEditorCore} this
22055 * @param {String} html
22059 * @event beforepush
22060 * Fires before the iframe editor is updated with content from the textarea. Return false
22061 * to cancel the push.
22062 * @param {Roo.HtmlEditorCore} this
22063 * @param {String} html
22068 * Fires when the textarea is updated with content from the editor iframe.
22069 * @param {Roo.HtmlEditorCore} this
22070 * @param {String} html
22075 * Fires when the iframe editor is updated with content from the textarea.
22076 * @param {Roo.HtmlEditorCore} this
22077 * @param {String} html
22082 * @event editorevent
22083 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
22084 * @param {Roo.HtmlEditorCore} this
22090 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
22092 // defaults : white / black...
22093 this.applyBlacklists();
22100 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
22104 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
22110 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
22115 * @cfg {Number} height (in pixels)
22119 * @cfg {Number} width (in pixels)
22124 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
22127 stylesheets: false,
22132 // private properties
22133 validationEvent : false,
22135 initialized : false,
22137 sourceEditMode : false,
22138 onFocus : Roo.emptyFn,
22140 hideMode:'offsets',
22144 // blacklist + whitelisted elements..
22151 * Protected method that will not generally be called directly. It
22152 * is called when the editor initializes the iframe with HTML contents. Override this method if you
22153 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
22155 getDocMarkup : function(){
22159 // inherit styels from page...??
22160 if (this.stylesheets === false) {
22162 Roo.get(document.head).select('style').each(function(node) {
22163 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
22166 Roo.get(document.head).select('link').each(function(node) {
22167 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
22170 } else if (!this.stylesheets.length) {
22172 st = '<style type="text/css">' +
22173 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
22176 st = '<style type="text/css">' +
22181 st += '<style type="text/css">' +
22182 'IMG { cursor: pointer } ' +
22185 var cls = 'roo-htmleditor-body';
22187 if(this.bodyCls.length){
22188 cls += ' ' + this.bodyCls;
22191 return '<html><head>' + st +
22192 //<style type="text/css">' +
22193 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
22195 ' </head><body class="' + cls + '"></body></html>';
22199 onRender : function(ct, position)
22202 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
22203 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
22206 this.el.dom.style.border = '0 none';
22207 this.el.dom.setAttribute('tabIndex', -1);
22208 this.el.addClass('x-hidden hide');
22212 if(Roo.isIE){ // fix IE 1px bogus margin
22213 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
22217 this.frameId = Roo.id();
22221 var iframe = this.owner.wrap.createChild({
22223 cls: 'form-control', // bootstrap..
22225 name: this.frameId,
22226 frameBorder : 'no',
22227 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
22232 this.iframe = iframe.dom;
22234 this.assignDocWin();
22236 this.doc.designMode = 'on';
22239 this.doc.write(this.getDocMarkup());
22243 var task = { // must defer to wait for browser to be ready
22245 //console.log("run task?" + this.doc.readyState);
22246 this.assignDocWin();
22247 if(this.doc.body || this.doc.readyState == 'complete'){
22249 this.doc.designMode="on";
22253 Roo.TaskMgr.stop(task);
22254 this.initEditor.defer(10, this);
22261 Roo.TaskMgr.start(task);
22266 onResize : function(w, h)
22268 Roo.log('resize: ' +w + ',' + h );
22269 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
22273 if(typeof w == 'number'){
22275 this.iframe.style.width = w + 'px';
22277 if(typeof h == 'number'){
22279 this.iframe.style.height = h + 'px';
22281 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
22288 * Toggles the editor between standard and source edit mode.
22289 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
22291 toggleSourceEdit : function(sourceEditMode){
22293 this.sourceEditMode = sourceEditMode === true;
22295 if(this.sourceEditMode){
22297 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
22300 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
22301 //this.iframe.className = '';
22304 //this.setSize(this.owner.wrap.getSize());
22305 //this.fireEvent('editmodechange', this, this.sourceEditMode);
22312 * Protected method that will not generally be called directly. If you need/want
22313 * custom HTML cleanup, this is the method you should override.
22314 * @param {String} html The HTML to be cleaned
22315 * return {String} The cleaned HTML
22317 cleanHtml : function(html){
22318 html = String(html);
22319 if(html.length > 5){
22320 if(Roo.isSafari){ // strip safari nonsense
22321 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
22324 if(html == ' '){
22331 * HTML Editor -> Textarea
22332 * Protected method that will not generally be called directly. Syncs the contents
22333 * of the editor iframe with the textarea.
22335 syncValue : function(){
22336 if(this.initialized){
22337 var bd = (this.doc.body || this.doc.documentElement);
22338 //this.cleanUpPaste(); -- this is done else where and causes havoc..
22339 var html = bd.innerHTML;
22341 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
22342 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
22344 html = '<div style="'+m[0]+'">' + html + '</div>';
22347 html = this.cleanHtml(html);
22348 // fix up the special chars.. normaly like back quotes in word...
22349 // however we do not want to do this with chinese..
22350 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
22351 var cc = b.charCodeAt();
22353 (cc >= 0x4E00 && cc < 0xA000 ) ||
22354 (cc >= 0x3400 && cc < 0x4E00 ) ||
22355 (cc >= 0xf900 && cc < 0xfb00 )
22361 if(this.owner.fireEvent('beforesync', this, html) !== false){
22362 this.el.dom.value = html;
22363 this.owner.fireEvent('sync', this, html);
22369 * Protected method that will not generally be called directly. Pushes the value of the textarea
22370 * into the iframe editor.
22372 pushValue : function(){
22373 if(this.initialized){
22374 var v = this.el.dom.value.trim();
22376 // if(v.length < 1){
22380 if(this.owner.fireEvent('beforepush', this, v) !== false){
22381 var d = (this.doc.body || this.doc.documentElement);
22383 this.cleanUpPaste();
22384 this.el.dom.value = d.innerHTML;
22385 this.owner.fireEvent('push', this, v);
22391 deferFocus : function(){
22392 this.focus.defer(10, this);
22396 focus : function(){
22397 if(this.win && !this.sourceEditMode){
22404 assignDocWin: function()
22406 var iframe = this.iframe;
22409 this.doc = iframe.contentWindow.document;
22410 this.win = iframe.contentWindow;
22412 // if (!Roo.get(this.frameId)) {
22415 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
22416 // this.win = Roo.get(this.frameId).dom.contentWindow;
22418 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
22422 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
22423 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
22428 initEditor : function(){
22429 //console.log("INIT EDITOR");
22430 this.assignDocWin();
22434 this.doc.designMode="on";
22436 this.doc.write(this.getDocMarkup());
22439 var dbody = (this.doc.body || this.doc.documentElement);
22440 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
22441 // this copies styles from the containing element into thsi one..
22442 // not sure why we need all of this..
22443 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
22445 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
22446 //ss['background-attachment'] = 'fixed'; // w3c
22447 dbody.bgProperties = 'fixed'; // ie
22448 //Roo.DomHelper.applyStyles(dbody, ss);
22449 Roo.EventManager.on(this.doc, {
22450 //'mousedown': this.onEditorEvent,
22451 'mouseup': this.onEditorEvent,
22452 'dblclick': this.onEditorEvent,
22453 'click': this.onEditorEvent,
22454 'keyup': this.onEditorEvent,
22459 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
22461 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
22462 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
22464 this.initialized = true;
22466 this.owner.fireEvent('initialize', this);
22471 onDestroy : function(){
22477 //for (var i =0; i < this.toolbars.length;i++) {
22478 // // fixme - ask toolbars for heights?
22479 // this.toolbars[i].onDestroy();
22482 //this.wrap.dom.innerHTML = '';
22483 //this.wrap.remove();
22488 onFirstFocus : function(){
22490 this.assignDocWin();
22493 this.activated = true;
22496 if(Roo.isGecko){ // prevent silly gecko errors
22498 var s = this.win.getSelection();
22499 if(!s.focusNode || s.focusNode.nodeType != 3){
22500 var r = s.getRangeAt(0);
22501 r.selectNodeContents((this.doc.body || this.doc.documentElement));
22506 this.execCmd('useCSS', true);
22507 this.execCmd('styleWithCSS', false);
22510 this.owner.fireEvent('activate', this);
22514 adjustFont: function(btn){
22515 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
22516 //if(Roo.isSafari){ // safari
22519 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
22520 if(Roo.isSafari){ // safari
22521 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
22522 v = (v < 10) ? 10 : v;
22523 v = (v > 48) ? 48 : v;
22524 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
22529 v = Math.max(1, v+adjust);
22531 this.execCmd('FontSize', v );
22534 onEditorEvent : function(e)
22536 this.owner.fireEvent('editorevent', this, e);
22537 // this.updateToolbar();
22538 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
22541 insertTag : function(tg)
22543 // could be a bit smarter... -> wrap the current selected tRoo..
22544 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
22546 range = this.createRange(this.getSelection());
22547 var wrappingNode = this.doc.createElement(tg.toLowerCase());
22548 wrappingNode.appendChild(range.extractContents());
22549 range.insertNode(wrappingNode);
22556 this.execCmd("formatblock", tg);
22560 insertText : function(txt)
22564 var range = this.createRange();
22565 range.deleteContents();
22566 //alert(Sender.getAttribute('label'));
22568 range.insertNode(this.doc.createTextNode(txt));
22574 * Executes a Midas editor command on the editor document and performs necessary focus and
22575 * toolbar updates. <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 relayCmd : function(cmd, value){
22581 this.execCmd(cmd, value);
22582 this.owner.fireEvent('editorevent', this);
22583 //this.updateToolbar();
22584 this.owner.deferFocus();
22588 * Executes a Midas editor command directly on the editor document.
22589 * For visual commands, you should use {@link #relayCmd} instead.
22590 * <b>This should only be called after the editor is initialized.</b>
22591 * @param {String} cmd The Midas command
22592 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22594 execCmd : function(cmd, value){
22595 this.doc.execCommand(cmd, false, value === undefined ? null : value);
22602 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
22604 * @param {String} text | dom node..
22606 insertAtCursor : function(text)
22609 if(!this.activated){
22615 var r = this.doc.selection.createRange();
22626 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
22630 // from jquery ui (MIT licenced)
22632 var win = this.win;
22634 if (win.getSelection && win.getSelection().getRangeAt) {
22635 range = win.getSelection().getRangeAt(0);
22636 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
22637 range.insertNode(node);
22638 } else if (win.document.selection && win.document.selection.createRange) {
22639 // no firefox support
22640 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22641 win.document.selection.createRange().pasteHTML(txt);
22643 // no firefox support
22644 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22645 this.execCmd('InsertHTML', txt);
22654 mozKeyPress : function(e){
22656 var c = e.getCharCode(), cmd;
22659 c = String.fromCharCode(c).toLowerCase();
22673 this.cleanUpPaste.defer(100, this);
22681 e.preventDefault();
22689 fixKeys : function(){ // load time branching for fastest keydown performance
22691 return function(e){
22692 var k = e.getKey(), r;
22695 r = this.doc.selection.createRange();
22698 r.pasteHTML('    ');
22705 r = this.doc.selection.createRange();
22707 var target = r.parentElement();
22708 if(!target || target.tagName.toLowerCase() != 'li'){
22710 r.pasteHTML('<br />');
22716 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22717 this.cleanUpPaste.defer(100, this);
22723 }else if(Roo.isOpera){
22724 return function(e){
22725 var k = e.getKey();
22729 this.execCmd('InsertHTML','    ');
22732 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22733 this.cleanUpPaste.defer(100, this);
22738 }else if(Roo.isSafari){
22739 return function(e){
22740 var k = e.getKey();
22744 this.execCmd('InsertText','\t');
22748 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22749 this.cleanUpPaste.defer(100, this);
22757 getAllAncestors: function()
22759 var p = this.getSelectedNode();
22762 a.push(p); // push blank onto stack..
22763 p = this.getParentElement();
22767 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
22771 a.push(this.doc.body);
22775 lastSelNode : false,
22778 getSelection : function()
22780 this.assignDocWin();
22781 return Roo.isIE ? this.doc.selection : this.win.getSelection();
22784 getSelectedNode: function()
22786 // this may only work on Gecko!!!
22788 // should we cache this!!!!
22793 var range = this.createRange(this.getSelection()).cloneRange();
22796 var parent = range.parentElement();
22798 var testRange = range.duplicate();
22799 testRange.moveToElementText(parent);
22800 if (testRange.inRange(range)) {
22803 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
22806 parent = parent.parentElement;
22811 // is ancestor a text element.
22812 var ac = range.commonAncestorContainer;
22813 if (ac.nodeType == 3) {
22814 ac = ac.parentNode;
22817 var ar = ac.childNodes;
22820 var other_nodes = [];
22821 var has_other_nodes = false;
22822 for (var i=0;i<ar.length;i++) {
22823 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
22826 // fullly contained node.
22828 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
22833 // probably selected..
22834 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
22835 other_nodes.push(ar[i]);
22839 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
22844 has_other_nodes = true;
22846 if (!nodes.length && other_nodes.length) {
22847 nodes= other_nodes;
22849 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
22855 createRange: function(sel)
22857 // this has strange effects when using with
22858 // top toolbar - not sure if it's a great idea.
22859 //this.editor.contentWindow.focus();
22860 if (typeof sel != "undefined") {
22862 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
22864 return this.doc.createRange();
22867 return this.doc.createRange();
22870 getParentElement: function()
22873 this.assignDocWin();
22874 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
22876 var range = this.createRange(sel);
22879 var p = range.commonAncestorContainer;
22880 while (p.nodeType == 3) { // text node
22891 * Range intersection.. the hard stuff...
22895 * [ -- selected range --- ]
22899 * if end is before start or hits it. fail.
22900 * if start is after end or hits it fail.
22902 * if either hits (but other is outside. - then it's not
22908 // @see http://www.thismuchiknow.co.uk/?p=64.
22909 rangeIntersectsNode : function(range, node)
22911 var nodeRange = node.ownerDocument.createRange();
22913 nodeRange.selectNode(node);
22915 nodeRange.selectNodeContents(node);
22918 var rangeStartRange = range.cloneRange();
22919 rangeStartRange.collapse(true);
22921 var rangeEndRange = range.cloneRange();
22922 rangeEndRange.collapse(false);
22924 var nodeStartRange = nodeRange.cloneRange();
22925 nodeStartRange.collapse(true);
22927 var nodeEndRange = nodeRange.cloneRange();
22928 nodeEndRange.collapse(false);
22930 return rangeStartRange.compareBoundaryPoints(
22931 Range.START_TO_START, nodeEndRange) == -1 &&
22932 rangeEndRange.compareBoundaryPoints(
22933 Range.START_TO_START, nodeStartRange) == 1;
22937 rangeCompareNode : function(range, node)
22939 var nodeRange = node.ownerDocument.createRange();
22941 nodeRange.selectNode(node);
22943 nodeRange.selectNodeContents(node);
22947 range.collapse(true);
22949 nodeRange.collapse(true);
22951 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
22952 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
22954 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
22956 var nodeIsBefore = ss == 1;
22957 var nodeIsAfter = ee == -1;
22959 if (nodeIsBefore && nodeIsAfter) {
22962 if (!nodeIsBefore && nodeIsAfter) {
22963 return 1; //right trailed.
22966 if (nodeIsBefore && !nodeIsAfter) {
22967 return 2; // left trailed.
22973 // private? - in a new class?
22974 cleanUpPaste : function()
22976 // cleans up the whole document..
22977 Roo.log('cleanuppaste');
22979 this.cleanUpChildren(this.doc.body);
22980 var clean = this.cleanWordChars(this.doc.body.innerHTML);
22981 if (clean != this.doc.body.innerHTML) {
22982 this.doc.body.innerHTML = clean;
22987 cleanWordChars : function(input) {// change the chars to hex code
22988 var he = Roo.HtmlEditorCore;
22990 var output = input;
22991 Roo.each(he.swapCodes, function(sw) {
22992 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
22994 output = output.replace(swapper, sw[1]);
23001 cleanUpChildren : function (n)
23003 if (!n.childNodes.length) {
23006 for (var i = n.childNodes.length-1; i > -1 ; i--) {
23007 this.cleanUpChild(n.childNodes[i]);
23014 cleanUpChild : function (node)
23017 //console.log(node);
23018 if (node.nodeName == "#text") {
23019 // clean up silly Windows -- stuff?
23022 if (node.nodeName == "#comment") {
23023 node.parentNode.removeChild(node);
23024 // clean up silly Windows -- stuff?
23027 var lcname = node.tagName.toLowerCase();
23028 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
23029 // whitelist of tags..
23031 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
23033 node.parentNode.removeChild(node);
23038 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
23040 // remove <a name=....> as rendering on yahoo mailer is borked with this.
23041 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
23043 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
23044 // remove_keep_children = true;
23047 if (remove_keep_children) {
23048 this.cleanUpChildren(node);
23049 // inserts everything just before this node...
23050 while (node.childNodes.length) {
23051 var cn = node.childNodes[0];
23052 node.removeChild(cn);
23053 node.parentNode.insertBefore(cn, node);
23055 node.parentNode.removeChild(node);
23059 if (!node.attributes || !node.attributes.length) {
23060 this.cleanUpChildren(node);
23064 function cleanAttr(n,v)
23067 if (v.match(/^\./) || v.match(/^\//)) {
23070 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/) || v.match(/^ftp:/)) {
23073 if (v.match(/^#/)) {
23076 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
23077 node.removeAttribute(n);
23081 var cwhite = this.cwhite;
23082 var cblack = this.cblack;
23084 function cleanStyle(n,v)
23086 if (v.match(/expression/)) { //XSS?? should we even bother..
23087 node.removeAttribute(n);
23091 var parts = v.split(/;/);
23094 Roo.each(parts, function(p) {
23095 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
23099 var l = p.split(':').shift().replace(/\s+/g,'');
23100 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
23102 if ( cwhite.length && cblack.indexOf(l) > -1) {
23103 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
23104 //node.removeAttribute(n);
23108 // only allow 'c whitelisted system attributes'
23109 if ( cwhite.length && cwhite.indexOf(l) < 0) {
23110 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
23111 //node.removeAttribute(n);
23121 if (clean.length) {
23122 node.setAttribute(n, clean.join(';'));
23124 node.removeAttribute(n);
23130 for (var i = node.attributes.length-1; i > -1 ; i--) {
23131 var a = node.attributes[i];
23134 if (a.name.toLowerCase().substr(0,2)=='on') {
23135 node.removeAttribute(a.name);
23138 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
23139 node.removeAttribute(a.name);
23142 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
23143 cleanAttr(a.name,a.value); // fixme..
23146 if (a.name == 'style') {
23147 cleanStyle(a.name,a.value);
23150 /// clean up MS crap..
23151 // tecnically this should be a list of valid class'es..
23154 if (a.name == 'class') {
23155 if (a.value.match(/^Mso/)) {
23156 node.className = '';
23159 if (a.value.match(/^body$/)) {
23160 node.className = '';
23171 this.cleanUpChildren(node);
23177 * Clean up MS wordisms...
23179 cleanWord : function(node)
23184 this.cleanWord(this.doc.body);
23187 if (node.nodeName == "#text") {
23188 // clean up silly Windows -- stuff?
23191 if (node.nodeName == "#comment") {
23192 node.parentNode.removeChild(node);
23193 // clean up silly Windows -- stuff?
23197 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
23198 node.parentNode.removeChild(node);
23202 // remove - but keep children..
23203 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
23204 while (node.childNodes.length) {
23205 var cn = node.childNodes[0];
23206 node.removeChild(cn);
23207 node.parentNode.insertBefore(cn, node);
23209 node.parentNode.removeChild(node);
23210 this.iterateChildren(node, this.cleanWord);
23214 if (node.className.length) {
23216 var cn = node.className.split(/\W+/);
23218 Roo.each(cn, function(cls) {
23219 if (cls.match(/Mso[a-zA-Z]+/)) {
23224 node.className = cna.length ? cna.join(' ') : '';
23226 node.removeAttribute("class");
23230 if (node.hasAttribute("lang")) {
23231 node.removeAttribute("lang");
23234 if (node.hasAttribute("style")) {
23236 var styles = node.getAttribute("style").split(";");
23238 Roo.each(styles, function(s) {
23239 if (!s.match(/:/)) {
23242 var kv = s.split(":");
23243 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
23246 // what ever is left... we allow.
23249 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
23250 if (!nstyle.length) {
23251 node.removeAttribute('style');
23254 this.iterateChildren(node, this.cleanWord);
23260 * iterateChildren of a Node, calling fn each time, using this as the scole..
23261 * @param {DomNode} node node to iterate children of.
23262 * @param {Function} fn method of this class to call on each item.
23264 iterateChildren : function(node, fn)
23266 if (!node.childNodes.length) {
23269 for (var i = node.childNodes.length-1; i > -1 ; i--) {
23270 fn.call(this, node.childNodes[i])
23276 * cleanTableWidths.
23278 * Quite often pasting from word etc.. results in tables with column and widths.
23279 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
23282 cleanTableWidths : function(node)
23287 this.cleanTableWidths(this.doc.body);
23292 if (node.nodeName == "#text" || node.nodeName == "#comment") {
23295 Roo.log(node.tagName);
23296 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
23297 this.iterateChildren(node, this.cleanTableWidths);
23300 if (node.hasAttribute('width')) {
23301 node.removeAttribute('width');
23305 if (node.hasAttribute("style")) {
23308 var styles = node.getAttribute("style").split(";");
23310 Roo.each(styles, function(s) {
23311 if (!s.match(/:/)) {
23314 var kv = s.split(":");
23315 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
23318 // what ever is left... we allow.
23321 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
23322 if (!nstyle.length) {
23323 node.removeAttribute('style');
23327 this.iterateChildren(node, this.cleanTableWidths);
23335 domToHTML : function(currentElement, depth, nopadtext) {
23337 depth = depth || 0;
23338 nopadtext = nopadtext || false;
23340 if (!currentElement) {
23341 return this.domToHTML(this.doc.body);
23344 //Roo.log(currentElement);
23346 var allText = false;
23347 var nodeName = currentElement.nodeName;
23348 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
23350 if (nodeName == '#text') {
23352 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
23357 if (nodeName != 'BODY') {
23360 // Prints the node tagName, such as <A>, <IMG>, etc
23363 for(i = 0; i < currentElement.attributes.length;i++) {
23365 var aname = currentElement.attributes.item(i).name;
23366 if (!currentElement.attributes.item(i).value.length) {
23369 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
23372 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
23381 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
23384 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
23389 // Traverse the tree
23391 var currentElementChild = currentElement.childNodes.item(i);
23392 var allText = true;
23393 var innerHTML = '';
23395 while (currentElementChild) {
23396 // Formatting code (indent the tree so it looks nice on the screen)
23397 var nopad = nopadtext;
23398 if (lastnode == 'SPAN') {
23402 if (currentElementChild.nodeName == '#text') {
23403 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
23404 toadd = nopadtext ? toadd : toadd.trim();
23405 if (!nopad && toadd.length > 80) {
23406 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
23408 innerHTML += toadd;
23411 currentElementChild = currentElement.childNodes.item(i);
23417 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
23419 // Recursively traverse the tree structure of the child node
23420 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
23421 lastnode = currentElementChild.nodeName;
23423 currentElementChild=currentElement.childNodes.item(i);
23429 // The remaining code is mostly for formatting the tree
23430 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
23435 ret+= "</"+tagName+">";
23441 applyBlacklists : function()
23443 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
23444 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
23448 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
23449 if (b.indexOf(tag) > -1) {
23452 this.white.push(tag);
23456 Roo.each(w, function(tag) {
23457 if (b.indexOf(tag) > -1) {
23460 if (this.white.indexOf(tag) > -1) {
23463 this.white.push(tag);
23468 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
23469 if (w.indexOf(tag) > -1) {
23472 this.black.push(tag);
23476 Roo.each(b, function(tag) {
23477 if (w.indexOf(tag) > -1) {
23480 if (this.black.indexOf(tag) > -1) {
23483 this.black.push(tag);
23488 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
23489 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
23493 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
23494 if (b.indexOf(tag) > -1) {
23497 this.cwhite.push(tag);
23501 Roo.each(w, function(tag) {
23502 if (b.indexOf(tag) > -1) {
23505 if (this.cwhite.indexOf(tag) > -1) {
23508 this.cwhite.push(tag);
23513 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
23514 if (w.indexOf(tag) > -1) {
23517 this.cblack.push(tag);
23521 Roo.each(b, function(tag) {
23522 if (w.indexOf(tag) > -1) {
23525 if (this.cblack.indexOf(tag) > -1) {
23528 this.cblack.push(tag);
23533 setStylesheets : function(stylesheets)
23535 if(typeof(stylesheets) == 'string'){
23536 Roo.get(this.iframe.contentDocument.head).createChild({
23538 rel : 'stylesheet',
23547 Roo.each(stylesheets, function(s) {
23552 Roo.get(_this.iframe.contentDocument.head).createChild({
23554 rel : 'stylesheet',
23563 removeStylesheets : function()
23567 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
23572 setStyle : function(style)
23574 Roo.get(this.iframe.contentDocument.head).createChild({
23583 // hide stuff that is not compatible
23597 * @event specialkey
23601 * @cfg {String} fieldClass @hide
23604 * @cfg {String} focusClass @hide
23607 * @cfg {String} autoCreate @hide
23610 * @cfg {String} inputType @hide
23613 * @cfg {String} invalidClass @hide
23616 * @cfg {String} invalidText @hide
23619 * @cfg {String} msgFx @hide
23622 * @cfg {String} validateOnBlur @hide
23626 Roo.HtmlEditorCore.white = [
23627 'area', 'br', 'img', 'input', 'hr', 'wbr',
23629 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
23630 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
23631 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
23632 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
23633 'table', 'ul', 'xmp',
23635 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
23638 'dir', 'menu', 'ol', 'ul', 'dl',
23644 Roo.HtmlEditorCore.black = [
23645 // 'embed', 'object', // enable - backend responsiblity to clean thiese
23647 'base', 'basefont', 'bgsound', 'blink', 'body',
23648 'frame', 'frameset', 'head', 'html', 'ilayer',
23649 'iframe', 'layer', 'link', 'meta', 'object',
23650 'script', 'style' ,'title', 'xml' // clean later..
23652 Roo.HtmlEditorCore.clean = [
23653 'script', 'style', 'title', 'xml'
23655 Roo.HtmlEditorCore.remove = [
23660 Roo.HtmlEditorCore.ablack = [
23664 Roo.HtmlEditorCore.aclean = [
23665 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
23669 Roo.HtmlEditorCore.pwhite= [
23670 'http', 'https', 'mailto'
23673 // white listed style attributes.
23674 Roo.HtmlEditorCore.cwhite= [
23675 // 'text-align', /// default is to allow most things..
23681 // black listed style attributes.
23682 Roo.HtmlEditorCore.cblack= [
23683 // 'font-size' -- this can be set by the project
23687 Roo.HtmlEditorCore.swapCodes =[
23706 * @class Roo.bootstrap.HtmlEditor
23707 * @extends Roo.bootstrap.TextArea
23708 * Bootstrap HtmlEditor class
23711 * Create a new HtmlEditor
23712 * @param {Object} config The config object
23715 Roo.bootstrap.HtmlEditor = function(config){
23716 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
23717 if (!this.toolbars) {
23718 this.toolbars = [];
23721 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
23724 * @event initialize
23725 * Fires when the editor is fully initialized (including the iframe)
23726 * @param {HtmlEditor} this
23731 * Fires when the editor is first receives the focus. Any insertion must wait
23732 * until after this event.
23733 * @param {HtmlEditor} this
23737 * @event beforesync
23738 * Fires before the textarea is updated with content from the editor iframe. Return false
23739 * to cancel the sync.
23740 * @param {HtmlEditor} this
23741 * @param {String} html
23745 * @event beforepush
23746 * Fires before the iframe editor is updated with content from the textarea. Return false
23747 * to cancel the push.
23748 * @param {HtmlEditor} this
23749 * @param {String} html
23754 * Fires when the textarea is updated with content from the editor iframe.
23755 * @param {HtmlEditor} this
23756 * @param {String} html
23761 * Fires when the iframe editor is updated with content from the textarea.
23762 * @param {HtmlEditor} this
23763 * @param {String} html
23767 * @event editmodechange
23768 * Fires when the editor switches edit modes
23769 * @param {HtmlEditor} this
23770 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
23772 editmodechange: true,
23774 * @event editorevent
23775 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
23776 * @param {HtmlEditor} this
23780 * @event firstfocus
23781 * Fires when on first focus - needed by toolbars..
23782 * @param {HtmlEditor} this
23787 * Auto save the htmlEditor value as a file into Events
23788 * @param {HtmlEditor} this
23792 * @event savedpreview
23793 * preview the saved version of htmlEditor
23794 * @param {HtmlEditor} this
23801 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
23805 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
23810 * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
23815 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
23820 * @cfg {Number} height (in pixels)
23824 * @cfg {Number} width (in pixels)
23829 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
23832 stylesheets: false,
23837 // private properties
23838 validationEvent : false,
23840 initialized : false,
23843 onFocus : Roo.emptyFn,
23845 hideMode:'offsets',
23847 tbContainer : false,
23851 toolbarContainer :function() {
23852 return this.wrap.select('.x-html-editor-tb',true).first();
23856 * Protected method that will not generally be called directly. It
23857 * is called when the editor creates its toolbar. Override this method if you need to
23858 * add custom toolbar buttons.
23859 * @param {HtmlEditor} editor
23861 createToolbar : function(){
23862 Roo.log('renewing');
23863 Roo.log("create toolbars");
23865 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
23866 this.toolbars[0].render(this.toolbarContainer());
23870 // if (!editor.toolbars || !editor.toolbars.length) {
23871 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
23874 // for (var i =0 ; i < editor.toolbars.length;i++) {
23875 // editor.toolbars[i] = Roo.factory(
23876 // typeof(editor.toolbars[i]) == 'string' ?
23877 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
23878 // Roo.bootstrap.HtmlEditor);
23879 // editor.toolbars[i].init(editor);
23885 onRender : function(ct, position)
23887 // Roo.log("Call onRender: " + this.xtype);
23889 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
23891 this.wrap = this.inputEl().wrap({
23892 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
23895 this.editorcore.onRender(ct, position);
23897 if (this.resizable) {
23898 this.resizeEl = new Roo.Resizable(this.wrap, {
23902 minHeight : this.height,
23903 height: this.height,
23904 handles : this.resizable,
23907 resize : function(r, w, h) {
23908 _t.onResize(w,h); // -something
23914 this.createToolbar(this);
23917 if(!this.width && this.resizable){
23918 this.setSize(this.wrap.getSize());
23920 if (this.resizeEl) {
23921 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
23922 // should trigger onReize..
23928 onResize : function(w, h)
23930 Roo.log('resize: ' +w + ',' + h );
23931 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
23935 if(this.inputEl() ){
23936 if(typeof w == 'number'){
23937 var aw = w - this.wrap.getFrameWidth('lr');
23938 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
23941 if(typeof h == 'number'){
23942 var tbh = -11; // fixme it needs to tool bar size!
23943 for (var i =0; i < this.toolbars.length;i++) {
23944 // fixme - ask toolbars for heights?
23945 tbh += this.toolbars[i].el.getHeight();
23946 //if (this.toolbars[i].footer) {
23947 // tbh += this.toolbars[i].footer.el.getHeight();
23955 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
23956 ah -= 5; // knock a few pixes off for look..
23957 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
23961 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
23962 this.editorcore.onResize(ew,eh);
23967 * Toggles the editor between standard and source edit mode.
23968 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
23970 toggleSourceEdit : function(sourceEditMode)
23972 this.editorcore.toggleSourceEdit(sourceEditMode);
23974 if(this.editorcore.sourceEditMode){
23975 Roo.log('editor - showing textarea');
23978 // Roo.log(this.syncValue());
23980 this.inputEl().removeClass(['hide', 'x-hidden']);
23981 this.inputEl().dom.removeAttribute('tabIndex');
23982 this.inputEl().focus();
23984 Roo.log('editor - hiding textarea');
23986 // Roo.log(this.pushValue());
23989 this.inputEl().addClass(['hide', 'x-hidden']);
23990 this.inputEl().dom.setAttribute('tabIndex', -1);
23991 //this.deferFocus();
23994 if(this.resizable){
23995 this.setSize(this.wrap.getSize());
23998 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
24001 // private (for BoxComponent)
24002 adjustSize : Roo.BoxComponent.prototype.adjustSize,
24004 // private (for BoxComponent)
24005 getResizeEl : function(){
24009 // private (for BoxComponent)
24010 getPositionEl : function(){
24015 initEvents : function(){
24016 this.originalValue = this.getValue();
24020 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
24023 // markInvalid : Roo.emptyFn,
24025 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
24028 // clearInvalid : Roo.emptyFn,
24030 setValue : function(v){
24031 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
24032 this.editorcore.pushValue();
24037 deferFocus : function(){
24038 this.focus.defer(10, this);
24042 focus : function(){
24043 this.editorcore.focus();
24049 onDestroy : function(){
24055 for (var i =0; i < this.toolbars.length;i++) {
24056 // fixme - ask toolbars for heights?
24057 this.toolbars[i].onDestroy();
24060 this.wrap.dom.innerHTML = '';
24061 this.wrap.remove();
24066 onFirstFocus : function(){
24067 //Roo.log("onFirstFocus");
24068 this.editorcore.onFirstFocus();
24069 for (var i =0; i < this.toolbars.length;i++) {
24070 this.toolbars[i].onFirstFocus();
24076 syncValue : function()
24078 this.editorcore.syncValue();
24081 pushValue : function()
24083 this.editorcore.pushValue();
24087 // hide stuff that is not compatible
24101 * @event specialkey
24105 * @cfg {String} fieldClass @hide
24108 * @cfg {String} focusClass @hide
24111 * @cfg {String} autoCreate @hide
24114 * @cfg {String} inputType @hide
24118 * @cfg {String} invalidText @hide
24121 * @cfg {String} msgFx @hide
24124 * @cfg {String} validateOnBlur @hide
24133 Roo.namespace('Roo.bootstrap.htmleditor');
24135 * @class Roo.bootstrap.HtmlEditorToolbar1
24141 new Roo.bootstrap.HtmlEditor({
24144 new Roo.bootstrap.HtmlEditorToolbar1({
24145 disable : { fonts: 1 , format: 1, ..., ... , ...],
24151 * @cfg {Object} disable List of elements to disable..
24152 * @cfg {Array} btns List of additional buttons.
24156 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
24159 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
24162 Roo.apply(this, config);
24164 // default disabled, based on 'good practice'..
24165 this.disable = this.disable || {};
24166 Roo.applyIf(this.disable, {
24169 specialElements : true
24171 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
24173 this.editor = config.editor;
24174 this.editorcore = config.editor.editorcore;
24176 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
24178 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
24179 // dont call parent... till later.
24181 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
24186 editorcore : false,
24191 "h1","h2","h3","h4","h5","h6",
24193 "abbr", "acronym", "address", "cite", "samp", "var",
24197 onRender : function(ct, position)
24199 // Roo.log("Call onRender: " + this.xtype);
24201 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
24203 this.el.dom.style.marginBottom = '0';
24205 var editorcore = this.editorcore;
24206 var editor= this.editor;
24209 var btn = function(id,cmd , toggle, handler, html){
24211 var event = toggle ? 'toggle' : 'click';
24216 xns: Roo.bootstrap,
24220 enableToggle:toggle !== false,
24222 pressed : toggle ? false : null,
24225 a.listeners[toggle ? 'toggle' : 'click'] = function() {
24226 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
24232 // var cb_box = function...
24237 xns: Roo.bootstrap,
24242 xns: Roo.bootstrap,
24246 Roo.each(this.formats, function(f) {
24247 style.menu.items.push({
24249 xns: Roo.bootstrap,
24250 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
24255 editorcore.insertTag(this.tagname);
24262 children.push(style);
24264 btn('bold',false,true);
24265 btn('italic',false,true);
24266 btn('align-left', 'justifyleft',true);
24267 btn('align-center', 'justifycenter',true);
24268 btn('align-right' , 'justifyright',true);
24269 btn('link', false, false, function(btn) {
24270 //Roo.log("create link?");
24271 var url = prompt(this.createLinkText, this.defaultLinkValue);
24272 if(url && url != 'http:/'+'/'){
24273 this.editorcore.relayCmd('createlink', url);
24276 btn('list','insertunorderedlist',true);
24277 btn('pencil', false,true, function(btn){
24279 this.toggleSourceEdit(btn.pressed);
24282 if (this.editor.btns.length > 0) {
24283 for (var i = 0; i<this.editor.btns.length; i++) {
24284 children.push(this.editor.btns[i]);
24292 xns: Roo.bootstrap,
24297 xns: Roo.bootstrap,
24302 cog.menu.items.push({
24304 xns: Roo.bootstrap,
24305 html : Clean styles,
24310 editorcore.insertTag(this.tagname);
24319 this.xtype = 'NavSimplebar';
24321 for(var i=0;i< children.length;i++) {
24323 this.buttons.add(this.addxtypeChild(children[i]));
24327 editor.on('editorevent', this.updateToolbar, this);
24329 onBtnClick : function(id)
24331 this.editorcore.relayCmd(id);
24332 this.editorcore.focus();
24336 * Protected method that will not generally be called directly. It triggers
24337 * a toolbar update by reading the markup state of the current selection in the editor.
24339 updateToolbar: function(){
24341 if(!this.editorcore.activated){
24342 this.editor.onFirstFocus(); // is this neeed?
24346 var btns = this.buttons;
24347 var doc = this.editorcore.doc;
24348 btns.get('bold').setActive(doc.queryCommandState('bold'));
24349 btns.get('italic').setActive(doc.queryCommandState('italic'));
24350 //btns.get('underline').setActive(doc.queryCommandState('underline'));
24352 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
24353 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
24354 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
24356 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
24357 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
24360 var ans = this.editorcore.getAllAncestors();
24361 if (this.formatCombo) {
24364 var store = this.formatCombo.store;
24365 this.formatCombo.setValue("");
24366 for (var i =0; i < ans.length;i++) {
24367 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
24369 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
24377 // hides menus... - so this cant be on a menu...
24378 Roo.bootstrap.MenuMgr.hideAll();
24380 Roo.bootstrap.MenuMgr.hideAll();
24381 //this.editorsyncValue();
24383 onFirstFocus: function() {
24384 this.buttons.each(function(item){
24388 toggleSourceEdit : function(sourceEditMode){
24391 if(sourceEditMode){
24392 Roo.log("disabling buttons");
24393 this.buttons.each( function(item){
24394 if(item.cmd != 'pencil'){
24400 Roo.log("enabling buttons");
24401 if(this.editorcore.initialized){
24402 this.buttons.each( function(item){
24408 Roo.log("calling toggole on editor");
24409 // tell the editor that it's been pressed..
24410 this.editor.toggleSourceEdit(sourceEditMode);
24420 * @class Roo.bootstrap.Table.AbstractSelectionModel
24421 * @extends Roo.util.Observable
24422 * Abstract base class for grid SelectionModels. It provides the interface that should be
24423 * implemented by descendant classes. This class should not be directly instantiated.
24426 Roo.bootstrap.Table.AbstractSelectionModel = function(){
24427 this.locked = false;
24428 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
24432 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
24433 /** @ignore Called by the grid automatically. Do not call directly. */
24434 init : function(grid){
24440 * Locks the selections.
24443 this.locked = true;
24447 * Unlocks the selections.
24449 unlock : function(){
24450 this.locked = false;
24454 * Returns true if the selections are locked.
24455 * @return {Boolean}
24457 isLocked : function(){
24458 return this.locked;
24462 * @extends Roo.bootstrap.Table.AbstractSelectionModel
24463 * @class Roo.bootstrap.Table.RowSelectionModel
24464 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
24465 * It supports multiple selections and keyboard selection/navigation.
24467 * @param {Object} config
24470 Roo.bootstrap.Table.RowSelectionModel = function(config){
24471 Roo.apply(this, config);
24472 this.selections = new Roo.util.MixedCollection(false, function(o){
24477 this.lastActive = false;
24481 * @event selectionchange
24482 * Fires when the selection changes
24483 * @param {SelectionModel} this
24485 "selectionchange" : true,
24487 * @event afterselectionchange
24488 * Fires after the selection changes (eg. by key press or clicking)
24489 * @param {SelectionModel} this
24491 "afterselectionchange" : true,
24493 * @event beforerowselect
24494 * Fires when a row is selected being selected, return false to cancel.
24495 * @param {SelectionModel} this
24496 * @param {Number} rowIndex The selected index
24497 * @param {Boolean} keepExisting False if other selections will be cleared
24499 "beforerowselect" : true,
24502 * Fires when a row is selected.
24503 * @param {SelectionModel} this
24504 * @param {Number} rowIndex The selected index
24505 * @param {Roo.data.Record} r The record
24507 "rowselect" : true,
24509 * @event rowdeselect
24510 * Fires when a row is deselected.
24511 * @param {SelectionModel} this
24512 * @param {Number} rowIndex The selected index
24514 "rowdeselect" : true
24516 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
24517 this.locked = false;
24520 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
24522 * @cfg {Boolean} singleSelect
24523 * True to allow selection of only one row at a time (defaults to false)
24525 singleSelect : false,
24528 initEvents : function()
24531 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
24532 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
24533 //}else{ // allow click to work like normal
24534 // this.grid.on("rowclick", this.handleDragableRowClick, this);
24536 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
24537 this.grid.on("rowclick", this.handleMouseDown, this);
24539 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
24540 "up" : function(e){
24542 this.selectPrevious(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);
24555 "down" : function(e){
24557 this.selectNext(e.shiftKey);
24558 }else if(this.last !== false && this.lastActive !== false){
24559 var last = this.last;
24560 this.selectRange(this.last, this.lastActive+1);
24561 this.grid.getView().focusRow(this.lastActive);
24562 if(last !== false){
24566 this.selectFirstRow();
24568 this.fireEvent("afterselectionchange", this);
24572 this.grid.store.on('load', function(){
24573 this.selections.clear();
24576 var view = this.grid.view;
24577 view.on("refresh", this.onRefresh, this);
24578 view.on("rowupdated", this.onRowUpdated, this);
24579 view.on("rowremoved", this.onRemove, this);
24584 onRefresh : function()
24586 var ds = this.grid.store, i, v = this.grid.view;
24587 var s = this.selections;
24588 s.each(function(r){
24589 if((i = ds.indexOfId(r.id)) != -1){
24598 onRemove : function(v, index, r){
24599 this.selections.remove(r);
24603 onRowUpdated : function(v, index, r){
24604 if(this.isSelected(r)){
24605 v.onRowSelect(index);
24611 * @param {Array} records The records to select
24612 * @param {Boolean} keepExisting (optional) True to keep existing selections
24614 selectRecords : function(records, keepExisting)
24617 this.clearSelections();
24619 var ds = this.grid.store;
24620 for(var i = 0, len = records.length; i < len; i++){
24621 this.selectRow(ds.indexOf(records[i]), true);
24626 * Gets the number of selected rows.
24629 getCount : function(){
24630 return this.selections.length;
24634 * Selects the first row in the grid.
24636 selectFirstRow : function(){
24641 * Select the last row.
24642 * @param {Boolean} keepExisting (optional) True to keep existing selections
24644 selectLastRow : function(keepExisting){
24645 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
24646 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
24650 * Selects the row immediately following the last selected row.
24651 * @param {Boolean} keepExisting (optional) True to keep existing selections
24653 selectNext : function(keepExisting)
24655 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
24656 this.selectRow(this.last+1, keepExisting);
24657 this.grid.getView().focusRow(this.last);
24662 * Selects the row that precedes the last selected row.
24663 * @param {Boolean} keepExisting (optional) True to keep existing selections
24665 selectPrevious : function(keepExisting){
24667 this.selectRow(this.last-1, keepExisting);
24668 this.grid.getView().focusRow(this.last);
24673 * Returns the selected records
24674 * @return {Array} Array of selected records
24676 getSelections : function(){
24677 return [].concat(this.selections.items);
24681 * Returns the first selected record.
24684 getSelected : function(){
24685 return this.selections.itemAt(0);
24690 * Clears all selections.
24692 clearSelections : function(fast)
24698 var ds = this.grid.store;
24699 var s = this.selections;
24700 s.each(function(r){
24701 this.deselectRow(ds.indexOfId(r.id));
24705 this.selections.clear();
24712 * Selects all rows.
24714 selectAll : function(){
24718 this.selections.clear();
24719 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
24720 this.selectRow(i, true);
24725 * Returns True if there is a selection.
24726 * @return {Boolean}
24728 hasSelection : function(){
24729 return this.selections.length > 0;
24733 * Returns True if the specified row is selected.
24734 * @param {Number/Record} record The record or index of the record to check
24735 * @return {Boolean}
24737 isSelected : function(index){
24738 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
24739 return (r && this.selections.key(r.id) ? true : false);
24743 * Returns True if the specified record id is selected.
24744 * @param {String} id The id of record to check
24745 * @return {Boolean}
24747 isIdSelected : function(id){
24748 return (this.selections.key(id) ? true : false);
24753 handleMouseDBClick : function(e, t){
24757 handleMouseDown : function(e, t)
24759 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
24760 if(this.isLocked() || rowIndex < 0 ){
24763 if(e.shiftKey && this.last !== false){
24764 var last = this.last;
24765 this.selectRange(last, rowIndex, e.ctrlKey);
24766 this.last = last; // reset the last
24770 var isSelected = this.isSelected(rowIndex);
24771 //Roo.log("select row:" + rowIndex);
24773 this.deselectRow(rowIndex);
24775 this.selectRow(rowIndex, true);
24779 if(e.button !== 0 && isSelected){
24780 alert('rowIndex 2: ' + rowIndex);
24781 view.focusRow(rowIndex);
24782 }else if(e.ctrlKey && isSelected){
24783 this.deselectRow(rowIndex);
24784 }else if(!isSelected){
24785 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
24786 view.focusRow(rowIndex);
24790 this.fireEvent("afterselectionchange", this);
24793 handleDragableRowClick : function(grid, rowIndex, e)
24795 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
24796 this.selectRow(rowIndex, false);
24797 grid.view.focusRow(rowIndex);
24798 this.fireEvent("afterselectionchange", this);
24803 * Selects multiple rows.
24804 * @param {Array} rows Array of the indexes of the row to select
24805 * @param {Boolean} keepExisting (optional) True to keep existing selections
24807 selectRows : function(rows, keepExisting){
24809 this.clearSelections();
24811 for(var i = 0, len = rows.length; i < len; i++){
24812 this.selectRow(rows[i], true);
24817 * Selects a range of rows. All rows in between startRow and endRow are also selected.
24818 * @param {Number} startRow The index of the first row in the range
24819 * @param {Number} endRow The index of the last row in the range
24820 * @param {Boolean} keepExisting (optional) True to retain existing selections
24822 selectRange : function(startRow, endRow, keepExisting){
24827 this.clearSelections();
24829 if(startRow <= endRow){
24830 for(var i = startRow; i <= endRow; i++){
24831 this.selectRow(i, true);
24834 for(var i = startRow; i >= endRow; i--){
24835 this.selectRow(i, true);
24841 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
24842 * @param {Number} startRow The index of the first row in the range
24843 * @param {Number} endRow The index of the last row in the range
24845 deselectRange : function(startRow, endRow, preventViewNotify){
24849 for(var i = startRow; i <= endRow; i++){
24850 this.deselectRow(i, preventViewNotify);
24856 * @param {Number} row The index of the row to select
24857 * @param {Boolean} keepExisting (optional) True to keep existing selections
24859 selectRow : function(index, keepExisting, preventViewNotify)
24861 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
24864 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
24865 if(!keepExisting || this.singleSelect){
24866 this.clearSelections();
24869 var r = this.grid.store.getAt(index);
24870 //console.log('selectRow - record id :' + r.id);
24872 this.selections.add(r);
24873 this.last = this.lastActive = index;
24874 if(!preventViewNotify){
24875 var proxy = new Roo.Element(
24876 this.grid.getRowDom(index)
24878 proxy.addClass('bg-info info');
24880 this.fireEvent("rowselect", this, index, r);
24881 this.fireEvent("selectionchange", this);
24887 * @param {Number} row The index of the row to deselect
24889 deselectRow : function(index, preventViewNotify)
24894 if(this.last == index){
24897 if(this.lastActive == index){
24898 this.lastActive = false;
24901 var r = this.grid.store.getAt(index);
24906 this.selections.remove(r);
24907 //.console.log('deselectRow - record id :' + r.id);
24908 if(!preventViewNotify){
24910 var proxy = new Roo.Element(
24911 this.grid.getRowDom(index)
24913 proxy.removeClass('bg-info info');
24915 this.fireEvent("rowdeselect", this, index);
24916 this.fireEvent("selectionchange", this);
24920 restoreLast : function(){
24922 this.last = this._last;
24927 acceptsNav : function(row, col, cm){
24928 return !cm.isHidden(col) && cm.isCellEditable(col, row);
24932 onEditorKey : function(field, e){
24933 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
24938 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
24940 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
24942 }else if(k == e.ENTER && !e.ctrlKey){
24946 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
24948 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
24950 }else if(k == e.ESC){
24954 g.startEditing(newCell[0], newCell[1]);
24960 * Ext JS Library 1.1.1
24961 * Copyright(c) 2006-2007, Ext JS, LLC.
24963 * Originally Released Under LGPL - original licence link has changed is not relivant.
24966 * <script type="text/javascript">
24970 * @class Roo.bootstrap.PagingToolbar
24971 * @extends Roo.bootstrap.NavSimplebar
24972 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
24974 * Create a new PagingToolbar
24975 * @param {Object} config The config object
24976 * @param {Roo.data.Store} store
24978 Roo.bootstrap.PagingToolbar = function(config)
24980 // old args format still supported... - xtype is prefered..
24981 // created from xtype...
24983 this.ds = config.dataSource;
24985 if (config.store && !this.ds) {
24986 this.store= Roo.factory(config.store, Roo.data);
24987 this.ds = this.store;
24988 this.ds.xmodule = this.xmodule || false;
24991 this.toolbarItems = [];
24992 if (config.items) {
24993 this.toolbarItems = config.items;
24996 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
25001 this.bind(this.ds);
25004 if (Roo.bootstrap.version == 4) {
25005 this.navgroup = new Roo.bootstrap.ButtonGroup({ cls: 'pagination' });
25007 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
25012 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
25014 * @cfg {Roo.data.Store} dataSource
25015 * The underlying data store providing the paged data
25018 * @cfg {String/HTMLElement/Element} container
25019 * container The id or element that will contain the toolbar
25022 * @cfg {Boolean} displayInfo
25023 * True to display the displayMsg (defaults to false)
25026 * @cfg {Number} pageSize
25027 * The number of records to display per page (defaults to 20)
25031 * @cfg {String} displayMsg
25032 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
25034 displayMsg : 'Displaying {0} - {1} of {2}',
25036 * @cfg {String} emptyMsg
25037 * The message to display when no records are found (defaults to "No data to display")
25039 emptyMsg : 'No data to display',
25041 * Customizable piece of the default paging text (defaults to "Page")
25044 beforePageText : "Page",
25046 * Customizable piece of the default paging text (defaults to "of %0")
25049 afterPageText : "of {0}",
25051 * Customizable piece of the default paging text (defaults to "First Page")
25054 firstText : "First Page",
25056 * Customizable piece of the default paging text (defaults to "Previous Page")
25059 prevText : "Previous Page",
25061 * Customizable piece of the default paging text (defaults to "Next Page")
25064 nextText : "Next Page",
25066 * Customizable piece of the default paging text (defaults to "Last Page")
25069 lastText : "Last Page",
25071 * Customizable piece of the default paging text (defaults to "Refresh")
25074 refreshText : "Refresh",
25078 onRender : function(ct, position)
25080 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
25081 this.navgroup.parentId = this.id;
25082 this.navgroup.onRender(this.el, null);
25083 // add the buttons to the navgroup
25085 if(this.displayInfo){
25086 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
25087 this.displayEl = this.el.select('.x-paging-info', true).first();
25088 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
25089 // this.displayEl = navel.el.select('span',true).first();
25095 Roo.each(_this.buttons, function(e){ // this might need to use render????
25096 Roo.factory(e).render(_this.el);
25100 Roo.each(_this.toolbarItems, function(e) {
25101 _this.navgroup.addItem(e);
25105 this.first = this.navgroup.addItem({
25106 tooltip: this.firstText,
25107 cls: "prev btn-outline-secondary",
25108 html : ' <i class="fa fa-step-backward"></i>',
25110 preventDefault: true,
25111 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
25114 this.prev = this.navgroup.addItem({
25115 tooltip: this.prevText,
25116 cls: "prev btn-outline-secondary",
25117 html : ' <i class="fa fa-backward"></i>',
25119 preventDefault: true,
25120 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
25122 //this.addSeparator();
25125 var field = this.navgroup.addItem( {
25127 cls : 'x-paging-position btn-outline-secondary',
25129 html : this.beforePageText +
25130 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
25131 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
25134 this.field = field.el.select('input', true).first();
25135 this.field.on("keydown", this.onPagingKeydown, this);
25136 this.field.on("focus", function(){this.dom.select();});
25139 this.afterTextEl = field.el.select('.x-paging-after',true).first();
25140 //this.field.setHeight(18);
25141 //this.addSeparator();
25142 this.next = this.navgroup.addItem({
25143 tooltip: this.nextText,
25144 cls: "next btn-outline-secondary",
25145 html : ' <i class="fa fa-forward"></i>',
25147 preventDefault: true,
25148 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
25150 this.last = this.navgroup.addItem({
25151 tooltip: this.lastText,
25152 html : ' <i class="fa fa-step-forward"></i>',
25153 cls: "next btn-outline-secondary",
25155 preventDefault: true,
25156 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
25158 //this.addSeparator();
25159 this.loading = this.navgroup.addItem({
25160 tooltip: this.refreshText,
25161 cls: "btn-outline-secondary",
25162 html : ' <i class="fa fa-refresh"></i>',
25163 preventDefault: true,
25164 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
25170 updateInfo : function(){
25171 if(this.displayEl){
25172 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
25173 var msg = count == 0 ?
25177 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
25179 this.displayEl.update(msg);
25184 onLoad : function(ds, r, o)
25186 this.cursor = o.params.start ? o.params.start : 0;
25188 var d = this.getPageData(),
25193 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
25194 this.field.dom.value = ap;
25195 this.first.setDisabled(ap == 1);
25196 this.prev.setDisabled(ap == 1);
25197 this.next.setDisabled(ap == ps);
25198 this.last.setDisabled(ap == ps);
25199 this.loading.enable();
25204 getPageData : function(){
25205 var total = this.ds.getTotalCount();
25208 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
25209 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
25214 onLoadError : function(){
25215 this.loading.enable();
25219 onPagingKeydown : function(e){
25220 var k = e.getKey();
25221 var d = this.getPageData();
25223 var v = this.field.dom.value, pageNum;
25224 if(!v || isNaN(pageNum = parseInt(v, 10))){
25225 this.field.dom.value = d.activePage;
25228 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
25229 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
25232 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))
25234 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
25235 this.field.dom.value = pageNum;
25236 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
25239 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
25241 var v = this.field.dom.value, pageNum;
25242 var increment = (e.shiftKey) ? 10 : 1;
25243 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
25246 if(!v || isNaN(pageNum = parseInt(v, 10))) {
25247 this.field.dom.value = d.activePage;
25250 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
25252 this.field.dom.value = parseInt(v, 10) + increment;
25253 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
25254 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
25261 beforeLoad : function(){
25263 this.loading.disable();
25268 onClick : function(which){
25277 ds.load({params:{start: 0, limit: this.pageSize}});
25280 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
25283 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
25286 var total = ds.getTotalCount();
25287 var extra = total % this.pageSize;
25288 var lastStart = extra ? (total - extra) : total-this.pageSize;
25289 ds.load({params:{start: lastStart, limit: this.pageSize}});
25292 ds.load({params:{start: this.cursor, limit: this.pageSize}});
25298 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
25299 * @param {Roo.data.Store} store The data store to unbind
25301 unbind : function(ds){
25302 ds.un("beforeload", this.beforeLoad, this);
25303 ds.un("load", this.onLoad, this);
25304 ds.un("loadexception", this.onLoadError, this);
25305 ds.un("remove", this.updateInfo, this);
25306 ds.un("add", this.updateInfo, this);
25307 this.ds = undefined;
25311 * Binds the paging toolbar to the specified {@link Roo.data.Store}
25312 * @param {Roo.data.Store} store The data store to bind
25314 bind : function(ds){
25315 ds.on("beforeload", this.beforeLoad, this);
25316 ds.on("load", this.onLoad, this);
25317 ds.on("loadexception", this.onLoadError, this);
25318 ds.on("remove", this.updateInfo, this);
25319 ds.on("add", this.updateInfo, this);
25330 * @class Roo.bootstrap.MessageBar
25331 * @extends Roo.bootstrap.Component
25332 * Bootstrap MessageBar class
25333 * @cfg {String} html contents of the MessageBar
25334 * @cfg {String} weight (info | success | warning | danger) default info
25335 * @cfg {String} beforeClass insert the bar before the given class
25336 * @cfg {Boolean} closable (true | false) default false
25337 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
25340 * Create a new Element
25341 * @param {Object} config The config object
25344 Roo.bootstrap.MessageBar = function(config){
25345 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
25348 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
25354 beforeClass: 'bootstrap-sticky-wrap',
25356 getAutoCreate : function(){
25360 cls: 'alert alert-dismissable alert-' + this.weight,
25365 html: this.html || ''
25371 cfg.cls += ' alert-messages-fixed';
25385 onRender : function(ct, position)
25387 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
25390 var cfg = Roo.apply({}, this.getAutoCreate());
25394 cfg.cls += ' ' + this.cls;
25397 cfg.style = this.style;
25399 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
25401 this.el.setVisibilityMode(Roo.Element.DISPLAY);
25404 this.el.select('>button.close').on('click', this.hide, this);
25410 if (!this.rendered) {
25416 this.fireEvent('show', this);
25422 if (!this.rendered) {
25428 this.fireEvent('hide', this);
25431 update : function()
25433 // var e = this.el.dom.firstChild;
25435 // if(this.closable){
25436 // e = e.nextSibling;
25439 // e.data = this.html || '';
25441 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
25457 * @class Roo.bootstrap.Graph
25458 * @extends Roo.bootstrap.Component
25459 * Bootstrap Graph class
25463 @cfg {String} graphtype bar | vbar | pie
25464 @cfg {number} g_x coodinator | centre x (pie)
25465 @cfg {number} g_y coodinator | centre y (pie)
25466 @cfg {number} g_r radius (pie)
25467 @cfg {number} g_height height of the chart (respected by all elements in the set)
25468 @cfg {number} g_width width of the chart (respected by all elements in the set)
25469 @cfg {Object} title The title of the chart
25472 -opts (object) options for the chart
25474 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
25475 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
25477 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.
25478 o stacked (boolean) whether or not to tread values as in a stacked bar chart
25480 o stretch (boolean)
25482 -opts (object) options for the pie
25485 o startAngle (number)
25486 o endAngle (number)
25490 * Create a new Input
25491 * @param {Object} config The config object
25494 Roo.bootstrap.Graph = function(config){
25495 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
25501 * The img click event for the img.
25502 * @param {Roo.EventObject} e
25508 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
25519 //g_colors: this.colors,
25526 getAutoCreate : function(){
25537 onRender : function(ct,position){
25540 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
25542 if (typeof(Raphael) == 'undefined') {
25543 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
25547 this.raphael = Raphael(this.el.dom);
25549 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25550 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25551 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25552 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
25554 r.text(160, 10, "Single Series Chart").attr(txtattr);
25555 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
25556 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
25557 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
25559 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
25560 r.barchart(330, 10, 300, 220, data1);
25561 r.barchart(10, 250, 300, 220, data2, {stacked: true});
25562 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
25565 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25566 // r.barchart(30, 30, 560, 250, xdata, {
25567 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
25568 // axis : "0 0 1 1",
25569 // axisxlabels : xdata
25570 // //yvalues : cols,
25573 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25575 // this.load(null,xdata,{
25576 // axis : "0 0 1 1",
25577 // axisxlabels : xdata
25582 load : function(graphtype,xdata,opts)
25584 this.raphael.clear();
25586 graphtype = this.graphtype;
25591 var r = this.raphael,
25592 fin = function () {
25593 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
25595 fout = function () {
25596 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
25598 pfin = function() {
25599 this.sector.stop();
25600 this.sector.scale(1.1, 1.1, this.cx, this.cy);
25603 this.label[0].stop();
25604 this.label[0].attr({ r: 7.5 });
25605 this.label[1].attr({ "font-weight": 800 });
25608 pfout = function() {
25609 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
25612 this.label[0].animate({ r: 5 }, 500, "bounce");
25613 this.label[1].attr({ "font-weight": 400 });
25619 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25622 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25625 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
25626 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
25628 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
25635 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
25640 setTitle: function(o)
25645 initEvents: function() {
25648 this.el.on('click', this.onClick, this);
25652 onClick : function(e)
25654 Roo.log('img onclick');
25655 this.fireEvent('click', this, e);
25667 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25670 * @class Roo.bootstrap.dash.NumberBox
25671 * @extends Roo.bootstrap.Component
25672 * Bootstrap NumberBox class
25673 * @cfg {String} headline Box headline
25674 * @cfg {String} content Box content
25675 * @cfg {String} icon Box icon
25676 * @cfg {String} footer Footer text
25677 * @cfg {String} fhref Footer href
25680 * Create a new NumberBox
25681 * @param {Object} config The config object
25685 Roo.bootstrap.dash.NumberBox = function(config){
25686 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
25690 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
25699 getAutoCreate : function(){
25703 cls : 'small-box ',
25711 cls : 'roo-headline',
25712 html : this.headline
25716 cls : 'roo-content',
25717 html : this.content
25731 cls : 'ion ' + this.icon
25740 cls : 'small-box-footer',
25741 href : this.fhref || '#',
25745 cfg.cn.push(footer);
25752 onRender : function(ct,position){
25753 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
25760 setHeadline: function (value)
25762 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
25765 setFooter: function (value, href)
25767 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
25770 this.el.select('a.small-box-footer',true).first().attr('href', href);
25775 setContent: function (value)
25777 this.el.select('.roo-content',true).first().dom.innerHTML = value;
25780 initEvents: function()
25794 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25797 * @class Roo.bootstrap.dash.TabBox
25798 * @extends Roo.bootstrap.Component
25799 * Bootstrap TabBox class
25800 * @cfg {String} title Title of the TabBox
25801 * @cfg {String} icon Icon of the TabBox
25802 * @cfg {Boolean} showtabs (true|false) show the tabs default true
25803 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
25806 * Create a new TabBox
25807 * @param {Object} config The config object
25811 Roo.bootstrap.dash.TabBox = function(config){
25812 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
25817 * When a pane is added
25818 * @param {Roo.bootstrap.dash.TabPane} pane
25822 * @event activatepane
25823 * When a pane is activated
25824 * @param {Roo.bootstrap.dash.TabPane} pane
25826 "activatepane" : true
25834 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
25839 tabScrollable : false,
25841 getChildContainer : function()
25843 return this.el.select('.tab-content', true).first();
25846 getAutoCreate : function(){
25850 cls: 'pull-left header',
25858 cls: 'fa ' + this.icon
25864 cls: 'nav nav-tabs pull-right',
25870 if(this.tabScrollable){
25877 cls: 'nav nav-tabs pull-right',
25888 cls: 'nav-tabs-custom',
25893 cls: 'tab-content no-padding',
25901 initEvents : function()
25903 //Roo.log('add add pane handler');
25904 this.on('addpane', this.onAddPane, this);
25907 * Updates the box title
25908 * @param {String} html to set the title to.
25910 setTitle : function(value)
25912 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
25914 onAddPane : function(pane)
25916 this.panes.push(pane);
25917 //Roo.log('addpane');
25919 // tabs are rendere left to right..
25920 if(!this.showtabs){
25924 var ctr = this.el.select('.nav-tabs', true).first();
25927 var existing = ctr.select('.nav-tab',true);
25928 var qty = existing.getCount();;
25931 var tab = ctr.createChild({
25933 cls : 'nav-tab' + (qty ? '' : ' active'),
25941 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
25944 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
25946 pane.el.addClass('active');
25951 onTabClick : function(ev,un,ob,pane)
25953 //Roo.log('tab - prev default');
25954 ev.preventDefault();
25957 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
25958 pane.tab.addClass('active');
25959 //Roo.log(pane.title);
25960 this.getChildContainer().select('.tab-pane',true).removeClass('active');
25961 // technically we should have a deactivate event.. but maybe add later.
25962 // and it should not de-activate the selected tab...
25963 this.fireEvent('activatepane', pane);
25964 pane.el.addClass('active');
25965 pane.fireEvent('activate');
25970 getActivePane : function()
25973 Roo.each(this.panes, function(p) {
25974 if(p.el.hasClass('active')){
25995 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25997 * @class Roo.bootstrap.TabPane
25998 * @extends Roo.bootstrap.Component
25999 * Bootstrap TabPane class
26000 * @cfg {Boolean} active (false | true) Default false
26001 * @cfg {String} title title of panel
26005 * Create a new TabPane
26006 * @param {Object} config The config object
26009 Roo.bootstrap.dash.TabPane = function(config){
26010 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
26016 * When a pane is activated
26017 * @param {Roo.bootstrap.dash.TabPane} pane
26024 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
26029 // the tabBox that this is attached to.
26032 getAutoCreate : function()
26040 cfg.cls += ' active';
26045 initEvents : function()
26047 //Roo.log('trigger add pane handler');
26048 this.parent().fireEvent('addpane', this)
26052 * Updates the tab title
26053 * @param {String} html to set the title to.
26055 setTitle: function(str)
26061 this.tab.select('a', true).first().dom.innerHTML = str;
26078 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
26081 * @class Roo.bootstrap.menu.Menu
26082 * @extends Roo.bootstrap.Component
26083 * Bootstrap Menu class - container for Menu
26084 * @cfg {String} html Text of the menu
26085 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
26086 * @cfg {String} icon Font awesome icon
26087 * @cfg {String} pos Menu align to (top | bottom) default bottom
26091 * Create a new Menu
26092 * @param {Object} config The config object
26096 Roo.bootstrap.menu.Menu = function(config){
26097 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
26101 * @event beforeshow
26102 * Fires before this menu is displayed
26103 * @param {Roo.bootstrap.menu.Menu} this
26107 * @event beforehide
26108 * Fires before this menu is hidden
26109 * @param {Roo.bootstrap.menu.Menu} this
26114 * Fires after this menu is displayed
26115 * @param {Roo.bootstrap.menu.Menu} this
26120 * Fires after this menu is hidden
26121 * @param {Roo.bootstrap.menu.Menu} this
26126 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
26127 * @param {Roo.bootstrap.menu.Menu} this
26128 * @param {Roo.EventObject} e
26135 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
26139 weight : 'default',
26144 getChildContainer : function() {
26145 if(this.isSubMenu){
26149 return this.el.select('ul.dropdown-menu', true).first();
26152 getAutoCreate : function()
26157 cls : 'roo-menu-text',
26165 cls : 'fa ' + this.icon
26176 cls : 'dropdown-button btn btn-' + this.weight,
26181 cls : 'dropdown-toggle btn btn-' + this.weight,
26191 cls : 'dropdown-menu'
26197 if(this.pos == 'top'){
26198 cfg.cls += ' dropup';
26201 if(this.isSubMenu){
26204 cls : 'dropdown-menu'
26211 onRender : function(ct, position)
26213 this.isSubMenu = ct.hasClass('dropdown-submenu');
26215 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
26218 initEvents : function()
26220 if(this.isSubMenu){
26224 this.hidden = true;
26226 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
26227 this.triggerEl.on('click', this.onTriggerPress, this);
26229 this.buttonEl = this.el.select('button.dropdown-button', true).first();
26230 this.buttonEl.on('click', this.onClick, this);
26236 if(this.isSubMenu){
26240 return this.el.select('ul.dropdown-menu', true).first();
26243 onClick : function(e)
26245 this.fireEvent("click", this, e);
26248 onTriggerPress : function(e)
26250 if (this.isVisible()) {
26257 isVisible : function(){
26258 return !this.hidden;
26263 this.fireEvent("beforeshow", this);
26265 this.hidden = false;
26266 this.el.addClass('open');
26268 Roo.get(document).on("mouseup", this.onMouseUp, this);
26270 this.fireEvent("show", this);
26277 this.fireEvent("beforehide", this);
26279 this.hidden = true;
26280 this.el.removeClass('open');
26282 Roo.get(document).un("mouseup", this.onMouseUp);
26284 this.fireEvent("hide", this);
26287 onMouseUp : function()
26301 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
26304 * @class Roo.bootstrap.menu.Item
26305 * @extends Roo.bootstrap.Component
26306 * Bootstrap MenuItem class
26307 * @cfg {Boolean} submenu (true | false) default false
26308 * @cfg {String} html text of the item
26309 * @cfg {String} href the link
26310 * @cfg {Boolean} disable (true | false) default false
26311 * @cfg {Boolean} preventDefault (true | false) default true
26312 * @cfg {String} icon Font awesome icon
26313 * @cfg {String} pos Submenu align to (left | right) default right
26317 * Create a new Item
26318 * @param {Object} config The config object
26322 Roo.bootstrap.menu.Item = function(config){
26323 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
26327 * Fires when the mouse is hovering over this menu
26328 * @param {Roo.bootstrap.menu.Item} this
26329 * @param {Roo.EventObject} e
26334 * Fires when the mouse exits this menu
26335 * @param {Roo.bootstrap.menu.Item} this
26336 * @param {Roo.EventObject} e
26342 * The raw click event for the entire grid.
26343 * @param {Roo.EventObject} e
26349 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
26354 preventDefault: true,
26359 getAutoCreate : function()
26364 cls : 'roo-menu-item-text',
26372 cls : 'fa ' + this.icon
26381 href : this.href || '#',
26388 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
26392 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
26394 if(this.pos == 'left'){
26395 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
26402 initEvents : function()
26404 this.el.on('mouseover', this.onMouseOver, this);
26405 this.el.on('mouseout', this.onMouseOut, this);
26407 this.el.select('a', true).first().on('click', this.onClick, this);
26411 onClick : function(e)
26413 if(this.preventDefault){
26414 e.preventDefault();
26417 this.fireEvent("click", this, e);
26420 onMouseOver : function(e)
26422 if(this.submenu && this.pos == 'left'){
26423 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
26426 this.fireEvent("mouseover", this, e);
26429 onMouseOut : function(e)
26431 this.fireEvent("mouseout", this, e);
26443 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
26446 * @class Roo.bootstrap.menu.Separator
26447 * @extends Roo.bootstrap.Component
26448 * Bootstrap Separator class
26451 * Create a new Separator
26452 * @param {Object} config The config object
26456 Roo.bootstrap.menu.Separator = function(config){
26457 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
26460 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
26462 getAutoCreate : function(){
26483 * @class Roo.bootstrap.Tooltip
26484 * Bootstrap Tooltip class
26485 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
26486 * to determine which dom element triggers the tooltip.
26488 * It needs to add support for additional attributes like tooltip-position
26491 * Create a new Toolti
26492 * @param {Object} config The config object
26495 Roo.bootstrap.Tooltip = function(config){
26496 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
26498 this.alignment = Roo.bootstrap.Tooltip.alignment;
26500 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
26501 this.alignment = config.alignment;
26506 Roo.apply(Roo.bootstrap.Tooltip, {
26508 * @function init initialize tooltip monitoring.
26512 currentTip : false,
26513 currentRegion : false,
26519 Roo.get(document).on('mouseover', this.enter ,this);
26520 Roo.get(document).on('mouseout', this.leave, this);
26523 this.currentTip = new Roo.bootstrap.Tooltip();
26526 enter : function(ev)
26528 var dom = ev.getTarget();
26530 //Roo.log(['enter',dom]);
26531 var el = Roo.fly(dom);
26532 if (this.currentEl) {
26534 //Roo.log(this.currentEl);
26535 //Roo.log(this.currentEl.contains(dom));
26536 if (this.currentEl == el) {
26539 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
26545 if (this.currentTip.el) {
26546 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
26550 if(!el || el.dom == document){
26556 // you can not look for children, as if el is the body.. then everythign is the child..
26557 if (!el.attr('tooltip')) { //
26558 if (!el.select("[tooltip]").elements.length) {
26561 // is the mouse over this child...?
26562 bindEl = el.select("[tooltip]").first();
26563 var xy = ev.getXY();
26564 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
26565 //Roo.log("not in region.");
26568 //Roo.log("child element over..");
26571 this.currentEl = bindEl;
26572 this.currentTip.bind(bindEl);
26573 this.currentRegion = Roo.lib.Region.getRegion(dom);
26574 this.currentTip.enter();
26577 leave : function(ev)
26579 var dom = ev.getTarget();
26580 //Roo.log(['leave',dom]);
26581 if (!this.currentEl) {
26586 if (dom != this.currentEl.dom) {
26589 var xy = ev.getXY();
26590 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
26593 // only activate leave if mouse cursor is outside... bounding box..
26598 if (this.currentTip) {
26599 this.currentTip.leave();
26601 //Roo.log('clear currentEl');
26602 this.currentEl = false;
26607 'left' : ['r-l', [-2,0], 'right'],
26608 'right' : ['l-r', [2,0], 'left'],
26609 'bottom' : ['t-b', [0,2], 'top'],
26610 'top' : [ 'b-t', [0,-2], 'bottom']
26616 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
26621 delay : null, // can be { show : 300 , hide: 500}
26625 hoverState : null, //???
26627 placement : 'bottom',
26631 getAutoCreate : function(){
26638 cls : 'tooltip-arrow'
26641 cls : 'tooltip-inner'
26648 bind : function(el)
26654 enter : function () {
26656 if (this.timeout != null) {
26657 clearTimeout(this.timeout);
26660 this.hoverState = 'in';
26661 //Roo.log("enter - show");
26662 if (!this.delay || !this.delay.show) {
26667 this.timeout = setTimeout(function () {
26668 if (_t.hoverState == 'in') {
26671 }, this.delay.show);
26675 clearTimeout(this.timeout);
26677 this.hoverState = 'out';
26678 if (!this.delay || !this.delay.hide) {
26684 this.timeout = setTimeout(function () {
26685 //Roo.log("leave - timeout");
26687 if (_t.hoverState == 'out') {
26689 Roo.bootstrap.Tooltip.currentEl = false;
26694 show : function (msg)
26697 this.render(document.body);
26700 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
26702 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
26704 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
26706 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
26708 var placement = typeof this.placement == 'function' ?
26709 this.placement.call(this, this.el, on_el) :
26712 var autoToken = /\s?auto?\s?/i;
26713 var autoPlace = autoToken.test(placement);
26715 placement = placement.replace(autoToken, '') || 'top';
26719 //this.el.setXY([0,0]);
26721 //this.el.dom.style.display='block';
26723 //this.el.appendTo(on_el);
26725 var p = this.getPosition();
26726 var box = this.el.getBox();
26732 var align = this.alignment[placement];
26734 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
26736 if(placement == 'top' || placement == 'bottom'){
26738 placement = 'right';
26741 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
26742 placement = 'left';
26745 var scroll = Roo.select('body', true).first().getScroll();
26747 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
26751 align = this.alignment[placement];
26754 this.el.alignTo(this.bindEl, align[0],align[1]);
26755 //var arrow = this.el.select('.arrow',true).first();
26756 //arrow.set(align[2],
26758 this.el.addClass(placement);
26760 this.el.addClass('in fade');
26762 this.hoverState = null;
26764 if (this.el.hasClass('fade')) {
26775 //this.el.setXY([0,0]);
26776 this.el.removeClass('in');
26792 * @class Roo.bootstrap.LocationPicker
26793 * @extends Roo.bootstrap.Component
26794 * Bootstrap LocationPicker class
26795 * @cfg {Number} latitude Position when init default 0
26796 * @cfg {Number} longitude Position when init default 0
26797 * @cfg {Number} zoom default 15
26798 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
26799 * @cfg {Boolean} mapTypeControl default false
26800 * @cfg {Boolean} disableDoubleClickZoom default false
26801 * @cfg {Boolean} scrollwheel default true
26802 * @cfg {Boolean} streetViewControl default false
26803 * @cfg {Number} radius default 0
26804 * @cfg {String} locationName
26805 * @cfg {Boolean} draggable default true
26806 * @cfg {Boolean} enableAutocomplete default false
26807 * @cfg {Boolean} enableReverseGeocode default true
26808 * @cfg {String} markerTitle
26811 * Create a new LocationPicker
26812 * @param {Object} config The config object
26816 Roo.bootstrap.LocationPicker = function(config){
26818 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
26823 * Fires when the picker initialized.
26824 * @param {Roo.bootstrap.LocationPicker} this
26825 * @param {Google Location} location
26829 * @event positionchanged
26830 * Fires when the picker position changed.
26831 * @param {Roo.bootstrap.LocationPicker} this
26832 * @param {Google Location} location
26834 positionchanged : true,
26837 * Fires when the map resize.
26838 * @param {Roo.bootstrap.LocationPicker} this
26843 * Fires when the map show.
26844 * @param {Roo.bootstrap.LocationPicker} this
26849 * Fires when the map hide.
26850 * @param {Roo.bootstrap.LocationPicker} this
26855 * Fires when click the map.
26856 * @param {Roo.bootstrap.LocationPicker} this
26857 * @param {Map event} e
26861 * @event mapRightClick
26862 * Fires when right click the map.
26863 * @param {Roo.bootstrap.LocationPicker} this
26864 * @param {Map event} e
26866 mapRightClick : true,
26868 * @event markerClick
26869 * Fires when click the marker.
26870 * @param {Roo.bootstrap.LocationPicker} this
26871 * @param {Map event} e
26873 markerClick : true,
26875 * @event markerRightClick
26876 * Fires when right click the marker.
26877 * @param {Roo.bootstrap.LocationPicker} this
26878 * @param {Map event} e
26880 markerRightClick : true,
26882 * @event OverlayViewDraw
26883 * Fires when OverlayView Draw
26884 * @param {Roo.bootstrap.LocationPicker} this
26886 OverlayViewDraw : true,
26888 * @event OverlayViewOnAdd
26889 * Fires when OverlayView Draw
26890 * @param {Roo.bootstrap.LocationPicker} this
26892 OverlayViewOnAdd : true,
26894 * @event OverlayViewOnRemove
26895 * Fires when OverlayView Draw
26896 * @param {Roo.bootstrap.LocationPicker} this
26898 OverlayViewOnRemove : true,
26900 * @event OverlayViewShow
26901 * Fires when OverlayView Draw
26902 * @param {Roo.bootstrap.LocationPicker} this
26903 * @param {Pixel} cpx
26905 OverlayViewShow : true,
26907 * @event OverlayViewHide
26908 * Fires when OverlayView Draw
26909 * @param {Roo.bootstrap.LocationPicker} this
26911 OverlayViewHide : true,
26913 * @event loadexception
26914 * Fires when load google lib failed.
26915 * @param {Roo.bootstrap.LocationPicker} this
26917 loadexception : true
26922 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
26924 gMapContext: false,
26930 mapTypeControl: false,
26931 disableDoubleClickZoom: false,
26933 streetViewControl: false,
26937 enableAutocomplete: false,
26938 enableReverseGeocode: true,
26941 getAutoCreate: function()
26946 cls: 'roo-location-picker'
26952 initEvents: function(ct, position)
26954 if(!this.el.getWidth() || this.isApplied()){
26958 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26963 initial: function()
26965 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
26966 this.fireEvent('loadexception', this);
26970 if(!this.mapTypeId){
26971 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
26974 this.gMapContext = this.GMapContext();
26976 this.initOverlayView();
26978 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
26982 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
26983 _this.setPosition(_this.gMapContext.marker.position);
26986 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
26987 _this.fireEvent('mapClick', this, event);
26991 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
26992 _this.fireEvent('mapRightClick', this, event);
26996 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
26997 _this.fireEvent('markerClick', this, event);
27001 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
27002 _this.fireEvent('markerRightClick', this, event);
27006 this.setPosition(this.gMapContext.location);
27008 this.fireEvent('initial', this, this.gMapContext.location);
27011 initOverlayView: function()
27015 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
27019 _this.fireEvent('OverlayViewDraw', _this);
27024 _this.fireEvent('OverlayViewOnAdd', _this);
27027 onRemove: function()
27029 _this.fireEvent('OverlayViewOnRemove', _this);
27032 show: function(cpx)
27034 _this.fireEvent('OverlayViewShow', _this, cpx);
27039 _this.fireEvent('OverlayViewHide', _this);
27045 fromLatLngToContainerPixel: function(event)
27047 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
27050 isApplied: function()
27052 return this.getGmapContext() == false ? false : true;
27055 getGmapContext: function()
27057 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
27060 GMapContext: function()
27062 var position = new google.maps.LatLng(this.latitude, this.longitude);
27064 var _map = new google.maps.Map(this.el.dom, {
27067 mapTypeId: this.mapTypeId,
27068 mapTypeControl: this.mapTypeControl,
27069 disableDoubleClickZoom: this.disableDoubleClickZoom,
27070 scrollwheel: this.scrollwheel,
27071 streetViewControl: this.streetViewControl,
27072 locationName: this.locationName,
27073 draggable: this.draggable,
27074 enableAutocomplete: this.enableAutocomplete,
27075 enableReverseGeocode: this.enableReverseGeocode
27078 var _marker = new google.maps.Marker({
27079 position: position,
27081 title: this.markerTitle,
27082 draggable: this.draggable
27089 location: position,
27090 radius: this.radius,
27091 locationName: this.locationName,
27092 addressComponents: {
27093 formatted_address: null,
27094 addressLine1: null,
27095 addressLine2: null,
27097 streetNumber: null,
27101 stateOrProvince: null
27104 domContainer: this.el.dom,
27105 geodecoder: new google.maps.Geocoder()
27109 drawCircle: function(center, radius, options)
27111 if (this.gMapContext.circle != null) {
27112 this.gMapContext.circle.setMap(null);
27116 options = Roo.apply({}, options, {
27117 strokeColor: "#0000FF",
27118 strokeOpacity: .35,
27120 fillColor: "#0000FF",
27124 options.map = this.gMapContext.map;
27125 options.radius = radius;
27126 options.center = center;
27127 this.gMapContext.circle = new google.maps.Circle(options);
27128 return this.gMapContext.circle;
27134 setPosition: function(location)
27136 this.gMapContext.location = location;
27137 this.gMapContext.marker.setPosition(location);
27138 this.gMapContext.map.panTo(location);
27139 this.drawCircle(location, this.gMapContext.radius, {});
27143 if (this.gMapContext.settings.enableReverseGeocode) {
27144 this.gMapContext.geodecoder.geocode({
27145 latLng: this.gMapContext.location
27146 }, function(results, status) {
27148 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
27149 _this.gMapContext.locationName = results[0].formatted_address;
27150 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
27152 _this.fireEvent('positionchanged', this, location);
27159 this.fireEvent('positionchanged', this, location);
27164 google.maps.event.trigger(this.gMapContext.map, "resize");
27166 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
27168 this.fireEvent('resize', this);
27171 setPositionByLatLng: function(latitude, longitude)
27173 this.setPosition(new google.maps.LatLng(latitude, longitude));
27176 getCurrentPosition: function()
27179 latitude: this.gMapContext.location.lat(),
27180 longitude: this.gMapContext.location.lng()
27184 getAddressName: function()
27186 return this.gMapContext.locationName;
27189 getAddressComponents: function()
27191 return this.gMapContext.addressComponents;
27194 address_component_from_google_geocode: function(address_components)
27198 for (var i = 0; i < address_components.length; i++) {
27199 var component = address_components[i];
27200 if (component.types.indexOf("postal_code") >= 0) {
27201 result.postalCode = component.short_name;
27202 } else if (component.types.indexOf("street_number") >= 0) {
27203 result.streetNumber = component.short_name;
27204 } else if (component.types.indexOf("route") >= 0) {
27205 result.streetName = component.short_name;
27206 } else if (component.types.indexOf("neighborhood") >= 0) {
27207 result.city = component.short_name;
27208 } else if (component.types.indexOf("locality") >= 0) {
27209 result.city = component.short_name;
27210 } else if (component.types.indexOf("sublocality") >= 0) {
27211 result.district = component.short_name;
27212 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
27213 result.stateOrProvince = component.short_name;
27214 } else if (component.types.indexOf("country") >= 0) {
27215 result.country = component.short_name;
27219 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
27220 result.addressLine2 = "";
27224 setZoomLevel: function(zoom)
27226 this.gMapContext.map.setZoom(zoom);
27239 this.fireEvent('show', this);
27250 this.fireEvent('hide', this);
27255 Roo.apply(Roo.bootstrap.LocationPicker, {
27257 OverlayView : function(map, options)
27259 options = options || {};
27266 * @class Roo.bootstrap.Alert
27267 * @extends Roo.bootstrap.Component
27268 * Bootstrap Alert class - shows an alert area box
27270 * <div class="alert alert-danger" role="alert"><span class="fa fa-exclamation-triangle"></span><span class="sr-only">Error:</span>
27271 Enter a valid email address
27274 * @cfg {String} title The title of alert
27275 * @cfg {String} html The content of alert
27276 * @cfg {String} weight ( success | info | warning | danger )
27277 * @cfg {String} faicon font-awesomeicon
27280 * Create a new alert
27281 * @param {Object} config The config object
27285 Roo.bootstrap.Alert = function(config){
27286 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
27290 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
27297 getAutoCreate : function()
27306 cls : 'roo-alert-icon'
27311 cls : 'roo-alert-title',
27316 cls : 'roo-alert-text',
27323 cfg.cn[0].cls += ' fa ' + this.faicon;
27327 cfg.cls += ' alert-' + this.weight;
27333 initEvents: function()
27335 this.el.setVisibilityMode(Roo.Element.DISPLAY);
27338 setTitle : function(str)
27340 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
27343 setText : function(str)
27345 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
27348 setWeight : function(weight)
27351 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
27354 this.weight = weight;
27356 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
27359 setIcon : function(icon)
27362 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
27365 this.faicon = icon;
27367 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
27388 * @class Roo.bootstrap.UploadCropbox
27389 * @extends Roo.bootstrap.Component
27390 * Bootstrap UploadCropbox class
27391 * @cfg {String} emptyText show when image has been loaded
27392 * @cfg {String} rotateNotify show when image too small to rotate
27393 * @cfg {Number} errorTimeout default 3000
27394 * @cfg {Number} minWidth default 300
27395 * @cfg {Number} minHeight default 300
27396 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
27397 * @cfg {Boolean} isDocument (true|false) default false
27398 * @cfg {String} url action url
27399 * @cfg {String} paramName default 'imageUpload'
27400 * @cfg {String} method default POST
27401 * @cfg {Boolean} loadMask (true|false) default true
27402 * @cfg {Boolean} loadingText default 'Loading...'
27405 * Create a new UploadCropbox
27406 * @param {Object} config The config object
27409 Roo.bootstrap.UploadCropbox = function(config){
27410 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
27414 * @event beforeselectfile
27415 * Fire before select file
27416 * @param {Roo.bootstrap.UploadCropbox} this
27418 "beforeselectfile" : true,
27421 * Fire after initEvent
27422 * @param {Roo.bootstrap.UploadCropbox} this
27427 * Fire after initEvent
27428 * @param {Roo.bootstrap.UploadCropbox} this
27429 * @param {String} data
27434 * Fire when preparing the file data
27435 * @param {Roo.bootstrap.UploadCropbox} this
27436 * @param {Object} file
27441 * Fire when get exception
27442 * @param {Roo.bootstrap.UploadCropbox} this
27443 * @param {XMLHttpRequest} xhr
27445 "exception" : true,
27447 * @event beforeloadcanvas
27448 * Fire before load the canvas
27449 * @param {Roo.bootstrap.UploadCropbox} this
27450 * @param {String} src
27452 "beforeloadcanvas" : true,
27455 * Fire when trash image
27456 * @param {Roo.bootstrap.UploadCropbox} this
27461 * Fire when download the image
27462 * @param {Roo.bootstrap.UploadCropbox} this
27466 * @event footerbuttonclick
27467 * Fire when footerbuttonclick
27468 * @param {Roo.bootstrap.UploadCropbox} this
27469 * @param {String} type
27471 "footerbuttonclick" : true,
27475 * @param {Roo.bootstrap.UploadCropbox} this
27480 * Fire when rotate the image
27481 * @param {Roo.bootstrap.UploadCropbox} this
27482 * @param {String} pos
27487 * Fire when inspect the file
27488 * @param {Roo.bootstrap.UploadCropbox} this
27489 * @param {Object} file
27494 * Fire when xhr upload the file
27495 * @param {Roo.bootstrap.UploadCropbox} this
27496 * @param {Object} data
27501 * Fire when arrange the file data
27502 * @param {Roo.bootstrap.UploadCropbox} this
27503 * @param {Object} formData
27508 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
27511 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
27513 emptyText : 'Click to upload image',
27514 rotateNotify : 'Image is too small to rotate',
27515 errorTimeout : 3000,
27529 cropType : 'image/jpeg',
27531 canvasLoaded : false,
27532 isDocument : false,
27534 paramName : 'imageUpload',
27536 loadingText : 'Loading...',
27539 getAutoCreate : function()
27543 cls : 'roo-upload-cropbox',
27547 cls : 'roo-upload-cropbox-selector',
27552 cls : 'roo-upload-cropbox-body',
27553 style : 'cursor:pointer',
27557 cls : 'roo-upload-cropbox-preview'
27561 cls : 'roo-upload-cropbox-thumb'
27565 cls : 'roo-upload-cropbox-empty-notify',
27566 html : this.emptyText
27570 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
27571 html : this.rotateNotify
27577 cls : 'roo-upload-cropbox-footer',
27580 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
27590 onRender : function(ct, position)
27592 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
27594 if (this.buttons.length) {
27596 Roo.each(this.buttons, function(bb) {
27598 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
27600 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
27606 this.maskEl = this.el;
27610 initEvents : function()
27612 this.urlAPI = (window.createObjectURL && window) ||
27613 (window.URL && URL.revokeObjectURL && URL) ||
27614 (window.webkitURL && webkitURL);
27616 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
27617 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27619 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
27620 this.selectorEl.hide();
27622 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
27623 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27625 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
27626 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27627 this.thumbEl.hide();
27629 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
27630 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27632 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
27633 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27634 this.errorEl.hide();
27636 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
27637 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27638 this.footerEl.hide();
27640 this.setThumbBoxSize();
27646 this.fireEvent('initial', this);
27653 window.addEventListener("resize", function() { _this.resize(); } );
27655 this.bodyEl.on('click', this.beforeSelectFile, this);
27658 this.bodyEl.on('touchstart', this.onTouchStart, this);
27659 this.bodyEl.on('touchmove', this.onTouchMove, this);
27660 this.bodyEl.on('touchend', this.onTouchEnd, this);
27664 this.bodyEl.on('mousedown', this.onMouseDown, this);
27665 this.bodyEl.on('mousemove', this.onMouseMove, this);
27666 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
27667 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
27668 Roo.get(document).on('mouseup', this.onMouseUp, this);
27671 this.selectorEl.on('change', this.onFileSelected, this);
27677 this.baseScale = 1;
27679 this.baseRotate = 1;
27680 this.dragable = false;
27681 this.pinching = false;
27684 this.cropData = false;
27685 this.notifyEl.dom.innerHTML = this.emptyText;
27687 this.selectorEl.dom.value = '';
27691 resize : function()
27693 if(this.fireEvent('resize', this) != false){
27694 this.setThumbBoxPosition();
27695 this.setCanvasPosition();
27699 onFooterButtonClick : function(e, el, o, type)
27702 case 'rotate-left' :
27703 this.onRotateLeft(e);
27705 case 'rotate-right' :
27706 this.onRotateRight(e);
27709 this.beforeSelectFile(e);
27724 this.fireEvent('footerbuttonclick', this, type);
27727 beforeSelectFile : function(e)
27729 e.preventDefault();
27731 if(this.fireEvent('beforeselectfile', this) != false){
27732 this.selectorEl.dom.click();
27736 onFileSelected : function(e)
27738 e.preventDefault();
27740 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
27744 var file = this.selectorEl.dom.files[0];
27746 if(this.fireEvent('inspect', this, file) != false){
27747 this.prepare(file);
27752 trash : function(e)
27754 this.fireEvent('trash', this);
27757 download : function(e)
27759 this.fireEvent('download', this);
27762 loadCanvas : function(src)
27764 if(this.fireEvent('beforeloadcanvas', this, src) != false){
27768 this.imageEl = document.createElement('img');
27772 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
27774 this.imageEl.src = src;
27778 onLoadCanvas : function()
27780 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
27781 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
27783 this.bodyEl.un('click', this.beforeSelectFile, this);
27785 this.notifyEl.hide();
27786 this.thumbEl.show();
27787 this.footerEl.show();
27789 this.baseRotateLevel();
27791 if(this.isDocument){
27792 this.setThumbBoxSize();
27795 this.setThumbBoxPosition();
27797 this.baseScaleLevel();
27803 this.canvasLoaded = true;
27806 this.maskEl.unmask();
27811 setCanvasPosition : function()
27813 if(!this.canvasEl){
27817 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
27818 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
27820 this.previewEl.setLeft(pw);
27821 this.previewEl.setTop(ph);
27825 onMouseDown : function(e)
27829 this.dragable = true;
27830 this.pinching = false;
27832 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
27833 this.dragable = false;
27837 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27838 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27842 onMouseMove : function(e)
27846 if(!this.canvasLoaded){
27850 if (!this.dragable){
27854 var minX = Math.ceil(this.thumbEl.getLeft(true));
27855 var minY = Math.ceil(this.thumbEl.getTop(true));
27857 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
27858 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
27860 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27861 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27863 x = x - this.mouseX;
27864 y = y - this.mouseY;
27866 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
27867 var bgY = Math.ceil(y + this.previewEl.getTop(true));
27869 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
27870 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
27872 this.previewEl.setLeft(bgX);
27873 this.previewEl.setTop(bgY);
27875 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27876 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27879 onMouseUp : function(e)
27883 this.dragable = false;
27886 onMouseWheel : function(e)
27890 this.startScale = this.scale;
27892 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
27894 if(!this.zoomable()){
27895 this.scale = this.startScale;
27904 zoomable : function()
27906 var minScale = this.thumbEl.getWidth() / this.minWidth;
27908 if(this.minWidth < this.minHeight){
27909 minScale = this.thumbEl.getHeight() / this.minHeight;
27912 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
27913 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
27917 (this.rotate == 0 || this.rotate == 180) &&
27919 width > this.imageEl.OriginWidth ||
27920 height > this.imageEl.OriginHeight ||
27921 (width < this.minWidth && height < this.minHeight)
27929 (this.rotate == 90 || this.rotate == 270) &&
27931 width > this.imageEl.OriginWidth ||
27932 height > this.imageEl.OriginHeight ||
27933 (width < this.minHeight && height < this.minWidth)
27940 !this.isDocument &&
27941 (this.rotate == 0 || this.rotate == 180) &&
27943 width < this.minWidth ||
27944 width > this.imageEl.OriginWidth ||
27945 height < this.minHeight ||
27946 height > this.imageEl.OriginHeight
27953 !this.isDocument &&
27954 (this.rotate == 90 || this.rotate == 270) &&
27956 width < this.minHeight ||
27957 width > this.imageEl.OriginWidth ||
27958 height < this.minWidth ||
27959 height > this.imageEl.OriginHeight
27969 onRotateLeft : function(e)
27971 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27973 var minScale = this.thumbEl.getWidth() / this.minWidth;
27975 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27976 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27978 this.startScale = this.scale;
27980 while (this.getScaleLevel() < minScale){
27982 this.scale = this.scale + 1;
27984 if(!this.zoomable()){
27989 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27990 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27995 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
28002 this.scale = this.startScale;
28004 this.onRotateFail();
28009 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
28011 if(this.isDocument){
28012 this.setThumbBoxSize();
28013 this.setThumbBoxPosition();
28014 this.setCanvasPosition();
28019 this.fireEvent('rotate', this, 'left');
28023 onRotateRight : function(e)
28025 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
28027 var minScale = this.thumbEl.getWidth() / this.minWidth;
28029 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
28030 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
28032 this.startScale = this.scale;
28034 while (this.getScaleLevel() < minScale){
28036 this.scale = this.scale + 1;
28038 if(!this.zoomable()){
28043 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
28044 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
28049 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
28056 this.scale = this.startScale;
28058 this.onRotateFail();
28063 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
28065 if(this.isDocument){
28066 this.setThumbBoxSize();
28067 this.setThumbBoxPosition();
28068 this.setCanvasPosition();
28073 this.fireEvent('rotate', this, 'right');
28076 onRotateFail : function()
28078 this.errorEl.show(true);
28082 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
28087 this.previewEl.dom.innerHTML = '';
28089 var canvasEl = document.createElement("canvas");
28091 var contextEl = canvasEl.getContext("2d");
28093 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
28094 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
28095 var center = this.imageEl.OriginWidth / 2;
28097 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
28098 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
28099 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
28100 center = this.imageEl.OriginHeight / 2;
28103 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
28105 contextEl.translate(center, center);
28106 contextEl.rotate(this.rotate * Math.PI / 180);
28108 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
28110 this.canvasEl = document.createElement("canvas");
28112 this.contextEl = this.canvasEl.getContext("2d");
28114 switch (this.rotate) {
28117 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
28118 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
28120 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
28125 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
28126 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
28128 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28129 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);
28133 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
28138 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
28139 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
28141 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28142 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);
28146 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);
28151 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
28152 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
28154 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28155 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
28159 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);
28166 this.previewEl.appendChild(this.canvasEl);
28168 this.setCanvasPosition();
28173 if(!this.canvasLoaded){
28177 var imageCanvas = document.createElement("canvas");
28179 var imageContext = imageCanvas.getContext("2d");
28181 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
28182 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
28184 var center = imageCanvas.width / 2;
28186 imageContext.translate(center, center);
28188 imageContext.rotate(this.rotate * Math.PI / 180);
28190 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
28192 var canvas = document.createElement("canvas");
28194 var context = canvas.getContext("2d");
28196 canvas.width = this.minWidth;
28197 canvas.height = this.minHeight;
28199 switch (this.rotate) {
28202 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
28203 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
28205 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28206 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28208 var targetWidth = this.minWidth - 2 * x;
28209 var targetHeight = this.minHeight - 2 * y;
28213 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28214 scale = targetWidth / width;
28217 if(x > 0 && y == 0){
28218 scale = targetHeight / height;
28221 if(x > 0 && y > 0){
28222 scale = targetWidth / width;
28224 if(width < height){
28225 scale = targetHeight / height;
28229 context.scale(scale, scale);
28231 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28232 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28234 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28235 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28237 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28242 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
28243 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
28245 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28246 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28248 var targetWidth = this.minWidth - 2 * x;
28249 var targetHeight = this.minHeight - 2 * y;
28253 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28254 scale = targetWidth / width;
28257 if(x > 0 && y == 0){
28258 scale = targetHeight / height;
28261 if(x > 0 && y > 0){
28262 scale = targetWidth / width;
28264 if(width < height){
28265 scale = targetHeight / height;
28269 context.scale(scale, scale);
28271 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28272 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28274 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28275 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28277 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
28279 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28284 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
28285 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
28287 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28288 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28290 var targetWidth = this.minWidth - 2 * x;
28291 var targetHeight = this.minHeight - 2 * y;
28295 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28296 scale = targetWidth / width;
28299 if(x > 0 && y == 0){
28300 scale = targetHeight / height;
28303 if(x > 0 && y > 0){
28304 scale = targetWidth / width;
28306 if(width < height){
28307 scale = targetHeight / height;
28311 context.scale(scale, scale);
28313 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28314 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28316 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28317 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28319 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
28320 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
28322 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28327 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
28328 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
28330 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28331 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28333 var targetWidth = this.minWidth - 2 * x;
28334 var targetHeight = this.minHeight - 2 * y;
28338 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28339 scale = targetWidth / width;
28342 if(x > 0 && y == 0){
28343 scale = targetHeight / height;
28346 if(x > 0 && y > 0){
28347 scale = targetWidth / width;
28349 if(width < height){
28350 scale = targetHeight / height;
28354 context.scale(scale, scale);
28356 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28357 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28359 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28360 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28362 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
28364 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28371 this.cropData = canvas.toDataURL(this.cropType);
28373 if(this.fireEvent('crop', this, this.cropData) !== false){
28374 this.process(this.file, this.cropData);
28381 setThumbBoxSize : function()
28385 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
28386 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
28387 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
28389 this.minWidth = width;
28390 this.minHeight = height;
28392 if(this.rotate == 90 || this.rotate == 270){
28393 this.minWidth = height;
28394 this.minHeight = width;
28399 width = Math.ceil(this.minWidth * height / this.minHeight);
28401 if(this.minWidth > this.minHeight){
28403 height = Math.ceil(this.minHeight * width / this.minWidth);
28406 this.thumbEl.setStyle({
28407 width : width + 'px',
28408 height : height + 'px'
28415 setThumbBoxPosition : function()
28417 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
28418 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
28420 this.thumbEl.setLeft(x);
28421 this.thumbEl.setTop(y);
28425 baseRotateLevel : function()
28427 this.baseRotate = 1;
28430 typeof(this.exif) != 'undefined' &&
28431 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
28432 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
28434 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
28437 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
28441 baseScaleLevel : function()
28445 if(this.isDocument){
28447 if(this.baseRotate == 6 || this.baseRotate == 8){
28449 height = this.thumbEl.getHeight();
28450 this.baseScale = height / this.imageEl.OriginWidth;
28452 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
28453 width = this.thumbEl.getWidth();
28454 this.baseScale = width / this.imageEl.OriginHeight;
28460 height = this.thumbEl.getHeight();
28461 this.baseScale = height / this.imageEl.OriginHeight;
28463 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
28464 width = this.thumbEl.getWidth();
28465 this.baseScale = width / this.imageEl.OriginWidth;
28471 if(this.baseRotate == 6 || this.baseRotate == 8){
28473 width = this.thumbEl.getHeight();
28474 this.baseScale = width / this.imageEl.OriginHeight;
28476 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
28477 height = this.thumbEl.getWidth();
28478 this.baseScale = height / this.imageEl.OriginHeight;
28481 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28482 height = this.thumbEl.getWidth();
28483 this.baseScale = height / this.imageEl.OriginHeight;
28485 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
28486 width = this.thumbEl.getHeight();
28487 this.baseScale = width / this.imageEl.OriginWidth;
28494 width = this.thumbEl.getWidth();
28495 this.baseScale = width / this.imageEl.OriginWidth;
28497 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
28498 height = this.thumbEl.getHeight();
28499 this.baseScale = height / this.imageEl.OriginHeight;
28502 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28504 height = this.thumbEl.getHeight();
28505 this.baseScale = height / this.imageEl.OriginHeight;
28507 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
28508 width = this.thumbEl.getWidth();
28509 this.baseScale = width / this.imageEl.OriginWidth;
28517 getScaleLevel : function()
28519 return this.baseScale * Math.pow(1.1, this.scale);
28522 onTouchStart : function(e)
28524 if(!this.canvasLoaded){
28525 this.beforeSelectFile(e);
28529 var touches = e.browserEvent.touches;
28535 if(touches.length == 1){
28536 this.onMouseDown(e);
28540 if(touches.length != 2){
28546 for(var i = 0, finger; finger = touches[i]; i++){
28547 coords.push(finger.pageX, finger.pageY);
28550 var x = Math.pow(coords[0] - coords[2], 2);
28551 var y = Math.pow(coords[1] - coords[3], 2);
28553 this.startDistance = Math.sqrt(x + y);
28555 this.startScale = this.scale;
28557 this.pinching = true;
28558 this.dragable = false;
28562 onTouchMove : function(e)
28564 if(!this.pinching && !this.dragable){
28568 var touches = e.browserEvent.touches;
28575 this.onMouseMove(e);
28581 for(var i = 0, finger; finger = touches[i]; i++){
28582 coords.push(finger.pageX, finger.pageY);
28585 var x = Math.pow(coords[0] - coords[2], 2);
28586 var y = Math.pow(coords[1] - coords[3], 2);
28588 this.endDistance = Math.sqrt(x + y);
28590 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
28592 if(!this.zoomable()){
28593 this.scale = this.startScale;
28601 onTouchEnd : function(e)
28603 this.pinching = false;
28604 this.dragable = false;
28608 process : function(file, crop)
28611 this.maskEl.mask(this.loadingText);
28614 this.xhr = new XMLHttpRequest();
28616 file.xhr = this.xhr;
28618 this.xhr.open(this.method, this.url, true);
28621 "Accept": "application/json",
28622 "Cache-Control": "no-cache",
28623 "X-Requested-With": "XMLHttpRequest"
28626 for (var headerName in headers) {
28627 var headerValue = headers[headerName];
28629 this.xhr.setRequestHeader(headerName, headerValue);
28635 this.xhr.onload = function()
28637 _this.xhrOnLoad(_this.xhr);
28640 this.xhr.onerror = function()
28642 _this.xhrOnError(_this.xhr);
28645 var formData = new FormData();
28647 formData.append('returnHTML', 'NO');
28650 formData.append('crop', crop);
28653 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
28654 formData.append(this.paramName, file, file.name);
28657 if(typeof(file.filename) != 'undefined'){
28658 formData.append('filename', file.filename);
28661 if(typeof(file.mimetype) != 'undefined'){
28662 formData.append('mimetype', file.mimetype);
28665 if(this.fireEvent('arrange', this, formData) != false){
28666 this.xhr.send(formData);
28670 xhrOnLoad : function(xhr)
28673 this.maskEl.unmask();
28676 if (xhr.readyState !== 4) {
28677 this.fireEvent('exception', this, xhr);
28681 var response = Roo.decode(xhr.responseText);
28683 if(!response.success){
28684 this.fireEvent('exception', this, xhr);
28688 var response = Roo.decode(xhr.responseText);
28690 this.fireEvent('upload', this, response);
28694 xhrOnError : function()
28697 this.maskEl.unmask();
28700 Roo.log('xhr on error');
28702 var response = Roo.decode(xhr.responseText);
28708 prepare : function(file)
28711 this.maskEl.mask(this.loadingText);
28717 if(typeof(file) === 'string'){
28718 this.loadCanvas(file);
28722 if(!file || !this.urlAPI){
28727 this.cropType = file.type;
28731 if(this.fireEvent('prepare', this, this.file) != false){
28733 var reader = new FileReader();
28735 reader.onload = function (e) {
28736 if (e.target.error) {
28737 Roo.log(e.target.error);
28741 var buffer = e.target.result,
28742 dataView = new DataView(buffer),
28744 maxOffset = dataView.byteLength - 4,
28748 if (dataView.getUint16(0) === 0xffd8) {
28749 while (offset < maxOffset) {
28750 markerBytes = dataView.getUint16(offset);
28752 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
28753 markerLength = dataView.getUint16(offset + 2) + 2;
28754 if (offset + markerLength > dataView.byteLength) {
28755 Roo.log('Invalid meta data: Invalid segment size.');
28759 if(markerBytes == 0xffe1){
28760 _this.parseExifData(
28767 offset += markerLength;
28777 var url = _this.urlAPI.createObjectURL(_this.file);
28779 _this.loadCanvas(url);
28784 reader.readAsArrayBuffer(this.file);
28790 parseExifData : function(dataView, offset, length)
28792 var tiffOffset = offset + 10,
28796 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28797 // No Exif data, might be XMP data instead
28801 // Check for the ASCII code for "Exif" (0x45786966):
28802 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28803 // No Exif data, might be XMP data instead
28806 if (tiffOffset + 8 > dataView.byteLength) {
28807 Roo.log('Invalid Exif data: Invalid segment size.');
28810 // Check for the two null bytes:
28811 if (dataView.getUint16(offset + 8) !== 0x0000) {
28812 Roo.log('Invalid Exif data: Missing byte alignment offset.');
28815 // Check the byte alignment:
28816 switch (dataView.getUint16(tiffOffset)) {
28818 littleEndian = true;
28821 littleEndian = false;
28824 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
28827 // Check for the TIFF tag marker (0x002A):
28828 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
28829 Roo.log('Invalid Exif data: Missing TIFF marker.');
28832 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
28833 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
28835 this.parseExifTags(
28838 tiffOffset + dirOffset,
28843 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
28848 if (dirOffset + 6 > dataView.byteLength) {
28849 Roo.log('Invalid Exif data: Invalid directory offset.');
28852 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
28853 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
28854 if (dirEndOffset + 4 > dataView.byteLength) {
28855 Roo.log('Invalid Exif data: Invalid directory size.');
28858 for (i = 0; i < tagsNumber; i += 1) {
28862 dirOffset + 2 + 12 * i, // tag offset
28866 // Return the offset to the next directory:
28867 return dataView.getUint32(dirEndOffset, littleEndian);
28870 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
28872 var tag = dataView.getUint16(offset, littleEndian);
28874 this.exif[tag] = this.getExifValue(
28878 dataView.getUint16(offset + 2, littleEndian), // tag type
28879 dataView.getUint32(offset + 4, littleEndian), // tag length
28884 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
28886 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
28895 Roo.log('Invalid Exif data: Invalid tag type.');
28899 tagSize = tagType.size * length;
28900 // Determine if the value is contained in the dataOffset bytes,
28901 // or if the value at the dataOffset is a pointer to the actual data:
28902 dataOffset = tagSize > 4 ?
28903 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
28904 if (dataOffset + tagSize > dataView.byteLength) {
28905 Roo.log('Invalid Exif data: Invalid data offset.');
28908 if (length === 1) {
28909 return tagType.getValue(dataView, dataOffset, littleEndian);
28912 for (i = 0; i < length; i += 1) {
28913 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
28916 if (tagType.ascii) {
28918 // Concatenate the chars:
28919 for (i = 0; i < values.length; i += 1) {
28921 // Ignore the terminating NULL byte(s):
28922 if (c === '\u0000') {
28934 Roo.apply(Roo.bootstrap.UploadCropbox, {
28936 'Orientation': 0x0112
28940 1: 0, //'top-left',
28942 3: 180, //'bottom-right',
28943 // 4: 'bottom-left',
28945 6: 90, //'right-top',
28946 // 7: 'right-bottom',
28947 8: 270 //'left-bottom'
28951 // byte, 8-bit unsigned int:
28953 getValue: function (dataView, dataOffset) {
28954 return dataView.getUint8(dataOffset);
28958 // ascii, 8-bit byte:
28960 getValue: function (dataView, dataOffset) {
28961 return String.fromCharCode(dataView.getUint8(dataOffset));
28966 // short, 16 bit int:
28968 getValue: function (dataView, dataOffset, littleEndian) {
28969 return dataView.getUint16(dataOffset, littleEndian);
28973 // long, 32 bit int:
28975 getValue: function (dataView, dataOffset, littleEndian) {
28976 return dataView.getUint32(dataOffset, littleEndian);
28980 // rational = two long values, first is numerator, second is denominator:
28982 getValue: function (dataView, dataOffset, littleEndian) {
28983 return dataView.getUint32(dataOffset, littleEndian) /
28984 dataView.getUint32(dataOffset + 4, littleEndian);
28988 // slong, 32 bit signed int:
28990 getValue: function (dataView, dataOffset, littleEndian) {
28991 return dataView.getInt32(dataOffset, littleEndian);
28995 // srational, two slongs, first is numerator, second is denominator:
28997 getValue: function (dataView, dataOffset, littleEndian) {
28998 return dataView.getInt32(dataOffset, littleEndian) /
28999 dataView.getInt32(dataOffset + 4, littleEndian);
29009 cls : 'btn-group roo-upload-cropbox-rotate-left',
29010 action : 'rotate-left',
29014 cls : 'btn btn-default',
29015 html : '<i class="fa fa-undo"></i>'
29021 cls : 'btn-group roo-upload-cropbox-picture',
29022 action : 'picture',
29026 cls : 'btn btn-default',
29027 html : '<i class="fa fa-picture-o"></i>'
29033 cls : 'btn-group roo-upload-cropbox-rotate-right',
29034 action : 'rotate-right',
29038 cls : 'btn btn-default',
29039 html : '<i class="fa fa-repeat"></i>'
29047 cls : 'btn-group roo-upload-cropbox-rotate-left',
29048 action : 'rotate-left',
29052 cls : 'btn btn-default',
29053 html : '<i class="fa fa-undo"></i>'
29059 cls : 'btn-group roo-upload-cropbox-download',
29060 action : 'download',
29064 cls : 'btn btn-default',
29065 html : '<i class="fa fa-download"></i>'
29071 cls : 'btn-group roo-upload-cropbox-crop',
29076 cls : 'btn btn-default',
29077 html : '<i class="fa fa-crop"></i>'
29083 cls : 'btn-group roo-upload-cropbox-trash',
29088 cls : 'btn btn-default',
29089 html : '<i class="fa fa-trash"></i>'
29095 cls : 'btn-group roo-upload-cropbox-rotate-right',
29096 action : 'rotate-right',
29100 cls : 'btn btn-default',
29101 html : '<i class="fa fa-repeat"></i>'
29109 cls : 'btn-group roo-upload-cropbox-rotate-left',
29110 action : 'rotate-left',
29114 cls : 'btn btn-default',
29115 html : '<i class="fa fa-undo"></i>'
29121 cls : 'btn-group roo-upload-cropbox-rotate-right',
29122 action : 'rotate-right',
29126 cls : 'btn btn-default',
29127 html : '<i class="fa fa-repeat"></i>'
29140 * @class Roo.bootstrap.DocumentManager
29141 * @extends Roo.bootstrap.Component
29142 * Bootstrap DocumentManager class
29143 * @cfg {String} paramName default 'imageUpload'
29144 * @cfg {String} toolTipName default 'filename'
29145 * @cfg {String} method default POST
29146 * @cfg {String} url action url
29147 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
29148 * @cfg {Boolean} multiple multiple upload default true
29149 * @cfg {Number} thumbSize default 300
29150 * @cfg {String} fieldLabel
29151 * @cfg {Number} labelWidth default 4
29152 * @cfg {String} labelAlign (left|top) default left
29153 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
29154 * @cfg {Number} labellg set the width of label (1-12)
29155 * @cfg {Number} labelmd set the width of label (1-12)
29156 * @cfg {Number} labelsm set the width of label (1-12)
29157 * @cfg {Number} labelxs set the width of label (1-12)
29160 * Create a new DocumentManager
29161 * @param {Object} config The config object
29164 Roo.bootstrap.DocumentManager = function(config){
29165 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
29168 this.delegates = [];
29173 * Fire when initial the DocumentManager
29174 * @param {Roo.bootstrap.DocumentManager} this
29179 * inspect selected file
29180 * @param {Roo.bootstrap.DocumentManager} this
29181 * @param {File} file
29186 * Fire when xhr load exception
29187 * @param {Roo.bootstrap.DocumentManager} this
29188 * @param {XMLHttpRequest} xhr
29190 "exception" : true,
29192 * @event afterupload
29193 * Fire when xhr load exception
29194 * @param {Roo.bootstrap.DocumentManager} this
29195 * @param {XMLHttpRequest} xhr
29197 "afterupload" : true,
29200 * prepare the form data
29201 * @param {Roo.bootstrap.DocumentManager} this
29202 * @param {Object} formData
29207 * Fire when remove the file
29208 * @param {Roo.bootstrap.DocumentManager} this
29209 * @param {Object} file
29214 * Fire after refresh the file
29215 * @param {Roo.bootstrap.DocumentManager} this
29220 * Fire after click the image
29221 * @param {Roo.bootstrap.DocumentManager} this
29222 * @param {Object} file
29227 * Fire when upload a image and editable set to true
29228 * @param {Roo.bootstrap.DocumentManager} this
29229 * @param {Object} file
29233 * @event beforeselectfile
29234 * Fire before select file
29235 * @param {Roo.bootstrap.DocumentManager} this
29237 "beforeselectfile" : true,
29240 * Fire before process file
29241 * @param {Roo.bootstrap.DocumentManager} this
29242 * @param {Object} file
29246 * @event previewrendered
29247 * Fire when preview rendered
29248 * @param {Roo.bootstrap.DocumentManager} this
29249 * @param {Object} file
29251 "previewrendered" : true,
29254 "previewResize" : true
29259 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
29268 paramName : 'imageUpload',
29269 toolTipName : 'filename',
29272 labelAlign : 'left',
29282 getAutoCreate : function()
29284 var managerWidget = {
29286 cls : 'roo-document-manager',
29290 cls : 'roo-document-manager-selector',
29295 cls : 'roo-document-manager-uploader',
29299 cls : 'roo-document-manager-upload-btn',
29300 html : '<i class="fa fa-plus"></i>'
29311 cls : 'column col-md-12',
29316 if(this.fieldLabel.length){
29321 cls : 'column col-md-12',
29322 html : this.fieldLabel
29326 cls : 'column col-md-12',
29331 if(this.labelAlign == 'left'){
29336 html : this.fieldLabel
29345 if(this.labelWidth > 12){
29346 content[0].style = "width: " + this.labelWidth + 'px';
29349 if(this.labelWidth < 13 && this.labelmd == 0){
29350 this.labelmd = this.labelWidth;
29353 if(this.labellg > 0){
29354 content[0].cls += ' col-lg-' + this.labellg;
29355 content[1].cls += ' col-lg-' + (12 - this.labellg);
29358 if(this.labelmd > 0){
29359 content[0].cls += ' col-md-' + this.labelmd;
29360 content[1].cls += ' col-md-' + (12 - this.labelmd);
29363 if(this.labelsm > 0){
29364 content[0].cls += ' col-sm-' + this.labelsm;
29365 content[1].cls += ' col-sm-' + (12 - this.labelsm);
29368 if(this.labelxs > 0){
29369 content[0].cls += ' col-xs-' + this.labelxs;
29370 content[1].cls += ' col-xs-' + (12 - this.labelxs);
29378 cls : 'row clearfix',
29386 initEvents : function()
29388 this.managerEl = this.el.select('.roo-document-manager', true).first();
29389 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29391 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
29392 this.selectorEl.hide();
29395 this.selectorEl.attr('multiple', 'multiple');
29398 this.selectorEl.on('change', this.onFileSelected, this);
29400 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
29401 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29403 this.uploader.on('click', this.onUploaderClick, this);
29405 this.renderProgressDialog();
29409 window.addEventListener("resize", function() { _this.refresh(); } );
29411 this.fireEvent('initial', this);
29414 renderProgressDialog : function()
29418 this.progressDialog = new Roo.bootstrap.Modal({
29419 cls : 'roo-document-manager-progress-dialog',
29420 allow_close : false,
29431 btnclick : function() {
29432 _this.uploadCancel();
29438 this.progressDialog.render(Roo.get(document.body));
29440 this.progress = new Roo.bootstrap.Progress({
29441 cls : 'roo-document-manager-progress',
29446 this.progress.render(this.progressDialog.getChildContainer());
29448 this.progressBar = new Roo.bootstrap.ProgressBar({
29449 cls : 'roo-document-manager-progress-bar',
29452 aria_valuemax : 12,
29456 this.progressBar.render(this.progress.getChildContainer());
29459 onUploaderClick : function(e)
29461 e.preventDefault();
29463 if(this.fireEvent('beforeselectfile', this) != false){
29464 this.selectorEl.dom.click();
29469 onFileSelected : function(e)
29471 e.preventDefault();
29473 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
29477 Roo.each(this.selectorEl.dom.files, function(file){
29478 if(this.fireEvent('inspect', this, file) != false){
29479 this.files.push(file);
29489 this.selectorEl.dom.value = '';
29491 if(!this.files || !this.files.length){
29495 if(this.boxes > 0 && this.files.length > this.boxes){
29496 this.files = this.files.slice(0, this.boxes);
29499 this.uploader.show();
29501 if(this.boxes > 0 && this.files.length > this.boxes - 1){
29502 this.uploader.hide();
29511 Roo.each(this.files, function(file){
29513 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29514 var f = this.renderPreview(file);
29519 if(file.type.indexOf('image') != -1){
29520 this.delegates.push(
29522 _this.process(file);
29523 }).createDelegate(this)
29531 _this.process(file);
29532 }).createDelegate(this)
29537 this.files = files;
29539 this.delegates = this.delegates.concat(docs);
29541 if(!this.delegates.length){
29546 this.progressBar.aria_valuemax = this.delegates.length;
29553 arrange : function()
29555 if(!this.delegates.length){
29556 this.progressDialog.hide();
29561 var delegate = this.delegates.shift();
29563 this.progressDialog.show();
29565 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
29567 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
29572 refresh : function()
29574 this.uploader.show();
29576 if(this.boxes > 0 && this.files.length > this.boxes - 1){
29577 this.uploader.hide();
29580 Roo.isTouch ? this.closable(false) : this.closable(true);
29582 this.fireEvent('refresh', this);
29585 onRemove : function(e, el, o)
29587 e.preventDefault();
29589 this.fireEvent('remove', this, o);
29593 remove : function(o)
29597 Roo.each(this.files, function(file){
29598 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
29607 this.files = files;
29614 Roo.each(this.files, function(file){
29619 file.target.remove();
29628 onClick : function(e, el, o)
29630 e.preventDefault();
29632 this.fireEvent('click', this, o);
29636 closable : function(closable)
29638 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
29640 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29652 xhrOnLoad : function(xhr)
29654 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29658 if (xhr.readyState !== 4) {
29660 this.fireEvent('exception', this, xhr);
29664 var response = Roo.decode(xhr.responseText);
29666 if(!response.success){
29668 this.fireEvent('exception', this, xhr);
29672 var file = this.renderPreview(response.data);
29674 this.files.push(file);
29678 this.fireEvent('afterupload', this, xhr);
29682 xhrOnError : function(xhr)
29684 Roo.log('xhr on error');
29686 var response = Roo.decode(xhr.responseText);
29693 process : function(file)
29695 if(this.fireEvent('process', this, file) !== false){
29696 if(this.editable && file.type.indexOf('image') != -1){
29697 this.fireEvent('edit', this, file);
29701 this.uploadStart(file, false);
29708 uploadStart : function(file, crop)
29710 this.xhr = new XMLHttpRequest();
29712 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29717 file.xhr = this.xhr;
29719 this.managerEl.createChild({
29721 cls : 'roo-document-manager-loading',
29725 tooltip : file.name,
29726 cls : 'roo-document-manager-thumb',
29727 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29733 this.xhr.open(this.method, this.url, true);
29736 "Accept": "application/json",
29737 "Cache-Control": "no-cache",
29738 "X-Requested-With": "XMLHttpRequest"
29741 for (var headerName in headers) {
29742 var headerValue = headers[headerName];
29744 this.xhr.setRequestHeader(headerName, headerValue);
29750 this.xhr.onload = function()
29752 _this.xhrOnLoad(_this.xhr);
29755 this.xhr.onerror = function()
29757 _this.xhrOnError(_this.xhr);
29760 var formData = new FormData();
29762 formData.append('returnHTML', 'NO');
29765 formData.append('crop', crop);
29768 formData.append(this.paramName, file, file.name);
29775 if(this.fireEvent('prepare', this, formData, options) != false){
29777 if(options.manually){
29781 this.xhr.send(formData);
29785 this.uploadCancel();
29788 uploadCancel : function()
29794 this.delegates = [];
29796 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29803 renderPreview : function(file)
29805 if(typeof(file.target) != 'undefined' && file.target){
29809 var img_src = encodeURI(baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename);
29811 var previewEl = this.managerEl.createChild({
29813 cls : 'roo-document-manager-preview',
29817 tooltip : file[this.toolTipName],
29818 cls : 'roo-document-manager-thumb',
29819 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + img_src + '">'
29824 html : '<i class="fa fa-times-circle"></i>'
29829 var close = previewEl.select('button.close', true).first();
29831 close.on('click', this.onRemove, this, file);
29833 file.target = previewEl;
29835 var image = previewEl.select('img', true).first();
29839 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
29841 image.on('click', this.onClick, this, file);
29843 this.fireEvent('previewrendered', this, file);
29849 onPreviewLoad : function(file, image)
29851 if(typeof(file.target) == 'undefined' || !file.target){
29855 var width = image.dom.naturalWidth || image.dom.width;
29856 var height = image.dom.naturalHeight || image.dom.height;
29858 if(!this.previewResize) {
29862 if(width > height){
29863 file.target.addClass('wide');
29867 file.target.addClass('tall');
29872 uploadFromSource : function(file, crop)
29874 this.xhr = new XMLHttpRequest();
29876 this.managerEl.createChild({
29878 cls : 'roo-document-manager-loading',
29882 tooltip : file.name,
29883 cls : 'roo-document-manager-thumb',
29884 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29890 this.xhr.open(this.method, this.url, true);
29893 "Accept": "application/json",
29894 "Cache-Control": "no-cache",
29895 "X-Requested-With": "XMLHttpRequest"
29898 for (var headerName in headers) {
29899 var headerValue = headers[headerName];
29901 this.xhr.setRequestHeader(headerName, headerValue);
29907 this.xhr.onload = function()
29909 _this.xhrOnLoad(_this.xhr);
29912 this.xhr.onerror = function()
29914 _this.xhrOnError(_this.xhr);
29917 var formData = new FormData();
29919 formData.append('returnHTML', 'NO');
29921 formData.append('crop', crop);
29923 if(typeof(file.filename) != 'undefined'){
29924 formData.append('filename', file.filename);
29927 if(typeof(file.mimetype) != 'undefined'){
29928 formData.append('mimetype', file.mimetype);
29933 if(this.fireEvent('prepare', this, formData) != false){
29934 this.xhr.send(formData);
29944 * @class Roo.bootstrap.DocumentViewer
29945 * @extends Roo.bootstrap.Component
29946 * Bootstrap DocumentViewer class
29947 * @cfg {Boolean} showDownload (true|false) show download button (default true)
29948 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
29951 * Create a new DocumentViewer
29952 * @param {Object} config The config object
29955 Roo.bootstrap.DocumentViewer = function(config){
29956 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
29961 * Fire after initEvent
29962 * @param {Roo.bootstrap.DocumentViewer} this
29968 * @param {Roo.bootstrap.DocumentViewer} this
29973 * Fire after download button
29974 * @param {Roo.bootstrap.DocumentViewer} this
29979 * Fire after trash button
29980 * @param {Roo.bootstrap.DocumentViewer} this
29987 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
29989 showDownload : true,
29993 getAutoCreate : function()
29997 cls : 'roo-document-viewer',
30001 cls : 'roo-document-viewer-body',
30005 cls : 'roo-document-viewer-thumb',
30009 cls : 'roo-document-viewer-image'
30017 cls : 'roo-document-viewer-footer',
30020 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
30024 cls : 'btn-group roo-document-viewer-download',
30028 cls : 'btn btn-default',
30029 html : '<i class="fa fa-download"></i>'
30035 cls : 'btn-group roo-document-viewer-trash',
30039 cls : 'btn btn-default',
30040 html : '<i class="fa fa-trash"></i>'
30053 initEvents : function()
30055 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
30056 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
30058 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
30059 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
30061 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
30062 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
30064 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
30065 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
30067 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
30068 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
30070 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
30071 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
30073 this.bodyEl.on('click', this.onClick, this);
30074 this.downloadBtn.on('click', this.onDownload, this);
30075 this.trashBtn.on('click', this.onTrash, this);
30077 this.downloadBtn.hide();
30078 this.trashBtn.hide();
30080 if(this.showDownload){
30081 this.downloadBtn.show();
30084 if(this.showTrash){
30085 this.trashBtn.show();
30088 if(!this.showDownload && !this.showTrash) {
30089 this.footerEl.hide();
30094 initial : function()
30096 this.fireEvent('initial', this);
30100 onClick : function(e)
30102 e.preventDefault();
30104 this.fireEvent('click', this);
30107 onDownload : function(e)
30109 e.preventDefault();
30111 this.fireEvent('download', this);
30114 onTrash : function(e)
30116 e.preventDefault();
30118 this.fireEvent('trash', this);
30130 * @class Roo.bootstrap.NavProgressBar
30131 * @extends Roo.bootstrap.Component
30132 * Bootstrap NavProgressBar class
30135 * Create a new nav progress bar
30136 * @param {Object} config The config object
30139 Roo.bootstrap.NavProgressBar = function(config){
30140 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
30142 this.bullets = this.bullets || [];
30144 // Roo.bootstrap.NavProgressBar.register(this);
30148 * Fires when the active item changes
30149 * @param {Roo.bootstrap.NavProgressBar} this
30150 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
30151 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
30158 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
30163 getAutoCreate : function()
30165 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
30169 cls : 'roo-navigation-bar-group',
30173 cls : 'roo-navigation-top-bar'
30177 cls : 'roo-navigation-bullets-bar',
30181 cls : 'roo-navigation-bar'
30188 cls : 'roo-navigation-bottom-bar'
30198 initEvents: function()
30203 onRender : function(ct, position)
30205 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30207 if(this.bullets.length){
30208 Roo.each(this.bullets, function(b){
30217 addItem : function(cfg)
30219 var item = new Roo.bootstrap.NavProgressItem(cfg);
30221 item.parentId = this.id;
30222 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
30225 var top = new Roo.bootstrap.Element({
30227 cls : 'roo-navigation-bar-text'
30230 var bottom = new Roo.bootstrap.Element({
30232 cls : 'roo-navigation-bar-text'
30235 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
30236 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
30238 var topText = new Roo.bootstrap.Element({
30240 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
30243 var bottomText = new Roo.bootstrap.Element({
30245 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
30248 topText.onRender(top.el, null);
30249 bottomText.onRender(bottom.el, null);
30252 item.bottomEl = bottom;
30255 this.barItems.push(item);
30260 getActive : function()
30262 var active = false;
30264 Roo.each(this.barItems, function(v){
30266 if (!v.isActive()) {
30278 setActiveItem : function(item)
30282 Roo.each(this.barItems, function(v){
30283 if (v.rid == item.rid) {
30287 if (v.isActive()) {
30288 v.setActive(false);
30293 item.setActive(true);
30295 this.fireEvent('changed', this, item, prev);
30298 getBarItem: function(rid)
30302 Roo.each(this.barItems, function(e) {
30303 if (e.rid != rid) {
30314 indexOfItem : function(item)
30318 Roo.each(this.barItems, function(v, i){
30320 if (v.rid != item.rid) {
30331 setActiveNext : function()
30333 var i = this.indexOfItem(this.getActive());
30335 if (i > this.barItems.length) {
30339 this.setActiveItem(this.barItems[i+1]);
30342 setActivePrev : function()
30344 var i = this.indexOfItem(this.getActive());
30350 this.setActiveItem(this.barItems[i-1]);
30353 format : function()
30355 if(!this.barItems.length){
30359 var width = 100 / this.barItems.length;
30361 Roo.each(this.barItems, function(i){
30362 i.el.setStyle('width', width + '%');
30363 i.topEl.el.setStyle('width', width + '%');
30364 i.bottomEl.el.setStyle('width', width + '%');
30373 * Nav Progress Item
30378 * @class Roo.bootstrap.NavProgressItem
30379 * @extends Roo.bootstrap.Component
30380 * Bootstrap NavProgressItem class
30381 * @cfg {String} rid the reference id
30382 * @cfg {Boolean} active (true|false) Is item active default false
30383 * @cfg {Boolean} disabled (true|false) Is item active default false
30384 * @cfg {String} html
30385 * @cfg {String} position (top|bottom) text position default bottom
30386 * @cfg {String} icon show icon instead of number
30389 * Create a new NavProgressItem
30390 * @param {Object} config The config object
30392 Roo.bootstrap.NavProgressItem = function(config){
30393 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
30398 * The raw click event for the entire grid.
30399 * @param {Roo.bootstrap.NavProgressItem} this
30400 * @param {Roo.EventObject} e
30407 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
30413 position : 'bottom',
30416 getAutoCreate : function()
30418 var iconCls = 'roo-navigation-bar-item-icon';
30420 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
30424 cls: 'roo-navigation-bar-item',
30434 cfg.cls += ' active';
30437 cfg.cls += ' disabled';
30443 disable : function()
30445 this.setDisabled(true);
30448 enable : function()
30450 this.setDisabled(false);
30453 initEvents: function()
30455 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
30457 this.iconEl.on('click', this.onClick, this);
30460 onClick : function(e)
30462 e.preventDefault();
30468 if(this.fireEvent('click', this, e) === false){
30472 this.parent().setActiveItem(this);
30475 isActive: function ()
30477 return this.active;
30480 setActive : function(state)
30482 if(this.active == state){
30486 this.active = state;
30489 this.el.addClass('active');
30493 this.el.removeClass('active');
30498 setDisabled : function(state)
30500 if(this.disabled == state){
30504 this.disabled = state;
30507 this.el.addClass('disabled');
30511 this.el.removeClass('disabled');
30514 tooltipEl : function()
30516 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
30529 * @class Roo.bootstrap.FieldLabel
30530 * @extends Roo.bootstrap.Component
30531 * Bootstrap FieldLabel class
30532 * @cfg {String} html contents of the element
30533 * @cfg {String} tag tag of the element default label
30534 * @cfg {String} cls class of the element
30535 * @cfg {String} target label target
30536 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
30537 * @cfg {String} invalidClass DEPRICATED - BS4 uses is-invalid
30538 * @cfg {String} validClass DEPRICATED - BS4 uses is-valid
30539 * @cfg {String} iconTooltip default "This field is required"
30540 * @cfg {String} indicatorpos (left|right) default left
30543 * Create a new FieldLabel
30544 * @param {Object} config The config object
30547 Roo.bootstrap.FieldLabel = function(config){
30548 Roo.bootstrap.Element.superclass.constructor.call(this, config);
30553 * Fires after the field has been marked as invalid.
30554 * @param {Roo.form.FieldLabel} this
30555 * @param {String} msg The validation message
30560 * Fires after the field has been validated with no errors.
30561 * @param {Roo.form.FieldLabel} this
30567 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
30574 invalidClass : 'has-warning',
30575 validClass : 'has-success',
30576 iconTooltip : 'This field is required',
30577 indicatorpos : 'left',
30579 getAutoCreate : function(){
30582 if (!this.allowBlank) {
30588 cls : 'roo-bootstrap-field-label ' + this.cls,
30593 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star ' + cls,
30594 tooltip : this.iconTooltip
30603 if(this.indicatorpos == 'right'){
30606 cls : 'roo-bootstrap-field-label ' + this.cls,
30615 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star '+ cls,
30616 tooltip : this.iconTooltip
30625 initEvents: function()
30627 Roo.bootstrap.Element.superclass.initEvents.call(this);
30629 this.indicator = this.indicatorEl();
30631 if(this.indicator){
30632 this.indicator.removeClass('visible');
30633 this.indicator.addClass('invisible');
30636 Roo.bootstrap.FieldLabel.register(this);
30639 indicatorEl : function()
30641 var indicator = this.el.select('i.roo-required-indicator',true).first();
30652 * Mark this field as valid
30654 markValid : function()
30656 if(this.indicator){
30657 this.indicator.removeClass('visible');
30658 this.indicator.addClass('invisible');
30660 if (Roo.bootstrap.version == 3) {
30661 this.el.removeClass(this.invalidClass);
30662 this.el.addClass(this.validClass);
30664 this.el.removeClass('is-invalid');
30665 this.el.addClass('is-valid');
30669 this.fireEvent('valid', this);
30673 * Mark this field as invalid
30674 * @param {String} msg The validation message
30676 markInvalid : function(msg)
30678 if(this.indicator){
30679 this.indicator.removeClass('invisible');
30680 this.indicator.addClass('visible');
30682 if (Roo.bootstrap.version == 3) {
30683 this.el.removeClass(this.validClass);
30684 this.el.addClass(this.invalidClass);
30686 this.el.removeClass('is-valid');
30687 this.el.addClass('is-invalid');
30691 this.fireEvent('invalid', this, msg);
30697 Roo.apply(Roo.bootstrap.FieldLabel, {
30702 * register a FieldLabel Group
30703 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
30705 register : function(label)
30707 if(this.groups.hasOwnProperty(label.target)){
30711 this.groups[label.target] = label;
30715 * fetch a FieldLabel Group based on the target
30716 * @param {string} target
30717 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
30719 get: function(target) {
30720 if (typeof(this.groups[target]) == 'undefined') {
30724 return this.groups[target] ;
30733 * page DateSplitField.
30739 * @class Roo.bootstrap.DateSplitField
30740 * @extends Roo.bootstrap.Component
30741 * Bootstrap DateSplitField class
30742 * @cfg {string} fieldLabel - the label associated
30743 * @cfg {Number} labelWidth set the width of label (0-12)
30744 * @cfg {String} labelAlign (top|left)
30745 * @cfg {Boolean} dayAllowBlank (true|false) default false
30746 * @cfg {Boolean} monthAllowBlank (true|false) default false
30747 * @cfg {Boolean} yearAllowBlank (true|false) default false
30748 * @cfg {string} dayPlaceholder
30749 * @cfg {string} monthPlaceholder
30750 * @cfg {string} yearPlaceholder
30751 * @cfg {string} dayFormat default 'd'
30752 * @cfg {string} monthFormat default 'm'
30753 * @cfg {string} yearFormat default 'Y'
30754 * @cfg {Number} labellg set the width of label (1-12)
30755 * @cfg {Number} labelmd set the width of label (1-12)
30756 * @cfg {Number} labelsm set the width of label (1-12)
30757 * @cfg {Number} labelxs set the width of label (1-12)
30761 * Create a new DateSplitField
30762 * @param {Object} config The config object
30765 Roo.bootstrap.DateSplitField = function(config){
30766 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
30772 * getting the data of years
30773 * @param {Roo.bootstrap.DateSplitField} this
30774 * @param {Object} years
30779 * getting the data of days
30780 * @param {Roo.bootstrap.DateSplitField} this
30781 * @param {Object} days
30786 * Fires after the field has been marked as invalid.
30787 * @param {Roo.form.Field} this
30788 * @param {String} msg The validation message
30793 * Fires after the field has been validated with no errors.
30794 * @param {Roo.form.Field} this
30800 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
30803 labelAlign : 'top',
30805 dayAllowBlank : false,
30806 monthAllowBlank : false,
30807 yearAllowBlank : false,
30808 dayPlaceholder : '',
30809 monthPlaceholder : '',
30810 yearPlaceholder : '',
30814 isFormField : true,
30820 getAutoCreate : function()
30824 cls : 'row roo-date-split-field-group',
30829 cls : 'form-hidden-field roo-date-split-field-group-value',
30835 var labelCls = 'col-md-12';
30836 var contentCls = 'col-md-4';
30838 if(this.fieldLabel){
30842 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
30846 html : this.fieldLabel
30851 if(this.labelAlign == 'left'){
30853 if(this.labelWidth > 12){
30854 label.style = "width: " + this.labelWidth + 'px';
30857 if(this.labelWidth < 13 && this.labelmd == 0){
30858 this.labelmd = this.labelWidth;
30861 if(this.labellg > 0){
30862 labelCls = ' col-lg-' + this.labellg;
30863 contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
30866 if(this.labelmd > 0){
30867 labelCls = ' col-md-' + this.labelmd;
30868 contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
30871 if(this.labelsm > 0){
30872 labelCls = ' col-sm-' + this.labelsm;
30873 contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
30876 if(this.labelxs > 0){
30877 labelCls = ' col-xs-' + this.labelxs;
30878 contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
30882 label.cls += ' ' + labelCls;
30884 cfg.cn.push(label);
30887 Roo.each(['day', 'month', 'year'], function(t){
30890 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
30897 inputEl: function ()
30899 return this.el.select('.roo-date-split-field-group-value', true).first();
30902 onRender : function(ct, position)
30906 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30908 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
30910 this.dayField = new Roo.bootstrap.ComboBox({
30911 allowBlank : this.dayAllowBlank,
30912 alwaysQuery : true,
30913 displayField : 'value',
30916 forceSelection : true,
30918 placeholder : this.dayPlaceholder,
30919 selectOnFocus : true,
30920 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30921 triggerAction : 'all',
30923 valueField : 'value',
30924 store : new Roo.data.SimpleStore({
30925 data : (function() {
30927 _this.fireEvent('days', _this, days);
30930 fields : [ 'value' ]
30933 select : function (_self, record, index)
30935 _this.setValue(_this.getValue());
30940 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
30942 this.monthField = new Roo.bootstrap.MonthField({
30943 after : '<i class=\"fa fa-calendar\"></i>',
30944 allowBlank : this.monthAllowBlank,
30945 placeholder : this.monthPlaceholder,
30948 render : function (_self)
30950 this.el.select('span.input-group-addon', true).first().on('click', function(e){
30951 e.preventDefault();
30955 select : function (_self, oldvalue, newvalue)
30957 _this.setValue(_this.getValue());
30962 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
30964 this.yearField = new Roo.bootstrap.ComboBox({
30965 allowBlank : this.yearAllowBlank,
30966 alwaysQuery : true,
30967 displayField : 'value',
30970 forceSelection : true,
30972 placeholder : this.yearPlaceholder,
30973 selectOnFocus : true,
30974 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30975 triggerAction : 'all',
30977 valueField : 'value',
30978 store : new Roo.data.SimpleStore({
30979 data : (function() {
30981 _this.fireEvent('years', _this, years);
30984 fields : [ 'value' ]
30987 select : function (_self, record, index)
30989 _this.setValue(_this.getValue());
30994 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
30997 setValue : function(v, format)
30999 this.inputEl.dom.value = v;
31001 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
31003 var d = Date.parseDate(v, f);
31010 this.setDay(d.format(this.dayFormat));
31011 this.setMonth(d.format(this.monthFormat));
31012 this.setYear(d.format(this.yearFormat));
31019 setDay : function(v)
31021 this.dayField.setValue(v);
31022 this.inputEl.dom.value = this.getValue();
31027 setMonth : function(v)
31029 this.monthField.setValue(v, true);
31030 this.inputEl.dom.value = this.getValue();
31035 setYear : function(v)
31037 this.yearField.setValue(v);
31038 this.inputEl.dom.value = this.getValue();
31043 getDay : function()
31045 return this.dayField.getValue();
31048 getMonth : function()
31050 return this.monthField.getValue();
31053 getYear : function()
31055 return this.yearField.getValue();
31058 getValue : function()
31060 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
31062 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
31072 this.inputEl.dom.value = '';
31077 validate : function()
31079 var d = this.dayField.validate();
31080 var m = this.monthField.validate();
31081 var y = this.yearField.validate();
31086 (!this.dayAllowBlank && !d) ||
31087 (!this.monthAllowBlank && !m) ||
31088 (!this.yearAllowBlank && !y)
31093 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
31102 this.markInvalid();
31107 markValid : function()
31110 var label = this.el.select('label', true).first();
31111 var icon = this.el.select('i.fa-star', true).first();
31117 this.fireEvent('valid', this);
31121 * Mark this field as invalid
31122 * @param {String} msg The validation message
31124 markInvalid : function(msg)
31127 var label = this.el.select('label', true).first();
31128 var icon = this.el.select('i.fa-star', true).first();
31130 if(label && !icon){
31131 this.el.select('.roo-date-split-field-label', true).createChild({
31133 cls : 'text-danger fa fa-lg fa-star',
31134 tooltip : 'This field is required',
31135 style : 'margin-right:5px;'
31139 this.fireEvent('invalid', this, msg);
31142 clearInvalid : function()
31144 var label = this.el.select('label', true).first();
31145 var icon = this.el.select('i.fa-star', true).first();
31151 this.fireEvent('valid', this);
31154 getName: function()
31164 * http://masonry.desandro.com
31166 * The idea is to render all the bricks based on vertical width...
31168 * The original code extends 'outlayer' - we might need to use that....
31174 * @class Roo.bootstrap.LayoutMasonry
31175 * @extends Roo.bootstrap.Component
31176 * Bootstrap Layout Masonry class
31179 * Create a new Element
31180 * @param {Object} config The config object
31183 Roo.bootstrap.LayoutMasonry = function(config){
31185 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
31189 Roo.bootstrap.LayoutMasonry.register(this);
31195 * Fire after layout the items
31196 * @param {Roo.bootstrap.LayoutMasonry} this
31197 * @param {Roo.EventObject} e
31204 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
31207 * @cfg {Boolean} isLayoutInstant = no animation?
31209 isLayoutInstant : false, // needed?
31212 * @cfg {Number} boxWidth width of the columns
31217 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
31222 * @cfg {Number} padWidth padding below box..
31227 * @cfg {Number} gutter gutter width..
31232 * @cfg {Number} maxCols maximum number of columns
31238 * @cfg {Boolean} isAutoInitial defalut true
31240 isAutoInitial : true,
31245 * @cfg {Boolean} isHorizontal defalut false
31247 isHorizontal : false,
31249 currentSize : null,
31255 bricks: null, //CompositeElement
31259 _isLayoutInited : false,
31261 // isAlternative : false, // only use for vertical layout...
31264 * @cfg {Number} alternativePadWidth padding below box..
31266 alternativePadWidth : 50,
31268 selectedBrick : [],
31270 getAutoCreate : function(){
31272 var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
31276 cls: 'blog-masonary-wrapper ' + this.cls,
31278 cls : 'mas-boxes masonary'
31285 getChildContainer: function( )
31287 if (this.boxesEl) {
31288 return this.boxesEl;
31291 this.boxesEl = this.el.select('.mas-boxes').first();
31293 return this.boxesEl;
31297 initEvents : function()
31301 if(this.isAutoInitial){
31302 Roo.log('hook children rendered');
31303 this.on('childrenrendered', function() {
31304 Roo.log('children rendered');
31310 initial : function()
31312 this.selectedBrick = [];
31314 this.currentSize = this.el.getBox(true);
31316 Roo.EventManager.onWindowResize(this.resize, this);
31318 if(!this.isAutoInitial){
31326 //this.layout.defer(500,this);
31330 resize : function()
31332 var cs = this.el.getBox(true);
31335 this.currentSize.width == cs.width &&
31336 this.currentSize.x == cs.x &&
31337 this.currentSize.height == cs.height &&
31338 this.currentSize.y == cs.y
31340 Roo.log("no change in with or X or Y");
31344 this.currentSize = cs;
31350 layout : function()
31352 this._resetLayout();
31354 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
31356 this.layoutItems( isInstant );
31358 this._isLayoutInited = true;
31360 this.fireEvent('layout', this);
31364 _resetLayout : function()
31366 if(this.isHorizontal){
31367 this.horizontalMeasureColumns();
31371 this.verticalMeasureColumns();
31375 verticalMeasureColumns : function()
31377 this.getContainerWidth();
31379 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
31380 // this.colWidth = Math.floor(this.containerWidth * 0.8);
31384 var boxWidth = this.boxWidth + this.padWidth;
31386 if(this.containerWidth < this.boxWidth){
31387 boxWidth = this.containerWidth
31390 var containerWidth = this.containerWidth;
31392 var cols = Math.floor(containerWidth / boxWidth);
31394 this.cols = Math.max( cols, 1 );
31396 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
31398 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
31400 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
31402 this.colWidth = boxWidth + avail - this.padWidth;
31404 this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
31405 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
31408 horizontalMeasureColumns : function()
31410 this.getContainerWidth();
31412 var boxWidth = this.boxWidth;
31414 if(this.containerWidth < boxWidth){
31415 boxWidth = this.containerWidth;
31418 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
31420 this.el.setHeight(boxWidth);
31424 getContainerWidth : function()
31426 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
31429 layoutItems : function( isInstant )
31431 Roo.log(this.bricks);
31433 var items = Roo.apply([], this.bricks);
31435 if(this.isHorizontal){
31436 this._horizontalLayoutItems( items , isInstant );
31440 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
31441 // this._verticalAlternativeLayoutItems( items , isInstant );
31445 this._verticalLayoutItems( items , isInstant );
31449 _verticalLayoutItems : function ( items , isInstant)
31451 if ( !items || !items.length ) {
31456 ['xs', 'xs', 'xs', 'tall'],
31457 ['xs', 'xs', 'tall'],
31458 ['xs', 'xs', 'sm'],
31459 ['xs', 'xs', 'xs'],
31465 ['sm', 'xs', 'xs'],
31469 ['tall', 'xs', 'xs', 'xs'],
31470 ['tall', 'xs', 'xs'],
31482 Roo.each(items, function(item, k){
31484 switch (item.size) {
31485 // these layouts take up a full box,
31496 boxes.push([item]);
31519 var filterPattern = function(box, length)
31527 var pattern = box.slice(0, length);
31531 Roo.each(pattern, function(i){
31532 format.push(i.size);
31535 Roo.each(standard, function(s){
31537 if(String(s) != String(format)){
31546 if(!match && length == 1){
31551 filterPattern(box, length - 1);
31555 queue.push(pattern);
31557 box = box.slice(length, box.length);
31559 filterPattern(box, 4);
31565 Roo.each(boxes, function(box, k){
31571 if(box.length == 1){
31576 filterPattern(box, 4);
31580 this._processVerticalLayoutQueue( queue, isInstant );
31584 // _verticalAlternativeLayoutItems : function( items , isInstant )
31586 // if ( !items || !items.length ) {
31590 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
31594 _horizontalLayoutItems : function ( items , isInstant)
31596 if ( !items || !items.length || items.length < 3) {
31602 var eItems = items.slice(0, 3);
31604 items = items.slice(3, items.length);
31607 ['xs', 'xs', 'xs', 'wide'],
31608 ['xs', 'xs', 'wide'],
31609 ['xs', 'xs', 'sm'],
31610 ['xs', 'xs', 'xs'],
31616 ['sm', 'xs', 'xs'],
31620 ['wide', 'xs', 'xs', 'xs'],
31621 ['wide', 'xs', 'xs'],
31634 Roo.each(items, function(item, k){
31636 switch (item.size) {
31647 boxes.push([item]);
31671 var filterPattern = function(box, length)
31679 var pattern = box.slice(0, length);
31683 Roo.each(pattern, function(i){
31684 format.push(i.size);
31687 Roo.each(standard, function(s){
31689 if(String(s) != String(format)){
31698 if(!match && length == 1){
31703 filterPattern(box, length - 1);
31707 queue.push(pattern);
31709 box = box.slice(length, box.length);
31711 filterPattern(box, 4);
31717 Roo.each(boxes, function(box, k){
31723 if(box.length == 1){
31728 filterPattern(box, 4);
31735 var pos = this.el.getBox(true);
31739 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31741 var hit_end = false;
31743 Roo.each(queue, function(box){
31747 Roo.each(box, function(b){
31749 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31759 Roo.each(box, function(b){
31761 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31764 mx = Math.max(mx, b.x);
31768 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
31772 Roo.each(box, function(b){
31774 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31788 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
31791 /** Sets position of item in DOM
31792 * @param {Element} item
31793 * @param {Number} x - horizontal position
31794 * @param {Number} y - vertical position
31795 * @param {Boolean} isInstant - disables transitions
31797 _processVerticalLayoutQueue : function( queue, isInstant )
31799 var pos = this.el.getBox(true);
31804 for (var i = 0; i < this.cols; i++){
31808 Roo.each(queue, function(box, k){
31810 var col = k % this.cols;
31812 Roo.each(box, function(b,kk){
31814 b.el.position('absolute');
31816 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31817 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31819 if(b.size == 'md-left' || b.size == 'md-right'){
31820 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31821 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31824 b.el.setWidth(width);
31825 b.el.setHeight(height);
31827 b.el.select('iframe',true).setSize(width,height);
31831 for (var i = 0; i < this.cols; i++){
31833 if(maxY[i] < maxY[col]){
31838 col = Math.min(col, i);
31842 x = pos.x + col * (this.colWidth + this.padWidth);
31846 var positions = [];
31848 switch (box.length){
31850 positions = this.getVerticalOneBoxColPositions(x, y, box);
31853 positions = this.getVerticalTwoBoxColPositions(x, y, box);
31856 positions = this.getVerticalThreeBoxColPositions(x, y, box);
31859 positions = this.getVerticalFourBoxColPositions(x, y, box);
31865 Roo.each(box, function(b,kk){
31867 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31869 var sz = b.el.getSize();
31871 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
31879 for (var i = 0; i < this.cols; i++){
31880 mY = Math.max(mY, maxY[i]);
31883 this.el.setHeight(mY - pos.y);
31887 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
31889 // var pos = this.el.getBox(true);
31892 // var maxX = pos.right;
31894 // var maxHeight = 0;
31896 // Roo.each(items, function(item, k){
31900 // item.el.position('absolute');
31902 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
31904 // item.el.setWidth(width);
31906 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
31908 // item.el.setHeight(height);
31911 // item.el.setXY([x, y], isInstant ? false : true);
31913 // item.el.setXY([maxX - width, y], isInstant ? false : true);
31916 // y = y + height + this.alternativePadWidth;
31918 // maxHeight = maxHeight + height + this.alternativePadWidth;
31922 // this.el.setHeight(maxHeight);
31926 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
31928 var pos = this.el.getBox(true);
31933 var maxX = pos.right;
31935 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
31937 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31939 Roo.each(queue, function(box, k){
31941 Roo.each(box, function(b, kk){
31943 b.el.position('absolute');
31945 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31946 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31948 if(b.size == 'md-left' || b.size == 'md-right'){
31949 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31950 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31953 b.el.setWidth(width);
31954 b.el.setHeight(height);
31962 var positions = [];
31964 switch (box.length){
31966 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
31969 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
31972 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
31975 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
31981 Roo.each(box, function(b,kk){
31983 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31985 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
31993 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
31995 Roo.each(eItems, function(b,k){
31997 b.size = (k == 0) ? 'sm' : 'xs';
31998 b.x = (k == 0) ? 2 : 1;
31999 b.y = (k == 0) ? 2 : 1;
32001 b.el.position('absolute');
32003 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
32005 b.el.setWidth(width);
32007 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
32009 b.el.setHeight(height);
32013 var positions = [];
32016 x : maxX - this.unitWidth * 2 - this.gutter,
32021 x : maxX - this.unitWidth,
32022 y : minY + (this.unitWidth + this.gutter) * 2
32026 x : maxX - this.unitWidth * 3 - this.gutter * 2,
32030 Roo.each(eItems, function(b,k){
32032 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
32038 getVerticalOneBoxColPositions : function(x, y, box)
32042 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
32044 if(box[0].size == 'md-left'){
32048 if(box[0].size == 'md-right'){
32053 x : x + (this.unitWidth + this.gutter) * rand,
32060 getVerticalTwoBoxColPositions : function(x, y, box)
32064 if(box[0].size == 'xs'){
32068 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
32072 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
32086 x : x + (this.unitWidth + this.gutter) * 2,
32087 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
32094 getVerticalThreeBoxColPositions : function(x, y, box)
32098 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
32106 x : x + (this.unitWidth + this.gutter) * 1,
32111 x : x + (this.unitWidth + this.gutter) * 2,
32119 if(box[0].size == 'xs' && box[1].size == 'xs'){
32128 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
32132 x : x + (this.unitWidth + this.gutter) * 1,
32146 x : x + (this.unitWidth + this.gutter) * 2,
32151 x : x + (this.unitWidth + this.gutter) * 2,
32152 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
32159 getVerticalFourBoxColPositions : function(x, y, box)
32163 if(box[0].size == 'xs'){
32172 y : y + (this.unitHeight + this.gutter) * 1
32177 y : y + (this.unitHeight + this.gutter) * 2
32181 x : x + (this.unitWidth + this.gutter) * 1,
32195 x : x + (this.unitWidth + this.gutter) * 2,
32200 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
32201 y : y + (this.unitHeight + this.gutter) * 1
32205 x : x + (this.unitWidth + this.gutter) * 2,
32206 y : y + (this.unitWidth + this.gutter) * 2
32213 getHorizontalOneBoxColPositions : function(maxX, minY, box)
32217 if(box[0].size == 'md-left'){
32219 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
32226 if(box[0].size == 'md-right'){
32228 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
32229 y : minY + (this.unitWidth + this.gutter) * 1
32235 var rand = Math.floor(Math.random() * (4 - box[0].y));
32238 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32239 y : minY + (this.unitWidth + this.gutter) * rand
32246 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
32250 if(box[0].size == 'xs'){
32253 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32258 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32259 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
32267 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32272 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32273 y : minY + (this.unitWidth + this.gutter) * 2
32280 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
32284 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
32287 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32292 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32293 y : minY + (this.unitWidth + this.gutter) * 1
32297 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32298 y : minY + (this.unitWidth + this.gutter) * 2
32305 if(box[0].size == 'xs' && box[1].size == 'xs'){
32308 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32313 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32318 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32319 y : minY + (this.unitWidth + this.gutter) * 1
32327 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32332 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32333 y : minY + (this.unitWidth + this.gutter) * 2
32337 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32338 y : minY + (this.unitWidth + this.gutter) * 2
32345 getHorizontalFourBoxColPositions : function(maxX, minY, box)
32349 if(box[0].size == 'xs'){
32352 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32357 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32362 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),
32367 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
32368 y : minY + (this.unitWidth + this.gutter) * 1
32376 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32381 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32382 y : minY + (this.unitWidth + this.gutter) * 2
32386 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32387 y : minY + (this.unitWidth + this.gutter) * 2
32391 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),
32392 y : minY + (this.unitWidth + this.gutter) * 2
32400 * remove a Masonry Brick
32401 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
32403 removeBrick : function(brick_id)
32409 for (var i = 0; i<this.bricks.length; i++) {
32410 if (this.bricks[i].id == brick_id) {
32411 this.bricks.splice(i,1);
32412 this.el.dom.removeChild(Roo.get(brick_id).dom);
32419 * adds a Masonry Brick
32420 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32422 addBrick : function(cfg)
32424 var cn = new Roo.bootstrap.MasonryBrick(cfg);
32425 //this.register(cn);
32426 cn.parentId = this.id;
32427 cn.render(this.el);
32432 * register a Masonry Brick
32433 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32436 register : function(brick)
32438 this.bricks.push(brick);
32439 brick.masonryId = this.id;
32443 * clear all the Masonry Brick
32445 clearAll : function()
32448 //this.getChildContainer().dom.innerHTML = "";
32449 this.el.dom.innerHTML = '';
32452 getSelected : function()
32454 if (!this.selectedBrick) {
32458 return this.selectedBrick;
32462 Roo.apply(Roo.bootstrap.LayoutMasonry, {
32466 * register a Masonry Layout
32467 * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
32470 register : function(layout)
32472 this.groups[layout.id] = layout;
32475 * fetch a Masonry Layout based on the masonry layout ID
32476 * @param {string} the masonry layout to add
32477 * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
32480 get: function(layout_id) {
32481 if (typeof(this.groups[layout_id]) == 'undefined') {
32484 return this.groups[layout_id] ;
32496 * http://masonry.desandro.com
32498 * The idea is to render all the bricks based on vertical width...
32500 * The original code extends 'outlayer' - we might need to use that....
32506 * @class Roo.bootstrap.LayoutMasonryAuto
32507 * @extends Roo.bootstrap.Component
32508 * Bootstrap Layout Masonry class
32511 * Create a new Element
32512 * @param {Object} config The config object
32515 Roo.bootstrap.LayoutMasonryAuto = function(config){
32516 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
32519 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
32522 * @cfg {Boolean} isFitWidth - resize the width..
32524 isFitWidth : false, // options..
32526 * @cfg {Boolean} isOriginLeft = left align?
32528 isOriginLeft : true,
32530 * @cfg {Boolean} isOriginTop = top align?
32532 isOriginTop : false,
32534 * @cfg {Boolean} isLayoutInstant = no animation?
32536 isLayoutInstant : false, // needed?
32538 * @cfg {Boolean} isResizingContainer = not sure if this is used..
32540 isResizingContainer : true,
32542 * @cfg {Number} columnWidth width of the columns
32548 * @cfg {Number} maxCols maximum number of columns
32553 * @cfg {Number} padHeight padding below box..
32559 * @cfg {Boolean} isAutoInitial defalut true
32562 isAutoInitial : true,
32568 initialColumnWidth : 0,
32569 currentSize : null,
32571 colYs : null, // array.
32578 bricks: null, //CompositeElement
32579 cols : 0, // array?
32580 // element : null, // wrapped now this.el
32581 _isLayoutInited : null,
32584 getAutoCreate : function(){
32588 cls: 'blog-masonary-wrapper ' + this.cls,
32590 cls : 'mas-boxes masonary'
32597 getChildContainer: function( )
32599 if (this.boxesEl) {
32600 return this.boxesEl;
32603 this.boxesEl = this.el.select('.mas-boxes').first();
32605 return this.boxesEl;
32609 initEvents : function()
32613 if(this.isAutoInitial){
32614 Roo.log('hook children rendered');
32615 this.on('childrenrendered', function() {
32616 Roo.log('children rendered');
32623 initial : function()
32625 this.reloadItems();
32627 this.currentSize = this.el.getBox(true);
32629 /// was window resize... - let's see if this works..
32630 Roo.EventManager.onWindowResize(this.resize, this);
32632 if(!this.isAutoInitial){
32637 this.layout.defer(500,this);
32640 reloadItems: function()
32642 this.bricks = this.el.select('.masonry-brick', true);
32644 this.bricks.each(function(b) {
32645 //Roo.log(b.getSize());
32646 if (!b.attr('originalwidth')) {
32647 b.attr('originalwidth', b.getSize().width);
32652 Roo.log(this.bricks.elements.length);
32655 resize : function()
32658 var cs = this.el.getBox(true);
32660 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
32661 Roo.log("no change in with or X");
32664 this.currentSize = cs;
32668 layout : function()
32671 this._resetLayout();
32672 //this._manageStamps();
32674 // don't animate first layout
32675 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
32676 this.layoutItems( isInstant );
32678 // flag for initalized
32679 this._isLayoutInited = true;
32682 layoutItems : function( isInstant )
32684 //var items = this._getItemsForLayout( this.items );
32685 // original code supports filtering layout items.. we just ignore it..
32687 this._layoutItems( this.bricks , isInstant );
32689 this._postLayout();
32691 _layoutItems : function ( items , isInstant)
32693 //this.fireEvent( 'layout', this, items );
32696 if ( !items || !items.elements.length ) {
32697 // no items, emit event with empty array
32702 items.each(function(item) {
32703 Roo.log("layout item");
32705 // get x/y object from method
32706 var position = this._getItemLayoutPosition( item );
32708 position.item = item;
32709 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
32710 queue.push( position );
32713 this._processLayoutQueue( queue );
32715 /** Sets position of item in DOM
32716 * @param {Element} item
32717 * @param {Number} x - horizontal position
32718 * @param {Number} y - vertical position
32719 * @param {Boolean} isInstant - disables transitions
32721 _processLayoutQueue : function( queue )
32723 for ( var i=0, len = queue.length; i < len; i++ ) {
32724 var obj = queue[i];
32725 obj.item.position('absolute');
32726 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
32732 * Any logic you want to do after each layout,
32733 * i.e. size the container
32735 _postLayout : function()
32737 this.resizeContainer();
32740 resizeContainer : function()
32742 if ( !this.isResizingContainer ) {
32745 var size = this._getContainerSize();
32747 this.el.setSize(size.width,size.height);
32748 this.boxesEl.setSize(size.width,size.height);
32754 _resetLayout : function()
32756 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
32757 this.colWidth = this.el.getWidth();
32758 //this.gutter = this.el.getWidth();
32760 this.measureColumns();
32766 this.colYs.push( 0 );
32772 measureColumns : function()
32774 this.getContainerWidth();
32775 // if columnWidth is 0, default to outerWidth of first item
32776 if ( !this.columnWidth ) {
32777 var firstItem = this.bricks.first();
32778 Roo.log(firstItem);
32779 this.columnWidth = this.containerWidth;
32780 if (firstItem && firstItem.attr('originalwidth') ) {
32781 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
32783 // columnWidth fall back to item of first element
32784 Roo.log("set column width?");
32785 this.initialColumnWidth = this.columnWidth ;
32787 // if first elem has no width, default to size of container
32792 if (this.initialColumnWidth) {
32793 this.columnWidth = this.initialColumnWidth;
32798 // column width is fixed at the top - however if container width get's smaller we should
32801 // this bit calcs how man columns..
32803 var columnWidth = this.columnWidth += this.gutter;
32805 // calculate columns
32806 var containerWidth = this.containerWidth + this.gutter;
32808 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
32809 // fix rounding errors, typically with gutters
32810 var excess = columnWidth - containerWidth % columnWidth;
32813 // if overshoot is less than a pixel, round up, otherwise floor it
32814 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
32815 cols = Math[ mathMethod ]( cols );
32816 this.cols = Math.max( cols, 1 );
32817 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
32819 // padding positioning..
32820 var totalColWidth = this.cols * this.columnWidth;
32821 var padavail = this.containerWidth - totalColWidth;
32822 // so for 2 columns - we need 3 'pads'
32824 var padNeeded = (1+this.cols) * this.padWidth;
32826 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
32828 this.columnWidth += padExtra
32829 //this.padWidth = Math.floor(padavail / ( this.cols));
32831 // adjust colum width so that padding is fixed??
32833 // we have 3 columns ... total = width * 3
32834 // we have X left over... that should be used by
32836 //if (this.expandC) {
32844 getContainerWidth : function()
32846 /* // container is parent if fit width
32847 var container = this.isFitWidth ? this.element.parentNode : this.element;
32848 // check that this.size and size are there
32849 // IE8 triggers resize on body size change, so they might not be
32851 var size = getSize( container ); //FIXME
32852 this.containerWidth = size && size.innerWidth; //FIXME
32855 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
32859 _getItemLayoutPosition : function( item ) // what is item?
32861 // we resize the item to our columnWidth..
32863 item.setWidth(this.columnWidth);
32864 item.autoBoxAdjust = false;
32866 var sz = item.getSize();
32868 // how many columns does this brick span
32869 var remainder = this.containerWidth % this.columnWidth;
32871 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
32872 // round if off by 1 pixel, otherwise use ceil
32873 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
32874 colSpan = Math.min( colSpan, this.cols );
32876 // normally this should be '1' as we dont' currently allow multi width columns..
32878 var colGroup = this._getColGroup( colSpan );
32879 // get the minimum Y value from the columns
32880 var minimumY = Math.min.apply( Math, colGroup );
32881 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32883 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
32885 // position the brick
32887 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
32888 y: this.currentSize.y + minimumY + this.padHeight
32892 // apply setHeight to necessary columns
32893 var setHeight = minimumY + sz.height + this.padHeight;
32894 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32896 var setSpan = this.cols + 1 - colGroup.length;
32897 for ( var i = 0; i < setSpan; i++ ) {
32898 this.colYs[ shortColIndex + i ] = setHeight ;
32905 * @param {Number} colSpan - number of columns the element spans
32906 * @returns {Array} colGroup
32908 _getColGroup : function( colSpan )
32910 if ( colSpan < 2 ) {
32911 // if brick spans only one column, use all the column Ys
32916 // how many different places could this brick fit horizontally
32917 var groupCount = this.cols + 1 - colSpan;
32918 // for each group potential horizontal position
32919 for ( var i = 0; i < groupCount; i++ ) {
32920 // make an array of colY values for that one group
32921 var groupColYs = this.colYs.slice( i, i + colSpan );
32922 // and get the max value of the array
32923 colGroup[i] = Math.max.apply( Math, groupColYs );
32928 _manageStamp : function( stamp )
32930 var stampSize = stamp.getSize();
32931 var offset = stamp.getBox();
32932 // get the columns that this stamp affects
32933 var firstX = this.isOriginLeft ? offset.x : offset.right;
32934 var lastX = firstX + stampSize.width;
32935 var firstCol = Math.floor( firstX / this.columnWidth );
32936 firstCol = Math.max( 0, firstCol );
32938 var lastCol = Math.floor( lastX / this.columnWidth );
32939 // lastCol should not go over if multiple of columnWidth #425
32940 lastCol -= lastX % this.columnWidth ? 0 : 1;
32941 lastCol = Math.min( this.cols - 1, lastCol );
32943 // set colYs to bottom of the stamp
32944 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
32947 for ( var i = firstCol; i <= lastCol; i++ ) {
32948 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
32953 _getContainerSize : function()
32955 this.maxY = Math.max.apply( Math, this.colYs );
32960 if ( this.isFitWidth ) {
32961 size.width = this._getContainerFitWidth();
32967 _getContainerFitWidth : function()
32969 var unusedCols = 0;
32970 // count unused columns
32973 if ( this.colYs[i] !== 0 ) {
32978 // fit container to columns that have been used
32979 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
32982 needsResizeLayout : function()
32984 var previousWidth = this.containerWidth;
32985 this.getContainerWidth();
32986 return previousWidth !== this.containerWidth;
33001 * @class Roo.bootstrap.MasonryBrick
33002 * @extends Roo.bootstrap.Component
33003 * Bootstrap MasonryBrick class
33006 * Create a new MasonryBrick
33007 * @param {Object} config The config object
33010 Roo.bootstrap.MasonryBrick = function(config){
33012 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
33014 Roo.bootstrap.MasonryBrick.register(this);
33020 * When a MasonryBrick is clcik
33021 * @param {Roo.bootstrap.MasonryBrick} this
33022 * @param {Roo.EventObject} e
33028 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
33031 * @cfg {String} title
33035 * @cfg {String} html
33039 * @cfg {String} bgimage
33043 * @cfg {String} videourl
33047 * @cfg {String} cls
33051 * @cfg {String} href
33055 * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
33060 * @cfg {String} placetitle (center|bottom)
33065 * @cfg {Boolean} isFitContainer defalut true
33067 isFitContainer : true,
33070 * @cfg {Boolean} preventDefault defalut false
33072 preventDefault : false,
33075 * @cfg {Boolean} inverse defalut false
33077 maskInverse : false,
33079 getAutoCreate : function()
33081 if(!this.isFitContainer){
33082 return this.getSplitAutoCreate();
33085 var cls = 'masonry-brick masonry-brick-full';
33087 if(this.href.length){
33088 cls += ' masonry-brick-link';
33091 if(this.bgimage.length){
33092 cls += ' masonry-brick-image';
33095 if(this.maskInverse){
33096 cls += ' mask-inverse';
33099 if(!this.html.length && !this.maskInverse && !this.videourl.length){
33100 cls += ' enable-mask';
33104 cls += ' masonry-' + this.size + '-brick';
33107 if(this.placetitle.length){
33109 switch (this.placetitle) {
33111 cls += ' masonry-center-title';
33114 cls += ' masonry-bottom-title';
33121 if(!this.html.length && !this.bgimage.length){
33122 cls += ' masonry-center-title';
33125 if(!this.html.length && this.bgimage.length){
33126 cls += ' masonry-bottom-title';
33131 cls += ' ' + this.cls;
33135 tag: (this.href.length) ? 'a' : 'div',
33140 cls: 'masonry-brick-mask'
33144 cls: 'masonry-brick-paragraph',
33150 if(this.href.length){
33151 cfg.href = this.href;
33154 var cn = cfg.cn[1].cn;
33156 if(this.title.length){
33159 cls: 'masonry-brick-title',
33164 if(this.html.length){
33167 cls: 'masonry-brick-text',
33172 if (!this.title.length && !this.html.length) {
33173 cfg.cn[1].cls += ' hide';
33176 if(this.bgimage.length){
33179 cls: 'masonry-brick-image-view',
33184 if(this.videourl.length){
33185 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
33186 // youtube support only?
33189 cls: 'masonry-brick-image-view',
33192 allowfullscreen : true
33200 getSplitAutoCreate : function()
33202 var cls = 'masonry-brick masonry-brick-split';
33204 if(this.href.length){
33205 cls += ' masonry-brick-link';
33208 if(this.bgimage.length){
33209 cls += ' masonry-brick-image';
33213 cls += ' masonry-' + this.size + '-brick';
33216 switch (this.placetitle) {
33218 cls += ' masonry-center-title';
33221 cls += ' masonry-bottom-title';
33224 if(!this.bgimage.length){
33225 cls += ' masonry-center-title';
33228 if(this.bgimage.length){
33229 cls += ' masonry-bottom-title';
33235 cls += ' ' + this.cls;
33239 tag: (this.href.length) ? 'a' : 'div',
33244 cls: 'masonry-brick-split-head',
33248 cls: 'masonry-brick-paragraph',
33255 cls: 'masonry-brick-split-body',
33261 if(this.href.length){
33262 cfg.href = this.href;
33265 if(this.title.length){
33266 cfg.cn[0].cn[0].cn.push({
33268 cls: 'masonry-brick-title',
33273 if(this.html.length){
33274 cfg.cn[1].cn.push({
33276 cls: 'masonry-brick-text',
33281 if(this.bgimage.length){
33282 cfg.cn[0].cn.push({
33284 cls: 'masonry-brick-image-view',
33289 if(this.videourl.length){
33290 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
33291 // youtube support only?
33292 cfg.cn[0].cn.cn.push({
33294 cls: 'masonry-brick-image-view',
33297 allowfullscreen : true
33304 initEvents: function()
33306 switch (this.size) {
33339 this.el.on('touchstart', this.onTouchStart, this);
33340 this.el.on('touchmove', this.onTouchMove, this);
33341 this.el.on('touchend', this.onTouchEnd, this);
33342 this.el.on('contextmenu', this.onContextMenu, this);
33344 this.el.on('mouseenter' ,this.enter, this);
33345 this.el.on('mouseleave', this.leave, this);
33346 this.el.on('click', this.onClick, this);
33349 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
33350 this.parent().bricks.push(this);
33355 onClick: function(e, el)
33357 var time = this.endTimer - this.startTimer;
33358 // Roo.log(e.preventDefault());
33361 e.preventDefault();
33366 if(!this.preventDefault){
33370 e.preventDefault();
33372 if (this.activeClass != '') {
33373 this.selectBrick();
33376 this.fireEvent('click', this, e);
33379 enter: function(e, el)
33381 e.preventDefault();
33383 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
33387 if(this.bgimage.length && this.html.length){
33388 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
33392 leave: function(e, el)
33394 e.preventDefault();
33396 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
33400 if(this.bgimage.length && this.html.length){
33401 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
33405 onTouchStart: function(e, el)
33407 // e.preventDefault();
33409 this.touchmoved = false;
33411 if(!this.isFitContainer){
33415 if(!this.bgimage.length || !this.html.length){
33419 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
33421 this.timer = new Date().getTime();
33425 onTouchMove: function(e, el)
33427 this.touchmoved = true;
33430 onContextMenu : function(e,el)
33432 e.preventDefault();
33433 e.stopPropagation();
33437 onTouchEnd: function(e, el)
33439 // e.preventDefault();
33441 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
33448 if(!this.bgimage.length || !this.html.length){
33450 if(this.href.length){
33451 window.location.href = this.href;
33457 if(!this.isFitContainer){
33461 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
33463 window.location.href = this.href;
33466 //selection on single brick only
33467 selectBrick : function() {
33469 if (!this.parentId) {
33473 var m = Roo.bootstrap.LayoutMasonry.get(this.parentId);
33474 var index = m.selectedBrick.indexOf(this.id);
33477 m.selectedBrick.splice(index,1);
33478 this.el.removeClass(this.activeClass);
33482 for(var i = 0; i < m.selectedBrick.length; i++) {
33483 var b = Roo.bootstrap.MasonryBrick.get(m.selectedBrick[i]);
33484 b.el.removeClass(b.activeClass);
33487 m.selectedBrick = [];
33489 m.selectedBrick.push(this.id);
33490 this.el.addClass(this.activeClass);
33494 isSelected : function(){
33495 return this.el.hasClass(this.activeClass);
33500 Roo.apply(Roo.bootstrap.MasonryBrick, {
33503 groups : new Roo.util.MixedCollection(false, function(o) { return o.el.id; }),
33505 * register a Masonry Brick
33506 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
33509 register : function(brick)
33511 //this.groups[brick.id] = brick;
33512 this.groups.add(brick.id, brick);
33515 * fetch a masonry brick based on the masonry brick ID
33516 * @param {string} the masonry brick to add
33517 * @returns {Roo.bootstrap.MasonryBrick} the masonry brick
33520 get: function(brick_id)
33522 // if (typeof(this.groups[brick_id]) == 'undefined') {
33525 // return this.groups[brick_id] ;
33527 if(this.groups.key(brick_id)) {
33528 return this.groups.key(brick_id);
33546 * @class Roo.bootstrap.Brick
33547 * @extends Roo.bootstrap.Component
33548 * Bootstrap Brick class
33551 * Create a new Brick
33552 * @param {Object} config The config object
33555 Roo.bootstrap.Brick = function(config){
33556 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
33562 * When a Brick is click
33563 * @param {Roo.bootstrap.Brick} this
33564 * @param {Roo.EventObject} e
33570 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
33573 * @cfg {String} title
33577 * @cfg {String} html
33581 * @cfg {String} bgimage
33585 * @cfg {String} cls
33589 * @cfg {String} href
33593 * @cfg {String} video
33597 * @cfg {Boolean} square
33601 getAutoCreate : function()
33603 var cls = 'roo-brick';
33605 if(this.href.length){
33606 cls += ' roo-brick-link';
33609 if(this.bgimage.length){
33610 cls += ' roo-brick-image';
33613 if(!this.html.length && !this.bgimage.length){
33614 cls += ' roo-brick-center-title';
33617 if(!this.html.length && this.bgimage.length){
33618 cls += ' roo-brick-bottom-title';
33622 cls += ' ' + this.cls;
33626 tag: (this.href.length) ? 'a' : 'div',
33631 cls: 'roo-brick-paragraph',
33637 if(this.href.length){
33638 cfg.href = this.href;
33641 var cn = cfg.cn[0].cn;
33643 if(this.title.length){
33646 cls: 'roo-brick-title',
33651 if(this.html.length){
33654 cls: 'roo-brick-text',
33661 if(this.bgimage.length){
33664 cls: 'roo-brick-image-view',
33672 initEvents: function()
33674 if(this.title.length || this.html.length){
33675 this.el.on('mouseenter' ,this.enter, this);
33676 this.el.on('mouseleave', this.leave, this);
33679 Roo.EventManager.onWindowResize(this.resize, this);
33681 if(this.bgimage.length){
33682 this.imageEl = this.el.select('.roo-brick-image-view', true).first();
33683 this.imageEl.on('load', this.onImageLoad, this);
33690 onImageLoad : function()
33695 resize : function()
33697 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
33699 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
33701 if(this.bgimage.length){
33702 var image = this.el.select('.roo-brick-image-view', true).first();
33704 image.setWidth(paragraph.getWidth());
33707 image.setHeight(paragraph.getWidth());
33710 this.el.setHeight(image.getHeight());
33711 paragraph.setHeight(image.getHeight());
33717 enter: function(e, el)
33719 e.preventDefault();
33721 if(this.bgimage.length){
33722 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
33723 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
33727 leave: function(e, el)
33729 e.preventDefault();
33731 if(this.bgimage.length){
33732 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
33733 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
33748 * @class Roo.bootstrap.NumberField
33749 * @extends Roo.bootstrap.Input
33750 * Bootstrap NumberField class
33756 * Create a new NumberField
33757 * @param {Object} config The config object
33760 Roo.bootstrap.NumberField = function(config){
33761 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
33764 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
33767 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
33769 allowDecimals : true,
33771 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
33773 decimalSeparator : ".",
33775 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
33777 decimalPrecision : 2,
33779 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
33781 allowNegative : true,
33784 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
33788 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
33790 minValue : Number.NEGATIVE_INFINITY,
33792 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
33794 maxValue : Number.MAX_VALUE,
33796 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
33798 minText : "The minimum value for this field is {0}",
33800 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
33802 maxText : "The maximum value for this field is {0}",
33804 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
33805 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
33807 nanText : "{0} is not a valid number",
33809 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
33811 thousandsDelimiter : false,
33813 * @cfg {String} valueAlign alignment of value
33815 valueAlign : "left",
33817 getAutoCreate : function()
33819 var hiddenInput = {
33823 cls: 'hidden-number-input'
33827 hiddenInput.name = this.name;
33832 var cfg = Roo.bootstrap.NumberField.superclass.getAutoCreate.call(this);
33834 this.name = hiddenInput.name;
33836 if(cfg.cn.length > 0) {
33837 cfg.cn.push(hiddenInput);
33844 initEvents : function()
33846 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
33848 var allowed = "0123456789";
33850 if(this.allowDecimals){
33851 allowed += this.decimalSeparator;
33854 if(this.allowNegative){
33858 if(this.thousandsDelimiter) {
33862 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
33864 var keyPress = function(e){
33866 var k = e.getKey();
33868 var c = e.getCharCode();
33871 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
33872 allowed.indexOf(String.fromCharCode(c)) === -1
33878 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
33882 if(allowed.indexOf(String.fromCharCode(c)) === -1){
33887 this.el.on("keypress", keyPress, this);
33890 validateValue : function(value)
33893 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
33897 var num = this.parseValue(value);
33900 this.markInvalid(String.format(this.nanText, value));
33904 if(num < this.minValue){
33905 this.markInvalid(String.format(this.minText, this.minValue));
33909 if(num > this.maxValue){
33910 this.markInvalid(String.format(this.maxText, this.maxValue));
33917 getValue : function()
33919 var v = this.hiddenEl().getValue();
33921 return this.fixPrecision(this.parseValue(v));
33924 parseValue : function(value)
33926 if(this.thousandsDelimiter) {
33928 r = new RegExp(",", "g");
33929 value = value.replace(r, "");
33932 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
33933 return isNaN(value) ? '' : value;
33936 fixPrecision : function(value)
33938 if(this.thousandsDelimiter) {
33940 r = new RegExp(",", "g");
33941 value = value.replace(r, "");
33944 var nan = isNaN(value);
33946 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
33947 return nan ? '' : value;
33949 return parseFloat(value).toFixed(this.decimalPrecision);
33952 setValue : function(v)
33954 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
33960 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
33962 this.inputEl().dom.value = (v == '') ? '' :
33963 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
33965 if(!this.allowZero && v === '0') {
33966 this.hiddenEl().dom.value = '';
33967 this.inputEl().dom.value = '';
33974 decimalPrecisionFcn : function(v)
33976 return Math.floor(v);
33979 beforeBlur : function()
33981 var v = this.parseValue(this.getRawValue());
33983 if(v || v === 0 || v === ''){
33988 hiddenEl : function()
33990 return this.el.select('input.hidden-number-input',true).first();
34002 * @class Roo.bootstrap.DocumentSlider
34003 * @extends Roo.bootstrap.Component
34004 * Bootstrap DocumentSlider class
34007 * Create a new DocumentViewer
34008 * @param {Object} config The config object
34011 Roo.bootstrap.DocumentSlider = function(config){
34012 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
34019 * Fire after initEvent
34020 * @param {Roo.bootstrap.DocumentSlider} this
34025 * Fire after update
34026 * @param {Roo.bootstrap.DocumentSlider} this
34032 * @param {Roo.bootstrap.DocumentSlider} this
34038 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
34044 getAutoCreate : function()
34048 cls : 'roo-document-slider',
34052 cls : 'roo-document-slider-header',
34056 cls : 'roo-document-slider-header-title'
34062 cls : 'roo-document-slider-body',
34066 cls : 'roo-document-slider-prev',
34070 cls : 'fa fa-chevron-left'
34076 cls : 'roo-document-slider-thumb',
34080 cls : 'roo-document-slider-image'
34086 cls : 'roo-document-slider-next',
34090 cls : 'fa fa-chevron-right'
34102 initEvents : function()
34104 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
34105 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
34107 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
34108 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
34110 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
34111 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
34113 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
34114 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
34116 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
34117 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
34119 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
34120 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
34122 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
34123 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
34125 this.thumbEl.on('click', this.onClick, this);
34127 this.prevIndicator.on('click', this.prev, this);
34129 this.nextIndicator.on('click', this.next, this);
34133 initial : function()
34135 if(this.files.length){
34136 this.indicator = 1;
34140 this.fireEvent('initial', this);
34143 update : function()
34145 this.imageEl.attr('src', this.files[this.indicator - 1]);
34147 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
34149 this.prevIndicator.show();
34151 if(this.indicator == 1){
34152 this.prevIndicator.hide();
34155 this.nextIndicator.show();
34157 if(this.indicator == this.files.length){
34158 this.nextIndicator.hide();
34161 this.thumbEl.scrollTo('top');
34163 this.fireEvent('update', this);
34166 onClick : function(e)
34168 e.preventDefault();
34170 this.fireEvent('click', this);
34175 e.preventDefault();
34177 this.indicator = Math.max(1, this.indicator - 1);
34184 e.preventDefault();
34186 this.indicator = Math.min(this.files.length, this.indicator + 1);
34200 * @class Roo.bootstrap.RadioSet
34201 * @extends Roo.bootstrap.Input
34202 * Bootstrap RadioSet class
34203 * @cfg {String} indicatorpos (left|right) default left
34204 * @cfg {Boolean} inline (true|false) inline the element (default true)
34205 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
34207 * Create a new RadioSet
34208 * @param {Object} config The config object
34211 Roo.bootstrap.RadioSet = function(config){
34213 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
34217 Roo.bootstrap.RadioSet.register(this);
34222 * Fires when the element is checked or unchecked.
34223 * @param {Roo.bootstrap.RadioSet} this This radio
34224 * @param {Roo.bootstrap.Radio} item The checked item
34229 * Fires when the element is click.
34230 * @param {Roo.bootstrap.RadioSet} this This radio set
34231 * @param {Roo.bootstrap.Radio} item The checked item
34232 * @param {Roo.EventObject} e The event object
34239 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
34247 indicatorpos : 'left',
34249 getAutoCreate : function()
34253 cls : 'roo-radio-set-label',
34257 html : this.fieldLabel
34261 if (Roo.bootstrap.version == 3) {
34264 if(this.indicatorpos == 'left'){
34267 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
34268 tooltip : 'This field is required'
34273 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
34274 tooltip : 'This field is required'
34280 cls : 'roo-radio-set-items'
34283 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
34285 if (align === 'left' && this.fieldLabel.length) {
34288 cls : "roo-radio-set-right",
34294 if(this.labelWidth > 12){
34295 label.style = "width: " + this.labelWidth + 'px';
34298 if(this.labelWidth < 13 && this.labelmd == 0){
34299 this.labelmd = this.labelWidth;
34302 if(this.labellg > 0){
34303 label.cls += ' col-lg-' + this.labellg;
34304 items.cls += ' col-lg-' + (12 - this.labellg);
34307 if(this.labelmd > 0){
34308 label.cls += ' col-md-' + this.labelmd;
34309 items.cls += ' col-md-' + (12 - this.labelmd);
34312 if(this.labelsm > 0){
34313 label.cls += ' col-sm-' + this.labelsm;
34314 items.cls += ' col-sm-' + (12 - this.labelsm);
34317 if(this.labelxs > 0){
34318 label.cls += ' col-xs-' + this.labelxs;
34319 items.cls += ' col-xs-' + (12 - this.labelxs);
34325 cls : 'roo-radio-set',
34329 cls : 'roo-radio-set-input',
34332 value : this.value ? this.value : ''
34339 if(this.weight.length){
34340 cfg.cls += ' roo-radio-' + this.weight;
34344 cfg.cls += ' roo-radio-set-inline';
34348 ['xs','sm','md','lg'].map(function(size){
34349 if (settings[size]) {
34350 cfg.cls += ' col-' + size + '-' + settings[size];
34358 initEvents : function()
34360 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
34361 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
34363 if(!this.fieldLabel.length){
34364 this.labelEl.hide();
34367 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
34368 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
34370 this.indicator = this.indicatorEl();
34372 if(this.indicator){
34373 this.indicator.addClass('invisible');
34376 this.originalValue = this.getValue();
34380 inputEl: function ()
34382 return this.el.select('.roo-radio-set-input', true).first();
34385 getChildContainer : function()
34387 return this.itemsEl;
34390 register : function(item)
34392 this.radioes.push(item);
34396 validate : function()
34398 if(this.getVisibilityEl().hasClass('hidden')){
34404 Roo.each(this.radioes, function(i){
34413 if(this.allowBlank) {
34417 if(this.disabled || valid){
34422 this.markInvalid();
34427 markValid : function()
34429 if(this.labelEl.isVisible(true) && this.indicatorEl()){
34430 this.indicatorEl().removeClass('visible');
34431 this.indicatorEl().addClass('invisible');
34435 if (Roo.bootstrap.version == 3) {
34436 this.el.removeClass([this.invalidClass, this.validClass]);
34437 this.el.addClass(this.validClass);
34439 this.el.removeClass(['is-invalid','is-valid']);
34440 this.el.addClass(['is-valid']);
34442 this.fireEvent('valid', this);
34445 markInvalid : function(msg)
34447 if(this.allowBlank || this.disabled){
34451 if(this.labelEl.isVisible(true) && this.indicatorEl()){
34452 this.indicatorEl().removeClass('invisible');
34453 this.indicatorEl().addClass('visible');
34455 if (Roo.bootstrap.version == 3) {
34456 this.el.removeClass([this.invalidClass, this.validClass]);
34457 this.el.addClass(this.invalidClass);
34459 this.el.removeClass(['is-invalid','is-valid']);
34460 this.el.addClass(['is-invalid']);
34463 this.fireEvent('invalid', this, msg);
34467 setValue : function(v, suppressEvent)
34469 if(this.value === v){
34476 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
34479 Roo.each(this.radioes, function(i){
34481 i.el.removeClass('checked');
34484 Roo.each(this.radioes, function(i){
34486 if(i.value === v || i.value.toString() === v.toString()){
34488 i.el.addClass('checked');
34490 if(suppressEvent !== true){
34491 this.fireEvent('check', this, i);
34502 clearInvalid : function(){
34504 if(!this.el || this.preventMark){
34508 this.el.removeClass([this.invalidClass]);
34510 this.fireEvent('valid', this);
34515 Roo.apply(Roo.bootstrap.RadioSet, {
34519 register : function(set)
34521 this.groups[set.name] = set;
34524 get: function(name)
34526 if (typeof(this.groups[name]) == 'undefined') {
34530 return this.groups[name] ;
34536 * Ext JS Library 1.1.1
34537 * Copyright(c) 2006-2007, Ext JS, LLC.
34539 * Originally Released Under LGPL - original licence link has changed is not relivant.
34542 * <script type="text/javascript">
34547 * @class Roo.bootstrap.SplitBar
34548 * @extends Roo.util.Observable
34549 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
34553 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
34554 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
34555 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
34556 split.minSize = 100;
34557 split.maxSize = 600;
34558 split.animate = true;
34559 split.on('moved', splitterMoved);
34562 * Create a new SplitBar
34563 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
34564 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
34565 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34566 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
34567 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
34568 position of the SplitBar).
34570 Roo.bootstrap.SplitBar = function(cfg){
34575 // dragElement : elm
34576 // resizingElement: el,
34578 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
34579 // placement : Roo.bootstrap.SplitBar.LEFT ,
34580 // existingProxy ???
34583 this.el = Roo.get(cfg.dragElement, true);
34584 this.el.dom.unselectable = "on";
34586 this.resizingEl = Roo.get(cfg.resizingElement, true);
34590 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34591 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
34594 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
34597 * The minimum size of the resizing element. (Defaults to 0)
34603 * The maximum size of the resizing element. (Defaults to 2000)
34606 this.maxSize = 2000;
34609 * Whether to animate the transition to the new size
34612 this.animate = false;
34615 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
34618 this.useShim = false;
34623 if(!cfg.existingProxy){
34625 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
34627 this.proxy = Roo.get(cfg.existingProxy).dom;
34630 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
34633 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
34636 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
34639 this.dragSpecs = {};
34642 * @private The adapter to use to positon and resize elements
34644 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34645 this.adapter.init(this);
34647 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34649 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
34650 this.el.addClass("roo-splitbar-h");
34653 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
34654 this.el.addClass("roo-splitbar-v");
34660 * Fires when the splitter is moved (alias for {@link #event-moved})
34661 * @param {Roo.bootstrap.SplitBar} this
34662 * @param {Number} newSize the new width or height
34667 * Fires when the splitter is moved
34668 * @param {Roo.bootstrap.SplitBar} this
34669 * @param {Number} newSize the new width or height
34673 * @event beforeresize
34674 * Fires before the splitter is dragged
34675 * @param {Roo.bootstrap.SplitBar} this
34677 "beforeresize" : true,
34679 "beforeapply" : true
34682 Roo.util.Observable.call(this);
34685 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
34686 onStartProxyDrag : function(x, y){
34687 this.fireEvent("beforeresize", this);
34689 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
34691 o.enableDisplayMode("block");
34692 // all splitbars share the same overlay
34693 Roo.bootstrap.SplitBar.prototype.overlay = o;
34695 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
34696 this.overlay.show();
34697 Roo.get(this.proxy).setDisplayed("block");
34698 var size = this.adapter.getElementSize(this);
34699 this.activeMinSize = this.getMinimumSize();;
34700 this.activeMaxSize = this.getMaximumSize();;
34701 var c1 = size - this.activeMinSize;
34702 var c2 = Math.max(this.activeMaxSize - size, 0);
34703 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34704 this.dd.resetConstraints();
34705 this.dd.setXConstraint(
34706 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
34707 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
34709 this.dd.setYConstraint(0, 0);
34711 this.dd.resetConstraints();
34712 this.dd.setXConstraint(0, 0);
34713 this.dd.setYConstraint(
34714 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
34715 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
34718 this.dragSpecs.startSize = size;
34719 this.dragSpecs.startPoint = [x, y];
34720 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
34724 * @private Called after the drag operation by the DDProxy
34726 onEndProxyDrag : function(e){
34727 Roo.get(this.proxy).setDisplayed(false);
34728 var endPoint = Roo.lib.Event.getXY(e);
34730 this.overlay.hide();
34733 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34734 newSize = this.dragSpecs.startSize +
34735 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
34736 endPoint[0] - this.dragSpecs.startPoint[0] :
34737 this.dragSpecs.startPoint[0] - endPoint[0]
34740 newSize = this.dragSpecs.startSize +
34741 (this.placement == Roo.bootstrap.SplitBar.TOP ?
34742 endPoint[1] - this.dragSpecs.startPoint[1] :
34743 this.dragSpecs.startPoint[1] - endPoint[1]
34746 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
34747 if(newSize != this.dragSpecs.startSize){
34748 if(this.fireEvent('beforeapply', this, newSize) !== false){
34749 this.adapter.setElementSize(this, newSize);
34750 this.fireEvent("moved", this, newSize);
34751 this.fireEvent("resize", this, newSize);
34757 * Get the adapter this SplitBar uses
34758 * @return The adapter object
34760 getAdapter : function(){
34761 return this.adapter;
34765 * Set the adapter this SplitBar uses
34766 * @param {Object} adapter A SplitBar adapter object
34768 setAdapter : function(adapter){
34769 this.adapter = adapter;
34770 this.adapter.init(this);
34774 * Gets the minimum size for the resizing element
34775 * @return {Number} The minimum size
34777 getMinimumSize : function(){
34778 return this.minSize;
34782 * Sets the minimum size for the resizing element
34783 * @param {Number} minSize The minimum size
34785 setMinimumSize : function(minSize){
34786 this.minSize = minSize;
34790 * Gets the maximum size for the resizing element
34791 * @return {Number} The maximum size
34793 getMaximumSize : function(){
34794 return this.maxSize;
34798 * Sets the maximum size for the resizing element
34799 * @param {Number} maxSize The maximum size
34801 setMaximumSize : function(maxSize){
34802 this.maxSize = maxSize;
34806 * Sets the initialize size for the resizing element
34807 * @param {Number} size The initial size
34809 setCurrentSize : function(size){
34810 var oldAnimate = this.animate;
34811 this.animate = false;
34812 this.adapter.setElementSize(this, size);
34813 this.animate = oldAnimate;
34817 * Destroy this splitbar.
34818 * @param {Boolean} removeEl True to remove the element
34820 destroy : function(removeEl){
34822 this.shim.remove();
34825 this.proxy.parentNode.removeChild(this.proxy);
34833 * @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.
34835 Roo.bootstrap.SplitBar.createProxy = function(dir){
34836 var proxy = new Roo.Element(document.createElement("div"));
34837 proxy.unselectable();
34838 var cls = 'roo-splitbar-proxy';
34839 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
34840 document.body.appendChild(proxy.dom);
34845 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
34846 * Default Adapter. It assumes the splitter and resizing element are not positioned
34847 * elements and only gets/sets the width of the element. Generally used for table based layouts.
34849 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
34852 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
34853 // do nothing for now
34854 init : function(s){
34858 * Called before drag operations to get the current size of the resizing element.
34859 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34861 getElementSize : function(s){
34862 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34863 return s.resizingEl.getWidth();
34865 return s.resizingEl.getHeight();
34870 * Called after drag operations to set the size of the resizing element.
34871 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34872 * @param {Number} newSize The new size to set
34873 * @param {Function} onComplete A function to be invoked when resizing is complete
34875 setElementSize : function(s, newSize, onComplete){
34876 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34878 s.resizingEl.setWidth(newSize);
34880 onComplete(s, newSize);
34883 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
34888 s.resizingEl.setHeight(newSize);
34890 onComplete(s, newSize);
34893 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
34900 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
34901 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
34902 * Adapter that moves the splitter element to align with the resized sizing element.
34903 * Used with an absolute positioned SplitBar.
34904 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
34905 * document.body, make sure you assign an id to the body element.
34907 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
34908 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34909 this.container = Roo.get(container);
34912 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
34913 init : function(s){
34914 this.basic.init(s);
34917 getElementSize : function(s){
34918 return this.basic.getElementSize(s);
34921 setElementSize : function(s, newSize, onComplete){
34922 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
34925 moveSplitter : function(s){
34926 var yes = Roo.bootstrap.SplitBar;
34927 switch(s.placement){
34929 s.el.setX(s.resizingEl.getRight());
34932 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
34935 s.el.setY(s.resizingEl.getBottom());
34938 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
34945 * Orientation constant - Create a vertical SplitBar
34949 Roo.bootstrap.SplitBar.VERTICAL = 1;
34952 * Orientation constant - Create a horizontal SplitBar
34956 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
34959 * Placement constant - The resizing element is to the left of the splitter element
34963 Roo.bootstrap.SplitBar.LEFT = 1;
34966 * Placement constant - The resizing element is to the right of the splitter element
34970 Roo.bootstrap.SplitBar.RIGHT = 2;
34973 * Placement constant - The resizing element is positioned above the splitter element
34977 Roo.bootstrap.SplitBar.TOP = 3;
34980 * Placement constant - The resizing element is positioned under splitter element
34984 Roo.bootstrap.SplitBar.BOTTOM = 4;
34985 Roo.namespace("Roo.bootstrap.layout");/*
34987 * Ext JS Library 1.1.1
34988 * Copyright(c) 2006-2007, Ext JS, LLC.
34990 * Originally Released Under LGPL - original licence link has changed is not relivant.
34993 * <script type="text/javascript">
34997 * @class Roo.bootstrap.layout.Manager
34998 * @extends Roo.bootstrap.Component
34999 * Base class for layout managers.
35001 Roo.bootstrap.layout.Manager = function(config)
35003 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
35009 /** false to disable window resize monitoring @type Boolean */
35010 this.monitorWindowResize = true;
35015 * Fires when a layout is performed.
35016 * @param {Roo.LayoutManager} this
35020 * @event regionresized
35021 * Fires when the user resizes a region.
35022 * @param {Roo.LayoutRegion} region The resized region
35023 * @param {Number} newSize The new size (width for east/west, height for north/south)
35025 "regionresized" : true,
35027 * @event regioncollapsed
35028 * Fires when a region is collapsed.
35029 * @param {Roo.LayoutRegion} region The collapsed region
35031 "regioncollapsed" : true,
35033 * @event regionexpanded
35034 * Fires when a region is expanded.
35035 * @param {Roo.LayoutRegion} region The expanded region
35037 "regionexpanded" : true
35039 this.updating = false;
35042 this.el = Roo.get(config.el);
35048 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
35053 monitorWindowResize : true,
35059 onRender : function(ct, position)
35062 this.el = Roo.get(ct);
35065 //this.fireEvent('render',this);
35069 initEvents: function()
35073 // ie scrollbar fix
35074 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
35075 document.body.scroll = "no";
35076 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
35077 this.el.position('relative');
35079 this.id = this.el.id;
35080 this.el.addClass("roo-layout-container");
35081 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
35082 if(this.el.dom != document.body ) {
35083 this.el.on('resize', this.layout,this);
35084 this.el.on('show', this.layout,this);
35090 * Returns true if this layout is currently being updated
35091 * @return {Boolean}
35093 isUpdating : function(){
35094 return this.updating;
35098 * Suspend the LayoutManager from doing auto-layouts while
35099 * making multiple add or remove calls
35101 beginUpdate : function(){
35102 this.updating = true;
35106 * Restore auto-layouts and optionally disable the manager from performing a layout
35107 * @param {Boolean} noLayout true to disable a layout update
35109 endUpdate : function(noLayout){
35110 this.updating = false;
35116 layout: function(){
35120 onRegionResized : function(region, newSize){
35121 this.fireEvent("regionresized", region, newSize);
35125 onRegionCollapsed : function(region){
35126 this.fireEvent("regioncollapsed", region);
35129 onRegionExpanded : function(region){
35130 this.fireEvent("regionexpanded", region);
35134 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
35135 * performs box-model adjustments.
35136 * @return {Object} The size as an object {width: (the width), height: (the height)}
35138 getViewSize : function()
35141 if(this.el.dom != document.body){
35142 size = this.el.getSize();
35144 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
35146 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
35147 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
35152 * Returns the Element this layout is bound to.
35153 * @return {Roo.Element}
35155 getEl : function(){
35160 * Returns the specified region.
35161 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
35162 * @return {Roo.LayoutRegion}
35164 getRegion : function(target){
35165 return this.regions[target.toLowerCase()];
35168 onWindowResize : function(){
35169 if(this.monitorWindowResize){
35176 * Ext JS Library 1.1.1
35177 * Copyright(c) 2006-2007, Ext JS, LLC.
35179 * Originally Released Under LGPL - original licence link has changed is not relivant.
35182 * <script type="text/javascript">
35185 * @class Roo.bootstrap.layout.Border
35186 * @extends Roo.bootstrap.layout.Manager
35187 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
35188 * please see: examples/bootstrap/nested.html<br><br>
35190 <b>The container the layout is rendered into can be either the body element or any other element.
35191 If it is not the body element, the container needs to either be an absolute positioned element,
35192 or you will need to add "position:relative" to the css of the container. You will also need to specify
35193 the container size if it is not the body element.</b>
35196 * Create a new Border
35197 * @param {Object} config Configuration options
35199 Roo.bootstrap.layout.Border = function(config){
35200 config = config || {};
35201 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
35205 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
35206 if(config[region]){
35207 config[region].region = region;
35208 this.addRegion(config[region]);
35214 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
35216 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
35218 parent : false, // this might point to a 'nest' or a ???
35221 * Creates and adds a new region if it doesn't already exist.
35222 * @param {String} target The target region key (north, south, east, west or center).
35223 * @param {Object} config The regions config object
35224 * @return {BorderLayoutRegion} The new region
35226 addRegion : function(config)
35228 if(!this.regions[config.region]){
35229 var r = this.factory(config);
35230 this.bindRegion(r);
35232 return this.regions[config.region];
35236 bindRegion : function(r){
35237 this.regions[r.config.region] = r;
35239 r.on("visibilitychange", this.layout, this);
35240 r.on("paneladded", this.layout, this);
35241 r.on("panelremoved", this.layout, this);
35242 r.on("invalidated", this.layout, this);
35243 r.on("resized", this.onRegionResized, this);
35244 r.on("collapsed", this.onRegionCollapsed, this);
35245 r.on("expanded", this.onRegionExpanded, this);
35249 * Performs a layout update.
35251 layout : function()
35253 if(this.updating) {
35257 // render all the rebions if they have not been done alreayd?
35258 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
35259 if(this.regions[region] && !this.regions[region].bodyEl){
35260 this.regions[region].onRender(this.el)
35264 var size = this.getViewSize();
35265 var w = size.width;
35266 var h = size.height;
35271 //var x = 0, y = 0;
35273 var rs = this.regions;
35274 var north = rs["north"];
35275 var south = rs["south"];
35276 var west = rs["west"];
35277 var east = rs["east"];
35278 var center = rs["center"];
35279 //if(this.hideOnLayout){ // not supported anymore
35280 //c.el.setStyle("display", "none");
35282 if(north && north.isVisible()){
35283 var b = north.getBox();
35284 var m = north.getMargins();
35285 b.width = w - (m.left+m.right);
35288 centerY = b.height + b.y + m.bottom;
35289 centerH -= centerY;
35290 north.updateBox(this.safeBox(b));
35292 if(south && south.isVisible()){
35293 var b = south.getBox();
35294 var m = south.getMargins();
35295 b.width = w - (m.left+m.right);
35297 var totalHeight = (b.height + m.top + m.bottom);
35298 b.y = h - totalHeight + m.top;
35299 centerH -= totalHeight;
35300 south.updateBox(this.safeBox(b));
35302 if(west && west.isVisible()){
35303 var b = west.getBox();
35304 var m = west.getMargins();
35305 b.height = centerH - (m.top+m.bottom);
35307 b.y = centerY + m.top;
35308 var totalWidth = (b.width + m.left + m.right);
35309 centerX += totalWidth;
35310 centerW -= totalWidth;
35311 west.updateBox(this.safeBox(b));
35313 if(east && east.isVisible()){
35314 var b = east.getBox();
35315 var m = east.getMargins();
35316 b.height = centerH - (m.top+m.bottom);
35317 var totalWidth = (b.width + m.left + m.right);
35318 b.x = w - totalWidth + m.left;
35319 b.y = centerY + m.top;
35320 centerW -= totalWidth;
35321 east.updateBox(this.safeBox(b));
35324 var m = center.getMargins();
35326 x: centerX + m.left,
35327 y: centerY + m.top,
35328 width: centerW - (m.left+m.right),
35329 height: centerH - (m.top+m.bottom)
35331 //if(this.hideOnLayout){
35332 //center.el.setStyle("display", "block");
35334 center.updateBox(this.safeBox(centerBox));
35337 this.fireEvent("layout", this);
35341 safeBox : function(box){
35342 box.width = Math.max(0, box.width);
35343 box.height = Math.max(0, box.height);
35348 * Adds a ContentPanel (or subclass) to this layout.
35349 * @param {String} target The target region key (north, south, east, west or center).
35350 * @param {Roo.ContentPanel} panel The panel to add
35351 * @return {Roo.ContentPanel} The added panel
35353 add : function(target, panel){
35355 target = target.toLowerCase();
35356 return this.regions[target].add(panel);
35360 * Remove a ContentPanel (or subclass) to this layout.
35361 * @param {String} target The target region key (north, south, east, west or center).
35362 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
35363 * @return {Roo.ContentPanel} The removed panel
35365 remove : function(target, panel){
35366 target = target.toLowerCase();
35367 return this.regions[target].remove(panel);
35371 * Searches all regions for a panel with the specified id
35372 * @param {String} panelId
35373 * @return {Roo.ContentPanel} The panel or null if it wasn't found
35375 findPanel : function(panelId){
35376 var rs = this.regions;
35377 for(var target in rs){
35378 if(typeof rs[target] != "function"){
35379 var p = rs[target].getPanel(panelId);
35389 * Searches all regions for a panel with the specified id and activates (shows) it.
35390 * @param {String/ContentPanel} panelId The panels id or the panel itself
35391 * @return {Roo.ContentPanel} The shown panel or null
35393 showPanel : function(panelId) {
35394 var rs = this.regions;
35395 for(var target in rs){
35396 var r = rs[target];
35397 if(typeof r != "function"){
35398 if(r.hasPanel(panelId)){
35399 return r.showPanel(panelId);
35407 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
35408 * @param {Roo.state.Provider} provider (optional) An alternate state provider
35411 restoreState : function(provider){
35413 provider = Roo.state.Manager;
35415 var sm = new Roo.LayoutStateManager();
35416 sm.init(this, provider);
35422 * Adds a xtype elements to the layout.
35426 xtype : 'ContentPanel',
35433 xtype : 'NestedLayoutPanel',
35439 items : [ ... list of content panels or nested layout panels.. ]
35443 * @param {Object} cfg Xtype definition of item to add.
35445 addxtype : function(cfg)
35447 // basically accepts a pannel...
35448 // can accept a layout region..!?!?
35449 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
35452 // theory? children can only be panels??
35454 //if (!cfg.xtype.match(/Panel$/)) {
35459 if (typeof(cfg.region) == 'undefined') {
35460 Roo.log("Failed to add Panel, region was not set");
35464 var region = cfg.region;
35470 xitems = cfg.items;
35475 if ( region == 'center') {
35476 Roo.log("Center: " + cfg.title);
35482 case 'Content': // ContentPanel (el, cfg)
35483 case 'Scroll': // ContentPanel (el, cfg)
35485 cfg.autoCreate = cfg.autoCreate || true;
35486 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35488 // var el = this.el.createChild();
35489 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
35492 this.add(region, ret);
35496 case 'TreePanel': // our new panel!
35497 cfg.el = this.el.createChild();
35498 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
35499 this.add(region, ret);
35504 // create a new Layout (which is a Border Layout...
35506 var clayout = cfg.layout;
35507 clayout.el = this.el.createChild();
35508 clayout.items = clayout.items || [];
35512 // replace this exitems with the clayout ones..
35513 xitems = clayout.items;
35515 // force background off if it's in center...
35516 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
35517 cfg.background = false;
35519 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
35522 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35523 //console.log('adding nested layout panel ' + cfg.toSource());
35524 this.add(region, ret);
35525 nb = {}; /// find first...
35530 // needs grid and region
35532 //var el = this.getRegion(region).el.createChild();
35534 *var el = this.el.createChild();
35535 // create the grid first...
35536 cfg.grid.container = el;
35537 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
35540 if (region == 'center' && this.active ) {
35541 cfg.background = false;
35544 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35546 this.add(region, ret);
35548 if (cfg.background) {
35549 // render grid on panel activation (if panel background)
35550 ret.on('activate', function(gp) {
35551 if (!gp.grid.rendered) {
35552 // gp.grid.render(el);
35556 // cfg.grid.render(el);
35562 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
35563 // it was the old xcomponent building that caused this before.
35564 // espeically if border is the top element in the tree.
35574 if (typeof(Roo[cfg.xtype]) != 'undefined') {
35576 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
35577 this.add(region, ret);
35581 throw "Can not add '" + cfg.xtype + "' to Border";
35587 this.beginUpdate();
35591 Roo.each(xitems, function(i) {
35592 region = nb && i.region ? i.region : false;
35594 var add = ret.addxtype(i);
35597 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
35598 if (!i.background) {
35599 abn[region] = nb[region] ;
35606 // make the last non-background panel active..
35607 //if (nb) { Roo.log(abn); }
35610 for(var r in abn) {
35611 region = this.getRegion(r);
35613 // tried using nb[r], but it does not work..
35615 region.showPanel(abn[r]);
35626 factory : function(cfg)
35629 var validRegions = Roo.bootstrap.layout.Border.regions;
35631 var target = cfg.region;
35634 var r = Roo.bootstrap.layout;
35638 return new r.North(cfg);
35640 return new r.South(cfg);
35642 return new r.East(cfg);
35644 return new r.West(cfg);
35646 return new r.Center(cfg);
35648 throw 'Layout region "'+target+'" not supported.';
35655 * Ext JS Library 1.1.1
35656 * Copyright(c) 2006-2007, Ext JS, LLC.
35658 * Originally Released Under LGPL - original licence link has changed is not relivant.
35661 * <script type="text/javascript">
35665 * @class Roo.bootstrap.layout.Basic
35666 * @extends Roo.util.Observable
35667 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
35668 * and does not have a titlebar, tabs or any other features. All it does is size and position
35669 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
35670 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35671 * @cfg {string} region the region that it inhabits..
35672 * @cfg {bool} skipConfig skip config?
35676 Roo.bootstrap.layout.Basic = function(config){
35678 this.mgr = config.mgr;
35680 this.position = config.region;
35682 var skipConfig = config.skipConfig;
35686 * @scope Roo.BasicLayoutRegion
35690 * @event beforeremove
35691 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
35692 * @param {Roo.LayoutRegion} this
35693 * @param {Roo.ContentPanel} panel The panel
35694 * @param {Object} e The cancel event object
35696 "beforeremove" : true,
35698 * @event invalidated
35699 * Fires when the layout for this region is changed.
35700 * @param {Roo.LayoutRegion} this
35702 "invalidated" : true,
35704 * @event visibilitychange
35705 * Fires when this region is shown or hidden
35706 * @param {Roo.LayoutRegion} this
35707 * @param {Boolean} visibility true or false
35709 "visibilitychange" : true,
35711 * @event paneladded
35712 * Fires when a panel is added.
35713 * @param {Roo.LayoutRegion} this
35714 * @param {Roo.ContentPanel} panel The panel
35716 "paneladded" : true,
35718 * @event panelremoved
35719 * Fires when a panel is removed.
35720 * @param {Roo.LayoutRegion} this
35721 * @param {Roo.ContentPanel} panel The panel
35723 "panelremoved" : true,
35725 * @event beforecollapse
35726 * Fires when this region before collapse.
35727 * @param {Roo.LayoutRegion} this
35729 "beforecollapse" : true,
35732 * Fires when this region is collapsed.
35733 * @param {Roo.LayoutRegion} this
35735 "collapsed" : true,
35738 * Fires when this region is expanded.
35739 * @param {Roo.LayoutRegion} this
35744 * Fires when this region is slid into view.
35745 * @param {Roo.LayoutRegion} this
35747 "slideshow" : true,
35750 * Fires when this region slides out of view.
35751 * @param {Roo.LayoutRegion} this
35753 "slidehide" : true,
35755 * @event panelactivated
35756 * Fires when a panel is activated.
35757 * @param {Roo.LayoutRegion} this
35758 * @param {Roo.ContentPanel} panel The activated panel
35760 "panelactivated" : true,
35763 * Fires when the user resizes this region.
35764 * @param {Roo.LayoutRegion} this
35765 * @param {Number} newSize The new size (width for east/west, height for north/south)
35769 /** A collection of panels in this region. @type Roo.util.MixedCollection */
35770 this.panels = new Roo.util.MixedCollection();
35771 this.panels.getKey = this.getPanelId.createDelegate(this);
35773 this.activePanel = null;
35774 // ensure listeners are added...
35776 if (config.listeners || config.events) {
35777 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
35778 listeners : config.listeners || {},
35779 events : config.events || {}
35783 if(skipConfig !== true){
35784 this.applyConfig(config);
35788 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
35790 getPanelId : function(p){
35794 applyConfig : function(config){
35795 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35796 this.config = config;
35801 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
35802 * the width, for horizontal (north, south) the height.
35803 * @param {Number} newSize The new width or height
35805 resizeTo : function(newSize){
35806 var el = this.el ? this.el :
35807 (this.activePanel ? this.activePanel.getEl() : null);
35809 switch(this.position){
35812 el.setWidth(newSize);
35813 this.fireEvent("resized", this, newSize);
35817 el.setHeight(newSize);
35818 this.fireEvent("resized", this, newSize);
35824 getBox : function(){
35825 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
35828 getMargins : function(){
35829 return this.margins;
35832 updateBox : function(box){
35834 var el = this.activePanel.getEl();
35835 el.dom.style.left = box.x + "px";
35836 el.dom.style.top = box.y + "px";
35837 this.activePanel.setSize(box.width, box.height);
35841 * Returns the container element for this region.
35842 * @return {Roo.Element}
35844 getEl : function(){
35845 return this.activePanel;
35849 * Returns true if this region is currently visible.
35850 * @return {Boolean}
35852 isVisible : function(){
35853 return this.activePanel ? true : false;
35856 setActivePanel : function(panel){
35857 panel = this.getPanel(panel);
35858 if(this.activePanel && this.activePanel != panel){
35859 this.activePanel.setActiveState(false);
35860 this.activePanel.getEl().setLeftTop(-10000,-10000);
35862 this.activePanel = panel;
35863 panel.setActiveState(true);
35865 panel.setSize(this.box.width, this.box.height);
35867 this.fireEvent("panelactivated", this, panel);
35868 this.fireEvent("invalidated");
35872 * Show the specified panel.
35873 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
35874 * @return {Roo.ContentPanel} The shown panel or null
35876 showPanel : function(panel){
35877 panel = this.getPanel(panel);
35879 this.setActivePanel(panel);
35885 * Get the active panel for this region.
35886 * @return {Roo.ContentPanel} The active panel or null
35888 getActivePanel : function(){
35889 return this.activePanel;
35893 * Add the passed ContentPanel(s)
35894 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35895 * @return {Roo.ContentPanel} The panel added (if only one was added)
35897 add : function(panel){
35898 if(arguments.length > 1){
35899 for(var i = 0, len = arguments.length; i < len; i++) {
35900 this.add(arguments[i]);
35904 if(this.hasPanel(panel)){
35905 this.showPanel(panel);
35908 var el = panel.getEl();
35909 if(el.dom.parentNode != this.mgr.el.dom){
35910 this.mgr.el.dom.appendChild(el.dom);
35912 if(panel.setRegion){
35913 panel.setRegion(this);
35915 this.panels.add(panel);
35916 el.setStyle("position", "absolute");
35917 if(!panel.background){
35918 this.setActivePanel(panel);
35919 if(this.config.initialSize && this.panels.getCount()==1){
35920 this.resizeTo(this.config.initialSize);
35923 this.fireEvent("paneladded", this, panel);
35928 * Returns true if the panel is in this region.
35929 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35930 * @return {Boolean}
35932 hasPanel : function(panel){
35933 if(typeof panel == "object"){ // must be panel obj
35934 panel = panel.getId();
35936 return this.getPanel(panel) ? true : false;
35940 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35941 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35942 * @param {Boolean} preservePanel Overrides the config preservePanel option
35943 * @return {Roo.ContentPanel} The panel that was removed
35945 remove : function(panel, preservePanel){
35946 panel = this.getPanel(panel);
35951 this.fireEvent("beforeremove", this, panel, e);
35952 if(e.cancel === true){
35955 var panelId = panel.getId();
35956 this.panels.removeKey(panelId);
35961 * Returns the panel specified or null if it's not in this region.
35962 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35963 * @return {Roo.ContentPanel}
35965 getPanel : function(id){
35966 if(typeof id == "object"){ // must be panel obj
35969 return this.panels.get(id);
35973 * Returns this regions position (north/south/east/west/center).
35976 getPosition: function(){
35977 return this.position;
35981 * Ext JS Library 1.1.1
35982 * Copyright(c) 2006-2007, Ext JS, LLC.
35984 * Originally Released Under LGPL - original licence link has changed is not relivant.
35987 * <script type="text/javascript">
35991 * @class Roo.bootstrap.layout.Region
35992 * @extends Roo.bootstrap.layout.Basic
35993 * This class represents a region in a layout manager.
35995 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
35996 * @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})
35997 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
35998 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
35999 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
36000 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
36001 * @cfg {String} title The title for the region (overrides panel titles)
36002 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
36003 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
36004 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
36005 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
36006 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
36007 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
36008 * the space available, similar to FireFox 1.5 tabs (defaults to false)
36009 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
36010 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
36011 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
36013 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
36014 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
36015 * @cfg {Boolean} disableTabTips True to disable tab tooltips
36016 * @cfg {Number} width For East/West panels
36017 * @cfg {Number} height For North/South panels
36018 * @cfg {Boolean} split To show the splitter
36019 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
36021 * @cfg {string} cls Extra CSS classes to add to region
36023 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
36024 * @cfg {string} region the region that it inhabits..
36027 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
36028 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
36030 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
36031 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
36032 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
36034 Roo.bootstrap.layout.Region = function(config)
36036 this.applyConfig(config);
36038 var mgr = config.mgr;
36039 var pos = config.region;
36040 config.skipConfig = true;
36041 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
36044 this.onRender(mgr.el);
36047 this.visible = true;
36048 this.collapsed = false;
36049 this.unrendered_panels = [];
36052 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
36054 position: '', // set by wrapper (eg. north/south etc..)
36055 unrendered_panels : null, // unrendered panels.
36057 tabPosition : false,
36059 mgr: false, // points to 'Border'
36062 createBody : function(){
36063 /** This region's body element
36064 * @type Roo.Element */
36065 this.bodyEl = this.el.createChild({
36067 cls: "roo-layout-panel-body tab-content" // bootstrap added...
36071 onRender: function(ctr, pos)
36073 var dh = Roo.DomHelper;
36074 /** This region's container element
36075 * @type Roo.Element */
36076 this.el = dh.append(ctr.dom, {
36078 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
36080 /** This region's title element
36081 * @type Roo.Element */
36083 this.titleEl = dh.append(this.el.dom, {
36085 unselectable: "on",
36086 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
36088 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
36089 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
36093 this.titleEl.enableDisplayMode();
36094 /** This region's title text element
36095 * @type HTMLElement */
36096 this.titleTextEl = this.titleEl.dom.firstChild;
36097 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
36099 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
36100 this.closeBtn.enableDisplayMode();
36101 this.closeBtn.on("click", this.closeClicked, this);
36102 this.closeBtn.hide();
36104 this.createBody(this.config);
36105 if(this.config.hideWhenEmpty){
36107 this.on("paneladded", this.validateVisibility, this);
36108 this.on("panelremoved", this.validateVisibility, this);
36110 if(this.autoScroll){
36111 this.bodyEl.setStyle("overflow", "auto");
36113 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
36115 //if(c.titlebar !== false){
36116 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
36117 this.titleEl.hide();
36119 this.titleEl.show();
36120 if(this.config.title){
36121 this.titleTextEl.innerHTML = this.config.title;
36125 if(this.config.collapsed){
36126 this.collapse(true);
36128 if(this.config.hidden){
36132 if (this.unrendered_panels && this.unrendered_panels.length) {
36133 for (var i =0;i< this.unrendered_panels.length; i++) {
36134 this.add(this.unrendered_panels[i]);
36136 this.unrendered_panels = null;
36142 applyConfig : function(c)
36145 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
36146 var dh = Roo.DomHelper;
36147 if(c.titlebar !== false){
36148 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
36149 this.collapseBtn.on("click", this.collapse, this);
36150 this.collapseBtn.enableDisplayMode();
36152 if(c.showPin === true || this.showPin){
36153 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
36154 this.stickBtn.enableDisplayMode();
36155 this.stickBtn.on("click", this.expand, this);
36156 this.stickBtn.hide();
36161 /** This region's collapsed element
36162 * @type Roo.Element */
36165 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
36166 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
36169 if(c.floatable !== false){
36170 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
36171 this.collapsedEl.on("click", this.collapseClick, this);
36174 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
36175 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
36176 id: "message", unselectable: "on", style:{"float":"left"}});
36177 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
36179 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
36180 this.expandBtn.on("click", this.expand, this);
36184 if(this.collapseBtn){
36185 this.collapseBtn.setVisible(c.collapsible == true);
36188 this.cmargins = c.cmargins || this.cmargins ||
36189 (this.position == "west" || this.position == "east" ?
36190 {top: 0, left: 2, right:2, bottom: 0} :
36191 {top: 2, left: 0, right:0, bottom: 2});
36193 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
36196 this.tabPosition = [ 'top','bottom', 'west'].indexOf(c.tabPosition) > -1 ? c.tabPosition : "top";
36198 this.autoScroll = c.autoScroll || false;
36203 this.duration = c.duration || .30;
36204 this.slideDuration = c.slideDuration || .45;
36209 * Returns true if this region is currently visible.
36210 * @return {Boolean}
36212 isVisible : function(){
36213 return this.visible;
36217 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
36218 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
36220 //setCollapsedTitle : function(title){
36221 // title = title || " ";
36222 // if(this.collapsedTitleTextEl){
36223 // this.collapsedTitleTextEl.innerHTML = title;
36227 getBox : function(){
36229 // if(!this.collapsed){
36230 b = this.el.getBox(false, true);
36232 // b = this.collapsedEl.getBox(false, true);
36237 getMargins : function(){
36238 return this.margins;
36239 //return this.collapsed ? this.cmargins : this.margins;
36242 highlight : function(){
36243 this.el.addClass("x-layout-panel-dragover");
36246 unhighlight : function(){
36247 this.el.removeClass("x-layout-panel-dragover");
36250 updateBox : function(box)
36252 if (!this.bodyEl) {
36253 return; // not rendered yet..
36257 if(!this.collapsed){
36258 this.el.dom.style.left = box.x + "px";
36259 this.el.dom.style.top = box.y + "px";
36260 this.updateBody(box.width, box.height);
36262 this.collapsedEl.dom.style.left = box.x + "px";
36263 this.collapsedEl.dom.style.top = box.y + "px";
36264 this.collapsedEl.setSize(box.width, box.height);
36267 this.tabs.autoSizeTabs();
36271 updateBody : function(w, h)
36274 this.el.setWidth(w);
36275 w -= this.el.getBorderWidth("rl");
36276 if(this.config.adjustments){
36277 w += this.config.adjustments[0];
36280 if(h !== null && h > 0){
36281 this.el.setHeight(h);
36282 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
36283 h -= this.el.getBorderWidth("tb");
36284 if(this.config.adjustments){
36285 h += this.config.adjustments[1];
36287 this.bodyEl.setHeight(h);
36289 h = this.tabs.syncHeight(h);
36292 if(this.panelSize){
36293 w = w !== null ? w : this.panelSize.width;
36294 h = h !== null ? h : this.panelSize.height;
36296 if(this.activePanel){
36297 var el = this.activePanel.getEl();
36298 w = w !== null ? w : el.getWidth();
36299 h = h !== null ? h : el.getHeight();
36300 this.panelSize = {width: w, height: h};
36301 this.activePanel.setSize(w, h);
36303 if(Roo.isIE && this.tabs){
36304 this.tabs.el.repaint();
36309 * Returns the container element for this region.
36310 * @return {Roo.Element}
36312 getEl : function(){
36317 * Hides this region.
36320 //if(!this.collapsed){
36321 this.el.dom.style.left = "-2000px";
36324 // this.collapsedEl.dom.style.left = "-2000px";
36325 // this.collapsedEl.hide();
36327 this.visible = false;
36328 this.fireEvent("visibilitychange", this, false);
36332 * Shows this region if it was previously hidden.
36335 //if(!this.collapsed){
36338 // this.collapsedEl.show();
36340 this.visible = true;
36341 this.fireEvent("visibilitychange", this, true);
36344 closeClicked : function(){
36345 if(this.activePanel){
36346 this.remove(this.activePanel);
36350 collapseClick : function(e){
36352 e.stopPropagation();
36355 e.stopPropagation();
36361 * Collapses this region.
36362 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
36365 collapse : function(skipAnim, skipCheck = false){
36366 if(this.collapsed) {
36370 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
36372 this.collapsed = true;
36374 this.split.el.hide();
36376 if(this.config.animate && skipAnim !== true){
36377 this.fireEvent("invalidated", this);
36378 this.animateCollapse();
36380 this.el.setLocation(-20000,-20000);
36382 this.collapsedEl.show();
36383 this.fireEvent("collapsed", this);
36384 this.fireEvent("invalidated", this);
36390 animateCollapse : function(){
36395 * Expands this region if it was previously collapsed.
36396 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
36397 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
36400 expand : function(e, skipAnim){
36402 e.stopPropagation();
36404 if(!this.collapsed || this.el.hasActiveFx()) {
36408 this.afterSlideIn();
36411 this.collapsed = false;
36412 if(this.config.animate && skipAnim !== true){
36413 this.animateExpand();
36417 this.split.el.show();
36419 this.collapsedEl.setLocation(-2000,-2000);
36420 this.collapsedEl.hide();
36421 this.fireEvent("invalidated", this);
36422 this.fireEvent("expanded", this);
36426 animateExpand : function(){
36430 initTabs : function()
36432 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
36434 var ts = new Roo.bootstrap.panel.Tabs({
36435 el: this.bodyEl.dom,
36437 tabPosition: this.tabPosition ? this.tabPosition : 'top',
36438 disableTooltips: this.config.disableTabTips,
36439 toolbar : this.config.toolbar
36442 if(this.config.hideTabs){
36443 ts.stripWrap.setDisplayed(false);
36446 ts.resizeTabs = this.config.resizeTabs === true;
36447 ts.minTabWidth = this.config.minTabWidth || 40;
36448 ts.maxTabWidth = this.config.maxTabWidth || 250;
36449 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
36450 ts.monitorResize = false;
36451 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
36452 ts.bodyEl.addClass('roo-layout-tabs-body');
36453 this.panels.each(this.initPanelAsTab, this);
36456 initPanelAsTab : function(panel){
36457 var ti = this.tabs.addTab(
36461 this.config.closeOnTab && panel.isClosable(),
36464 if(panel.tabTip !== undefined){
36465 ti.setTooltip(panel.tabTip);
36467 ti.on("activate", function(){
36468 this.setActivePanel(panel);
36471 if(this.config.closeOnTab){
36472 ti.on("beforeclose", function(t, e){
36474 this.remove(panel);
36478 panel.tabItem = ti;
36483 updatePanelTitle : function(panel, title)
36485 if(this.activePanel == panel){
36486 this.updateTitle(title);
36489 var ti = this.tabs.getTab(panel.getEl().id);
36491 if(panel.tabTip !== undefined){
36492 ti.setTooltip(panel.tabTip);
36497 updateTitle : function(title){
36498 if(this.titleTextEl && !this.config.title){
36499 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
36503 setActivePanel : function(panel)
36505 panel = this.getPanel(panel);
36506 if(this.activePanel && this.activePanel != panel){
36507 if(this.activePanel.setActiveState(false) === false){
36511 this.activePanel = panel;
36512 panel.setActiveState(true);
36513 if(this.panelSize){
36514 panel.setSize(this.panelSize.width, this.panelSize.height);
36517 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
36519 this.updateTitle(panel.getTitle());
36521 this.fireEvent("invalidated", this);
36523 this.fireEvent("panelactivated", this, panel);
36527 * Shows the specified panel.
36528 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
36529 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
36531 showPanel : function(panel)
36533 panel = this.getPanel(panel);
36536 var tab = this.tabs.getTab(panel.getEl().id);
36537 if(tab.isHidden()){
36538 this.tabs.unhideTab(tab.id);
36542 this.setActivePanel(panel);
36549 * Get the active panel for this region.
36550 * @return {Roo.ContentPanel} The active panel or null
36552 getActivePanel : function(){
36553 return this.activePanel;
36556 validateVisibility : function(){
36557 if(this.panels.getCount() < 1){
36558 this.updateTitle(" ");
36559 this.closeBtn.hide();
36562 if(!this.isVisible()){
36569 * Adds the passed ContentPanel(s) to this region.
36570 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
36571 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
36573 add : function(panel)
36575 if(arguments.length > 1){
36576 for(var i = 0, len = arguments.length; i < len; i++) {
36577 this.add(arguments[i]);
36582 // if we have not been rendered yet, then we can not really do much of this..
36583 if (!this.bodyEl) {
36584 this.unrendered_panels.push(panel);
36591 if(this.hasPanel(panel)){
36592 this.showPanel(panel);
36595 panel.setRegion(this);
36596 this.panels.add(panel);
36597 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
36598 // sinle panel - no tab...?? would it not be better to render it with the tabs,
36599 // and hide them... ???
36600 this.bodyEl.dom.appendChild(panel.getEl().dom);
36601 if(panel.background !== true){
36602 this.setActivePanel(panel);
36604 this.fireEvent("paneladded", this, panel);
36611 this.initPanelAsTab(panel);
36615 if(panel.background !== true){
36616 this.tabs.activate(panel.getEl().id);
36618 this.fireEvent("paneladded", this, panel);
36623 * Hides the tab for the specified panel.
36624 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36626 hidePanel : function(panel){
36627 if(this.tabs && (panel = this.getPanel(panel))){
36628 this.tabs.hideTab(panel.getEl().id);
36633 * Unhides the tab for a previously hidden panel.
36634 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36636 unhidePanel : function(panel){
36637 if(this.tabs && (panel = this.getPanel(panel))){
36638 this.tabs.unhideTab(panel.getEl().id);
36642 clearPanels : function(){
36643 while(this.panels.getCount() > 0){
36644 this.remove(this.panels.first());
36649 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
36650 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36651 * @param {Boolean} preservePanel Overrides the config preservePanel option
36652 * @return {Roo.ContentPanel} The panel that was removed
36654 remove : function(panel, preservePanel)
36656 panel = this.getPanel(panel);
36661 this.fireEvent("beforeremove", this, panel, e);
36662 if(e.cancel === true){
36665 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
36666 var panelId = panel.getId();
36667 this.panels.removeKey(panelId);
36669 document.body.appendChild(panel.getEl().dom);
36672 this.tabs.removeTab(panel.getEl().id);
36673 }else if (!preservePanel){
36674 this.bodyEl.dom.removeChild(panel.getEl().dom);
36676 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
36677 var p = this.panels.first();
36678 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
36679 tempEl.appendChild(p.getEl().dom);
36680 this.bodyEl.update("");
36681 this.bodyEl.dom.appendChild(p.getEl().dom);
36683 this.updateTitle(p.getTitle());
36685 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
36686 this.setActivePanel(p);
36688 panel.setRegion(null);
36689 if(this.activePanel == panel){
36690 this.activePanel = null;
36692 if(this.config.autoDestroy !== false && preservePanel !== true){
36693 try{panel.destroy();}catch(e){}
36695 this.fireEvent("panelremoved", this, panel);
36700 * Returns the TabPanel component used by this region
36701 * @return {Roo.TabPanel}
36703 getTabs : function(){
36707 createTool : function(parentEl, className){
36708 var btn = Roo.DomHelper.append(parentEl, {
36710 cls: "x-layout-tools-button",
36713 cls: "roo-layout-tools-button-inner " + className,
36717 btn.addClassOnOver("roo-layout-tools-button-over");
36722 * Ext JS Library 1.1.1
36723 * Copyright(c) 2006-2007, Ext JS, LLC.
36725 * Originally Released Under LGPL - original licence link has changed is not relivant.
36728 * <script type="text/javascript">
36734 * @class Roo.SplitLayoutRegion
36735 * @extends Roo.LayoutRegion
36736 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
36738 Roo.bootstrap.layout.Split = function(config){
36739 this.cursor = config.cursor;
36740 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
36743 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
36745 splitTip : "Drag to resize.",
36746 collapsibleSplitTip : "Drag to resize. Double click to hide.",
36747 useSplitTips : false,
36749 applyConfig : function(config){
36750 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
36753 onRender : function(ctr,pos) {
36755 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
36756 if(!this.config.split){
36761 var splitEl = Roo.DomHelper.append(ctr.dom, {
36763 id: this.el.id + "-split",
36764 cls: "roo-layout-split roo-layout-split-"+this.position,
36767 /** The SplitBar for this region
36768 * @type Roo.SplitBar */
36769 // does not exist yet...
36770 Roo.log([this.position, this.orientation]);
36772 this.split = new Roo.bootstrap.SplitBar({
36773 dragElement : splitEl,
36774 resizingElement: this.el,
36775 orientation : this.orientation
36778 this.split.on("moved", this.onSplitMove, this);
36779 this.split.useShim = this.config.useShim === true;
36780 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
36781 if(this.useSplitTips){
36782 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
36784 //if(config.collapsible){
36785 // this.split.el.on("dblclick", this.collapse, this);
36788 if(typeof this.config.minSize != "undefined"){
36789 this.split.minSize = this.config.minSize;
36791 if(typeof this.config.maxSize != "undefined"){
36792 this.split.maxSize = this.config.maxSize;
36794 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
36795 this.hideSplitter();
36800 getHMaxSize : function(){
36801 var cmax = this.config.maxSize || 10000;
36802 var center = this.mgr.getRegion("center");
36803 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
36806 getVMaxSize : function(){
36807 var cmax = this.config.maxSize || 10000;
36808 var center = this.mgr.getRegion("center");
36809 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
36812 onSplitMove : function(split, newSize){
36813 this.fireEvent("resized", this, newSize);
36817 * Returns the {@link Roo.SplitBar} for this region.
36818 * @return {Roo.SplitBar}
36820 getSplitBar : function(){
36825 this.hideSplitter();
36826 Roo.bootstrap.layout.Split.superclass.hide.call(this);
36829 hideSplitter : function(){
36831 this.split.el.setLocation(-2000,-2000);
36832 this.split.el.hide();
36838 this.split.el.show();
36840 Roo.bootstrap.layout.Split.superclass.show.call(this);
36843 beforeSlide: function(){
36844 if(Roo.isGecko){// firefox overflow auto bug workaround
36845 this.bodyEl.clip();
36847 this.tabs.bodyEl.clip();
36849 if(this.activePanel){
36850 this.activePanel.getEl().clip();
36852 if(this.activePanel.beforeSlide){
36853 this.activePanel.beforeSlide();
36859 afterSlide : function(){
36860 if(Roo.isGecko){// firefox overflow auto bug workaround
36861 this.bodyEl.unclip();
36863 this.tabs.bodyEl.unclip();
36865 if(this.activePanel){
36866 this.activePanel.getEl().unclip();
36867 if(this.activePanel.afterSlide){
36868 this.activePanel.afterSlide();
36874 initAutoHide : function(){
36875 if(this.autoHide !== false){
36876 if(!this.autoHideHd){
36877 var st = new Roo.util.DelayedTask(this.slideIn, this);
36878 this.autoHideHd = {
36879 "mouseout": function(e){
36880 if(!e.within(this.el, true)){
36884 "mouseover" : function(e){
36890 this.el.on(this.autoHideHd);
36894 clearAutoHide : function(){
36895 if(this.autoHide !== false){
36896 this.el.un("mouseout", this.autoHideHd.mouseout);
36897 this.el.un("mouseover", this.autoHideHd.mouseover);
36901 clearMonitor : function(){
36902 Roo.get(document).un("click", this.slideInIf, this);
36905 // these names are backwards but not changed for compat
36906 slideOut : function(){
36907 if(this.isSlid || this.el.hasActiveFx()){
36910 this.isSlid = true;
36911 if(this.collapseBtn){
36912 this.collapseBtn.hide();
36914 this.closeBtnState = this.closeBtn.getStyle('display');
36915 this.closeBtn.hide();
36917 this.stickBtn.show();
36920 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
36921 this.beforeSlide();
36922 this.el.setStyle("z-index", 10001);
36923 this.el.slideIn(this.getSlideAnchor(), {
36924 callback: function(){
36926 this.initAutoHide();
36927 Roo.get(document).on("click", this.slideInIf, this);
36928 this.fireEvent("slideshow", this);
36935 afterSlideIn : function(){
36936 this.clearAutoHide();
36937 this.isSlid = false;
36938 this.clearMonitor();
36939 this.el.setStyle("z-index", "");
36940 if(this.collapseBtn){
36941 this.collapseBtn.show();
36943 this.closeBtn.setStyle('display', this.closeBtnState);
36945 this.stickBtn.hide();
36947 this.fireEvent("slidehide", this);
36950 slideIn : function(cb){
36951 if(!this.isSlid || this.el.hasActiveFx()){
36955 this.isSlid = false;
36956 this.beforeSlide();
36957 this.el.slideOut(this.getSlideAnchor(), {
36958 callback: function(){
36959 this.el.setLeftTop(-10000, -10000);
36961 this.afterSlideIn();
36969 slideInIf : function(e){
36970 if(!e.within(this.el)){
36975 animateCollapse : function(){
36976 this.beforeSlide();
36977 this.el.setStyle("z-index", 20000);
36978 var anchor = this.getSlideAnchor();
36979 this.el.slideOut(anchor, {
36980 callback : function(){
36981 this.el.setStyle("z-index", "");
36982 this.collapsedEl.slideIn(anchor, {duration:.3});
36984 this.el.setLocation(-10000,-10000);
36986 this.fireEvent("collapsed", this);
36993 animateExpand : function(){
36994 this.beforeSlide();
36995 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
36996 this.el.setStyle("z-index", 20000);
36997 this.collapsedEl.hide({
37000 this.el.slideIn(this.getSlideAnchor(), {
37001 callback : function(){
37002 this.el.setStyle("z-index", "");
37005 this.split.el.show();
37007 this.fireEvent("invalidated", this);
37008 this.fireEvent("expanded", this);
37036 getAnchor : function(){
37037 return this.anchors[this.position];
37040 getCollapseAnchor : function(){
37041 return this.canchors[this.position];
37044 getSlideAnchor : function(){
37045 return this.sanchors[this.position];
37048 getAlignAdj : function(){
37049 var cm = this.cmargins;
37050 switch(this.position){
37066 getExpandAdj : function(){
37067 var c = this.collapsedEl, cm = this.cmargins;
37068 switch(this.position){
37070 return [-(cm.right+c.getWidth()+cm.left), 0];
37073 return [cm.right+c.getWidth()+cm.left, 0];
37076 return [0, -(cm.top+cm.bottom+c.getHeight())];
37079 return [0, cm.top+cm.bottom+c.getHeight()];
37085 * Ext JS Library 1.1.1
37086 * Copyright(c) 2006-2007, Ext JS, LLC.
37088 * Originally Released Under LGPL - original licence link has changed is not relivant.
37091 * <script type="text/javascript">
37094 * These classes are private internal classes
37096 Roo.bootstrap.layout.Center = function(config){
37097 config.region = "center";
37098 Roo.bootstrap.layout.Region.call(this, config);
37099 this.visible = true;
37100 this.minWidth = config.minWidth || 20;
37101 this.minHeight = config.minHeight || 20;
37104 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
37106 // center panel can't be hidden
37110 // center panel can't be hidden
37113 getMinWidth: function(){
37114 return this.minWidth;
37117 getMinHeight: function(){
37118 return this.minHeight;
37132 Roo.bootstrap.layout.North = function(config)
37134 config.region = 'north';
37135 config.cursor = 'n-resize';
37137 Roo.bootstrap.layout.Split.call(this, config);
37141 this.split.placement = Roo.bootstrap.SplitBar.TOP;
37142 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
37143 this.split.el.addClass("roo-layout-split-v");
37145 var size = config.initialSize || config.height;
37146 if(typeof size != "undefined"){
37147 this.el.setHeight(size);
37150 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
37152 orientation: Roo.bootstrap.SplitBar.VERTICAL,
37156 getBox : function(){
37157 if(this.collapsed){
37158 return this.collapsedEl.getBox();
37160 var box = this.el.getBox();
37162 box.height += this.split.el.getHeight();
37167 updateBox : function(box){
37168 if(this.split && !this.collapsed){
37169 box.height -= this.split.el.getHeight();
37170 this.split.el.setLeft(box.x);
37171 this.split.el.setTop(box.y+box.height);
37172 this.split.el.setWidth(box.width);
37174 if(this.collapsed){
37175 this.updateBody(box.width, null);
37177 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37185 Roo.bootstrap.layout.South = function(config){
37186 config.region = 'south';
37187 config.cursor = 's-resize';
37188 Roo.bootstrap.layout.Split.call(this, config);
37190 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
37191 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
37192 this.split.el.addClass("roo-layout-split-v");
37194 var size = config.initialSize || config.height;
37195 if(typeof size != "undefined"){
37196 this.el.setHeight(size);
37200 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
37201 orientation: Roo.bootstrap.SplitBar.VERTICAL,
37202 getBox : function(){
37203 if(this.collapsed){
37204 return this.collapsedEl.getBox();
37206 var box = this.el.getBox();
37208 var sh = this.split.el.getHeight();
37215 updateBox : function(box){
37216 if(this.split && !this.collapsed){
37217 var sh = this.split.el.getHeight();
37220 this.split.el.setLeft(box.x);
37221 this.split.el.setTop(box.y-sh);
37222 this.split.el.setWidth(box.width);
37224 if(this.collapsed){
37225 this.updateBody(box.width, null);
37227 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37231 Roo.bootstrap.layout.East = function(config){
37232 config.region = "east";
37233 config.cursor = "e-resize";
37234 Roo.bootstrap.layout.Split.call(this, config);
37236 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
37237 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
37238 this.split.el.addClass("roo-layout-split-h");
37240 var size = config.initialSize || config.width;
37241 if(typeof size != "undefined"){
37242 this.el.setWidth(size);
37245 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
37246 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
37247 getBox : function(){
37248 if(this.collapsed){
37249 return this.collapsedEl.getBox();
37251 var box = this.el.getBox();
37253 var sw = this.split.el.getWidth();
37260 updateBox : function(box){
37261 if(this.split && !this.collapsed){
37262 var sw = this.split.el.getWidth();
37264 this.split.el.setLeft(box.x);
37265 this.split.el.setTop(box.y);
37266 this.split.el.setHeight(box.height);
37269 if(this.collapsed){
37270 this.updateBody(null, box.height);
37272 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37276 Roo.bootstrap.layout.West = function(config){
37277 config.region = "west";
37278 config.cursor = "w-resize";
37280 Roo.bootstrap.layout.Split.call(this, config);
37282 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
37283 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
37284 this.split.el.addClass("roo-layout-split-h");
37288 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
37289 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
37291 onRender: function(ctr, pos)
37293 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
37294 var size = this.config.initialSize || this.config.width;
37295 if(typeof size != "undefined"){
37296 this.el.setWidth(size);
37300 getBox : function(){
37301 if(this.collapsed){
37302 return this.collapsedEl.getBox();
37304 var box = this.el.getBox();
37306 box.width += this.split.el.getWidth();
37311 updateBox : function(box){
37312 if(this.split && !this.collapsed){
37313 var sw = this.split.el.getWidth();
37315 this.split.el.setLeft(box.x+box.width);
37316 this.split.el.setTop(box.y);
37317 this.split.el.setHeight(box.height);
37319 if(this.collapsed){
37320 this.updateBody(null, box.height);
37322 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37324 });Roo.namespace("Roo.bootstrap.panel");/*
37326 * Ext JS Library 1.1.1
37327 * Copyright(c) 2006-2007, Ext JS, LLC.
37329 * Originally Released Under LGPL - original licence link has changed is not relivant.
37332 * <script type="text/javascript">
37335 * @class Roo.ContentPanel
37336 * @extends Roo.util.Observable
37337 * A basic ContentPanel element.
37338 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
37339 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
37340 * @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
37341 * @cfg {Boolean} closable True if the panel can be closed/removed
37342 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
37343 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
37344 * @cfg {Toolbar} toolbar A toolbar for this panel
37345 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
37346 * @cfg {String} title The title for this panel
37347 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
37348 * @cfg {String} url Calls {@link #setUrl} with this value
37349 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
37350 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
37351 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
37352 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
37353 * @cfg {Boolean} badges render the badges
37356 * Create a new ContentPanel.
37357 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
37358 * @param {String/Object} config A string to set only the title or a config object
37359 * @param {String} content (optional) Set the HTML content for this panel
37360 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
37362 Roo.bootstrap.panel.Content = function( config){
37364 this.tpl = config.tpl || false;
37366 var el = config.el;
37367 var content = config.content;
37369 if(config.autoCreate){ // xtype is available if this is called from factory
37372 this.el = Roo.get(el);
37373 if(!this.el && config && config.autoCreate){
37374 if(typeof config.autoCreate == "object"){
37375 if(!config.autoCreate.id){
37376 config.autoCreate.id = config.id||el;
37378 this.el = Roo.DomHelper.append(document.body,
37379 config.autoCreate, true);
37381 var elcfg = { tag: "div",
37382 cls: "roo-layout-inactive-content",
37386 elcfg.html = config.html;
37390 this.el = Roo.DomHelper.append(document.body, elcfg , true);
37393 this.closable = false;
37394 this.loaded = false;
37395 this.active = false;
37398 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
37400 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
37402 this.wrapEl = this.el; //this.el.wrap();
37404 if (config.toolbar.items) {
37405 ti = config.toolbar.items ;
37406 delete config.toolbar.items ;
37410 this.toolbar.render(this.wrapEl, 'before');
37411 for(var i =0;i < ti.length;i++) {
37412 // Roo.log(['add child', items[i]]);
37413 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37415 this.toolbar.items = nitems;
37416 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
37417 delete config.toolbar;
37421 // xtype created footer. - not sure if will work as we normally have to render first..
37422 if (this.footer && !this.footer.el && this.footer.xtype) {
37423 if (!this.wrapEl) {
37424 this.wrapEl = this.el.wrap();
37427 this.footer.container = this.wrapEl.createChild();
37429 this.footer = Roo.factory(this.footer, Roo);
37434 if(typeof config == "string"){
37435 this.title = config;
37437 Roo.apply(this, config);
37441 this.resizeEl = Roo.get(this.resizeEl, true);
37443 this.resizeEl = this.el;
37445 // handle view.xtype
37453 * Fires when this panel is activated.
37454 * @param {Roo.ContentPanel} this
37458 * @event deactivate
37459 * Fires when this panel is activated.
37460 * @param {Roo.ContentPanel} this
37462 "deactivate" : true,
37466 * Fires when this panel is resized if fitToFrame is true.
37467 * @param {Roo.ContentPanel} this
37468 * @param {Number} width The width after any component adjustments
37469 * @param {Number} height The height after any component adjustments
37475 * Fires when this tab is created
37476 * @param {Roo.ContentPanel} this
37487 if(this.autoScroll){
37488 this.resizeEl.setStyle("overflow", "auto");
37490 // fix randome scrolling
37491 //this.el.on('scroll', function() {
37492 // Roo.log('fix random scolling');
37493 // this.scrollTo('top',0);
37496 content = content || this.content;
37498 this.setContent(content);
37500 if(config && config.url){
37501 this.setUrl(this.url, this.params, this.loadOnce);
37506 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
37508 if (this.view && typeof(this.view.xtype) != 'undefined') {
37509 this.view.el = this.el.appendChild(document.createElement("div"));
37510 this.view = Roo.factory(this.view);
37511 this.view.render && this.view.render(false, '');
37515 this.fireEvent('render', this);
37518 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
37522 setRegion : function(region){
37523 this.region = region;
37524 this.setActiveClass(region && !this.background);
37528 setActiveClass: function(state)
37531 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
37532 this.el.setStyle('position','relative');
37534 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
37535 this.el.setStyle('position', 'absolute');
37540 * Returns the toolbar for this Panel if one was configured.
37541 * @return {Roo.Toolbar}
37543 getToolbar : function(){
37544 return this.toolbar;
37547 setActiveState : function(active)
37549 this.active = active;
37550 this.setActiveClass(active);
37552 if(this.fireEvent("deactivate", this) === false){
37557 this.fireEvent("activate", this);
37561 * Updates this panel's element
37562 * @param {String} content The new content
37563 * @param {Boolean} loadScripts (optional) true to look for and process scripts
37565 setContent : function(content, loadScripts){
37566 this.el.update(content, loadScripts);
37569 ignoreResize : function(w, h){
37570 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
37573 this.lastSize = {width: w, height: h};
37578 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
37579 * @return {Roo.UpdateManager} The UpdateManager
37581 getUpdateManager : function(){
37582 return this.el.getUpdateManager();
37585 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
37586 * @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:
37589 url: "your-url.php",
37590 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
37591 callback: yourFunction,
37592 scope: yourObject, //(optional scope)
37595 text: "Loading...",
37600 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
37601 * 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.
37602 * @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}
37603 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
37604 * @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.
37605 * @return {Roo.ContentPanel} this
37608 var um = this.el.getUpdateManager();
37609 um.update.apply(um, arguments);
37615 * 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.
37616 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
37617 * @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)
37618 * @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)
37619 * @return {Roo.UpdateManager} The UpdateManager
37621 setUrl : function(url, params, loadOnce){
37622 if(this.refreshDelegate){
37623 this.removeListener("activate", this.refreshDelegate);
37625 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
37626 this.on("activate", this.refreshDelegate);
37627 return this.el.getUpdateManager();
37630 _handleRefresh : function(url, params, loadOnce){
37631 if(!loadOnce || !this.loaded){
37632 var updater = this.el.getUpdateManager();
37633 updater.update(url, params, this._setLoaded.createDelegate(this));
37637 _setLoaded : function(){
37638 this.loaded = true;
37642 * Returns this panel's id
37645 getId : function(){
37650 * Returns this panel's element - used by regiosn to add.
37651 * @return {Roo.Element}
37653 getEl : function(){
37654 return this.wrapEl || this.el;
37659 adjustForComponents : function(width, height)
37661 //Roo.log('adjustForComponents ');
37662 if(this.resizeEl != this.el){
37663 width -= this.el.getFrameWidth('lr');
37664 height -= this.el.getFrameWidth('tb');
37667 var te = this.toolbar.getEl();
37668 te.setWidth(width);
37669 height -= te.getHeight();
37672 var te = this.footer.getEl();
37673 te.setWidth(width);
37674 height -= te.getHeight();
37678 if(this.adjustments){
37679 width += this.adjustments[0];
37680 height += this.adjustments[1];
37682 return {"width": width, "height": height};
37685 setSize : function(width, height){
37686 if(this.fitToFrame && !this.ignoreResize(width, height)){
37687 if(this.fitContainer && this.resizeEl != this.el){
37688 this.el.setSize(width, height);
37690 var size = this.adjustForComponents(width, height);
37691 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
37692 this.fireEvent('resize', this, size.width, size.height);
37697 * Returns this panel's title
37700 getTitle : function(){
37702 if (typeof(this.title) != 'object') {
37707 for (var k in this.title) {
37708 if (!this.title.hasOwnProperty(k)) {
37712 if (k.indexOf('-') >= 0) {
37713 var s = k.split('-');
37714 for (var i = 0; i<s.length; i++) {
37715 t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
37718 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
37725 * Set this panel's title
37726 * @param {String} title
37728 setTitle : function(title){
37729 this.title = title;
37731 this.region.updatePanelTitle(this, title);
37736 * Returns true is this panel was configured to be closable
37737 * @return {Boolean}
37739 isClosable : function(){
37740 return this.closable;
37743 beforeSlide : function(){
37745 this.resizeEl.clip();
37748 afterSlide : function(){
37750 this.resizeEl.unclip();
37754 * Force a content refresh from the URL specified in the {@link #setUrl} method.
37755 * Will fail silently if the {@link #setUrl} method has not been called.
37756 * This does not activate the panel, just updates its content.
37758 refresh : function(){
37759 if(this.refreshDelegate){
37760 this.loaded = false;
37761 this.refreshDelegate();
37766 * Destroys this panel
37768 destroy : function(){
37769 this.el.removeAllListeners();
37770 var tempEl = document.createElement("span");
37771 tempEl.appendChild(this.el.dom);
37772 tempEl.innerHTML = "";
37778 * form - if the content panel contains a form - this is a reference to it.
37779 * @type {Roo.form.Form}
37783 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
37784 * This contains a reference to it.
37790 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
37800 * @param {Object} cfg Xtype definition of item to add.
37804 getChildContainer: function () {
37805 return this.getEl();
37810 var ret = new Roo.factory(cfg);
37815 if (cfg.xtype.match(/^Form$/)) {
37818 //if (this.footer) {
37819 // el = this.footer.container.insertSibling(false, 'before');
37821 el = this.el.createChild();
37824 this.form = new Roo.form.Form(cfg);
37827 if ( this.form.allItems.length) {
37828 this.form.render(el.dom);
37832 // should only have one of theses..
37833 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
37834 // views.. should not be just added - used named prop 'view''
37836 cfg.el = this.el.appendChild(document.createElement("div"));
37839 var ret = new Roo.factory(cfg);
37841 ret.render && ret.render(false, ''); // render blank..
37851 * @class Roo.bootstrap.panel.Grid
37852 * @extends Roo.bootstrap.panel.Content
37854 * Create a new GridPanel.
37855 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
37856 * @param {Object} config A the config object
37862 Roo.bootstrap.panel.Grid = function(config)
37866 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
37867 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
37869 config.el = this.wrapper;
37870 //this.el = this.wrapper;
37872 if (config.container) {
37873 // ctor'ed from a Border/panel.grid
37876 this.wrapper.setStyle("overflow", "hidden");
37877 this.wrapper.addClass('roo-grid-container');
37882 if(config.toolbar){
37883 var tool_el = this.wrapper.createChild();
37884 this.toolbar = Roo.factory(config.toolbar);
37886 if (config.toolbar.items) {
37887 ti = config.toolbar.items ;
37888 delete config.toolbar.items ;
37892 this.toolbar.render(tool_el);
37893 for(var i =0;i < ti.length;i++) {
37894 // Roo.log(['add child', items[i]]);
37895 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37897 this.toolbar.items = nitems;
37899 delete config.toolbar;
37902 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
37903 config.grid.scrollBody = true;;
37904 config.grid.monitorWindowResize = false; // turn off autosizing
37905 config.grid.autoHeight = false;
37906 config.grid.autoWidth = false;
37908 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
37910 if (config.background) {
37911 // render grid on panel activation (if panel background)
37912 this.on('activate', function(gp) {
37913 if (!gp.grid.rendered) {
37914 gp.grid.render(this.wrapper);
37915 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37920 this.grid.render(this.wrapper);
37921 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37924 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
37925 // ??? needed ??? config.el = this.wrapper;
37930 // xtype created footer. - not sure if will work as we normally have to render first..
37931 if (this.footer && !this.footer.el && this.footer.xtype) {
37933 var ctr = this.grid.getView().getFooterPanel(true);
37934 this.footer.dataSource = this.grid.dataSource;
37935 this.footer = Roo.factory(this.footer, Roo);
37936 this.footer.render(ctr);
37946 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
37947 getId : function(){
37948 return this.grid.id;
37952 * Returns the grid for this panel
37953 * @return {Roo.bootstrap.Table}
37955 getGrid : function(){
37959 setSize : function(width, height){
37960 if(!this.ignoreResize(width, height)){
37961 var grid = this.grid;
37962 var size = this.adjustForComponents(width, height);
37963 var gridel = grid.getGridEl();
37964 gridel.setSize(size.width, size.height);
37966 var thd = grid.getGridEl().select('thead',true).first();
37967 var tbd = grid.getGridEl().select('tbody', true).first();
37969 tbd.setSize(width, height - thd.getHeight());
37978 beforeSlide : function(){
37979 this.grid.getView().scroller.clip();
37982 afterSlide : function(){
37983 this.grid.getView().scroller.unclip();
37986 destroy : function(){
37987 this.grid.destroy();
37989 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
37994 * @class Roo.bootstrap.panel.Nest
37995 * @extends Roo.bootstrap.panel.Content
37997 * Create a new Panel, that can contain a layout.Border.
38000 * @param {Roo.BorderLayout} layout The layout for this panel
38001 * @param {String/Object} config A string to set only the title or a config object
38003 Roo.bootstrap.panel.Nest = function(config)
38005 // construct with only one argument..
38006 /* FIXME - implement nicer consturctors
38007 if (layout.layout) {
38009 layout = config.layout;
38010 delete config.layout;
38012 if (layout.xtype && !layout.getEl) {
38013 // then layout needs constructing..
38014 layout = Roo.factory(layout, Roo);
38018 config.el = config.layout.getEl();
38020 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
38022 config.layout.monitorWindowResize = false; // turn off autosizing
38023 this.layout = config.layout;
38024 this.layout.getEl().addClass("roo-layout-nested-layout");
38025 this.layout.parent = this;
38032 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
38034 setSize : function(width, height){
38035 if(!this.ignoreResize(width, height)){
38036 var size = this.adjustForComponents(width, height);
38037 var el = this.layout.getEl();
38038 if (size.height < 1) {
38039 el.setWidth(size.width);
38041 el.setSize(size.width, size.height);
38043 var touch = el.dom.offsetWidth;
38044 this.layout.layout();
38045 // ie requires a double layout on the first pass
38046 if(Roo.isIE && !this.initialized){
38047 this.initialized = true;
38048 this.layout.layout();
38053 // activate all subpanels if not currently active..
38055 setActiveState : function(active){
38056 this.active = active;
38057 this.setActiveClass(active);
38060 this.fireEvent("deactivate", this);
38064 this.fireEvent("activate", this);
38065 // not sure if this should happen before or after..
38066 if (!this.layout) {
38067 return; // should not happen..
38070 for (var r in this.layout.regions) {
38071 reg = this.layout.getRegion(r);
38072 if (reg.getActivePanel()) {
38073 //reg.showPanel(reg.getActivePanel()); // force it to activate..
38074 reg.setActivePanel(reg.getActivePanel());
38077 if (!reg.panels.length) {
38080 reg.showPanel(reg.getPanel(0));
38089 * Returns the nested BorderLayout for this panel
38090 * @return {Roo.BorderLayout}
38092 getLayout : function(){
38093 return this.layout;
38097 * Adds a xtype elements to the layout of the nested panel
38101 xtype : 'ContentPanel',
38108 xtype : 'NestedLayoutPanel',
38114 items : [ ... list of content panels or nested layout panels.. ]
38118 * @param {Object} cfg Xtype definition of item to add.
38120 addxtype : function(cfg) {
38121 return this.layout.addxtype(cfg);
38126 * Ext JS Library 1.1.1
38127 * Copyright(c) 2006-2007, Ext JS, LLC.
38129 * Originally Released Under LGPL - original licence link has changed is not relivant.
38132 * <script type="text/javascript">
38135 * @class Roo.TabPanel
38136 * @extends Roo.util.Observable
38137 * A lightweight tab container.
38141 // basic tabs 1, built from existing content
38142 var tabs = new Roo.TabPanel("tabs1");
38143 tabs.addTab("script", "View Script");
38144 tabs.addTab("markup", "View Markup");
38145 tabs.activate("script");
38147 // more advanced tabs, built from javascript
38148 var jtabs = new Roo.TabPanel("jtabs");
38149 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
38151 // set up the UpdateManager
38152 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
38153 var updater = tab2.getUpdateManager();
38154 updater.setDefaultUrl("ajax1.htm");
38155 tab2.on('activate', updater.refresh, updater, true);
38157 // Use setUrl for Ajax loading
38158 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
38159 tab3.setUrl("ajax2.htm", null, true);
38162 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
38165 jtabs.activate("jtabs-1");
38168 * Create a new TabPanel.
38169 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
38170 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
38172 Roo.bootstrap.panel.Tabs = function(config){
38174 * The container element for this TabPanel.
38175 * @type Roo.Element
38177 this.el = Roo.get(config.el);
38180 if(typeof config == "boolean"){
38181 this.tabPosition = config ? "bottom" : "top";
38183 Roo.apply(this, config);
38187 if(this.tabPosition == "bottom"){
38188 // if tabs are at the bottom = create the body first.
38189 this.bodyEl = Roo.get(this.createBody(this.el.dom));
38190 this.el.addClass("roo-tabs-bottom");
38192 // next create the tabs holders
38194 if (this.tabPosition == "west"){
38196 var reg = this.region; // fake it..
38198 if (!reg.mgr.parent) {
38201 reg = reg.mgr.parent.region;
38203 Roo.log("got nest?");
38205 if (reg.mgr.getRegion('west')) {
38206 var ctrdom = reg.mgr.getRegion('west').bodyEl.dom;
38207 this.stripWrap = Roo.get(this.createStrip(ctrdom ), true);
38208 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
38209 this.stripEl.setVisibilityMode(Roo.Element.DISPLAY);
38210 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
38218 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
38219 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
38220 this.stripEl.setVisibilityMode(Roo.Element.DISPLAY);
38221 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
38226 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
38229 // finally - if tabs are at the top, then create the body last..
38230 if(this.tabPosition != "bottom"){
38231 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
38232 * @type Roo.Element
38234 this.bodyEl = Roo.get(this.createBody(this.el.dom));
38235 this.el.addClass("roo-tabs-top");
38239 this.bodyEl.setStyle("position", "relative");
38241 this.active = null;
38242 this.activateDelegate = this.activate.createDelegate(this);
38247 * Fires when the active tab changes
38248 * @param {Roo.TabPanel} this
38249 * @param {Roo.TabPanelItem} activePanel The new active tab
38253 * @event beforetabchange
38254 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
38255 * @param {Roo.TabPanel} this
38256 * @param {Object} e Set cancel to true on this object to cancel the tab change
38257 * @param {Roo.TabPanelItem} tab The tab being changed to
38259 "beforetabchange" : true
38262 Roo.EventManager.onWindowResize(this.onResize, this);
38263 this.cpad = this.el.getPadding("lr");
38264 this.hiddenCount = 0;
38267 // toolbar on the tabbar support...
38268 if (this.toolbar) {
38269 alert("no toolbar support yet");
38270 this.toolbar = false;
38272 var tcfg = this.toolbar;
38273 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
38274 this.toolbar = new Roo.Toolbar(tcfg);
38275 if (Roo.isSafari) {
38276 var tbl = tcfg.container.child('table', true);
38277 tbl.setAttribute('width', '100%');
38285 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
38288 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
38290 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
38292 tabPosition : "top",
38294 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
38296 currentTabWidth : 0,
38298 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
38302 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
38306 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
38308 preferredTabWidth : 175,
38310 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
38312 resizeTabs : false,
38314 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
38316 monitorResize : true,
38318 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
38320 toolbar : false, // set by caller..
38322 region : false, /// set by caller
38324 disableTooltips : true, // not used yet...
38327 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
38328 * @param {String} id The id of the div to use <b>or create</b>
38329 * @param {String} text The text for the tab
38330 * @param {String} content (optional) Content to put in the TabPanelItem body
38331 * @param {Boolean} closable (optional) True to create a close icon on the tab
38332 * @return {Roo.TabPanelItem} The created TabPanelItem
38334 addTab : function(id, text, content, closable, tpl)
38336 var item = new Roo.bootstrap.panel.TabItem({
38340 closable : closable,
38343 this.addTabItem(item);
38345 item.setContent(content);
38351 * Returns the {@link Roo.TabPanelItem} with the specified id/index
38352 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
38353 * @return {Roo.TabPanelItem}
38355 getTab : function(id){
38356 return this.items[id];
38360 * Hides the {@link Roo.TabPanelItem} with the specified id/index
38361 * @param {String/Number} id The id or index of the TabPanelItem to hide.
38363 hideTab : function(id){
38364 var t = this.items[id];
38367 this.hiddenCount++;
38368 this.autoSizeTabs();
38373 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
38374 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
38376 unhideTab : function(id){
38377 var t = this.items[id];
38379 t.setHidden(false);
38380 this.hiddenCount--;
38381 this.autoSizeTabs();
38386 * Adds an existing {@link Roo.TabPanelItem}.
38387 * @param {Roo.TabPanelItem} item The TabPanelItem to add
38389 addTabItem : function(item)
38391 this.items[item.id] = item;
38392 this.items.push(item);
38393 this.autoSizeTabs();
38394 // if(this.resizeTabs){
38395 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
38396 // this.autoSizeTabs();
38398 // item.autoSize();
38403 * Removes a {@link Roo.TabPanelItem}.
38404 * @param {String/Number} id The id or index of the TabPanelItem to remove.
38406 removeTab : function(id){
38407 var items = this.items;
38408 var tab = items[id];
38409 if(!tab) { return; }
38410 var index = items.indexOf(tab);
38411 if(this.active == tab && items.length > 1){
38412 var newTab = this.getNextAvailable(index);
38417 this.stripEl.dom.removeChild(tab.pnode.dom);
38418 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
38419 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
38421 items.splice(index, 1);
38422 delete this.items[tab.id];
38423 tab.fireEvent("close", tab);
38424 tab.purgeListeners();
38425 this.autoSizeTabs();
38428 getNextAvailable : function(start){
38429 var items = this.items;
38431 // look for a next tab that will slide over to
38432 // replace the one being removed
38433 while(index < items.length){
38434 var item = items[++index];
38435 if(item && !item.isHidden()){
38439 // if one isn't found select the previous tab (on the left)
38442 var item = items[--index];
38443 if(item && !item.isHidden()){
38451 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
38452 * @param {String/Number} id The id or index of the TabPanelItem to disable.
38454 disableTab : function(id){
38455 var tab = this.items[id];
38456 if(tab && this.active != tab){
38462 * Enables a {@link Roo.TabPanelItem} that is disabled.
38463 * @param {String/Number} id The id or index of the TabPanelItem to enable.
38465 enableTab : function(id){
38466 var tab = this.items[id];
38471 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
38472 * @param {String/Number} id The id or index of the TabPanelItem to activate.
38473 * @return {Roo.TabPanelItem} The TabPanelItem.
38475 activate : function(id)
38477 //Roo.log('activite:' + id);
38479 var tab = this.items[id];
38483 if(tab == this.active || tab.disabled){
38487 this.fireEvent("beforetabchange", this, e, tab);
38488 if(e.cancel !== true && !tab.disabled){
38490 this.active.hide();
38492 this.active = this.items[id];
38493 this.active.show();
38494 this.fireEvent("tabchange", this, this.active);
38500 * Gets the active {@link Roo.TabPanelItem}.
38501 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
38503 getActiveTab : function(){
38504 return this.active;
38508 * Updates the tab body element to fit the height of the container element
38509 * for overflow scrolling
38510 * @param {Number} targetHeight (optional) Override the starting height from the elements height
38512 syncHeight : function(targetHeight){
38513 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
38514 var bm = this.bodyEl.getMargins();
38515 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
38516 this.bodyEl.setHeight(newHeight);
38520 onResize : function(){
38521 if(this.monitorResize){
38522 this.autoSizeTabs();
38527 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
38529 beginUpdate : function(){
38530 this.updating = true;
38534 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
38536 endUpdate : function(){
38537 this.updating = false;
38538 this.autoSizeTabs();
38542 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
38544 autoSizeTabs : function()
38546 var count = this.items.length;
38547 var vcount = count - this.hiddenCount;
38550 this.stripEl.hide();
38552 this.stripEl.show();
38555 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
38560 var w = Math.max(this.el.getWidth() - this.cpad, 10);
38561 var availWidth = Math.floor(w / vcount);
38562 var b = this.stripBody;
38563 if(b.getWidth() > w){
38564 var tabs = this.items;
38565 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
38566 if(availWidth < this.minTabWidth){
38567 /*if(!this.sleft){ // incomplete scrolling code
38568 this.createScrollButtons();
38571 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
38574 if(this.currentTabWidth < this.preferredTabWidth){
38575 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
38581 * Returns the number of tabs in this TabPanel.
38584 getCount : function(){
38585 return this.items.length;
38589 * Resizes all the tabs to the passed width
38590 * @param {Number} The new width
38592 setTabWidth : function(width){
38593 this.currentTabWidth = width;
38594 for(var i = 0, len = this.items.length; i < len; i++) {
38595 if(!this.items[i].isHidden()) {
38596 this.items[i].setWidth(width);
38602 * Destroys this TabPanel
38603 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
38605 destroy : function(removeEl){
38606 Roo.EventManager.removeResizeListener(this.onResize, this);
38607 for(var i = 0, len = this.items.length; i < len; i++){
38608 this.items[i].purgeListeners();
38610 if(removeEl === true){
38611 this.el.update("");
38616 createStrip : function(container)
38618 var strip = document.createElement("nav");
38619 strip.className = Roo.bootstrap.version == 4 ?
38620 "navbar-light bg-light" :
38621 "navbar navbar-default"; //"x-tabs-wrap";
38622 container.appendChild(strip);
38626 createStripList : function(strip)
38628 // div wrapper for retard IE
38629 // returns the "tr" element.
38630 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
38631 //'<div class="x-tabs-strip-wrap">'+
38632 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
38633 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
38634 return strip.firstChild; //.firstChild.firstChild.firstChild;
38636 createBody : function(container)
38638 var body = document.createElement("div");
38639 Roo.id(body, "tab-body");
38640 //Roo.fly(body).addClass("x-tabs-body");
38641 Roo.fly(body).addClass("tab-content");
38642 container.appendChild(body);
38645 createItemBody :function(bodyEl, id){
38646 var body = Roo.getDom(id);
38648 body = document.createElement("div");
38651 //Roo.fly(body).addClass("x-tabs-item-body");
38652 Roo.fly(body).addClass("tab-pane");
38653 bodyEl.insertBefore(body, bodyEl.firstChild);
38657 createStripElements : function(stripEl, text, closable, tpl)
38659 var td = document.createElement("li"); // was td..
38660 td.className = 'nav-item';
38662 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
38665 stripEl.appendChild(td);
38667 td.className = "x-tabs-closable";
38668 if(!this.closeTpl){
38669 this.closeTpl = new Roo.Template(
38670 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38671 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
38672 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
38675 var el = this.closeTpl.overwrite(td, {"text": text});
38676 var close = el.getElementsByTagName("div")[0];
38677 var inner = el.getElementsByTagName("em")[0];
38678 return {"el": el, "close": close, "inner": inner};
38681 // not sure what this is..
38682 // if(!this.tabTpl){
38683 //this.tabTpl = new Roo.Template(
38684 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38685 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
38687 // this.tabTpl = new Roo.Template(
38688 // '<a href="#">' +
38689 // '<span unselectable="on"' +
38690 // (this.disableTooltips ? '' : ' title="{text}"') +
38691 // ' >{text}</span></a>'
38697 var template = tpl || this.tabTpl || false;
38700 template = new Roo.Template(
38701 Roo.bootstrap.version == 4 ?
38703 '<a class="nav-link" href="#" unselectable="on"' +
38704 (this.disableTooltips ? '' : ' title="{text}"') +
38707 '<a class="nav-link" href="#">' +
38708 '<span unselectable="on"' +
38709 (this.disableTooltips ? '' : ' title="{text}"') +
38710 ' >{text}</span></a>'
38715 switch (typeof(template)) {
38719 template = new Roo.Template(template);
38725 var el = template.overwrite(td, {"text": text});
38727 var inner = el.getElementsByTagName("span")[0];
38729 return {"el": el, "inner": inner};
38737 * @class Roo.TabPanelItem
38738 * @extends Roo.util.Observable
38739 * Represents an individual item (tab plus body) in a TabPanel.
38740 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
38741 * @param {String} id The id of this TabPanelItem
38742 * @param {String} text The text for the tab of this TabPanelItem
38743 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
38745 Roo.bootstrap.panel.TabItem = function(config){
38747 * The {@link Roo.TabPanel} this TabPanelItem belongs to
38748 * @type Roo.TabPanel
38750 this.tabPanel = config.panel;
38752 * The id for this TabPanelItem
38755 this.id = config.id;
38757 this.disabled = false;
38759 this.text = config.text;
38761 this.loaded = false;
38762 this.closable = config.closable;
38765 * The body element for this TabPanelItem.
38766 * @type Roo.Element
38768 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
38769 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
38770 this.bodyEl.setStyle("display", "block");
38771 this.bodyEl.setStyle("zoom", "1");
38772 //this.hideAction();
38774 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
38776 this.el = Roo.get(els.el);
38777 this.inner = Roo.get(els.inner, true);
38778 this.textEl = Roo.bootstrap.version == 4 ?
38779 this.el : Roo.get(this.el.dom.firstChild, true);
38781 this.pnode = this.linode = Roo.get(els.el.parentNode, true);
38782 this.status_node = Roo.bootstrap.version == 4 ? this.el : this.linode;
38785 // this.el.on("mousedown", this.onTabMouseDown, this);
38786 this.el.on("click", this.onTabClick, this);
38788 if(config.closable){
38789 var c = Roo.get(els.close, true);
38790 c.dom.title = this.closeText;
38791 c.addClassOnOver("close-over");
38792 c.on("click", this.closeClick, this);
38798 * Fires when this tab becomes the active tab.
38799 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38800 * @param {Roo.TabPanelItem} this
38804 * @event beforeclose
38805 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
38806 * @param {Roo.TabPanelItem} this
38807 * @param {Object} e Set cancel to true on this object to cancel the close.
38809 "beforeclose": true,
38812 * Fires when this tab is closed.
38813 * @param {Roo.TabPanelItem} this
38817 * @event deactivate
38818 * Fires when this tab is no longer the active tab.
38819 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38820 * @param {Roo.TabPanelItem} this
38822 "deactivate" : true
38824 this.hidden = false;
38826 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
38829 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
38831 purgeListeners : function(){
38832 Roo.util.Observable.prototype.purgeListeners.call(this);
38833 this.el.removeAllListeners();
38836 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
38839 this.status_node.addClass("active");
38842 this.tabPanel.stripWrap.repaint();
38844 this.fireEvent("activate", this.tabPanel, this);
38848 * Returns true if this tab is the active tab.
38849 * @return {Boolean}
38851 isActive : function(){
38852 return this.tabPanel.getActiveTab() == this;
38856 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
38859 this.status_node.removeClass("active");
38861 this.fireEvent("deactivate", this.tabPanel, this);
38864 hideAction : function(){
38865 this.bodyEl.hide();
38866 this.bodyEl.setStyle("position", "absolute");
38867 this.bodyEl.setLeft("-20000px");
38868 this.bodyEl.setTop("-20000px");
38871 showAction : function(){
38872 this.bodyEl.setStyle("position", "relative");
38873 this.bodyEl.setTop("");
38874 this.bodyEl.setLeft("");
38875 this.bodyEl.show();
38879 * Set the tooltip for the tab.
38880 * @param {String} tooltip The tab's tooltip
38882 setTooltip : function(text){
38883 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
38884 this.textEl.dom.qtip = text;
38885 this.textEl.dom.removeAttribute('title');
38887 this.textEl.dom.title = text;
38891 onTabClick : function(e){
38892 e.preventDefault();
38893 this.tabPanel.activate(this.id);
38896 onTabMouseDown : function(e){
38897 e.preventDefault();
38898 this.tabPanel.activate(this.id);
38901 getWidth : function(){
38902 return this.inner.getWidth();
38905 setWidth : function(width){
38906 var iwidth = width - this.linode.getPadding("lr");
38907 this.inner.setWidth(iwidth);
38908 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
38909 this.linode.setWidth(width);
38913 * Show or hide the tab
38914 * @param {Boolean} hidden True to hide or false to show.
38916 setHidden : function(hidden){
38917 this.hidden = hidden;
38918 this.linode.setStyle("display", hidden ? "none" : "");
38922 * Returns true if this tab is "hidden"
38923 * @return {Boolean}
38925 isHidden : function(){
38926 return this.hidden;
38930 * Returns the text for this tab
38933 getText : function(){
38937 autoSize : function(){
38938 //this.el.beginMeasure();
38939 this.textEl.setWidth(1);
38941 * #2804 [new] Tabs in Roojs
38942 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
38944 //this.setWidth(this.textEl.dom.scrollWidth+this.linode.getPadding("lr")+this.inner.getPadding("lr") + 2);
38945 //this.el.endMeasure();
38949 * Sets the text for the tab (Note: this also sets the tooltip text)
38950 * @param {String} text The tab's text and tooltip
38952 setText : function(text){
38954 this.textEl.update(text);
38955 this.setTooltip(text);
38956 //if(!this.tabPanel.resizeTabs){
38957 // this.autoSize();
38961 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
38963 activate : function(){
38964 this.tabPanel.activate(this.id);
38968 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
38970 disable : function(){
38971 if(this.tabPanel.active != this){
38972 this.disabled = true;
38973 this.status_node.addClass("disabled");
38978 * Enables this TabPanelItem if it was previously disabled.
38980 enable : function(){
38981 this.disabled = false;
38982 this.status_node.removeClass("disabled");
38986 * Sets the content for this TabPanelItem.
38987 * @param {String} content The content
38988 * @param {Boolean} loadScripts true to look for and load scripts
38990 setContent : function(content, loadScripts){
38991 this.bodyEl.update(content, loadScripts);
38995 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
38996 * @return {Roo.UpdateManager} The UpdateManager
38998 getUpdateManager : function(){
38999 return this.bodyEl.getUpdateManager();
39003 * Set a URL to be used to load the content for this TabPanelItem.
39004 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
39005 * @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)
39006 * @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)
39007 * @return {Roo.UpdateManager} The UpdateManager
39009 setUrl : function(url, params, loadOnce){
39010 if(this.refreshDelegate){
39011 this.un('activate', this.refreshDelegate);
39013 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
39014 this.on("activate", this.refreshDelegate);
39015 return this.bodyEl.getUpdateManager();
39019 _handleRefresh : function(url, params, loadOnce){
39020 if(!loadOnce || !this.loaded){
39021 var updater = this.bodyEl.getUpdateManager();
39022 updater.update(url, params, this._setLoaded.createDelegate(this));
39027 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
39028 * Will fail silently if the setUrl method has not been called.
39029 * This does not activate the panel, just updates its content.
39031 refresh : function(){
39032 if(this.refreshDelegate){
39033 this.loaded = false;
39034 this.refreshDelegate();
39039 _setLoaded : function(){
39040 this.loaded = true;
39044 closeClick : function(e){
39047 this.fireEvent("beforeclose", this, o);
39048 if(o.cancel !== true){
39049 this.tabPanel.removeTab(this.id);
39053 * The text displayed in the tooltip for the close icon.
39056 closeText : "Close this tab"
39059 * This script refer to:
39060 * Title: International Telephone Input
39061 * Author: Jack O'Connor
39062 * Code version: v12.1.12
39063 * Availability: https://github.com/jackocnr/intl-tel-input.git
39066 Roo.bootstrap.PhoneInputData = function() {
39069 "Afghanistan (افغانستان)",
39074 "Albania (Shqipëri)",
39079 "Algeria (الجزائر)",
39104 "Antigua and Barbuda",
39114 "Armenia (Հայաստան)",
39130 "Austria (Österreich)",
39135 "Azerbaijan (Azərbaycan)",
39145 "Bahrain (البحرين)",
39150 "Bangladesh (বাংলাদেশ)",
39160 "Belarus (Беларусь)",
39165 "Belgium (België)",
39195 "Bosnia and Herzegovina (Босна и Херцеговина)",
39210 "British Indian Ocean Territory",
39215 "British Virgin Islands",
39225 "Bulgaria (България)",
39235 "Burundi (Uburundi)",
39240 "Cambodia (កម្ពុជា)",
39245 "Cameroon (Cameroun)",
39254 ["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"]
39257 "Cape Verde (Kabu Verdi)",
39262 "Caribbean Netherlands",
39273 "Central African Republic (République centrafricaine)",
39293 "Christmas Island",
39299 "Cocos (Keeling) Islands",
39310 "Comoros (جزر القمر)",
39315 "Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)",
39320 "Congo (Republic) (Congo-Brazzaville)",
39340 "Croatia (Hrvatska)",
39361 "Czech Republic (Česká republika)",
39366 "Denmark (Danmark)",
39381 "Dominican Republic (República Dominicana)",
39385 ["809", "829", "849"]
39403 "Equatorial Guinea (Guinea Ecuatorial)",
39423 "Falkland Islands (Islas Malvinas)",
39428 "Faroe Islands (Føroyar)",
39449 "French Guiana (Guyane française)",
39454 "French Polynesia (Polynésie française)",
39469 "Georgia (საქართველო)",
39474 "Germany (Deutschland)",
39494 "Greenland (Kalaallit Nunaat)",
39531 "Guinea-Bissau (Guiné Bissau)",
39556 "Hungary (Magyarország)",
39561 "Iceland (Ísland)",
39581 "Iraq (العراق)",
39597 "Israel (ישראל)",
39624 "Jordan (الأردن)",
39629 "Kazakhstan (Казахстан)",
39650 "Kuwait (الكويت)",
39655 "Kyrgyzstan (Кыргызстан)",
39665 "Latvia (Latvija)",
39670 "Lebanon (لبنان)",
39685 "Libya (ليبيا)",
39695 "Lithuania (Lietuva)",
39710 "Macedonia (FYROM) (Македонија)",
39715 "Madagascar (Madagasikara)",
39745 "Marshall Islands",
39755 "Mauritania (موريتانيا)",
39760 "Mauritius (Moris)",
39781 "Moldova (Republica Moldova)",
39791 "Mongolia (Монгол)",
39796 "Montenegro (Crna Gora)",
39806 "Morocco (المغرب)",
39812 "Mozambique (Moçambique)",
39817 "Myanmar (Burma) (မြန်မာ)",
39822 "Namibia (Namibië)",
39837 "Netherlands (Nederland)",
39842 "New Caledonia (Nouvelle-Calédonie)",
39877 "North Korea (조선 민주주의 인민 공화국)",
39882 "Northern Mariana Islands",
39898 "Pakistan (پاکستان)",
39908 "Palestine (فلسطين)",
39918 "Papua New Guinea",
39960 "Réunion (La Réunion)",
39966 "Romania (România)",
39982 "Saint Barthélemy",
39993 "Saint Kitts and Nevis",
40003 "Saint Martin (Saint-Martin (partie française))",
40009 "Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)",
40014 "Saint Vincent and the Grenadines",
40029 "São Tomé and Príncipe (São Tomé e Príncipe)",
40034 "Saudi Arabia (المملكة العربية السعودية)",
40039 "Senegal (Sénégal)",
40069 "Slovakia (Slovensko)",
40074 "Slovenia (Slovenija)",
40084 "Somalia (Soomaaliya)",
40094 "South Korea (대한민국)",
40099 "South Sudan (جنوب السودان)",
40109 "Sri Lanka (ශ්රී ලංකාව)",
40114 "Sudan (السودان)",
40124 "Svalbard and Jan Mayen",
40135 "Sweden (Sverige)",
40140 "Switzerland (Schweiz)",
40145 "Syria (سوريا)",
40190 "Trinidad and Tobago",
40195 "Tunisia (تونس)",
40200 "Turkey (Türkiye)",
40210 "Turks and Caicos Islands",
40220 "U.S. Virgin Islands",
40230 "Ukraine (Україна)",
40235 "United Arab Emirates (الإمارات العربية المتحدة)",
40257 "Uzbekistan (Oʻzbekiston)",
40267 "Vatican City (Città del Vaticano)",
40278 "Vietnam (Việt Nam)",
40283 "Wallis and Futuna (Wallis-et-Futuna)",
40288 "Western Sahara (الصحراء الغربية)",
40294 "Yemen (اليمن)",
40318 * This script refer to:
40319 * Title: International Telephone Input
40320 * Author: Jack O'Connor
40321 * Code version: v12.1.12
40322 * Availability: https://github.com/jackocnr/intl-tel-input.git
40326 * @class Roo.bootstrap.PhoneInput
40327 * @extends Roo.bootstrap.TriggerField
40328 * An input with International dial-code selection
40330 * @cfg {String} defaultDialCode default '+852'
40331 * @cfg {Array} preferedCountries default []
40334 * Create a new PhoneInput.
40335 * @param {Object} config Configuration options
40338 Roo.bootstrap.PhoneInput = function(config) {
40339 Roo.bootstrap.PhoneInput.superclass.constructor.call(this, config);
40342 Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
40344 listWidth: undefined,
40346 selectedClass: 'active',
40348 invalidClass : "has-warning",
40350 validClass: 'has-success',
40352 allowed: '0123456789',
40357 * @cfg {String} defaultDialCode The default dial code when initializing the input
40359 defaultDialCode: '+852',
40362 * @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
40364 preferedCountries: false,
40366 getAutoCreate : function()
40368 var data = Roo.bootstrap.PhoneInputData();
40369 var align = this.labelAlign || this.parentLabelAlign();
40372 this.allCountries = [];
40373 this.dialCodeMapping = [];
40375 for (var i = 0; i < data.length; i++) {
40377 this.allCountries[i] = {
40381 priority: c[3] || 0,
40382 areaCodes: c[4] || null
40384 this.dialCodeMapping[c[2]] = {
40387 priority: c[3] || 0,
40388 areaCodes: c[4] || null
40400 // type: 'number', -- do not use number - we get the flaky up/down arrows.
40401 maxlength: this.max_length,
40402 cls : 'form-control tel-input',
40403 autocomplete: 'new-password'
40406 var hiddenInput = {
40409 cls: 'hidden-tel-input'
40413 hiddenInput.name = this.name;
40416 if (this.disabled) {
40417 input.disabled = true;
40420 var flag_container = {
40437 cls: this.hasFeedback ? 'has-feedback' : '',
40443 cls: 'dial-code-holder',
40450 cls: 'roo-select2-container input-group',
40457 if (this.fieldLabel.length) {
40460 tooltip: 'This field is required'
40466 cls: 'control-label',
40472 html: this.fieldLabel
40475 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40481 if(this.indicatorpos == 'right') {
40482 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40489 if(align == 'left') {
40497 if(this.labelWidth > 12){
40498 label.style = "width: " + this.labelWidth + 'px';
40500 if(this.labelWidth < 13 && this.labelmd == 0){
40501 this.labelmd = this.labelWidth;
40503 if(this.labellg > 0){
40504 label.cls += ' col-lg-' + this.labellg;
40505 input.cls += ' col-lg-' + (12 - this.labellg);
40507 if(this.labelmd > 0){
40508 label.cls += ' col-md-' + this.labelmd;
40509 container.cls += ' col-md-' + (12 - this.labelmd);
40511 if(this.labelsm > 0){
40512 label.cls += ' col-sm-' + this.labelsm;
40513 container.cls += ' col-sm-' + (12 - this.labelsm);
40515 if(this.labelxs > 0){
40516 label.cls += ' col-xs-' + this.labelxs;
40517 container.cls += ' col-xs-' + (12 - this.labelxs);
40527 var settings = this;
40529 ['xs','sm','md','lg'].map(function(size){
40530 if (settings[size]) {
40531 cfg.cls += ' col-' + size + '-' + settings[size];
40535 this.store = new Roo.data.Store({
40536 proxy : new Roo.data.MemoryProxy({}),
40537 reader : new Roo.data.JsonReader({
40548 'name' : 'dialCode',
40552 'name' : 'priority',
40556 'name' : 'areaCodes',
40563 if(!this.preferedCountries) {
40564 this.preferedCountries = [
40571 var p = this.preferedCountries.reverse();
40574 for (var i = 0; i < p.length; i++) {
40575 for (var j = 0; j < this.allCountries.length; j++) {
40576 if(this.allCountries[j].iso2 == p[i]) {
40577 var t = this.allCountries[j];
40578 this.allCountries.splice(j,1);
40579 this.allCountries.unshift(t);
40585 this.store.proxy.data = {
40587 data: this.allCountries
40593 initEvents : function()
40596 Roo.bootstrap.PhoneInput.superclass.initEvents.call(this);
40598 this.indicator = this.indicatorEl();
40599 this.flag = this.flagEl();
40600 this.dialCodeHolder = this.dialCodeHolderEl();
40602 this.trigger = this.el.select('div.flag-box',true).first();
40603 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
40608 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40609 _this.list.setWidth(lw);
40612 this.list.on('mouseover', this.onViewOver, this);
40613 this.list.on('mousemove', this.onViewMove, this);
40614 this.inputEl().on("keyup", this.onKeyUp, this);
40615 this.inputEl().on("keypress", this.onKeyPress, this);
40617 this.tpl = '<li><a href="#"><div class="flag {iso2}"></div>{name} <span class="dial-code">+{dialCode}</span></a></li>';
40619 this.view = new Roo.View(this.list, this.tpl, {
40620 singleSelect:true, store: this.store, selectedClass: this.selectedClass
40623 this.view.on('click', this.onViewClick, this);
40624 this.setValue(this.defaultDialCode);
40627 onTriggerClick : function(e)
40629 Roo.log('trigger click');
40634 if(this.isExpanded()){
40636 this.hasFocus = false;
40638 this.store.load({});
40639 this.hasFocus = true;
40644 isExpanded : function()
40646 return this.list.isVisible();
40649 collapse : function()
40651 if(!this.isExpanded()){
40655 Roo.get(document).un('mousedown', this.collapseIf, this);
40656 Roo.get(document).un('mousewheel', this.collapseIf, this);
40657 this.fireEvent('collapse', this);
40661 expand : function()
40665 if(this.isExpanded() || !this.hasFocus){
40669 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
40670 this.list.setWidth(lw);
40673 this.restrictHeight();
40675 Roo.get(document).on('mousedown', this.collapseIf, this);
40676 Roo.get(document).on('mousewheel', this.collapseIf, this);
40678 this.fireEvent('expand', this);
40681 restrictHeight : function()
40683 this.list.alignTo(this.inputEl(), this.listAlign);
40684 this.list.alignTo(this.inputEl(), this.listAlign);
40687 onViewOver : function(e, t)
40689 if(this.inKeyMode){
40692 var item = this.view.findItemFromChild(t);
40695 var index = this.view.indexOf(item);
40696 this.select(index, false);
40701 onViewClick : function(view, doFocus, el, e)
40703 var index = this.view.getSelectedIndexes()[0];
40705 var r = this.store.getAt(index);
40708 this.onSelect(r, index);
40710 if(doFocus !== false && !this.blockFocus){
40711 this.inputEl().focus();
40715 onViewMove : function(e, t)
40717 this.inKeyMode = false;
40720 select : function(index, scrollIntoView)
40722 this.selectedIndex = index;
40723 this.view.select(index);
40724 if(scrollIntoView !== false){
40725 var el = this.view.getNode(index);
40727 this.list.scrollChildIntoView(el, false);
40732 createList : function()
40734 this.list = Roo.get(document.body).createChild({
40736 cls: 'typeahead typeahead-long dropdown-menu tel-list',
40737 style: 'display:none'
40740 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
40743 collapseIf : function(e)
40745 var in_combo = e.within(this.el);
40746 var in_list = e.within(this.list);
40747 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
40749 if (in_combo || in_list || is_list) {
40755 onSelect : function(record, index)
40757 if(this.fireEvent('beforeselect', this, record, index) !== false){
40759 this.setFlagClass(record.data.iso2);
40760 this.setDialCode(record.data.dialCode);
40761 this.hasFocus = false;
40763 this.fireEvent('select', this, record, index);
40767 flagEl : function()
40769 var flag = this.el.select('div.flag',true).first();
40776 dialCodeHolderEl : function()
40778 var d = this.el.select('input.dial-code-holder',true).first();
40785 setDialCode : function(v)
40787 this.dialCodeHolder.dom.value = '+'+v;
40790 setFlagClass : function(n)
40792 this.flag.dom.className = 'flag '+n;
40795 getValue : function()
40797 var v = this.inputEl().getValue();
40798 if(this.dialCodeHolder) {
40799 v = this.dialCodeHolder.dom.value+this.inputEl().getValue();
40804 setValue : function(v)
40806 var d = this.getDialCode(v);
40808 //invalid dial code
40809 if(v.length == 0 || !d || d.length == 0) {
40811 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
40812 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
40818 this.setFlagClass(this.dialCodeMapping[d].iso2);
40819 this.setDialCode(d);
40820 this.inputEl().dom.value = v.replace('+'+d,'');
40821 this.hiddenEl().dom.value = this.getValue();
40826 getDialCode : function(v)
40830 if (v.length == 0) {
40831 return this.dialCodeHolder.dom.value;
40835 if (v.charAt(0) != "+") {
40838 var numericChars = "";
40839 for (var i = 1; i < v.length; i++) {
40840 var c = v.charAt(i);
40843 if (this.dialCodeMapping[numericChars]) {
40844 dialCode = v.substr(1, i);
40846 if (numericChars.length == 4) {
40856 this.setValue(this.defaultDialCode);
40860 hiddenEl : function()
40862 return this.el.select('input.hidden-tel-input',true).first();
40865 // after setting val
40866 onKeyUp : function(e){
40867 this.setValue(this.getValue());
40870 onKeyPress : function(e){
40871 if(this.allowed.indexOf(String.fromCharCode(e.getCharCode())) === -1){
40878 * @class Roo.bootstrap.MoneyField
40879 * @extends Roo.bootstrap.ComboBox
40880 * Bootstrap MoneyField class
40883 * Create a new MoneyField.
40884 * @param {Object} config Configuration options
40887 Roo.bootstrap.MoneyField = function(config) {
40889 Roo.bootstrap.MoneyField.superclass.constructor.call(this, config);
40893 Roo.extend(Roo.bootstrap.MoneyField, Roo.bootstrap.ComboBox, {
40896 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
40898 allowDecimals : true,
40900 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
40902 decimalSeparator : ".",
40904 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
40906 decimalPrecision : 0,
40908 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
40910 allowNegative : true,
40912 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
40916 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
40918 minValue : Number.NEGATIVE_INFINITY,
40920 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
40922 maxValue : Number.MAX_VALUE,
40924 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
40926 minText : "The minimum value for this field is {0}",
40928 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
40930 maxText : "The maximum value for this field is {0}",
40932 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
40933 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
40935 nanText : "{0} is not a valid number",
40937 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
40941 * @cfg {String} defaults currency of the MoneyField
40942 * value should be in lkey
40944 defaultCurrency : false,
40946 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
40948 thousandsDelimiter : false,
40950 * @cfg {Number} max_length Maximum input field length allowed (defaults to Number.MAX_VALUE)
40961 getAutoCreate : function()
40963 var align = this.labelAlign || this.parentLabelAlign();
40975 cls : 'form-control roo-money-amount-input',
40976 autocomplete: 'new-password'
40979 var hiddenInput = {
40983 cls: 'hidden-number-input'
40986 if(this.max_length) {
40987 input.maxlength = this.max_length;
40991 hiddenInput.name = this.name;
40994 if (this.disabled) {
40995 input.disabled = true;
40998 var clg = 12 - this.inputlg;
40999 var cmd = 12 - this.inputmd;
41000 var csm = 12 - this.inputsm;
41001 var cxs = 12 - this.inputxs;
41005 cls : 'row roo-money-field',
41009 cls : 'roo-money-currency column col-lg-' + clg + ' col-md-' + cmd + ' col-sm-' + csm + ' col-xs-' + cxs,
41013 cls: 'roo-select2-container input-group',
41017 cls : 'form-control roo-money-currency-input',
41018 autocomplete: 'new-password',
41020 name : this.currencyName
41024 cls : 'input-group-addon',
41038 cls : 'roo-money-amount column col-lg-' + this.inputlg + ' col-md-' + this.inputmd + ' col-sm-' + this.inputsm + ' col-xs-' + this.inputxs,
41042 cls: this.hasFeedback ? 'has-feedback' : '',
41053 if (this.fieldLabel.length) {
41056 tooltip: 'This field is required'
41062 cls: 'control-label',
41068 html: this.fieldLabel
41071 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
41077 if(this.indicatorpos == 'right') {
41078 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
41085 if(align == 'left') {
41093 if(this.labelWidth > 12){
41094 label.style = "width: " + this.labelWidth + 'px';
41096 if(this.labelWidth < 13 && this.labelmd == 0){
41097 this.labelmd = this.labelWidth;
41099 if(this.labellg > 0){
41100 label.cls += ' col-lg-' + this.labellg;
41101 input.cls += ' col-lg-' + (12 - this.labellg);
41103 if(this.labelmd > 0){
41104 label.cls += ' col-md-' + this.labelmd;
41105 container.cls += ' col-md-' + (12 - this.labelmd);
41107 if(this.labelsm > 0){
41108 label.cls += ' col-sm-' + this.labelsm;
41109 container.cls += ' col-sm-' + (12 - this.labelsm);
41111 if(this.labelxs > 0){
41112 label.cls += ' col-xs-' + this.labelxs;
41113 container.cls += ' col-xs-' + (12 - this.labelxs);
41124 var settings = this;
41126 ['xs','sm','md','lg'].map(function(size){
41127 if (settings[size]) {
41128 cfg.cls += ' col-' + size + '-' + settings[size];
41135 initEvents : function()
41137 this.indicator = this.indicatorEl();
41139 this.initCurrencyEvent();
41141 this.initNumberEvent();
41144 initCurrencyEvent : function()
41147 throw "can not find store for combo";
41150 this.store = Roo.factory(this.store, Roo.data);
41151 this.store.parent = this;
41155 this.triggerEl = this.el.select('.input-group-addon', true).first();
41157 this.triggerEl.on("click", this.onTriggerClick, this, { preventDefault : true });
41162 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
41163 _this.list.setWidth(lw);
41166 this.list.on('mouseover', this.onViewOver, this);
41167 this.list.on('mousemove', this.onViewMove, this);
41168 this.list.on('scroll', this.onViewScroll, this);
41171 this.tpl = '<li><a href="#">{' + this.currencyField + '}</a></li>';
41174 this.view = new Roo.View(this.list, this.tpl, {
41175 singleSelect:true, store: this.store, selectedClass: this.selectedClass
41178 this.view.on('click', this.onViewClick, this);
41180 this.store.on('beforeload', this.onBeforeLoad, this);
41181 this.store.on('load', this.onLoad, this);
41182 this.store.on('loadexception', this.onLoadException, this);
41184 this.keyNav = new Roo.KeyNav(this.currencyEl(), {
41185 "up" : function(e){
41186 this.inKeyMode = true;
41190 "down" : function(e){
41191 if(!this.isExpanded()){
41192 this.onTriggerClick();
41194 this.inKeyMode = true;
41199 "enter" : function(e){
41202 if(this.fireEvent("specialkey", this, e)){
41203 this.onViewClick(false);
41209 "esc" : function(e){
41213 "tab" : function(e){
41216 if(this.fireEvent("specialkey", this, e)){
41217 this.onViewClick(false);
41225 doRelay : function(foo, bar, hname){
41226 if(hname == 'down' || this.scope.isExpanded()){
41227 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
41235 this.currencyEl().on("click", this.onTriggerClick, this, { preventDefault : true });
41239 initNumberEvent : function(e)
41241 this.inputEl().on("keydown" , this.fireKey, this);
41242 this.inputEl().on("focus", this.onFocus, this);
41243 this.inputEl().on("blur", this.onBlur, this);
41245 this.inputEl().relayEvent('keyup', this);
41247 if(this.indicator){
41248 this.indicator.addClass('invisible');
41251 this.originalValue = this.getValue();
41253 if(this.validationEvent == 'keyup'){
41254 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
41255 this.inputEl().on('keyup', this.filterValidation, this);
41257 else if(this.validationEvent !== false){
41258 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
41261 if(this.selectOnFocus){
41262 this.on("focus", this.preFocus, this);
41265 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
41266 this.inputEl().on("keypress", this.filterKeys, this);
41268 this.inputEl().relayEvent('keypress', this);
41271 var allowed = "0123456789";
41273 if(this.allowDecimals){
41274 allowed += this.decimalSeparator;
41277 if(this.allowNegative){
41281 if(this.thousandsDelimiter) {
41285 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
41287 var keyPress = function(e){
41289 var k = e.getKey();
41291 var c = e.getCharCode();
41294 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
41295 allowed.indexOf(String.fromCharCode(c)) === -1
41301 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
41305 if(allowed.indexOf(String.fromCharCode(c)) === -1){
41310 this.inputEl().on("keypress", keyPress, this);
41314 onTriggerClick : function(e)
41321 this.loadNext = false;
41323 if(this.isExpanded()){
41328 this.hasFocus = true;
41330 if(this.triggerAction == 'all') {
41331 this.doQuery(this.allQuery, true);
41335 this.doQuery(this.getRawValue());
41338 getCurrency : function()
41340 var v = this.currencyEl().getValue();
41345 restrictHeight : function()
41347 this.list.alignTo(this.currencyEl(), this.listAlign);
41348 this.list.alignTo(this.currencyEl(), this.listAlign);
41351 onViewClick : function(view, doFocus, el, e)
41353 var index = this.view.getSelectedIndexes()[0];
41355 var r = this.store.getAt(index);
41358 this.onSelect(r, index);
41362 onSelect : function(record, index){
41364 if(this.fireEvent('beforeselect', this, record, index) !== false){
41366 this.setFromCurrencyData(index > -1 ? record.data : false);
41370 this.fireEvent('select', this, record, index);
41374 setFromCurrencyData : function(o)
41378 this.lastCurrency = o;
41380 if (this.currencyField) {
41381 currency = !o || typeof(o[this.currencyField]) == 'undefined' ? '' : o[this.currencyField];
41383 Roo.log('no currencyField value set for '+ (this.name ? this.name : this.id));
41386 this.lastSelectionText = currency;
41388 //setting default currency
41389 if(o[this.currencyField] * 1 == 0 && this.defaultCurrency) {
41390 this.setCurrency(this.defaultCurrency);
41394 this.setCurrency(currency);
41397 setFromData : function(o)
41401 c[this.currencyField] = !o || typeof(o[this.currencyName]) == 'undefined' ? '' : o[this.currencyName];
41403 this.setFromCurrencyData(c);
41408 value = !o || typeof(o[this.name]) == 'undefined' ? '' : o[this.name];
41410 Roo.log('no value set for '+ (this.name ? this.name : this.id));
41413 this.setValue(value);
41417 setCurrency : function(v)
41419 this.currencyValue = v;
41422 this.currencyEl().dom.value = (v === null || v === undefined ? '' : v);
41427 setValue : function(v)
41429 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
41435 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
41437 this.inputEl().dom.value = (v == '') ? '' :
41438 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
41440 if(!this.allowZero && v === '0') {
41441 this.hiddenEl().dom.value = '';
41442 this.inputEl().dom.value = '';
41449 getRawValue : function()
41451 var v = this.inputEl().getValue();
41456 getValue : function()
41458 return this.fixPrecision(this.parseValue(this.getRawValue()));
41461 parseValue : function(value)
41463 if(this.thousandsDelimiter) {
41465 r = new RegExp(",", "g");
41466 value = value.replace(r, "");
41469 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
41470 return isNaN(value) ? '' : value;
41474 fixPrecision : function(value)
41476 if(this.thousandsDelimiter) {
41478 r = new RegExp(",", "g");
41479 value = value.replace(r, "");
41482 var nan = isNaN(value);
41484 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
41485 return nan ? '' : value;
41487 return parseFloat(value).toFixed(this.decimalPrecision);
41490 decimalPrecisionFcn : function(v)
41492 return Math.floor(v);
41495 validateValue : function(value)
41497 if(!Roo.bootstrap.MoneyField.superclass.validateValue.call(this, value)){
41501 var num = this.parseValue(value);
41504 this.markInvalid(String.format(this.nanText, value));
41508 if(num < this.minValue){
41509 this.markInvalid(String.format(this.minText, this.minValue));
41513 if(num > this.maxValue){
41514 this.markInvalid(String.format(this.maxText, this.maxValue));
41521 validate : function()
41523 if(this.disabled || this.allowBlank){
41528 var currency = this.getCurrency();
41530 if(this.validateValue(this.getRawValue()) && currency.length){
41535 this.markInvalid();
41539 getName: function()
41544 beforeBlur : function()
41550 var v = this.parseValue(this.getRawValue());
41557 onBlur : function()
41561 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
41562 //this.el.removeClass(this.focusClass);
41565 this.hasFocus = false;
41567 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
41571 var v = this.getValue();
41573 if(String(v) !== String(this.startValue)){
41574 this.fireEvent('change', this, v, this.startValue);
41577 this.fireEvent("blur", this);
41580 inputEl : function()
41582 return this.el.select('.roo-money-amount-input', true).first();
41585 currencyEl : function()
41587 return this.el.select('.roo-money-currency-input', true).first();
41590 hiddenEl : function()
41592 return this.el.select('input.hidden-number-input',true).first();
41596 * @class Roo.bootstrap.BezierSignature
41597 * @extends Roo.bootstrap.Component
41598 * Bootstrap BezierSignature class
41599 * This script refer to:
41600 * Title: Signature Pad
41602 * Availability: https://github.com/szimek/signature_pad
41605 * Create a new BezierSignature
41606 * @param {Object} config The config object
41609 Roo.bootstrap.BezierSignature = function(config){
41610 Roo.bootstrap.BezierSignature.superclass.constructor.call(this, config);
41616 Roo.extend(Roo.bootstrap.BezierSignature, Roo.bootstrap.Component,
41623 mouse_btn_down: true,
41626 * @cfg {int} canvas height
41628 canvas_height: '200px',
41631 * @cfg {float|function} Radius of a single dot.
41636 * @cfg {float} Minimum width of a line. Defaults to 0.5.
41641 * @cfg {float} Maximum width of a line. Defaults to 2.5.
41646 * @cfg {integer} Draw the next point at most once per every x milliseconds. Set it to 0 to turn off throttling. Defaults to 16.
41651 * @cfg {integer} Add the next point only if the previous one is farther than x pixels. Defaults to 5.
41656 * @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.
41658 bg_color: 'rgba(0, 0, 0, 0)',
41661 * @cfg {string} Color used to draw the lines. Can be any color format accepted by context.fillStyle. Defaults to "black".
41663 dot_color: 'black',
41666 * @cfg {float} Weight used to modify new velocity based on the previous velocity. Defaults to 0.7.
41668 velocity_filter_weight: 0.7,
41671 * @cfg {function} Callback when stroke begin.
41676 * @cfg {function} Callback when stroke end.
41680 getAutoCreate : function()
41682 var cls = 'roo-signature column';
41685 cls += ' ' + this.cls;
41695 for(var i = 0; i < col_sizes.length; i++) {
41696 if(this[col_sizes[i]]) {
41697 cls += " col-"+col_sizes[i]+"-"+this[col_sizes[i]];
41707 cls: 'roo-signature-body',
41711 cls: 'roo-signature-body-canvas',
41712 height: this.canvas_height,
41713 width: this.canvas_width
41720 style: 'display: none'
41728 initEvents: function()
41730 Roo.bootstrap.BezierSignature.superclass.initEvents.call(this);
41732 var canvas = this.canvasEl();
41734 // mouse && touch event swapping...
41735 canvas.dom.style.touchAction = 'none';
41736 canvas.dom.style.msTouchAction = 'none';
41738 this.mouse_btn_down = false;
41739 canvas.on('mousedown', this._handleMouseDown, this);
41740 canvas.on('mousemove', this._handleMouseMove, this);
41741 Roo.select('html').first().on('mouseup', this._handleMouseUp, this);
41743 if (window.PointerEvent) {
41744 canvas.on('pointerdown', this._handleMouseDown, this);
41745 canvas.on('pointermove', this._handleMouseMove, this);
41746 Roo.select('html').first().on('pointerup', this._handleMouseUp, this);
41749 if ('ontouchstart' in window) {
41750 canvas.on('touchstart', this._handleTouchStart, this);
41751 canvas.on('touchmove', this._handleTouchMove, this);
41752 canvas.on('touchend', this._handleTouchEnd, this);
41755 Roo.EventManager.onWindowResize(this.resize, this, true);
41757 // file input event
41758 this.fileEl().on('change', this.uploadImage, this);
41765 resize: function(){
41767 var canvas = this.canvasEl().dom;
41768 var ctx = this.canvasElCtx();
41769 var img_data = false;
41771 if(canvas.width > 0) {
41772 var img_data = ctx.getImageData(0, 0, canvas.width, canvas.height);
41774 // setting canvas width will clean img data
41777 var style = window.getComputedStyle ?
41778 getComputedStyle(this.el.dom, null) : this.el.dom.currentStyle;
41780 var padding_left = parseInt(style.paddingLeft) || 0;
41781 var padding_right = parseInt(style.paddingRight) || 0;
41783 canvas.width = this.el.dom.clientWidth - padding_left - padding_right;
41786 ctx.putImageData(img_data, 0, 0);
41790 _handleMouseDown: function(e)
41792 if (e.browserEvent.which === 1) {
41793 this.mouse_btn_down = true;
41794 this.strokeBegin(e);
41798 _handleMouseMove: function (e)
41800 if (this.mouse_btn_down) {
41801 this.strokeMoveUpdate(e);
41805 _handleMouseUp: function (e)
41807 if (e.browserEvent.which === 1 && this.mouse_btn_down) {
41808 this.mouse_btn_down = false;
41813 _handleTouchStart: function (e) {
41815 e.preventDefault();
41816 if (e.browserEvent.targetTouches.length === 1) {
41817 // var touch = e.browserEvent.changedTouches[0];
41818 // this.strokeBegin(touch);
41820 this.strokeBegin(e); // assume e catching the correct xy...
41824 _handleTouchMove: function (e) {
41825 e.preventDefault();
41826 // var touch = event.targetTouches[0];
41827 // _this._strokeMoveUpdate(touch);
41828 this.strokeMoveUpdate(e);
41831 _handleTouchEnd: function (e) {
41832 var wasCanvasTouched = e.target === this.canvasEl().dom;
41833 if (wasCanvasTouched) {
41834 e.preventDefault();
41835 // var touch = event.changedTouches[0];
41836 // _this._strokeEnd(touch);
41841 reset: function () {
41842 this._lastPoints = [];
41843 this._lastVelocity = 0;
41844 this._lastWidth = (this.min_width + this.max_width) / 2;
41845 this.canvasElCtx().fillStyle = this.dot_color;
41848 strokeMoveUpdate: function(e)
41850 this.strokeUpdate(e);
41852 if (this.throttle) {
41853 this.throttleStroke(this.strokeUpdate, this.throttle);
41856 this.strokeUpdate(e);
41860 strokeBegin: function(e)
41862 var newPointGroup = {
41863 color: this.dot_color,
41867 if (typeof this.onBegin === 'function') {
41871 this.curve_data.push(newPointGroup);
41873 this.strokeUpdate(e);
41876 strokeUpdate: function(e)
41878 var rect = this.canvasEl().dom.getBoundingClientRect();
41879 var point = new this.Point(e.xy[0] - rect.left, e.xy[1] - rect.top, new Date().getTime());
41880 var lastPointGroup = this.curve_data[this.curve_data.length - 1];
41881 var lastPoints = lastPointGroup.points;
41882 var lastPoint = lastPoints.length > 0 && lastPoints[lastPoints.length - 1];
41883 var isLastPointTooClose = lastPoint
41884 ? point.distanceTo(lastPoint) <= this.min_distance
41886 var color = lastPointGroup.color;
41887 if (!lastPoint || !(lastPoint && isLastPointTooClose)) {
41888 var curve = this.addPoint(point);
41890 this.drawDot({color: color, point: point});
41893 this.drawCurve({color: color, curve: curve});
41903 strokeEnd: function(e)
41905 this.strokeUpdate(e);
41906 if (typeof this.onEnd === 'function') {
41911 addPoint: function (point) {
41912 var _lastPoints = this._lastPoints;
41913 _lastPoints.push(point);
41914 if (_lastPoints.length > 2) {
41915 if (_lastPoints.length === 3) {
41916 _lastPoints.unshift(_lastPoints[0]);
41918 var widths = this.calculateCurveWidths(_lastPoints[1], _lastPoints[2]);
41919 var curve = this.Bezier.fromPoints(_lastPoints, widths, this);
41920 _lastPoints.shift();
41926 calculateCurveWidths: function (startPoint, endPoint) {
41927 var velocity = this.velocity_filter_weight * endPoint.velocityFrom(startPoint) +
41928 (1 - this.velocity_filter_weight) * this._lastVelocity;
41930 var newWidth = Math.max(this.max_width / (velocity + 1), this.min_width);
41933 start: this._lastWidth
41936 this._lastVelocity = velocity;
41937 this._lastWidth = newWidth;
41941 drawDot: function (_a) {
41942 var color = _a.color, point = _a.point;
41943 var ctx = this.canvasElCtx();
41944 var width = typeof this.dot_size === 'function' ? this.dot_size() : this.dot_size;
41946 this.drawCurveSegment(point.x, point.y, width);
41948 ctx.fillStyle = color;
41952 drawCurve: function (_a) {
41953 var color = _a.color, curve = _a.curve;
41954 var ctx = this.canvasElCtx();
41955 var widthDelta = curve.endWidth - curve.startWidth;
41956 var drawSteps = Math.floor(curve.length()) * 2;
41958 ctx.fillStyle = color;
41959 for (var i = 0; i < drawSteps; i += 1) {
41960 var t = i / drawSteps;
41966 var x = uuu * curve.startPoint.x;
41967 x += 3 * uu * t * curve.control1.x;
41968 x += 3 * u * tt * curve.control2.x;
41969 x += ttt * curve.endPoint.x;
41970 var y = uuu * curve.startPoint.y;
41971 y += 3 * uu * t * curve.control1.y;
41972 y += 3 * u * tt * curve.control2.y;
41973 y += ttt * curve.endPoint.y;
41974 var width = curve.startWidth + ttt * widthDelta;
41975 this.drawCurveSegment(x, y, width);
41981 drawCurveSegment: function (x, y, width) {
41982 var ctx = this.canvasElCtx();
41984 ctx.arc(x, y, width, 0, 2 * Math.PI, false);
41985 this.is_empty = false;
41990 var ctx = this.canvasElCtx();
41991 var canvas = this.canvasEl().dom;
41992 ctx.fillStyle = this.bg_color;
41993 ctx.clearRect(0, 0, canvas.width, canvas.height);
41994 ctx.fillRect(0, 0, canvas.width, canvas.height);
41995 this.curve_data = [];
41997 this.is_empty = true;
42002 return this.el.select('input',true).first();
42005 canvasEl: function()
42007 return this.el.select('canvas',true).first();
42010 canvasElCtx: function()
42012 return this.el.select('canvas',true).first().dom.getContext('2d');
42015 getImage: function(type)
42017 if(this.is_empty) {
42022 return this.canvasEl().dom.toDataURL('image/'+type, 1);
42025 drawFromImage: function(img_src)
42027 var img = new Image();
42029 img.onload = function(){
42030 this.canvasElCtx().drawImage(img, 0, 0);
42035 this.is_empty = false;
42038 selectImage: function()
42040 this.fileEl().dom.click();
42043 uploadImage: function(e)
42045 var reader = new FileReader();
42047 reader.onload = function(e){
42048 var img = new Image();
42049 img.onload = function(){
42051 this.canvasElCtx().drawImage(img, 0, 0);
42053 img.src = e.target.result;
42056 reader.readAsDataURL(e.target.files[0]);
42059 // Bezier Point Constructor
42060 Point: (function () {
42061 function Point(x, y, time) {
42064 this.time = time || Date.now();
42066 Point.prototype.distanceTo = function (start) {
42067 return Math.sqrt(Math.pow(this.x - start.x, 2) + Math.pow(this.y - start.y, 2));
42069 Point.prototype.equals = function (other) {
42070 return this.x === other.x && this.y === other.y && this.time === other.time;
42072 Point.prototype.velocityFrom = function (start) {
42073 return this.time !== start.time
42074 ? this.distanceTo(start) / (this.time - start.time)
42081 // Bezier Constructor
42082 Bezier: (function () {
42083 function Bezier(startPoint, control2, control1, endPoint, startWidth, endWidth) {
42084 this.startPoint = startPoint;
42085 this.control2 = control2;
42086 this.control1 = control1;
42087 this.endPoint = endPoint;
42088 this.startWidth = startWidth;
42089 this.endWidth = endWidth;
42091 Bezier.fromPoints = function (points, widths, scope) {
42092 var c2 = this.calculateControlPoints(points[0], points[1], points[2], scope).c2;
42093 var c3 = this.calculateControlPoints(points[1], points[2], points[3], scope).c1;
42094 return new Bezier(points[1], c2, c3, points[2], widths.start, widths.end);
42096 Bezier.calculateControlPoints = function (s1, s2, s3, scope) {
42097 var dx1 = s1.x - s2.x;
42098 var dy1 = s1.y - s2.y;
42099 var dx2 = s2.x - s3.x;
42100 var dy2 = s2.y - s3.y;
42101 var m1 = { x: (s1.x + s2.x) / 2.0, y: (s1.y + s2.y) / 2.0 };
42102 var m2 = { x: (s2.x + s3.x) / 2.0, y: (s2.y + s3.y) / 2.0 };
42103 var l1 = Math.sqrt(dx1 * dx1 + dy1 * dy1);
42104 var l2 = Math.sqrt(dx2 * dx2 + dy2 * dy2);
42105 var dxm = m1.x - m2.x;
42106 var dym = m1.y - m2.y;
42107 var k = l2 / (l1 + l2);
42108 var cm = { x: m2.x + dxm * k, y: m2.y + dym * k };
42109 var tx = s2.x - cm.x;
42110 var ty = s2.y - cm.y;
42112 c1: new scope.Point(m1.x + tx, m1.y + ty),
42113 c2: new scope.Point(m2.x + tx, m2.y + ty)
42116 Bezier.prototype.length = function () {
42121 for (var i = 0; i <= steps; i += 1) {
42123 var cx = this.point(t, this.startPoint.x, this.control1.x, this.control2.x, this.endPoint.x);
42124 var cy = this.point(t, this.startPoint.y, this.control1.y, this.control2.y, this.endPoint.y);
42126 var xdiff = cx - px;
42127 var ydiff = cy - py;
42128 length += Math.sqrt(xdiff * xdiff + ydiff * ydiff);
42135 Bezier.prototype.point = function (t, start, c1, c2, end) {
42136 return (start * (1.0 - t) * (1.0 - t) * (1.0 - t))
42137 + (3.0 * c1 * (1.0 - t) * (1.0 - t) * t)
42138 + (3.0 * c2 * (1.0 - t) * t * t)
42139 + (end * t * t * t);
42144 throttleStroke: function(fn, wait) {
42145 if (wait === void 0) { wait = 250; }
42147 var timeout = null;
42151 var later = function () {
42152 previous = Date.now();
42154 result = fn.apply(storedContext, storedArgs);
42156 storedContext = null;
42160 return function wrapper() {
42162 for (var _i = 0; _i < arguments.length; _i++) {
42163 args[_i] = arguments[_i];
42165 var now = Date.now();
42166 var remaining = wait - (now - previous);
42167 storedContext = this;
42169 if (remaining <= 0 || remaining > wait) {
42171 clearTimeout(timeout);
42175 result = fn.apply(storedContext, storedArgs);
42177 storedContext = null;
42181 else if (!timeout) {
42182 timeout = window.setTimeout(later, remaining);