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
61 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent, {
64 allowDomMove : false, // to stop relocations in parent onRender...
74 * Initialize Events for the element
76 initEvents : function() { },
82 can_build_overlaid : true,
84 container_method : false,
91 // returns the parent component..
92 return Roo.ComponentMgr.get(this.parentId)
98 onRender : function(ct, position)
100 // Roo.log("Call onRender: " + this.xtype);
102 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
105 if (this.el.attr('xtype')) {
106 this.el.attr('xtypex', this.el.attr('xtype'));
107 this.el.dom.removeAttribute('xtype');
117 var cfg = Roo.apply({}, this.getAutoCreate());
119 cfg.id = this.id || Roo.id();
121 // fill in the extra attributes
122 if (this.xattr && typeof(this.xattr) =='object') {
123 for (var i in this.xattr) {
124 cfg[i] = this.xattr[i];
129 cfg.dataId = this.dataId;
133 cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
136 if (this.style) { // fixme needs to support more complex style data.
137 cfg.style = this.style;
141 cfg.name = this.name;
144 this.el = ct.createChild(cfg, position);
147 this.tooltipEl().attr('tooltip', this.tooltip);
150 if(this.tabIndex !== undefined){
151 this.el.dom.setAttribute('tabIndex', this.tabIndex);
158 * Fetch the element to add children to
159 * @return {Roo.Element} defaults to this.el
161 getChildContainer : function()
166 * Fetch the element to display the tooltip on.
167 * @return {Roo.Element} defaults to this.el
169 tooltipEl : function()
174 * This is really a wrapper for addxtypeChild
175 * it handles stuff relating to flexy:foreach / flexy:if
176 * = some of our projects use a flat rendering of the output, and try and overlay it with dynamic data.
177 * -- this is a bit of a nightmare... and is even more confusing to debug..
182 addxtype : function(tree,cntr)
186 cn = Roo.factory(tree);
187 //Roo.log(['addxtype', cn]);
189 cn.parentType = this.xtype; //??
190 cn.parentId = this.id;
192 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
193 if (typeof(cn.container_method) == 'string') {
194 cntr = cn.container_method;
198 var has_flexy_each = (typeof(tree['flexy:foreach']) != 'undefined');
200 var has_flexy_if = (typeof(tree['flexy:if']) != 'undefined');
202 var build_from_html = Roo.XComponent.build_from_html;
204 var is_body = (tree.xtype == 'Body') ;
206 var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
208 var self_cntr_el = Roo.get(this[cntr](false));
210 // do not try and build conditional elements
211 if ((has_flexy_each || has_flexy_if || this.can_build_overlaid == false ) && build_from_html) {
215 if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
216 if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
217 return this.addxtypeChild(tree,cntr, is_body);
220 var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
223 return this.addxtypeChild(Roo.apply({}, tree),cntr);
226 Roo.log('skipping render');
232 if (!build_from_html) {
236 // this i think handles overlaying multiple children of the same type
237 // with the sam eelement.. - which might be buggy..
239 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
245 if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
249 ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
255 * add a child to this element
256 * - turn the child.cfg into a child_instance
257 * - call child_instance.render( this { getContainerMethod()} )
258 * - loop through the children, and call addxtype.. (reall this) on newly created child.
262 addxtypeChild : function (tree, cntr, is_body)
264 Roo.debug && Roo.log('addxtypeChild:' + cntr);
266 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
269 var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
270 (typeof(tree['flexy:foreach']) != 'undefined');
274 skip_children = false;
275 // render the element if it's not BODY.
278 // if parent was disabled, then do not try and create the children..
279 if(!this[cntr](true)){
284 cn = Roo.factory(tree);
286 cn.parentType = this.xtype; //??
287 cn.parentId = this.id;
289 var build_from_html = Roo.XComponent.build_from_html;
292 // does the container contain child eleemnts with 'xtype' attributes.
293 // that match this xtype..
294 // note - when we render we create these as well..
295 // so we should check to see if body has xtype set.
296 if (build_from_html && Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
298 var self_cntr_el = Roo.get(this[cntr](false));
299 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
301 //Roo.log(Roo.XComponent.build_from_html);
302 //Roo.log("got echild:");
305 // there is a scenario where some of the child elements are flexy:if (and all of the same type)
306 // and are not displayed -this causes this to use up the wrong element when matching.
307 // at present the only work around for this is to nest flexy:if elements in another element that is always rendered.
310 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
311 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
317 //echild.dom.removeAttribute('xtype');
319 Roo.debug && Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
320 Roo.debug && Roo.log(self_cntr_el);
321 Roo.debug && Roo.log(echild);
322 Roo.debug && Roo.log(cn);
328 // if object has flexy:if - then it may or may not be rendered.
329 if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) {
330 // skip a flexy if element.
331 Roo.debug && Roo.log('skipping render');
332 Roo.debug && Roo.log(tree);
334 Roo.debug && Roo.log('skipping all children');
335 skip_children = true;
340 // actually if flexy:foreach is found, we really want to create
341 // multiple copies here...
343 //Roo.log(this[cntr]());
344 // some elements do not have render methods.. like the layouts...
346 if(this[cntr](true) === false){
351 cn.render && cn.render(this[cntr](true));
354 // then add the element..
361 cn.addxtypeChildren(tree.items, skip_children);
367 * add a number of children to this object,
368 * which in turn calls render...
372 addxtypeChildren: function(child_array, skip_children)
375 if (!child_array || !child_array.length ) {
380 for(var i =0;i < child_array.length;i++) {
384 // Roo.log(['add child', items[i]]);
385 nitems.push(this.addxtype(Roo.apply({}, child_array[i])));
389 this.fireEvent('childrenrendered', this);
396 * Set the element that will be used to show or hide
398 setVisibilityEl : function(el)
400 this.visibilityEl = el;
404 * Get the element that will be used to show or hide
406 getVisibilityEl : function()
408 if (typeof(this.visibilityEl) == 'object') {
409 return this.visibilityEl;
412 if (typeof(this.visibilityEl) == 'string') {
413 return this.visibilityEl == 'parent' ? this.parent().getEl() : this.getEl();
420 * Show a component - removes 'hidden' class
424 if(!this.getVisibilityEl()){
428 this.getVisibilityEl().removeClass(['hidden','d-none']);
430 this.fireEvent('show', this);
435 * Hide a component - adds 'hidden' class
439 if(!this.getVisibilityEl()){
443 this.getVisibilityEl().addClass(['hidden','d-none']);
445 this.fireEvent('hide', this);
458 * @class Roo.bootstrap.Body
459 * @extends Roo.bootstrap.Component
460 * Bootstrap Body class
464 * @param {Object} config The config object
465 * @cfg {DomElement} do_render - if this is set, then the constructor will try and initialize render, using this as the start point
469 Roo.bootstrap.Body = function(config){
471 config = config || {};
473 Roo.bootstrap.Body.superclass.constructor.call(this, config);
474 this.el = Roo.get(config.el ? config.el : document.body );
475 if (this.cls && this.cls.length) {
476 Roo.get(document.body).addClass(this.cls);
478 if (config.do_render) {
479 this.onRender(config.do_render, '');
480 this.addxtypeChildren(config.items);
485 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
488 is_body : true,// just to make sure it's constructed?
493 onRender : function(ct, position)
495 if (!this.do_render) {
498 this.el = Roo.get(this.do_render);
499 /* Roo.log("Roo.bootstrap.Body - onRender");
500 if (this.cls && this.cls.length) {
501 Roo.get(document.body).addClass(this.cls);
520 * @class Roo.bootstrap.ButtonGroup
521 * @extends Roo.bootstrap.Component
522 * Bootstrap ButtonGroup class
523 * @cfg {String} size lg | sm | xs (default empty normal)
524 * @cfg {String} align vertical | justified (default none)
525 * @cfg {String} direction up | down (default down)
526 * @cfg {Boolean} toolbar false | true
527 * @cfg {Boolean} btn true | false
532 * @param {Object} config The config object
535 Roo.bootstrap.ButtonGroup = function(config){
536 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
539 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
547 getAutoCreate : function(){
553 cfg.html = this.html || cfg.html;
564 if (['vertical','justified'].indexOf(this.align)!==-1) {
565 cfg.cls = 'btn-group-' + this.align;
567 if (this.align == 'justified') {
568 console.log(this.items);
572 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
573 cfg.cls += ' btn-group-' + this.size;
576 if (this.direction == 'up') {
577 cfg.cls += ' dropup' ;
583 * Add a button to the group (similar to NavItem API.)
585 addItem : function(cfg)
587 var cn = new Roo.bootstrap.Button(cfg);
589 cn.parentId = this.id;
590 cn.onRender(this.el, null);
604 * @class Roo.bootstrap.Button
605 * @extends Roo.bootstrap.Component
606 * Bootstrap Button class
607 * @cfg {String} html The button content
608 * @cfg {String} weight (default | primary | secondary | success | info | warning | danger | link ) default
609 * @cfg {String} badge_weight (default | primary | secondary | success | info | warning | danger | link ) default (same as button)
610 * @cfg {Boolean} outline default false (except for weight=default which emulates old behaveiour with an outline)
611 * @cfg {String} size ( lg | sm | xs)
612 * @cfg {String} tag ( a | input | submit)
613 * @cfg {String} href empty or href
614 * @cfg {Boolean} disabled default false;
615 * @cfg {Boolean} isClose default false;
616 * @cfg {String} glyphicon depricated - use fa
617 * @cfg {String} fa fontawesome icon - eg. 'comment' - without the fa/fas etc..
618 * @cfg {String} badge text for badge
619 * @cfg {String} theme (default|glow)
620 * @cfg {Boolean} inverse dark themed version
621 * @cfg {Boolean} toggle is it a slidy toggle button
622 * @cfg {Boolean} pressed (true|false) default null - if the button ahs active state
623 * @cfg {String} ontext text for on slidy toggle state
624 * @cfg {String} offtext text for off slidy toggle state
625 * @cfg {Boolean} preventDefault default true (stop click event triggering the URL if it's a link.)
626 * @cfg {Boolean} removeClass remove the standard class..
627 * @cfg {String} target target for a href. (_self|_blank|_parent|_top| other)
630 * Create a new button
631 * @param {Object} config The config object
635 Roo.bootstrap.Button = function(config){
636 Roo.bootstrap.Button.superclass.constructor.call(this, config);
637 this.weightClass = ["btn-default btn-outline-secondary",
649 * When a butotn is pressed
650 * @param {Roo.bootstrap.Button} btn
651 * @param {Roo.EventObject} e
656 * After the button has been toggles
657 * @param {Roo.bootstrap.Button} btn
658 * @param {Roo.EventObject} e
659 * @param {boolean} pressed (also available as button.pressed)
665 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
686 preventDefault: true,
694 getAutoCreate : function(){
702 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
703 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
708 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
710 if (this.toggle == true) {
713 cls: 'slider-frame roo-button',
718 'data-off-text':'OFF',
719 cls: 'slider-button',
725 if (['default', 'secondary' , 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
726 cfg.cls += ' '+this.weight;
735 cfg["aria-hidden"] = true;
737 cfg.html = "×";
743 if (this.theme==='default') {
744 cfg.cls = 'btn roo-button';
746 //if (this.parentType != 'Navbar') {
747 this.weight = this.weight.length ? this.weight : 'default';
749 if (['default', 'primary', 'secondary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
751 var outline = this.outline || this.weight == 'default' ? 'outline-' : '';
752 var weight = this.weight == 'default' ? 'secondary' : this.weight;
753 cfg.cls += ' btn-' + outline + weight;
754 if (this.weight == 'default') {
756 cfg.cls += ' btn-' + this.weight;
759 } else if (this.theme==='glow') {
762 cfg.cls = 'btn-glow roo-button';
764 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
766 cfg.cls += ' ' + this.weight;
772 this.cls += ' inverse';
776 if (this.active || this.pressed === true) {
777 cfg.cls += ' active';
781 cfg.disabled = 'disabled';
785 Roo.log('changing to ul' );
787 this.glyphicon = 'caret';
788 if (Roo.bootstrap.version == 4) {
789 this.fa = 'caret-down';
794 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
796 //gsRoo.log(this.parentType);
797 if (this.parentType === 'Navbar' && !this.parent().bar) {
798 Roo.log('changing to li?');
807 href : this.href || '#'
810 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
811 cfg.cls += ' dropdown';
818 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
820 if (this.glyphicon) {
821 cfg.html = ' ' + cfg.html;
826 cls: 'glyphicon glyphicon-' + this.glyphicon
831 cfg.html = ' ' + cfg.html;
836 cls: 'fa fas fa-' + this.fa
846 // cfg.cls='btn roo-button';
850 var value = cfg.html;
855 cls: 'glyphicon glyphicon-' + this.glyphicon,
862 cls: 'fa fas fa-' + this.fa,
867 var bw = this.badge_weight.length ? this.badge_weight :
868 (this.weight.length ? this.weight : 'secondary');
869 bw = bw == 'default' ? 'secondary' : bw;
875 cls: 'badge badge-' + bw,
884 cfg.cls += ' dropdown';
885 cfg.html = typeof(cfg.html) != 'undefined' ?
886 cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
889 if (cfg.tag !== 'a' && this.href !== '') {
890 throw "Tag must be a to set href.";
891 } else if (this.href.length > 0) {
892 cfg.href = this.href;
895 if(this.removeClass){
900 cfg.target = this.target;
905 initEvents: function() {
906 // Roo.log('init events?');
907 // Roo.log(this.el.dom);
910 if (typeof (this.menu) != 'undefined') {
911 this.menu.parentType = this.xtype;
912 this.menu.triggerEl = this.el;
913 this.addxtype(Roo.apply({}, this.menu));
917 if (this.el.hasClass('roo-button')) {
918 this.el.on('click', this.onClick, this);
920 this.el.select('.roo-button').on('click', this.onClick, this);
923 if(this.removeClass){
924 this.el.on('click', this.onClick, this);
927 this.el.enableDisplayMode();
930 onClick : function(e)
936 Roo.log('button on click ');
937 if(this.preventDefault){
941 if (this.pressed === true || this.pressed === false) {
942 this.toggleActive(e);
946 this.fireEvent('click', this, e);
950 * Enables this button
954 this.disabled = false;
955 this.el.removeClass('disabled');
959 * Disable this button
963 this.disabled = true;
964 this.el.addClass('disabled');
967 * sets the active state on/off,
968 * @param {Boolean} state (optional) Force a particular state
970 setActive : function(v) {
972 this.el[v ? 'addClass' : 'removeClass']('active');
976 * toggles the current active state
978 toggleActive : function(e)
980 this.setActive(!this.pressed);
981 this.fireEvent('toggle', this, e, !this.pressed);
984 * get the current active state
985 * @return {boolean} true if it's active
987 isActive : function()
989 return this.el.hasClass('active');
992 * set the text of the first selected button
994 setText : function(str)
996 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
999 * get the text of the first selected button
1001 getText : function()
1003 return this.el.select('.roo-button-text',true).first().dom.innerHTML;
1006 setWeight : function(str)
1008 this.el.removeClass(this.weightClass);
1010 var outline = this.outline ? 'outline-' : '';
1011 if (str == 'default') {
1012 this.el.addClass('btn-default btn-outline-secondary');
1015 this.el.addClass('btn-' + outline + str);
1029 * @class Roo.bootstrap.Column
1030 * @extends Roo.bootstrap.Component
1031 * Bootstrap Column class
1032 * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
1033 * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
1034 * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
1035 * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
1036 * @cfg {Number} xsoff colspan offset out of 12 for mobile-sized screens or 0 for hidden
1037 * @cfg {Number} smoff colspan offset out of 12 for tablet-sized screens or 0 for hidden
1038 * @cfg {Number} mdoff colspan offset out of 12 for computer-sized screens or 0 for hidden
1039 * @cfg {Number} lgoff colspan offset out of 12 for large computer-sized screens or 0 for hidden
1042 * @cfg {Boolean} hidden (true|false) hide the element
1043 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
1044 * @cfg {String} fa (ban|check|...) font awesome icon
1045 * @cfg {Number} fasize (1|2|....) font awsome size
1047 * @cfg {String} icon (info-sign|check|...) glyphicon name
1049 * @cfg {String} html content of column.
1052 * Create a new Column
1053 * @param {Object} config The config object
1056 Roo.bootstrap.Column = function(config){
1057 Roo.bootstrap.Column.superclass.constructor.call(this, config);
1060 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
1078 getAutoCreate : function(){
1079 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
1087 ['xs','sm','md','lg'].map(function(size){
1088 //Roo.log( size + ':' + settings[size]);
1090 if (settings[size+'off'] !== false) {
1091 cfg.cls += ' col-' + size + '-offset-' + settings[size+'off'] ;
1094 if (settings[size] === false) {
1098 if (!settings[size]) { // 0 = hidden
1099 cfg.cls += ' hidden-' + size + ' hidden' + size + '-down';;
1102 cfg.cls += ' col-' + size + '-' + settings[size] + (
1103 size == 'xs' ? (' col-' + settings[size] ) : '' // bs4 col-{num} replaces col-xs
1109 cfg.cls += ' hidden';
1112 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1113 cfg.cls +=' alert alert-' + this.alert;
1117 if (this.html.length) {
1118 cfg.html = this.html;
1122 if (this.fasize > 1) {
1123 fasize = ' fa-' + this.fasize + 'x';
1125 cfg.html = '<i class="fa fa-'+this.fa + fasize + '"></i>' + (cfg.html || '');
1130 cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + (cfg.html || '');
1149 * @class Roo.bootstrap.Container
1150 * @extends Roo.bootstrap.Component
1151 * Bootstrap Container class
1152 * @cfg {Boolean} jumbotron is it a jumbotron element
1153 * @cfg {String} html content of element
1154 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
1155 * @cfg {String} panel (default|primary|success|info|warning|danger) render as panel - type - primary/success.....
1156 * @cfg {String} header content of header (for panel)
1157 * @cfg {String} footer content of footer (for panel)
1158 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
1159 * @cfg {String} tag (header|aside|section) type of HTML tag.
1160 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
1161 * @cfg {String} fa font awesome icon
1162 * @cfg {String} icon (info-sign|check|...) glyphicon name
1163 * @cfg {Boolean} hidden (true|false) hide the element
1164 * @cfg {Boolean} expandable (true|false) default false
1165 * @cfg {Boolean} expanded (true|false) default true
1166 * @cfg {String} rheader contet on the right of header
1167 * @cfg {Boolean} clickable (true|false) default false
1171 * Create a new Container
1172 * @param {Object} config The config object
1175 Roo.bootstrap.Container = function(config){
1176 Roo.bootstrap.Container.superclass.constructor.call(this, config);
1182 * After the panel has been expand
1184 * @param {Roo.bootstrap.Container} this
1189 * After the panel has been collapsed
1191 * @param {Roo.bootstrap.Container} this
1196 * When a element is chick
1197 * @param {Roo.bootstrap.Container} this
1198 * @param {Roo.EventObject} e
1204 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
1222 getChildContainer : function() {
1228 if (this.panel.length) {
1229 return this.el.select('.panel-body',true).first();
1236 getAutoCreate : function(){
1239 tag : this.tag || 'div',
1243 if (this.jumbotron) {
1244 cfg.cls = 'jumbotron';
1249 // - this is applied by the parent..
1251 // cfg.cls = this.cls + '';
1254 if (this.sticky.length) {
1256 var bd = Roo.get(document.body);
1257 if (!bd.hasClass('bootstrap-sticky')) {
1258 bd.addClass('bootstrap-sticky');
1259 Roo.select('html',true).setStyle('height', '100%');
1262 cfg.cls += 'bootstrap-sticky-' + this.sticky;
1266 if (this.well.length) {
1267 switch (this.well) {
1270 cfg.cls +=' well well-' +this.well;
1279 cfg.cls += ' hidden';
1283 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1284 cfg.cls +=' alert alert-' + this.alert;
1289 if (this.panel.length) {
1290 cfg.cls += ' panel panel-' + this.panel;
1292 if (this.header.length) {
1296 if(this.expandable){
1298 cfg.cls = cfg.cls + ' expandable';
1302 cls: (this.expanded ? 'fa fa-minus' : 'fa fa-plus')
1310 cls : 'panel-title',
1311 html : (this.expandable ? ' ' : '') + this.header
1315 cls: 'panel-header-right',
1321 cls : 'panel-heading',
1322 style : this.expandable ? 'cursor: pointer' : '',
1330 cls : 'panel-body' + (this.expanded ? '' : ' hide'),
1335 if (this.footer.length) {
1337 cls : 'panel-footer',
1346 body.html = this.html || cfg.html;
1347 // prefix with the icons..
1349 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1352 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1357 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1358 cfg.cls = 'container';
1364 initEvents: function()
1366 if(this.expandable){
1367 var headerEl = this.headerEl();
1370 headerEl.on('click', this.onToggleClick, this);
1375 this.el.on('click', this.onClick, this);
1380 onToggleClick : function()
1382 var headerEl = this.headerEl();
1398 if(this.fireEvent('expand', this)) {
1400 this.expanded = true;
1402 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).show();
1404 this.el.select('.panel-body',true).first().removeClass('hide');
1406 var toggleEl = this.toggleEl();
1412 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-minus']);
1417 collapse : function()
1419 if(this.fireEvent('collapse', this)) {
1421 this.expanded = false;
1423 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).hide();
1424 this.el.select('.panel-body',true).first().addClass('hide');
1426 var toggleEl = this.toggleEl();
1432 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-plus']);
1436 toggleEl : function()
1438 if(!this.el || !this.panel.length || !this.header.length || !this.expandable){
1442 return this.el.select('.panel-heading .fa',true).first();
1445 headerEl : function()
1447 if(!this.el || !this.panel.length || !this.header.length){
1451 return this.el.select('.panel-heading',true).first()
1456 if(!this.el || !this.panel.length){
1460 return this.el.select('.panel-body',true).first()
1463 titleEl : function()
1465 if(!this.el || !this.panel.length || !this.header.length){
1469 return this.el.select('.panel-title',true).first();
1472 setTitle : function(v)
1474 var titleEl = this.titleEl();
1480 titleEl.dom.innerHTML = v;
1483 getTitle : function()
1486 var titleEl = this.titleEl();
1492 return titleEl.dom.innerHTML;
1495 setRightTitle : function(v)
1497 var t = this.el.select('.panel-header-right',true).first();
1503 t.dom.innerHTML = v;
1506 onClick : function(e)
1510 this.fireEvent('click', this, e);
1523 * @class Roo.bootstrap.Img
1524 * @extends Roo.bootstrap.Component
1525 * Bootstrap Img class
1526 * @cfg {Boolean} imgResponsive false | true
1527 * @cfg {String} border rounded | circle | thumbnail
1528 * @cfg {String} src image source
1529 * @cfg {String} alt image alternative text
1530 * @cfg {String} href a tag href
1531 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1532 * @cfg {String} xsUrl xs image source
1533 * @cfg {String} smUrl sm image source
1534 * @cfg {String} mdUrl md image source
1535 * @cfg {String} lgUrl lg image source
1538 * Create a new Input
1539 * @param {Object} config The config object
1542 Roo.bootstrap.Img = function(config){
1543 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1549 * The img click event for the img.
1550 * @param {Roo.EventObject} e
1556 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1558 imgResponsive: true,
1568 getAutoCreate : function()
1570 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1571 return this.createSingleImg();
1576 cls: 'roo-image-responsive-group',
1581 Roo.each(['xs', 'sm', 'md', 'lg'], function(size){
1583 if(!_this[size + 'Url']){
1589 cls: (_this.imgResponsive) ? 'img-responsive' : '',
1590 html: _this.html || cfg.html,
1591 src: _this[size + 'Url']
1594 img.cls += ' roo-image-responsive-' + size;
1596 var s = ['xs', 'sm', 'md', 'lg'];
1598 s.splice(s.indexOf(size), 1);
1600 Roo.each(s, function(ss){
1601 img.cls += ' hidden-' + ss;
1604 if (['rounded','circle','thumbnail'].indexOf(_this.border)>-1) {
1605 cfg.cls += ' img-' + _this.border;
1609 cfg.alt = _this.alt;
1622 a.target = _this.target;
1626 cfg.cn.push((_this.href) ? a : img);
1633 createSingleImg : function()
1637 cls: (this.imgResponsive) ? 'img-responsive' : '',
1639 src : 'about:blank' // just incase src get's set to undefined?!?
1642 cfg.html = this.html || cfg.html;
1644 cfg.src = this.src || cfg.src;
1646 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1647 cfg.cls += ' img-' + this.border;
1664 a.target = this.target;
1669 return (this.href) ? a : cfg;
1672 initEvents: function()
1675 this.el.on('click', this.onClick, this);
1680 onClick : function(e)
1682 Roo.log('img onclick');
1683 this.fireEvent('click', this, e);
1686 * Sets the url of the image - used to update it
1687 * @param {String} url the url of the image
1690 setSrc : function(url)
1694 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1695 this.el.dom.src = url;
1699 this.el.select('img', true).first().dom.src = url;
1715 * @class Roo.bootstrap.Link
1716 * @extends Roo.bootstrap.Component
1717 * Bootstrap Link Class
1718 * @cfg {String} alt image alternative text
1719 * @cfg {String} href a tag href
1720 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1721 * @cfg {String} html the content of the link.
1722 * @cfg {String} anchor name for the anchor link
1723 * @cfg {String} fa - favicon
1725 * @cfg {Boolean} preventDefault (true | false) default false
1729 * Create a new Input
1730 * @param {Object} config The config object
1733 Roo.bootstrap.Link = function(config){
1734 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1740 * The img click event for the img.
1741 * @param {Roo.EventObject} e
1747 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1751 preventDefault: false,
1757 getAutoCreate : function()
1759 var html = this.html || '';
1761 if (this.fa !== false) {
1762 html = '<i class="fa fa-' + this.fa + '"></i>';
1767 // anchor's do not require html/href...
1768 if (this.anchor === false) {
1770 cfg.href = this.href || '#';
1772 cfg.name = this.anchor;
1773 if (this.html !== false || this.fa !== false) {
1776 if (this.href !== false) {
1777 cfg.href = this.href;
1781 if(this.alt !== false){
1786 if(this.target !== false) {
1787 cfg.target = this.target;
1793 initEvents: function() {
1795 if(!this.href || this.preventDefault){
1796 this.el.on('click', this.onClick, this);
1800 onClick : function(e)
1802 if(this.preventDefault){
1805 //Roo.log('img onclick');
1806 this.fireEvent('click', this, e);
1819 * @class Roo.bootstrap.Header
1820 * @extends Roo.bootstrap.Component
1821 * Bootstrap Header class
1822 * @cfg {String} html content of header
1823 * @cfg {Number} level (1|2|3|4|5|6) default 1
1826 * Create a new Header
1827 * @param {Object} config The config object
1831 Roo.bootstrap.Header = function(config){
1832 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1835 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1843 getAutoCreate : function(){
1848 tag: 'h' + (1 *this.level),
1849 html: this.html || ''
1861 * Ext JS Library 1.1.1
1862 * Copyright(c) 2006-2007, Ext JS, LLC.
1864 * Originally Released Under LGPL - original licence link has changed is not relivant.
1867 * <script type="text/javascript">
1871 * @class Roo.bootstrap.MenuMgr
1872 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1875 Roo.bootstrap.MenuMgr = function(){
1876 var menus, active, groups = {}, attached = false, lastShow = new Date();
1878 // private - called when first menu is created
1881 active = new Roo.util.MixedCollection();
1882 Roo.get(document).addKeyListener(27, function(){
1883 if(active.length > 0){
1891 if(active && active.length > 0){
1892 var c = active.clone();
1902 if(active.length < 1){
1903 Roo.get(document).un("mouseup", onMouseDown);
1911 var last = active.last();
1912 lastShow = new Date();
1915 Roo.get(document).on("mouseup", onMouseDown);
1920 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1921 m.parentMenu.activeChild = m;
1922 }else if(last && last.isVisible()){
1923 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1928 function onBeforeHide(m){
1930 m.activeChild.hide();
1932 if(m.autoHideTimer){
1933 clearTimeout(m.autoHideTimer);
1934 delete m.autoHideTimer;
1939 function onBeforeShow(m){
1940 var pm = m.parentMenu;
1941 if(!pm && !m.allowOtherMenus){
1943 }else if(pm && pm.activeChild && active != m){
1944 pm.activeChild.hide();
1948 // private this should really trigger on mouseup..
1949 function onMouseDown(e){
1950 Roo.log("on Mouse Up");
1952 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".dropdown-menu") && !e.getTarget('.user-menu')){
1953 Roo.log("MenuManager hideAll");
1962 function onBeforeCheck(mi, state){
1964 var g = groups[mi.group];
1965 for(var i = 0, l = g.length; i < l; i++){
1967 g[i].setChecked(false);
1976 * Hides all menus that are currently visible
1978 hideAll : function(){
1983 register : function(menu){
1987 menus[menu.id] = menu;
1988 menu.on("beforehide", onBeforeHide);
1989 menu.on("hide", onHide);
1990 menu.on("beforeshow", onBeforeShow);
1991 menu.on("show", onShow);
1993 if(g && menu.events["checkchange"]){
1997 groups[g].push(menu);
1998 menu.on("checkchange", onCheck);
2003 * Returns a {@link Roo.menu.Menu} object
2004 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
2005 * be used to generate and return a new Menu instance.
2007 get : function(menu){
2008 if(typeof menu == "string"){ // menu id
2010 }else if(menu.events){ // menu instance
2013 /*else if(typeof menu.length == 'number'){ // array of menu items?
2014 return new Roo.bootstrap.Menu({items:menu});
2015 }else{ // otherwise, must be a config
2016 return new Roo.bootstrap.Menu(menu);
2023 unregister : function(menu){
2024 delete menus[menu.id];
2025 menu.un("beforehide", onBeforeHide);
2026 menu.un("hide", onHide);
2027 menu.un("beforeshow", onBeforeShow);
2028 menu.un("show", onShow);
2030 if(g && menu.events["checkchange"]){
2031 groups[g].remove(menu);
2032 menu.un("checkchange", onCheck);
2037 registerCheckable : function(menuItem){
2038 var g = menuItem.group;
2043 groups[g].push(menuItem);
2044 menuItem.on("beforecheckchange", onBeforeCheck);
2049 unregisterCheckable : function(menuItem){
2050 var g = menuItem.group;
2052 groups[g].remove(menuItem);
2053 menuItem.un("beforecheckchange", onBeforeCheck);
2065 * @class Roo.bootstrap.Menu
2066 * @extends Roo.bootstrap.Component
2067 * Bootstrap Menu class - container for MenuItems
2068 * @cfg {String} type (dropdown|treeview|submenu) type of menu
2069 * @cfg {bool} hidden if the menu should be hidden when rendered.
2070 * @cfg {bool} stopEvent (true|false) Stop event after trigger press (default true)
2071 * @cfg {bool} isLink (true|false) the menu has link disable auto expand and collaspe (default false)
2075 * @param {Object} config The config object
2079 Roo.bootstrap.Menu = function(config){
2080 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
2081 if (this.registerMenu && this.type != 'treeview') {
2082 Roo.bootstrap.MenuMgr.register(this);
2089 * Fires before this menu is displayed (return false to block)
2090 * @param {Roo.menu.Menu} this
2095 * Fires before this menu is hidden (return false to block)
2096 * @param {Roo.menu.Menu} this
2101 * Fires after this menu is displayed
2102 * @param {Roo.menu.Menu} this
2107 * Fires after this menu is hidden
2108 * @param {Roo.menu.Menu} this
2113 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
2114 * @param {Roo.menu.Menu} this
2115 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2116 * @param {Roo.EventObject} e
2121 * Fires when the mouse is hovering over this menu
2122 * @param {Roo.menu.Menu} this
2123 * @param {Roo.EventObject} e
2124 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2129 * Fires when the mouse exits this menu
2130 * @param {Roo.menu.Menu} this
2131 * @param {Roo.EventObject} e
2132 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2137 * Fires when a menu item contained in this menu is clicked
2138 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
2139 * @param {Roo.EventObject} e
2143 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
2146 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
2150 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
2153 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
2155 registerMenu : true,
2157 menuItems :false, // stores the menu items..
2167 getChildContainer : function() {
2171 getAutoCreate : function(){
2173 //if (['right'].indexOf(this.align)!==-1) {
2174 // cfg.cn[1].cls += ' pull-right'
2180 cls : 'dropdown-menu' ,
2181 style : 'z-index:1000'
2185 if (this.type === 'submenu') {
2186 cfg.cls = 'submenu active';
2188 if (this.type === 'treeview') {
2189 cfg.cls = 'treeview-menu';
2194 initEvents : function() {
2196 // Roo.log("ADD event");
2197 // Roo.log(this.triggerEl.dom);
2199 this.triggerEl.on('click', this.onTriggerClick, this);
2201 this.triggerEl.on(Roo.isTouch ? 'touchstart' : 'mouseup', this.onTriggerPress, this);
2204 if (this.triggerEl.hasClass('nav-item')) {
2205 // dropdown toggle on the 'a' in BS4?
2206 this.triggerEl.select('.nav-link',true).first().addClass('dropdown-toggle');
2208 this.triggerEl.addClass('dropdown-toggle');
2211 this.el.on('touchstart' , this.onTouch, this);
2213 this.el.on('click' , this.onClick, this);
2215 this.el.on("mouseover", this.onMouseOver, this);
2216 this.el.on("mouseout", this.onMouseOut, this);
2220 findTargetItem : function(e)
2222 var t = e.getTarget(".dropdown-menu-item", this.el, true);
2226 //Roo.log(t); Roo.log(t.id);
2228 //Roo.log(this.menuitems);
2229 return this.menuitems.get(t.id);
2231 //return this.items.get(t.menuItemId);
2237 onTouch : function(e)
2239 Roo.log("menu.onTouch");
2240 //e.stopEvent(); this make the user popdown broken
2244 onClick : function(e)
2246 Roo.log("menu.onClick");
2248 var t = this.findTargetItem(e);
2249 if(!t || t.isContainer){
2254 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
2255 if(t == this.activeItem && t.shouldDeactivate(e)){
2256 this.activeItem.deactivate();
2257 delete this.activeItem;
2261 this.setActiveItem(t, true);
2269 Roo.log('pass click event');
2273 this.fireEvent("click", this, t, e);
2277 if(!t.href.length || t.href == '#'){
2278 (function() { _this.hide(); }).defer(100);
2283 onMouseOver : function(e){
2284 var t = this.findTargetItem(e);
2287 // if(t.canActivate && !t.disabled){
2288 // this.setActiveItem(t, true);
2292 this.fireEvent("mouseover", this, e, t);
2294 isVisible : function(){
2295 return !this.hidden;
2297 onMouseOut : function(e){
2298 var t = this.findTargetItem(e);
2301 // if(t == this.activeItem && t.shouldDeactivate(e)){
2302 // this.activeItem.deactivate();
2303 // delete this.activeItem;
2306 this.fireEvent("mouseout", this, e, t);
2311 * Displays this menu relative to another element
2312 * @param {String/HTMLElement/Roo.Element} element The element to align to
2313 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
2314 * the element (defaults to this.defaultAlign)
2315 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2317 show : function(el, pos, parentMenu)
2319 if (false === this.fireEvent("beforeshow", this)) {
2320 Roo.log("show canceled");
2323 this.parentMenu = parentMenu;
2328 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
2331 * Displays this menu at a specific xy position
2332 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
2333 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2335 showAt : function(xy, parentMenu, /* private: */_e){
2336 this.parentMenu = parentMenu;
2341 this.fireEvent("beforeshow", this);
2342 //xy = this.el.adjustForConstraints(xy);
2346 this.hideMenuItems();
2347 this.hidden = false;
2348 this.triggerEl.addClass('open');
2349 this.el.addClass('show');
2351 // reassign x when hitting right
2352 if(this.el.getWidth() + xy[0] >= Roo.lib.Dom.getViewWidth()){
2353 xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
2356 // reassign y when hitting bottom
2357 if(this.el.getHeight() + xy[1] >= Roo.lib.Dom.getViewHeight()){
2358 xy[1] = xy[1] - this.el.getHeight() - this.triggerEl.getHeight();
2361 // but the list may align on trigger left or trigger top... should it be a properity?
2363 if(this.el.getStyle('top') != 'auto' && this.el.getStyle('top').slice(-1) != "%"){
2368 this.fireEvent("show", this);
2374 this.doFocus.defer(50, this);
2378 doFocus : function(){
2380 this.focusEl.focus();
2385 * Hides this menu and optionally all parent menus
2386 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
2388 hide : function(deep)
2390 if (false === this.fireEvent("beforehide", this)) {
2391 Roo.log("hide canceled");
2394 this.hideMenuItems();
2395 if(this.el && this.isVisible()){
2397 if(this.activeItem){
2398 this.activeItem.deactivate();
2399 this.activeItem = null;
2401 this.triggerEl.removeClass('open');;
2402 this.el.removeClass('show');
2404 this.fireEvent("hide", this);
2406 if(deep === true && this.parentMenu){
2407 this.parentMenu.hide(true);
2411 onTriggerClick : function(e)
2413 Roo.log('trigger click');
2415 var target = e.getTarget();
2417 Roo.log(target.nodeName.toLowerCase());
2419 if(target.nodeName.toLowerCase() === 'i'){
2425 onTriggerPress : function(e)
2427 Roo.log('trigger press');
2428 //Roo.log(e.getTarget());
2429 // Roo.log(this.triggerEl.dom);
2431 // trigger only occurs on normal menu's -- if it's a treeview or dropdown... do not hide/show..
2432 var pel = Roo.get(e.getTarget());
2433 if (pel.findParent('.dropdown-menu') || pel.findParent('.treeview-menu') ) {
2434 Roo.log('is treeview or dropdown?');
2438 if(e.getTarget().nodeName.toLowerCase() !== 'i' && this.isLink){
2442 if (this.isVisible()) {
2447 this.show(this.triggerEl, '?', false);
2450 if(this.stopEvent || e.getTarget().nodeName.toLowerCase() === 'i'){
2457 hideMenuItems : function()
2459 Roo.log("hide Menu Items");
2464 this.el.select('.open',true).each(function(aa) {
2466 aa.removeClass('open');
2470 addxtypeChild : function (tree, cntr) {
2471 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
2473 this.menuitems.add(comp);
2485 this.getEl().dom.innerHTML = '';
2486 this.menuitems.clear();
2500 * @class Roo.bootstrap.MenuItem
2501 * @extends Roo.bootstrap.Component
2502 * Bootstrap MenuItem class
2503 * @cfg {String} html the menu label
2504 * @cfg {String} href the link
2505 * @cfg {Boolean} preventDefault do not trigger A href on clicks (default false).
2506 * @cfg {Boolean} isContainer is it a container - just returns a drop down item..
2507 * @cfg {Boolean} active used on sidebars to highlight active itesm
2508 * @cfg {String} fa favicon to show on left of menu item.
2509 * @cfg {Roo.bootsrap.Menu} menu the child menu.
2513 * Create a new MenuItem
2514 * @param {Object} config The config object
2518 Roo.bootstrap.MenuItem = function(config){
2519 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
2524 * The raw click event for the entire grid.
2525 * @param {Roo.bootstrap.MenuItem} this
2526 * @param {Roo.EventObject} e
2532 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
2536 preventDefault: false,
2537 isContainer : false,
2541 getAutoCreate : function(){
2543 if(this.isContainer){
2546 cls: 'dropdown-menu-item '
2556 cls : 'dropdown-item',
2561 if (this.fa !== false) {
2564 cls : 'fa fa-' + this.fa
2573 cls: 'dropdown-menu-item',
2576 if (this.parent().type == 'treeview') {
2577 cfg.cls = 'treeview-menu';
2580 cfg.cls += ' active';
2585 anc.href = this.href || cfg.cn[0].href ;
2586 ctag.html = this.html || cfg.cn[0].html ;
2590 initEvents: function()
2592 if (this.parent().type == 'treeview') {
2593 this.el.select('a').on('click', this.onClick, this);
2597 this.menu.parentType = this.xtype;
2598 this.menu.triggerEl = this.el;
2599 this.menu = this.addxtype(Roo.apply({}, this.menu));
2603 onClick : function(e)
2605 Roo.log('item on click ');
2607 if(this.preventDefault){
2610 //this.parent().hideMenuItems();
2612 this.fireEvent('click', this, e);
2631 * @class Roo.bootstrap.MenuSeparator
2632 * @extends Roo.bootstrap.Component
2633 * Bootstrap MenuSeparator class
2636 * Create a new MenuItem
2637 * @param {Object} config The config object
2641 Roo.bootstrap.MenuSeparator = function(config){
2642 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2645 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2647 getAutoCreate : function(){
2666 * @class Roo.bootstrap.Modal
2667 * @extends Roo.bootstrap.Component
2668 * Bootstrap Modal class
2669 * @cfg {String} title Title of dialog
2670 * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2671 * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method adn
2672 * @cfg {Boolean} specificTitle default false
2673 * @cfg {Array} buttons Array of buttons or standard button set..
2674 * @cfg {String} buttonPosition (left|right|center) default right (DEPRICATED) - use mr-auto on buttons to put them on the left
2675 * @cfg {Boolean} animate default true
2676 * @cfg {Boolean} allow_close default true
2677 * @cfg {Boolean} fitwindow default false
2678 * @cfg {String} size (sm|lg) default empty
2679 * @cfg {Number} max_width set the max width of modal
2683 * Create a new Modal Dialog
2684 * @param {Object} config The config object
2687 Roo.bootstrap.Modal = function(config){
2688 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2693 * The raw btnclick event for the button
2694 * @param {Roo.EventObject} e
2699 * Fire when dialog resize
2700 * @param {Roo.bootstrap.Modal} this
2701 * @param {Roo.EventObject} e
2705 this.buttons = this.buttons || [];
2708 this.tmpl = Roo.factory(this.tmpl);
2713 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2715 title : 'test dialog',
2725 specificTitle: false,
2727 buttonPosition: 'right',
2750 onRender : function(ct, position)
2752 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2755 var cfg = Roo.apply({}, this.getAutoCreate());
2758 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2760 //if (!cfg.name.length) {
2764 cfg.cls += ' ' + this.cls;
2767 cfg.style = this.style;
2769 this.el = Roo.get(document.body).createChild(cfg, position);
2771 //var type = this.el.dom.type;
2774 if(this.tabIndex !== undefined){
2775 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2778 this.dialogEl = this.el.select('.modal-dialog',true).first();
2779 this.bodyEl = this.el.select('.modal-body',true).first();
2780 this.closeEl = this.el.select('.modal-header .close', true).first();
2781 this.headerEl = this.el.select('.modal-header',true).first();
2782 this.titleEl = this.el.select('.modal-title',true).first();
2783 this.footerEl = this.el.select('.modal-footer',true).first();
2785 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2787 //this.el.addClass("x-dlg-modal");
2789 if (this.buttons.length) {
2790 Roo.each(this.buttons, function(bb) {
2791 var b = Roo.apply({}, bb);
2792 b.xns = b.xns || Roo.bootstrap;
2793 b.xtype = b.xtype || 'Button';
2794 if (typeof(b.listeners) == 'undefined') {
2795 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2798 var btn = Roo.factory(b);
2800 btn.render(this.getButtonContainer());
2804 // render the children.
2807 if(typeof(this.items) != 'undefined'){
2808 var items = this.items;
2811 for(var i =0;i < items.length;i++) {
2812 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2816 this.items = nitems;
2818 // where are these used - they used to be body/close/footer
2822 //this.el.addClass([this.fieldClass, this.cls]);
2826 getAutoCreate : function()
2830 html : this.html || ''
2835 cls : 'modal-title',
2839 if(this.specificTitle){
2845 if (this.allow_close && Roo.bootstrap.version == 3) {
2855 if (this.allow_close && Roo.bootstrap.version == 4) {
2865 if(this.size.length){
2866 size = 'modal-' + this.size;
2869 var footer = Roo.bootstrap.version == 3 ?
2871 cls : 'modal-footer',
2875 cls: 'btn-' + this.buttonPosition
2880 { // BS4 uses mr-auto on left buttons....
2881 cls : 'modal-footer'
2892 cls: "modal-dialog " + size,
2895 cls : "modal-content",
2898 cls : 'modal-header',
2913 modal.cls += ' fade';
2919 getChildContainer : function() {
2924 getButtonContainer : function() {
2926 return Roo.bootstrap.version == 4 ?
2927 this.el.select('.modal-footer',true).first()
2928 : this.el.select('.modal-footer div',true).first();
2931 initEvents : function()
2933 if (this.allow_close) {
2934 this.closeEl.on('click', this.hide, this);
2936 Roo.EventManager.onWindowResize(this.resize, this, true);
2944 this.maskEl.setSize(
2945 Roo.lib.Dom.getViewWidth(true),
2946 Roo.lib.Dom.getViewHeight(true)
2949 if (this.fitwindow) {
2953 this.width || Roo.lib.Dom.getViewportWidth(true) - 30,
2954 this.height || Roo.lib.Dom.getViewportHeight(true) // catering margin-top 30 margin-bottom 30
2959 if(this.max_width !== 0) {
2961 var w = Math.min(this.max_width, Roo.lib.Dom.getViewportWidth(true) - 30);
2964 this.setSize(w, this.height);
2968 if(this.max_height) {
2969 this.setSize(w,Math.min(
2971 Roo.lib.Dom.getViewportHeight(true) - 60
2977 if(!this.fit_content) {
2978 this.setSize(w, Roo.lib.Dom.getViewportHeight(true) - 60);
2982 this.setSize(w, Math.min(
2984 this.headerEl.getHeight() +
2985 this.footerEl.getHeight() +
2986 this.getChildHeight(this.bodyEl.dom.childNodes),
2987 Roo.lib.Dom.getViewportHeight(true) - 60)
2993 setSize : function(w,h)
3004 if (!this.rendered) {
3008 //this.el.setStyle('display', 'block');
3009 this.el.removeClass('hideing');
3010 this.el.dom.style.display='block';
3012 Roo.get(document.body).addClass('modal-open');
3014 if(this.animate){ // element has 'fade' - so stuff happens after .3s ?- not sure why the delay?
3017 this.el.addClass('show');
3018 this.el.addClass('in');
3021 this.el.addClass('show');
3022 this.el.addClass('in');
3025 // not sure how we can show data in here..
3027 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
3030 Roo.get(document.body).addClass("x-body-masked");
3032 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
3033 this.maskEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
3034 this.maskEl.dom.style.display = 'block';
3035 this.maskEl.addClass('show');
3040 this.fireEvent('show', this);
3042 // set zindex here - otherwise it appears to be ignored...
3043 this.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
3046 this.items.forEach( function(e) {
3047 e.layout ? e.layout() : false;
3055 if(this.fireEvent("beforehide", this) !== false){
3057 this.maskEl.removeClass('show');
3059 this.maskEl.dom.style.display = '';
3060 Roo.get(document.body).removeClass("x-body-masked");
3061 this.el.removeClass('in');
3062 this.el.select('.modal-dialog', true).first().setStyle('transform','');
3064 if(this.animate){ // why
3065 this.el.addClass('hideing');
3066 this.el.removeClass('show');
3068 if (!this.el.hasClass('hideing')) {
3069 return; // it's been shown again...
3072 this.el.dom.style.display='';
3074 Roo.get(document.body).removeClass('modal-open');
3075 this.el.removeClass('hideing');
3079 this.el.removeClass('show');
3080 this.el.dom.style.display='';
3081 Roo.get(document.body).removeClass('modal-open');
3084 this.fireEvent('hide', this);
3087 isVisible : function()
3090 return this.el.hasClass('show') && !this.el.hasClass('hideing');
3094 addButton : function(str, cb)
3098 var b = Roo.apply({}, { html : str } );
3099 b.xns = b.xns || Roo.bootstrap;
3100 b.xtype = b.xtype || 'Button';
3101 if (typeof(b.listeners) == 'undefined') {
3102 b.listeners = { click : cb.createDelegate(this) };
3105 var btn = Roo.factory(b);
3107 btn.render(this.getButtonContainer());
3113 setDefaultButton : function(btn)
3115 //this.el.select('.modal-footer').()
3118 resizeTo: function(w,h)
3120 this.dialogEl.setWidth(w);
3122 var diff = this.headerEl.getHeight() + this.footerEl.getHeight() + 60; // dialog margin-bottom: 30
3124 this.bodyEl.setHeight(h - diff);
3126 this.fireEvent('resize', this);
3129 setContentSize : function(w, h)
3133 onButtonClick: function(btn,e)
3136 this.fireEvent('btnclick', btn.name, e);
3139 * Set the title of the Dialog
3140 * @param {String} str new Title
3142 setTitle: function(str) {
3143 this.titleEl.dom.innerHTML = str;
3146 * Set the body of the Dialog
3147 * @param {String} str new Title
3149 setBody: function(str) {
3150 this.bodyEl.dom.innerHTML = str;
3153 * Set the body of the Dialog using the template
3154 * @param {Obj} data - apply this data to the template and replace the body contents.
3156 applyBody: function(obj)
3159 Roo.log("Error - using apply Body without a template");
3162 this.tmpl.overwrite(this.bodyEl, obj);
3165 getChildHeight : function(child_nodes)
3169 child_nodes.length == 0
3174 var child_height = 0;
3176 for(var i = 0; i < child_nodes.length; i++) {
3179 * for modal with tabs...
3180 if(child_nodes[i].classList.contains('roo-layout-panel')) {
3182 var layout_childs = child_nodes[i].childNodes;
3184 for(var j = 0; j < layout_childs.length; j++) {
3186 if(layout_childs[j].classList.contains('roo-layout-panel-body')) {
3188 var layout_body_childs = layout_childs[j].childNodes;
3190 for(var k = 0; k < layout_body_childs.length; k++) {
3192 if(layout_body_childs[k].classList.contains('navbar')) {
3193 child_height += layout_body_childs[k].offsetHeight;
3197 if(layout_body_childs[k].classList.contains('roo-layout-tabs-body')) {
3199 var layout_body_tab_childs = layout_body_childs[k].childNodes;
3201 for(var m = 0; m < layout_body_tab_childs.length; m++) {
3203 if(layout_body_tab_childs[m].classList.contains('roo-layout-active-content')) {
3204 child_height += this.getChildHeight(layout_body_tab_childs[m].childNodes);
3219 child_height += child_nodes[i].offsetHeight;
3220 // Roo.log(child_nodes[i].offsetHeight);
3223 return child_height;
3229 Roo.apply(Roo.bootstrap.Modal, {
3231 * Button config that displays a single OK button
3240 * Button config that displays Yes and No buttons
3256 * Button config that displays OK and Cancel buttons
3271 * Button config that displays Yes, No and Cancel buttons
3295 * messagebox - can be used as a replace
3299 * @class Roo.MessageBox
3300 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
3304 Roo.Msg.alert('Status', 'Changes saved successfully.');
3306 // Prompt for user data:
3307 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
3309 // process text value...
3313 // Show a dialog using config options:
3315 title:'Save Changes?',
3316 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
3317 buttons: Roo.Msg.YESNOCANCEL,
3324 Roo.bootstrap.MessageBox = function(){
3325 var dlg, opt, mask, waitTimer;
3326 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
3327 var buttons, activeTextEl, bwidth;
3331 var handleButton = function(button){
3333 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
3337 var handleHide = function(){
3339 dlg.el.removeClass(opt.cls);
3342 // Roo.TaskMgr.stop(waitTimer);
3343 // waitTimer = null;
3348 var updateButtons = function(b){
3351 buttons["ok"].hide();
3352 buttons["cancel"].hide();
3353 buttons["yes"].hide();
3354 buttons["no"].hide();
3355 dlg.footerEl.hide();
3359 dlg.footerEl.show();
3360 for(var k in buttons){
3361 if(typeof buttons[k] != "function"){
3364 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
3365 width += buttons[k].el.getWidth()+15;
3375 var handleEsc = function(d, k, e){
3376 if(opt && opt.closable !== false){
3386 * Returns a reference to the underlying {@link Roo.BasicDialog} element
3387 * @return {Roo.BasicDialog} The BasicDialog element
3389 getDialog : function(){
3391 dlg = new Roo.bootstrap.Modal( {
3394 //constraintoviewport:false,
3396 //collapsible : false,
3401 //buttonAlign:"center",
3402 closeClick : function(){
3403 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
3406 handleButton("cancel");
3411 dlg.on("hide", handleHide);
3413 //dlg.addKeyListener(27, handleEsc);
3415 this.buttons = buttons;
3416 var bt = this.buttonText;
3417 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
3418 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
3419 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
3420 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
3422 bodyEl = dlg.bodyEl.createChild({
3424 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
3425 '<textarea class="roo-mb-textarea"></textarea>' +
3426 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
3428 msgEl = bodyEl.dom.firstChild;
3429 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
3430 textboxEl.enableDisplayMode();
3431 textboxEl.addKeyListener([10,13], function(){
3432 if(dlg.isVisible() && opt && opt.buttons){
3435 }else if(opt.buttons.yes){
3436 handleButton("yes");
3440 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
3441 textareaEl.enableDisplayMode();
3442 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
3443 progressEl.enableDisplayMode();
3445 // This is supposed to be the progessElement.. but I think it's controlling the height of everything..
3446 var pf = progressEl.dom.firstChild;
3448 pp = Roo.get(pf.firstChild);
3449 pp.setHeight(pf.offsetHeight);
3457 * Updates the message box body text
3458 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
3459 * the XHTML-compliant non-breaking space character '&#160;')
3460 * @return {Roo.MessageBox} This message box
3462 updateText : function(text)
3464 if(!dlg.isVisible() && !opt.width){
3465 dlg.dialogEl.setStyle({ 'max-width' : this.maxWidth});
3466 // dlg.resizeTo(this.maxWidth, 100); // forcing the height breaks long alerts()
3468 msgEl.innerHTML = text || ' ';
3470 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
3471 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
3473 Math.min(opt.width || cw , this.maxWidth),
3474 Math.max(opt.minWidth || this.minWidth, bwidth)
3477 activeTextEl.setWidth(w);
3479 if(dlg.isVisible()){
3480 dlg.fixedcenter = false;
3482 // to big, make it scroll. = But as usual stupid IE does not support
3485 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
3486 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
3487 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
3489 bodyEl.dom.style.height = '';
3490 bodyEl.dom.style.overflowY = '';
3493 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
3495 bodyEl.dom.style.overflowX = '';
3498 dlg.setContentSize(w, bodyEl.getHeight());
3499 if(dlg.isVisible()){
3500 dlg.fixedcenter = true;
3506 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
3507 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
3508 * @param {Number} value Any number between 0 and 1 (e.g., .5)
3509 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
3510 * @return {Roo.MessageBox} This message box
3512 updateProgress : function(value, text){
3514 this.updateText(text);
3517 if (pp) { // weird bug on my firefox - for some reason this is not defined
3518 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
3519 pp.setHeight(Math.floor(progressEl.dom.firstChild.offsetHeight));
3525 * Returns true if the message box is currently displayed
3526 * @return {Boolean} True if the message box is visible, else false
3528 isVisible : function(){
3529 return dlg && dlg.isVisible();
3533 * Hides the message box if it is displayed
3536 if(this.isVisible()){
3542 * Displays a new message box, or reinitializes an existing message box, based on the config options
3543 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
3544 * The following config object properties are supported:
3546 Property Type Description
3547 ---------- --------------- ------------------------------------------------------------------------------------
3548 animEl String/Element An id or Element from which the message box should animate as it opens and
3549 closes (defaults to undefined)
3550 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
3551 cancel:'Bar'}), or false to not show any buttons (defaults to false)
3552 closable Boolean False to hide the top-right close button (defaults to true). Note that
3553 progress and wait dialogs will ignore this property and always hide the
3554 close button as they can only be closed programmatically.
3555 cls String A custom CSS class to apply to the message box element
3556 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
3557 displayed (defaults to 75)
3558 fn Function A callback function to execute after closing the dialog. The arguments to the
3559 function will be btn (the name of the button that was clicked, if applicable,
3560 e.g. "ok"), and text (the value of the active text field, if applicable).
3561 Progress and wait dialogs will ignore this option since they do not respond to
3562 user actions and can only be closed programmatically, so any required function
3563 should be called by the same code after it closes the dialog.
3564 icon String A CSS class that provides a background image to be used as an icon for
3565 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
3566 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
3567 minWidth Number The minimum width in pixels of the message box (defaults to 100)
3568 modal Boolean False to allow user interaction with the page while the message box is
3569 displayed (defaults to true)
3570 msg String A string that will replace the existing message box body text (defaults
3571 to the XHTML-compliant non-breaking space character ' ')
3572 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
3573 progress Boolean True to display a progress bar (defaults to false)
3574 progressText String The text to display inside the progress bar if progress = true (defaults to '')
3575 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
3576 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
3577 title String The title text
3578 value String The string value to set into the active textbox element if displayed
3579 wait Boolean True to display a progress bar (defaults to false)
3580 width Number The width of the dialog in pixels
3587 msg: 'Please enter your address:',
3589 buttons: Roo.MessageBox.OKCANCEL,
3592 animEl: 'addAddressBtn'
3595 * @param {Object} config Configuration options
3596 * @return {Roo.MessageBox} This message box
3598 show : function(options)
3601 // this causes nightmares if you show one dialog after another
3602 // especially on callbacks..
3604 if(this.isVisible()){
3607 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
3608 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
3609 Roo.log("New Dialog Message:" + options.msg )
3610 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
3611 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
3614 var d = this.getDialog();
3616 d.setTitle(opt.title || " ");
3617 d.closeEl.setDisplayed(opt.closable !== false);
3618 activeTextEl = textboxEl;
3619 opt.prompt = opt.prompt || (opt.multiline ? true : false);
3624 textareaEl.setHeight(typeof opt.multiline == "number" ?
3625 opt.multiline : this.defaultTextHeight);
3626 activeTextEl = textareaEl;
3635 progressEl.setDisplayed(opt.progress === true);
3637 d.animate = false; // do not animate progress, as it may not have finished animating before we close it..
3639 this.updateProgress(0);
3640 activeTextEl.dom.value = opt.value || "";
3642 dlg.setDefaultButton(activeTextEl);
3644 var bs = opt.buttons;
3648 }else if(bs && bs.yes){
3649 db = buttons["yes"];
3651 dlg.setDefaultButton(db);
3653 bwidth = updateButtons(opt.buttons);
3654 this.updateText(opt.msg);
3656 d.el.addClass(opt.cls);
3658 d.proxyDrag = opt.proxyDrag === true;
3659 d.modal = opt.modal !== false;
3660 d.mask = opt.modal !== false ? mask : false;
3662 // force it to the end of the z-index stack so it gets a cursor in FF
3663 document.body.appendChild(dlg.el.dom);
3664 d.animateTarget = null;
3665 d.show(options.animEl);
3671 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
3672 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
3673 * and closing the message box when the process is complete.
3674 * @param {String} title The title bar text
3675 * @param {String} msg The message box body text
3676 * @return {Roo.MessageBox} This message box
3678 progress : function(title, msg){
3685 minWidth: this.minProgressWidth,
3692 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
3693 * If a callback function is passed it will be called after the user clicks the button, and the
3694 * id of the button that was clicked will be passed as the only parameter to the callback
3695 * (could also be the top-right close button).
3696 * @param {String} title The title bar text
3697 * @param {String} msg The message box body text
3698 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3699 * @param {Object} scope (optional) The scope of the callback function
3700 * @return {Roo.MessageBox} This message box
3702 alert : function(title, msg, fn, scope)
3717 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
3718 * interaction while waiting for a long-running process to complete that does not have defined intervals.
3719 * You are responsible for closing the message box when the process is complete.
3720 * @param {String} msg The message box body text
3721 * @param {String} title (optional) The title bar text
3722 * @return {Roo.MessageBox} This message box
3724 wait : function(msg, title){
3735 waitTimer = Roo.TaskMgr.start({
3737 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
3745 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
3746 * If a callback function is passed it will be called after the user clicks either button, and the id of the
3747 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
3748 * @param {String} title The title bar text
3749 * @param {String} msg The message box body text
3750 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3751 * @param {Object} scope (optional) The scope of the callback function
3752 * @return {Roo.MessageBox} This message box
3754 confirm : function(title, msg, fn, scope){
3758 buttons: this.YESNO,
3767 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
3768 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
3769 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
3770 * (could also be the top-right close button) and the text that was entered will be passed as the two
3771 * parameters to the callback.
3772 * @param {String} title The title bar text
3773 * @param {String} msg The message box body text
3774 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3775 * @param {Object} scope (optional) The scope of the callback function
3776 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
3777 * property, or the height in pixels to create the textbox (defaults to false / single-line)
3778 * @return {Roo.MessageBox} This message box
3780 prompt : function(title, msg, fn, scope, multiline){
3784 buttons: this.OKCANCEL,
3789 multiline: multiline,
3796 * Button config that displays a single OK button
3801 * Button config that displays Yes and No buttons
3804 YESNO : {yes:true, no:true},
3806 * Button config that displays OK and Cancel buttons
3809 OKCANCEL : {ok:true, cancel:true},
3811 * Button config that displays Yes, No and Cancel buttons
3814 YESNOCANCEL : {yes:true, no:true, cancel:true},
3817 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3820 defaultTextHeight : 75,
3822 * The maximum width in pixels of the message box (defaults to 600)
3827 * The minimum width in pixels of the message box (defaults to 100)
3832 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3833 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3836 minProgressWidth : 250,
3838 * An object containing the default button text strings that can be overriden for localized language support.
3839 * Supported properties are: ok, cancel, yes and no.
3840 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3853 * Shorthand for {@link Roo.MessageBox}
3855 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3856 Roo.Msg = Roo.Msg || Roo.MessageBox;
3865 * @class Roo.bootstrap.Navbar
3866 * @extends Roo.bootstrap.Component
3867 * Bootstrap Navbar class
3870 * Create a new Navbar
3871 * @param {Object} config The config object
3875 Roo.bootstrap.Navbar = function(config){
3876 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3880 * @event beforetoggle
3881 * Fire before toggle the menu
3882 * @param {Roo.EventObject} e
3884 "beforetoggle" : true
3888 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3897 getAutoCreate : function(){
3900 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3904 initEvents :function ()
3906 //Roo.log(this.el.select('.navbar-toggle',true));
3907 this.el.select('.navbar-toggle',true).on('click', this.onToggle , this);
3914 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3916 var size = this.el.getSize();
3917 this.maskEl.setSize(size.width, size.height);
3918 this.maskEl.enableDisplayMode("block");
3927 getChildContainer : function()
3929 if (this.el && this.el.select('.collapse').getCount()) {
3930 return this.el.select('.collapse',true).first();
3945 onToggle : function()
3948 if(this.fireEvent('beforetoggle', this) === false){
3951 var ce = this.el.select('.navbar-collapse',true).first();
3953 if (!ce.hasClass('show')) {
3963 * Expand the navbar pulldown
3965 expand : function ()
3968 var ce = this.el.select('.navbar-collapse',true).first();
3969 if (ce.hasClass('collapsing')) {
3972 ce.dom.style.height = '';
3974 ce.addClass('in'); // old...
3975 ce.removeClass('collapse');
3976 ce.addClass('show');
3977 var h = ce.getHeight();
3979 ce.removeClass('show');
3980 // at this point we should be able to see it..
3981 ce.addClass('collapsing');
3983 ce.setHeight(0); // resize it ...
3984 ce.on('transitionend', function() {
3985 //Roo.log('done transition');
3986 ce.removeClass('collapsing');
3987 ce.addClass('show');
3988 ce.removeClass('collapse');
3990 ce.dom.style.height = '';
3991 }, this, { single: true} );
3993 ce.dom.scrollTop = 0;
3996 * Collapse the navbar pulldown
3998 collapse : function()
4000 var ce = this.el.select('.navbar-collapse',true).first();
4002 if (ce.hasClass('collapsing') || ce.hasClass('collapse') ) {
4003 // it's collapsed or collapsing..
4006 ce.removeClass('in'); // old...
4007 ce.setHeight(ce.getHeight());
4008 ce.removeClass('show');
4009 ce.addClass('collapsing');
4011 ce.on('transitionend', function() {
4012 ce.dom.style.height = '';
4013 ce.removeClass('collapsing');
4014 ce.addClass('collapse');
4015 }, this, { single: true} );
4035 * @class Roo.bootstrap.NavSimplebar
4036 * @extends Roo.bootstrap.Navbar
4037 * Bootstrap Sidebar class
4039 * @cfg {Boolean} inverse is inverted color
4041 * @cfg {String} type (nav | pills | tabs)
4042 * @cfg {Boolean} arrangement stacked | justified
4043 * @cfg {String} align (left | right) alignment
4045 * @cfg {Boolean} main (true|false) main nav bar? default false
4046 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
4048 * @cfg {String} tag (header|footer|nav|div) default is nav
4050 * @cfg {String} weight (light|primary|secondary|success|danger|warning|info|dark|white) default is light.
4054 * Create a new Sidebar
4055 * @param {Object} config The config object
4059 Roo.bootstrap.NavSimplebar = function(config){
4060 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
4063 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
4079 getAutoCreate : function(){
4083 tag : this.tag || 'div',
4084 cls : 'navbar roo-navbar-simple' //navbar-expand-lg ??
4086 if (['light','white'].indexOf(this.weight) > -1) {
4087 cfg.cls += ['light','white'].indexOf(this.weight) > -1 ? ' navbar-light' : ' navbar-dark';
4089 cfg.cls += ' bg-' + this.weight;
4092 cfg.cls += ' navbar-inverse';
4096 // i'm not actually sure these are really used - normally we add a navGroup to a navbar
4098 if (Roo.bootstrap.version == 4 && this.xtype == 'NavSimplebar') {
4107 cls: 'nav nav-' + this.xtype,
4113 this.type = this.type || 'nav';
4114 if (['tabs','pills'].indexOf(this.type) != -1) {
4115 cfg.cn[0].cls += ' nav-' + this.type
4119 if (this.type!=='nav') {
4120 Roo.log('nav type must be nav/tabs/pills')
4122 cfg.cn[0].cls += ' navbar-nav'
4128 if (['stacked','justified'].indexOf(this.arrangement) != -1) {
4129 cfg.cn[0].cls += ' nav-' + this.arrangement;
4133 if (this.align === 'right') {
4134 cfg.cn[0].cls += ' navbar-right';
4159 * navbar-expand-md fixed-top
4163 * @class Roo.bootstrap.NavHeaderbar
4164 * @extends Roo.bootstrap.NavSimplebar
4165 * Bootstrap Sidebar class
4167 * @cfg {String} brand what is brand
4168 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
4169 * @cfg {String} brand_href href of the brand
4170 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
4171 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
4172 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
4173 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
4176 * Create a new Sidebar
4177 * @param {Object} config The config object
4181 Roo.bootstrap.NavHeaderbar = function(config){
4182 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
4186 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
4193 desktopCenter : false,
4196 getAutoCreate : function(){
4199 tag: this.nav || 'nav',
4200 cls: 'navbar navbar-expand-md',
4206 if (this.desktopCenter) {
4207 cn.push({cls : 'container', cn : []});
4215 cls: 'navbar-toggle navbar-toggler',
4216 'data-toggle': 'collapse',
4221 html: 'Toggle navigation'
4225 cls: 'icon-bar navbar-toggler-icon'
4238 cn.push( Roo.bootstrap.version == 4 ? btn : {
4240 cls: 'navbar-header',
4249 cls: Roo.bootstrap.version == 4 ? 'nav flex-row roo-navbar-collapse' : 'collapse navbar-collapse roo-navbar-collapse',
4253 cfg.cls += this.inverse ? ' navbar-inverse navbar-dark bg-dark' : ' navbar-default';
4255 if (['light','white'].indexOf(this.weight) > -1) {
4256 cfg.cls += ['light','white'].indexOf(this.weight) > -1 ? ' navbar-light' : ' navbar-dark';
4258 cfg.cls += ' bg-' + this.weight;
4261 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
4262 cfg.cls += ' navbar-' + this.position + ' ' + this.position ;
4264 // tag can override this..
4266 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
4269 if (this.brand !== '') {
4270 var cp = Roo.bootstrap.version == 4 ? cn : cn[0].cn;
4271 cp.unshift({ // changed from push ?? BS4 needs it at the start? - does this break or exsiting?
4273 href: this.brand_href ? this.brand_href : '#',
4274 cls: 'navbar-brand',
4282 cfg.cls += ' main-nav';
4290 getHeaderChildContainer : function()
4292 if (this.srButton && this.el.select('.navbar-header').getCount()) {
4293 return this.el.select('.navbar-header',true).first();
4296 return this.getChildContainer();
4300 initEvents : function()
4302 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
4304 if (this.autohide) {
4309 Roo.get(document).on('scroll',function(e) {
4310 var ns = Roo.get(document).getScroll().top;
4311 var os = prevScroll;
4315 ft.removeClass('slideDown');
4316 ft.addClass('slideUp');
4319 ft.removeClass('slideUp');
4320 ft.addClass('slideDown');
4341 * @class Roo.bootstrap.NavSidebar
4342 * @extends Roo.bootstrap.Navbar
4343 * Bootstrap Sidebar class
4346 * Create a new Sidebar
4347 * @param {Object} config The config object
4351 Roo.bootstrap.NavSidebar = function(config){
4352 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
4355 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
4357 sidebar : true, // used by Navbar Item and NavbarGroup at present...
4359 getAutoCreate : function(){
4364 cls: 'sidebar sidebar-nav'
4386 * @class Roo.bootstrap.NavGroup
4387 * @extends Roo.bootstrap.Component
4388 * Bootstrap NavGroup class
4389 * @cfg {String} align (left|right)
4390 * @cfg {Boolean} inverse
4391 * @cfg {String} type (nav|pills|tab) default nav
4392 * @cfg {String} navId - reference Id for navbar.
4396 * Create a new nav group
4397 * @param {Object} config The config object
4400 Roo.bootstrap.NavGroup = function(config){
4401 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
4404 Roo.bootstrap.NavGroup.register(this);
4408 * Fires when the active item changes
4409 * @param {Roo.bootstrap.NavGroup} this
4410 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
4411 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
4418 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
4429 getAutoCreate : function()
4431 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
4437 if (Roo.bootstrap.version == 4) {
4438 if (['tabs','pills'].indexOf(this.type) != -1) {
4439 cfg.cls += ' nav-' + this.type;
4441 // trying to remove so header bar can right align top?
4442 if (this.parent() && this.parent().xtype != 'NavHeaderbar') {
4443 // do not use on header bar...
4444 cfg.cls += ' navbar-nav';
4449 if (['tabs','pills'].indexOf(this.type) != -1) {
4450 cfg.cls += ' nav-' + this.type
4452 if (this.type !== 'nav') {
4453 Roo.log('nav type must be nav/tabs/pills')
4455 cfg.cls += ' navbar-nav'
4459 if (this.parent() && this.parent().sidebar) {
4462 cls: 'dashboard-menu sidebar-menu'
4468 if (this.form === true) {
4471 cls: 'navbar-form form-inline'
4473 //nav navbar-right ml-md-auto
4474 if (this.align === 'right') {
4475 cfg.cls += ' navbar-right ml-md-auto';
4477 cfg.cls += ' navbar-left';
4481 if (this.align === 'right') {
4482 cfg.cls += ' navbar-right ml-md-auto';
4484 cfg.cls += ' mr-auto';
4488 cfg.cls += ' navbar-inverse';
4496 * sets the active Navigation item
4497 * @param {Roo.bootstrap.NavItem} the new current navitem
4499 setActiveItem : function(item)
4502 Roo.each(this.navItems, function(v){
4507 v.setActive(false, true);
4514 item.setActive(true, true);
4515 this.fireEvent('changed', this, item, prev);
4520 * gets the active Navigation item
4521 * @return {Roo.bootstrap.NavItem} the current navitem
4523 getActive : function()
4527 Roo.each(this.navItems, function(v){
4538 indexOfNav : function()
4542 Roo.each(this.navItems, function(v,i){
4553 * adds a Navigation item
4554 * @param {Roo.bootstrap.NavItem} the navitem to add
4556 addItem : function(cfg)
4558 if (this.form && Roo.bootstrap.version == 4) {
4561 var cn = new Roo.bootstrap.NavItem(cfg);
4563 cn.parentId = this.id;
4564 cn.onRender(this.el, null);
4568 * register a Navigation item
4569 * @param {Roo.bootstrap.NavItem} the navitem to add
4571 register : function(item)
4573 this.navItems.push( item);
4574 item.navId = this.navId;
4579 * clear all the Navigation item
4582 clearAll : function()
4585 this.el.dom.innerHTML = '';
4588 getNavItem: function(tabId)
4591 Roo.each(this.navItems, function(e) {
4592 if (e.tabId == tabId) {
4602 setActiveNext : function()
4604 var i = this.indexOfNav(this.getActive());
4605 if (i > this.navItems.length) {
4608 this.setActiveItem(this.navItems[i+1]);
4610 setActivePrev : function()
4612 var i = this.indexOfNav(this.getActive());
4616 this.setActiveItem(this.navItems[i-1]);
4618 clearWasActive : function(except) {
4619 Roo.each(this.navItems, function(e) {
4620 if (e.tabId != except.tabId && e.was_active) {
4621 e.was_active = false;
4628 getWasActive : function ()
4631 Roo.each(this.navItems, function(e) {
4646 Roo.apply(Roo.bootstrap.NavGroup, {
4650 * register a Navigation Group
4651 * @param {Roo.bootstrap.NavGroup} the navgroup to add
4653 register : function(navgrp)
4655 this.groups[navgrp.navId] = navgrp;
4659 * fetch a Navigation Group based on the navigation ID
4660 * @param {string} the navgroup to add
4661 * @returns {Roo.bootstrap.NavGroup} the navgroup
4663 get: function(navId) {
4664 if (typeof(this.groups[navId]) == 'undefined') {
4666 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
4668 return this.groups[navId] ;
4683 * @class Roo.bootstrap.NavItem
4684 * @extends Roo.bootstrap.Component
4685 * Bootstrap Navbar.NavItem class
4686 * @cfg {String} href link to
4687 * @cfg {String} button_weight (default | primary | secondary | success | info | warning | danger | link ) default none
4689 * @cfg {String} html content of button
4690 * @cfg {String} badge text inside badge
4691 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
4692 * @cfg {String} glyphicon DEPRICATED - use fa
4693 * @cfg {String} icon DEPRICATED - use fa
4694 * @cfg {String} fa - Fontawsome icon name (can add stuff to it like fa-2x)
4695 * @cfg {Boolean} active Is item active
4696 * @cfg {Boolean} disabled Is item disabled
4698 * @cfg {Boolean} preventDefault (true | false) default false
4699 * @cfg {String} tabId the tab that this item activates.
4700 * @cfg {String} tagtype (a|span) render as a href or span?
4701 * @cfg {Boolean} animateRef (true|false) link to element default false
4704 * Create a new Navbar Item
4705 * @param {Object} config The config object
4707 Roo.bootstrap.NavItem = function(config){
4708 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
4713 * The raw click event for the entire grid.
4714 * @param {Roo.EventObject} e
4719 * Fires when the active item active state changes
4720 * @param {Roo.bootstrap.NavItem} this
4721 * @param {boolean} state the new state
4727 * Fires when scroll to element
4728 * @param {Roo.bootstrap.NavItem} this
4729 * @param {Object} options
4730 * @param {Roo.EventObject} e
4738 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
4747 preventDefault : false,
4755 button_outline : false,
4759 getAutoCreate : function(){
4767 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
4769 if (this.disabled) {
4770 cfg.cls += ' disabled';
4774 if (this.button_weight.length) {
4775 cfg.tag = this.href ? 'a' : 'button';
4776 cfg.html = this.html || '';
4777 cfg.cls += ' btn btn' + (this.button_outline ? '-outline' : '') + '-' + this.button_weight;
4779 cfg.href = this.href;
4782 cfg.html = '<i class="fa fas fa-'+this.fa+'"></i> <span>' + this.html + '</span>';
4785 // menu .. should add dropdown-menu class - so no need for carat..
4787 if (this.badge !== '') {
4789 cfg.html += ' <span class="badge badge-secondary">' + this.badge + '</span>';
4794 if (this.href || this.html || this.glyphicon || this.icon || this.fa) {
4798 href : this.href || "#",
4799 html: this.html || ''
4802 if (this.tagtype == 'a') {
4803 cfg.cn[0].cls = 'nav-link';
4806 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>';
4809 cfg.cn[0].html = '<i class="fa fas fa-'+this.fa+'"></i> <span>' + cfg.cn[0].html + '</span>';
4811 if(this.glyphicon) {
4812 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
4817 cfg.cn[0].html += " <span class='caret'></span>";
4821 if (this.badge !== '') {
4823 cfg.cn[0].html += ' <span class="badge badge-secondary">' + this.badge + '</span>';
4831 onRender : function(ct, position)
4833 // Roo.log("Call onRender: " + this.xtype);
4834 if (Roo.bootstrap.version == 4 && ct.dom.type != 'ul') {
4838 var ret = Roo.bootstrap.NavItem.superclass.onRender.call(this, ct, position);
4839 this.navLink = this.el.select('.nav-link',true).first();
4844 initEvents: function()
4846 if (typeof (this.menu) != 'undefined') {
4847 this.menu.parentType = this.xtype;
4848 this.menu.triggerEl = this.el;
4849 this.menu = this.addxtype(Roo.apply({}, this.menu));
4852 this.el.select('a',true).on('click', this.onClick, this);
4854 if(this.tagtype == 'span'){
4855 this.el.select('span',true).on('click', this.onClick, this);
4858 // at this point parent should be available..
4859 this.parent().register(this);
4862 onClick : function(e)
4864 if (e.getTarget('.dropdown-menu-item')) {
4865 // did you click on a menu itemm.... - then don't trigger onclick..
4870 this.preventDefault ||
4873 Roo.log("NavItem - prevent Default?");
4877 if (this.disabled) {
4881 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4882 if (tg && tg.transition) {
4883 Roo.log("waiting for the transitionend");
4889 //Roo.log("fire event clicked");
4890 if(this.fireEvent('click', this, e) === false){
4894 if(this.tagtype == 'span'){
4898 //Roo.log(this.href);
4899 var ael = this.el.select('a',true).first();
4902 if(ael && this.animateRef && this.href.indexOf('#') > -1){
4903 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4904 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4905 return; // ignore... - it's a 'hash' to another page.
4907 Roo.log("NavItem - prevent Default?");
4909 this.scrollToElement(e);
4913 var p = this.parent();
4915 if (['tabs','pills'].indexOf(p.type)!==-1) {
4916 if (typeof(p.setActiveItem) !== 'undefined') {
4917 p.setActiveItem(this);
4921 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4922 if (p.parentType == 'NavHeaderbar' && !this.menu) {
4923 // remove the collapsed menu expand...
4924 p.parent().el.select('.roo-navbar-collapse',true).removeClass('in');
4928 isActive: function () {
4931 setActive : function(state, fire, is_was_active)
4933 if (this.active && !state && this.navId) {
4934 this.was_active = true;
4935 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4937 nv.clearWasActive(this);
4941 this.active = state;
4944 this.el.removeClass('active');
4945 this.navLink ? this.navLink.removeClass('active') : false;
4946 } else if (!this.el.hasClass('active')) {
4948 this.el.addClass('active');
4949 if (Roo.bootstrap.version == 4 && this.navLink ) {
4950 this.navLink.addClass('active');
4955 this.fireEvent('changed', this, state);
4958 // show a panel if it's registered and related..
4960 if (!this.navId || !this.tabId || !state || is_was_active) {
4964 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4968 var pan = tg.getPanelByName(this.tabId);
4972 // if we can not flip to new panel - go back to old nav highlight..
4973 if (false == tg.showPanel(pan)) {
4974 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4976 var onav = nv.getWasActive();
4978 onav.setActive(true, false, true);
4987 // this should not be here...
4988 setDisabled : function(state)
4990 this.disabled = state;
4992 this.el.removeClass('disabled');
4993 } else if (!this.el.hasClass('disabled')) {
4994 this.el.addClass('disabled');
5000 * Fetch the element to display the tooltip on.
5001 * @return {Roo.Element} defaults to this.el
5003 tooltipEl : function()
5005 return this.el.select('' + this.tagtype + '', true).first();
5008 scrollToElement : function(e)
5010 var c = document.body;
5013 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
5015 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
5016 c = document.documentElement;
5019 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
5025 var o = target.calcOffsetsTo(c);
5032 this.fireEvent('scrollto', this, options, e);
5034 Roo.get(c).scrollTo('top', options.value, true);
5047 * <span> icon </span>
5048 * <span> text </span>
5049 * <span>badge </span>
5053 * @class Roo.bootstrap.NavSidebarItem
5054 * @extends Roo.bootstrap.NavItem
5055 * Bootstrap Navbar.NavSidebarItem class
5056 * {String} badgeWeight (default|primary|success|info|warning|danger)the extra classes for the badge
5057 * {Boolean} open is the menu open
5058 * {Boolean} buttonView use button as the tigger el rather that a (default false)
5059 * {String} buttonWeight (default|primary|success|info|warning|danger)the extra classes for the button
5060 * {String} buttonSize (sm|md|lg)the extra classes for the button
5061 * {Boolean} showArrow show arrow next to the text (default true)
5063 * Create a new Navbar Button
5064 * @param {Object} config The config object
5066 Roo.bootstrap.NavSidebarItem = function(config){
5067 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
5072 * The raw click event for the entire grid.
5073 * @param {Roo.EventObject} e
5078 * Fires when the active item active state changes
5079 * @param {Roo.bootstrap.NavSidebarItem} this
5080 * @param {boolean} state the new state
5088 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
5090 badgeWeight : 'default',
5096 buttonWeight : 'default',
5102 getAutoCreate : function(){
5107 href : this.href || '#',
5113 if(this.buttonView){
5116 href : this.href || '#',
5117 cls: 'btn btn-' + this.buttonWeight + ' btn-' + this.buttonSize + 'roo-button-dropdown-toggle',
5130 cfg.cls += ' active';
5133 if (this.disabled) {
5134 cfg.cls += ' disabled';
5137 cfg.cls += ' open x-open';
5140 if (this.glyphicon || this.icon) {
5141 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
5142 a.cn.push({ tag : 'i', cls : c }) ;
5145 if(!this.buttonView){
5148 html : this.html || ''
5155 if (this.badge !== '') {
5156 a.cn.push({ tag: 'span', cls : 'badge pull-right badge-' + this.badgeWeight, html: this.badge });
5162 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
5165 a.cls += ' dropdown-toggle treeview' ;
5171 initEvents : function()
5173 if (typeof (this.menu) != 'undefined') {
5174 this.menu.parentType = this.xtype;
5175 this.menu.triggerEl = this.el;
5176 this.menu = this.addxtype(Roo.apply({}, this.menu));
5179 this.el.on('click', this.onClick, this);
5181 if(this.badge !== ''){
5182 this.badgeEl = this.el.select('.badge', true).first().setVisibilityMode(Roo.Element.DISPLAY);
5187 onClick : function(e)
5194 if(this.preventDefault){
5198 this.fireEvent('click', this, e);
5201 disable : function()
5203 this.setDisabled(true);
5208 this.setDisabled(false);
5211 setDisabled : function(state)
5213 if(this.disabled == state){
5217 this.disabled = state;
5220 this.el.addClass('disabled');
5224 this.el.removeClass('disabled');
5229 setActive : function(state)
5231 if(this.active == state){
5235 this.active = state;
5238 this.el.addClass('active');
5242 this.el.removeClass('active');
5247 isActive: function ()
5252 setBadge : function(str)
5258 this.badgeEl.dom.innerHTML = str;
5275 * @class Roo.bootstrap.Row
5276 * @extends Roo.bootstrap.Component
5277 * Bootstrap Row class (contains columns...)
5281 * @param {Object} config The config object
5284 Roo.bootstrap.Row = function(config){
5285 Roo.bootstrap.Row.superclass.constructor.call(this, config);
5288 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
5290 getAutoCreate : function(){
5309 * @class Roo.bootstrap.Element
5310 * @extends Roo.bootstrap.Component
5311 * Bootstrap Element class
5312 * @cfg {String} html contents of the element
5313 * @cfg {String} tag tag of the element
5314 * @cfg {String} cls class of the element
5315 * @cfg {Boolean} preventDefault (true|false) default false
5316 * @cfg {Boolean} clickable (true|false) default false
5319 * Create a new Element
5320 * @param {Object} config The config object
5323 Roo.bootstrap.Element = function(config){
5324 Roo.bootstrap.Element.superclass.constructor.call(this, config);
5330 * When a element is chick
5331 * @param {Roo.bootstrap.Element} this
5332 * @param {Roo.EventObject} e
5338 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
5343 preventDefault: false,
5346 getAutoCreate : function(){
5350 // cls: this.cls, double assign in parent class Component.js :: onRender
5357 initEvents: function()
5359 Roo.bootstrap.Element.superclass.initEvents.call(this);
5362 this.el.on('click', this.onClick, this);
5367 onClick : function(e)
5369 if(this.preventDefault){
5373 this.fireEvent('click', this, e);
5376 getValue : function()
5378 return this.el.dom.innerHTML;
5381 setValue : function(value)
5383 this.el.dom.innerHTML = value;
5398 * @class Roo.bootstrap.Pagination
5399 * @extends Roo.bootstrap.Component
5400 * Bootstrap Pagination class
5401 * @cfg {String} size xs | sm | md | lg
5402 * @cfg {Boolean} inverse false | true
5405 * Create a new Pagination
5406 * @param {Object} config The config object
5409 Roo.bootstrap.Pagination = function(config){
5410 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
5413 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
5419 getAutoCreate : function(){
5425 cfg.cls += ' inverse';
5431 cfg.cls += " " + this.cls;
5449 * @class Roo.bootstrap.PaginationItem
5450 * @extends Roo.bootstrap.Component
5451 * Bootstrap PaginationItem class
5452 * @cfg {String} html text
5453 * @cfg {String} href the link
5454 * @cfg {Boolean} preventDefault (true | false) default true
5455 * @cfg {Boolean} active (true | false) default false
5456 * @cfg {Boolean} disabled default false
5460 * Create a new PaginationItem
5461 * @param {Object} config The config object
5465 Roo.bootstrap.PaginationItem = function(config){
5466 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
5471 * The raw click event for the entire grid.
5472 * @param {Roo.EventObject} e
5478 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
5482 preventDefault: true,
5487 getAutoCreate : function(){
5493 href : this.href ? this.href : '#',
5494 html : this.html ? this.html : ''
5504 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
5508 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
5514 initEvents: function() {
5516 this.el.on('click', this.onClick, this);
5519 onClick : function(e)
5521 Roo.log('PaginationItem on click ');
5522 if(this.preventDefault){
5530 this.fireEvent('click', this, e);
5546 * @class Roo.bootstrap.Slider
5547 * @extends Roo.bootstrap.Component
5548 * Bootstrap Slider class
5551 * Create a new Slider
5552 * @param {Object} config The config object
5555 Roo.bootstrap.Slider = function(config){
5556 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
5559 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
5561 getAutoCreate : function(){
5565 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
5569 cls: 'ui-slider-handle ui-state-default ui-corner-all'
5581 * Ext JS Library 1.1.1
5582 * Copyright(c) 2006-2007, Ext JS, LLC.
5584 * Originally Released Under LGPL - original licence link has changed is not relivant.
5587 * <script type="text/javascript">
5592 * @class Roo.grid.ColumnModel
5593 * @extends Roo.util.Observable
5594 * This is the default implementation of a ColumnModel used by the Grid. It defines
5595 * the columns in the grid.
5598 var colModel = new Roo.grid.ColumnModel([
5599 {header: "Ticker", width: 60, sortable: true, locked: true},
5600 {header: "Company Name", width: 150, sortable: true},
5601 {header: "Market Cap.", width: 100, sortable: true},
5602 {header: "$ Sales", width: 100, sortable: true, renderer: money},
5603 {header: "Employees", width: 100, sortable: true, resizable: false}
5608 * The config options listed for this class are options which may appear in each
5609 * individual column definition.
5610 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
5612 * @param {Object} config An Array of column config objects. See this class's
5613 * config objects for details.
5615 Roo.grid.ColumnModel = function(config){
5617 * The config passed into the constructor
5619 this.config = config;
5622 // if no id, create one
5623 // if the column does not have a dataIndex mapping,
5624 // map it to the order it is in the config
5625 for(var i = 0, len = config.length; i < len; i++){
5627 if(typeof c.dataIndex == "undefined"){
5630 if(typeof c.renderer == "string"){
5631 c.renderer = Roo.util.Format[c.renderer];
5633 if(typeof c.id == "undefined"){
5636 if(c.editor && c.editor.xtype){
5637 c.editor = Roo.factory(c.editor, Roo.grid);
5639 if(c.editor && c.editor.isFormField){
5640 c.editor = new Roo.grid.GridEditor(c.editor);
5642 this.lookup[c.id] = c;
5646 * The width of columns which have no width specified (defaults to 100)
5649 this.defaultWidth = 100;
5652 * Default sortable of columns which have no sortable specified (defaults to false)
5655 this.defaultSortable = false;
5659 * @event widthchange
5660 * Fires when the width of a column changes.
5661 * @param {ColumnModel} this
5662 * @param {Number} columnIndex The column index
5663 * @param {Number} newWidth The new width
5665 "widthchange": true,
5667 * @event headerchange
5668 * Fires when the text of a header changes.
5669 * @param {ColumnModel} this
5670 * @param {Number} columnIndex The column index
5671 * @param {Number} newText The new header text
5673 "headerchange": true,
5675 * @event hiddenchange
5676 * Fires when a column is hidden or "unhidden".
5677 * @param {ColumnModel} this
5678 * @param {Number} columnIndex The column index
5679 * @param {Boolean} hidden true if hidden, false otherwise
5681 "hiddenchange": true,
5683 * @event columnmoved
5684 * Fires when a column is moved.
5685 * @param {ColumnModel} this
5686 * @param {Number} oldIndex
5687 * @param {Number} newIndex
5689 "columnmoved" : true,
5691 * @event columlockchange
5692 * Fires when a column's locked state is changed
5693 * @param {ColumnModel} this
5694 * @param {Number} colIndex
5695 * @param {Boolean} locked true if locked
5697 "columnlockchange" : true
5699 Roo.grid.ColumnModel.superclass.constructor.call(this);
5701 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
5703 * @cfg {String} header The header text to display in the Grid view.
5706 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
5707 * {@link Roo.data.Record} definition from which to draw the column's value. If not
5708 * specified, the column's index is used as an index into the Record's data Array.
5711 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
5712 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
5715 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
5716 * Defaults to the value of the {@link #defaultSortable} property.
5717 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
5720 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
5723 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
5726 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
5729 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
5732 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
5733 * given the cell's data value. See {@link #setRenderer}. If not specified, the
5734 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
5735 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
5738 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
5741 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
5744 * @cfg {String} valign (Optional) Set the CSS vertical-align property of the column (eg. middle, top, bottom etc). Defaults to undefined.
5747 * @cfg {String} cursor (Optional)
5750 * @cfg {String} tooltip (Optional)
5753 * @cfg {Number} xs (Optional)
5756 * @cfg {Number} sm (Optional)
5759 * @cfg {Number} md (Optional)
5762 * @cfg {Number} lg (Optional)
5765 * Returns the id of the column at the specified index.
5766 * @param {Number} index The column index
5767 * @return {String} the id
5769 getColumnId : function(index){
5770 return this.config[index].id;
5774 * Returns the column for a specified id.
5775 * @param {String} id The column id
5776 * @return {Object} the column
5778 getColumnById : function(id){
5779 return this.lookup[id];
5784 * Returns the column for a specified dataIndex.
5785 * @param {String} dataIndex The column dataIndex
5786 * @return {Object|Boolean} the column or false if not found
5788 getColumnByDataIndex: function(dataIndex){
5789 var index = this.findColumnIndex(dataIndex);
5790 return index > -1 ? this.config[index] : false;
5794 * Returns the index for a specified column id.
5795 * @param {String} id The column id
5796 * @return {Number} the index, or -1 if not found
5798 getIndexById : function(id){
5799 for(var i = 0, len = this.config.length; i < len; i++){
5800 if(this.config[i].id == id){
5808 * Returns the index for a specified column dataIndex.
5809 * @param {String} dataIndex The column dataIndex
5810 * @return {Number} the index, or -1 if not found
5813 findColumnIndex : function(dataIndex){
5814 for(var i = 0, len = this.config.length; i < len; i++){
5815 if(this.config[i].dataIndex == dataIndex){
5823 moveColumn : function(oldIndex, newIndex){
5824 var c = this.config[oldIndex];
5825 this.config.splice(oldIndex, 1);
5826 this.config.splice(newIndex, 0, c);
5827 this.dataMap = null;
5828 this.fireEvent("columnmoved", this, oldIndex, newIndex);
5831 isLocked : function(colIndex){
5832 return this.config[colIndex].locked === true;
5835 setLocked : function(colIndex, value, suppressEvent){
5836 if(this.isLocked(colIndex) == value){
5839 this.config[colIndex].locked = value;
5841 this.fireEvent("columnlockchange", this, colIndex, value);
5845 getTotalLockedWidth : function(){
5847 for(var i = 0; i < this.config.length; i++){
5848 if(this.isLocked(i) && !this.isHidden(i)){
5849 this.totalWidth += this.getColumnWidth(i);
5855 getLockedCount : function(){
5856 for(var i = 0, len = this.config.length; i < len; i++){
5857 if(!this.isLocked(i)){
5862 return this.config.length;
5866 * Returns the number of columns.
5869 getColumnCount : function(visibleOnly){
5870 if(visibleOnly === true){
5872 for(var i = 0, len = this.config.length; i < len; i++){
5873 if(!this.isHidden(i)){
5879 return this.config.length;
5883 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
5884 * @param {Function} fn
5885 * @param {Object} scope (optional)
5886 * @return {Array} result
5888 getColumnsBy : function(fn, scope){
5890 for(var i = 0, len = this.config.length; i < len; i++){
5891 var c = this.config[i];
5892 if(fn.call(scope||this, c, i) === true){
5900 * Returns true if the specified column is sortable.
5901 * @param {Number} col The column index
5904 isSortable : function(col){
5905 if(typeof this.config[col].sortable == "undefined"){
5906 return this.defaultSortable;
5908 return this.config[col].sortable;
5912 * Returns the rendering (formatting) function defined for the column.
5913 * @param {Number} col The column index.
5914 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
5916 getRenderer : function(col){
5917 if(!this.config[col].renderer){
5918 return Roo.grid.ColumnModel.defaultRenderer;
5920 return this.config[col].renderer;
5924 * Sets the rendering (formatting) function for a column.
5925 * @param {Number} col The column index
5926 * @param {Function} fn The function to use to process the cell's raw data
5927 * to return HTML markup for the grid view. The render function is called with
5928 * the following parameters:<ul>
5929 * <li>Data value.</li>
5930 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
5931 * <li>css A CSS style string to apply to the table cell.</li>
5932 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
5933 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
5934 * <li>Row index</li>
5935 * <li>Column index</li>
5936 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
5938 setRenderer : function(col, fn){
5939 this.config[col].renderer = fn;
5943 * Returns the width for the specified column.
5944 * @param {Number} col The column index
5947 getColumnWidth : function(col){
5948 return this.config[col].width * 1 || this.defaultWidth;
5952 * Sets the width for a column.
5953 * @param {Number} col The column index
5954 * @param {Number} width The new width
5956 setColumnWidth : function(col, width, suppressEvent){
5957 this.config[col].width = width;
5958 this.totalWidth = null;
5960 this.fireEvent("widthchange", this, col, width);
5965 * Returns the total width of all columns.
5966 * @param {Boolean} includeHidden True to include hidden column widths
5969 getTotalWidth : function(includeHidden){
5970 if(!this.totalWidth){
5971 this.totalWidth = 0;
5972 for(var i = 0, len = this.config.length; i < len; i++){
5973 if(includeHidden || !this.isHidden(i)){
5974 this.totalWidth += this.getColumnWidth(i);
5978 return this.totalWidth;
5982 * Returns the header for the specified column.
5983 * @param {Number} col The column index
5986 getColumnHeader : function(col){
5987 return this.config[col].header;
5991 * Sets the header for a column.
5992 * @param {Number} col The column index
5993 * @param {String} header The new header
5995 setColumnHeader : function(col, header){
5996 this.config[col].header = header;
5997 this.fireEvent("headerchange", this, col, header);
6001 * Returns the tooltip for the specified column.
6002 * @param {Number} col The column index
6005 getColumnTooltip : function(col){
6006 return this.config[col].tooltip;
6009 * Sets the tooltip for a column.
6010 * @param {Number} col The column index
6011 * @param {String} tooltip The new tooltip
6013 setColumnTooltip : function(col, tooltip){
6014 this.config[col].tooltip = tooltip;
6018 * Returns the dataIndex for the specified column.
6019 * @param {Number} col The column index
6022 getDataIndex : function(col){
6023 return this.config[col].dataIndex;
6027 * Sets the dataIndex for a column.
6028 * @param {Number} col The column index
6029 * @param {Number} dataIndex The new dataIndex
6031 setDataIndex : function(col, dataIndex){
6032 this.config[col].dataIndex = dataIndex;
6038 * Returns true if the cell is editable.
6039 * @param {Number} colIndex The column index
6040 * @param {Number} rowIndex The row index - this is nto actually used..?
6043 isCellEditable : function(colIndex, rowIndex){
6044 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
6048 * Returns the editor defined for the cell/column.
6049 * return false or null to disable editing.
6050 * @param {Number} colIndex The column index
6051 * @param {Number} rowIndex The row index
6054 getCellEditor : function(colIndex, rowIndex){
6055 return this.config[colIndex].editor;
6059 * Sets if a column is editable.
6060 * @param {Number} col The column index
6061 * @param {Boolean} editable True if the column is editable
6063 setEditable : function(col, editable){
6064 this.config[col].editable = editable;
6069 * Returns true if the column is hidden.
6070 * @param {Number} colIndex The column index
6073 isHidden : function(colIndex){
6074 return this.config[colIndex].hidden;
6079 * Returns true if the column width cannot be changed
6081 isFixed : function(colIndex){
6082 return this.config[colIndex].fixed;
6086 * Returns true if the column can be resized
6089 isResizable : function(colIndex){
6090 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
6093 * Sets if a column is hidden.
6094 * @param {Number} colIndex The column index
6095 * @param {Boolean} hidden True if the column is hidden
6097 setHidden : function(colIndex, hidden){
6098 this.config[colIndex].hidden = hidden;
6099 this.totalWidth = null;
6100 this.fireEvent("hiddenchange", this, colIndex, hidden);
6104 * Sets the editor for a column.
6105 * @param {Number} col The column index
6106 * @param {Object} editor The editor object
6108 setEditor : function(col, editor){
6109 this.config[col].editor = editor;
6113 Roo.grid.ColumnModel.defaultRenderer = function(value)
6115 if(typeof value == "object") {
6118 if(typeof value == "string" && value.length < 1){
6122 return String.format("{0}", value);
6125 // Alias for backwards compatibility
6126 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
6129 * Ext JS Library 1.1.1
6130 * Copyright(c) 2006-2007, Ext JS, LLC.
6132 * Originally Released Under LGPL - original licence link has changed is not relivant.
6135 * <script type="text/javascript">
6139 * @class Roo.LoadMask
6140 * A simple utility class for generically masking elements while loading data. If the element being masked has
6141 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
6142 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
6143 * element's UpdateManager load indicator and will be destroyed after the initial load.
6145 * Create a new LoadMask
6146 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
6147 * @param {Object} config The config object
6149 Roo.LoadMask = function(el, config){
6150 this.el = Roo.get(el);
6151 Roo.apply(this, config);
6153 this.store.on('beforeload', this.onBeforeLoad, this);
6154 this.store.on('load', this.onLoad, this);
6155 this.store.on('loadexception', this.onLoadException, this);
6156 this.removeMask = false;
6158 var um = this.el.getUpdateManager();
6159 um.showLoadIndicator = false; // disable the default indicator
6160 um.on('beforeupdate', this.onBeforeLoad, this);
6161 um.on('update', this.onLoad, this);
6162 um.on('failure', this.onLoad, this);
6163 this.removeMask = true;
6167 Roo.LoadMask.prototype = {
6169 * @cfg {Boolean} removeMask
6170 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
6171 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
6175 * The text to display in a centered loading message box (defaults to 'Loading...')
6179 * @cfg {String} msgCls
6180 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
6182 msgCls : 'x-mask-loading',
6185 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
6191 * Disables the mask to prevent it from being displayed
6193 disable : function(){
6194 this.disabled = true;
6198 * Enables the mask so that it can be displayed
6200 enable : function(){
6201 this.disabled = false;
6204 onLoadException : function()
6208 if (typeof(arguments[3]) != 'undefined') {
6209 Roo.MessageBox.alert("Error loading",arguments[3]);
6213 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
6214 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
6221 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
6226 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
6230 onBeforeLoad : function(){
6232 (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
6237 destroy : function(){
6239 this.store.un('beforeload', this.onBeforeLoad, this);
6240 this.store.un('load', this.onLoad, this);
6241 this.store.un('loadexception', this.onLoadException, this);
6243 var um = this.el.getUpdateManager();
6244 um.un('beforeupdate', this.onBeforeLoad, this);
6245 um.un('update', this.onLoad, this);
6246 um.un('failure', this.onLoad, this);
6257 * @class Roo.bootstrap.Table
6258 * @extends Roo.bootstrap.Component
6259 * Bootstrap Table class
6260 * @cfg {String} cls table class
6261 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
6262 * @cfg {String} bgcolor Specifies the background color for a table
6263 * @cfg {Number} border Specifies whether the table cells should have borders or not
6264 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
6265 * @cfg {Number} cellspacing Specifies the space between cells
6266 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
6267 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
6268 * @cfg {String} sortable Specifies that the table should be sortable
6269 * @cfg {String} summary Specifies a summary of the content of a table
6270 * @cfg {Number} width Specifies the width of a table
6271 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
6273 * @cfg {boolean} striped Should the rows be alternative striped
6274 * @cfg {boolean} bordered Add borders to the table
6275 * @cfg {boolean} hover Add hover highlighting
6276 * @cfg {boolean} condensed Format condensed
6277 * @cfg {boolean} responsive Format condensed
6278 * @cfg {Boolean} loadMask (true|false) default false
6279 * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
6280 * @cfg {Boolean} headerShow (true|false) generate thead, default true
6281 * @cfg {Boolean} rowSelection (true|false) default false
6282 * @cfg {Boolean} cellSelection (true|false) default false
6283 * @cfg {Boolean} scrollBody (true|false) default false - body scrolled / fixed header
6284 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
6285 * @cfg {Boolean} lazyLoad auto load data while scrolling to the end (default false)
6286 * @cfg {Boolean} auto_hide_footer auto hide footer if only one page (default false)
6290 * Create a new Table
6291 * @param {Object} config The config object
6294 Roo.bootstrap.Table = function(config){
6295 Roo.bootstrap.Table.superclass.constructor.call(this, config);
6300 this.rowSelection = (typeof(config.rowSelection) != 'undefined') ? config.rowSelection : this.rowSelection;
6301 this.cellSelection = (typeof(config.cellSelection) != 'undefined') ? config.cellSelection : this.cellSelection;
6302 this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
6303 this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
6305 this.sm = this.sm || {xtype: 'RowSelectionModel'};
6307 this.sm.grid = this;
6308 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
6309 this.sm = this.selModel;
6310 this.sm.xmodule = this.xmodule || false;
6313 if (this.cm && typeof(this.cm.config) == 'undefined') {
6314 this.colModel = new Roo.grid.ColumnModel(this.cm);
6315 this.cm = this.colModel;
6316 this.cm.xmodule = this.xmodule || false;
6319 this.store= Roo.factory(this.store, Roo.data);
6320 this.ds = this.store;
6321 this.ds.xmodule = this.xmodule || false;
6324 if (this.footer && this.store) {
6325 this.footer.dataSource = this.ds;
6326 this.footer = Roo.factory(this.footer);
6333 * Fires when a cell is clicked
6334 * @param {Roo.bootstrap.Table} this
6335 * @param {Roo.Element} el
6336 * @param {Number} rowIndex
6337 * @param {Number} columnIndex
6338 * @param {Roo.EventObject} e
6342 * @event celldblclick
6343 * Fires when a cell is double clicked
6344 * @param {Roo.bootstrap.Table} this
6345 * @param {Roo.Element} el
6346 * @param {Number} rowIndex
6347 * @param {Number} columnIndex
6348 * @param {Roo.EventObject} e
6350 "celldblclick" : true,
6353 * Fires when a row is clicked
6354 * @param {Roo.bootstrap.Table} this
6355 * @param {Roo.Element} el
6356 * @param {Number} rowIndex
6357 * @param {Roo.EventObject} e
6361 * @event rowdblclick
6362 * Fires when a row is double clicked
6363 * @param {Roo.bootstrap.Table} this
6364 * @param {Roo.Element} el
6365 * @param {Number} rowIndex
6366 * @param {Roo.EventObject} e
6368 "rowdblclick" : true,
6371 * Fires when a mouseover occur
6372 * @param {Roo.bootstrap.Table} this
6373 * @param {Roo.Element} el
6374 * @param {Number} rowIndex
6375 * @param {Number} columnIndex
6376 * @param {Roo.EventObject} e
6381 * Fires when a mouseout occur
6382 * @param {Roo.bootstrap.Table} this
6383 * @param {Roo.Element} el
6384 * @param {Number} rowIndex
6385 * @param {Number} columnIndex
6386 * @param {Roo.EventObject} e
6391 * Fires when a row is rendered, so you can change add a style to it.
6392 * @param {Roo.bootstrap.Table} this
6393 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
6397 * @event rowsrendered
6398 * Fires when all the rows have been rendered
6399 * @param {Roo.bootstrap.Table} this
6401 'rowsrendered' : true,
6403 * @event contextmenu
6404 * The raw contextmenu event for the entire grid.
6405 * @param {Roo.EventObject} e
6407 "contextmenu" : true,
6409 * @event rowcontextmenu
6410 * Fires when a row is right clicked
6411 * @param {Roo.bootstrap.Table} this
6412 * @param {Number} rowIndex
6413 * @param {Roo.EventObject} e
6415 "rowcontextmenu" : true,
6417 * @event cellcontextmenu
6418 * Fires when a cell is right clicked
6419 * @param {Roo.bootstrap.Table} this
6420 * @param {Number} rowIndex
6421 * @param {Number} cellIndex
6422 * @param {Roo.EventObject} e
6424 "cellcontextmenu" : true,
6426 * @event headercontextmenu
6427 * Fires when a header is right clicked
6428 * @param {Roo.bootstrap.Table} this
6429 * @param {Number} columnIndex
6430 * @param {Roo.EventObject} e
6432 "headercontextmenu" : true
6436 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
6462 rowSelection : false,
6463 cellSelection : false,
6466 // Roo.Element - the tbody
6468 // Roo.Element - thead element
6471 container: false, // used by gridpanel...
6477 auto_hide_footer : false,
6479 getAutoCreate : function()
6481 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
6488 if (this.scrollBody) {
6489 cfg.cls += ' table-body-fixed';
6492 cfg.cls += ' table-striped';
6496 cfg.cls += ' table-hover';
6498 if (this.bordered) {
6499 cfg.cls += ' table-bordered';
6501 if (this.condensed) {
6502 cfg.cls += ' table-condensed';
6504 if (this.responsive) {
6505 cfg.cls += ' table-responsive';
6509 cfg.cls+= ' ' +this.cls;
6512 // this lot should be simplifed...
6525 ].forEach(function(k) {
6533 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
6536 if(this.store || this.cm){
6537 if(this.headerShow){
6538 cfg.cn.push(this.renderHeader());
6541 cfg.cn.push(this.renderBody());
6543 if(this.footerShow){
6544 cfg.cn.push(this.renderFooter());
6546 // where does this come from?
6547 //cfg.cls+= ' TableGrid';
6550 return { cn : [ cfg ] };
6553 initEvents : function()
6555 if(!this.store || !this.cm){
6558 if (this.selModel) {
6559 this.selModel.initEvents();
6563 //Roo.log('initEvents with ds!!!!');
6565 this.mainBody = this.el.select('tbody', true).first();
6566 this.mainHead = this.el.select('thead', true).first();
6567 this.mainFoot = this.el.select('tfoot', true).first();
6573 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6574 e.on('click', _this.sort, _this);
6577 this.mainBody.on("click", this.onClick, this);
6578 this.mainBody.on("dblclick", this.onDblClick, this);
6580 // why is this done????? = it breaks dialogs??
6581 //this.parent().el.setStyle('position', 'relative');
6585 this.footer.parentId = this.id;
6586 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
6589 this.el.select('tfoot tr td').first().addClass('hide');
6594 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
6597 this.store.on('load', this.onLoad, this);
6598 this.store.on('beforeload', this.onBeforeLoad, this);
6599 this.store.on('update', this.onUpdate, this);
6600 this.store.on('add', this.onAdd, this);
6601 this.store.on("clear", this.clear, this);
6603 this.el.on("contextmenu", this.onContextMenu, this);
6605 this.mainBody.on('scroll', this.onBodyScroll, this);
6607 this.cm.on("headerchange", this.onHeaderChange, this);
6609 this.cm.on("hiddenchange", this.onHiddenChange, this, arguments);
6613 onContextMenu : function(e, t)
6615 this.processEvent("contextmenu", e);
6618 processEvent : function(name, e)
6620 if (name != 'touchstart' ) {
6621 this.fireEvent(name, e);
6624 var t = e.getTarget();
6626 var cell = Roo.get(t);
6632 if(cell.findParent('tfoot', false, true)){
6636 if(cell.findParent('thead', false, true)){
6638 if(e.getTarget().nodeName.toLowerCase() != 'th'){
6639 cell = Roo.get(t).findParent('th', false, true);
6641 Roo.log("failed to find th in thead?");
6642 Roo.log(e.getTarget());
6647 var cellIndex = cell.dom.cellIndex;
6649 var ename = name == 'touchstart' ? 'click' : name;
6650 this.fireEvent("header" + ename, this, cellIndex, e);
6655 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6656 cell = Roo.get(t).findParent('td', false, true);
6658 Roo.log("failed to find th in tbody?");
6659 Roo.log(e.getTarget());
6664 var row = cell.findParent('tr', false, true);
6665 var cellIndex = cell.dom.cellIndex;
6666 var rowIndex = row.dom.rowIndex - 1;
6670 this.fireEvent("row" + name, this, rowIndex, e);
6674 this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
6680 onMouseover : function(e, el)
6682 var cell = Roo.get(el);
6688 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6689 cell = cell.findParent('td', false, true);
6692 var row = cell.findParent('tr', false, true);
6693 var cellIndex = cell.dom.cellIndex;
6694 var rowIndex = row.dom.rowIndex - 1; // start from 0
6696 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
6700 onMouseout : function(e, el)
6702 var cell = Roo.get(el);
6708 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6709 cell = cell.findParent('td', false, true);
6712 var row = cell.findParent('tr', false, true);
6713 var cellIndex = cell.dom.cellIndex;
6714 var rowIndex = row.dom.rowIndex - 1; // start from 0
6716 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
6720 onClick : function(e, el)
6722 var cell = Roo.get(el);
6724 if(!cell || (!this.cellSelection && !this.rowSelection)){
6728 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6729 cell = cell.findParent('td', false, true);
6732 if(!cell || typeof(cell) == 'undefined'){
6736 var row = cell.findParent('tr', false, true);
6738 if(!row || typeof(row) == 'undefined'){
6742 var cellIndex = cell.dom.cellIndex;
6743 var rowIndex = this.getRowIndex(row);
6745 // why??? - should these not be based on SelectionModel?
6746 if(this.cellSelection){
6747 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
6750 if(this.rowSelection){
6751 this.fireEvent('rowclick', this, row, rowIndex, e);
6757 onDblClick : function(e,el)
6759 var cell = Roo.get(el);
6761 if(!cell || (!this.cellSelection && !this.rowSelection)){
6765 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6766 cell = cell.findParent('td', false, true);
6769 if(!cell || typeof(cell) == 'undefined'){
6773 var row = cell.findParent('tr', false, true);
6775 if(!row || typeof(row) == 'undefined'){
6779 var cellIndex = cell.dom.cellIndex;
6780 var rowIndex = this.getRowIndex(row);
6782 if(this.cellSelection){
6783 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
6786 if(this.rowSelection){
6787 this.fireEvent('rowdblclick', this, row, rowIndex, e);
6791 sort : function(e,el)
6793 var col = Roo.get(el);
6795 if(!col.hasClass('sortable')){
6799 var sort = col.attr('sort');
6802 if(col.select('i', true).first().hasClass('glyphicon-arrow-up')){
6806 this.store.sortInfo = {field : sort, direction : dir};
6809 Roo.log("calling footer first");
6810 this.footer.onClick('first');
6813 this.store.load({ params : { start : 0 } });
6817 renderHeader : function()
6825 this.totalWidth = 0;
6827 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6829 var config = cm.config[i];
6833 cls : 'x-hcol-' + i,
6835 html: cm.getColumnHeader(i)
6840 if(typeof(config.sortable) != 'undefined' && config.sortable){
6842 c.html = '<i class="glyphicon"></i>' + c.html;
6845 // could use BS4 hidden-..-down
6847 if(typeof(config.lgHeader) != 'undefined'){
6848 hh += '<span class="hidden-xs hidden-sm hidden-md ">' + config.lgHeader + '</span>';
6851 if(typeof(config.mdHeader) != 'undefined'){
6852 hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
6855 if(typeof(config.smHeader) != 'undefined'){
6856 hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
6859 if(typeof(config.xsHeader) != 'undefined'){
6860 hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
6867 if(typeof(config.tooltip) != 'undefined'){
6868 c.tooltip = config.tooltip;
6871 if(typeof(config.colspan) != 'undefined'){
6872 c.colspan = config.colspan;
6875 if(typeof(config.hidden) != 'undefined' && config.hidden){
6876 c.style += ' display:none;';
6879 if(typeof(config.dataIndex) != 'undefined'){
6880 c.sort = config.dataIndex;
6885 if(typeof(config.align) != 'undefined' && config.align.length){
6886 c.style += ' text-align:' + config.align + ';';
6889 if(typeof(config.width) != 'undefined'){
6890 c.style += ' width:' + config.width + 'px;';
6891 this.totalWidth += config.width;
6893 this.totalWidth += 100; // assume minimum of 100 per column?
6896 if(typeof(config.cls) != 'undefined'){
6897 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
6900 ['xs','sm','md','lg'].map(function(size){
6902 if(typeof(config[size]) == 'undefined'){
6906 if (!config[size]) { // 0 = hidden
6907 // BS 4 '0' is treated as hide that column and below.
6908 c.cls += ' hidden-' + size + ' hidden' + size + '-down';
6912 c.cls += ' col-' + size + '-' + config[size] + (
6913 size == 'xs' ? (' col-' + config[size] ) : '' // bs4 col-{num} replaces col-xs
6925 renderBody : function()
6935 colspan : this.cm.getColumnCount()
6945 renderFooter : function()
6955 colspan : this.cm.getColumnCount()
6969 // Roo.log('ds onload');
6974 var ds = this.store;
6976 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6977 e.select('i', true).removeClass(['glyphicon-arrow-up', 'glyphicon-arrow-down']);
6978 if (_this.store.sortInfo) {
6980 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
6981 e.select('i', true).addClass(['glyphicon-arrow-up']);
6984 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
6985 e.select('i', true).addClass(['glyphicon-arrow-down']);
6990 var tbody = this.mainBody;
6992 if(ds.getCount() > 0){
6993 ds.data.each(function(d,rowIndex){
6994 var row = this.renderRow(cm, ds, rowIndex);
6996 tbody.createChild(row);
7000 if(row.cellObjects.length){
7001 Roo.each(row.cellObjects, function(r){
7002 _this.renderCellObject(r);
7009 var tfoot = this.el.select('tfoot', true).first();
7011 if(this.footerShow && this.auto_hide_footer && this.mainFoot){
7013 this.mainFoot.setVisibilityMode(Roo.Element.DISPLAY).hide();
7015 var total = this.ds.getTotalCount();
7017 if(this.footer.pageSize < total){
7018 this.mainFoot.show();
7022 Roo.each(this.el.select('tbody td', true).elements, function(e){
7023 e.on('mouseover', _this.onMouseover, _this);
7026 Roo.each(this.el.select('tbody td', true).elements, function(e){
7027 e.on('mouseout', _this.onMouseout, _this);
7029 this.fireEvent('rowsrendered', this);
7035 onUpdate : function(ds,record)
7037 this.refreshRow(record);
7041 onRemove : function(ds, record, index, isUpdate){
7042 if(isUpdate !== true){
7043 this.fireEvent("beforerowremoved", this, index, record);
7045 var bt = this.mainBody.dom;
7047 var rows = this.el.select('tbody > tr', true).elements;
7049 if(typeof(rows[index]) != 'undefined'){
7050 bt.removeChild(rows[index].dom);
7053 // if(bt.rows[index]){
7054 // bt.removeChild(bt.rows[index]);
7057 if(isUpdate !== true){
7058 //this.stripeRows(index);
7059 //this.syncRowHeights(index, index);
7061 this.fireEvent("rowremoved", this, index, record);
7065 onAdd : function(ds, records, rowIndex)
7067 //Roo.log('on Add called');
7068 // - note this does not handle multiple adding very well..
7069 var bt = this.mainBody.dom;
7070 for (var i =0 ; i < records.length;i++) {
7071 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
7072 //Roo.log(records[i]);
7073 //Roo.log(this.store.getAt(rowIndex+i));
7074 this.insertRow(this.store, rowIndex + i, false);
7081 refreshRow : function(record){
7082 var ds = this.store, index;
7083 if(typeof record == 'number'){
7085 record = ds.getAt(index);
7087 index = ds.indexOf(record);
7089 this.insertRow(ds, index, true);
7091 this.onRemove(ds, record, index+1, true);
7093 //this.syncRowHeights(index, index);
7095 this.fireEvent("rowupdated", this, index, record);
7098 insertRow : function(dm, rowIndex, isUpdate){
7101 this.fireEvent("beforerowsinserted", this, rowIndex);
7103 //var s = this.getScrollState();
7104 var row = this.renderRow(this.cm, this.store, rowIndex);
7105 // insert before rowIndex..
7106 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
7110 if(row.cellObjects.length){
7111 Roo.each(row.cellObjects, function(r){
7112 _this.renderCellObject(r);
7117 this.fireEvent("rowsinserted", this, rowIndex);
7118 //this.syncRowHeights(firstRow, lastRow);
7119 //this.stripeRows(firstRow);
7126 getRowDom : function(rowIndex)
7128 var rows = this.el.select('tbody > tr', true).elements;
7130 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
7133 // returns the object tree for a tr..
7136 renderRow : function(cm, ds, rowIndex)
7138 var d = ds.getAt(rowIndex);
7142 cls : 'x-row-' + rowIndex,
7146 var cellObjects = [];
7148 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
7149 var config = cm.config[i];
7151 var renderer = cm.getRenderer(i);
7155 if(typeof(renderer) !== 'undefined'){
7156 value = renderer(d.data[cm.getDataIndex(i)], false, d);
7158 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
7159 // and are rendered into the cells after the row is rendered - using the id for the element.
7161 if(typeof(value) === 'object'){
7171 rowIndex : rowIndex,
7176 this.fireEvent('rowclass', this, rowcfg);
7180 cls : rowcfg.rowClass + ' x-col-' + i,
7182 html: (typeof(value) === 'object') ? '' : value
7189 if(typeof(config.colspan) != 'undefined'){
7190 td.colspan = config.colspan;
7193 if(typeof(config.hidden) != 'undefined' && config.hidden){
7194 td.style += ' display:none;';
7197 if(typeof(config.align) != 'undefined' && config.align.length){
7198 td.style += ' text-align:' + config.align + ';';
7200 if(typeof(config.valign) != 'undefined' && config.valign.length){
7201 td.style += ' vertical-align:' + config.valign + ';';
7204 if(typeof(config.width) != 'undefined'){
7205 td.style += ' width:' + config.width + 'px;';
7208 if(typeof(config.cursor) != 'undefined'){
7209 td.style += ' cursor:' + config.cursor + ';';
7212 if(typeof(config.cls) != 'undefined'){
7213 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
7216 ['xs','sm','md','lg'].map(function(size){
7218 if(typeof(config[size]) == 'undefined'){
7224 if (!config[size]) { // 0 = hidden
7225 // BS 4 '0' is treated as hide that column and below.
7226 td.cls += ' hidden-' + size + ' hidden' + size + '-down';
7230 td.cls += ' col-' + size + '-' + config[size] + (
7231 size == 'xs' ? (' col-' + config[size] ) : '' // bs4 col-{num} replaces col-xs
7241 row.cellObjects = cellObjects;
7249 onBeforeLoad : function()
7258 this.el.select('tbody', true).first().dom.innerHTML = '';
7261 * Show or hide a row.
7262 * @param {Number} rowIndex to show or hide
7263 * @param {Boolean} state hide
7265 setRowVisibility : function(rowIndex, state)
7267 var bt = this.mainBody.dom;
7269 var rows = this.el.select('tbody > tr', true).elements;
7271 if(typeof(rows[rowIndex]) == 'undefined'){
7274 rows[rowIndex].dom.style.display = state ? '' : 'none';
7278 getSelectionModel : function(){
7280 this.selModel = new Roo.bootstrap.Table.RowSelectionModel({grid: this});
7282 return this.selModel;
7285 * Render the Roo.bootstrap object from renderder
7287 renderCellObject : function(r)
7291 r.cfg.parentId = (typeof(r.container) == 'string') ? r.container : r.container.id;
7293 var t = r.cfg.render(r.container);
7296 Roo.each(r.cfg.cn, function(c){
7298 container: t.getChildContainer(),
7301 _this.renderCellObject(child);
7306 getRowIndex : function(row)
7310 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
7321 * Returns the grid's underlying element = used by panel.Grid
7322 * @return {Element} The element
7324 getGridEl : function(){
7328 * Forces a resize - used by panel.Grid
7329 * @return {Element} The element
7331 autoSize : function()
7333 //var ctr = Roo.get(this.container.dom.parentElement);
7334 var ctr = Roo.get(this.el.dom);
7336 var thd = this.getGridEl().select('thead',true).first();
7337 var tbd = this.getGridEl().select('tbody', true).first();
7338 var tfd = this.getGridEl().select('tfoot', true).first();
7340 var cw = ctr.getWidth();
7344 tbd.setSize(ctr.getWidth(),
7345 ctr.getHeight() - ((thd ? thd.getHeight() : 0) + (tfd ? tfd.getHeight() : 0))
7347 var barsize = (tbd.dom.offsetWidth - tbd.dom.clientWidth);
7350 cw = Math.max(cw, this.totalWidth);
7351 this.getGridEl().select('tr',true).setWidth(cw);
7352 // resize 'expandable coloumn?
7354 return; // we doe not have a view in this design..
7357 onBodyScroll: function()
7359 //Roo.log("body scrolled');" + this.mainBody.dom.scrollLeft);
7361 this.mainHead.setStyle({
7362 'position' : 'relative',
7363 'left': (-1* this.mainBody.dom.scrollLeft) + 'px'
7369 var scrollHeight = this.mainBody.dom.scrollHeight;
7371 var scrollTop = Math.ceil(this.mainBody.getScroll().top);
7373 var height = this.mainBody.getHeight();
7375 if(scrollHeight - height == scrollTop) {
7377 var total = this.ds.getTotalCount();
7379 if(this.footer.cursor + this.footer.pageSize < total){
7381 this.footer.ds.load({
7383 start : this.footer.cursor + this.footer.pageSize,
7384 limit : this.footer.pageSize
7394 onHeaderChange : function()
7396 var header = this.renderHeader();
7397 var table = this.el.select('table', true).first();
7399 this.mainHead.remove();
7400 this.mainHead = table.createChild(header, this.mainBody, false);
7403 onHiddenChange : function(colModel, colIndex, hidden)
7405 var thSelector = '#' + this.id + ' .x-hcol-' + colIndex;
7406 var tdSelector = '#' + this.id + ' .x-col-' + colIndex;
7408 this.CSS.updateRule(thSelector, "display", "");
7409 this.CSS.updateRule(tdSelector, "display", "");
7412 this.CSS.updateRule(thSelector, "display", "none");
7413 this.CSS.updateRule(tdSelector, "display", "none");
7416 this.onHeaderChange();
7420 setColumnWidth: function(col_index, width)
7422 // width = "md-2 xs-2..."
7423 if(!this.colModel.config[col_index]) {
7427 var w = width.split(" ");
7429 var rows = this.el.dom.getElementsByClassName("x-col-"+col_index);
7431 var h_row = this.el.dom.getElementsByClassName("x-hcol-"+col_index);
7434 for(var j = 0; j < w.length; j++) {
7440 var size_cls = w[j].split("-");
7442 if(!Number.isInteger(size_cls[1] * 1)) {
7446 if(!this.colModel.config[col_index][size_cls[0]]) {
7450 if(!h_row[0].classList.contains("col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]])) {
7454 h_row[0].classList.replace(
7455 "col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]],
7456 "col-"+size_cls[0]+"-"+size_cls[1]
7459 for(var i = 0; i < rows.length; i++) {
7461 var size_cls = w[j].split("-");
7463 if(!Number.isInteger(size_cls[1] * 1)) {
7467 if(!this.colModel.config[col_index][size_cls[0]]) {
7471 if(!rows[i].classList.contains("col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]])) {
7475 rows[i].classList.replace(
7476 "col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]],
7477 "col-"+size_cls[0]+"-"+size_cls[1]
7481 this.colModel.config[col_index][size_cls[0]] = size_cls[1];
7496 * @class Roo.bootstrap.TableCell
7497 * @extends Roo.bootstrap.Component
7498 * Bootstrap TableCell class
7499 * @cfg {String} html cell contain text
7500 * @cfg {String} cls cell class
7501 * @cfg {String} tag cell tag (td|th) default td
7502 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
7503 * @cfg {String} align Aligns the content in a cell
7504 * @cfg {String} axis Categorizes cells
7505 * @cfg {String} bgcolor Specifies the background color of a cell
7506 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7507 * @cfg {Number} colspan Specifies the number of columns a cell should span
7508 * @cfg {String} headers Specifies one or more header cells a cell is related to
7509 * @cfg {Number} height Sets the height of a cell
7510 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
7511 * @cfg {Number} rowspan Sets the number of rows a cell should span
7512 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
7513 * @cfg {String} valign Vertical aligns the content in a cell
7514 * @cfg {Number} width Specifies the width of a cell
7517 * Create a new TableCell
7518 * @param {Object} config The config object
7521 Roo.bootstrap.TableCell = function(config){
7522 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
7525 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
7545 getAutoCreate : function(){
7546 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
7566 cfg.align=this.align
7572 cfg.bgcolor=this.bgcolor
7575 cfg.charoff=this.charoff
7578 cfg.colspan=this.colspan
7581 cfg.headers=this.headers
7584 cfg.height=this.height
7587 cfg.nowrap=this.nowrap
7590 cfg.rowspan=this.rowspan
7593 cfg.scope=this.scope
7596 cfg.valign=this.valign
7599 cfg.width=this.width
7618 * @class Roo.bootstrap.TableRow
7619 * @extends Roo.bootstrap.Component
7620 * Bootstrap TableRow class
7621 * @cfg {String} cls row class
7622 * @cfg {String} align Aligns the content in a table row
7623 * @cfg {String} bgcolor Specifies a background color for a table row
7624 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7625 * @cfg {String} valign Vertical aligns the content in a table row
7628 * Create a new TableRow
7629 * @param {Object} config The config object
7632 Roo.bootstrap.TableRow = function(config){
7633 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
7636 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
7644 getAutoCreate : function(){
7645 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
7655 cfg.align = this.align;
7658 cfg.bgcolor = this.bgcolor;
7661 cfg.charoff = this.charoff;
7664 cfg.valign = this.valign;
7682 * @class Roo.bootstrap.TableBody
7683 * @extends Roo.bootstrap.Component
7684 * Bootstrap TableBody class
7685 * @cfg {String} cls element class
7686 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
7687 * @cfg {String} align Aligns the content inside the element
7688 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
7689 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
7692 * Create a new TableBody
7693 * @param {Object} config The config object
7696 Roo.bootstrap.TableBody = function(config){
7697 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
7700 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
7708 getAutoCreate : function(){
7709 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
7723 cfg.align = this.align;
7726 cfg.charoff = this.charoff;
7729 cfg.valign = this.valign;
7736 // initEvents : function()
7743 // this.store = Roo.factory(this.store, Roo.data);
7744 // this.store.on('load', this.onLoad, this);
7746 // this.store.load();
7750 // onLoad: function ()
7752 // this.fireEvent('load', this);
7762 * Ext JS Library 1.1.1
7763 * Copyright(c) 2006-2007, Ext JS, LLC.
7765 * Originally Released Under LGPL - original licence link has changed is not relivant.
7768 * <script type="text/javascript">
7771 // as we use this in bootstrap.
7772 Roo.namespace('Roo.form');
7774 * @class Roo.form.Action
7775 * Internal Class used to handle form actions
7777 * @param {Roo.form.BasicForm} el The form element or its id
7778 * @param {Object} config Configuration options
7783 // define the action interface
7784 Roo.form.Action = function(form, options){
7786 this.options = options || {};
7789 * Client Validation Failed
7792 Roo.form.Action.CLIENT_INVALID = 'client';
7794 * Server Validation Failed
7797 Roo.form.Action.SERVER_INVALID = 'server';
7799 * Connect to Server Failed
7802 Roo.form.Action.CONNECT_FAILURE = 'connect';
7804 * Reading Data from Server Failed
7807 Roo.form.Action.LOAD_FAILURE = 'load';
7809 Roo.form.Action.prototype = {
7811 failureType : undefined,
7812 response : undefined,
7816 run : function(options){
7821 success : function(response){
7826 handleResponse : function(response){
7830 // default connection failure
7831 failure : function(response){
7833 this.response = response;
7834 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7835 this.form.afterAction(this, false);
7838 processResponse : function(response){
7839 this.response = response;
7840 if(!response.responseText){
7843 this.result = this.handleResponse(response);
7847 // utility functions used internally
7848 getUrl : function(appendParams){
7849 var url = this.options.url || this.form.url || this.form.el.dom.action;
7851 var p = this.getParams();
7853 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
7859 getMethod : function(){
7860 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
7863 getParams : function(){
7864 var bp = this.form.baseParams;
7865 var p = this.options.params;
7867 if(typeof p == "object"){
7868 p = Roo.urlEncode(Roo.applyIf(p, bp));
7869 }else if(typeof p == 'string' && bp){
7870 p += '&' + Roo.urlEncode(bp);
7873 p = Roo.urlEncode(bp);
7878 createCallback : function(){
7880 success: this.success,
7881 failure: this.failure,
7883 timeout: (this.form.timeout*1000),
7884 upload: this.form.fileUpload ? this.success : undefined
7889 Roo.form.Action.Submit = function(form, options){
7890 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
7893 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
7896 haveProgress : false,
7897 uploadComplete : false,
7899 // uploadProgress indicator.
7900 uploadProgress : function()
7902 if (!this.form.progressUrl) {
7906 if (!this.haveProgress) {
7907 Roo.MessageBox.progress("Uploading", "Uploading");
7909 if (this.uploadComplete) {
7910 Roo.MessageBox.hide();
7914 this.haveProgress = true;
7916 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
7918 var c = new Roo.data.Connection();
7920 url : this.form.progressUrl,
7925 success : function(req){
7926 //console.log(data);
7930 rdata = Roo.decode(req.responseText)
7932 Roo.log("Invalid data from server..");
7936 if (!rdata || !rdata.success) {
7938 Roo.MessageBox.alert(Roo.encode(rdata));
7941 var data = rdata.data;
7943 if (this.uploadComplete) {
7944 Roo.MessageBox.hide();
7949 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
7950 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
7953 this.uploadProgress.defer(2000,this);
7956 failure: function(data) {
7957 Roo.log('progress url failed ');
7968 // run get Values on the form, so it syncs any secondary forms.
7969 this.form.getValues();
7971 var o = this.options;
7972 var method = this.getMethod();
7973 var isPost = method == 'POST';
7974 if(o.clientValidation === false || this.form.isValid()){
7976 if (this.form.progressUrl) {
7977 this.form.findField('UPLOAD_IDENTIFIER').setValue(
7978 (new Date() * 1) + '' + Math.random());
7983 Roo.Ajax.request(Roo.apply(this.createCallback(), {
7984 form:this.form.el.dom,
7985 url:this.getUrl(!isPost),
7987 params:isPost ? this.getParams() : null,
7988 isUpload: this.form.fileUpload,
7989 formData : this.form.formData
7992 this.uploadProgress();
7994 }else if (o.clientValidation !== false){ // client validation failed
7995 this.failureType = Roo.form.Action.CLIENT_INVALID;
7996 this.form.afterAction(this, false);
8000 success : function(response)
8002 this.uploadComplete= true;
8003 if (this.haveProgress) {
8004 Roo.MessageBox.hide();
8008 var result = this.processResponse(response);
8009 if(result === true || result.success){
8010 this.form.afterAction(this, true);
8014 this.form.markInvalid(result.errors);
8015 this.failureType = Roo.form.Action.SERVER_INVALID;
8017 this.form.afterAction(this, false);
8019 failure : function(response)
8021 this.uploadComplete= true;
8022 if (this.haveProgress) {
8023 Roo.MessageBox.hide();
8026 this.response = response;
8027 this.failureType = Roo.form.Action.CONNECT_FAILURE;
8028 this.form.afterAction(this, false);
8031 handleResponse : function(response){
8032 if(this.form.errorReader){
8033 var rs = this.form.errorReader.read(response);
8036 for(var i = 0, len = rs.records.length; i < len; i++) {
8037 var r = rs.records[i];
8041 if(errors.length < 1){
8045 success : rs.success,
8051 ret = Roo.decode(response.responseText);
8055 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
8065 Roo.form.Action.Load = function(form, options){
8066 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
8067 this.reader = this.form.reader;
8070 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
8075 Roo.Ajax.request(Roo.apply(
8076 this.createCallback(), {
8077 method:this.getMethod(),
8078 url:this.getUrl(false),
8079 params:this.getParams()
8083 success : function(response){
8085 var result = this.processResponse(response);
8086 if(result === true || !result.success || !result.data){
8087 this.failureType = Roo.form.Action.LOAD_FAILURE;
8088 this.form.afterAction(this, false);
8091 this.form.clearInvalid();
8092 this.form.setValues(result.data);
8093 this.form.afterAction(this, true);
8096 handleResponse : function(response){
8097 if(this.form.reader){
8098 var rs = this.form.reader.read(response);
8099 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
8101 success : rs.success,
8105 return Roo.decode(response.responseText);
8109 Roo.form.Action.ACTION_TYPES = {
8110 'load' : Roo.form.Action.Load,
8111 'submit' : Roo.form.Action.Submit
8120 * @class Roo.bootstrap.Form
8121 * @extends Roo.bootstrap.Component
8122 * Bootstrap Form class
8123 * @cfg {String} method GET | POST (default POST)
8124 * @cfg {String} labelAlign top | left (default top)
8125 * @cfg {String} align left | right - for navbars
8126 * @cfg {Boolean} loadMask load mask when submit (default true)
8131 * @param {Object} config The config object
8135 Roo.bootstrap.Form = function(config){
8137 Roo.bootstrap.Form.superclass.constructor.call(this, config);
8139 Roo.bootstrap.Form.popover.apply();
8143 * @event clientvalidation
8144 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
8145 * @param {Form} this
8146 * @param {Boolean} valid true if the form has passed client-side validation
8148 clientvalidation: true,
8150 * @event beforeaction
8151 * Fires before any action is performed. Return false to cancel the action.
8152 * @param {Form} this
8153 * @param {Action} action The action to be performed
8157 * @event actionfailed
8158 * Fires when an action fails.
8159 * @param {Form} this
8160 * @param {Action} action The action that failed
8162 actionfailed : true,
8164 * @event actioncomplete
8165 * Fires when an action is completed.
8166 * @param {Form} this
8167 * @param {Action} action The action that completed
8169 actioncomplete : true
8173 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
8176 * @cfg {String} method
8177 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
8182 * The URL to use for form actions if one isn't supplied in the action options.
8185 * @cfg {Boolean} fileUpload
8186 * Set to true if this form is a file upload.
8190 * @cfg {Object} baseParams
8191 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
8195 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
8199 * @cfg {Sting} align (left|right) for navbar forms
8204 activeAction : null,
8207 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
8208 * element by passing it or its id or mask the form itself by passing in true.
8211 waitMsgTarget : false,
8216 * @cfg {Boolean} errorMask (true|false) default false
8221 * @cfg {Number} maskOffset Default 100
8226 * @cfg {Boolean} maskBody
8230 getAutoCreate : function(){
8234 method : this.method || 'POST',
8235 id : this.id || Roo.id(),
8238 if (this.parent().xtype.match(/^Nav/)) {
8239 cfg.cls = 'navbar-form form-inline navbar-' + this.align;
8243 if (this.labelAlign == 'left' ) {
8244 cfg.cls += ' form-horizontal';
8250 initEvents : function()
8252 this.el.on('submit', this.onSubmit, this);
8253 // this was added as random key presses on the form where triggering form submit.
8254 this.el.on('keypress', function(e) {
8255 if (e.getCharCode() != 13) {
8258 // we might need to allow it for textareas.. and some other items.
8259 // check e.getTarget().
8261 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
8265 Roo.log("keypress blocked");
8273 onSubmit : function(e){
8278 * Returns true if client-side validation on the form is successful.
8281 isValid : function(){
8282 var items = this.getItems();
8286 items.each(function(f){
8292 Roo.log('invalid field: ' + f.name);
8296 if(!target && f.el.isVisible(true)){
8302 if(this.errorMask && !valid){
8303 Roo.bootstrap.Form.popover.mask(this, target);
8310 * Returns true if any fields in this form have changed since their original load.
8313 isDirty : function(){
8315 var items = this.getItems();
8316 items.each(function(f){
8326 * Performs a predefined action (submit or load) or custom actions you define on this form.
8327 * @param {String} actionName The name of the action type
8328 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
8329 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
8330 * accept other config options):
8332 Property Type Description
8333 ---------------- --------------- ----------------------------------------------------------------------------------
8334 url String The url for the action (defaults to the form's url)
8335 method String The form method to use (defaults to the form's method, or POST if not defined)
8336 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
8337 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
8338 validate the form on the client (defaults to false)
8340 * @return {BasicForm} this
8342 doAction : function(action, options){
8343 if(typeof action == 'string'){
8344 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
8346 if(this.fireEvent('beforeaction', this, action) !== false){
8347 this.beforeAction(action);
8348 action.run.defer(100, action);
8354 beforeAction : function(action){
8355 var o = action.options;
8360 Roo.get(document.body).mask(o.waitMsg || "Sending", 'x-mask-loading')
8362 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
8365 // not really supported yet.. ??
8367 //if(this.waitMsgTarget === true){
8368 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
8369 //}else if(this.waitMsgTarget){
8370 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
8371 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
8373 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
8379 afterAction : function(action, success){
8380 this.activeAction = null;
8381 var o = action.options;
8386 Roo.get(document.body).unmask();
8392 //if(this.waitMsgTarget === true){
8393 // this.el.unmask();
8394 //}else if(this.waitMsgTarget){
8395 // this.waitMsgTarget.unmask();
8397 // Roo.MessageBox.updateProgress(1);
8398 // Roo.MessageBox.hide();
8405 Roo.callback(o.success, o.scope, [this, action]);
8406 this.fireEvent('actioncomplete', this, action);
8410 // failure condition..
8411 // we have a scenario where updates need confirming.
8412 // eg. if a locking scenario exists..
8413 // we look for { errors : { needs_confirm : true }} in the response.
8415 (typeof(action.result) != 'undefined') &&
8416 (typeof(action.result.errors) != 'undefined') &&
8417 (typeof(action.result.errors.needs_confirm) != 'undefined')
8420 Roo.log("not supported yet");
8423 Roo.MessageBox.confirm(
8424 "Change requires confirmation",
8425 action.result.errorMsg,
8430 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
8440 Roo.callback(o.failure, o.scope, [this, action]);
8441 // show an error message if no failed handler is set..
8442 if (!this.hasListener('actionfailed')) {
8443 Roo.log("need to add dialog support");
8445 Roo.MessageBox.alert("Error",
8446 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
8447 action.result.errorMsg :
8448 "Saving Failed, please check your entries or try again"
8453 this.fireEvent('actionfailed', this, action);
8458 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
8459 * @param {String} id The value to search for
8462 findField : function(id){
8463 var items = this.getItems();
8464 var field = items.get(id);
8466 items.each(function(f){
8467 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
8474 return field || null;
8477 * Mark fields in this form invalid in bulk.
8478 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
8479 * @return {BasicForm} this
8481 markInvalid : function(errors){
8482 if(errors instanceof Array){
8483 for(var i = 0, len = errors.length; i < len; i++){
8484 var fieldError = errors[i];
8485 var f = this.findField(fieldError.id);
8487 f.markInvalid(fieldError.msg);
8493 if(typeof errors[id] != 'function' && (field = this.findField(id))){
8494 field.markInvalid(errors[id]);
8498 //Roo.each(this.childForms || [], function (f) {
8499 // f.markInvalid(errors);
8506 * Set values for fields in this form in bulk.
8507 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
8508 * @return {BasicForm} this
8510 setValues : function(values){
8511 if(values instanceof Array){ // array of objects
8512 for(var i = 0, len = values.length; i < len; i++){
8514 var f = this.findField(v.id);
8516 f.setValue(v.value);
8517 if(this.trackResetOnLoad){
8518 f.originalValue = f.getValue();
8522 }else{ // object hash
8525 if(typeof values[id] != 'function' && (field = this.findField(id))){
8527 if (field.setFromData &&
8529 field.displayField &&
8530 // combos' with local stores can
8531 // be queried via setValue()
8532 // to set their value..
8533 (field.store && !field.store.isLocal)
8537 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
8538 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
8539 field.setFromData(sd);
8541 } else if(field.setFromData && (field.store && !field.store.isLocal)) {
8543 field.setFromData(values);
8546 field.setValue(values[id]);
8550 if(this.trackResetOnLoad){
8551 field.originalValue = field.getValue();
8557 //Roo.each(this.childForms || [], function (f) {
8558 // f.setValues(values);
8565 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
8566 * they are returned as an array.
8567 * @param {Boolean} asString
8570 getValues : function(asString){
8571 //if (this.childForms) {
8572 // copy values from the child forms
8573 // Roo.each(this.childForms, function (f) {
8574 // this.setValues(f.getValues());
8580 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
8581 if(asString === true){
8584 return Roo.urlDecode(fs);
8588 * Returns the fields in this form as an object with key/value pairs.
8589 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
8592 getFieldValues : function(with_hidden)
8594 var items = this.getItems();
8596 items.each(function(f){
8602 var v = f.getValue();
8604 if (f.inputType =='radio') {
8605 if (typeof(ret[f.getName()]) == 'undefined') {
8606 ret[f.getName()] = ''; // empty..
8609 if (!f.el.dom.checked) {
8617 if(f.xtype == 'MoneyField'){
8618 ret[f.currencyName] = f.getCurrency();
8621 // not sure if this supported any more..
8622 if ((typeof(v) == 'object') && f.getRawValue) {
8623 v = f.getRawValue() ; // dates..
8625 // combo boxes where name != hiddenName...
8626 if (f.name !== false && f.name != '' && f.name != f.getName()) {
8627 ret[f.name] = f.getRawValue();
8629 ret[f.getName()] = v;
8636 * Clears all invalid messages in this form.
8637 * @return {BasicForm} this
8639 clearInvalid : function(){
8640 var items = this.getItems();
8642 items.each(function(f){
8651 * @return {BasicForm} this
8654 var items = this.getItems();
8655 items.each(function(f){
8659 Roo.each(this.childForms || [], function (f) {
8667 getItems : function()
8669 var r=new Roo.util.MixedCollection(false, function(o){
8670 return o.id || (o.id = Roo.id());
8672 var iter = function(el) {
8679 Roo.each(el.items,function(e) {
8688 hideFields : function(items)
8690 Roo.each(items, function(i){
8692 var f = this.findField(i);
8703 showFields : function(items)
8705 Roo.each(items, function(i){
8707 var f = this.findField(i);
8720 Roo.apply(Roo.bootstrap.Form, {
8747 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
8748 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
8749 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
8750 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
8753 this.maskEl.top.enableDisplayMode("block");
8754 this.maskEl.left.enableDisplayMode("block");
8755 this.maskEl.bottom.enableDisplayMode("block");
8756 this.maskEl.right.enableDisplayMode("block");
8758 this.toolTip = new Roo.bootstrap.Tooltip({
8759 cls : 'roo-form-error-popover',
8761 'left' : ['r-l', [-2,0], 'right'],
8762 'right' : ['l-r', [2,0], 'left'],
8763 'bottom' : ['tl-bl', [0,2], 'top'],
8764 'top' : [ 'bl-tl', [0,-2], 'bottom']
8768 this.toolTip.render(Roo.get(document.body));
8770 this.toolTip.el.enableDisplayMode("block");
8772 Roo.get(document.body).on('click', function(){
8776 Roo.get(document.body).on('touchstart', function(){
8780 this.isApplied = true
8783 mask : function(form, target)
8787 this.target = target;
8789 if(!this.form.errorMask || !target.el){
8793 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.modal', 100, true) || Roo.get(document.body);
8795 Roo.log(scrollable);
8797 var ot = this.target.el.calcOffsetsTo(scrollable);
8799 var scrollTo = ot[1] - this.form.maskOffset;
8801 scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
8803 scrollable.scrollTo('top', scrollTo);
8805 var box = this.target.el.getBox();
8807 var zIndex = Roo.bootstrap.Modal.zIndex++;
8810 this.maskEl.top.setStyle('position', 'absolute');
8811 this.maskEl.top.setStyle('z-index', zIndex);
8812 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
8813 this.maskEl.top.setLeft(0);
8814 this.maskEl.top.setTop(0);
8815 this.maskEl.top.show();
8817 this.maskEl.left.setStyle('position', 'absolute');
8818 this.maskEl.left.setStyle('z-index', zIndex);
8819 this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
8820 this.maskEl.left.setLeft(0);
8821 this.maskEl.left.setTop(box.y - this.padding);
8822 this.maskEl.left.show();
8824 this.maskEl.bottom.setStyle('position', 'absolute');
8825 this.maskEl.bottom.setStyle('z-index', zIndex);
8826 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
8827 this.maskEl.bottom.setLeft(0);
8828 this.maskEl.bottom.setTop(box.bottom + this.padding);
8829 this.maskEl.bottom.show();
8831 this.maskEl.right.setStyle('position', 'absolute');
8832 this.maskEl.right.setStyle('z-index', zIndex);
8833 this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
8834 this.maskEl.right.setLeft(box.right + this.padding);
8835 this.maskEl.right.setTop(box.y - this.padding);
8836 this.maskEl.right.show();
8838 this.toolTip.bindEl = this.target.el;
8840 this.toolTip.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
8842 var tip = this.target.blankText;
8844 if(this.target.getValue() !== '' ) {
8846 if (this.target.invalidText.length) {
8847 tip = this.target.invalidText;
8848 } else if (this.target.regexText.length){
8849 tip = this.target.regexText;
8853 this.toolTip.show(tip);
8855 this.intervalID = window.setInterval(function() {
8856 Roo.bootstrap.Form.popover.unmask();
8859 window.onwheel = function(){ return false;};
8861 (function(){ this.isMasked = true; }).defer(500, this);
8867 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
8871 this.maskEl.top.setStyle('position', 'absolute');
8872 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
8873 this.maskEl.top.hide();
8875 this.maskEl.left.setStyle('position', 'absolute');
8876 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
8877 this.maskEl.left.hide();
8879 this.maskEl.bottom.setStyle('position', 'absolute');
8880 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
8881 this.maskEl.bottom.hide();
8883 this.maskEl.right.setStyle('position', 'absolute');
8884 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
8885 this.maskEl.right.hide();
8887 this.toolTip.hide();
8889 this.toolTip.el.hide();
8891 window.onwheel = function(){ return true;};
8893 if(this.intervalID){
8894 window.clearInterval(this.intervalID);
8895 this.intervalID = false;
8898 this.isMasked = false;
8908 * Ext JS Library 1.1.1
8909 * Copyright(c) 2006-2007, Ext JS, LLC.
8911 * Originally Released Under LGPL - original licence link has changed is not relivant.
8914 * <script type="text/javascript">
8917 * @class Roo.form.VTypes
8918 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
8921 Roo.form.VTypes = function(){
8922 // closure these in so they are only created once.
8923 var alpha = /^[a-zA-Z_]+$/;
8924 var alphanum = /^[a-zA-Z0-9_]+$/;
8925 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
8926 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
8928 // All these messages and functions are configurable
8931 * The function used to validate email addresses
8932 * @param {String} value The email address
8934 'email' : function(v){
8935 return email.test(v);
8938 * The error text to display when the email validation function returns false
8941 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
8943 * The keystroke filter mask to be applied on email input
8946 'emailMask' : /[a-z0-9_\.\-@]/i,
8949 * The function used to validate URLs
8950 * @param {String} value The URL
8952 'url' : function(v){
8956 * The error text to display when the url validation function returns false
8959 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
8962 * The function used to validate alpha values
8963 * @param {String} value The value
8965 'alpha' : function(v){
8966 return alpha.test(v);
8969 * The error text to display when the alpha validation function returns false
8972 'alphaText' : 'This field should only contain letters and _',
8974 * The keystroke filter mask to be applied on alpha input
8977 'alphaMask' : /[a-z_]/i,
8980 * The function used to validate alphanumeric values
8981 * @param {String} value The value
8983 'alphanum' : function(v){
8984 return alphanum.test(v);
8987 * The error text to display when the alphanumeric validation function returns false
8990 'alphanumText' : 'This field should only contain letters, numbers and _',
8992 * The keystroke filter mask to be applied on alphanumeric input
8995 'alphanumMask' : /[a-z0-9_]/i
9005 * @class Roo.bootstrap.Input
9006 * @extends Roo.bootstrap.Component
9007 * Bootstrap Input class
9008 * @cfg {Boolean} disabled is it disabled
9009 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
9010 * @cfg {String} name name of the input
9011 * @cfg {string} fieldLabel - the label associated
9012 * @cfg {string} placeholder - placeholder to put in text.
9013 * @cfg {string} before - input group add on before
9014 * @cfg {string} after - input group add on after
9015 * @cfg {string} size - (lg|sm) or leave empty..
9016 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
9017 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
9018 * @cfg {Number} md colspan out of 12 for computer-sized screens
9019 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
9020 * @cfg {string} value default value of the input
9021 * @cfg {Number} labelWidth set the width of label
9022 * @cfg {Number} labellg set the width of label (1-12)
9023 * @cfg {Number} labelmd set the width of label (1-12)
9024 * @cfg {Number} labelsm set the width of label (1-12)
9025 * @cfg {Number} labelxs set the width of label (1-12)
9026 * @cfg {String} labelAlign (top|left)
9027 * @cfg {Boolean} readOnly Specifies that the field should be read-only
9028 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
9029 * @cfg {String} indicatorpos (left|right) default left
9030 * @cfg {String} capture (user|camera) use for file input only. (default empty)
9031 * @cfg {String} accept (image|video|audio) use for file input only. (default empty)
9033 * @cfg {String} align (left|center|right) Default left
9034 * @cfg {Boolean} forceFeedback (true|false) Default false
9037 * Create a new Input
9038 * @param {Object} config The config object
9041 Roo.bootstrap.Input = function(config){
9043 Roo.bootstrap.Input.superclass.constructor.call(this, config);
9048 * Fires when this field receives input focus.
9049 * @param {Roo.form.Field} this
9054 * Fires when this field loses input focus.
9055 * @param {Roo.form.Field} this
9060 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
9061 * {@link Roo.EventObject#getKey} to determine which key was pressed.
9062 * @param {Roo.form.Field} this
9063 * @param {Roo.EventObject} e The event object
9068 * Fires just before the field blurs if the field value has changed.
9069 * @param {Roo.form.Field} this
9070 * @param {Mixed} newValue The new value
9071 * @param {Mixed} oldValue The original value
9076 * Fires after the field has been marked as invalid.
9077 * @param {Roo.form.Field} this
9078 * @param {String} msg The validation message
9083 * Fires after the field has been validated with no errors.
9084 * @param {Roo.form.Field} this
9089 * Fires after the key up
9090 * @param {Roo.form.Field} this
9091 * @param {Roo.EventObject} e The event Object
9097 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
9099 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
9100 automatic validation (defaults to "keyup").
9102 validationEvent : "keyup",
9104 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
9106 validateOnBlur : true,
9108 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
9110 validationDelay : 250,
9112 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
9114 focusClass : "x-form-focus", // not needed???
9118 * @cfg {String} invalidClass DEPRICATED - code uses BS4 - is-valid / is-invalid
9120 invalidClass : "has-warning",
9123 * @cfg {String} validClass DEPRICATED - code uses BS4 - is-valid / is-invalid
9125 validClass : "has-success",
9128 * @cfg {Boolean} hasFeedback (true|false) default true
9133 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
9135 invalidFeedbackClass : "glyphicon-warning-sign",
9138 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
9140 validFeedbackClass : "glyphicon-ok",
9143 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
9145 selectOnFocus : false,
9148 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
9152 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
9157 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
9159 disableKeyFilter : false,
9162 * @cfg {Boolean} disabled True to disable the field (defaults to false).
9166 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
9170 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
9172 blankText : "Please complete this mandatory field",
9175 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
9179 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
9181 maxLength : Number.MAX_VALUE,
9183 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
9185 minLengthText : "The minimum length for this field is {0}",
9187 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
9189 maxLengthText : "The maximum length for this field is {0}",
9193 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
9194 * If available, this function will be called only after the basic validators all return true, and will be passed the
9195 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
9199 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
9200 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
9201 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
9205 * @cfg {String} regexText -- Depricated - use Invalid Text
9210 * @cfg {String} invalidText The error text to display if {@link #validator} test fails during validation (defaults to "")
9216 autocomplete: false,
9235 formatedValue : false,
9236 forceFeedback : false,
9238 indicatorpos : 'left',
9248 parentLabelAlign : function()
9251 while (parent.parent()) {
9252 parent = parent.parent();
9253 if (typeof(parent.labelAlign) !='undefined') {
9254 return parent.labelAlign;
9261 getAutoCreate : function()
9263 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9269 if(this.inputType != 'hidden'){
9270 cfg.cls = 'form-group' //input-group
9276 type : this.inputType,
9278 cls : 'form-control',
9279 placeholder : this.placeholder || '',
9280 autocomplete : this.autocomplete || 'new-password'
9283 if(this.capture.length){
9284 input.capture = this.capture;
9287 if(this.accept.length){
9288 input.accept = this.accept + "/*";
9292 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
9295 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9296 input.maxLength = this.maxLength;
9299 if (this.disabled) {
9300 input.disabled=true;
9303 if (this.readOnly) {
9304 input.readonly=true;
9308 input.name = this.name;
9312 input.cls += ' input-' + this.size;
9316 ['xs','sm','md','lg'].map(function(size){
9317 if (settings[size]) {
9318 cfg.cls += ' col-' + size + '-' + settings[size];
9322 var inputblock = input;
9326 cls: 'glyphicon form-control-feedback'
9329 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9332 cls : 'has-feedback',
9340 if (this.before || this.after) {
9343 cls : 'input-group',
9347 if (this.before && typeof(this.before) == 'string') {
9349 inputblock.cn.push({
9351 cls : 'roo-input-before input-group-addon input-group-prepend input-group-text',
9355 if (this.before && typeof(this.before) == 'object') {
9356 this.before = Roo.factory(this.before);
9358 inputblock.cn.push({
9360 cls : 'roo-input-before input-group-prepend input-group-text input-group-' +
9361 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
9365 inputblock.cn.push(input);
9367 if (this.after && typeof(this.after) == 'string') {
9368 inputblock.cn.push({
9370 cls : 'roo-input-after input-group-append input-group-text input-group-addon',
9374 if (this.after && typeof(this.after) == 'object') {
9375 this.after = Roo.factory(this.after);
9377 inputblock.cn.push({
9379 cls : 'roo-input-after input-group-append input-group-text input-group-' +
9380 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
9384 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9385 inputblock.cls += ' has-feedback';
9386 inputblock.cn.push(feedback);
9391 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
9392 tooltip : 'This field is required'
9394 if (Roo.bootstrap.version == 4) {
9397 style : 'display-none'
9400 if (align ==='left' && this.fieldLabel.length) {
9402 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
9409 cls : 'control-label col-form-label',
9410 html : this.fieldLabel
9421 var labelCfg = cfg.cn[1];
9422 var contentCfg = cfg.cn[2];
9424 if(this.indicatorpos == 'right'){
9429 cls : 'control-label col-form-label',
9433 html : this.fieldLabel
9447 labelCfg = cfg.cn[0];
9448 contentCfg = cfg.cn[1];
9452 if(this.labelWidth > 12){
9453 labelCfg.style = "width: " + this.labelWidth + 'px';
9456 if(this.labelWidth < 13 && this.labelmd == 0){
9457 this.labelmd = this.labelWidth;
9460 if(this.labellg > 0){
9461 labelCfg.cls += ' col-lg-' + this.labellg;
9462 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
9465 if(this.labelmd > 0){
9466 labelCfg.cls += ' col-md-' + this.labelmd;
9467 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
9470 if(this.labelsm > 0){
9471 labelCfg.cls += ' col-sm-' + this.labelsm;
9472 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
9475 if(this.labelxs > 0){
9476 labelCfg.cls += ' col-xs-' + this.labelxs;
9477 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
9481 } else if ( this.fieldLabel.length) {
9486 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
9487 tooltip : 'This field is required'
9491 //cls : 'input-group-addon',
9492 html : this.fieldLabel
9500 if(this.indicatorpos == 'right'){
9505 //cls : 'input-group-addon',
9506 html : this.fieldLabel
9511 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9512 tooltip : 'This field is required'
9532 if (this.parentType === 'Navbar' && this.parent().bar) {
9533 cfg.cls += ' navbar-form';
9536 if (this.parentType === 'NavGroup' && !(Roo.bootstrap.version == 4 && this.parent().form)) {
9537 // on BS4 we do this only if not form
9538 cfg.cls += ' navbar-form';
9546 * return the real input element.
9548 inputEl: function ()
9550 return this.el.select('input.form-control',true).first();
9553 tooltipEl : function()
9555 return this.inputEl();
9558 indicatorEl : function()
9560 if (Roo.bootstrap.version == 4) {
9561 return false; // not enabled in v4 yet.
9564 var indicator = this.el.select('i.roo-required-indicator',true).first();
9574 setDisabled : function(v)
9576 var i = this.inputEl().dom;
9578 i.removeAttribute('disabled');
9582 i.setAttribute('disabled','true');
9584 initEvents : function()
9587 this.inputEl().on("keydown" , this.fireKey, this);
9588 this.inputEl().on("focus", this.onFocus, this);
9589 this.inputEl().on("blur", this.onBlur, this);
9591 this.inputEl().relayEvent('keyup', this);
9593 this.indicator = this.indicatorEl();
9596 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible'); // changed from invisible??? -
9599 // reference to original value for reset
9600 this.originalValue = this.getValue();
9601 //Roo.form.TextField.superclass.initEvents.call(this);
9602 if(this.validationEvent == 'keyup'){
9603 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
9604 this.inputEl().on('keyup', this.filterValidation, this);
9606 else if(this.validationEvent !== false){
9607 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
9610 if(this.selectOnFocus){
9611 this.on("focus", this.preFocus, this);
9614 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
9615 this.inputEl().on("keypress", this.filterKeys, this);
9617 this.inputEl().relayEvent('keypress', this);
9620 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
9621 this.el.on("click", this.autoSize, this);
9624 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
9625 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
9628 if (typeof(this.before) == 'object') {
9629 this.before.render(this.el.select('.roo-input-before',true).first());
9631 if (typeof(this.after) == 'object') {
9632 this.after.render(this.el.select('.roo-input-after',true).first());
9635 this.inputEl().on('change', this.onChange, this);
9638 filterValidation : function(e){
9639 if(!e.isNavKeyPress()){
9640 this.validationTask.delay(this.validationDelay);
9644 * Validates the field value
9645 * @return {Boolean} True if the value is valid, else false
9647 validate : function(){
9648 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
9649 if(this.disabled || this.validateValue(this.getRawValue())){
9660 * Validates a value according to the field's validation rules and marks the field as invalid
9661 * if the validation fails
9662 * @param {Mixed} value The value to validate
9663 * @return {Boolean} True if the value is valid, else false
9665 validateValue : function(value)
9667 if(this.getVisibilityEl().hasClass('hidden')){
9671 if(value.length < 1) { // if it's blank
9672 if(this.allowBlank){
9678 if(value.length < this.minLength){
9681 if(value.length > this.maxLength){
9685 var vt = Roo.form.VTypes;
9686 if(!vt[this.vtype](value, this)){
9690 if(typeof this.validator == "function"){
9691 var msg = this.validator(value);
9695 if (typeof(msg) == 'string') {
9696 this.invalidText = msg;
9700 if(this.regex && !this.regex.test(value)){
9708 fireKey : function(e){
9709 //Roo.log('field ' + e.getKey());
9710 if(e.isNavKeyPress()){
9711 this.fireEvent("specialkey", this, e);
9714 focus : function (selectText){
9716 this.inputEl().focus();
9717 if(selectText === true){
9718 this.inputEl().dom.select();
9724 onFocus : function(){
9725 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9726 // this.el.addClass(this.focusClass);
9729 this.hasFocus = true;
9730 this.startValue = this.getValue();
9731 this.fireEvent("focus", this);
9735 beforeBlur : Roo.emptyFn,
9739 onBlur : function(){
9741 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9742 //this.el.removeClass(this.focusClass);
9744 this.hasFocus = false;
9745 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
9748 var v = this.getValue();
9749 if(String(v) !== String(this.startValue)){
9750 this.fireEvent('change', this, v, this.startValue);
9752 this.fireEvent("blur", this);
9755 onChange : function(e)
9757 var v = this.getValue();
9758 if(String(v) !== String(this.startValue)){
9759 this.fireEvent('change', this, v, this.startValue);
9765 * Resets the current field value to the originally loaded value and clears any validation messages
9768 this.setValue(this.originalValue);
9772 * Returns the name of the field
9773 * @return {Mixed} name The name field
9775 getName: function(){
9779 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
9780 * @return {Mixed} value The field value
9782 getValue : function(){
9784 var v = this.inputEl().getValue();
9789 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
9790 * @return {Mixed} value The field value
9792 getRawValue : function(){
9793 var v = this.inputEl().getValue();
9799 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
9800 * @param {Mixed} value The value to set
9802 setRawValue : function(v){
9803 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9806 selectText : function(start, end){
9807 var v = this.getRawValue();
9809 start = start === undefined ? 0 : start;
9810 end = end === undefined ? v.length : end;
9811 var d = this.inputEl().dom;
9812 if(d.setSelectionRange){
9813 d.setSelectionRange(start, end);
9814 }else if(d.createTextRange){
9815 var range = d.createTextRange();
9816 range.moveStart("character", start);
9817 range.moveEnd("character", v.length-end);
9824 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
9825 * @param {Mixed} value The value to set
9827 setValue : function(v){
9830 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9836 processValue : function(value){
9837 if(this.stripCharsRe){
9838 var newValue = value.replace(this.stripCharsRe, '');
9839 if(newValue !== value){
9840 this.setRawValue(newValue);
9847 preFocus : function(){
9849 if(this.selectOnFocus){
9850 this.inputEl().dom.select();
9853 filterKeys : function(e){
9855 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
9858 var c = e.getCharCode(), cc = String.fromCharCode(c);
9859 if(Roo.isIE && (e.isSpecialKey() || !cc)){
9862 if(!this.maskRe.test(cc)){
9867 * Clear any invalid styles/messages for this field
9869 clearInvalid : function(){
9871 if(!this.el || this.preventMark){ // not rendered
9876 this.el.removeClass([this.invalidClass, 'is-invalid']);
9878 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9880 var feedback = this.el.select('.form-control-feedback', true).first();
9883 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9889 this.indicator.removeClass('visible');
9890 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9893 this.fireEvent('valid', this);
9897 * Mark this field as valid
9899 markValid : function()
9901 if(!this.el || this.preventMark){ // not rendered...
9905 this.el.removeClass([this.invalidClass, this.validClass]);
9906 this.inputEl().removeClass(['is-valid', 'is-invalid']);
9908 var feedback = this.el.select('.form-control-feedback', true).first();
9911 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9915 this.indicator.removeClass('visible');
9916 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9923 if(this.allowBlank && !this.getRawValue().length){
9926 if (Roo.bootstrap.version == 3) {
9927 this.el.addClass(this.validClass);
9929 this.inputEl().addClass('is-valid');
9932 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9934 var feedback = this.el.select('.form-control-feedback', true).first();
9937 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9938 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9943 this.fireEvent('valid', this);
9947 * Mark this field as invalid
9948 * @param {String} msg The validation message
9950 markInvalid : function(msg)
9952 if(!this.el || this.preventMark){ // not rendered
9956 this.el.removeClass([this.invalidClass, this.validClass]);
9957 this.inputEl().removeClass(['is-valid', 'is-invalid']);
9959 var feedback = this.el.select('.form-control-feedback', true).first();
9962 this.el.select('.form-control-feedback', true).first().removeClass(
9963 [this.invalidFeedbackClass, this.validFeedbackClass]);
9970 if(this.allowBlank && !this.getRawValue().length){
9975 this.indicator.removeClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9976 this.indicator.addClass('visible');
9978 if (Roo.bootstrap.version == 3) {
9979 this.el.addClass(this.invalidClass);
9981 this.inputEl().addClass('is-invalid');
9986 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9988 var feedback = this.el.select('.form-control-feedback', true).first();
9991 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9993 if(this.getValue().length || this.forceFeedback){
9994 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
10001 this.fireEvent('invalid', this, msg);
10004 SafariOnKeyDown : function(event)
10006 // this is a workaround for a password hang bug on chrome/ webkit.
10007 if (this.inputEl().dom.type != 'password') {
10011 var isSelectAll = false;
10013 if(this.inputEl().dom.selectionEnd > 0){
10014 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
10016 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
10017 event.preventDefault();
10022 if(isSelectAll && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
10024 event.preventDefault();
10025 // this is very hacky as keydown always get's upper case.
10027 var cc = String.fromCharCode(event.getCharCode());
10028 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
10032 adjustWidth : function(tag, w){
10033 tag = tag.toLowerCase();
10034 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
10035 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
10036 if(tag == 'input'){
10039 if(tag == 'textarea'){
10042 }else if(Roo.isOpera){
10043 if(tag == 'input'){
10046 if(tag == 'textarea'){
10054 setFieldLabel : function(v)
10056 if(!this.rendered){
10060 if(this.indicatorEl()){
10061 var ar = this.el.select('label > span',true);
10063 if (ar.elements.length) {
10064 this.el.select('label > span',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
10065 this.fieldLabel = v;
10069 var br = this.el.select('label',true);
10071 if(br.elements.length) {
10072 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
10073 this.fieldLabel = v;
10077 Roo.log('Cannot Found any of label > span || label in input');
10081 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
10082 this.fieldLabel = v;
10097 * @class Roo.bootstrap.TextArea
10098 * @extends Roo.bootstrap.Input
10099 * Bootstrap TextArea class
10100 * @cfg {Number} cols Specifies the visible width of a text area
10101 * @cfg {Number} rows Specifies the visible number of lines in a text area
10102 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
10103 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
10104 * @cfg {string} html text
10107 * Create a new TextArea
10108 * @param {Object} config The config object
10111 Roo.bootstrap.TextArea = function(config){
10112 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
10116 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
10126 getAutoCreate : function(){
10128 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
10134 if(this.inputType != 'hidden'){
10135 cfg.cls = 'form-group' //input-group
10143 value : this.value || '',
10144 html: this.html || '',
10145 cls : 'form-control',
10146 placeholder : this.placeholder || ''
10150 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
10151 input.maxLength = this.maxLength;
10155 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
10159 input.cols = this.cols;
10162 if (this.readOnly) {
10163 input.readonly = true;
10167 input.name = this.name;
10171 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
10175 ['xs','sm','md','lg'].map(function(size){
10176 if (settings[size]) {
10177 cfg.cls += ' col-' + size + '-' + settings[size];
10181 var inputblock = input;
10183 if(this.hasFeedback && !this.allowBlank){
10187 cls: 'glyphicon form-control-feedback'
10191 cls : 'has-feedback',
10200 if (this.before || this.after) {
10203 cls : 'input-group',
10207 inputblock.cn.push({
10209 cls : 'input-group-addon',
10214 inputblock.cn.push(input);
10216 if(this.hasFeedback && !this.allowBlank){
10217 inputblock.cls += ' has-feedback';
10218 inputblock.cn.push(feedback);
10222 inputblock.cn.push({
10224 cls : 'input-group-addon',
10231 if (align ==='left' && this.fieldLabel.length) {
10236 cls : 'control-label',
10237 html : this.fieldLabel
10248 if(this.labelWidth > 12){
10249 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
10252 if(this.labelWidth < 13 && this.labelmd == 0){
10253 this.labelmd = this.labelWidth;
10256 if(this.labellg > 0){
10257 cfg.cn[0].cls += ' col-lg-' + this.labellg;
10258 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
10261 if(this.labelmd > 0){
10262 cfg.cn[0].cls += ' col-md-' + this.labelmd;
10263 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
10266 if(this.labelsm > 0){
10267 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
10268 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
10271 if(this.labelxs > 0){
10272 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
10273 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
10276 } else if ( this.fieldLabel.length) {
10281 //cls : 'input-group-addon',
10282 html : this.fieldLabel
10300 if (this.disabled) {
10301 input.disabled=true;
10308 * return the real textarea element.
10310 inputEl: function ()
10312 return this.el.select('textarea.form-control',true).first();
10316 * Clear any invalid styles/messages for this field
10318 clearInvalid : function()
10321 if(!this.el || this.preventMark){ // not rendered
10325 var label = this.el.select('label', true).first();
10326 var icon = this.el.select('i.fa-star', true).first();
10331 this.el.removeClass( this.validClass);
10332 this.inputEl().removeClass('is-invalid');
10334 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10336 var feedback = this.el.select('.form-control-feedback', true).first();
10339 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
10344 this.fireEvent('valid', this);
10348 * Mark this field as valid
10350 markValid : function()
10352 if(!this.el || this.preventMark){ // not rendered
10356 this.el.removeClass([this.invalidClass, this.validClass]);
10357 this.inputEl().removeClass(['is-valid', 'is-invalid']);
10359 var feedback = this.el.select('.form-control-feedback', true).first();
10362 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10365 if(this.disabled || this.allowBlank){
10369 var label = this.el.select('label', true).first();
10370 var icon = this.el.select('i.fa-star', true).first();
10375 if (Roo.bootstrap.version == 3) {
10376 this.el.addClass(this.validClass);
10378 this.inputEl().addClass('is-valid');
10382 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
10384 var feedback = this.el.select('.form-control-feedback', true).first();
10387 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10388 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
10393 this.fireEvent('valid', this);
10397 * Mark this field as invalid
10398 * @param {String} msg The validation message
10400 markInvalid : function(msg)
10402 if(!this.el || this.preventMark){ // not rendered
10406 this.el.removeClass([this.invalidClass, this.validClass]);
10407 this.inputEl().removeClass(['is-valid', 'is-invalid']);
10409 var feedback = this.el.select('.form-control-feedback', true).first();
10412 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10415 if(this.disabled || this.allowBlank){
10419 var label = this.el.select('label', true).first();
10420 var icon = this.el.select('i.fa-star', true).first();
10422 if(!this.getValue().length && label && !icon){
10423 this.el.createChild({
10425 cls : 'text-danger fa fa-lg fa-star',
10426 tooltip : 'This field is required',
10427 style : 'margin-right:5px;'
10431 if (Roo.bootstrap.version == 3) {
10432 this.el.addClass(this.invalidClass);
10434 this.inputEl().addClass('is-invalid');
10437 // fixme ... this may be depricated need to test..
10438 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10440 var feedback = this.el.select('.form-control-feedback', true).first();
10443 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10445 if(this.getValue().length || this.forceFeedback){
10446 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
10453 this.fireEvent('invalid', this, msg);
10461 * trigger field - base class for combo..
10466 * @class Roo.bootstrap.TriggerField
10467 * @extends Roo.bootstrap.Input
10468 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
10469 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
10470 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
10471 * for which you can provide a custom implementation. For example:
10473 var trigger = new Roo.bootstrap.TriggerField();
10474 trigger.onTriggerClick = myTriggerFn;
10475 trigger.applyTo('my-field');
10478 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
10479 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
10480 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
10481 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
10482 * @cfg {String} caret (search|calendar) BS3 only - carat fa name
10485 * Create a new TriggerField.
10486 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
10487 * to the base TextField)
10489 Roo.bootstrap.TriggerField = function(config){
10490 this.mimicing = false;
10491 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
10494 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
10496 * @cfg {String} triggerClass A CSS class to apply to the trigger
10499 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
10504 * @cfg {Boolean} removable (true|false) special filter default false
10508 /** @cfg {Boolean} grow @hide */
10509 /** @cfg {Number} growMin @hide */
10510 /** @cfg {Number} growMax @hide */
10516 autoSize: Roo.emptyFn,
10520 deferHeight : true,
10523 actionMode : 'wrap',
10528 getAutoCreate : function(){
10530 var align = this.labelAlign || this.parentLabelAlign();
10535 cls: 'form-group' //input-group
10542 type : this.inputType,
10543 cls : 'form-control',
10544 autocomplete: 'new-password',
10545 placeholder : this.placeholder || ''
10549 input.name = this.name;
10552 input.cls += ' input-' + this.size;
10555 if (this.disabled) {
10556 input.disabled=true;
10559 var inputblock = input;
10561 if(this.hasFeedback && !this.allowBlank){
10565 cls: 'glyphicon form-control-feedback'
10568 if(this.removable && !this.editable && !this.tickable){
10570 cls : 'has-feedback',
10576 cls : 'roo-combo-removable-btn close'
10583 cls : 'has-feedback',
10592 if(this.removable && !this.editable && !this.tickable){
10594 cls : 'roo-removable',
10600 cls : 'roo-combo-removable-btn close'
10607 if (this.before || this.after) {
10610 cls : 'input-group',
10614 inputblock.cn.push({
10616 cls : 'input-group-addon input-group-prepend input-group-text',
10621 inputblock.cn.push(input);
10623 if(this.hasFeedback && !this.allowBlank){
10624 inputblock.cls += ' has-feedback';
10625 inputblock.cn.push(feedback);
10629 inputblock.cn.push({
10631 cls : 'input-group-addon input-group-append input-group-text',
10640 var ibwrap = inputblock;
10645 cls: 'roo-select2-choices',
10649 cls: 'roo-select2-search-field',
10661 cls: 'roo-select2-container input-group',
10666 cls: 'form-hidden-field'
10672 if(!this.multiple && this.showToggleBtn){
10678 if (this.caret != false) {
10681 cls: 'fa fa-' + this.caret
10688 cls : 'input-group-addon input-group-append input-group-text btn dropdown-toggle',
10690 Roo.bootstrap.version == 3 ? caret : '',
10693 cls: 'combobox-clear',
10707 combobox.cls += ' roo-select2-container-multi';
10711 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
10712 tooltip : 'This field is required'
10714 if (Roo.bootstrap.version == 4) {
10717 style : 'display:none'
10722 if (align ==='left' && this.fieldLabel.length) {
10724 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
10731 cls : 'control-label',
10732 html : this.fieldLabel
10744 var labelCfg = cfg.cn[1];
10745 var contentCfg = cfg.cn[2];
10747 if(this.indicatorpos == 'right'){
10752 cls : 'control-label',
10756 html : this.fieldLabel
10770 labelCfg = cfg.cn[0];
10771 contentCfg = cfg.cn[1];
10774 if(this.labelWidth > 12){
10775 labelCfg.style = "width: " + this.labelWidth + 'px';
10778 if(this.labelWidth < 13 && this.labelmd == 0){
10779 this.labelmd = this.labelWidth;
10782 if(this.labellg > 0){
10783 labelCfg.cls += ' col-lg-' + this.labellg;
10784 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
10787 if(this.labelmd > 0){
10788 labelCfg.cls += ' col-md-' + this.labelmd;
10789 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
10792 if(this.labelsm > 0){
10793 labelCfg.cls += ' col-sm-' + this.labelsm;
10794 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
10797 if(this.labelxs > 0){
10798 labelCfg.cls += ' col-xs-' + this.labelxs;
10799 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
10802 } else if ( this.fieldLabel.length) {
10803 // Roo.log(" label");
10808 //cls : 'input-group-addon',
10809 html : this.fieldLabel
10817 if(this.indicatorpos == 'right'){
10825 html : this.fieldLabel
10839 // Roo.log(" no label && no align");
10846 ['xs','sm','md','lg'].map(function(size){
10847 if (settings[size]) {
10848 cfg.cls += ' col-' + size + '-' + settings[size];
10859 onResize : function(w, h){
10860 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
10861 // if(typeof w == 'number'){
10862 // var x = w - this.trigger.getWidth();
10863 // this.inputEl().setWidth(this.adjustWidth('input', x));
10864 // this.trigger.setStyle('left', x+'px');
10869 adjustSize : Roo.BoxComponent.prototype.adjustSize,
10872 getResizeEl : function(){
10873 return this.inputEl();
10877 getPositionEl : function(){
10878 return this.inputEl();
10882 alignErrorIcon : function(){
10883 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
10887 initEvents : function(){
10891 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
10892 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
10893 if(!this.multiple && this.showToggleBtn){
10894 this.trigger = this.el.select('span.dropdown-toggle',true).first();
10895 if(this.hideTrigger){
10896 this.trigger.setDisplayed(false);
10898 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10902 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
10905 if(this.removable && !this.editable && !this.tickable){
10906 var close = this.closeTriggerEl();
10909 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
10910 close.on('click', this.removeBtnClick, this, close);
10914 //this.trigger.addClassOnOver('x-form-trigger-over');
10915 //this.trigger.addClassOnClick('x-form-trigger-click');
10918 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
10922 closeTriggerEl : function()
10924 var close = this.el.select('.roo-combo-removable-btn', true).first();
10925 return close ? close : false;
10928 removeBtnClick : function(e, h, el)
10930 e.preventDefault();
10932 if(this.fireEvent("remove", this) !== false){
10934 this.fireEvent("afterremove", this)
10938 createList : function()
10940 this.list = Roo.get(document.body).createChild({
10941 tag: Roo.bootstrap.version == 4 ? 'div' : 'ul',
10942 cls: 'typeahead typeahead-long dropdown-menu',
10943 style: 'display:none'
10946 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
10951 initTrigger : function(){
10956 onDestroy : function(){
10958 this.trigger.removeAllListeners();
10959 // this.trigger.remove();
10962 // this.wrap.remove();
10964 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
10968 onFocus : function(){
10969 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
10971 if(!this.mimicing){
10972 this.wrap.addClass('x-trigger-wrap-focus');
10973 this.mimicing = true;
10974 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
10975 if(this.monitorTab){
10976 this.el.on("keydown", this.checkTab, this);
10983 checkTab : function(e){
10984 if(e.getKey() == e.TAB){
10985 this.triggerBlur();
10990 onBlur : function(){
10995 mimicBlur : function(e, t){
10997 if(!this.wrap.contains(t) && this.validateBlur()){
10998 this.triggerBlur();
11004 triggerBlur : function(){
11005 this.mimicing = false;
11006 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
11007 if(this.monitorTab){
11008 this.el.un("keydown", this.checkTab, this);
11010 //this.wrap.removeClass('x-trigger-wrap-focus');
11011 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
11015 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
11016 validateBlur : function(e, t){
11021 onDisable : function(){
11022 this.inputEl().dom.disabled = true;
11023 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
11025 // this.wrap.addClass('x-item-disabled');
11030 onEnable : function(){
11031 this.inputEl().dom.disabled = false;
11032 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
11034 // this.el.removeClass('x-item-disabled');
11039 onShow : function(){
11040 var ae = this.getActionEl();
11043 ae.dom.style.display = '';
11044 ae.dom.style.visibility = 'visible';
11050 onHide : function(){
11051 var ae = this.getActionEl();
11052 ae.dom.style.display = 'none';
11056 * The function that should handle the trigger's click event. This method does nothing by default until overridden
11057 * by an implementing function.
11059 * @param {EventObject} e
11061 onTriggerClick : Roo.emptyFn
11065 * Ext JS Library 1.1.1
11066 * Copyright(c) 2006-2007, Ext JS, LLC.
11068 * Originally Released Under LGPL - original licence link has changed is not relivant.
11071 * <script type="text/javascript">
11076 * @class Roo.data.SortTypes
11078 * Defines the default sorting (casting?) comparison functions used when sorting data.
11080 Roo.data.SortTypes = {
11082 * Default sort that does nothing
11083 * @param {Mixed} s The value being converted
11084 * @return {Mixed} The comparison value
11086 none : function(s){
11091 * The regular expression used to strip tags
11095 stripTagsRE : /<\/?[^>]+>/gi,
11098 * Strips all HTML tags to sort on text only
11099 * @param {Mixed} s The value being converted
11100 * @return {String} The comparison value
11102 asText : function(s){
11103 return String(s).replace(this.stripTagsRE, "");
11107 * Strips all HTML tags to sort on text only - Case insensitive
11108 * @param {Mixed} s The value being converted
11109 * @return {String} The comparison value
11111 asUCText : function(s){
11112 return String(s).toUpperCase().replace(this.stripTagsRE, "");
11116 * Case insensitive string
11117 * @param {Mixed} s The value being converted
11118 * @return {String} The comparison value
11120 asUCString : function(s) {
11121 return String(s).toUpperCase();
11126 * @param {Mixed} s The value being converted
11127 * @return {Number} The comparison value
11129 asDate : function(s) {
11133 if(s instanceof Date){
11134 return s.getTime();
11136 return Date.parse(String(s));
11141 * @param {Mixed} s The value being converted
11142 * @return {Float} The comparison value
11144 asFloat : function(s) {
11145 var val = parseFloat(String(s).replace(/,/g, ""));
11154 * @param {Mixed} s The value being converted
11155 * @return {Number} The comparison value
11157 asInt : function(s) {
11158 var val = parseInt(String(s).replace(/,/g, ""));
11166 * Ext JS Library 1.1.1
11167 * Copyright(c) 2006-2007, Ext JS, LLC.
11169 * Originally Released Under LGPL - original licence link has changed is not relivant.
11172 * <script type="text/javascript">
11176 * @class Roo.data.Record
11177 * Instances of this class encapsulate both record <em>definition</em> information, and record
11178 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
11179 * to access Records cached in an {@link Roo.data.Store} object.<br>
11181 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
11182 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
11185 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
11187 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
11188 * {@link #create}. The parameters are the same.
11189 * @param {Array} data An associative Array of data values keyed by the field name.
11190 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
11191 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
11192 * not specified an integer id is generated.
11194 Roo.data.Record = function(data, id){
11195 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
11200 * Generate a constructor for a specific record layout.
11201 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
11202 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
11203 * Each field definition object may contain the following properties: <ul>
11204 * <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,
11205 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
11206 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
11207 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
11208 * is being used, then this is a string containing the javascript expression to reference the data relative to
11209 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
11210 * to the data item relative to the record element. If the mapping expression is the same as the field name,
11211 * this may be omitted.</p></li>
11212 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
11213 * <ul><li>auto (Default, implies no conversion)</li>
11218 * <li>date</li></ul></p></li>
11219 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
11220 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
11221 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
11222 * by the Reader into an object that will be stored in the Record. It is passed the
11223 * following parameters:<ul>
11224 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
11226 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
11228 * <br>usage:<br><pre><code>
11229 var TopicRecord = Roo.data.Record.create(
11230 {name: 'title', mapping: 'topic_title'},
11231 {name: 'author', mapping: 'username'},
11232 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
11233 {name: 'lastPost', mapping: 'post_time', type: 'date'},
11234 {name: 'lastPoster', mapping: 'user2'},
11235 {name: 'excerpt', mapping: 'post_text'}
11238 var myNewRecord = new TopicRecord({
11239 title: 'Do my job please',
11242 lastPost: new Date(),
11243 lastPoster: 'Animal',
11244 excerpt: 'No way dude!'
11246 myStore.add(myNewRecord);
11251 Roo.data.Record.create = function(o){
11252 var f = function(){
11253 f.superclass.constructor.apply(this, arguments);
11255 Roo.extend(f, Roo.data.Record);
11256 var p = f.prototype;
11257 p.fields = new Roo.util.MixedCollection(false, function(field){
11260 for(var i = 0, len = o.length; i < len; i++){
11261 p.fields.add(new Roo.data.Field(o[i]));
11263 f.getField = function(name){
11264 return p.fields.get(name);
11269 Roo.data.Record.AUTO_ID = 1000;
11270 Roo.data.Record.EDIT = 'edit';
11271 Roo.data.Record.REJECT = 'reject';
11272 Roo.data.Record.COMMIT = 'commit';
11274 Roo.data.Record.prototype = {
11276 * Readonly flag - true if this record has been modified.
11285 join : function(store){
11286 this.store = store;
11290 * Set the named field to the specified value.
11291 * @param {String} name The name of the field to set.
11292 * @param {Object} value The value to set the field to.
11294 set : function(name, value){
11295 if(this.data[name] == value){
11299 if(!this.modified){
11300 this.modified = {};
11302 if(typeof this.modified[name] == 'undefined'){
11303 this.modified[name] = this.data[name];
11305 this.data[name] = value;
11306 if(!this.editing && this.store){
11307 this.store.afterEdit(this);
11312 * Get the value of the named field.
11313 * @param {String} name The name of the field to get the value of.
11314 * @return {Object} The value of the field.
11316 get : function(name){
11317 return this.data[name];
11321 beginEdit : function(){
11322 this.editing = true;
11323 this.modified = {};
11327 cancelEdit : function(){
11328 this.editing = false;
11329 delete this.modified;
11333 endEdit : function(){
11334 this.editing = false;
11335 if(this.dirty && this.store){
11336 this.store.afterEdit(this);
11341 * Usually called by the {@link Roo.data.Store} which owns the Record.
11342 * Rejects all changes made to the Record since either creation, or the last commit operation.
11343 * Modified fields are reverted to their original values.
11345 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
11346 * of reject operations.
11348 reject : function(){
11349 var m = this.modified;
11351 if(typeof m[n] != "function"){
11352 this.data[n] = m[n];
11355 this.dirty = false;
11356 delete this.modified;
11357 this.editing = false;
11359 this.store.afterReject(this);
11364 * Usually called by the {@link Roo.data.Store} which owns the Record.
11365 * Commits all changes made to the Record since either creation, or the last commit operation.
11367 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
11368 * of commit operations.
11370 commit : function(){
11371 this.dirty = false;
11372 delete this.modified;
11373 this.editing = false;
11375 this.store.afterCommit(this);
11380 hasError : function(){
11381 return this.error != null;
11385 clearError : function(){
11390 * Creates a copy of this record.
11391 * @param {String} id (optional) A new record id if you don't want to use this record's id
11394 copy : function(newId) {
11395 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
11399 * Ext JS Library 1.1.1
11400 * Copyright(c) 2006-2007, Ext JS, LLC.
11402 * Originally Released Under LGPL - original licence link has changed is not relivant.
11405 * <script type="text/javascript">
11411 * @class Roo.data.Store
11412 * @extends Roo.util.Observable
11413 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
11414 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
11416 * 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
11417 * has no knowledge of the format of the data returned by the Proxy.<br>
11419 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
11420 * instances from the data object. These records are cached and made available through accessor functions.
11422 * Creates a new Store.
11423 * @param {Object} config A config object containing the objects needed for the Store to access data,
11424 * and read the data into Records.
11426 Roo.data.Store = function(config){
11427 this.data = new Roo.util.MixedCollection(false);
11428 this.data.getKey = function(o){
11431 this.baseParams = {};
11433 this.paramNames = {
11438 "multisort" : "_multisort"
11441 if(config && config.data){
11442 this.inlineData = config.data;
11443 delete config.data;
11446 Roo.apply(this, config);
11448 if(this.reader){ // reader passed
11449 this.reader = Roo.factory(this.reader, Roo.data);
11450 this.reader.xmodule = this.xmodule || false;
11451 if(!this.recordType){
11452 this.recordType = this.reader.recordType;
11454 if(this.reader.onMetaChange){
11455 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
11459 if(this.recordType){
11460 this.fields = this.recordType.prototype.fields;
11462 this.modified = [];
11466 * @event datachanged
11467 * Fires when the data cache has changed, and a widget which is using this Store
11468 * as a Record cache should refresh its view.
11469 * @param {Store} this
11471 datachanged : true,
11473 * @event metachange
11474 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
11475 * @param {Store} this
11476 * @param {Object} meta The JSON metadata
11481 * Fires when Records have been added to the Store
11482 * @param {Store} this
11483 * @param {Roo.data.Record[]} records The array of Records added
11484 * @param {Number} index The index at which the record(s) were added
11489 * Fires when a Record has been removed from the Store
11490 * @param {Store} this
11491 * @param {Roo.data.Record} record The Record that was removed
11492 * @param {Number} index The index at which the record was removed
11497 * Fires when a Record has been updated
11498 * @param {Store} this
11499 * @param {Roo.data.Record} record The Record that was updated
11500 * @param {String} operation The update operation being performed. Value may be one of:
11502 Roo.data.Record.EDIT
11503 Roo.data.Record.REJECT
11504 Roo.data.Record.COMMIT
11510 * Fires when the data cache has been cleared.
11511 * @param {Store} this
11515 * @event beforeload
11516 * Fires before a request is made for a new data object. If the beforeload handler returns false
11517 * the load action will be canceled.
11518 * @param {Store} this
11519 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11523 * @event beforeloadadd
11524 * Fires after a new set of Records has been loaded.
11525 * @param {Store} this
11526 * @param {Roo.data.Record[]} records The Records that were loaded
11527 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11529 beforeloadadd : true,
11532 * Fires after a new set of Records has been loaded, before they are added to the store.
11533 * @param {Store} this
11534 * @param {Roo.data.Record[]} records The Records that were loaded
11535 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11536 * @params {Object} return from reader
11540 * @event loadexception
11541 * Fires if an exception occurs in the Proxy during loading.
11542 * Called with the signature of the Proxy's "loadexception" event.
11543 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
11546 * @param {Object} return from JsonData.reader() - success, totalRecords, records
11547 * @param {Object} load options
11548 * @param {Object} jsonData from your request (normally this contains the Exception)
11550 loadexception : true
11554 this.proxy = Roo.factory(this.proxy, Roo.data);
11555 this.proxy.xmodule = this.xmodule || false;
11556 this.relayEvents(this.proxy, ["loadexception"]);
11558 this.sortToggle = {};
11559 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
11561 Roo.data.Store.superclass.constructor.call(this);
11563 if(this.inlineData){
11564 this.loadData(this.inlineData);
11565 delete this.inlineData;
11569 Roo.extend(Roo.data.Store, Roo.util.Observable, {
11571 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
11572 * without a remote query - used by combo/forms at present.
11576 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
11579 * @cfg {Array} data Inline data to be loaded when the store is initialized.
11582 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
11583 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
11586 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
11587 * on any HTTP request
11590 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
11593 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
11597 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
11598 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
11600 remoteSort : false,
11603 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
11604 * loaded or when a record is removed. (defaults to false).
11606 pruneModifiedRecords : false,
11609 lastOptions : null,
11612 * Add Records to the Store and fires the add event.
11613 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11615 add : function(records){
11616 records = [].concat(records);
11617 for(var i = 0, len = records.length; i < len; i++){
11618 records[i].join(this);
11620 var index = this.data.length;
11621 this.data.addAll(records);
11622 this.fireEvent("add", this, records, index);
11626 * Remove a Record from the Store and fires the remove event.
11627 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
11629 remove : function(record){
11630 var index = this.data.indexOf(record);
11631 this.data.removeAt(index);
11633 if(this.pruneModifiedRecords){
11634 this.modified.remove(record);
11636 this.fireEvent("remove", this, record, index);
11640 * Remove all Records from the Store and fires the clear event.
11642 removeAll : function(){
11644 if(this.pruneModifiedRecords){
11645 this.modified = [];
11647 this.fireEvent("clear", this);
11651 * Inserts Records to the Store at the given index and fires the add event.
11652 * @param {Number} index The start index at which to insert the passed Records.
11653 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11655 insert : function(index, records){
11656 records = [].concat(records);
11657 for(var i = 0, len = records.length; i < len; i++){
11658 this.data.insert(index, records[i]);
11659 records[i].join(this);
11661 this.fireEvent("add", this, records, index);
11665 * Get the index within the cache of the passed Record.
11666 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
11667 * @return {Number} The index of the passed Record. Returns -1 if not found.
11669 indexOf : function(record){
11670 return this.data.indexOf(record);
11674 * Get the index within the cache of the Record with the passed id.
11675 * @param {String} id The id of the Record to find.
11676 * @return {Number} The index of the Record. Returns -1 if not found.
11678 indexOfId : function(id){
11679 return this.data.indexOfKey(id);
11683 * Get the Record with the specified id.
11684 * @param {String} id The id of the Record to find.
11685 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
11687 getById : function(id){
11688 return this.data.key(id);
11692 * Get the Record at the specified index.
11693 * @param {Number} index The index of the Record to find.
11694 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
11696 getAt : function(index){
11697 return this.data.itemAt(index);
11701 * Returns a range of Records between specified indices.
11702 * @param {Number} startIndex (optional) The starting index (defaults to 0)
11703 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
11704 * @return {Roo.data.Record[]} An array of Records
11706 getRange : function(start, end){
11707 return this.data.getRange(start, end);
11711 storeOptions : function(o){
11712 o = Roo.apply({}, o);
11715 this.lastOptions = o;
11719 * Loads the Record cache from the configured Proxy using the configured Reader.
11721 * If using remote paging, then the first load call must specify the <em>start</em>
11722 * and <em>limit</em> properties in the options.params property to establish the initial
11723 * position within the dataset, and the number of Records to cache on each read from the Proxy.
11725 * <strong>It is important to note that for remote data sources, loading is asynchronous,
11726 * and this call will return before the new data has been loaded. Perform any post-processing
11727 * in a callback function, or in a "load" event handler.</strong>
11729 * @param {Object} options An object containing properties which control loading options:<ul>
11730 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
11731 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
11732 * passed the following arguments:<ul>
11733 * <li>r : Roo.data.Record[]</li>
11734 * <li>options: Options object from the load call</li>
11735 * <li>success: Boolean success indicator</li></ul></li>
11736 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
11737 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
11740 load : function(options){
11741 options = options || {};
11742 if(this.fireEvent("beforeload", this, options) !== false){
11743 this.storeOptions(options);
11744 var p = Roo.apply(options.params || {}, this.baseParams);
11745 // if meta was not loaded from remote source.. try requesting it.
11746 if (!this.reader.metaFromRemote) {
11747 p._requestMeta = 1;
11749 if(this.sortInfo && this.remoteSort){
11750 var pn = this.paramNames;
11751 p[pn["sort"]] = this.sortInfo.field;
11752 p[pn["dir"]] = this.sortInfo.direction;
11754 if (this.multiSort) {
11755 var pn = this.paramNames;
11756 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
11759 this.proxy.load(p, this.reader, this.loadRecords, this, options);
11764 * Reloads the Record cache from the configured Proxy using the configured Reader and
11765 * the options from the last load operation performed.
11766 * @param {Object} options (optional) An object containing properties which may override the options
11767 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
11768 * the most recently used options are reused).
11770 reload : function(options){
11771 this.load(Roo.applyIf(options||{}, this.lastOptions));
11775 // Called as a callback by the Reader during a load operation.
11776 loadRecords : function(o, options, success){
11777 if(!o || success === false){
11778 if(success !== false){
11779 this.fireEvent("load", this, [], options, o);
11781 if(options.callback){
11782 options.callback.call(options.scope || this, [], options, false);
11786 // if data returned failure - throw an exception.
11787 if (o.success === false) {
11788 // show a message if no listener is registered.
11789 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
11790 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
11792 // loadmask wil be hooked into this..
11793 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
11796 var r = o.records, t = o.totalRecords || r.length;
11798 this.fireEvent("beforeloadadd", this, r, options, o);
11800 if(!options || options.add !== true){
11801 if(this.pruneModifiedRecords){
11802 this.modified = [];
11804 for(var i = 0, len = r.length; i < len; i++){
11808 this.data = this.snapshot;
11809 delete this.snapshot;
11812 this.data.addAll(r);
11813 this.totalLength = t;
11815 this.fireEvent("datachanged", this);
11817 this.totalLength = Math.max(t, this.data.length+r.length);
11821 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
11823 var e = new Roo.data.Record({});
11825 e.set(this.parent.displayField, this.parent.emptyTitle);
11826 e.set(this.parent.valueField, '');
11831 this.fireEvent("load", this, r, options, o);
11832 if(options.callback){
11833 options.callback.call(options.scope || this, r, options, true);
11839 * Loads data from a passed data block. A Reader which understands the format of the data
11840 * must have been configured in the constructor.
11841 * @param {Object} data The data block from which to read the Records. The format of the data expected
11842 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
11843 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
11845 loadData : function(o, append){
11846 var r = this.reader.readRecords(o);
11847 this.loadRecords(r, {add: append}, true);
11851 * Gets the number of cached records.
11853 * <em>If using paging, this may not be the total size of the dataset. If the data object
11854 * used by the Reader contains the dataset size, then the getTotalCount() function returns
11855 * the data set size</em>
11857 getCount : function(){
11858 return this.data.length || 0;
11862 * Gets the total number of records in the dataset as returned by the server.
11864 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
11865 * the dataset size</em>
11867 getTotalCount : function(){
11868 return this.totalLength || 0;
11872 * Returns the sort state of the Store as an object with two properties:
11874 field {String} The name of the field by which the Records are sorted
11875 direction {String} The sort order, "ASC" or "DESC"
11878 getSortState : function(){
11879 return this.sortInfo;
11883 applySort : function(){
11884 if(this.sortInfo && !this.remoteSort){
11885 var s = this.sortInfo, f = s.field;
11886 var st = this.fields.get(f).sortType;
11887 var fn = function(r1, r2){
11888 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
11889 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
11891 this.data.sort(s.direction, fn);
11892 if(this.snapshot && this.snapshot != this.data){
11893 this.snapshot.sort(s.direction, fn);
11899 * Sets the default sort column and order to be used by the next load operation.
11900 * @param {String} fieldName The name of the field to sort by.
11901 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11903 setDefaultSort : function(field, dir){
11904 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
11908 * Sort the Records.
11909 * If remote sorting is used, the sort is performed on the server, and the cache is
11910 * reloaded. If local sorting is used, the cache is sorted internally.
11911 * @param {String} fieldName The name of the field to sort by.
11912 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11914 sort : function(fieldName, dir){
11915 var f = this.fields.get(fieldName);
11917 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
11919 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
11920 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
11925 this.sortToggle[f.name] = dir;
11926 this.sortInfo = {field: f.name, direction: dir};
11927 if(!this.remoteSort){
11929 this.fireEvent("datachanged", this);
11931 this.load(this.lastOptions);
11936 * Calls the specified function for each of the Records in the cache.
11937 * @param {Function} fn The function to call. The Record is passed as the first parameter.
11938 * Returning <em>false</em> aborts and exits the iteration.
11939 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
11941 each : function(fn, scope){
11942 this.data.each(fn, scope);
11946 * Gets all records modified since the last commit. Modified records are persisted across load operations
11947 * (e.g., during paging).
11948 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
11950 getModifiedRecords : function(){
11951 return this.modified;
11955 createFilterFn : function(property, value, anyMatch){
11956 if(!value.exec){ // not a regex
11957 value = String(value);
11958 if(value.length == 0){
11961 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
11963 return function(r){
11964 return value.test(r.data[property]);
11969 * Sums the value of <i>property</i> for each record between start and end and returns the result.
11970 * @param {String} property A field on your records
11971 * @param {Number} start The record index to start at (defaults to 0)
11972 * @param {Number} end The last record index to include (defaults to length - 1)
11973 * @return {Number} The sum
11975 sum : function(property, start, end){
11976 var rs = this.data.items, v = 0;
11977 start = start || 0;
11978 end = (end || end === 0) ? end : rs.length-1;
11980 for(var i = start; i <= end; i++){
11981 v += (rs[i].data[property] || 0);
11987 * Filter the records by a specified property.
11988 * @param {String} field A field on your records
11989 * @param {String/RegExp} value Either a string that the field
11990 * should start with or a RegExp to test against the field
11991 * @param {Boolean} anyMatch True to match any part not just the beginning
11993 filter : function(property, value, anyMatch){
11994 var fn = this.createFilterFn(property, value, anyMatch);
11995 return fn ? this.filterBy(fn) : this.clearFilter();
11999 * Filter by a function. The specified function will be called with each
12000 * record in this data source. If the function returns true the record is included,
12001 * otherwise it is filtered.
12002 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
12003 * @param {Object} scope (optional) The scope of the function (defaults to this)
12005 filterBy : function(fn, scope){
12006 this.snapshot = this.snapshot || this.data;
12007 this.data = this.queryBy(fn, scope||this);
12008 this.fireEvent("datachanged", this);
12012 * Query the records by a specified property.
12013 * @param {String} field A field on your records
12014 * @param {String/RegExp} value Either a string that the field
12015 * should start with or a RegExp to test against the field
12016 * @param {Boolean} anyMatch True to match any part not just the beginning
12017 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
12019 query : function(property, value, anyMatch){
12020 var fn = this.createFilterFn(property, value, anyMatch);
12021 return fn ? this.queryBy(fn) : this.data.clone();
12025 * Query by a function. The specified function will be called with each
12026 * record in this data source. If the function returns true the record is included
12028 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
12029 * @param {Object} scope (optional) The scope of the function (defaults to this)
12030 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
12032 queryBy : function(fn, scope){
12033 var data = this.snapshot || this.data;
12034 return data.filterBy(fn, scope||this);
12038 * Collects unique values for a particular dataIndex from this store.
12039 * @param {String} dataIndex The property to collect
12040 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
12041 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
12042 * @return {Array} An array of the unique values
12044 collect : function(dataIndex, allowNull, bypassFilter){
12045 var d = (bypassFilter === true && this.snapshot) ?
12046 this.snapshot.items : this.data.items;
12047 var v, sv, r = [], l = {};
12048 for(var i = 0, len = d.length; i < len; i++){
12049 v = d[i].data[dataIndex];
12051 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
12060 * Revert to a view of the Record cache with no filtering applied.
12061 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
12063 clearFilter : function(suppressEvent){
12064 if(this.snapshot && this.snapshot != this.data){
12065 this.data = this.snapshot;
12066 delete this.snapshot;
12067 if(suppressEvent !== true){
12068 this.fireEvent("datachanged", this);
12074 afterEdit : function(record){
12075 if(this.modified.indexOf(record) == -1){
12076 this.modified.push(record);
12078 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
12082 afterReject : function(record){
12083 this.modified.remove(record);
12084 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
12088 afterCommit : function(record){
12089 this.modified.remove(record);
12090 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
12094 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
12095 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
12097 commitChanges : function(){
12098 var m = this.modified.slice(0);
12099 this.modified = [];
12100 for(var i = 0, len = m.length; i < len; i++){
12106 * Cancel outstanding changes on all changed records.
12108 rejectChanges : function(){
12109 var m = this.modified.slice(0);
12110 this.modified = [];
12111 for(var i = 0, len = m.length; i < len; i++){
12116 onMetaChange : function(meta, rtype, o){
12117 this.recordType = rtype;
12118 this.fields = rtype.prototype.fields;
12119 delete this.snapshot;
12120 this.sortInfo = meta.sortInfo || this.sortInfo;
12121 this.modified = [];
12122 this.fireEvent('metachange', this, this.reader.meta);
12125 moveIndex : function(data, type)
12127 var index = this.indexOf(data);
12129 var newIndex = index + type;
12133 this.insert(newIndex, data);
12138 * Ext JS Library 1.1.1
12139 * Copyright(c) 2006-2007, Ext JS, LLC.
12141 * Originally Released Under LGPL - original licence link has changed is not relivant.
12144 * <script type="text/javascript">
12148 * @class Roo.data.SimpleStore
12149 * @extends Roo.data.Store
12150 * Small helper class to make creating Stores from Array data easier.
12151 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
12152 * @cfg {Array} fields An array of field definition objects, or field name strings.
12153 * @cfg {Array} data The multi-dimensional array of data
12155 * @param {Object} config
12157 Roo.data.SimpleStore = function(config){
12158 Roo.data.SimpleStore.superclass.constructor.call(this, {
12160 reader: new Roo.data.ArrayReader({
12163 Roo.data.Record.create(config.fields)
12165 proxy : new Roo.data.MemoryProxy(config.data)
12169 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
12171 * Ext JS Library 1.1.1
12172 * Copyright(c) 2006-2007, Ext JS, LLC.
12174 * Originally Released Under LGPL - original licence link has changed is not relivant.
12177 * <script type="text/javascript">
12182 * @extends Roo.data.Store
12183 * @class Roo.data.JsonStore
12184 * Small helper class to make creating Stores for JSON data easier. <br/>
12186 var store = new Roo.data.JsonStore({
12187 url: 'get-images.php',
12189 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
12192 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
12193 * JsonReader and HttpProxy (unless inline data is provided).</b>
12194 * @cfg {Array} fields An array of field definition objects, or field name strings.
12196 * @param {Object} config
12198 Roo.data.JsonStore = function(c){
12199 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
12200 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
12201 reader: new Roo.data.JsonReader(c, c.fields)
12204 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
12206 * Ext JS Library 1.1.1
12207 * Copyright(c) 2006-2007, Ext JS, LLC.
12209 * Originally Released Under LGPL - original licence link has changed is not relivant.
12212 * <script type="text/javascript">
12216 Roo.data.Field = function(config){
12217 if(typeof config == "string"){
12218 config = {name: config};
12220 Roo.apply(this, config);
12223 this.type = "auto";
12226 var st = Roo.data.SortTypes;
12227 // named sortTypes are supported, here we look them up
12228 if(typeof this.sortType == "string"){
12229 this.sortType = st[this.sortType];
12232 // set default sortType for strings and dates
12233 if(!this.sortType){
12236 this.sortType = st.asUCString;
12239 this.sortType = st.asDate;
12242 this.sortType = st.none;
12247 var stripRe = /[\$,%]/g;
12249 // prebuilt conversion function for this field, instead of
12250 // switching every time we're reading a value
12252 var cv, dateFormat = this.dateFormat;
12257 cv = function(v){ return v; };
12260 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
12264 return v !== undefined && v !== null && v !== '' ?
12265 parseInt(String(v).replace(stripRe, ""), 10) : '';
12270 return v !== undefined && v !== null && v !== '' ?
12271 parseFloat(String(v).replace(stripRe, ""), 10) : '';
12276 cv = function(v){ return v === true || v === "true" || v == 1; };
12283 if(v instanceof Date){
12287 if(dateFormat == "timestamp"){
12288 return new Date(v*1000);
12290 return Date.parseDate(v, dateFormat);
12292 var parsed = Date.parse(v);
12293 return parsed ? new Date(parsed) : null;
12302 Roo.data.Field.prototype = {
12310 * Ext JS Library 1.1.1
12311 * Copyright(c) 2006-2007, Ext JS, LLC.
12313 * Originally Released Under LGPL - original licence link has changed is not relivant.
12316 * <script type="text/javascript">
12319 // Base class for reading structured data from a data source. This class is intended to be
12320 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
12323 * @class Roo.data.DataReader
12324 * Base class for reading structured data from a data source. This class is intended to be
12325 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
12328 Roo.data.DataReader = function(meta, recordType){
12332 this.recordType = recordType instanceof Array ?
12333 Roo.data.Record.create(recordType) : recordType;
12336 Roo.data.DataReader.prototype = {
12338 * Create an empty record
12339 * @param {Object} data (optional) - overlay some values
12340 * @return {Roo.data.Record} record created.
12342 newRow : function(d) {
12344 this.recordType.prototype.fields.each(function(c) {
12346 case 'int' : da[c.name] = 0; break;
12347 case 'date' : da[c.name] = new Date(); break;
12348 case 'float' : da[c.name] = 0.0; break;
12349 case 'boolean' : da[c.name] = false; break;
12350 default : da[c.name] = ""; break;
12354 return new this.recordType(Roo.apply(da, d));
12359 * Ext JS Library 1.1.1
12360 * Copyright(c) 2006-2007, Ext JS, LLC.
12362 * Originally Released Under LGPL - original licence link has changed is not relivant.
12365 * <script type="text/javascript">
12369 * @class Roo.data.DataProxy
12370 * @extends Roo.data.Observable
12371 * This class is an abstract base class for implementations which provide retrieval of
12372 * unformatted data objects.<br>
12374 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
12375 * (of the appropriate type which knows how to parse the data object) to provide a block of
12376 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
12378 * Custom implementations must implement the load method as described in
12379 * {@link Roo.data.HttpProxy#load}.
12381 Roo.data.DataProxy = function(){
12384 * @event beforeload
12385 * Fires before a network request is made to retrieve a data object.
12386 * @param {Object} This DataProxy object.
12387 * @param {Object} params The params parameter to the load function.
12392 * Fires before the load method's callback is called.
12393 * @param {Object} This DataProxy object.
12394 * @param {Object} o The data object.
12395 * @param {Object} arg The callback argument object passed to the load function.
12399 * @event loadexception
12400 * Fires if an Exception occurs during data retrieval.
12401 * @param {Object} This DataProxy object.
12402 * @param {Object} o The data object.
12403 * @param {Object} arg The callback argument object passed to the load function.
12404 * @param {Object} e The Exception.
12406 loadexception : true
12408 Roo.data.DataProxy.superclass.constructor.call(this);
12411 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
12414 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
12418 * Ext JS Library 1.1.1
12419 * Copyright(c) 2006-2007, Ext JS, LLC.
12421 * Originally Released Under LGPL - original licence link has changed is not relivant.
12424 * <script type="text/javascript">
12427 * @class Roo.data.MemoryProxy
12428 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
12429 * to the Reader when its load method is called.
12431 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
12433 Roo.data.MemoryProxy = function(data){
12437 Roo.data.MemoryProxy.superclass.constructor.call(this);
12441 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
12444 * Load data from the requested source (in this case an in-memory
12445 * data object passed to the constructor), read the data object into
12446 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12447 * process that block using the passed callback.
12448 * @param {Object} params This parameter is not used by the MemoryProxy class.
12449 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12450 * object into a block of Roo.data.Records.
12451 * @param {Function} callback The function into which to pass the block of Roo.data.records.
12452 * The function must be passed <ul>
12453 * <li>The Record block object</li>
12454 * <li>The "arg" argument from the load function</li>
12455 * <li>A boolean success indicator</li>
12457 * @param {Object} scope The scope in which to call the callback
12458 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12460 load : function(params, reader, callback, scope, arg){
12461 params = params || {};
12464 result = reader.readRecords(params.data ? params.data :this.data);
12466 this.fireEvent("loadexception", this, arg, null, e);
12467 callback.call(scope, null, arg, false);
12470 callback.call(scope, result, arg, true);
12474 update : function(params, records){
12479 * Ext JS Library 1.1.1
12480 * Copyright(c) 2006-2007, Ext JS, LLC.
12482 * Originally Released Under LGPL - original licence link has changed is not relivant.
12485 * <script type="text/javascript">
12488 * @class Roo.data.HttpProxy
12489 * @extends Roo.data.DataProxy
12490 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
12491 * configured to reference a certain URL.<br><br>
12493 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
12494 * from which the running page was served.<br><br>
12496 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
12498 * Be aware that to enable the browser to parse an XML document, the server must set
12499 * the Content-Type header in the HTTP response to "text/xml".
12501 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
12502 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
12503 * will be used to make the request.
12505 Roo.data.HttpProxy = function(conn){
12506 Roo.data.HttpProxy.superclass.constructor.call(this);
12507 // is conn a conn config or a real conn?
12509 this.useAjax = !conn || !conn.events;
12513 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
12514 // thse are take from connection...
12517 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
12520 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
12521 * extra parameters to each request made by this object. (defaults to undefined)
12524 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
12525 * to each request made by this object. (defaults to undefined)
12528 * @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)
12531 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
12534 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
12540 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
12544 * Return the {@link Roo.data.Connection} object being used by this Proxy.
12545 * @return {Connection} The Connection object. This object may be used to subscribe to events on
12546 * a finer-grained basis than the DataProxy events.
12548 getConnection : function(){
12549 return this.useAjax ? Roo.Ajax : this.conn;
12553 * Load data from the configured {@link Roo.data.Connection}, read the data object into
12554 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
12555 * process that block using the passed callback.
12556 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12557 * for the request to the remote server.
12558 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12559 * object into a block of Roo.data.Records.
12560 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12561 * The function must be passed <ul>
12562 * <li>The Record block object</li>
12563 * <li>The "arg" argument from the load function</li>
12564 * <li>A boolean success indicator</li>
12566 * @param {Object} scope The scope in which to call the callback
12567 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12569 load : function(params, reader, callback, scope, arg){
12570 if(this.fireEvent("beforeload", this, params) !== false){
12572 params : params || {},
12574 callback : callback,
12579 callback : this.loadResponse,
12583 Roo.applyIf(o, this.conn);
12584 if(this.activeRequest){
12585 Roo.Ajax.abort(this.activeRequest);
12587 this.activeRequest = Roo.Ajax.request(o);
12589 this.conn.request(o);
12592 callback.call(scope||this, null, arg, false);
12597 loadResponse : function(o, success, response){
12598 delete this.activeRequest;
12600 this.fireEvent("loadexception", this, o, response);
12601 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12606 result = o.reader.read(response);
12608 this.fireEvent("loadexception", this, o, response, e);
12609 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12613 this.fireEvent("load", this, o, o.request.arg);
12614 o.request.callback.call(o.request.scope, result, o.request.arg, true);
12618 update : function(dataSet){
12623 updateResponse : function(dataSet){
12628 * Ext JS Library 1.1.1
12629 * Copyright(c) 2006-2007, Ext JS, LLC.
12631 * Originally Released Under LGPL - original licence link has changed is not relivant.
12634 * <script type="text/javascript">
12638 * @class Roo.data.ScriptTagProxy
12639 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
12640 * other than the originating domain of the running page.<br><br>
12642 * <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
12643 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
12645 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
12646 * source code that is used as the source inside a <script> tag.<br><br>
12648 * In order for the browser to process the returned data, the server must wrap the data object
12649 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
12650 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
12651 * depending on whether the callback name was passed:
12654 boolean scriptTag = false;
12655 String cb = request.getParameter("callback");
12658 response.setContentType("text/javascript");
12660 response.setContentType("application/x-json");
12662 Writer out = response.getWriter();
12664 out.write(cb + "(");
12666 out.print(dataBlock.toJsonString());
12673 * @param {Object} config A configuration object.
12675 Roo.data.ScriptTagProxy = function(config){
12676 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
12677 Roo.apply(this, config);
12678 this.head = document.getElementsByTagName("head")[0];
12681 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
12683 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
12685 * @cfg {String} url The URL from which to request the data object.
12688 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
12692 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
12693 * the server the name of the callback function set up by the load call to process the returned data object.
12694 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
12695 * javascript output which calls this named function passing the data object as its only parameter.
12697 callbackParam : "callback",
12699 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
12700 * name to the request.
12705 * Load data from the configured URL, read the data object into
12706 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12707 * process that block using the passed callback.
12708 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12709 * for the request to the remote server.
12710 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12711 * object into a block of Roo.data.Records.
12712 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12713 * The function must be passed <ul>
12714 * <li>The Record block object</li>
12715 * <li>The "arg" argument from the load function</li>
12716 * <li>A boolean success indicator</li>
12718 * @param {Object} scope The scope in which to call the callback
12719 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12721 load : function(params, reader, callback, scope, arg){
12722 if(this.fireEvent("beforeload", this, params) !== false){
12724 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
12726 var url = this.url;
12727 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
12729 url += "&_dc=" + (new Date().getTime());
12731 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
12734 cb : "stcCallback"+transId,
12735 scriptId : "stcScript"+transId,
12739 callback : callback,
12745 window[trans.cb] = function(o){
12746 conn.handleResponse(o, trans);
12749 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
12751 if(this.autoAbort !== false){
12755 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
12757 var script = document.createElement("script");
12758 script.setAttribute("src", url);
12759 script.setAttribute("type", "text/javascript");
12760 script.setAttribute("id", trans.scriptId);
12761 this.head.appendChild(script);
12763 this.trans = trans;
12765 callback.call(scope||this, null, arg, false);
12770 isLoading : function(){
12771 return this.trans ? true : false;
12775 * Abort the current server request.
12777 abort : function(){
12778 if(this.isLoading()){
12779 this.destroyTrans(this.trans);
12784 destroyTrans : function(trans, isLoaded){
12785 this.head.removeChild(document.getElementById(trans.scriptId));
12786 clearTimeout(trans.timeoutId);
12788 window[trans.cb] = undefined;
12790 delete window[trans.cb];
12793 // if hasn't been loaded, wait for load to remove it to prevent script error
12794 window[trans.cb] = function(){
12795 window[trans.cb] = undefined;
12797 delete window[trans.cb];
12804 handleResponse : function(o, trans){
12805 this.trans = false;
12806 this.destroyTrans(trans, true);
12809 result = trans.reader.readRecords(o);
12811 this.fireEvent("loadexception", this, o, trans.arg, e);
12812 trans.callback.call(trans.scope||window, null, trans.arg, false);
12815 this.fireEvent("load", this, o, trans.arg);
12816 trans.callback.call(trans.scope||window, result, trans.arg, true);
12820 handleFailure : function(trans){
12821 this.trans = false;
12822 this.destroyTrans(trans, false);
12823 this.fireEvent("loadexception", this, null, trans.arg);
12824 trans.callback.call(trans.scope||window, null, trans.arg, false);
12828 * Ext JS Library 1.1.1
12829 * Copyright(c) 2006-2007, Ext JS, LLC.
12831 * Originally Released Under LGPL - original licence link has changed is not relivant.
12834 * <script type="text/javascript">
12838 * @class Roo.data.JsonReader
12839 * @extends Roo.data.DataReader
12840 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
12841 * based on mappings in a provided Roo.data.Record constructor.
12843 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
12844 * in the reply previously.
12849 var RecordDef = Roo.data.Record.create([
12850 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
12851 {name: 'occupation'} // This field will use "occupation" as the mapping.
12853 var myReader = new Roo.data.JsonReader({
12854 totalProperty: "results", // The property which contains the total dataset size (optional)
12855 root: "rows", // The property which contains an Array of row objects
12856 id: "id" // The property within each row object that provides an ID for the record (optional)
12860 * This would consume a JSON file like this:
12862 { 'results': 2, 'rows': [
12863 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
12864 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
12867 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
12868 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
12869 * paged from the remote server.
12870 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
12871 * @cfg {String} root name of the property which contains the Array of row objects.
12872 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
12873 * @cfg {Array} fields Array of field definition objects
12875 * Create a new JsonReader
12876 * @param {Object} meta Metadata configuration options
12877 * @param {Object} recordType Either an Array of field definition objects,
12878 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
12880 Roo.data.JsonReader = function(meta, recordType){
12883 // set some defaults:
12884 Roo.applyIf(meta, {
12885 totalProperty: 'total',
12886 successProperty : 'success',
12891 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
12893 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
12896 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
12897 * Used by Store query builder to append _requestMeta to params.
12900 metaFromRemote : false,
12902 * This method is only used by a DataProxy which has retrieved data from a remote server.
12903 * @param {Object} response The XHR object which contains the JSON data in its responseText.
12904 * @return {Object} data A data block which is used by an Roo.data.Store object as
12905 * a cache of Roo.data.Records.
12907 read : function(response){
12908 var json = response.responseText;
12910 var o = /* eval:var:o */ eval("("+json+")");
12912 throw {message: "JsonReader.read: Json object not found"};
12918 this.metaFromRemote = true;
12919 this.meta = o.metaData;
12920 this.recordType = Roo.data.Record.create(o.metaData.fields);
12921 this.onMetaChange(this.meta, this.recordType, o);
12923 return this.readRecords(o);
12926 // private function a store will implement
12927 onMetaChange : function(meta, recordType, o){
12934 simpleAccess: function(obj, subsc) {
12941 getJsonAccessor: function(){
12943 return function(expr) {
12945 return(re.test(expr))
12946 ? new Function("obj", "return obj." + expr)
12951 return Roo.emptyFn;
12956 * Create a data block containing Roo.data.Records from an XML document.
12957 * @param {Object} o An object which contains an Array of row objects in the property specified
12958 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
12959 * which contains the total size of the dataset.
12960 * @return {Object} data A data block which is used by an Roo.data.Store object as
12961 * a cache of Roo.data.Records.
12963 readRecords : function(o){
12965 * After any data loads, the raw JSON data is available for further custom processing.
12969 var s = this.meta, Record = this.recordType,
12970 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
12972 // Generate extraction functions for the totalProperty, the root, the id, and for each field
12974 if(s.totalProperty) {
12975 this.getTotal = this.getJsonAccessor(s.totalProperty);
12977 if(s.successProperty) {
12978 this.getSuccess = this.getJsonAccessor(s.successProperty);
12980 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
12982 var g = this.getJsonAccessor(s.id);
12983 this.getId = function(rec) {
12985 return (r === undefined || r === "") ? null : r;
12988 this.getId = function(){return null;};
12991 for(var jj = 0; jj < fl; jj++){
12993 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
12994 this.ef[jj] = this.getJsonAccessor(map);
12998 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
12999 if(s.totalProperty){
13000 var vt = parseInt(this.getTotal(o), 10);
13005 if(s.successProperty){
13006 var vs = this.getSuccess(o);
13007 if(vs === false || vs === 'false'){
13012 for(var i = 0; i < c; i++){
13015 var id = this.getId(n);
13016 for(var j = 0; j < fl; j++){
13018 var v = this.ef[j](n);
13020 Roo.log('missing convert for ' + f.name);
13024 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
13026 var record = new Record(values, id);
13028 records[i] = record;
13034 totalRecords : totalRecords
13039 * Ext JS Library 1.1.1
13040 * Copyright(c) 2006-2007, Ext JS, LLC.
13042 * Originally Released Under LGPL - original licence link has changed is not relivant.
13045 * <script type="text/javascript">
13049 * @class Roo.data.ArrayReader
13050 * @extends Roo.data.DataReader
13051 * Data reader class to create an Array of Roo.data.Record objects from an Array.
13052 * Each element of that Array represents a row of data fields. The
13053 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
13054 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
13058 var RecordDef = Roo.data.Record.create([
13059 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
13060 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
13062 var myReader = new Roo.data.ArrayReader({
13063 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
13067 * This would consume an Array like this:
13069 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
13073 * Create a new JsonReader
13074 * @param {Object} meta Metadata configuration options.
13075 * @param {Object|Array} recordType Either an Array of field definition objects
13077 * @cfg {Array} fields Array of field definition objects
13078 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
13079 * as specified to {@link Roo.data.Record#create},
13080 * or an {@link Roo.data.Record} object
13083 * created using {@link Roo.data.Record#create}.
13085 Roo.data.ArrayReader = function(meta, recordType){
13088 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType||meta.fields);
13091 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
13093 * Create a data block containing Roo.data.Records from an XML document.
13094 * @param {Object} o An Array of row objects which represents the dataset.
13095 * @return {Object} A data block which is used by an {@link Roo.data.Store} object as
13096 * a cache of Roo.data.Records.
13098 readRecords : function(o){
13099 var sid = this.meta ? this.meta.id : null;
13100 var recordType = this.recordType, fields = recordType.prototype.fields;
13103 for(var i = 0; i < root.length; i++){
13106 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
13107 for(var j = 0, jlen = fields.length; j < jlen; j++){
13108 var f = fields.items[j];
13109 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
13110 var v = n[k] !== undefined ? n[k] : f.defaultValue;
13112 values[f.name] = v;
13114 var record = new recordType(values, id);
13116 records[records.length] = record;
13120 totalRecords : records.length
13129 * @class Roo.bootstrap.ComboBox
13130 * @extends Roo.bootstrap.TriggerField
13131 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
13132 * @cfg {Boolean} append (true|false) default false
13133 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
13134 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
13135 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
13136 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
13137 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
13138 * @cfg {Boolean} animate default true
13139 * @cfg {Boolean} emptyResultText only for touch device
13140 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
13141 * @cfg {String} emptyTitle default ''
13143 * Create a new ComboBox.
13144 * @param {Object} config Configuration options
13146 Roo.bootstrap.ComboBox = function(config){
13147 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
13151 * Fires when the dropdown list is expanded
13152 * @param {Roo.bootstrap.ComboBox} combo This combo box
13157 * Fires when the dropdown list is collapsed
13158 * @param {Roo.bootstrap.ComboBox} combo This combo box
13162 * @event beforeselect
13163 * Fires before a list item is selected. Return false to cancel the selection.
13164 * @param {Roo.bootstrap.ComboBox} combo This combo box
13165 * @param {Roo.data.Record} record The data record returned from the underlying store
13166 * @param {Number} index The index of the selected item in the dropdown list
13168 'beforeselect' : true,
13171 * Fires when a list item is selected
13172 * @param {Roo.bootstrap.ComboBox} combo This combo box
13173 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
13174 * @param {Number} index The index of the selected item in the dropdown list
13178 * @event beforequery
13179 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
13180 * The event object passed has these properties:
13181 * @param {Roo.bootstrap.ComboBox} combo This combo box
13182 * @param {String} query The query
13183 * @param {Boolean} forceAll true to force "all" query
13184 * @param {Boolean} cancel true to cancel the query
13185 * @param {Object} e The query event object
13187 'beforequery': true,
13190 * Fires when the 'add' icon is pressed (add a listener to enable add button)
13191 * @param {Roo.bootstrap.ComboBox} combo This combo box
13196 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
13197 * @param {Roo.bootstrap.ComboBox} combo This combo box
13198 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
13203 * Fires when the remove value from the combobox array
13204 * @param {Roo.bootstrap.ComboBox} combo This combo box
13208 * @event afterremove
13209 * Fires when the remove value from the combobox array
13210 * @param {Roo.bootstrap.ComboBox} combo This combo box
13212 'afterremove' : true,
13214 * @event specialfilter
13215 * Fires when specialfilter
13216 * @param {Roo.bootstrap.ComboBox} combo This combo box
13218 'specialfilter' : true,
13221 * Fires when tick the element
13222 * @param {Roo.bootstrap.ComboBox} combo This combo box
13226 * @event touchviewdisplay
13227 * Fires when touch view require special display (default is using displayField)
13228 * @param {Roo.bootstrap.ComboBox} combo This combo box
13229 * @param {Object} cfg set html .
13231 'touchviewdisplay' : true
13236 this.tickItems = [];
13238 this.selectedIndex = -1;
13239 if(this.mode == 'local'){
13240 if(config.queryDelay === undefined){
13241 this.queryDelay = 10;
13243 if(config.minChars === undefined){
13249 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
13252 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
13253 * rendering into an Roo.Editor, defaults to false)
13256 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
13257 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
13260 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
13263 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
13264 * the dropdown list (defaults to undefined, with no header element)
13268 * @cfg {String/Roo.Template} tpl The template to use to render the output
13272 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
13274 listWidth: undefined,
13276 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
13277 * mode = 'remote' or 'text' if mode = 'local')
13279 displayField: undefined,
13282 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
13283 * mode = 'remote' or 'value' if mode = 'local').
13284 * Note: use of a valueField requires the user make a selection
13285 * in order for a value to be mapped.
13287 valueField: undefined,
13289 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
13294 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
13295 * field's data value (defaults to the underlying DOM element's name)
13297 hiddenName: undefined,
13299 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
13303 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
13305 selectedClass: 'active',
13308 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
13312 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
13313 * anchor positions (defaults to 'tl-bl')
13315 listAlign: 'tl-bl?',
13317 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
13321 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
13322 * query specified by the allQuery config option (defaults to 'query')
13324 triggerAction: 'query',
13326 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
13327 * (defaults to 4, does not apply if editable = false)
13331 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
13332 * delay (typeAheadDelay) if it matches a known value (defaults to false)
13336 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
13337 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
13341 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
13342 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
13346 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
13347 * when editable = true (defaults to false)
13349 selectOnFocus:false,
13351 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
13353 queryParam: 'query',
13355 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
13356 * when mode = 'remote' (defaults to 'Loading...')
13358 loadingText: 'Loading...',
13360 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
13364 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
13368 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
13369 * traditional select (defaults to true)
13373 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
13377 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
13381 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
13382 * listWidth has a higher value)
13386 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
13387 * allow the user to set arbitrary text into the field (defaults to false)
13389 forceSelection:false,
13391 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
13392 * if typeAhead = true (defaults to 250)
13394 typeAheadDelay : 250,
13396 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
13397 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
13399 valueNotFoundText : undefined,
13401 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
13403 blockFocus : false,
13406 * @cfg {Boolean} disableClear Disable showing of clear button.
13408 disableClear : false,
13410 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
13412 alwaysQuery : false,
13415 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
13420 * @cfg {String} invalidClass DEPRICATED - uses BS4 is-valid now
13422 invalidClass : "has-warning",
13425 * @cfg {String} validClass DEPRICATED - uses BS4 is-valid now
13427 validClass : "has-success",
13430 * @cfg {Boolean} specialFilter (true|false) special filter default false
13432 specialFilter : false,
13435 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
13437 mobileTouchView : true,
13440 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
13442 useNativeIOS : false,
13445 * @cfg {Boolean} mobile_restrict_height (true|false) restrict height for touch view
13447 mobile_restrict_height : false,
13449 ios_options : false,
13461 btnPosition : 'right',
13462 triggerList : true,
13463 showToggleBtn : true,
13465 emptyResultText: 'Empty',
13466 triggerText : 'Select',
13469 // element that contains real text value.. (when hidden is used..)
13471 getAutoCreate : function()
13476 * Render classic select for iso
13479 if(Roo.isIOS && this.useNativeIOS){
13480 cfg = this.getAutoCreateNativeIOS();
13488 if(Roo.isTouch && this.mobileTouchView){
13489 cfg = this.getAutoCreateTouchView();
13496 if(!this.tickable){
13497 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
13502 * ComboBox with tickable selections
13505 var align = this.labelAlign || this.parentLabelAlign();
13508 cls : 'form-group roo-combobox-tickable' //input-group
13511 var btn_text_select = '';
13512 var btn_text_done = '';
13513 var btn_text_cancel = '';
13515 if (this.btn_text_show) {
13516 btn_text_select = 'Select';
13517 btn_text_done = 'Done';
13518 btn_text_cancel = 'Cancel';
13523 cls : 'tickable-buttons',
13528 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
13529 //html : this.triggerText
13530 html: btn_text_select
13536 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
13538 html: btn_text_done
13544 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
13546 html: btn_text_cancel
13552 buttons.cn.unshift({
13554 cls: 'roo-select2-search-field-input'
13560 Roo.each(buttons.cn, function(c){
13562 c.cls += ' btn-' + _this.size;
13565 if (_this.disabled) {
13572 style : 'display: contents',
13577 cls: 'form-hidden-field'
13581 cls: 'roo-select2-choices',
13585 cls: 'roo-select2-search-field',
13596 cls: 'roo-select2-container input-group roo-select2-container-multi',
13602 // cls: 'typeahead typeahead-long dropdown-menu',
13603 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
13608 if(this.hasFeedback && !this.allowBlank){
13612 cls: 'glyphicon form-control-feedback'
13615 combobox.cn.push(feedback);
13620 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
13621 tooltip : 'This field is required'
13623 if (Roo.bootstrap.version == 4) {
13626 style : 'display:none'
13629 if (align ==='left' && this.fieldLabel.length) {
13631 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
13638 cls : 'control-label col-form-label',
13639 html : this.fieldLabel
13651 var labelCfg = cfg.cn[1];
13652 var contentCfg = cfg.cn[2];
13655 if(this.indicatorpos == 'right'){
13661 cls : 'control-label col-form-label',
13665 html : this.fieldLabel
13681 labelCfg = cfg.cn[0];
13682 contentCfg = cfg.cn[1];
13686 if(this.labelWidth > 12){
13687 labelCfg.style = "width: " + this.labelWidth + 'px';
13690 if(this.labelWidth < 13 && this.labelmd == 0){
13691 this.labelmd = this.labelWidth;
13694 if(this.labellg > 0){
13695 labelCfg.cls += ' col-lg-' + this.labellg;
13696 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
13699 if(this.labelmd > 0){
13700 labelCfg.cls += ' col-md-' + this.labelmd;
13701 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
13704 if(this.labelsm > 0){
13705 labelCfg.cls += ' col-sm-' + this.labelsm;
13706 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
13709 if(this.labelxs > 0){
13710 labelCfg.cls += ' col-xs-' + this.labelxs;
13711 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
13715 } else if ( this.fieldLabel.length) {
13716 // Roo.log(" label");
13721 //cls : 'input-group-addon',
13722 html : this.fieldLabel
13727 if(this.indicatorpos == 'right'){
13731 //cls : 'input-group-addon',
13732 html : this.fieldLabel
13742 // Roo.log(" no label && no align");
13749 ['xs','sm','md','lg'].map(function(size){
13750 if (settings[size]) {
13751 cfg.cls += ' col-' + size + '-' + settings[size];
13759 _initEventsCalled : false,
13762 initEvents: function()
13764 if (this._initEventsCalled) { // as we call render... prevent looping...
13767 this._initEventsCalled = true;
13770 throw "can not find store for combo";
13773 this.indicator = this.indicatorEl();
13775 this.store = Roo.factory(this.store, Roo.data);
13776 this.store.parent = this;
13778 // if we are building from html. then this element is so complex, that we can not really
13779 // use the rendered HTML.
13780 // so we have to trash and replace the previous code.
13781 if (Roo.XComponent.build_from_html) {
13782 // remove this element....
13783 var e = this.el.dom, k=0;
13784 while (e ) { e = e.previousSibling; ++k;}
13789 this.rendered = false;
13791 this.render(this.parent().getChildContainer(true), k);
13794 if(Roo.isIOS && this.useNativeIOS){
13795 this.initIOSView();
13803 if(Roo.isTouch && this.mobileTouchView){
13804 this.initTouchView();
13809 this.initTickableEvents();
13813 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
13815 if(this.hiddenName){
13817 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13819 this.hiddenField.dom.value =
13820 this.hiddenValue !== undefined ? this.hiddenValue :
13821 this.value !== undefined ? this.value : '';
13823 // prevent input submission
13824 this.el.dom.removeAttribute('name');
13825 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13830 // this.el.dom.setAttribute('autocomplete', 'off');
13833 var cls = 'x-combo-list';
13835 //this.list = new Roo.Layer({
13836 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
13842 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13843 _this.list.setWidth(lw);
13846 this.list.on('mouseover', this.onViewOver, this);
13847 this.list.on('mousemove', this.onViewMove, this);
13848 this.list.on('scroll', this.onViewScroll, this);
13851 this.list.swallowEvent('mousewheel');
13852 this.assetHeight = 0;
13855 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
13856 this.assetHeight += this.header.getHeight();
13859 this.innerList = this.list.createChild({cls:cls+'-inner'});
13860 this.innerList.on('mouseover', this.onViewOver, this);
13861 this.innerList.on('mousemove', this.onViewMove, this);
13862 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13864 if(this.allowBlank && !this.pageSize && !this.disableClear){
13865 this.footer = this.list.createChild({cls:cls+'-ft'});
13866 this.pageTb = new Roo.Toolbar(this.footer);
13870 this.footer = this.list.createChild({cls:cls+'-ft'});
13871 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
13872 {pageSize: this.pageSize});
13876 if (this.pageTb && this.allowBlank && !this.disableClear) {
13878 this.pageTb.add(new Roo.Toolbar.Fill(), {
13879 cls: 'x-btn-icon x-btn-clear',
13881 handler: function()
13884 _this.clearValue();
13885 _this.onSelect(false, -1);
13890 this.assetHeight += this.footer.getHeight();
13895 this.tpl = Roo.bootstrap.version == 4 ?
13896 '<a class="dropdown-item" href="#">{' + this.displayField + '}</a>' : // 4 does not need <li> and it get's really confisued.
13897 '<li><a class="dropdown-item" href="#">{' + this.displayField + '}</a></li>';
13900 this.view = new Roo.View(this.list, this.tpl, {
13901 singleSelect:true, store: this.store, selectedClass: this.selectedClass
13903 //this.view.wrapEl.setDisplayed(false);
13904 this.view.on('click', this.onViewClick, this);
13907 this.store.on('beforeload', this.onBeforeLoad, this);
13908 this.store.on('load', this.onLoad, this);
13909 this.store.on('loadexception', this.onLoadException, this);
13911 if(this.resizable){
13912 this.resizer = new Roo.Resizable(this.list, {
13913 pinned:true, handles:'se'
13915 this.resizer.on('resize', function(r, w, h){
13916 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
13917 this.listWidth = w;
13918 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
13919 this.restrictHeight();
13921 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
13924 if(!this.editable){
13925 this.editable = true;
13926 this.setEditable(false);
13931 if (typeof(this.events.add.listeners) != 'undefined') {
13933 this.addicon = this.wrap.createChild(
13934 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
13936 this.addicon.on('click', function(e) {
13937 this.fireEvent('add', this);
13940 if (typeof(this.events.edit.listeners) != 'undefined') {
13942 this.editicon = this.wrap.createChild(
13943 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
13944 if (this.addicon) {
13945 this.editicon.setStyle('margin-left', '40px');
13947 this.editicon.on('click', function(e) {
13949 // we fire even if inothing is selected..
13950 this.fireEvent('edit', this, this.lastData );
13956 this.keyNav = new Roo.KeyNav(this.inputEl(), {
13957 "up" : function(e){
13958 this.inKeyMode = true;
13962 "down" : function(e){
13963 if(!this.isExpanded()){
13964 this.onTriggerClick();
13966 this.inKeyMode = true;
13971 "enter" : function(e){
13972 // this.onViewClick();
13976 if(this.fireEvent("specialkey", this, e)){
13977 this.onViewClick(false);
13983 "esc" : function(e){
13987 "tab" : function(e){
13990 if(this.fireEvent("specialkey", this, e)){
13991 this.onViewClick(false);
13999 doRelay : function(foo, bar, hname){
14000 if(hname == 'down' || this.scope.isExpanded()){
14001 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
14010 this.queryDelay = Math.max(this.queryDelay || 10,
14011 this.mode == 'local' ? 10 : 250);
14014 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
14016 if(this.typeAhead){
14017 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
14019 if(this.editable !== false){
14020 this.inputEl().on("keyup", this.onKeyUp, this);
14022 if(this.forceSelection){
14023 this.inputEl().on('blur', this.doForce, this);
14027 this.choices = this.el.select('ul.roo-select2-choices', true).first();
14028 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
14032 initTickableEvents: function()
14036 if(this.hiddenName){
14038 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
14040 this.hiddenField.dom.value =
14041 this.hiddenValue !== undefined ? this.hiddenValue :
14042 this.value !== undefined ? this.value : '';
14044 // prevent input submission
14045 this.el.dom.removeAttribute('name');
14046 this.hiddenField.dom.setAttribute('name', this.hiddenName);
14051 // this.list = this.el.select('ul.dropdown-menu',true).first();
14053 this.choices = this.el.select('ul.roo-select2-choices', true).first();
14054 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
14055 if(this.triggerList){
14056 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
14059 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
14060 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
14062 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
14063 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
14065 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
14066 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
14068 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
14069 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
14070 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
14073 this.cancelBtn.hide();
14078 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
14079 _this.list.setWidth(lw);
14082 this.list.on('mouseover', this.onViewOver, this);
14083 this.list.on('mousemove', this.onViewMove, this);
14085 this.list.on('scroll', this.onViewScroll, this);
14088 this.tpl = '<li class="roo-select2-result"><div class="checkbox"><input id="{roo-id}"' +
14089 'type="checkbox" {roo-data-checked}><label for="{roo-id}"><b>{' + this.displayField + '}</b></label></div></li>';
14092 this.view = new Roo.View(this.list, this.tpl, {
14097 selectedClass: this.selectedClass
14100 //this.view.wrapEl.setDisplayed(false);
14101 this.view.on('click', this.onViewClick, this);
14105 this.store.on('beforeload', this.onBeforeLoad, this);
14106 this.store.on('load', this.onLoad, this);
14107 this.store.on('loadexception', this.onLoadException, this);
14110 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
14111 "up" : function(e){
14112 this.inKeyMode = true;
14116 "down" : function(e){
14117 this.inKeyMode = true;
14121 "enter" : function(e){
14122 if(this.fireEvent("specialkey", this, e)){
14123 this.onViewClick(false);
14129 "esc" : function(e){
14130 this.onTickableFooterButtonClick(e, false, false);
14133 "tab" : function(e){
14134 this.fireEvent("specialkey", this, e);
14136 this.onTickableFooterButtonClick(e, false, false);
14143 doRelay : function(e, fn, key){
14144 if(this.scope.isExpanded()){
14145 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
14154 this.queryDelay = Math.max(this.queryDelay || 10,
14155 this.mode == 'local' ? 10 : 250);
14158 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
14160 if(this.typeAhead){
14161 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
14164 if(this.editable !== false){
14165 this.tickableInputEl().on("keyup", this.onKeyUp, this);
14168 this.indicator = this.indicatorEl();
14170 if(this.indicator){
14171 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
14172 this.indicator.hide();
14177 onDestroy : function(){
14179 this.view.setStore(null);
14180 this.view.el.removeAllListeners();
14181 this.view.el.remove();
14182 this.view.purgeListeners();
14185 this.list.dom.innerHTML = '';
14189 this.store.un('beforeload', this.onBeforeLoad, this);
14190 this.store.un('load', this.onLoad, this);
14191 this.store.un('loadexception', this.onLoadException, this);
14193 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
14197 fireKey : function(e){
14198 if(e.isNavKeyPress() && !this.list.isVisible()){
14199 this.fireEvent("specialkey", this, e);
14204 onResize: function(w, h){
14205 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
14207 // if(typeof w != 'number'){
14208 // // we do not handle it!?!?
14211 // var tw = this.trigger.getWidth();
14212 // // tw += this.addicon ? this.addicon.getWidth() : 0;
14213 // // tw += this.editicon ? this.editicon.getWidth() : 0;
14215 // this.inputEl().setWidth( this.adjustWidth('input', x));
14217 // //this.trigger.setStyle('left', x+'px');
14219 // if(this.list && this.listWidth === undefined){
14220 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
14221 // this.list.setWidth(lw);
14222 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
14230 * Allow or prevent the user from directly editing the field text. If false is passed,
14231 * the user will only be able to select from the items defined in the dropdown list. This method
14232 * is the runtime equivalent of setting the 'editable' config option at config time.
14233 * @param {Boolean} value True to allow the user to directly edit the field text
14235 setEditable : function(value){
14236 if(value == this.editable){
14239 this.editable = value;
14241 this.inputEl().dom.setAttribute('readOnly', true);
14242 this.inputEl().on('mousedown', this.onTriggerClick, this);
14243 this.inputEl().addClass('x-combo-noedit');
14245 this.inputEl().dom.setAttribute('readOnly', false);
14246 this.inputEl().un('mousedown', this.onTriggerClick, this);
14247 this.inputEl().removeClass('x-combo-noedit');
14253 onBeforeLoad : function(combo,opts){
14254 if(!this.hasFocus){
14258 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
14260 this.restrictHeight();
14261 this.selectedIndex = -1;
14265 onLoad : function(){
14267 this.hasQuery = false;
14269 if(!this.hasFocus){
14273 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
14274 this.loading.hide();
14277 if(this.store.getCount() > 0){
14280 this.restrictHeight();
14281 if(this.lastQuery == this.allQuery){
14282 if(this.editable && !this.tickable){
14283 this.inputEl().dom.select();
14287 !this.selectByValue(this.value, true) &&
14290 !this.store.lastOptions ||
14291 typeof(this.store.lastOptions.add) == 'undefined' ||
14292 this.store.lastOptions.add != true
14295 this.select(0, true);
14298 if(this.autoFocus){
14301 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
14302 this.taTask.delay(this.typeAheadDelay);
14306 this.onEmptyResults();
14312 onLoadException : function()
14314 this.hasQuery = false;
14316 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
14317 this.loading.hide();
14320 if(this.tickable && this.editable){
14325 // only causes errors at present
14326 //Roo.log(this.store.reader.jsonData);
14327 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
14329 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
14335 onTypeAhead : function(){
14336 if(this.store.getCount() > 0){
14337 var r = this.store.getAt(0);
14338 var newValue = r.data[this.displayField];
14339 var len = newValue.length;
14340 var selStart = this.getRawValue().length;
14342 if(selStart != len){
14343 this.setRawValue(newValue);
14344 this.selectText(selStart, newValue.length);
14350 onSelect : function(record, index){
14352 if(this.fireEvent('beforeselect', this, record, index) !== false){
14354 this.setFromData(index > -1 ? record.data : false);
14357 this.fireEvent('select', this, record, index);
14362 * Returns the currently selected field value or empty string if no value is set.
14363 * @return {String} value The selected value
14365 getValue : function()
14367 if(Roo.isIOS && this.useNativeIOS){
14368 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
14372 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
14375 if(this.valueField){
14376 return typeof this.value != 'undefined' ? this.value : '';
14378 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
14382 getRawValue : function()
14384 if(Roo.isIOS && this.useNativeIOS){
14385 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
14388 var v = this.inputEl().getValue();
14394 * Clears any text/value currently set in the field
14396 clearValue : function(){
14398 if(this.hiddenField){
14399 this.hiddenField.dom.value = '';
14402 this.setRawValue('');
14403 this.lastSelectionText = '';
14404 this.lastData = false;
14406 var close = this.closeTriggerEl();
14417 * Sets the specified value into the field. If the value finds a match, the corresponding record text
14418 * will be displayed in the field. If the value does not match the data value of an existing item,
14419 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
14420 * Otherwise the field will be blank (although the value will still be set).
14421 * @param {String} value The value to match
14423 setValue : function(v)
14425 if(Roo.isIOS && this.useNativeIOS){
14426 this.setIOSValue(v);
14436 if(this.valueField){
14437 var r = this.findRecord(this.valueField, v);
14439 text = r.data[this.displayField];
14440 }else if(this.valueNotFoundText !== undefined){
14441 text = this.valueNotFoundText;
14444 this.lastSelectionText = text;
14445 if(this.hiddenField){
14446 this.hiddenField.dom.value = v;
14448 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
14451 var close = this.closeTriggerEl();
14454 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
14460 * @property {Object} the last set data for the element
14465 * Sets the value of the field based on a object which is related to the record format for the store.
14466 * @param {Object} value the value to set as. or false on reset?
14468 setFromData : function(o){
14475 var dv = ''; // display value
14476 var vv = ''; // value value..
14478 if (this.displayField) {
14479 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14481 // this is an error condition!!!
14482 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14485 if(this.valueField){
14486 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
14489 var close = this.closeTriggerEl();
14492 if(dv.length || vv * 1 > 0){
14494 this.blockFocus=true;
14500 if(this.hiddenField){
14501 this.hiddenField.dom.value = vv;
14503 this.lastSelectionText = dv;
14504 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14508 // no hidden field.. - we store the value in 'value', but still display
14509 // display field!!!!
14510 this.lastSelectionText = dv;
14511 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14518 reset : function(){
14519 // overridden so that last data is reset..
14526 this.setValue(this.originalValue);
14527 //this.clearInvalid();
14528 this.lastData = false;
14530 this.view.clearSelections();
14536 findRecord : function(prop, value){
14538 if(this.store.getCount() > 0){
14539 this.store.each(function(r){
14540 if(r.data[prop] == value){
14550 getName: function()
14552 // returns hidden if it's set..
14553 if (!this.rendered) {return ''};
14554 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
14558 onViewMove : function(e, t){
14559 this.inKeyMode = false;
14563 onViewOver : function(e, t){
14564 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
14567 var item = this.view.findItemFromChild(t);
14570 var index = this.view.indexOf(item);
14571 this.select(index, false);
14576 onViewClick : function(view, doFocus, el, e)
14578 var index = this.view.getSelectedIndexes()[0];
14580 var r = this.store.getAt(index);
14584 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
14591 Roo.each(this.tickItems, function(v,k){
14593 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
14595 _this.tickItems.splice(k, 1);
14597 if(typeof(e) == 'undefined' && view == false){
14598 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
14610 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
14611 this.tickItems.push(r.data);
14614 if(typeof(e) == 'undefined' && view == false){
14615 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
14622 this.onSelect(r, index);
14624 if(doFocus !== false && !this.blockFocus){
14625 this.inputEl().focus();
14630 restrictHeight : function(){
14631 //this.innerList.dom.style.height = '';
14632 //var inner = this.innerList.dom;
14633 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
14634 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
14635 //this.list.beginUpdate();
14636 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
14637 this.list.alignTo(this.inputEl(), this.listAlign);
14638 this.list.alignTo(this.inputEl(), this.listAlign);
14639 //this.list.endUpdate();
14643 onEmptyResults : function(){
14645 if(this.tickable && this.editable){
14646 this.hasFocus = false;
14647 this.restrictHeight();
14655 * Returns true if the dropdown list is expanded, else false.
14657 isExpanded : function(){
14658 return this.list.isVisible();
14662 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
14663 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14664 * @param {String} value The data value of the item to select
14665 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14666 * selected item if it is not currently in view (defaults to true)
14667 * @return {Boolean} True if the value matched an item in the list, else false
14669 selectByValue : function(v, scrollIntoView){
14670 if(v !== undefined && v !== null){
14671 var r = this.findRecord(this.valueField || this.displayField, v);
14673 this.select(this.store.indexOf(r), scrollIntoView);
14681 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
14682 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14683 * @param {Number} index The zero-based index of the list item to select
14684 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14685 * selected item if it is not currently in view (defaults to true)
14687 select : function(index, scrollIntoView){
14688 this.selectedIndex = index;
14689 this.view.select(index);
14690 if(scrollIntoView !== false){
14691 var el = this.view.getNode(index);
14693 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
14696 this.list.scrollChildIntoView(el, false);
14702 selectNext : function(){
14703 var ct = this.store.getCount();
14705 if(this.selectedIndex == -1){
14707 }else if(this.selectedIndex < ct-1){
14708 this.select(this.selectedIndex+1);
14714 selectPrev : function(){
14715 var ct = this.store.getCount();
14717 if(this.selectedIndex == -1){
14719 }else if(this.selectedIndex != 0){
14720 this.select(this.selectedIndex-1);
14726 onKeyUp : function(e){
14727 if(this.editable !== false && !e.isSpecialKey()){
14728 this.lastKey = e.getKey();
14729 this.dqTask.delay(this.queryDelay);
14734 validateBlur : function(){
14735 return !this.list || !this.list.isVisible();
14739 initQuery : function(){
14741 var v = this.getRawValue();
14743 if(this.tickable && this.editable){
14744 v = this.tickableInputEl().getValue();
14751 doForce : function(){
14752 if(this.inputEl().dom.value.length > 0){
14753 this.inputEl().dom.value =
14754 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
14760 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
14761 * query allowing the query action to be canceled if needed.
14762 * @param {String} query The SQL query to execute
14763 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
14764 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
14765 * saved in the current store (defaults to false)
14767 doQuery : function(q, forceAll){
14769 if(q === undefined || q === null){
14774 forceAll: forceAll,
14778 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
14783 forceAll = qe.forceAll;
14784 if(forceAll === true || (q.length >= this.minChars)){
14786 this.hasQuery = true;
14788 if(this.lastQuery != q || this.alwaysQuery){
14789 this.lastQuery = q;
14790 if(this.mode == 'local'){
14791 this.selectedIndex = -1;
14793 this.store.clearFilter();
14796 if(this.specialFilter){
14797 this.fireEvent('specialfilter', this);
14802 this.store.filter(this.displayField, q);
14805 this.store.fireEvent("datachanged", this.store);
14812 this.store.baseParams[this.queryParam] = q;
14814 var options = {params : this.getParams(q)};
14817 options.add = true;
14818 options.params.start = this.page * this.pageSize;
14821 this.store.load(options);
14824 * this code will make the page width larger, at the beginning, the list not align correctly,
14825 * we should expand the list on onLoad
14826 * so command out it
14831 this.selectedIndex = -1;
14836 this.loadNext = false;
14840 getParams : function(q){
14842 //p[this.queryParam] = q;
14846 p.limit = this.pageSize;
14852 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
14854 collapse : function(){
14855 if(!this.isExpanded()){
14861 this.hasFocus = false;
14865 this.cancelBtn.hide();
14866 this.trigger.show();
14869 this.tickableInputEl().dom.value = '';
14870 this.tickableInputEl().blur();
14875 Roo.get(document).un('mousedown', this.collapseIf, this);
14876 Roo.get(document).un('mousewheel', this.collapseIf, this);
14877 if (!this.editable) {
14878 Roo.get(document).un('keydown', this.listKeyPress, this);
14880 this.fireEvent('collapse', this);
14886 collapseIf : function(e){
14887 var in_combo = e.within(this.el);
14888 var in_list = e.within(this.list);
14889 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
14891 if (in_combo || in_list || is_list) {
14892 //e.stopPropagation();
14897 this.onTickableFooterButtonClick(e, false, false);
14905 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
14907 expand : function(){
14909 if(this.isExpanded() || !this.hasFocus){
14913 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
14914 this.list.setWidth(lw);
14920 this.restrictHeight();
14924 this.tickItems = Roo.apply([], this.item);
14927 this.cancelBtn.show();
14928 this.trigger.hide();
14931 this.tickableInputEl().focus();
14936 Roo.get(document).on('mousedown', this.collapseIf, this);
14937 Roo.get(document).on('mousewheel', this.collapseIf, this);
14938 if (!this.editable) {
14939 Roo.get(document).on('keydown', this.listKeyPress, this);
14942 this.fireEvent('expand', this);
14946 // Implements the default empty TriggerField.onTriggerClick function
14947 onTriggerClick : function(e)
14949 Roo.log('trigger click');
14951 if(this.disabled || !this.triggerList){
14956 this.loadNext = false;
14958 if(this.isExpanded()){
14960 if (!this.blockFocus) {
14961 this.inputEl().focus();
14965 this.hasFocus = true;
14966 if(this.triggerAction == 'all') {
14967 this.doQuery(this.allQuery, true);
14969 this.doQuery(this.getRawValue());
14971 if (!this.blockFocus) {
14972 this.inputEl().focus();
14977 onTickableTriggerClick : function(e)
14984 this.loadNext = false;
14985 this.hasFocus = true;
14987 if(this.triggerAction == 'all') {
14988 this.doQuery(this.allQuery, true);
14990 this.doQuery(this.getRawValue());
14994 onSearchFieldClick : function(e)
14996 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
14997 this.onTickableFooterButtonClick(e, false, false);
15001 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
15006 this.loadNext = false;
15007 this.hasFocus = true;
15009 if(this.triggerAction == 'all') {
15010 this.doQuery(this.allQuery, true);
15012 this.doQuery(this.getRawValue());
15016 listKeyPress : function(e)
15018 //Roo.log('listkeypress');
15019 // scroll to first matching element based on key pres..
15020 if (e.isSpecialKey()) {
15023 var k = String.fromCharCode(e.getKey()).toUpperCase();
15026 var csel = this.view.getSelectedNodes();
15027 var cselitem = false;
15029 var ix = this.view.indexOf(csel[0]);
15030 cselitem = this.store.getAt(ix);
15031 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
15037 this.store.each(function(v) {
15039 // start at existing selection.
15040 if (cselitem.id == v.id) {
15046 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
15047 match = this.store.indexOf(v);
15053 if (match === false) {
15054 return true; // no more action?
15057 this.view.select(match);
15058 var sn = Roo.get(this.view.getSelectedNodes()[0]);
15059 sn.scrollIntoView(sn.dom.parentNode, false);
15062 onViewScroll : function(e, t){
15064 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){
15068 this.hasQuery = true;
15070 this.loading = this.list.select('.loading', true).first();
15072 if(this.loading === null){
15073 this.list.createChild({
15075 cls: 'loading roo-select2-more-results roo-select2-active',
15076 html: 'Loading more results...'
15079 this.loading = this.list.select('.loading', true).first();
15081 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
15083 this.loading.hide();
15086 this.loading.show();
15091 this.loadNext = true;
15093 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
15098 addItem : function(o)
15100 var dv = ''; // display value
15102 if (this.displayField) {
15103 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
15105 // this is an error condition!!!
15106 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
15113 var choice = this.choices.createChild({
15115 cls: 'roo-select2-search-choice',
15124 cls: 'roo-select2-search-choice-close fa fa-times',
15129 }, this.searchField);
15131 var close = choice.select('a.roo-select2-search-choice-close', true).first();
15133 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
15141 this.inputEl().dom.value = '';
15146 onRemoveItem : function(e, _self, o)
15148 e.preventDefault();
15150 this.lastItem = Roo.apply([], this.item);
15152 var index = this.item.indexOf(o.data) * 1;
15155 Roo.log('not this item?!');
15159 this.item.splice(index, 1);
15164 this.fireEvent('remove', this, e);
15170 syncValue : function()
15172 if(!this.item.length){
15179 Roo.each(this.item, function(i){
15180 if(_this.valueField){
15181 value.push(i[_this.valueField]);
15188 this.value = value.join(',');
15190 if(this.hiddenField){
15191 this.hiddenField.dom.value = this.value;
15194 this.store.fireEvent("datachanged", this.store);
15199 clearItem : function()
15201 if(!this.multiple){
15207 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
15215 if(this.tickable && !Roo.isTouch){
15216 this.view.refresh();
15220 inputEl: function ()
15222 if(Roo.isIOS && this.useNativeIOS){
15223 return this.el.select('select.roo-ios-select', true).first();
15226 if(Roo.isTouch && this.mobileTouchView){
15227 return this.el.select('input.form-control',true).first();
15231 return this.searchField;
15234 return this.el.select('input.form-control',true).first();
15237 onTickableFooterButtonClick : function(e, btn, el)
15239 e.preventDefault();
15241 this.lastItem = Roo.apply([], this.item);
15243 if(btn && btn.name == 'cancel'){
15244 this.tickItems = Roo.apply([], this.item);
15253 Roo.each(this.tickItems, function(o){
15261 validate : function()
15263 if(this.getVisibilityEl().hasClass('hidden')){
15267 var v = this.getRawValue();
15270 v = this.getValue();
15273 if(this.disabled || this.allowBlank || v.length){
15278 this.markInvalid();
15282 tickableInputEl : function()
15284 if(!this.tickable || !this.editable){
15285 return this.inputEl();
15288 return this.inputEl().select('.roo-select2-search-field-input', true).first();
15292 getAutoCreateTouchView : function()
15297 cls: 'form-group' //input-group
15303 type : this.inputType,
15304 cls : 'form-control x-combo-noedit',
15305 autocomplete: 'new-password',
15306 placeholder : this.placeholder || '',
15311 input.name = this.name;
15315 input.cls += ' input-' + this.size;
15318 if (this.disabled) {
15319 input.disabled = true;
15330 inputblock.cls += ' input-group';
15332 inputblock.cn.unshift({
15334 cls : 'input-group-addon input-group-prepend input-group-text',
15339 if(this.removable && !this.multiple){
15340 inputblock.cls += ' roo-removable';
15342 inputblock.cn.push({
15345 cls : 'roo-combo-removable-btn close'
15349 if(this.hasFeedback && !this.allowBlank){
15351 inputblock.cls += ' has-feedback';
15353 inputblock.cn.push({
15355 cls: 'glyphicon form-control-feedback'
15362 inputblock.cls += (this.before) ? '' : ' input-group';
15364 inputblock.cn.push({
15366 cls : 'input-group-addon input-group-append input-group-text',
15372 var ibwrap = inputblock;
15377 cls: 'roo-select2-choices',
15381 cls: 'roo-select2-search-field',
15394 cls: 'roo-select2-container input-group roo-touchview-combobox ',
15399 cls: 'form-hidden-field'
15405 if(!this.multiple && this.showToggleBtn){
15411 if (this.caret != false) {
15414 cls: 'fa fa-' + this.caret
15421 cls : 'input-group-addon input-group-append input-group-text btn dropdown-toggle',
15423 Roo.bootstrap.version == 3 ? caret : '',
15426 cls: 'combobox-clear',
15440 combobox.cls += ' roo-select2-container-multi';
15443 var align = this.labelAlign || this.parentLabelAlign();
15445 if (align ==='left' && this.fieldLabel.length) {
15450 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15451 tooltip : 'This field is required'
15455 cls : 'control-label col-form-label',
15456 html : this.fieldLabel
15467 var labelCfg = cfg.cn[1];
15468 var contentCfg = cfg.cn[2];
15471 if(this.indicatorpos == 'right'){
15476 cls : 'control-label col-form-label',
15480 html : this.fieldLabel
15484 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15485 tooltip : 'This field is required'
15498 labelCfg = cfg.cn[0];
15499 contentCfg = cfg.cn[1];
15504 if(this.labelWidth > 12){
15505 labelCfg.style = "width: " + this.labelWidth + 'px';
15508 if(this.labelWidth < 13 && this.labelmd == 0){
15509 this.labelmd = this.labelWidth;
15512 if(this.labellg > 0){
15513 labelCfg.cls += ' col-lg-' + this.labellg;
15514 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
15517 if(this.labelmd > 0){
15518 labelCfg.cls += ' col-md-' + this.labelmd;
15519 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
15522 if(this.labelsm > 0){
15523 labelCfg.cls += ' col-sm-' + this.labelsm;
15524 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
15527 if(this.labelxs > 0){
15528 labelCfg.cls += ' col-xs-' + this.labelxs;
15529 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
15533 } else if ( this.fieldLabel.length) {
15537 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15538 tooltip : 'This field is required'
15542 cls : 'control-label',
15543 html : this.fieldLabel
15554 if(this.indicatorpos == 'right'){
15558 cls : 'control-label',
15559 html : this.fieldLabel,
15563 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15564 tooltip : 'This field is required'
15581 var settings = this;
15583 ['xs','sm','md','lg'].map(function(size){
15584 if (settings[size]) {
15585 cfg.cls += ' col-' + size + '-' + settings[size];
15592 initTouchView : function()
15594 this.renderTouchView();
15596 this.touchViewEl.on('scroll', function(){
15597 this.el.dom.scrollTop = 0;
15600 this.originalValue = this.getValue();
15602 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
15604 this.inputEl().on("click", this.showTouchView, this);
15605 if (this.triggerEl) {
15606 this.triggerEl.on("click", this.showTouchView, this);
15610 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
15611 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
15613 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
15615 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
15616 this.store.on('load', this.onTouchViewLoad, this);
15617 this.store.on('loadexception', this.onTouchViewLoadException, this);
15619 if(this.hiddenName){
15621 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
15623 this.hiddenField.dom.value =
15624 this.hiddenValue !== undefined ? this.hiddenValue :
15625 this.value !== undefined ? this.value : '';
15627 this.el.dom.removeAttribute('name');
15628 this.hiddenField.dom.setAttribute('name', this.hiddenName);
15632 this.choices = this.el.select('ul.roo-select2-choices', true).first();
15633 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
15636 if(this.removable && !this.multiple){
15637 var close = this.closeTriggerEl();
15639 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
15640 close.on('click', this.removeBtnClick, this, close);
15644 * fix the bug in Safari iOS8
15646 this.inputEl().on("focus", function(e){
15647 document.activeElement.blur();
15650 this._touchViewMask = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
15657 renderTouchView : function()
15659 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
15660 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15662 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
15663 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15665 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
15666 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15667 this.touchViewBodyEl.setStyle('overflow', 'auto');
15669 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
15670 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15672 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
15673 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15677 showTouchView : function()
15683 this.touchViewHeaderEl.hide();
15685 if(this.modalTitle.length){
15686 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
15687 this.touchViewHeaderEl.show();
15690 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
15691 this.touchViewEl.show();
15693 this.touchViewEl.select('.modal-dialog', true).first().setStyle({ margin : '0px', width : '100%'});
15695 //this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
15696 // Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15698 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15700 if(this.modalTitle.length){
15701 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15704 this.touchViewBodyEl.setHeight(bodyHeight);
15708 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
15710 this.touchViewEl.addClass('in');
15713 if(this._touchViewMask){
15714 Roo.get(document.body).addClass("x-body-masked");
15715 this._touchViewMask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15716 this._touchViewMask.setStyle('z-index', 10000);
15717 this._touchViewMask.addClass('show');
15720 this.doTouchViewQuery();
15724 hideTouchView : function()
15726 this.touchViewEl.removeClass('in');
15730 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
15732 this.touchViewEl.setStyle('display', 'none');
15735 if(this._touchViewMask){
15736 this._touchViewMask.removeClass('show');
15737 Roo.get(document.body).removeClass("x-body-masked");
15741 setTouchViewValue : function()
15748 Roo.each(this.tickItems, function(o){
15753 this.hideTouchView();
15756 doTouchViewQuery : function()
15765 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
15769 if(!this.alwaysQuery || this.mode == 'local'){
15770 this.onTouchViewLoad();
15777 onTouchViewBeforeLoad : function(combo,opts)
15783 onTouchViewLoad : function()
15785 if(this.store.getCount() < 1){
15786 this.onTouchViewEmptyResults();
15790 this.clearTouchView();
15792 var rawValue = this.getRawValue();
15794 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
15796 this.tickItems = [];
15798 this.store.data.each(function(d, rowIndex){
15799 var row = this.touchViewListGroup.createChild(template);
15801 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
15802 row.addClass(d.data.cls);
15805 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15808 html : d.data[this.displayField]
15811 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
15812 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
15815 row.removeClass('selected');
15816 if(!this.multiple && this.valueField &&
15817 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
15820 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15821 row.addClass('selected');
15824 if(this.multiple && this.valueField &&
15825 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
15829 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15830 this.tickItems.push(d.data);
15833 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
15837 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
15839 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15841 if(this.modalTitle.length){
15842 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15845 var listHeight = this.touchViewListGroup.getHeight() + this.touchViewBodyEl.getPadding('tb') * 2;
15847 if(this.mobile_restrict_height && listHeight < bodyHeight){
15848 this.touchViewBodyEl.setHeight(listHeight);
15853 if(firstChecked && listHeight > bodyHeight){
15854 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
15859 onTouchViewLoadException : function()
15861 this.hideTouchView();
15864 onTouchViewEmptyResults : function()
15866 this.clearTouchView();
15868 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
15870 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
15874 clearTouchView : function()
15876 this.touchViewListGroup.dom.innerHTML = '';
15879 onTouchViewClick : function(e, el, o)
15881 e.preventDefault();
15884 var rowIndex = o.rowIndex;
15886 var r = this.store.getAt(rowIndex);
15888 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
15890 if(!this.multiple){
15891 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
15892 c.dom.removeAttribute('checked');
15895 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15897 this.setFromData(r.data);
15899 var close = this.closeTriggerEl();
15905 this.hideTouchView();
15907 this.fireEvent('select', this, r, rowIndex);
15912 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
15913 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
15914 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
15918 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15919 this.addItem(r.data);
15920 this.tickItems.push(r.data);
15924 getAutoCreateNativeIOS : function()
15927 cls: 'form-group' //input-group,
15932 cls : 'roo-ios-select'
15936 combobox.name = this.name;
15939 if (this.disabled) {
15940 combobox.disabled = true;
15943 var settings = this;
15945 ['xs','sm','md','lg'].map(function(size){
15946 if (settings[size]) {
15947 cfg.cls += ' col-' + size + '-' + settings[size];
15957 initIOSView : function()
15959 this.store.on('load', this.onIOSViewLoad, this);
15964 onIOSViewLoad : function()
15966 if(this.store.getCount() < 1){
15970 this.clearIOSView();
15972 if(this.allowBlank) {
15974 var default_text = '-- SELECT --';
15976 if(this.placeholder.length){
15977 default_text = this.placeholder;
15980 if(this.emptyTitle.length){
15981 default_text += ' - ' + this.emptyTitle + ' -';
15984 var opt = this.inputEl().createChild({
15987 html : default_text
15991 o[this.valueField] = 0;
15992 o[this.displayField] = default_text;
15994 this.ios_options.push({
16001 this.store.data.each(function(d, rowIndex){
16005 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
16006 html = d.data[this.displayField];
16011 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
16012 value = d.data[this.valueField];
16021 if(this.value == d.data[this.valueField]){
16022 option['selected'] = true;
16025 var opt = this.inputEl().createChild(option);
16027 this.ios_options.push({
16034 this.inputEl().on('change', function(){
16035 this.fireEvent('select', this);
16040 clearIOSView: function()
16042 this.inputEl().dom.innerHTML = '';
16044 this.ios_options = [];
16047 setIOSValue: function(v)
16051 if(!this.ios_options){
16055 Roo.each(this.ios_options, function(opts){
16057 opts.el.dom.removeAttribute('selected');
16059 if(opts.data[this.valueField] != v){
16063 opts.el.dom.setAttribute('selected', true);
16069 * @cfg {Boolean} grow
16073 * @cfg {Number} growMin
16077 * @cfg {Number} growMax
16086 Roo.apply(Roo.bootstrap.ComboBox, {
16090 cls: 'modal-header',
16112 cls: 'list-group-item',
16116 cls: 'roo-combobox-list-group-item-value'
16120 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
16134 listItemCheckbox : {
16136 cls: 'list-group-item',
16140 cls: 'roo-combobox-list-group-item-value'
16144 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
16160 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
16165 cls: 'modal-footer',
16173 cls: 'col-xs-6 text-left',
16176 cls: 'btn btn-danger roo-touch-view-cancel',
16182 cls: 'col-xs-6 text-right',
16185 cls: 'btn btn-success roo-touch-view-ok',
16196 Roo.apply(Roo.bootstrap.ComboBox, {
16198 touchViewTemplate : {
16200 cls: 'modal fade roo-combobox-touch-view',
16204 cls: 'modal-dialog',
16205 style : 'position:fixed', // we have to fix position....
16209 cls: 'modal-content',
16211 Roo.bootstrap.ComboBox.header,
16212 Roo.bootstrap.ComboBox.body,
16213 Roo.bootstrap.ComboBox.footer
16222 * Ext JS Library 1.1.1
16223 * Copyright(c) 2006-2007, Ext JS, LLC.
16225 * Originally Released Under LGPL - original licence link has changed is not relivant.
16228 * <script type="text/javascript">
16233 * @extends Roo.util.Observable
16234 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
16235 * This class also supports single and multi selection modes. <br>
16236 * Create a data model bound view:
16238 var store = new Roo.data.Store(...);
16240 var view = new Roo.View({
16242 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
16244 singleSelect: true,
16245 selectedClass: "ydataview-selected",
16249 // listen for node click?
16250 view.on("click", function(vw, index, node, e){
16251 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
16255 dataModel.load("foobar.xml");
16257 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
16259 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
16260 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
16262 * Note: old style constructor is still suported (container, template, config)
16265 * Create a new View
16266 * @param {Object} config The config object
16269 Roo.View = function(config, depreciated_tpl, depreciated_config){
16271 this.parent = false;
16273 if (typeof(depreciated_tpl) == 'undefined') {
16274 // new way.. - universal constructor.
16275 Roo.apply(this, config);
16276 this.el = Roo.get(this.el);
16279 this.el = Roo.get(config);
16280 this.tpl = depreciated_tpl;
16281 Roo.apply(this, depreciated_config);
16283 this.wrapEl = this.el.wrap().wrap();
16284 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
16287 if(typeof(this.tpl) == "string"){
16288 this.tpl = new Roo.Template(this.tpl);
16290 // support xtype ctors..
16291 this.tpl = new Roo.factory(this.tpl, Roo);
16295 this.tpl.compile();
16300 * @event beforeclick
16301 * Fires before a click is processed. Returns false to cancel the default action.
16302 * @param {Roo.View} this
16303 * @param {Number} index The index of the target node
16304 * @param {HTMLElement} node The target node
16305 * @param {Roo.EventObject} e The raw event object
16307 "beforeclick" : true,
16310 * Fires when a template node is clicked.
16311 * @param {Roo.View} this
16312 * @param {Number} index The index of the target node
16313 * @param {HTMLElement} node The target node
16314 * @param {Roo.EventObject} e The raw event object
16319 * Fires when a template node is double clicked.
16320 * @param {Roo.View} this
16321 * @param {Number} index The index of the target node
16322 * @param {HTMLElement} node The target node
16323 * @param {Roo.EventObject} e The raw event object
16327 * @event contextmenu
16328 * Fires when a template node is right clicked.
16329 * @param {Roo.View} this
16330 * @param {Number} index The index of the target node
16331 * @param {HTMLElement} node The target node
16332 * @param {Roo.EventObject} e The raw event object
16334 "contextmenu" : true,
16336 * @event selectionchange
16337 * Fires when the selected nodes change.
16338 * @param {Roo.View} this
16339 * @param {Array} selections Array of the selected nodes
16341 "selectionchange" : true,
16344 * @event beforeselect
16345 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
16346 * @param {Roo.View} this
16347 * @param {HTMLElement} node The node to be selected
16348 * @param {Array} selections Array of currently selected nodes
16350 "beforeselect" : true,
16352 * @event preparedata
16353 * Fires on every row to render, to allow you to change the data.
16354 * @param {Roo.View} this
16355 * @param {Object} data to be rendered (change this)
16357 "preparedata" : true
16365 "click": this.onClick,
16366 "dblclick": this.onDblClick,
16367 "contextmenu": this.onContextMenu,
16371 this.selections = [];
16373 this.cmp = new Roo.CompositeElementLite([]);
16375 this.store = Roo.factory(this.store, Roo.data);
16376 this.setStore(this.store, true);
16379 if ( this.footer && this.footer.xtype) {
16381 var fctr = this.wrapEl.appendChild(document.createElement("div"));
16383 this.footer.dataSource = this.store;
16384 this.footer.container = fctr;
16385 this.footer = Roo.factory(this.footer, Roo);
16386 fctr.insertFirst(this.el);
16388 // this is a bit insane - as the paging toolbar seems to detach the el..
16389 // dom.parentNode.parentNode.parentNode
16390 // they get detached?
16394 Roo.View.superclass.constructor.call(this);
16399 Roo.extend(Roo.View, Roo.util.Observable, {
16402 * @cfg {Roo.data.Store} store Data store to load data from.
16407 * @cfg {String|Roo.Element} el The container element.
16412 * @cfg {String|Roo.Template} tpl The template used by this View
16416 * @cfg {String} dataName the named area of the template to use as the data area
16417 * Works with domtemplates roo-name="name"
16421 * @cfg {String} selectedClass The css class to add to selected nodes
16423 selectedClass : "x-view-selected",
16425 * @cfg {String} emptyText The empty text to show when nothing is loaded.
16430 * @cfg {String} text to display on mask (default Loading)
16434 * @cfg {Boolean} multiSelect Allow multiple selection
16436 multiSelect : false,
16438 * @cfg {Boolean} singleSelect Allow single selection
16440 singleSelect: false,
16443 * @cfg {Boolean} toggleSelect - selecting
16445 toggleSelect : false,
16448 * @cfg {Boolean} tickable - selecting
16453 * Returns the element this view is bound to.
16454 * @return {Roo.Element}
16456 getEl : function(){
16457 return this.wrapEl;
16463 * Refreshes the view. - called by datachanged on the store. - do not call directly.
16465 refresh : function(){
16466 //Roo.log('refresh');
16469 // if we are using something like 'domtemplate', then
16470 // the what gets used is:
16471 // t.applySubtemplate(NAME, data, wrapping data..)
16472 // the outer template then get' applied with
16473 // the store 'extra data'
16474 // and the body get's added to the
16475 // roo-name="data" node?
16476 // <span class='roo-tpl-{name}'></span> ?????
16480 this.clearSelections();
16481 this.el.update("");
16483 var records = this.store.getRange();
16484 if(records.length < 1) {
16486 // is this valid?? = should it render a template??
16488 this.el.update(this.emptyText);
16492 if (this.dataName) {
16493 this.el.update(t.apply(this.store.meta)); //????
16494 el = this.el.child('.roo-tpl-' + this.dataName);
16497 for(var i = 0, len = records.length; i < len; i++){
16498 var data = this.prepareData(records[i].data, i, records[i]);
16499 this.fireEvent("preparedata", this, data, i, records[i]);
16501 var d = Roo.apply({}, data);
16504 Roo.apply(d, {'roo-id' : Roo.id()});
16508 Roo.each(this.parent.item, function(item){
16509 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
16512 Roo.apply(d, {'roo-data-checked' : 'checked'});
16516 html[html.length] = Roo.util.Format.trim(
16518 t.applySubtemplate(this.dataName, d, this.store.meta) :
16525 el.update(html.join(""));
16526 this.nodes = el.dom.childNodes;
16527 this.updateIndexes(0);
16532 * Function to override to reformat the data that is sent to
16533 * the template for each node.
16534 * DEPRICATED - use the preparedata event handler.
16535 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
16536 * a JSON object for an UpdateManager bound view).
16538 prepareData : function(data, index, record)
16540 this.fireEvent("preparedata", this, data, index, record);
16544 onUpdate : function(ds, record){
16545 // Roo.log('on update');
16546 this.clearSelections();
16547 var index = this.store.indexOf(record);
16548 var n = this.nodes[index];
16549 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
16550 n.parentNode.removeChild(n);
16551 this.updateIndexes(index, index);
16557 onAdd : function(ds, records, index)
16559 //Roo.log(['on Add', ds, records, index] );
16560 this.clearSelections();
16561 if(this.nodes.length == 0){
16565 var n = this.nodes[index];
16566 for(var i = 0, len = records.length; i < len; i++){
16567 var d = this.prepareData(records[i].data, i, records[i]);
16569 this.tpl.insertBefore(n, d);
16572 this.tpl.append(this.el, d);
16575 this.updateIndexes(index);
16578 onRemove : function(ds, record, index){
16579 // Roo.log('onRemove');
16580 this.clearSelections();
16581 var el = this.dataName ?
16582 this.el.child('.roo-tpl-' + this.dataName) :
16585 el.dom.removeChild(this.nodes[index]);
16586 this.updateIndexes(index);
16590 * Refresh an individual node.
16591 * @param {Number} index
16593 refreshNode : function(index){
16594 this.onUpdate(this.store, this.store.getAt(index));
16597 updateIndexes : function(startIndex, endIndex){
16598 var ns = this.nodes;
16599 startIndex = startIndex || 0;
16600 endIndex = endIndex || ns.length - 1;
16601 for(var i = startIndex; i <= endIndex; i++){
16602 ns[i].nodeIndex = i;
16607 * Changes the data store this view uses and refresh the view.
16608 * @param {Store} store
16610 setStore : function(store, initial){
16611 if(!initial && this.store){
16612 this.store.un("datachanged", this.refresh);
16613 this.store.un("add", this.onAdd);
16614 this.store.un("remove", this.onRemove);
16615 this.store.un("update", this.onUpdate);
16616 this.store.un("clear", this.refresh);
16617 this.store.un("beforeload", this.onBeforeLoad);
16618 this.store.un("load", this.onLoad);
16619 this.store.un("loadexception", this.onLoad);
16623 store.on("datachanged", this.refresh, this);
16624 store.on("add", this.onAdd, this);
16625 store.on("remove", this.onRemove, this);
16626 store.on("update", this.onUpdate, this);
16627 store.on("clear", this.refresh, this);
16628 store.on("beforeload", this.onBeforeLoad, this);
16629 store.on("load", this.onLoad, this);
16630 store.on("loadexception", this.onLoad, this);
16638 * onbeforeLoad - masks the loading area.
16641 onBeforeLoad : function(store,opts)
16643 //Roo.log('onBeforeLoad');
16645 this.el.update("");
16647 this.el.mask(this.mask ? this.mask : "Loading" );
16649 onLoad : function ()
16656 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
16657 * @param {HTMLElement} node
16658 * @return {HTMLElement} The template node
16660 findItemFromChild : function(node){
16661 var el = this.dataName ?
16662 this.el.child('.roo-tpl-' + this.dataName,true) :
16665 if(!node || node.parentNode == el){
16668 var p = node.parentNode;
16669 while(p && p != el){
16670 if(p.parentNode == el){
16679 onClick : function(e){
16680 var item = this.findItemFromChild(e.getTarget());
16682 var index = this.indexOf(item);
16683 if(this.onItemClick(item, index, e) !== false){
16684 this.fireEvent("click", this, index, item, e);
16687 this.clearSelections();
16692 onContextMenu : function(e){
16693 var item = this.findItemFromChild(e.getTarget());
16695 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
16700 onDblClick : function(e){
16701 var item = this.findItemFromChild(e.getTarget());
16703 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
16707 onItemClick : function(item, index, e)
16709 if(this.fireEvent("beforeclick", this, index, item, e) === false){
16712 if (this.toggleSelect) {
16713 var m = this.isSelected(item) ? 'unselect' : 'select';
16716 _t[m](item, true, false);
16719 if(this.multiSelect || this.singleSelect){
16720 if(this.multiSelect && e.shiftKey && this.lastSelection){
16721 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
16723 this.select(item, this.multiSelect && e.ctrlKey);
16724 this.lastSelection = item;
16727 if(!this.tickable){
16728 e.preventDefault();
16736 * Get the number of selected nodes.
16739 getSelectionCount : function(){
16740 return this.selections.length;
16744 * Get the currently selected nodes.
16745 * @return {Array} An array of HTMLElements
16747 getSelectedNodes : function(){
16748 return this.selections;
16752 * Get the indexes of the selected nodes.
16755 getSelectedIndexes : function(){
16756 var indexes = [], s = this.selections;
16757 for(var i = 0, len = s.length; i < len; i++){
16758 indexes.push(s[i].nodeIndex);
16764 * Clear all selections
16765 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
16767 clearSelections : function(suppressEvent){
16768 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
16769 this.cmp.elements = this.selections;
16770 this.cmp.removeClass(this.selectedClass);
16771 this.selections = [];
16772 if(!suppressEvent){
16773 this.fireEvent("selectionchange", this, this.selections);
16779 * Returns true if the passed node is selected
16780 * @param {HTMLElement/Number} node The node or node index
16781 * @return {Boolean}
16783 isSelected : function(node){
16784 var s = this.selections;
16788 node = this.getNode(node);
16789 return s.indexOf(node) !== -1;
16794 * @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
16795 * @param {Boolean} keepExisting (optional) true to keep existing selections
16796 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16798 select : function(nodeInfo, keepExisting, suppressEvent){
16799 if(nodeInfo instanceof Array){
16801 this.clearSelections(true);
16803 for(var i = 0, len = nodeInfo.length; i < len; i++){
16804 this.select(nodeInfo[i], true, true);
16808 var node = this.getNode(nodeInfo);
16809 if(!node || this.isSelected(node)){
16810 return; // already selected.
16813 this.clearSelections(true);
16816 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
16817 Roo.fly(node).addClass(this.selectedClass);
16818 this.selections.push(node);
16819 if(!suppressEvent){
16820 this.fireEvent("selectionchange", this, this.selections);
16828 * @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
16829 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
16830 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16832 unselect : function(nodeInfo, keepExisting, suppressEvent)
16834 if(nodeInfo instanceof Array){
16835 Roo.each(this.selections, function(s) {
16836 this.unselect(s, nodeInfo);
16840 var node = this.getNode(nodeInfo);
16841 if(!node || !this.isSelected(node)){
16842 //Roo.log("not selected");
16843 return; // not selected.
16847 Roo.each(this.selections, function(s) {
16849 Roo.fly(node).removeClass(this.selectedClass);
16856 this.selections= ns;
16857 this.fireEvent("selectionchange", this, this.selections);
16861 * Gets a template node.
16862 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16863 * @return {HTMLElement} The node or null if it wasn't found
16865 getNode : function(nodeInfo){
16866 if(typeof nodeInfo == "string"){
16867 return document.getElementById(nodeInfo);
16868 }else if(typeof nodeInfo == "number"){
16869 return this.nodes[nodeInfo];
16875 * Gets a range template nodes.
16876 * @param {Number} startIndex
16877 * @param {Number} endIndex
16878 * @return {Array} An array of nodes
16880 getNodes : function(start, end){
16881 var ns = this.nodes;
16882 start = start || 0;
16883 end = typeof end == "undefined" ? ns.length - 1 : end;
16886 for(var i = start; i <= end; i++){
16890 for(var i = start; i >= end; i--){
16898 * Finds the index of the passed node
16899 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16900 * @return {Number} The index of the node or -1
16902 indexOf : function(node){
16903 node = this.getNode(node);
16904 if(typeof node.nodeIndex == "number"){
16905 return node.nodeIndex;
16907 var ns = this.nodes;
16908 for(var i = 0, len = ns.length; i < len; i++){
16919 * based on jquery fullcalendar
16923 Roo.bootstrap = Roo.bootstrap || {};
16925 * @class Roo.bootstrap.Calendar
16926 * @extends Roo.bootstrap.Component
16927 * Bootstrap Calendar class
16928 * @cfg {Boolean} loadMask (true|false) default false
16929 * @cfg {Object} header generate the user specific header of the calendar, default false
16932 * Create a new Container
16933 * @param {Object} config The config object
16938 Roo.bootstrap.Calendar = function(config){
16939 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
16943 * Fires when a date is selected
16944 * @param {DatePicker} this
16945 * @param {Date} date The selected date
16949 * @event monthchange
16950 * Fires when the displayed month changes
16951 * @param {DatePicker} this
16952 * @param {Date} date The selected month
16954 'monthchange': true,
16956 * @event evententer
16957 * Fires when mouse over an event
16958 * @param {Calendar} this
16959 * @param {event} Event
16961 'evententer': true,
16963 * @event eventleave
16964 * Fires when the mouse leaves an
16965 * @param {Calendar} this
16968 'eventleave': true,
16970 * @event eventclick
16971 * Fires when the mouse click an
16972 * @param {Calendar} this
16981 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
16984 * @cfg {Number} startDay
16985 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16993 getAutoCreate : function(){
16996 var fc_button = function(name, corner, style, content ) {
16997 return Roo.apply({},{
16999 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
17001 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
17004 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
17015 style : 'width:100%',
17022 cls : 'fc-header-left',
17024 fc_button('prev', 'left', 'arrow', '‹' ),
17025 fc_button('next', 'right', 'arrow', '›' ),
17026 { tag: 'span', cls: 'fc-header-space' },
17027 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
17035 cls : 'fc-header-center',
17039 cls: 'fc-header-title',
17042 html : 'month / year'
17050 cls : 'fc-header-right',
17052 /* fc_button('month', 'left', '', 'month' ),
17053 fc_button('week', '', '', 'week' ),
17054 fc_button('day', 'right', '', 'day' )
17066 header = this.header;
17069 var cal_heads = function() {
17071 // fixme - handle this.
17073 for (var i =0; i < Date.dayNames.length; i++) {
17074 var d = Date.dayNames[i];
17077 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
17078 html : d.substring(0,3)
17082 ret[0].cls += ' fc-first';
17083 ret[6].cls += ' fc-last';
17086 var cal_cell = function(n) {
17089 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
17094 cls: 'fc-day-number',
17098 cls: 'fc-day-content',
17102 style: 'position: relative;' // height: 17px;
17114 var cal_rows = function() {
17117 for (var r = 0; r < 6; r++) {
17124 for (var i =0; i < Date.dayNames.length; i++) {
17125 var d = Date.dayNames[i];
17126 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
17129 row.cn[0].cls+=' fc-first';
17130 row.cn[0].cn[0].style = 'min-height:90px';
17131 row.cn[6].cls+=' fc-last';
17135 ret[0].cls += ' fc-first';
17136 ret[4].cls += ' fc-prev-last';
17137 ret[5].cls += ' fc-last';
17144 cls: 'fc-border-separate',
17145 style : 'width:100%',
17153 cls : 'fc-first fc-last',
17171 cls : 'fc-content',
17172 style : "position: relative;",
17175 cls : 'fc-view fc-view-month fc-grid',
17176 style : 'position: relative',
17177 unselectable : 'on',
17180 cls : 'fc-event-container',
17181 style : 'position:absolute;z-index:8;top:0;left:0;'
17199 initEvents : function()
17202 throw "can not find store for calendar";
17208 style: "text-align:center",
17212 style: "background-color:white;width:50%;margin:250 auto",
17216 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
17227 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
17229 var size = this.el.select('.fc-content', true).first().getSize();
17230 this.maskEl.setSize(size.width, size.height);
17231 this.maskEl.enableDisplayMode("block");
17232 if(!this.loadMask){
17233 this.maskEl.hide();
17236 this.store = Roo.factory(this.store, Roo.data);
17237 this.store.on('load', this.onLoad, this);
17238 this.store.on('beforeload', this.onBeforeLoad, this);
17242 this.cells = this.el.select('.fc-day',true);
17243 //Roo.log(this.cells);
17244 this.textNodes = this.el.query('.fc-day-number');
17245 this.cells.addClassOnOver('fc-state-hover');
17247 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
17248 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
17249 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
17250 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
17252 this.on('monthchange', this.onMonthChange, this);
17254 this.update(new Date().clearTime());
17257 resize : function() {
17258 var sz = this.el.getSize();
17260 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
17261 this.el.select('.fc-day-content div',true).setHeight(34);
17266 showPrevMonth : function(e){
17267 this.update(this.activeDate.add("mo", -1));
17269 showToday : function(e){
17270 this.update(new Date().clearTime());
17273 showNextMonth : function(e){
17274 this.update(this.activeDate.add("mo", 1));
17278 showPrevYear : function(){
17279 this.update(this.activeDate.add("y", -1));
17283 showNextYear : function(){
17284 this.update(this.activeDate.add("y", 1));
17289 update : function(date)
17291 var vd = this.activeDate;
17292 this.activeDate = date;
17293 // if(vd && this.el){
17294 // var t = date.getTime();
17295 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
17296 // Roo.log('using add remove');
17298 // this.fireEvent('monthchange', this, date);
17300 // this.cells.removeClass("fc-state-highlight");
17301 // this.cells.each(function(c){
17302 // if(c.dateValue == t){
17303 // c.addClass("fc-state-highlight");
17304 // setTimeout(function(){
17305 // try{c.dom.firstChild.focus();}catch(e){}
17315 var days = date.getDaysInMonth();
17317 var firstOfMonth = date.getFirstDateOfMonth();
17318 var startingPos = firstOfMonth.getDay()-this.startDay;
17320 if(startingPos < this.startDay){
17324 var pm = date.add(Date.MONTH, -1);
17325 var prevStart = pm.getDaysInMonth()-startingPos;
17327 this.cells = this.el.select('.fc-day',true);
17328 this.textNodes = this.el.query('.fc-day-number');
17329 this.cells.addClassOnOver('fc-state-hover');
17331 var cells = this.cells.elements;
17332 var textEls = this.textNodes;
17334 Roo.each(cells, function(cell){
17335 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
17338 days += startingPos;
17340 // convert everything to numbers so it's fast
17341 var day = 86400000;
17342 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
17345 //Roo.log(prevStart);
17347 var today = new Date().clearTime().getTime();
17348 var sel = date.clearTime().getTime();
17349 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
17350 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
17351 var ddMatch = this.disabledDatesRE;
17352 var ddText = this.disabledDatesText;
17353 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
17354 var ddaysText = this.disabledDaysText;
17355 var format = this.format;
17357 var setCellClass = function(cal, cell){
17361 //Roo.log('set Cell Class');
17363 var t = d.getTime();
17367 cell.dateValue = t;
17369 cell.className += " fc-today";
17370 cell.className += " fc-state-highlight";
17371 cell.title = cal.todayText;
17374 // disable highlight in other month..
17375 //cell.className += " fc-state-highlight";
17380 cell.className = " fc-state-disabled";
17381 cell.title = cal.minText;
17385 cell.className = " fc-state-disabled";
17386 cell.title = cal.maxText;
17390 if(ddays.indexOf(d.getDay()) != -1){
17391 cell.title = ddaysText;
17392 cell.className = " fc-state-disabled";
17395 if(ddMatch && format){
17396 var fvalue = d.dateFormat(format);
17397 if(ddMatch.test(fvalue)){
17398 cell.title = ddText.replace("%0", fvalue);
17399 cell.className = " fc-state-disabled";
17403 if (!cell.initialClassName) {
17404 cell.initialClassName = cell.dom.className;
17407 cell.dom.className = cell.initialClassName + ' ' + cell.className;
17412 for(; i < startingPos; i++) {
17413 textEls[i].innerHTML = (++prevStart);
17414 d.setDate(d.getDate()+1);
17416 cells[i].className = "fc-past fc-other-month";
17417 setCellClass(this, cells[i]);
17422 for(; i < days; i++){
17423 intDay = i - startingPos + 1;
17424 textEls[i].innerHTML = (intDay);
17425 d.setDate(d.getDate()+1);
17427 cells[i].className = ''; // "x-date-active";
17428 setCellClass(this, cells[i]);
17432 for(; i < 42; i++) {
17433 textEls[i].innerHTML = (++extraDays);
17434 d.setDate(d.getDate()+1);
17436 cells[i].className = "fc-future fc-other-month";
17437 setCellClass(this, cells[i]);
17440 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
17442 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
17444 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
17445 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
17447 if(totalRows != 6){
17448 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
17449 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
17452 this.fireEvent('monthchange', this, date);
17456 if(!this.internalRender){
17457 var main = this.el.dom.firstChild;
17458 var w = main.offsetWidth;
17459 this.el.setWidth(w + this.el.getBorderWidth("lr"));
17460 Roo.fly(main).setWidth(w);
17461 this.internalRender = true;
17462 // opera does not respect the auto grow header center column
17463 // then, after it gets a width opera refuses to recalculate
17464 // without a second pass
17465 if(Roo.isOpera && !this.secondPass){
17466 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
17467 this.secondPass = true;
17468 this.update.defer(10, this, [date]);
17475 findCell : function(dt) {
17476 dt = dt.clearTime().getTime();
17478 this.cells.each(function(c){
17479 //Roo.log("check " +c.dateValue + '?=' + dt);
17480 if(c.dateValue == dt){
17490 findCells : function(ev) {
17491 var s = ev.start.clone().clearTime().getTime();
17493 var e= ev.end.clone().clearTime().getTime();
17496 this.cells.each(function(c){
17497 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
17499 if(c.dateValue > e){
17502 if(c.dateValue < s){
17511 // findBestRow: function(cells)
17515 // for (var i =0 ; i < cells.length;i++) {
17516 // ret = Math.max(cells[i].rows || 0,ret);
17523 addItem : function(ev)
17525 // look for vertical location slot in
17526 var cells = this.findCells(ev);
17528 // ev.row = this.findBestRow(cells);
17530 // work out the location.
17534 for(var i =0; i < cells.length; i++) {
17536 cells[i].row = cells[0].row;
17539 cells[i].row = cells[i].row + 1;
17549 if (crow.start.getY() == cells[i].getY()) {
17551 crow.end = cells[i];
17568 cells[0].events.push(ev);
17570 this.calevents.push(ev);
17573 clearEvents: function() {
17575 if(!this.calevents){
17579 Roo.each(this.cells.elements, function(c){
17585 Roo.each(this.calevents, function(e) {
17586 Roo.each(e.els, function(el) {
17587 el.un('mouseenter' ,this.onEventEnter, this);
17588 el.un('mouseleave' ,this.onEventLeave, this);
17593 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
17599 renderEvents: function()
17603 this.cells.each(function(c) {
17612 if(c.row != c.events.length){
17613 r = 4 - (4 - (c.row - c.events.length));
17616 c.events = ev.slice(0, r);
17617 c.more = ev.slice(r);
17619 if(c.more.length && c.more.length == 1){
17620 c.events.push(c.more.pop());
17623 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
17627 this.cells.each(function(c) {
17629 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
17632 for (var e = 0; e < c.events.length; e++){
17633 var ev = c.events[e];
17634 var rows = ev.rows;
17636 for(var i = 0; i < rows.length; i++) {
17638 // how many rows should it span..
17641 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
17642 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
17644 unselectable : "on",
17647 cls: 'fc-event-inner',
17651 // cls: 'fc-event-time',
17652 // html : cells.length > 1 ? '' : ev.time
17656 cls: 'fc-event-title',
17657 html : String.format('{0}', ev.title)
17664 cls: 'ui-resizable-handle ui-resizable-e',
17665 html : '  '
17672 cfg.cls += ' fc-event-start';
17674 if ((i+1) == rows.length) {
17675 cfg.cls += ' fc-event-end';
17678 var ctr = _this.el.select('.fc-event-container',true).first();
17679 var cg = ctr.createChild(cfg);
17681 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
17682 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
17684 var r = (c.more.length) ? 1 : 0;
17685 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
17686 cg.setWidth(ebox.right - sbox.x -2);
17688 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
17689 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
17690 cg.on('click', _this.onEventClick, _this, ev);
17701 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
17702 style : 'position: absolute',
17703 unselectable : "on",
17706 cls: 'fc-event-inner',
17710 cls: 'fc-event-title',
17718 cls: 'ui-resizable-handle ui-resizable-e',
17719 html : '  '
17725 var ctr = _this.el.select('.fc-event-container',true).first();
17726 var cg = ctr.createChild(cfg);
17728 var sbox = c.select('.fc-day-content',true).first().getBox();
17729 var ebox = c.select('.fc-day-content',true).first().getBox();
17731 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
17732 cg.setWidth(ebox.right - sbox.x -2);
17734 cg.on('click', _this.onMoreEventClick, _this, c.more);
17744 onEventEnter: function (e, el,event,d) {
17745 this.fireEvent('evententer', this, el, event);
17748 onEventLeave: function (e, el,event,d) {
17749 this.fireEvent('eventleave', this, el, event);
17752 onEventClick: function (e, el,event,d) {
17753 this.fireEvent('eventclick', this, el, event);
17756 onMonthChange: function () {
17760 onMoreEventClick: function(e, el, more)
17764 this.calpopover.placement = 'right';
17765 this.calpopover.setTitle('More');
17767 this.calpopover.setContent('');
17769 var ctr = this.calpopover.el.select('.popover-content', true).first();
17771 Roo.each(more, function(m){
17773 cls : 'fc-event-hori fc-event-draggable',
17776 var cg = ctr.createChild(cfg);
17778 cg.on('click', _this.onEventClick, _this, m);
17781 this.calpopover.show(el);
17786 onLoad: function ()
17788 this.calevents = [];
17791 if(this.store.getCount() > 0){
17792 this.store.data.each(function(d){
17795 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
17796 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
17797 time : d.data.start_time,
17798 title : d.data.title,
17799 description : d.data.description,
17800 venue : d.data.venue
17805 this.renderEvents();
17807 if(this.calevents.length && this.loadMask){
17808 this.maskEl.hide();
17812 onBeforeLoad: function()
17814 this.clearEvents();
17816 this.maskEl.show();
17830 * @class Roo.bootstrap.Popover
17831 * @extends Roo.bootstrap.Component
17832 * Bootstrap Popover class
17833 * @cfg {String} html contents of the popover (or false to use children..)
17834 * @cfg {String} title of popover (or false to hide)
17835 * @cfg {String} placement how it is placed
17836 * @cfg {String} trigger click || hover (or false to trigger manually)
17837 * @cfg {String} over what (parent or false to trigger manually.)
17838 * @cfg {Number} delay - delay before showing
17841 * Create a new Popover
17842 * @param {Object} config The config object
17845 Roo.bootstrap.Popover = function(config){
17846 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
17852 * After the popover show
17854 * @param {Roo.bootstrap.Popover} this
17859 * After the popover hide
17861 * @param {Roo.bootstrap.Popover} this
17867 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
17869 title: 'Fill in a title',
17872 placement : 'right',
17873 trigger : 'hover', // hover
17879 can_build_overlaid : false,
17881 getChildContainer : function()
17883 return this.el.select('.popover-content',true).first();
17886 getAutoCreate : function(){
17889 cls : 'popover roo-dynamic',
17890 style: 'display:block',
17896 cls : 'popover-inner',
17900 cls: 'popover-title popover-header',
17904 cls : 'popover-content popover-body',
17915 setTitle: function(str)
17918 this.el.select('.popover-title',true).first().dom.innerHTML = str;
17920 setContent: function(str)
17923 this.el.select('.popover-content',true).first().dom.innerHTML = str;
17925 // as it get's added to the bottom of the page.
17926 onRender : function(ct, position)
17928 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17930 var cfg = Roo.apply({}, this.getAutoCreate());
17934 cfg.cls += ' ' + this.cls;
17937 cfg.style = this.style;
17939 //Roo.log("adding to ");
17940 this.el = Roo.get(document.body).createChild(cfg, position);
17941 // Roo.log(this.el);
17946 initEvents : function()
17948 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
17949 this.el.enableDisplayMode('block');
17951 if (this.over === false) {
17954 if (this.triggers === false) {
17957 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17958 var triggers = this.trigger ? this.trigger.split(' ') : [];
17959 Roo.each(triggers, function(trigger) {
17961 if (trigger == 'click') {
17962 on_el.on('click', this.toggle, this);
17963 } else if (trigger != 'manual') {
17964 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
17965 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
17967 on_el.on(eventIn ,this.enter, this);
17968 on_el.on(eventOut, this.leave, this);
17979 toggle : function () {
17980 this.hoverState == 'in' ? this.leave() : this.enter();
17983 enter : function () {
17985 clearTimeout(this.timeout);
17987 this.hoverState = 'in';
17989 if (!this.delay || !this.delay.show) {
17994 this.timeout = setTimeout(function () {
17995 if (_t.hoverState == 'in') {
17998 }, this.delay.show)
18001 leave : function() {
18002 clearTimeout(this.timeout);
18004 this.hoverState = 'out';
18006 if (!this.delay || !this.delay.hide) {
18011 this.timeout = setTimeout(function () {
18012 if (_t.hoverState == 'out') {
18015 }, this.delay.hide)
18018 show : function (on_el)
18021 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
18025 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
18026 if (this.html !== false) {
18027 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
18029 this.el.removeClass([
18030 'fade','top','bottom', 'left', 'right','in',
18031 'bs-popover-top','bs-popover-bottom', 'bs-popover-left', 'bs-popover-right'
18033 if (!this.title.length) {
18034 this.el.select('.popover-title',true).hide();
18037 var placement = typeof this.placement == 'function' ?
18038 this.placement.call(this, this.el, on_el) :
18041 var autoToken = /\s?auto?\s?/i;
18042 var autoPlace = autoToken.test(placement);
18044 placement = placement.replace(autoToken, '') || 'top';
18048 //this.el.setXY([0,0]);
18050 this.el.dom.style.display='block';
18051 this.el.addClass(placement);
18053 //this.el.appendTo(on_el);
18055 var p = this.getPosition();
18056 var box = this.el.getBox();
18061 var align = Roo.bootstrap.Popover.alignment[placement];
18064 this.el.alignTo(on_el, align[0],align[1]);
18065 //var arrow = this.el.select('.arrow',true).first();
18066 //arrow.set(align[2],
18068 this.el.addClass('in');
18071 if (this.el.hasClass('fade')) {
18075 this.hoverState = 'in';
18077 this.fireEvent('show', this);
18082 this.el.setXY([0,0]);
18083 this.el.removeClass('in');
18085 this.hoverState = null;
18087 this.fireEvent('hide', this);
18092 Roo.bootstrap.Popover.alignment = {
18093 'left' : ['r-l', [-10,0], 'right bs-popover-right'],
18094 'right' : ['l-r', [10,0], 'left bs-popover-left'],
18095 'bottom' : ['t-b', [0,10], 'top bs-popover-top'],
18096 'top' : [ 'b-t', [0,-10], 'bottom bs-popover-bottom']
18107 * @class Roo.bootstrap.Progress
18108 * @extends Roo.bootstrap.Component
18109 * Bootstrap Progress class
18110 * @cfg {Boolean} striped striped of the progress bar
18111 * @cfg {Boolean} active animated of the progress bar
18115 * Create a new Progress
18116 * @param {Object} config The config object
18119 Roo.bootstrap.Progress = function(config){
18120 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
18123 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
18128 getAutoCreate : function(){
18136 cfg.cls += ' progress-striped';
18140 cfg.cls += ' active';
18159 * @class Roo.bootstrap.ProgressBar
18160 * @extends Roo.bootstrap.Component
18161 * Bootstrap ProgressBar class
18162 * @cfg {Number} aria_valuenow aria-value now
18163 * @cfg {Number} aria_valuemin aria-value min
18164 * @cfg {Number} aria_valuemax aria-value max
18165 * @cfg {String} label label for the progress bar
18166 * @cfg {String} panel (success | info | warning | danger )
18167 * @cfg {String} role role of the progress bar
18168 * @cfg {String} sr_only text
18172 * Create a new ProgressBar
18173 * @param {Object} config The config object
18176 Roo.bootstrap.ProgressBar = function(config){
18177 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
18180 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
18184 aria_valuemax : 100,
18190 getAutoCreate : function()
18195 cls: 'progress-bar',
18196 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
18208 cfg.role = this.role;
18211 if(this.aria_valuenow){
18212 cfg['aria-valuenow'] = this.aria_valuenow;
18215 if(this.aria_valuemin){
18216 cfg['aria-valuemin'] = this.aria_valuemin;
18219 if(this.aria_valuemax){
18220 cfg['aria-valuemax'] = this.aria_valuemax;
18223 if(this.label && !this.sr_only){
18224 cfg.html = this.label;
18228 cfg.cls += ' progress-bar-' + this.panel;
18234 update : function(aria_valuenow)
18236 this.aria_valuenow = aria_valuenow;
18238 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
18253 * @class Roo.bootstrap.TabGroup
18254 * @extends Roo.bootstrap.Column
18255 * Bootstrap Column class
18256 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
18257 * @cfg {Boolean} carousel true to make the group behave like a carousel
18258 * @cfg {Boolean} bullets show bullets for the panels
18259 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
18260 * @cfg {Number} timer auto slide timer .. default 0 millisecond
18261 * @cfg {Boolean} showarrow (true|false) show arrow default true
18264 * Create a new TabGroup
18265 * @param {Object} config The config object
18268 Roo.bootstrap.TabGroup = function(config){
18269 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
18271 this.navId = Roo.id();
18274 Roo.bootstrap.TabGroup.register(this);
18278 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
18281 transition : false,
18286 slideOnTouch : false,
18289 getAutoCreate : function()
18291 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
18293 cfg.cls += ' tab-content';
18295 if (this.carousel) {
18296 cfg.cls += ' carousel slide';
18299 cls : 'carousel-inner',
18303 if(this.bullets && !Roo.isTouch){
18306 cls : 'carousel-bullets',
18310 if(this.bullets_cls){
18311 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
18318 cfg.cn[0].cn.push(bullets);
18321 if(this.showarrow){
18322 cfg.cn[0].cn.push({
18324 class : 'carousel-arrow',
18328 class : 'carousel-prev',
18332 class : 'fa fa-chevron-left'
18338 class : 'carousel-next',
18342 class : 'fa fa-chevron-right'
18355 initEvents: function()
18357 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
18358 // this.el.on("touchstart", this.onTouchStart, this);
18361 if(this.autoslide){
18364 this.slideFn = window.setInterval(function() {
18365 _this.showPanelNext();
18369 if(this.showarrow){
18370 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
18371 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
18377 // onTouchStart : function(e, el, o)
18379 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
18383 // this.showPanelNext();
18387 getChildContainer : function()
18389 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
18393 * register a Navigation item
18394 * @param {Roo.bootstrap.NavItem} the navitem to add
18396 register : function(item)
18398 this.tabs.push( item);
18399 item.navId = this.navId; // not really needed..
18404 getActivePanel : function()
18407 Roo.each(this.tabs, function(t) {
18417 getPanelByName : function(n)
18420 Roo.each(this.tabs, function(t) {
18421 if (t.tabId == n) {
18429 indexOfPanel : function(p)
18432 Roo.each(this.tabs, function(t,i) {
18433 if (t.tabId == p.tabId) {
18442 * show a specific panel
18443 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
18444 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
18446 showPanel : function (pan)
18448 if(this.transition || typeof(pan) == 'undefined'){
18449 Roo.log("waiting for the transitionend");
18453 if (typeof(pan) == 'number') {
18454 pan = this.tabs[pan];
18457 if (typeof(pan) == 'string') {
18458 pan = this.getPanelByName(pan);
18461 var cur = this.getActivePanel();
18464 Roo.log('pan or acitve pan is undefined');
18468 if (pan.tabId == this.getActivePanel().tabId) {
18472 if (false === cur.fireEvent('beforedeactivate')) {
18476 if(this.bullets > 0 && !Roo.isTouch){
18477 this.setActiveBullet(this.indexOfPanel(pan));
18480 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
18482 //class="carousel-item carousel-item-next carousel-item-left"
18484 this.transition = true;
18485 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
18486 var lr = dir == 'next' ? 'left' : 'right';
18487 pan.el.addClass(dir); // or prev
18488 pan.el.addClass('carousel-item-' + dir); // or prev
18489 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
18490 cur.el.addClass(lr); // or right
18491 pan.el.addClass(lr);
18492 cur.el.addClass('carousel-item-' +lr); // or right
18493 pan.el.addClass('carousel-item-' +lr);
18497 cur.el.on('transitionend', function() {
18498 Roo.log("trans end?");
18500 pan.el.removeClass([lr,dir, 'carousel-item-' + lr, 'carousel-item-' + dir]);
18501 pan.setActive(true);
18503 cur.el.removeClass([lr, 'carousel-item-' + lr]);
18504 cur.setActive(false);
18506 _this.transition = false;
18508 }, this, { single: true } );
18513 cur.setActive(false);
18514 pan.setActive(true);
18519 showPanelNext : function()
18521 var i = this.indexOfPanel(this.getActivePanel());
18523 if (i >= this.tabs.length - 1 && !this.autoslide) {
18527 if (i >= this.tabs.length - 1 && this.autoslide) {
18531 this.showPanel(this.tabs[i+1]);
18534 showPanelPrev : function()
18536 var i = this.indexOfPanel(this.getActivePanel());
18538 if (i < 1 && !this.autoslide) {
18542 if (i < 1 && this.autoslide) {
18543 i = this.tabs.length;
18546 this.showPanel(this.tabs[i-1]);
18550 addBullet: function()
18552 if(!this.bullets || Roo.isTouch){
18555 var ctr = this.el.select('.carousel-bullets',true).first();
18556 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
18557 var bullet = ctr.createChild({
18558 cls : 'bullet bullet-' + i
18559 },ctr.dom.lastChild);
18564 bullet.on('click', (function(e, el, o, ii, t){
18566 e.preventDefault();
18568 this.showPanel(ii);
18570 if(this.autoslide && this.slideFn){
18571 clearInterval(this.slideFn);
18572 this.slideFn = window.setInterval(function() {
18573 _this.showPanelNext();
18577 }).createDelegate(this, [i, bullet], true));
18582 setActiveBullet : function(i)
18588 Roo.each(this.el.select('.bullet', true).elements, function(el){
18589 el.removeClass('selected');
18592 var bullet = this.el.select('.bullet-' + i, true).first();
18598 bullet.addClass('selected');
18609 Roo.apply(Roo.bootstrap.TabGroup, {
18613 * register a Navigation Group
18614 * @param {Roo.bootstrap.NavGroup} the navgroup to add
18616 register : function(navgrp)
18618 this.groups[navgrp.navId] = navgrp;
18622 * fetch a Navigation Group based on the navigation ID
18623 * if one does not exist , it will get created.
18624 * @param {string} the navgroup to add
18625 * @returns {Roo.bootstrap.NavGroup} the navgroup
18627 get: function(navId) {
18628 if (typeof(this.groups[navId]) == 'undefined') {
18629 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
18631 return this.groups[navId] ;
18646 * @class Roo.bootstrap.TabPanel
18647 * @extends Roo.bootstrap.Component
18648 * Bootstrap TabPanel class
18649 * @cfg {Boolean} active panel active
18650 * @cfg {String} html panel content
18651 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
18652 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
18653 * @cfg {String} href click to link..
18657 * Create a new TabPanel
18658 * @param {Object} config The config object
18661 Roo.bootstrap.TabPanel = function(config){
18662 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
18666 * Fires when the active status changes
18667 * @param {Roo.bootstrap.TabPanel} this
18668 * @param {Boolean} state the new state
18673 * @event beforedeactivate
18674 * Fires before a tab is de-activated - can be used to do validation on a form.
18675 * @param {Roo.bootstrap.TabPanel} this
18676 * @return {Boolean} false if there is an error
18679 'beforedeactivate': true
18682 this.tabId = this.tabId || Roo.id();
18686 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
18694 getAutoCreate : function(){
18699 // item is needed for carousel - not sure if it has any effect otherwise
18700 cls: 'carousel-item tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
18701 html: this.html || ''
18705 cfg.cls += ' active';
18709 cfg.tabId = this.tabId;
18717 initEvents: function()
18719 var p = this.parent();
18721 this.navId = this.navId || p.navId;
18723 if (typeof(this.navId) != 'undefined') {
18724 // not really needed.. but just in case.. parent should be a NavGroup.
18725 var tg = Roo.bootstrap.TabGroup.get(this.navId);
18729 var i = tg.tabs.length - 1;
18731 if(this.active && tg.bullets > 0 && i < tg.bullets){
18732 tg.setActiveBullet(i);
18736 this.el.on('click', this.onClick, this);
18739 this.el.on("touchstart", this.onTouchStart, this);
18740 this.el.on("touchmove", this.onTouchMove, this);
18741 this.el.on("touchend", this.onTouchEnd, this);
18746 onRender : function(ct, position)
18748 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
18751 setActive : function(state)
18753 Roo.log("panel - set active " + this.tabId + "=" + state);
18755 this.active = state;
18757 this.el.removeClass('active');
18759 } else if (!this.el.hasClass('active')) {
18760 this.el.addClass('active');
18763 this.fireEvent('changed', this, state);
18766 onClick : function(e)
18768 e.preventDefault();
18770 if(!this.href.length){
18774 window.location.href = this.href;
18783 onTouchStart : function(e)
18785 this.swiping = false;
18787 this.startX = e.browserEvent.touches[0].clientX;
18788 this.startY = e.browserEvent.touches[0].clientY;
18791 onTouchMove : function(e)
18793 this.swiping = true;
18795 this.endX = e.browserEvent.touches[0].clientX;
18796 this.endY = e.browserEvent.touches[0].clientY;
18799 onTouchEnd : function(e)
18806 var tabGroup = this.parent();
18808 if(this.endX > this.startX){ // swiping right
18809 tabGroup.showPanelPrev();
18813 if(this.startX > this.endX){ // swiping left
18814 tabGroup.showPanelNext();
18833 * @class Roo.bootstrap.DateField
18834 * @extends Roo.bootstrap.Input
18835 * Bootstrap DateField class
18836 * @cfg {Number} weekStart default 0
18837 * @cfg {String} viewMode default empty, (months|years)
18838 * @cfg {String} minViewMode default empty, (months|years)
18839 * @cfg {Number} startDate default -Infinity
18840 * @cfg {Number} endDate default Infinity
18841 * @cfg {Boolean} todayHighlight default false
18842 * @cfg {Boolean} todayBtn default false
18843 * @cfg {Boolean} calendarWeeks default false
18844 * @cfg {Object} daysOfWeekDisabled default empty
18845 * @cfg {Boolean} singleMode default false (true | false)
18847 * @cfg {Boolean} keyboardNavigation default true
18848 * @cfg {String} language default en
18851 * Create a new DateField
18852 * @param {Object} config The config object
18855 Roo.bootstrap.DateField = function(config){
18856 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
18860 * Fires when this field show.
18861 * @param {Roo.bootstrap.DateField} this
18862 * @param {Mixed} date The date value
18867 * Fires when this field hide.
18868 * @param {Roo.bootstrap.DateField} this
18869 * @param {Mixed} date The date value
18874 * Fires when select a date.
18875 * @param {Roo.bootstrap.DateField} this
18876 * @param {Mixed} date The date value
18880 * @event beforeselect
18881 * Fires when before select a date.
18882 * @param {Roo.bootstrap.DateField} this
18883 * @param {Mixed} date The date value
18885 beforeselect : true
18889 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
18892 * @cfg {String} format
18893 * The default date format string which can be overriden for localization support. The format must be
18894 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
18898 * @cfg {String} altFormats
18899 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
18900 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
18902 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
18910 todayHighlight : false,
18916 keyboardNavigation: true,
18918 calendarWeeks: false,
18920 startDate: -Infinity,
18924 daysOfWeekDisabled: [],
18928 singleMode : false,
18930 UTCDate: function()
18932 return new Date(Date.UTC.apply(Date, arguments));
18935 UTCToday: function()
18937 var today = new Date();
18938 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
18941 getDate: function() {
18942 var d = this.getUTCDate();
18943 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
18946 getUTCDate: function() {
18950 setDate: function(d) {
18951 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
18954 setUTCDate: function(d) {
18956 this.setValue(this.formatDate(this.date));
18959 onRender: function(ct, position)
18962 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
18964 this.language = this.language || 'en';
18965 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
18966 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
18968 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
18969 this.format = this.format || 'm/d/y';
18970 this.isInline = false;
18971 this.isInput = true;
18972 this.component = this.el.select('.add-on', true).first() || false;
18973 this.component = (this.component && this.component.length === 0) ? false : this.component;
18974 this.hasInput = this.component && this.inputEl().length;
18976 if (typeof(this.minViewMode === 'string')) {
18977 switch (this.minViewMode) {
18979 this.minViewMode = 1;
18982 this.minViewMode = 2;
18985 this.minViewMode = 0;
18990 if (typeof(this.viewMode === 'string')) {
18991 switch (this.viewMode) {
19004 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
19006 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
19008 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19010 this.picker().on('mousedown', this.onMousedown, this);
19011 this.picker().on('click', this.onClick, this);
19013 this.picker().addClass('datepicker-dropdown');
19015 this.startViewMode = this.viewMode;
19017 if(this.singleMode){
19018 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
19019 v.setVisibilityMode(Roo.Element.DISPLAY);
19023 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
19024 v.setStyle('width', '189px');
19028 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
19029 if(!this.calendarWeeks){
19034 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
19035 v.attr('colspan', function(i, val){
19036 return parseInt(val) + 1;
19041 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
19043 this.setStartDate(this.startDate);
19044 this.setEndDate(this.endDate);
19046 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
19053 if(this.isInline) {
19058 picker : function()
19060 return this.pickerEl;
19061 // return this.el.select('.datepicker', true).first();
19064 fillDow: function()
19066 var dowCnt = this.weekStart;
19075 if(this.calendarWeeks){
19083 while (dowCnt < this.weekStart + 7) {
19087 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
19091 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
19094 fillMonths: function()
19097 var months = this.picker().select('>.datepicker-months td', true).first();
19099 months.dom.innerHTML = '';
19105 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
19108 months.createChild(month);
19115 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;
19117 if (this.date < this.startDate) {
19118 this.viewDate = new Date(this.startDate);
19119 } else if (this.date > this.endDate) {
19120 this.viewDate = new Date(this.endDate);
19122 this.viewDate = new Date(this.date);
19130 var d = new Date(this.viewDate),
19131 year = d.getUTCFullYear(),
19132 month = d.getUTCMonth(),
19133 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
19134 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
19135 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
19136 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
19137 currentDate = this.date && this.date.valueOf(),
19138 today = this.UTCToday();
19140 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
19142 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
19144 // this.picker.select('>tfoot th.today').
19145 // .text(dates[this.language].today)
19146 // .toggle(this.todayBtn !== false);
19148 this.updateNavArrows();
19151 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
19153 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
19155 prevMonth.setUTCDate(day);
19157 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
19159 var nextMonth = new Date(prevMonth);
19161 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
19163 nextMonth = nextMonth.valueOf();
19165 var fillMonths = false;
19167 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
19169 while(prevMonth.valueOf() <= nextMonth) {
19172 if (prevMonth.getUTCDay() === this.weekStart) {
19174 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
19182 if(this.calendarWeeks){
19183 // ISO 8601: First week contains first thursday.
19184 // ISO also states week starts on Monday, but we can be more abstract here.
19186 // Start of current week: based on weekstart/current date
19187 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
19188 // Thursday of this week
19189 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
19190 // First Thursday of year, year from thursday
19191 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
19192 // Calendar week: ms between thursdays, div ms per day, div 7 days
19193 calWeek = (th - yth) / 864e5 / 7 + 1;
19195 fillMonths.cn.push({
19203 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
19205 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
19208 if (this.todayHighlight &&
19209 prevMonth.getUTCFullYear() == today.getFullYear() &&
19210 prevMonth.getUTCMonth() == today.getMonth() &&
19211 prevMonth.getUTCDate() == today.getDate()) {
19212 clsName += ' today';
19215 if (currentDate && prevMonth.valueOf() === currentDate) {
19216 clsName += ' active';
19219 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
19220 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
19221 clsName += ' disabled';
19224 fillMonths.cn.push({
19226 cls: 'day ' + clsName,
19227 html: prevMonth.getDate()
19230 prevMonth.setDate(prevMonth.getDate()+1);
19233 var currentYear = this.date && this.date.getUTCFullYear();
19234 var currentMonth = this.date && this.date.getUTCMonth();
19236 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
19238 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
19239 v.removeClass('active');
19241 if(currentYear === year && k === currentMonth){
19242 v.addClass('active');
19245 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
19246 v.addClass('disabled');
19252 year = parseInt(year/10, 10) * 10;
19254 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
19256 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
19259 for (var i = -1; i < 11; i++) {
19260 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
19262 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
19270 showMode: function(dir)
19273 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
19276 Roo.each(this.picker().select('>div',true).elements, function(v){
19277 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19280 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
19285 if(this.isInline) {
19289 this.picker().removeClass(['bottom', 'top']);
19291 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
19293 * place to the top of element!
19297 this.picker().addClass('top');
19298 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
19303 this.picker().addClass('bottom');
19305 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
19308 parseDate : function(value)
19310 if(!value || value instanceof Date){
19313 var v = Date.parseDate(value, this.format);
19314 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
19315 v = Date.parseDate(value, 'Y-m-d');
19317 if(!v && this.altFormats){
19318 if(!this.altFormatsArray){
19319 this.altFormatsArray = this.altFormats.split("|");
19321 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
19322 v = Date.parseDate(value, this.altFormatsArray[i]);
19328 formatDate : function(date, fmt)
19330 return (!date || !(date instanceof Date)) ?
19331 date : date.dateFormat(fmt || this.format);
19334 onFocus : function()
19336 Roo.bootstrap.DateField.superclass.onFocus.call(this);
19340 onBlur : function()
19342 Roo.bootstrap.DateField.superclass.onBlur.call(this);
19344 var d = this.inputEl().getValue();
19351 showPopup : function()
19353 this.picker().show();
19357 this.fireEvent('showpopup', this, this.date);
19360 hidePopup : function()
19362 if(this.isInline) {
19365 this.picker().hide();
19366 this.viewMode = this.startViewMode;
19369 this.fireEvent('hidepopup', this, this.date);
19373 onMousedown: function(e)
19375 e.stopPropagation();
19376 e.preventDefault();
19381 Roo.bootstrap.DateField.superclass.keyup.call(this);
19385 setValue: function(v)
19387 if(this.fireEvent('beforeselect', this, v) !== false){
19388 var d = new Date(this.parseDate(v) ).clearTime();
19390 if(isNaN(d.getTime())){
19391 this.date = this.viewDate = '';
19392 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
19396 v = this.formatDate(d);
19398 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
19400 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
19404 this.fireEvent('select', this, this.date);
19408 getValue: function()
19410 return this.formatDate(this.date);
19413 fireKey: function(e)
19415 if (!this.picker().isVisible()){
19416 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19422 var dateChanged = false,
19424 newDate, newViewDate;
19429 e.preventDefault();
19433 if (!this.keyboardNavigation) {
19436 dir = e.keyCode == 37 ? -1 : 1;
19439 newDate = this.moveYear(this.date, dir);
19440 newViewDate = this.moveYear(this.viewDate, dir);
19441 } else if (e.shiftKey){
19442 newDate = this.moveMonth(this.date, dir);
19443 newViewDate = this.moveMonth(this.viewDate, dir);
19445 newDate = new Date(this.date);
19446 newDate.setUTCDate(this.date.getUTCDate() + dir);
19447 newViewDate = new Date(this.viewDate);
19448 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
19450 if (this.dateWithinRange(newDate)){
19451 this.date = newDate;
19452 this.viewDate = newViewDate;
19453 this.setValue(this.formatDate(this.date));
19455 e.preventDefault();
19456 dateChanged = true;
19461 if (!this.keyboardNavigation) {
19464 dir = e.keyCode == 38 ? -1 : 1;
19466 newDate = this.moveYear(this.date, dir);
19467 newViewDate = this.moveYear(this.viewDate, dir);
19468 } else if (e.shiftKey){
19469 newDate = this.moveMonth(this.date, dir);
19470 newViewDate = this.moveMonth(this.viewDate, dir);
19472 newDate = new Date(this.date);
19473 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
19474 newViewDate = new Date(this.viewDate);
19475 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
19477 if (this.dateWithinRange(newDate)){
19478 this.date = newDate;
19479 this.viewDate = newViewDate;
19480 this.setValue(this.formatDate(this.date));
19482 e.preventDefault();
19483 dateChanged = true;
19487 this.setValue(this.formatDate(this.date));
19489 e.preventDefault();
19492 this.setValue(this.formatDate(this.date));
19506 onClick: function(e)
19508 e.stopPropagation();
19509 e.preventDefault();
19511 var target = e.getTarget();
19513 if(target.nodeName.toLowerCase() === 'i'){
19514 target = Roo.get(target).dom.parentNode;
19517 var nodeName = target.nodeName;
19518 var className = target.className;
19519 var html = target.innerHTML;
19520 //Roo.log(nodeName);
19522 switch(nodeName.toLowerCase()) {
19524 switch(className) {
19530 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
19531 switch(this.viewMode){
19533 this.viewDate = this.moveMonth(this.viewDate, dir);
19537 this.viewDate = this.moveYear(this.viewDate, dir);
19543 var date = new Date();
19544 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
19546 this.setValue(this.formatDate(this.date));
19553 if (className.indexOf('disabled') < 0) {
19554 this.viewDate.setUTCDate(1);
19555 if (className.indexOf('month') > -1) {
19556 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
19558 var year = parseInt(html, 10) || 0;
19559 this.viewDate.setUTCFullYear(year);
19563 if(this.singleMode){
19564 this.setValue(this.formatDate(this.viewDate));
19575 //Roo.log(className);
19576 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
19577 var day = parseInt(html, 10) || 1;
19578 var year = this.viewDate.getUTCFullYear(),
19579 month = this.viewDate.getUTCMonth();
19581 if (className.indexOf('old') > -1) {
19588 } else if (className.indexOf('new') > -1) {
19596 //Roo.log([year,month,day]);
19597 this.date = this.UTCDate(year, month, day,0,0,0,0);
19598 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
19600 //Roo.log(this.formatDate(this.date));
19601 this.setValue(this.formatDate(this.date));
19608 setStartDate: function(startDate)
19610 this.startDate = startDate || -Infinity;
19611 if (this.startDate !== -Infinity) {
19612 this.startDate = this.parseDate(this.startDate);
19615 this.updateNavArrows();
19618 setEndDate: function(endDate)
19620 this.endDate = endDate || Infinity;
19621 if (this.endDate !== Infinity) {
19622 this.endDate = this.parseDate(this.endDate);
19625 this.updateNavArrows();
19628 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
19630 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
19631 if (typeof(this.daysOfWeekDisabled) !== 'object') {
19632 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
19634 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
19635 return parseInt(d, 10);
19638 this.updateNavArrows();
19641 updateNavArrows: function()
19643 if(this.singleMode){
19647 var d = new Date(this.viewDate),
19648 year = d.getUTCFullYear(),
19649 month = d.getUTCMonth();
19651 Roo.each(this.picker().select('.prev', true).elements, function(v){
19653 switch (this.viewMode) {
19656 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
19662 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
19669 Roo.each(this.picker().select('.next', true).elements, function(v){
19671 switch (this.viewMode) {
19674 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
19680 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
19688 moveMonth: function(date, dir)
19693 var new_date = new Date(date.valueOf()),
19694 day = new_date.getUTCDate(),
19695 month = new_date.getUTCMonth(),
19696 mag = Math.abs(dir),
19698 dir = dir > 0 ? 1 : -1;
19701 // If going back one month, make sure month is not current month
19702 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
19704 return new_date.getUTCMonth() == month;
19706 // If going forward one month, make sure month is as expected
19707 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
19709 return new_date.getUTCMonth() != new_month;
19711 new_month = month + dir;
19712 new_date.setUTCMonth(new_month);
19713 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
19714 if (new_month < 0 || new_month > 11) {
19715 new_month = (new_month + 12) % 12;
19718 // For magnitudes >1, move one month at a time...
19719 for (var i=0; i<mag; i++) {
19720 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
19721 new_date = this.moveMonth(new_date, dir);
19723 // ...then reset the day, keeping it in the new month
19724 new_month = new_date.getUTCMonth();
19725 new_date.setUTCDate(day);
19727 return new_month != new_date.getUTCMonth();
19730 // Common date-resetting loop -- if date is beyond end of month, make it
19733 new_date.setUTCDate(--day);
19734 new_date.setUTCMonth(new_month);
19739 moveYear: function(date, dir)
19741 return this.moveMonth(date, dir*12);
19744 dateWithinRange: function(date)
19746 return date >= this.startDate && date <= this.endDate;
19752 this.picker().remove();
19755 validateValue : function(value)
19757 if(this.getVisibilityEl().hasClass('hidden')){
19761 if(value.length < 1) {
19762 if(this.allowBlank){
19768 if(value.length < this.minLength){
19771 if(value.length > this.maxLength){
19775 var vt = Roo.form.VTypes;
19776 if(!vt[this.vtype](value, this)){
19780 if(typeof this.validator == "function"){
19781 var msg = this.validator(value);
19787 if(this.regex && !this.regex.test(value)){
19791 if(typeof(this.parseDate(value)) == 'undefined'){
19795 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
19799 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
19809 this.date = this.viewDate = '';
19811 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
19816 Roo.apply(Roo.bootstrap.DateField, {
19827 html: '<i class="fa fa-arrow-left"/>'
19837 html: '<i class="fa fa-arrow-right"/>'
19879 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
19880 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
19881 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
19882 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19883 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
19896 navFnc: 'FullYear',
19901 navFnc: 'FullYear',
19906 Roo.apply(Roo.bootstrap.DateField, {
19910 cls: 'datepicker dropdown-menu roo-dynamic',
19914 cls: 'datepicker-days',
19918 cls: 'table-condensed',
19920 Roo.bootstrap.DateField.head,
19924 Roo.bootstrap.DateField.footer
19931 cls: 'datepicker-months',
19935 cls: 'table-condensed',
19937 Roo.bootstrap.DateField.head,
19938 Roo.bootstrap.DateField.content,
19939 Roo.bootstrap.DateField.footer
19946 cls: 'datepicker-years',
19950 cls: 'table-condensed',
19952 Roo.bootstrap.DateField.head,
19953 Roo.bootstrap.DateField.content,
19954 Roo.bootstrap.DateField.footer
19973 * @class Roo.bootstrap.TimeField
19974 * @extends Roo.bootstrap.Input
19975 * Bootstrap DateField class
19979 * Create a new TimeField
19980 * @param {Object} config The config object
19983 Roo.bootstrap.TimeField = function(config){
19984 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
19988 * Fires when this field show.
19989 * @param {Roo.bootstrap.DateField} thisthis
19990 * @param {Mixed} date The date value
19995 * Fires when this field hide.
19996 * @param {Roo.bootstrap.DateField} this
19997 * @param {Mixed} date The date value
20002 * Fires when select a date.
20003 * @param {Roo.bootstrap.DateField} this
20004 * @param {Mixed} date The date value
20010 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
20013 * @cfg {String} format
20014 * The default time format string which can be overriden for localization support. The format must be
20015 * valid according to {@link Date#parseDate} (defaults to 'H:i').
20019 onRender: function(ct, position)
20022 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
20024 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
20026 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
20028 this.pop = this.picker().select('>.datepicker-time',true).first();
20029 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
20031 this.picker().on('mousedown', this.onMousedown, this);
20032 this.picker().on('click', this.onClick, this);
20034 this.picker().addClass('datepicker-dropdown');
20039 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
20040 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
20041 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
20042 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
20043 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
20044 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
20048 fireKey: function(e){
20049 if (!this.picker().isVisible()){
20050 if (e.keyCode == 27) { // allow escape to hide and re-show picker
20056 e.preventDefault();
20064 this.onTogglePeriod();
20067 this.onIncrementMinutes();
20070 this.onDecrementMinutes();
20079 onClick: function(e) {
20080 e.stopPropagation();
20081 e.preventDefault();
20084 picker : function()
20086 return this.el.select('.datepicker', true).first();
20089 fillTime: function()
20091 var time = this.pop.select('tbody', true).first();
20093 time.dom.innerHTML = '';
20108 cls: 'hours-up glyphicon glyphicon-chevron-up'
20128 cls: 'minutes-up glyphicon glyphicon-chevron-up'
20149 cls: 'timepicker-hour',
20164 cls: 'timepicker-minute',
20179 cls: 'btn btn-primary period',
20201 cls: 'hours-down glyphicon glyphicon-chevron-down'
20221 cls: 'minutes-down glyphicon glyphicon-chevron-down'
20239 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
20246 var hours = this.time.getHours();
20247 var minutes = this.time.getMinutes();
20260 hours = hours - 12;
20264 hours = '0' + hours;
20268 minutes = '0' + minutes;
20271 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
20272 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
20273 this.pop.select('button', true).first().dom.innerHTML = period;
20279 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
20281 var cls = ['bottom'];
20283 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
20290 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
20295 this.picker().addClass(cls.join('-'));
20299 Roo.each(cls, function(c){
20301 _this.picker().setTop(_this.inputEl().getHeight());
20305 _this.picker().setTop(0 - _this.picker().getHeight());
20310 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
20314 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
20321 onFocus : function()
20323 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
20327 onBlur : function()
20329 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
20335 this.picker().show();
20340 this.fireEvent('show', this, this.date);
20345 this.picker().hide();
20348 this.fireEvent('hide', this, this.date);
20351 setTime : function()
20354 this.setValue(this.time.format(this.format));
20356 this.fireEvent('select', this, this.date);
20361 onMousedown: function(e){
20362 e.stopPropagation();
20363 e.preventDefault();
20366 onIncrementHours: function()
20368 Roo.log('onIncrementHours');
20369 this.time = this.time.add(Date.HOUR, 1);
20374 onDecrementHours: function()
20376 Roo.log('onDecrementHours');
20377 this.time = this.time.add(Date.HOUR, -1);
20381 onIncrementMinutes: function()
20383 Roo.log('onIncrementMinutes');
20384 this.time = this.time.add(Date.MINUTE, 1);
20388 onDecrementMinutes: function()
20390 Roo.log('onDecrementMinutes');
20391 this.time = this.time.add(Date.MINUTE, -1);
20395 onTogglePeriod: function()
20397 Roo.log('onTogglePeriod');
20398 this.time = this.time.add(Date.HOUR, 12);
20405 Roo.apply(Roo.bootstrap.TimeField, {
20435 cls: 'btn btn-info ok',
20447 Roo.apply(Roo.bootstrap.TimeField, {
20451 cls: 'datepicker dropdown-menu',
20455 cls: 'datepicker-time',
20459 cls: 'table-condensed',
20461 Roo.bootstrap.TimeField.content,
20462 Roo.bootstrap.TimeField.footer
20481 * @class Roo.bootstrap.MonthField
20482 * @extends Roo.bootstrap.Input
20483 * Bootstrap MonthField class
20485 * @cfg {String} language default en
20488 * Create a new MonthField
20489 * @param {Object} config The config object
20492 Roo.bootstrap.MonthField = function(config){
20493 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
20498 * Fires when this field show.
20499 * @param {Roo.bootstrap.MonthField} this
20500 * @param {Mixed} date The date value
20505 * Fires when this field hide.
20506 * @param {Roo.bootstrap.MonthField} this
20507 * @param {Mixed} date The date value
20512 * Fires when select a date.
20513 * @param {Roo.bootstrap.MonthField} this
20514 * @param {String} oldvalue The old value
20515 * @param {String} newvalue The new value
20521 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
20523 onRender: function(ct, position)
20526 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
20528 this.language = this.language || 'en';
20529 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
20530 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
20532 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
20533 this.isInline = false;
20534 this.isInput = true;
20535 this.component = this.el.select('.add-on', true).first() || false;
20536 this.component = (this.component && this.component.length === 0) ? false : this.component;
20537 this.hasInput = this.component && this.inputEL().length;
20539 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
20541 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
20543 this.picker().on('mousedown', this.onMousedown, this);
20544 this.picker().on('click', this.onClick, this);
20546 this.picker().addClass('datepicker-dropdown');
20548 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
20549 v.setStyle('width', '189px');
20556 if(this.isInline) {
20562 setValue: function(v, suppressEvent)
20564 var o = this.getValue();
20566 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
20570 if(suppressEvent !== true){
20571 this.fireEvent('select', this, o, v);
20576 getValue: function()
20581 onClick: function(e)
20583 e.stopPropagation();
20584 e.preventDefault();
20586 var target = e.getTarget();
20588 if(target.nodeName.toLowerCase() === 'i'){
20589 target = Roo.get(target).dom.parentNode;
20592 var nodeName = target.nodeName;
20593 var className = target.className;
20594 var html = target.innerHTML;
20596 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
20600 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
20602 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20608 picker : function()
20610 return this.pickerEl;
20613 fillMonths: function()
20616 var months = this.picker().select('>.datepicker-months td', true).first();
20618 months.dom.innerHTML = '';
20624 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
20627 months.createChild(month);
20636 if(typeof(this.vIndex) == 'undefined' && this.value.length){
20637 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
20640 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
20641 e.removeClass('active');
20643 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
20644 e.addClass('active');
20651 if(this.isInline) {
20655 this.picker().removeClass(['bottom', 'top']);
20657 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
20659 * place to the top of element!
20663 this.picker().addClass('top');
20664 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
20669 this.picker().addClass('bottom');
20671 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
20674 onFocus : function()
20676 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
20680 onBlur : function()
20682 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
20684 var d = this.inputEl().getValue();
20693 this.picker().show();
20694 this.picker().select('>.datepicker-months', true).first().show();
20698 this.fireEvent('show', this, this.date);
20703 if(this.isInline) {
20706 this.picker().hide();
20707 this.fireEvent('hide', this, this.date);
20711 onMousedown: function(e)
20713 e.stopPropagation();
20714 e.preventDefault();
20719 Roo.bootstrap.MonthField.superclass.keyup.call(this);
20723 fireKey: function(e)
20725 if (!this.picker().isVisible()){
20726 if (e.keyCode == 27) {// allow escape to hide and re-show picker
20737 e.preventDefault();
20741 dir = e.keyCode == 37 ? -1 : 1;
20743 this.vIndex = this.vIndex + dir;
20745 if(this.vIndex < 0){
20749 if(this.vIndex > 11){
20753 if(isNaN(this.vIndex)){
20757 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20763 dir = e.keyCode == 38 ? -1 : 1;
20765 this.vIndex = this.vIndex + dir * 4;
20767 if(this.vIndex < 0){
20771 if(this.vIndex > 11){
20775 if(isNaN(this.vIndex)){
20779 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20784 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20785 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20789 e.preventDefault();
20792 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20793 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20809 this.picker().remove();
20814 Roo.apply(Roo.bootstrap.MonthField, {
20833 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
20834 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
20839 Roo.apply(Roo.bootstrap.MonthField, {
20843 cls: 'datepicker dropdown-menu roo-dynamic',
20847 cls: 'datepicker-months',
20851 cls: 'table-condensed',
20853 Roo.bootstrap.DateField.content
20873 * @class Roo.bootstrap.CheckBox
20874 * @extends Roo.bootstrap.Input
20875 * Bootstrap CheckBox class
20877 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
20878 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
20879 * @cfg {String} boxLabel The text that appears beside the checkbox
20880 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
20881 * @cfg {Boolean} checked initnal the element
20882 * @cfg {Boolean} inline inline the element (default false)
20883 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
20884 * @cfg {String} tooltip label tooltip
20887 * Create a new CheckBox
20888 * @param {Object} config The config object
20891 Roo.bootstrap.CheckBox = function(config){
20892 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
20897 * Fires when the element is checked or unchecked.
20898 * @param {Roo.bootstrap.CheckBox} this This input
20899 * @param {Boolean} checked The new checked value
20904 * Fires when the element is click.
20905 * @param {Roo.bootstrap.CheckBox} this This input
20912 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
20914 inputType: 'checkbox',
20923 getAutoCreate : function()
20925 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20931 cfg.cls = 'form-group ' + this.inputType; //input-group
20934 cfg.cls += ' ' + this.inputType + '-inline';
20940 type : this.inputType,
20941 value : this.inputValue,
20942 cls : 'roo-' + this.inputType, //'form-box',
20943 placeholder : this.placeholder || ''
20947 if(this.inputType != 'radio'){
20951 cls : 'roo-hidden-value',
20952 value : this.checked ? this.inputValue : this.valueOff
20957 if (this.weight) { // Validity check?
20958 cfg.cls += " " + this.inputType + "-" + this.weight;
20961 if (this.disabled) {
20962 input.disabled=true;
20966 input.checked = this.checked;
20971 input.name = this.name;
20973 if(this.inputType != 'radio'){
20974 hidden.name = this.name;
20975 input.name = '_hidden_' + this.name;
20980 input.cls += ' input-' + this.size;
20985 ['xs','sm','md','lg'].map(function(size){
20986 if (settings[size]) {
20987 cfg.cls += ' col-' + size + '-' + settings[size];
20991 var inputblock = input;
20993 if (this.before || this.after) {
20996 cls : 'input-group',
21001 inputblock.cn.push({
21003 cls : 'input-group-addon',
21008 inputblock.cn.push(input);
21010 if(this.inputType != 'radio'){
21011 inputblock.cn.push(hidden);
21015 inputblock.cn.push({
21017 cls : 'input-group-addon',
21024 if (align ==='left' && this.fieldLabel.length) {
21025 // Roo.log("left and has label");
21030 cls : 'control-label',
21031 html : this.fieldLabel
21041 if(this.labelWidth > 12){
21042 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
21045 if(this.labelWidth < 13 && this.labelmd == 0){
21046 this.labelmd = this.labelWidth;
21049 if(this.labellg > 0){
21050 cfg.cn[0].cls += ' col-lg-' + this.labellg;
21051 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
21054 if(this.labelmd > 0){
21055 cfg.cn[0].cls += ' col-md-' + this.labelmd;
21056 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
21059 if(this.labelsm > 0){
21060 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
21061 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
21064 if(this.labelxs > 0){
21065 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
21066 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
21069 } else if ( this.fieldLabel.length) {
21070 // Roo.log(" label");
21074 tag: this.boxLabel ? 'span' : 'label',
21076 cls: 'control-label box-input-label',
21077 //cls : 'input-group-addon',
21078 html : this.fieldLabel
21087 // Roo.log(" no label && no align");
21088 cfg.cn = [ inputblock ] ;
21094 var boxLabelCfg = {
21096 //'for': id, // box label is handled by onclick - so no for...
21098 html: this.boxLabel
21102 boxLabelCfg.tooltip = this.tooltip;
21105 cfg.cn.push(boxLabelCfg);
21108 if(this.inputType != 'radio'){
21109 cfg.cn.push(hidden);
21117 * return the real input element.
21119 inputEl: function ()
21121 return this.el.select('input.roo-' + this.inputType,true).first();
21123 hiddenEl: function ()
21125 return this.el.select('input.roo-hidden-value',true).first();
21128 labelEl: function()
21130 return this.el.select('label.control-label',true).first();
21132 /* depricated... */
21136 return this.labelEl();
21139 boxLabelEl: function()
21141 return this.el.select('label.box-label',true).first();
21144 initEvents : function()
21146 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
21148 this.inputEl().on('click', this.onClick, this);
21150 if (this.boxLabel) {
21151 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
21154 this.startValue = this.getValue();
21157 Roo.bootstrap.CheckBox.register(this);
21161 onClick : function(e)
21163 if(this.fireEvent('click', this, e) !== false){
21164 this.setChecked(!this.checked);
21169 setChecked : function(state,suppressEvent)
21171 this.startValue = this.getValue();
21173 if(this.inputType == 'radio'){
21175 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21176 e.dom.checked = false;
21179 this.inputEl().dom.checked = true;
21181 this.inputEl().dom.value = this.inputValue;
21183 if(suppressEvent !== true){
21184 this.fireEvent('check', this, true);
21192 this.checked = state;
21194 this.inputEl().dom.checked = state;
21197 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
21199 if(suppressEvent !== true){
21200 this.fireEvent('check', this, state);
21206 getValue : function()
21208 if(this.inputType == 'radio'){
21209 return this.getGroupValue();
21212 return this.hiddenEl().dom.value;
21216 getGroupValue : function()
21218 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
21222 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
21225 setValue : function(v,suppressEvent)
21227 if(this.inputType == 'radio'){
21228 this.setGroupValue(v, suppressEvent);
21232 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
21237 setGroupValue : function(v, suppressEvent)
21239 this.startValue = this.getValue();
21241 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21242 e.dom.checked = false;
21244 if(e.dom.value == v){
21245 e.dom.checked = true;
21249 if(suppressEvent !== true){
21250 this.fireEvent('check', this, true);
21258 validate : function()
21260 if(this.getVisibilityEl().hasClass('hidden')){
21266 (this.inputType == 'radio' && this.validateRadio()) ||
21267 (this.inputType == 'checkbox' && this.validateCheckbox())
21273 this.markInvalid();
21277 validateRadio : function()
21279 if(this.getVisibilityEl().hasClass('hidden')){
21283 if(this.allowBlank){
21289 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21290 if(!e.dom.checked){
21302 validateCheckbox : function()
21305 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
21306 //return (this.getValue() == this.inputValue) ? true : false;
21309 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21317 for(var i in group){
21318 if(group[i].el.isVisible(true)){
21326 for(var i in group){
21331 r = (group[i].getValue() == group[i].inputValue) ? true : false;
21338 * Mark this field as valid
21340 markValid : function()
21344 this.fireEvent('valid', this);
21346 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21349 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
21356 if(this.inputType == 'radio'){
21357 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21358 var fg = e.findParent('.form-group', false, true);
21359 if (Roo.bootstrap.version == 3) {
21360 fg.removeClass([_this.invalidClass, _this.validClass]);
21361 fg.addClass(_this.validClass);
21363 fg.removeClass(['is-valid', 'is-invalid']);
21364 fg.addClass('is-valid');
21372 var fg = this.el.findParent('.form-group', false, true);
21373 if (Roo.bootstrap.version == 3) {
21374 fg.removeClass([this.invalidClass, this.validClass]);
21375 fg.addClass(this.validClass);
21377 fg.removeClass(['is-valid', 'is-invalid']);
21378 fg.addClass('is-valid');
21383 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21389 for(var i in group){
21390 var fg = group[i].el.findParent('.form-group', false, true);
21391 if (Roo.bootstrap.version == 3) {
21392 fg.removeClass([this.invalidClass, this.validClass]);
21393 fg.addClass(this.validClass);
21395 fg.removeClass(['is-valid', 'is-invalid']);
21396 fg.addClass('is-valid');
21402 * Mark this field as invalid
21403 * @param {String} msg The validation message
21405 markInvalid : function(msg)
21407 if(this.allowBlank){
21413 this.fireEvent('invalid', this, msg);
21415 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21418 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
21422 label.markInvalid();
21425 if(this.inputType == 'radio'){
21427 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21428 var fg = e.findParent('.form-group', false, true);
21429 if (Roo.bootstrap.version == 3) {
21430 fg.removeClass([_this.invalidClass, _this.validClass]);
21431 fg.addClass(_this.invalidClass);
21433 fg.removeClass(['is-invalid', 'is-valid']);
21434 fg.addClass('is-invalid');
21442 var fg = this.el.findParent('.form-group', false, true);
21443 if (Roo.bootstrap.version == 3) {
21444 fg.removeClass([_this.invalidClass, _this.validClass]);
21445 fg.addClass(_this.invalidClass);
21447 fg.removeClass(['is-invalid', 'is-valid']);
21448 fg.addClass('is-invalid');
21453 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21459 for(var i in group){
21460 var fg = group[i].el.findParent('.form-group', false, true);
21461 if (Roo.bootstrap.version == 3) {
21462 fg.removeClass([_this.invalidClass, _this.validClass]);
21463 fg.addClass(_this.invalidClass);
21465 fg.removeClass(['is-invalid', 'is-valid']);
21466 fg.addClass('is-invalid');
21472 clearInvalid : function()
21474 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
21476 // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21478 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21480 if (label && label.iconEl) {
21481 label.iconEl.removeClass([ label.validClass, label.invalidClass ]);
21482 label.iconEl.removeClass(['is-invalid', 'is-valid']);
21486 disable : function()
21488 if(this.inputType != 'radio'){
21489 Roo.bootstrap.CheckBox.superclass.disable.call(this);
21496 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21497 _this.getActionEl().addClass(this.disabledClass);
21498 e.dom.disabled = true;
21502 this.disabled = true;
21503 this.fireEvent("disable", this);
21507 enable : function()
21509 if(this.inputType != 'radio'){
21510 Roo.bootstrap.CheckBox.superclass.enable.call(this);
21517 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21518 _this.getActionEl().removeClass(this.disabledClass);
21519 e.dom.disabled = false;
21523 this.disabled = false;
21524 this.fireEvent("enable", this);
21528 setBoxLabel : function(v)
21533 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21539 Roo.apply(Roo.bootstrap.CheckBox, {
21544 * register a CheckBox Group
21545 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
21547 register : function(checkbox)
21549 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
21550 this.groups[checkbox.groupId] = {};
21553 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
21557 this.groups[checkbox.groupId][checkbox.name] = checkbox;
21561 * fetch a CheckBox Group based on the group ID
21562 * @param {string} the group ID
21563 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
21565 get: function(groupId) {
21566 if (typeof(this.groups[groupId]) == 'undefined') {
21570 return this.groups[groupId] ;
21583 * @class Roo.bootstrap.Radio
21584 * @extends Roo.bootstrap.Component
21585 * Bootstrap Radio class
21586 * @cfg {String} boxLabel - the label associated
21587 * @cfg {String} value - the value of radio
21590 * Create a new Radio
21591 * @param {Object} config The config object
21593 Roo.bootstrap.Radio = function(config){
21594 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
21598 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
21604 getAutoCreate : function()
21608 cls : 'form-group radio',
21613 html : this.boxLabel
21621 initEvents : function()
21623 this.parent().register(this);
21625 this.el.on('click', this.onClick, this);
21629 onClick : function(e)
21631 if(this.parent().fireEvent('click', this.parent(), this, e) !== false){
21632 this.setChecked(true);
21636 setChecked : function(state, suppressEvent)
21638 this.parent().setValue(this.value, suppressEvent);
21642 setBoxLabel : function(v)
21647 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21662 * @class Roo.bootstrap.SecurePass
21663 * @extends Roo.bootstrap.Input
21664 * Bootstrap SecurePass class
21668 * Create a new SecurePass
21669 * @param {Object} config The config object
21672 Roo.bootstrap.SecurePass = function (config) {
21673 // these go here, so the translation tool can replace them..
21675 PwdEmpty: "Please type a password, and then retype it to confirm.",
21676 PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21677 PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21678 PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21679 IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21680 FNInPwd: "Your password can't contain your first name. Please type a different password.",
21681 LNInPwd: "Your password can't contain your last name. Please type a different password.",
21682 TooWeak: "Your password is Too Weak."
21684 this.meterLabel = "Password strength:";
21685 this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
21686 this.meterClass = [
21687 "roo-password-meter-tooweak",
21688 "roo-password-meter-weak",
21689 "roo-password-meter-medium",
21690 "roo-password-meter-strong",
21691 "roo-password-meter-grey"
21696 Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
21699 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
21701 * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
21703 * PwdEmpty: "Please type a password, and then retype it to confirm.",
21704 * PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21705 * PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21706 * PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21707 * IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21708 * FNInPwd: "Your password can't contain your first name. Please type a different password.",
21709 * LNInPwd: "Your password can't contain your last name. Please type a different password."
21719 * @cfg {String/Object} Label for the strength meter (defaults to
21720 * 'Password strength:')
21725 * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
21726 * ['Weak', 'Medium', 'Strong'])
21729 pwdStrengths: false,
21742 initEvents: function ()
21744 Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
21746 if (this.el.is('input[type=password]') && Roo.isSafari) {
21747 this.el.on('keydown', this.SafariOnKeyDown, this);
21750 this.el.on('keyup', this.checkStrength, this, {buffer: 50});
21753 onRender: function (ct, position)
21755 Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
21756 this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
21757 this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
21759 this.trigger.createChild({
21764 cls: 'roo-password-meter-grey col-xs-12',
21767 //width: this.meterWidth + 'px'
21771 cls: 'roo-password-meter-text'
21777 if (this.hideTrigger) {
21778 this.trigger.setDisplayed(false);
21780 this.setSize(this.width || '', this.height || '');
21783 onDestroy: function ()
21785 if (this.trigger) {
21786 this.trigger.removeAllListeners();
21787 this.trigger.remove();
21790 this.wrap.remove();
21792 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
21795 checkStrength: function ()
21797 var pwd = this.inputEl().getValue();
21798 if (pwd == this._lastPwd) {
21803 if (this.ClientSideStrongPassword(pwd)) {
21805 } else if (this.ClientSideMediumPassword(pwd)) {
21807 } else if (this.ClientSideWeakPassword(pwd)) {
21813 Roo.log('strength1: ' + strength);
21815 //var pm = this.trigger.child('div/div/div').dom;
21816 var pm = this.trigger.child('div/div');
21817 pm.removeClass(this.meterClass);
21818 pm.addClass(this.meterClass[strength]);
21821 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21823 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21825 this._lastPwd = pwd;
21829 Roo.bootstrap.SecurePass.superclass.reset.call(this);
21831 this._lastPwd = '';
21833 var pm = this.trigger.child('div/div');
21834 pm.removeClass(this.meterClass);
21835 pm.addClass('roo-password-meter-grey');
21838 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21841 this.inputEl().dom.type='password';
21844 validateValue: function (value)
21847 if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
21850 if (value.length == 0) {
21851 if (this.allowBlank) {
21852 this.clearInvalid();
21856 this.markInvalid(this.errors.PwdEmpty);
21857 this.errorMsg = this.errors.PwdEmpty;
21865 if ('[\x21-\x7e]*'.match(value)) {
21866 this.markInvalid(this.errors.PwdBadChar);
21867 this.errorMsg = this.errors.PwdBadChar;
21870 if (value.length < 6) {
21871 this.markInvalid(this.errors.PwdShort);
21872 this.errorMsg = this.errors.PwdShort;
21875 if (value.length > 16) {
21876 this.markInvalid(this.errors.PwdLong);
21877 this.errorMsg = this.errors.PwdLong;
21881 if (this.ClientSideStrongPassword(value)) {
21883 } else if (this.ClientSideMediumPassword(value)) {
21885 } else if (this.ClientSideWeakPassword(value)) {
21892 if (strength < 2) {
21893 //this.markInvalid(this.errors.TooWeak);
21894 this.errorMsg = this.errors.TooWeak;
21899 console.log('strength2: ' + strength);
21901 //var pm = this.trigger.child('div/div/div').dom;
21903 var pm = this.trigger.child('div/div');
21904 pm.removeClass(this.meterClass);
21905 pm.addClass(this.meterClass[strength]);
21907 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21909 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21911 this.errorMsg = '';
21915 CharacterSetChecks: function (type)
21918 this.fResult = false;
21921 isctype: function (character, type)
21924 case this.kCapitalLetter:
21925 if (character >= 'A' && character <= 'Z') {
21930 case this.kSmallLetter:
21931 if (character >= 'a' && character <= 'z') {
21937 if (character >= '0' && character <= '9') {
21942 case this.kPunctuation:
21943 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
21954 IsLongEnough: function (pwd, size)
21956 return !(pwd == null || isNaN(size) || pwd.length < size);
21959 SpansEnoughCharacterSets: function (word, nb)
21961 if (!this.IsLongEnough(word, nb))
21966 var characterSetChecks = new Array(
21967 new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
21968 new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
21971 for (var index = 0; index < word.length; ++index) {
21972 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21973 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
21974 characterSetChecks[nCharSet].fResult = true;
21981 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21982 if (characterSetChecks[nCharSet].fResult) {
21987 if (nCharSets < nb) {
21993 ClientSideStrongPassword: function (pwd)
21995 return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
21998 ClientSideMediumPassword: function (pwd)
22000 return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
22003 ClientSideWeakPassword: function (pwd)
22005 return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
22008 })//<script type="text/javascript">
22011 * Based Ext JS Library 1.1.1
22012 * Copyright(c) 2006-2007, Ext JS, LLC.
22018 * @class Roo.HtmlEditorCore
22019 * @extends Roo.Component
22020 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
22022 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
22025 Roo.HtmlEditorCore = function(config){
22028 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
22033 * @event initialize
22034 * Fires when the editor is fully initialized (including the iframe)
22035 * @param {Roo.HtmlEditorCore} this
22040 * Fires when the editor is first receives the focus. Any insertion must wait
22041 * until after this event.
22042 * @param {Roo.HtmlEditorCore} this
22046 * @event beforesync
22047 * Fires before the textarea is updated with content from the editor iframe. Return false
22048 * to cancel the sync.
22049 * @param {Roo.HtmlEditorCore} this
22050 * @param {String} html
22054 * @event beforepush
22055 * Fires before the iframe editor is updated with content from the textarea. Return false
22056 * to cancel the push.
22057 * @param {Roo.HtmlEditorCore} this
22058 * @param {String} html
22063 * Fires when the textarea is updated with content from the editor iframe.
22064 * @param {Roo.HtmlEditorCore} this
22065 * @param {String} html
22070 * Fires when the iframe editor is updated with content from the textarea.
22071 * @param {Roo.HtmlEditorCore} this
22072 * @param {String} html
22077 * @event editorevent
22078 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
22079 * @param {Roo.HtmlEditorCore} this
22085 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
22087 // defaults : white / black...
22088 this.applyBlacklists();
22095 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
22099 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
22105 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
22110 * @cfg {Number} height (in pixels)
22114 * @cfg {Number} width (in pixels)
22119 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
22122 stylesheets: false,
22127 // private properties
22128 validationEvent : false,
22130 initialized : false,
22132 sourceEditMode : false,
22133 onFocus : Roo.emptyFn,
22135 hideMode:'offsets',
22139 // blacklist + whitelisted elements..
22146 * Protected method that will not generally be called directly. It
22147 * is called when the editor initializes the iframe with HTML contents. Override this method if you
22148 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
22150 getDocMarkup : function(){
22154 // inherit styels from page...??
22155 if (this.stylesheets === false) {
22157 Roo.get(document.head).select('style').each(function(node) {
22158 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
22161 Roo.get(document.head).select('link').each(function(node) {
22162 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
22165 } else if (!this.stylesheets.length) {
22167 st = '<style type="text/css">' +
22168 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
22171 st = '<style type="text/css">' +
22176 st += '<style type="text/css">' +
22177 'IMG { cursor: pointer } ' +
22180 var cls = 'roo-htmleditor-body';
22182 if(this.bodyCls.length){
22183 cls += ' ' + this.bodyCls;
22186 return '<html><head>' + st +
22187 //<style type="text/css">' +
22188 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
22190 ' </head><body class="' + cls + '"></body></html>';
22194 onRender : function(ct, position)
22197 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
22198 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
22201 this.el.dom.style.border = '0 none';
22202 this.el.dom.setAttribute('tabIndex', -1);
22203 this.el.addClass('x-hidden hide');
22207 if(Roo.isIE){ // fix IE 1px bogus margin
22208 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
22212 this.frameId = Roo.id();
22216 var iframe = this.owner.wrap.createChild({
22218 cls: 'form-control', // bootstrap..
22220 name: this.frameId,
22221 frameBorder : 'no',
22222 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
22227 this.iframe = iframe.dom;
22229 this.assignDocWin();
22231 this.doc.designMode = 'on';
22234 this.doc.write(this.getDocMarkup());
22238 var task = { // must defer to wait for browser to be ready
22240 //console.log("run task?" + this.doc.readyState);
22241 this.assignDocWin();
22242 if(this.doc.body || this.doc.readyState == 'complete'){
22244 this.doc.designMode="on";
22248 Roo.TaskMgr.stop(task);
22249 this.initEditor.defer(10, this);
22256 Roo.TaskMgr.start(task);
22261 onResize : function(w, h)
22263 Roo.log('resize: ' +w + ',' + h );
22264 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
22268 if(typeof w == 'number'){
22270 this.iframe.style.width = w + 'px';
22272 if(typeof h == 'number'){
22274 this.iframe.style.height = h + 'px';
22276 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
22283 * Toggles the editor between standard and source edit mode.
22284 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
22286 toggleSourceEdit : function(sourceEditMode){
22288 this.sourceEditMode = sourceEditMode === true;
22290 if(this.sourceEditMode){
22292 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
22295 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
22296 //this.iframe.className = '';
22299 //this.setSize(this.owner.wrap.getSize());
22300 //this.fireEvent('editmodechange', this, this.sourceEditMode);
22307 * Protected method that will not generally be called directly. If you need/want
22308 * custom HTML cleanup, this is the method you should override.
22309 * @param {String} html The HTML to be cleaned
22310 * return {String} The cleaned HTML
22312 cleanHtml : function(html){
22313 html = String(html);
22314 if(html.length > 5){
22315 if(Roo.isSafari){ // strip safari nonsense
22316 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
22319 if(html == ' '){
22326 * HTML Editor -> Textarea
22327 * Protected method that will not generally be called directly. Syncs the contents
22328 * of the editor iframe with the textarea.
22330 syncValue : function(){
22331 if(this.initialized){
22332 var bd = (this.doc.body || this.doc.documentElement);
22333 //this.cleanUpPaste(); -- this is done else where and causes havoc..
22334 var html = bd.innerHTML;
22336 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
22337 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
22339 html = '<div style="'+m[0]+'">' + html + '</div>';
22342 html = this.cleanHtml(html);
22343 // fix up the special chars.. normaly like back quotes in word...
22344 // however we do not want to do this with chinese..
22345 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
22346 var cc = b.charCodeAt();
22348 (cc >= 0x4E00 && cc < 0xA000 ) ||
22349 (cc >= 0x3400 && cc < 0x4E00 ) ||
22350 (cc >= 0xf900 && cc < 0xfb00 )
22356 if(this.owner.fireEvent('beforesync', this, html) !== false){
22357 this.el.dom.value = html;
22358 this.owner.fireEvent('sync', this, html);
22364 * Protected method that will not generally be called directly. Pushes the value of the textarea
22365 * into the iframe editor.
22367 pushValue : function(){
22368 if(this.initialized){
22369 var v = this.el.dom.value.trim();
22371 // if(v.length < 1){
22375 if(this.owner.fireEvent('beforepush', this, v) !== false){
22376 var d = (this.doc.body || this.doc.documentElement);
22378 this.cleanUpPaste();
22379 this.el.dom.value = d.innerHTML;
22380 this.owner.fireEvent('push', this, v);
22386 deferFocus : function(){
22387 this.focus.defer(10, this);
22391 focus : function(){
22392 if(this.win && !this.sourceEditMode){
22399 assignDocWin: function()
22401 var iframe = this.iframe;
22404 this.doc = iframe.contentWindow.document;
22405 this.win = iframe.contentWindow;
22407 // if (!Roo.get(this.frameId)) {
22410 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
22411 // this.win = Roo.get(this.frameId).dom.contentWindow;
22413 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
22417 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
22418 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
22423 initEditor : function(){
22424 //console.log("INIT EDITOR");
22425 this.assignDocWin();
22429 this.doc.designMode="on";
22431 this.doc.write(this.getDocMarkup());
22434 var dbody = (this.doc.body || this.doc.documentElement);
22435 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
22436 // this copies styles from the containing element into thsi one..
22437 // not sure why we need all of this..
22438 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
22440 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
22441 //ss['background-attachment'] = 'fixed'; // w3c
22442 dbody.bgProperties = 'fixed'; // ie
22443 //Roo.DomHelper.applyStyles(dbody, ss);
22444 Roo.EventManager.on(this.doc, {
22445 //'mousedown': this.onEditorEvent,
22446 'mouseup': this.onEditorEvent,
22447 'dblclick': this.onEditorEvent,
22448 'click': this.onEditorEvent,
22449 'keyup': this.onEditorEvent,
22454 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
22456 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
22457 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
22459 this.initialized = true;
22461 this.owner.fireEvent('initialize', this);
22466 onDestroy : function(){
22472 //for (var i =0; i < this.toolbars.length;i++) {
22473 // // fixme - ask toolbars for heights?
22474 // this.toolbars[i].onDestroy();
22477 //this.wrap.dom.innerHTML = '';
22478 //this.wrap.remove();
22483 onFirstFocus : function(){
22485 this.assignDocWin();
22488 this.activated = true;
22491 if(Roo.isGecko){ // prevent silly gecko errors
22493 var s = this.win.getSelection();
22494 if(!s.focusNode || s.focusNode.nodeType != 3){
22495 var r = s.getRangeAt(0);
22496 r.selectNodeContents((this.doc.body || this.doc.documentElement));
22501 this.execCmd('useCSS', true);
22502 this.execCmd('styleWithCSS', false);
22505 this.owner.fireEvent('activate', this);
22509 adjustFont: function(btn){
22510 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
22511 //if(Roo.isSafari){ // safari
22514 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
22515 if(Roo.isSafari){ // safari
22516 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
22517 v = (v < 10) ? 10 : v;
22518 v = (v > 48) ? 48 : v;
22519 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
22524 v = Math.max(1, v+adjust);
22526 this.execCmd('FontSize', v );
22529 onEditorEvent : function(e)
22531 this.owner.fireEvent('editorevent', this, e);
22532 // this.updateToolbar();
22533 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
22536 insertTag : function(tg)
22538 // could be a bit smarter... -> wrap the current selected tRoo..
22539 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
22541 range = this.createRange(this.getSelection());
22542 var wrappingNode = this.doc.createElement(tg.toLowerCase());
22543 wrappingNode.appendChild(range.extractContents());
22544 range.insertNode(wrappingNode);
22551 this.execCmd("formatblock", tg);
22555 insertText : function(txt)
22559 var range = this.createRange();
22560 range.deleteContents();
22561 //alert(Sender.getAttribute('label'));
22563 range.insertNode(this.doc.createTextNode(txt));
22569 * Executes a Midas editor command on the editor document and performs necessary focus and
22570 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
22571 * @param {String} cmd The Midas command
22572 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22574 relayCmd : function(cmd, value){
22576 this.execCmd(cmd, value);
22577 this.owner.fireEvent('editorevent', this);
22578 //this.updateToolbar();
22579 this.owner.deferFocus();
22583 * Executes a Midas editor command directly on the editor document.
22584 * For visual commands, you should use {@link #relayCmd} instead.
22585 * <b>This should only be called after the editor is initialized.</b>
22586 * @param {String} cmd The Midas command
22587 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22589 execCmd : function(cmd, value){
22590 this.doc.execCommand(cmd, false, value === undefined ? null : value);
22597 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
22599 * @param {String} text | dom node..
22601 insertAtCursor : function(text)
22604 if(!this.activated){
22610 var r = this.doc.selection.createRange();
22621 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
22625 // from jquery ui (MIT licenced)
22627 var win = this.win;
22629 if (win.getSelection && win.getSelection().getRangeAt) {
22630 range = win.getSelection().getRangeAt(0);
22631 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
22632 range.insertNode(node);
22633 } else if (win.document.selection && win.document.selection.createRange) {
22634 // no firefox support
22635 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22636 win.document.selection.createRange().pasteHTML(txt);
22638 // no firefox support
22639 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22640 this.execCmd('InsertHTML', txt);
22649 mozKeyPress : function(e){
22651 var c = e.getCharCode(), cmd;
22654 c = String.fromCharCode(c).toLowerCase();
22668 this.cleanUpPaste.defer(100, this);
22676 e.preventDefault();
22684 fixKeys : function(){ // load time branching for fastest keydown performance
22686 return function(e){
22687 var k = e.getKey(), r;
22690 r = this.doc.selection.createRange();
22693 r.pasteHTML('    ');
22700 r = this.doc.selection.createRange();
22702 var target = r.parentElement();
22703 if(!target || target.tagName.toLowerCase() != 'li'){
22705 r.pasteHTML('<br />');
22711 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22712 this.cleanUpPaste.defer(100, this);
22718 }else if(Roo.isOpera){
22719 return function(e){
22720 var k = e.getKey();
22724 this.execCmd('InsertHTML','    ');
22727 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22728 this.cleanUpPaste.defer(100, this);
22733 }else if(Roo.isSafari){
22734 return function(e){
22735 var k = e.getKey();
22739 this.execCmd('InsertText','\t');
22743 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22744 this.cleanUpPaste.defer(100, this);
22752 getAllAncestors: function()
22754 var p = this.getSelectedNode();
22757 a.push(p); // push blank onto stack..
22758 p = this.getParentElement();
22762 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
22766 a.push(this.doc.body);
22770 lastSelNode : false,
22773 getSelection : function()
22775 this.assignDocWin();
22776 return Roo.isIE ? this.doc.selection : this.win.getSelection();
22779 getSelectedNode: function()
22781 // this may only work on Gecko!!!
22783 // should we cache this!!!!
22788 var range = this.createRange(this.getSelection()).cloneRange();
22791 var parent = range.parentElement();
22793 var testRange = range.duplicate();
22794 testRange.moveToElementText(parent);
22795 if (testRange.inRange(range)) {
22798 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
22801 parent = parent.parentElement;
22806 // is ancestor a text element.
22807 var ac = range.commonAncestorContainer;
22808 if (ac.nodeType == 3) {
22809 ac = ac.parentNode;
22812 var ar = ac.childNodes;
22815 var other_nodes = [];
22816 var has_other_nodes = false;
22817 for (var i=0;i<ar.length;i++) {
22818 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
22821 // fullly contained node.
22823 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
22828 // probably selected..
22829 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
22830 other_nodes.push(ar[i]);
22834 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
22839 has_other_nodes = true;
22841 if (!nodes.length && other_nodes.length) {
22842 nodes= other_nodes;
22844 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
22850 createRange: function(sel)
22852 // this has strange effects when using with
22853 // top toolbar - not sure if it's a great idea.
22854 //this.editor.contentWindow.focus();
22855 if (typeof sel != "undefined") {
22857 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
22859 return this.doc.createRange();
22862 return this.doc.createRange();
22865 getParentElement: function()
22868 this.assignDocWin();
22869 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
22871 var range = this.createRange(sel);
22874 var p = range.commonAncestorContainer;
22875 while (p.nodeType == 3) { // text node
22886 * Range intersection.. the hard stuff...
22890 * [ -- selected range --- ]
22894 * if end is before start or hits it. fail.
22895 * if start is after end or hits it fail.
22897 * if either hits (but other is outside. - then it's not
22903 // @see http://www.thismuchiknow.co.uk/?p=64.
22904 rangeIntersectsNode : function(range, node)
22906 var nodeRange = node.ownerDocument.createRange();
22908 nodeRange.selectNode(node);
22910 nodeRange.selectNodeContents(node);
22913 var rangeStartRange = range.cloneRange();
22914 rangeStartRange.collapse(true);
22916 var rangeEndRange = range.cloneRange();
22917 rangeEndRange.collapse(false);
22919 var nodeStartRange = nodeRange.cloneRange();
22920 nodeStartRange.collapse(true);
22922 var nodeEndRange = nodeRange.cloneRange();
22923 nodeEndRange.collapse(false);
22925 return rangeStartRange.compareBoundaryPoints(
22926 Range.START_TO_START, nodeEndRange) == -1 &&
22927 rangeEndRange.compareBoundaryPoints(
22928 Range.START_TO_START, nodeStartRange) == 1;
22932 rangeCompareNode : function(range, node)
22934 var nodeRange = node.ownerDocument.createRange();
22936 nodeRange.selectNode(node);
22938 nodeRange.selectNodeContents(node);
22942 range.collapse(true);
22944 nodeRange.collapse(true);
22946 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
22947 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
22949 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
22951 var nodeIsBefore = ss == 1;
22952 var nodeIsAfter = ee == -1;
22954 if (nodeIsBefore && nodeIsAfter) {
22957 if (!nodeIsBefore && nodeIsAfter) {
22958 return 1; //right trailed.
22961 if (nodeIsBefore && !nodeIsAfter) {
22962 return 2; // left trailed.
22968 // private? - in a new class?
22969 cleanUpPaste : function()
22971 // cleans up the whole document..
22972 Roo.log('cleanuppaste');
22974 this.cleanUpChildren(this.doc.body);
22975 var clean = this.cleanWordChars(this.doc.body.innerHTML);
22976 if (clean != this.doc.body.innerHTML) {
22977 this.doc.body.innerHTML = clean;
22982 cleanWordChars : function(input) {// change the chars to hex code
22983 var he = Roo.HtmlEditorCore;
22985 var output = input;
22986 Roo.each(he.swapCodes, function(sw) {
22987 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
22989 output = output.replace(swapper, sw[1]);
22996 cleanUpChildren : function (n)
22998 if (!n.childNodes.length) {
23001 for (var i = n.childNodes.length-1; i > -1 ; i--) {
23002 this.cleanUpChild(n.childNodes[i]);
23009 cleanUpChild : function (node)
23012 //console.log(node);
23013 if (node.nodeName == "#text") {
23014 // clean up silly Windows -- stuff?
23017 if (node.nodeName == "#comment") {
23018 node.parentNode.removeChild(node);
23019 // clean up silly Windows -- stuff?
23022 var lcname = node.tagName.toLowerCase();
23023 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
23024 // whitelist of tags..
23026 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
23028 node.parentNode.removeChild(node);
23033 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
23035 // remove <a name=....> as rendering on yahoo mailer is borked with this.
23036 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
23038 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
23039 // remove_keep_children = true;
23042 if (remove_keep_children) {
23043 this.cleanUpChildren(node);
23044 // inserts everything just before this node...
23045 while (node.childNodes.length) {
23046 var cn = node.childNodes[0];
23047 node.removeChild(cn);
23048 node.parentNode.insertBefore(cn, node);
23050 node.parentNode.removeChild(node);
23054 if (!node.attributes || !node.attributes.length) {
23055 this.cleanUpChildren(node);
23059 function cleanAttr(n,v)
23062 if (v.match(/^\./) || v.match(/^\//)) {
23065 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/) || v.match(/^ftp:/)) {
23068 if (v.match(/^#/)) {
23071 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
23072 node.removeAttribute(n);
23076 var cwhite = this.cwhite;
23077 var cblack = this.cblack;
23079 function cleanStyle(n,v)
23081 if (v.match(/expression/)) { //XSS?? should we even bother..
23082 node.removeAttribute(n);
23086 var parts = v.split(/;/);
23089 Roo.each(parts, function(p) {
23090 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
23094 var l = p.split(':').shift().replace(/\s+/g,'');
23095 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
23097 if ( cwhite.length && cblack.indexOf(l) > -1) {
23098 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
23099 //node.removeAttribute(n);
23103 // only allow 'c whitelisted system attributes'
23104 if ( cwhite.length && cwhite.indexOf(l) < 0) {
23105 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
23106 //node.removeAttribute(n);
23116 if (clean.length) {
23117 node.setAttribute(n, clean.join(';'));
23119 node.removeAttribute(n);
23125 for (var i = node.attributes.length-1; i > -1 ; i--) {
23126 var a = node.attributes[i];
23129 if (a.name.toLowerCase().substr(0,2)=='on') {
23130 node.removeAttribute(a.name);
23133 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
23134 node.removeAttribute(a.name);
23137 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
23138 cleanAttr(a.name,a.value); // fixme..
23141 if (a.name == 'style') {
23142 cleanStyle(a.name,a.value);
23145 /// clean up MS crap..
23146 // tecnically this should be a list of valid class'es..
23149 if (a.name == 'class') {
23150 if (a.value.match(/^Mso/)) {
23151 node.className = '';
23154 if (a.value.match(/^body$/)) {
23155 node.className = '';
23166 this.cleanUpChildren(node);
23172 * Clean up MS wordisms...
23174 cleanWord : function(node)
23179 this.cleanWord(this.doc.body);
23182 if (node.nodeName == "#text") {
23183 // clean up silly Windows -- stuff?
23186 if (node.nodeName == "#comment") {
23187 node.parentNode.removeChild(node);
23188 // clean up silly Windows -- stuff?
23192 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
23193 node.parentNode.removeChild(node);
23197 // remove - but keep children..
23198 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
23199 while (node.childNodes.length) {
23200 var cn = node.childNodes[0];
23201 node.removeChild(cn);
23202 node.parentNode.insertBefore(cn, node);
23204 node.parentNode.removeChild(node);
23205 this.iterateChildren(node, this.cleanWord);
23209 if (node.className.length) {
23211 var cn = node.className.split(/\W+/);
23213 Roo.each(cn, function(cls) {
23214 if (cls.match(/Mso[a-zA-Z]+/)) {
23219 node.className = cna.length ? cna.join(' ') : '';
23221 node.removeAttribute("class");
23225 if (node.hasAttribute("lang")) {
23226 node.removeAttribute("lang");
23229 if (node.hasAttribute("style")) {
23231 var styles = node.getAttribute("style").split(";");
23233 Roo.each(styles, function(s) {
23234 if (!s.match(/:/)) {
23237 var kv = s.split(":");
23238 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
23241 // what ever is left... we allow.
23244 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
23245 if (!nstyle.length) {
23246 node.removeAttribute('style');
23249 this.iterateChildren(node, this.cleanWord);
23255 * iterateChildren of a Node, calling fn each time, using this as the scole..
23256 * @param {DomNode} node node to iterate children of.
23257 * @param {Function} fn method of this class to call on each item.
23259 iterateChildren : function(node, fn)
23261 if (!node.childNodes.length) {
23264 for (var i = node.childNodes.length-1; i > -1 ; i--) {
23265 fn.call(this, node.childNodes[i])
23271 * cleanTableWidths.
23273 * Quite often pasting from word etc.. results in tables with column and widths.
23274 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
23277 cleanTableWidths : function(node)
23282 this.cleanTableWidths(this.doc.body);
23287 if (node.nodeName == "#text" || node.nodeName == "#comment") {
23290 Roo.log(node.tagName);
23291 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
23292 this.iterateChildren(node, this.cleanTableWidths);
23295 if (node.hasAttribute('width')) {
23296 node.removeAttribute('width');
23300 if (node.hasAttribute("style")) {
23303 var styles = node.getAttribute("style").split(";");
23305 Roo.each(styles, function(s) {
23306 if (!s.match(/:/)) {
23309 var kv = s.split(":");
23310 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
23313 // what ever is left... we allow.
23316 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
23317 if (!nstyle.length) {
23318 node.removeAttribute('style');
23322 this.iterateChildren(node, this.cleanTableWidths);
23330 domToHTML : function(currentElement, depth, nopadtext) {
23332 depth = depth || 0;
23333 nopadtext = nopadtext || false;
23335 if (!currentElement) {
23336 return this.domToHTML(this.doc.body);
23339 //Roo.log(currentElement);
23341 var allText = false;
23342 var nodeName = currentElement.nodeName;
23343 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
23345 if (nodeName == '#text') {
23347 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
23352 if (nodeName != 'BODY') {
23355 // Prints the node tagName, such as <A>, <IMG>, etc
23358 for(i = 0; i < currentElement.attributes.length;i++) {
23360 var aname = currentElement.attributes.item(i).name;
23361 if (!currentElement.attributes.item(i).value.length) {
23364 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
23367 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
23376 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
23379 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
23384 // Traverse the tree
23386 var currentElementChild = currentElement.childNodes.item(i);
23387 var allText = true;
23388 var innerHTML = '';
23390 while (currentElementChild) {
23391 // Formatting code (indent the tree so it looks nice on the screen)
23392 var nopad = nopadtext;
23393 if (lastnode == 'SPAN') {
23397 if (currentElementChild.nodeName == '#text') {
23398 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
23399 toadd = nopadtext ? toadd : toadd.trim();
23400 if (!nopad && toadd.length > 80) {
23401 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
23403 innerHTML += toadd;
23406 currentElementChild = currentElement.childNodes.item(i);
23412 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
23414 // Recursively traverse the tree structure of the child node
23415 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
23416 lastnode = currentElementChild.nodeName;
23418 currentElementChild=currentElement.childNodes.item(i);
23424 // The remaining code is mostly for formatting the tree
23425 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
23430 ret+= "</"+tagName+">";
23436 applyBlacklists : function()
23438 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
23439 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
23443 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
23444 if (b.indexOf(tag) > -1) {
23447 this.white.push(tag);
23451 Roo.each(w, function(tag) {
23452 if (b.indexOf(tag) > -1) {
23455 if (this.white.indexOf(tag) > -1) {
23458 this.white.push(tag);
23463 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
23464 if (w.indexOf(tag) > -1) {
23467 this.black.push(tag);
23471 Roo.each(b, function(tag) {
23472 if (w.indexOf(tag) > -1) {
23475 if (this.black.indexOf(tag) > -1) {
23478 this.black.push(tag);
23483 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
23484 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
23488 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
23489 if (b.indexOf(tag) > -1) {
23492 this.cwhite.push(tag);
23496 Roo.each(w, function(tag) {
23497 if (b.indexOf(tag) > -1) {
23500 if (this.cwhite.indexOf(tag) > -1) {
23503 this.cwhite.push(tag);
23508 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
23509 if (w.indexOf(tag) > -1) {
23512 this.cblack.push(tag);
23516 Roo.each(b, function(tag) {
23517 if (w.indexOf(tag) > -1) {
23520 if (this.cblack.indexOf(tag) > -1) {
23523 this.cblack.push(tag);
23528 setStylesheets : function(stylesheets)
23530 if(typeof(stylesheets) == 'string'){
23531 Roo.get(this.iframe.contentDocument.head).createChild({
23533 rel : 'stylesheet',
23542 Roo.each(stylesheets, function(s) {
23547 Roo.get(_this.iframe.contentDocument.head).createChild({
23549 rel : 'stylesheet',
23558 removeStylesheets : function()
23562 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
23567 setStyle : function(style)
23569 Roo.get(this.iframe.contentDocument.head).createChild({
23578 // hide stuff that is not compatible
23592 * @event specialkey
23596 * @cfg {String} fieldClass @hide
23599 * @cfg {String} focusClass @hide
23602 * @cfg {String} autoCreate @hide
23605 * @cfg {String} inputType @hide
23608 * @cfg {String} invalidClass @hide
23611 * @cfg {String} invalidText @hide
23614 * @cfg {String} msgFx @hide
23617 * @cfg {String} validateOnBlur @hide
23621 Roo.HtmlEditorCore.white = [
23622 'area', 'br', 'img', 'input', 'hr', 'wbr',
23624 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
23625 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
23626 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
23627 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
23628 'table', 'ul', 'xmp',
23630 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
23633 'dir', 'menu', 'ol', 'ul', 'dl',
23639 Roo.HtmlEditorCore.black = [
23640 // 'embed', 'object', // enable - backend responsiblity to clean thiese
23642 'base', 'basefont', 'bgsound', 'blink', 'body',
23643 'frame', 'frameset', 'head', 'html', 'ilayer',
23644 'iframe', 'layer', 'link', 'meta', 'object',
23645 'script', 'style' ,'title', 'xml' // clean later..
23647 Roo.HtmlEditorCore.clean = [
23648 'script', 'style', 'title', 'xml'
23650 Roo.HtmlEditorCore.remove = [
23655 Roo.HtmlEditorCore.ablack = [
23659 Roo.HtmlEditorCore.aclean = [
23660 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
23664 Roo.HtmlEditorCore.pwhite= [
23665 'http', 'https', 'mailto'
23668 // white listed style attributes.
23669 Roo.HtmlEditorCore.cwhite= [
23670 // 'text-align', /// default is to allow most things..
23676 // black listed style attributes.
23677 Roo.HtmlEditorCore.cblack= [
23678 // 'font-size' -- this can be set by the project
23682 Roo.HtmlEditorCore.swapCodes =[
23701 * @class Roo.bootstrap.HtmlEditor
23702 * @extends Roo.bootstrap.TextArea
23703 * Bootstrap HtmlEditor class
23706 * Create a new HtmlEditor
23707 * @param {Object} config The config object
23710 Roo.bootstrap.HtmlEditor = function(config){
23711 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
23712 if (!this.toolbars) {
23713 this.toolbars = [];
23716 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
23719 * @event initialize
23720 * Fires when the editor is fully initialized (including the iframe)
23721 * @param {HtmlEditor} this
23726 * Fires when the editor is first receives the focus. Any insertion must wait
23727 * until after this event.
23728 * @param {HtmlEditor} this
23732 * @event beforesync
23733 * Fires before the textarea is updated with content from the editor iframe. Return false
23734 * to cancel the sync.
23735 * @param {HtmlEditor} this
23736 * @param {String} html
23740 * @event beforepush
23741 * Fires before the iframe editor is updated with content from the textarea. Return false
23742 * to cancel the push.
23743 * @param {HtmlEditor} this
23744 * @param {String} html
23749 * Fires when the textarea is updated with content from the editor iframe.
23750 * @param {HtmlEditor} this
23751 * @param {String} html
23756 * Fires when the iframe editor is updated with content from the textarea.
23757 * @param {HtmlEditor} this
23758 * @param {String} html
23762 * @event editmodechange
23763 * Fires when the editor switches edit modes
23764 * @param {HtmlEditor} this
23765 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
23767 editmodechange: true,
23769 * @event editorevent
23770 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
23771 * @param {HtmlEditor} this
23775 * @event firstfocus
23776 * Fires when on first focus - needed by toolbars..
23777 * @param {HtmlEditor} this
23782 * Auto save the htmlEditor value as a file into Events
23783 * @param {HtmlEditor} this
23787 * @event savedpreview
23788 * preview the saved version of htmlEditor
23789 * @param {HtmlEditor} this
23796 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
23800 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
23805 * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
23810 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
23815 * @cfg {Number} height (in pixels)
23819 * @cfg {Number} width (in pixels)
23824 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
23827 stylesheets: false,
23832 // private properties
23833 validationEvent : false,
23835 initialized : false,
23838 onFocus : Roo.emptyFn,
23840 hideMode:'offsets',
23842 tbContainer : false,
23846 toolbarContainer :function() {
23847 return this.wrap.select('.x-html-editor-tb',true).first();
23851 * Protected method that will not generally be called directly. It
23852 * is called when the editor creates its toolbar. Override this method if you need to
23853 * add custom toolbar buttons.
23854 * @param {HtmlEditor} editor
23856 createToolbar : function(){
23857 Roo.log('renewing');
23858 Roo.log("create toolbars");
23860 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
23861 this.toolbars[0].render(this.toolbarContainer());
23865 // if (!editor.toolbars || !editor.toolbars.length) {
23866 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
23869 // for (var i =0 ; i < editor.toolbars.length;i++) {
23870 // editor.toolbars[i] = Roo.factory(
23871 // typeof(editor.toolbars[i]) == 'string' ?
23872 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
23873 // Roo.bootstrap.HtmlEditor);
23874 // editor.toolbars[i].init(editor);
23880 onRender : function(ct, position)
23882 // Roo.log("Call onRender: " + this.xtype);
23884 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
23886 this.wrap = this.inputEl().wrap({
23887 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
23890 this.editorcore.onRender(ct, position);
23892 if (this.resizable) {
23893 this.resizeEl = new Roo.Resizable(this.wrap, {
23897 minHeight : this.height,
23898 height: this.height,
23899 handles : this.resizable,
23902 resize : function(r, w, h) {
23903 _t.onResize(w,h); // -something
23909 this.createToolbar(this);
23912 if(!this.width && this.resizable){
23913 this.setSize(this.wrap.getSize());
23915 if (this.resizeEl) {
23916 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
23917 // should trigger onReize..
23923 onResize : function(w, h)
23925 Roo.log('resize: ' +w + ',' + h );
23926 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
23930 if(this.inputEl() ){
23931 if(typeof w == 'number'){
23932 var aw = w - this.wrap.getFrameWidth('lr');
23933 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
23936 if(typeof h == 'number'){
23937 var tbh = -11; // fixme it needs to tool bar size!
23938 for (var i =0; i < this.toolbars.length;i++) {
23939 // fixme - ask toolbars for heights?
23940 tbh += this.toolbars[i].el.getHeight();
23941 //if (this.toolbars[i].footer) {
23942 // tbh += this.toolbars[i].footer.el.getHeight();
23950 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
23951 ah -= 5; // knock a few pixes off for look..
23952 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
23956 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
23957 this.editorcore.onResize(ew,eh);
23962 * Toggles the editor between standard and source edit mode.
23963 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
23965 toggleSourceEdit : function(sourceEditMode)
23967 this.editorcore.toggleSourceEdit(sourceEditMode);
23969 if(this.editorcore.sourceEditMode){
23970 Roo.log('editor - showing textarea');
23973 // Roo.log(this.syncValue());
23975 this.inputEl().removeClass(['hide', 'x-hidden']);
23976 this.inputEl().dom.removeAttribute('tabIndex');
23977 this.inputEl().focus();
23979 Roo.log('editor - hiding textarea');
23981 // Roo.log(this.pushValue());
23984 this.inputEl().addClass(['hide', 'x-hidden']);
23985 this.inputEl().dom.setAttribute('tabIndex', -1);
23986 //this.deferFocus();
23989 if(this.resizable){
23990 this.setSize(this.wrap.getSize());
23993 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
23996 // private (for BoxComponent)
23997 adjustSize : Roo.BoxComponent.prototype.adjustSize,
23999 // private (for BoxComponent)
24000 getResizeEl : function(){
24004 // private (for BoxComponent)
24005 getPositionEl : function(){
24010 initEvents : function(){
24011 this.originalValue = this.getValue();
24015 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
24018 // markInvalid : Roo.emptyFn,
24020 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
24023 // clearInvalid : Roo.emptyFn,
24025 setValue : function(v){
24026 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
24027 this.editorcore.pushValue();
24032 deferFocus : function(){
24033 this.focus.defer(10, this);
24037 focus : function(){
24038 this.editorcore.focus();
24044 onDestroy : function(){
24050 for (var i =0; i < this.toolbars.length;i++) {
24051 // fixme - ask toolbars for heights?
24052 this.toolbars[i].onDestroy();
24055 this.wrap.dom.innerHTML = '';
24056 this.wrap.remove();
24061 onFirstFocus : function(){
24062 //Roo.log("onFirstFocus");
24063 this.editorcore.onFirstFocus();
24064 for (var i =0; i < this.toolbars.length;i++) {
24065 this.toolbars[i].onFirstFocus();
24071 syncValue : function()
24073 this.editorcore.syncValue();
24076 pushValue : function()
24078 this.editorcore.pushValue();
24082 // hide stuff that is not compatible
24096 * @event specialkey
24100 * @cfg {String} fieldClass @hide
24103 * @cfg {String} focusClass @hide
24106 * @cfg {String} autoCreate @hide
24109 * @cfg {String} inputType @hide
24113 * @cfg {String} invalidText @hide
24116 * @cfg {String} msgFx @hide
24119 * @cfg {String} validateOnBlur @hide
24128 Roo.namespace('Roo.bootstrap.htmleditor');
24130 * @class Roo.bootstrap.HtmlEditorToolbar1
24136 new Roo.bootstrap.HtmlEditor({
24139 new Roo.bootstrap.HtmlEditorToolbar1({
24140 disable : { fonts: 1 , format: 1, ..., ... , ...],
24146 * @cfg {Object} disable List of elements to disable..
24147 * @cfg {Array} btns List of additional buttons.
24151 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
24154 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
24157 Roo.apply(this, config);
24159 // default disabled, based on 'good practice'..
24160 this.disable = this.disable || {};
24161 Roo.applyIf(this.disable, {
24164 specialElements : true
24166 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
24168 this.editor = config.editor;
24169 this.editorcore = config.editor.editorcore;
24171 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
24173 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
24174 // dont call parent... till later.
24176 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
24181 editorcore : false,
24186 "h1","h2","h3","h4","h5","h6",
24188 "abbr", "acronym", "address", "cite", "samp", "var",
24192 onRender : function(ct, position)
24194 // Roo.log("Call onRender: " + this.xtype);
24196 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
24198 this.el.dom.style.marginBottom = '0';
24200 var editorcore = this.editorcore;
24201 var editor= this.editor;
24204 var btn = function(id,cmd , toggle, handler, html){
24206 var event = toggle ? 'toggle' : 'click';
24211 xns: Roo.bootstrap,
24215 enableToggle:toggle !== false,
24217 pressed : toggle ? false : null,
24220 a.listeners[toggle ? 'toggle' : 'click'] = function() {
24221 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
24227 // var cb_box = function...
24232 xns: Roo.bootstrap,
24237 xns: Roo.bootstrap,
24241 Roo.each(this.formats, function(f) {
24242 style.menu.items.push({
24244 xns: Roo.bootstrap,
24245 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
24250 editorcore.insertTag(this.tagname);
24257 children.push(style);
24259 btn('bold',false,true);
24260 btn('italic',false,true);
24261 btn('align-left', 'justifyleft',true);
24262 btn('align-center', 'justifycenter',true);
24263 btn('align-right' , 'justifyright',true);
24264 btn('link', false, false, function(btn) {
24265 //Roo.log("create link?");
24266 var url = prompt(this.createLinkText, this.defaultLinkValue);
24267 if(url && url != 'http:/'+'/'){
24268 this.editorcore.relayCmd('createlink', url);
24271 btn('list','insertunorderedlist',true);
24272 btn('pencil', false,true, function(btn){
24274 this.toggleSourceEdit(btn.pressed);
24277 if (this.editor.btns.length > 0) {
24278 for (var i = 0; i<this.editor.btns.length; i++) {
24279 children.push(this.editor.btns[i]);
24287 xns: Roo.bootstrap,
24292 xns: Roo.bootstrap,
24297 cog.menu.items.push({
24299 xns: Roo.bootstrap,
24300 html : Clean styles,
24305 editorcore.insertTag(this.tagname);
24314 this.xtype = 'NavSimplebar';
24316 for(var i=0;i< children.length;i++) {
24318 this.buttons.add(this.addxtypeChild(children[i]));
24322 editor.on('editorevent', this.updateToolbar, this);
24324 onBtnClick : function(id)
24326 this.editorcore.relayCmd(id);
24327 this.editorcore.focus();
24331 * Protected method that will not generally be called directly. It triggers
24332 * a toolbar update by reading the markup state of the current selection in the editor.
24334 updateToolbar: function(){
24336 if(!this.editorcore.activated){
24337 this.editor.onFirstFocus(); // is this neeed?
24341 var btns = this.buttons;
24342 var doc = this.editorcore.doc;
24343 btns.get('bold').setActive(doc.queryCommandState('bold'));
24344 btns.get('italic').setActive(doc.queryCommandState('italic'));
24345 //btns.get('underline').setActive(doc.queryCommandState('underline'));
24347 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
24348 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
24349 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
24351 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
24352 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
24355 var ans = this.editorcore.getAllAncestors();
24356 if (this.formatCombo) {
24359 var store = this.formatCombo.store;
24360 this.formatCombo.setValue("");
24361 for (var i =0; i < ans.length;i++) {
24362 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
24364 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
24372 // hides menus... - so this cant be on a menu...
24373 Roo.bootstrap.MenuMgr.hideAll();
24375 Roo.bootstrap.MenuMgr.hideAll();
24376 //this.editorsyncValue();
24378 onFirstFocus: function() {
24379 this.buttons.each(function(item){
24383 toggleSourceEdit : function(sourceEditMode){
24386 if(sourceEditMode){
24387 Roo.log("disabling buttons");
24388 this.buttons.each( function(item){
24389 if(item.cmd != 'pencil'){
24395 Roo.log("enabling buttons");
24396 if(this.editorcore.initialized){
24397 this.buttons.each( function(item){
24403 Roo.log("calling toggole on editor");
24404 // tell the editor that it's been pressed..
24405 this.editor.toggleSourceEdit(sourceEditMode);
24415 * @class Roo.bootstrap.Table.AbstractSelectionModel
24416 * @extends Roo.util.Observable
24417 * Abstract base class for grid SelectionModels. It provides the interface that should be
24418 * implemented by descendant classes. This class should not be directly instantiated.
24421 Roo.bootstrap.Table.AbstractSelectionModel = function(){
24422 this.locked = false;
24423 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
24427 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
24428 /** @ignore Called by the grid automatically. Do not call directly. */
24429 init : function(grid){
24435 * Locks the selections.
24438 this.locked = true;
24442 * Unlocks the selections.
24444 unlock : function(){
24445 this.locked = false;
24449 * Returns true if the selections are locked.
24450 * @return {Boolean}
24452 isLocked : function(){
24453 return this.locked;
24457 * @extends Roo.bootstrap.Table.AbstractSelectionModel
24458 * @class Roo.bootstrap.Table.RowSelectionModel
24459 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
24460 * It supports multiple selections and keyboard selection/navigation.
24462 * @param {Object} config
24465 Roo.bootstrap.Table.RowSelectionModel = function(config){
24466 Roo.apply(this, config);
24467 this.selections = new Roo.util.MixedCollection(false, function(o){
24472 this.lastActive = false;
24476 * @event selectionchange
24477 * Fires when the selection changes
24478 * @param {SelectionModel} this
24480 "selectionchange" : true,
24482 * @event afterselectionchange
24483 * Fires after the selection changes (eg. by key press or clicking)
24484 * @param {SelectionModel} this
24486 "afterselectionchange" : true,
24488 * @event beforerowselect
24489 * Fires when a row is selected being selected, return false to cancel.
24490 * @param {SelectionModel} this
24491 * @param {Number} rowIndex The selected index
24492 * @param {Boolean} keepExisting False if other selections will be cleared
24494 "beforerowselect" : true,
24497 * Fires when a row is selected.
24498 * @param {SelectionModel} this
24499 * @param {Number} rowIndex The selected index
24500 * @param {Roo.data.Record} r The record
24502 "rowselect" : true,
24504 * @event rowdeselect
24505 * Fires when a row is deselected.
24506 * @param {SelectionModel} this
24507 * @param {Number} rowIndex The selected index
24509 "rowdeselect" : true
24511 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
24512 this.locked = false;
24515 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
24517 * @cfg {Boolean} singleSelect
24518 * True to allow selection of only one row at a time (defaults to false)
24520 singleSelect : false,
24523 initEvents : function()
24526 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
24527 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
24528 //}else{ // allow click to work like normal
24529 // this.grid.on("rowclick", this.handleDragableRowClick, this);
24531 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
24532 this.grid.on("rowclick", this.handleMouseDown, this);
24534 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
24535 "up" : function(e){
24537 this.selectPrevious(e.shiftKey);
24538 }else if(this.last !== false && this.lastActive !== false){
24539 var last = this.last;
24540 this.selectRange(this.last, this.lastActive-1);
24541 this.grid.getView().focusRow(this.lastActive);
24542 if(last !== false){
24546 this.selectFirstRow();
24548 this.fireEvent("afterselectionchange", this);
24550 "down" : function(e){
24552 this.selectNext(e.shiftKey);
24553 }else if(this.last !== false && this.lastActive !== false){
24554 var last = this.last;
24555 this.selectRange(this.last, this.lastActive+1);
24556 this.grid.getView().focusRow(this.lastActive);
24557 if(last !== false){
24561 this.selectFirstRow();
24563 this.fireEvent("afterselectionchange", this);
24567 this.grid.store.on('load', function(){
24568 this.selections.clear();
24571 var view = this.grid.view;
24572 view.on("refresh", this.onRefresh, this);
24573 view.on("rowupdated", this.onRowUpdated, this);
24574 view.on("rowremoved", this.onRemove, this);
24579 onRefresh : function()
24581 var ds = this.grid.store, i, v = this.grid.view;
24582 var s = this.selections;
24583 s.each(function(r){
24584 if((i = ds.indexOfId(r.id)) != -1){
24593 onRemove : function(v, index, r){
24594 this.selections.remove(r);
24598 onRowUpdated : function(v, index, r){
24599 if(this.isSelected(r)){
24600 v.onRowSelect(index);
24606 * @param {Array} records The records to select
24607 * @param {Boolean} keepExisting (optional) True to keep existing selections
24609 selectRecords : function(records, keepExisting)
24612 this.clearSelections();
24614 var ds = this.grid.store;
24615 for(var i = 0, len = records.length; i < len; i++){
24616 this.selectRow(ds.indexOf(records[i]), true);
24621 * Gets the number of selected rows.
24624 getCount : function(){
24625 return this.selections.length;
24629 * Selects the first row in the grid.
24631 selectFirstRow : function(){
24636 * Select the last row.
24637 * @param {Boolean} keepExisting (optional) True to keep existing selections
24639 selectLastRow : function(keepExisting){
24640 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
24641 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
24645 * Selects the row immediately following the last selected row.
24646 * @param {Boolean} keepExisting (optional) True to keep existing selections
24648 selectNext : function(keepExisting)
24650 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
24651 this.selectRow(this.last+1, keepExisting);
24652 this.grid.getView().focusRow(this.last);
24657 * Selects the row that precedes the last selected row.
24658 * @param {Boolean} keepExisting (optional) True to keep existing selections
24660 selectPrevious : function(keepExisting){
24662 this.selectRow(this.last-1, keepExisting);
24663 this.grid.getView().focusRow(this.last);
24668 * Returns the selected records
24669 * @return {Array} Array of selected records
24671 getSelections : function(){
24672 return [].concat(this.selections.items);
24676 * Returns the first selected record.
24679 getSelected : function(){
24680 return this.selections.itemAt(0);
24685 * Clears all selections.
24687 clearSelections : function(fast)
24693 var ds = this.grid.store;
24694 var s = this.selections;
24695 s.each(function(r){
24696 this.deselectRow(ds.indexOfId(r.id));
24700 this.selections.clear();
24707 * Selects all rows.
24709 selectAll : function(){
24713 this.selections.clear();
24714 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
24715 this.selectRow(i, true);
24720 * Returns True if there is a selection.
24721 * @return {Boolean}
24723 hasSelection : function(){
24724 return this.selections.length > 0;
24728 * Returns True if the specified row is selected.
24729 * @param {Number/Record} record The record or index of the record to check
24730 * @return {Boolean}
24732 isSelected : function(index){
24733 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
24734 return (r && this.selections.key(r.id) ? true : false);
24738 * Returns True if the specified record id is selected.
24739 * @param {String} id The id of record to check
24740 * @return {Boolean}
24742 isIdSelected : function(id){
24743 return (this.selections.key(id) ? true : false);
24748 handleMouseDBClick : function(e, t){
24752 handleMouseDown : function(e, t)
24754 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
24755 if(this.isLocked() || rowIndex < 0 ){
24758 if(e.shiftKey && this.last !== false){
24759 var last = this.last;
24760 this.selectRange(last, rowIndex, e.ctrlKey);
24761 this.last = last; // reset the last
24765 var isSelected = this.isSelected(rowIndex);
24766 //Roo.log("select row:" + rowIndex);
24768 this.deselectRow(rowIndex);
24770 this.selectRow(rowIndex, true);
24774 if(e.button !== 0 && isSelected){
24775 alert('rowIndex 2: ' + rowIndex);
24776 view.focusRow(rowIndex);
24777 }else if(e.ctrlKey && isSelected){
24778 this.deselectRow(rowIndex);
24779 }else if(!isSelected){
24780 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
24781 view.focusRow(rowIndex);
24785 this.fireEvent("afterselectionchange", this);
24788 handleDragableRowClick : function(grid, rowIndex, e)
24790 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
24791 this.selectRow(rowIndex, false);
24792 grid.view.focusRow(rowIndex);
24793 this.fireEvent("afterselectionchange", this);
24798 * Selects multiple rows.
24799 * @param {Array} rows Array of the indexes of the row to select
24800 * @param {Boolean} keepExisting (optional) True to keep existing selections
24802 selectRows : function(rows, keepExisting){
24804 this.clearSelections();
24806 for(var i = 0, len = rows.length; i < len; i++){
24807 this.selectRow(rows[i], true);
24812 * Selects a range of rows. All rows in between startRow and endRow are also selected.
24813 * @param {Number} startRow The index of the first row in the range
24814 * @param {Number} endRow The index of the last row in the range
24815 * @param {Boolean} keepExisting (optional) True to retain existing selections
24817 selectRange : function(startRow, endRow, keepExisting){
24822 this.clearSelections();
24824 if(startRow <= endRow){
24825 for(var i = startRow; i <= endRow; i++){
24826 this.selectRow(i, true);
24829 for(var i = startRow; i >= endRow; i--){
24830 this.selectRow(i, true);
24836 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
24837 * @param {Number} startRow The index of the first row in the range
24838 * @param {Number} endRow The index of the last row in the range
24840 deselectRange : function(startRow, endRow, preventViewNotify){
24844 for(var i = startRow; i <= endRow; i++){
24845 this.deselectRow(i, preventViewNotify);
24851 * @param {Number} row The index of the row to select
24852 * @param {Boolean} keepExisting (optional) True to keep existing selections
24854 selectRow : function(index, keepExisting, preventViewNotify)
24856 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
24859 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
24860 if(!keepExisting || this.singleSelect){
24861 this.clearSelections();
24864 var r = this.grid.store.getAt(index);
24865 //console.log('selectRow - record id :' + r.id);
24867 this.selections.add(r);
24868 this.last = this.lastActive = index;
24869 if(!preventViewNotify){
24870 var proxy = new Roo.Element(
24871 this.grid.getRowDom(index)
24873 proxy.addClass('bg-info info');
24875 this.fireEvent("rowselect", this, index, r);
24876 this.fireEvent("selectionchange", this);
24882 * @param {Number} row The index of the row to deselect
24884 deselectRow : function(index, preventViewNotify)
24889 if(this.last == index){
24892 if(this.lastActive == index){
24893 this.lastActive = false;
24896 var r = this.grid.store.getAt(index);
24901 this.selections.remove(r);
24902 //.console.log('deselectRow - record id :' + r.id);
24903 if(!preventViewNotify){
24905 var proxy = new Roo.Element(
24906 this.grid.getRowDom(index)
24908 proxy.removeClass('bg-info info');
24910 this.fireEvent("rowdeselect", this, index);
24911 this.fireEvent("selectionchange", this);
24915 restoreLast : function(){
24917 this.last = this._last;
24922 acceptsNav : function(row, col, cm){
24923 return !cm.isHidden(col) && cm.isCellEditable(col, row);
24927 onEditorKey : function(field, e){
24928 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
24933 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
24935 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
24937 }else if(k == e.ENTER && !e.ctrlKey){
24941 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
24943 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
24945 }else if(k == e.ESC){
24949 g.startEditing(newCell[0], newCell[1]);
24955 * Ext JS Library 1.1.1
24956 * Copyright(c) 2006-2007, Ext JS, LLC.
24958 * Originally Released Under LGPL - original licence link has changed is not relivant.
24961 * <script type="text/javascript">
24965 * @class Roo.bootstrap.PagingToolbar
24966 * @extends Roo.bootstrap.NavSimplebar
24967 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
24969 * Create a new PagingToolbar
24970 * @param {Object} config The config object
24971 * @param {Roo.data.Store} store
24973 Roo.bootstrap.PagingToolbar = function(config)
24975 // old args format still supported... - xtype is prefered..
24976 // created from xtype...
24978 this.ds = config.dataSource;
24980 if (config.store && !this.ds) {
24981 this.store= Roo.factory(config.store, Roo.data);
24982 this.ds = this.store;
24983 this.ds.xmodule = this.xmodule || false;
24986 this.toolbarItems = [];
24987 if (config.items) {
24988 this.toolbarItems = config.items;
24991 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
24996 this.bind(this.ds);
24999 if (Roo.bootstrap.version == 4) {
25000 this.navgroup = new Roo.bootstrap.ButtonGroup({ cls: 'pagination' });
25002 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
25007 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
25009 * @cfg {Roo.data.Store} dataSource
25010 * The underlying data store providing the paged data
25013 * @cfg {String/HTMLElement/Element} container
25014 * container The id or element that will contain the toolbar
25017 * @cfg {Boolean} displayInfo
25018 * True to display the displayMsg (defaults to false)
25021 * @cfg {Number} pageSize
25022 * The number of records to display per page (defaults to 20)
25026 * @cfg {String} displayMsg
25027 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
25029 displayMsg : 'Displaying {0} - {1} of {2}',
25031 * @cfg {String} emptyMsg
25032 * The message to display when no records are found (defaults to "No data to display")
25034 emptyMsg : 'No data to display',
25036 * Customizable piece of the default paging text (defaults to "Page")
25039 beforePageText : "Page",
25041 * Customizable piece of the default paging text (defaults to "of %0")
25044 afterPageText : "of {0}",
25046 * Customizable piece of the default paging text (defaults to "First Page")
25049 firstText : "First Page",
25051 * Customizable piece of the default paging text (defaults to "Previous Page")
25054 prevText : "Previous Page",
25056 * Customizable piece of the default paging text (defaults to "Next Page")
25059 nextText : "Next Page",
25061 * Customizable piece of the default paging text (defaults to "Last Page")
25064 lastText : "Last Page",
25066 * Customizable piece of the default paging text (defaults to "Refresh")
25069 refreshText : "Refresh",
25073 onRender : function(ct, position)
25075 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
25076 this.navgroup.parentId = this.id;
25077 this.navgroup.onRender(this.el, null);
25078 // add the buttons to the navgroup
25080 if(this.displayInfo){
25081 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
25082 this.displayEl = this.el.select('.x-paging-info', true).first();
25083 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
25084 // this.displayEl = navel.el.select('span',true).first();
25090 Roo.each(_this.buttons, function(e){ // this might need to use render????
25091 Roo.factory(e).render(_this.el);
25095 Roo.each(_this.toolbarItems, function(e) {
25096 _this.navgroup.addItem(e);
25100 this.first = this.navgroup.addItem({
25101 tooltip: this.firstText,
25102 cls: "prev btn-outline-secondary",
25103 html : ' <i class="fa fa-step-backward"></i>',
25105 preventDefault: true,
25106 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
25109 this.prev = this.navgroup.addItem({
25110 tooltip: this.prevText,
25111 cls: "prev btn-outline-secondary",
25112 html : ' <i class="fa fa-backward"></i>',
25114 preventDefault: true,
25115 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
25117 //this.addSeparator();
25120 var field = this.navgroup.addItem( {
25122 cls : 'x-paging-position btn-outline-secondary',
25124 html : this.beforePageText +
25125 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
25126 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
25129 this.field = field.el.select('input', true).first();
25130 this.field.on("keydown", this.onPagingKeydown, this);
25131 this.field.on("focus", function(){this.dom.select();});
25134 this.afterTextEl = field.el.select('.x-paging-after',true).first();
25135 //this.field.setHeight(18);
25136 //this.addSeparator();
25137 this.next = this.navgroup.addItem({
25138 tooltip: this.nextText,
25139 cls: "next btn-outline-secondary",
25140 html : ' <i class="fa fa-forward"></i>',
25142 preventDefault: true,
25143 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
25145 this.last = this.navgroup.addItem({
25146 tooltip: this.lastText,
25147 html : ' <i class="fa fa-step-forward"></i>',
25148 cls: "next btn-outline-secondary",
25150 preventDefault: true,
25151 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
25153 //this.addSeparator();
25154 this.loading = this.navgroup.addItem({
25155 tooltip: this.refreshText,
25156 cls: "btn-outline-secondary",
25157 html : ' <i class="fa fa-refresh"></i>',
25158 preventDefault: true,
25159 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
25165 updateInfo : function(){
25166 if(this.displayEl){
25167 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
25168 var msg = count == 0 ?
25172 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
25174 this.displayEl.update(msg);
25179 onLoad : function(ds, r, o)
25181 this.cursor = o.params.start ? o.params.start : 0;
25183 var d = this.getPageData(),
25188 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
25189 this.field.dom.value = ap;
25190 this.first.setDisabled(ap == 1);
25191 this.prev.setDisabled(ap == 1);
25192 this.next.setDisabled(ap == ps);
25193 this.last.setDisabled(ap == ps);
25194 this.loading.enable();
25199 getPageData : function(){
25200 var total = this.ds.getTotalCount();
25203 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
25204 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
25209 onLoadError : function(){
25210 this.loading.enable();
25214 onPagingKeydown : function(e){
25215 var k = e.getKey();
25216 var d = this.getPageData();
25218 var v = this.field.dom.value, pageNum;
25219 if(!v || isNaN(pageNum = parseInt(v, 10))){
25220 this.field.dom.value = d.activePage;
25223 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
25224 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
25227 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))
25229 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
25230 this.field.dom.value = pageNum;
25231 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
25234 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
25236 var v = this.field.dom.value, pageNum;
25237 var increment = (e.shiftKey) ? 10 : 1;
25238 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
25241 if(!v || isNaN(pageNum = parseInt(v, 10))) {
25242 this.field.dom.value = d.activePage;
25245 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
25247 this.field.dom.value = parseInt(v, 10) + increment;
25248 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
25249 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
25256 beforeLoad : function(){
25258 this.loading.disable();
25263 onClick : function(which){
25272 ds.load({params:{start: 0, limit: this.pageSize}});
25275 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
25278 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
25281 var total = ds.getTotalCount();
25282 var extra = total % this.pageSize;
25283 var lastStart = extra ? (total - extra) : total-this.pageSize;
25284 ds.load({params:{start: lastStart, limit: this.pageSize}});
25287 ds.load({params:{start: this.cursor, limit: this.pageSize}});
25293 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
25294 * @param {Roo.data.Store} store The data store to unbind
25296 unbind : function(ds){
25297 ds.un("beforeload", this.beforeLoad, this);
25298 ds.un("load", this.onLoad, this);
25299 ds.un("loadexception", this.onLoadError, this);
25300 ds.un("remove", this.updateInfo, this);
25301 ds.un("add", this.updateInfo, this);
25302 this.ds = undefined;
25306 * Binds the paging toolbar to the specified {@link Roo.data.Store}
25307 * @param {Roo.data.Store} store The data store to bind
25309 bind : function(ds){
25310 ds.on("beforeload", this.beforeLoad, this);
25311 ds.on("load", this.onLoad, this);
25312 ds.on("loadexception", this.onLoadError, this);
25313 ds.on("remove", this.updateInfo, this);
25314 ds.on("add", this.updateInfo, this);
25325 * @class Roo.bootstrap.MessageBar
25326 * @extends Roo.bootstrap.Component
25327 * Bootstrap MessageBar class
25328 * @cfg {String} html contents of the MessageBar
25329 * @cfg {String} weight (info | success | warning | danger) default info
25330 * @cfg {String} beforeClass insert the bar before the given class
25331 * @cfg {Boolean} closable (true | false) default false
25332 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
25335 * Create a new Element
25336 * @param {Object} config The config object
25339 Roo.bootstrap.MessageBar = function(config){
25340 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
25343 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
25349 beforeClass: 'bootstrap-sticky-wrap',
25351 getAutoCreate : function(){
25355 cls: 'alert alert-dismissable alert-' + this.weight,
25360 html: this.html || ''
25366 cfg.cls += ' alert-messages-fixed';
25380 onRender : function(ct, position)
25382 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
25385 var cfg = Roo.apply({}, this.getAutoCreate());
25389 cfg.cls += ' ' + this.cls;
25392 cfg.style = this.style;
25394 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
25396 this.el.setVisibilityMode(Roo.Element.DISPLAY);
25399 this.el.select('>button.close').on('click', this.hide, this);
25405 if (!this.rendered) {
25411 this.fireEvent('show', this);
25417 if (!this.rendered) {
25423 this.fireEvent('hide', this);
25426 update : function()
25428 // var e = this.el.dom.firstChild;
25430 // if(this.closable){
25431 // e = e.nextSibling;
25434 // e.data = this.html || '';
25436 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
25452 * @class Roo.bootstrap.Graph
25453 * @extends Roo.bootstrap.Component
25454 * Bootstrap Graph class
25458 @cfg {String} graphtype bar | vbar | pie
25459 @cfg {number} g_x coodinator | centre x (pie)
25460 @cfg {number} g_y coodinator | centre y (pie)
25461 @cfg {number} g_r radius (pie)
25462 @cfg {number} g_height height of the chart (respected by all elements in the set)
25463 @cfg {number} g_width width of the chart (respected by all elements in the set)
25464 @cfg {Object} title The title of the chart
25467 -opts (object) options for the chart
25469 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
25470 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
25472 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.
25473 o stacked (boolean) whether or not to tread values as in a stacked bar chart
25475 o stretch (boolean)
25477 -opts (object) options for the pie
25480 o startAngle (number)
25481 o endAngle (number)
25485 * Create a new Input
25486 * @param {Object} config The config object
25489 Roo.bootstrap.Graph = function(config){
25490 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
25496 * The img click event for the img.
25497 * @param {Roo.EventObject} e
25503 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
25514 //g_colors: this.colors,
25521 getAutoCreate : function(){
25532 onRender : function(ct,position){
25535 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
25537 if (typeof(Raphael) == 'undefined') {
25538 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
25542 this.raphael = Raphael(this.el.dom);
25544 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25545 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25546 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25547 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
25549 r.text(160, 10, "Single Series Chart").attr(txtattr);
25550 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
25551 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
25552 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
25554 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
25555 r.barchart(330, 10, 300, 220, data1);
25556 r.barchart(10, 250, 300, 220, data2, {stacked: true});
25557 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
25560 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25561 // r.barchart(30, 30, 560, 250, xdata, {
25562 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
25563 // axis : "0 0 1 1",
25564 // axisxlabels : xdata
25565 // //yvalues : cols,
25568 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25570 // this.load(null,xdata,{
25571 // axis : "0 0 1 1",
25572 // axisxlabels : xdata
25577 load : function(graphtype,xdata,opts)
25579 this.raphael.clear();
25581 graphtype = this.graphtype;
25586 var r = this.raphael,
25587 fin = function () {
25588 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
25590 fout = function () {
25591 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
25593 pfin = function() {
25594 this.sector.stop();
25595 this.sector.scale(1.1, 1.1, this.cx, this.cy);
25598 this.label[0].stop();
25599 this.label[0].attr({ r: 7.5 });
25600 this.label[1].attr({ "font-weight": 800 });
25603 pfout = function() {
25604 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
25607 this.label[0].animate({ r: 5 }, 500, "bounce");
25608 this.label[1].attr({ "font-weight": 400 });
25614 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25617 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25620 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
25621 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
25623 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
25630 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
25635 setTitle: function(o)
25640 initEvents: function() {
25643 this.el.on('click', this.onClick, this);
25647 onClick : function(e)
25649 Roo.log('img onclick');
25650 this.fireEvent('click', this, e);
25662 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25665 * @class Roo.bootstrap.dash.NumberBox
25666 * @extends Roo.bootstrap.Component
25667 * Bootstrap NumberBox class
25668 * @cfg {String} headline Box headline
25669 * @cfg {String} content Box content
25670 * @cfg {String} icon Box icon
25671 * @cfg {String} footer Footer text
25672 * @cfg {String} fhref Footer href
25675 * Create a new NumberBox
25676 * @param {Object} config The config object
25680 Roo.bootstrap.dash.NumberBox = function(config){
25681 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
25685 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
25694 getAutoCreate : function(){
25698 cls : 'small-box ',
25706 cls : 'roo-headline',
25707 html : this.headline
25711 cls : 'roo-content',
25712 html : this.content
25726 cls : 'ion ' + this.icon
25735 cls : 'small-box-footer',
25736 href : this.fhref || '#',
25740 cfg.cn.push(footer);
25747 onRender : function(ct,position){
25748 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
25755 setHeadline: function (value)
25757 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
25760 setFooter: function (value, href)
25762 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
25765 this.el.select('a.small-box-footer',true).first().attr('href', href);
25770 setContent: function (value)
25772 this.el.select('.roo-content',true).first().dom.innerHTML = value;
25775 initEvents: function()
25789 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25792 * @class Roo.bootstrap.dash.TabBox
25793 * @extends Roo.bootstrap.Component
25794 * Bootstrap TabBox class
25795 * @cfg {String} title Title of the TabBox
25796 * @cfg {String} icon Icon of the TabBox
25797 * @cfg {Boolean} showtabs (true|false) show the tabs default true
25798 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
25801 * Create a new TabBox
25802 * @param {Object} config The config object
25806 Roo.bootstrap.dash.TabBox = function(config){
25807 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
25812 * When a pane is added
25813 * @param {Roo.bootstrap.dash.TabPane} pane
25817 * @event activatepane
25818 * When a pane is activated
25819 * @param {Roo.bootstrap.dash.TabPane} pane
25821 "activatepane" : true
25829 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
25834 tabScrollable : false,
25836 getChildContainer : function()
25838 return this.el.select('.tab-content', true).first();
25841 getAutoCreate : function(){
25845 cls: 'pull-left header',
25853 cls: 'fa ' + this.icon
25859 cls: 'nav nav-tabs pull-right',
25865 if(this.tabScrollable){
25872 cls: 'nav nav-tabs pull-right',
25883 cls: 'nav-tabs-custom',
25888 cls: 'tab-content no-padding',
25896 initEvents : function()
25898 //Roo.log('add add pane handler');
25899 this.on('addpane', this.onAddPane, this);
25902 * Updates the box title
25903 * @param {String} html to set the title to.
25905 setTitle : function(value)
25907 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
25909 onAddPane : function(pane)
25911 this.panes.push(pane);
25912 //Roo.log('addpane');
25914 // tabs are rendere left to right..
25915 if(!this.showtabs){
25919 var ctr = this.el.select('.nav-tabs', true).first();
25922 var existing = ctr.select('.nav-tab',true);
25923 var qty = existing.getCount();;
25926 var tab = ctr.createChild({
25928 cls : 'nav-tab' + (qty ? '' : ' active'),
25936 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
25939 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
25941 pane.el.addClass('active');
25946 onTabClick : function(ev,un,ob,pane)
25948 //Roo.log('tab - prev default');
25949 ev.preventDefault();
25952 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
25953 pane.tab.addClass('active');
25954 //Roo.log(pane.title);
25955 this.getChildContainer().select('.tab-pane',true).removeClass('active');
25956 // technically we should have a deactivate event.. but maybe add later.
25957 // and it should not de-activate the selected tab...
25958 this.fireEvent('activatepane', pane);
25959 pane.el.addClass('active');
25960 pane.fireEvent('activate');
25965 getActivePane : function()
25968 Roo.each(this.panes, function(p) {
25969 if(p.el.hasClass('active')){
25990 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25992 * @class Roo.bootstrap.TabPane
25993 * @extends Roo.bootstrap.Component
25994 * Bootstrap TabPane class
25995 * @cfg {Boolean} active (false | true) Default false
25996 * @cfg {String} title title of panel
26000 * Create a new TabPane
26001 * @param {Object} config The config object
26004 Roo.bootstrap.dash.TabPane = function(config){
26005 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
26011 * When a pane is activated
26012 * @param {Roo.bootstrap.dash.TabPane} pane
26019 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
26024 // the tabBox that this is attached to.
26027 getAutoCreate : function()
26035 cfg.cls += ' active';
26040 initEvents : function()
26042 //Roo.log('trigger add pane handler');
26043 this.parent().fireEvent('addpane', this)
26047 * Updates the tab title
26048 * @param {String} html to set the title to.
26050 setTitle: function(str)
26056 this.tab.select('a', true).first().dom.innerHTML = str;
26073 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
26076 * @class Roo.bootstrap.menu.Menu
26077 * @extends Roo.bootstrap.Component
26078 * Bootstrap Menu class - container for Menu
26079 * @cfg {String} html Text of the menu
26080 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
26081 * @cfg {String} icon Font awesome icon
26082 * @cfg {String} pos Menu align to (top | bottom) default bottom
26086 * Create a new Menu
26087 * @param {Object} config The config object
26091 Roo.bootstrap.menu.Menu = function(config){
26092 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
26096 * @event beforeshow
26097 * Fires before this menu is displayed
26098 * @param {Roo.bootstrap.menu.Menu} this
26102 * @event beforehide
26103 * Fires before this menu is hidden
26104 * @param {Roo.bootstrap.menu.Menu} this
26109 * Fires after this menu is displayed
26110 * @param {Roo.bootstrap.menu.Menu} this
26115 * Fires after this menu is hidden
26116 * @param {Roo.bootstrap.menu.Menu} this
26121 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
26122 * @param {Roo.bootstrap.menu.Menu} this
26123 * @param {Roo.EventObject} e
26130 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
26134 weight : 'default',
26139 getChildContainer : function() {
26140 if(this.isSubMenu){
26144 return this.el.select('ul.dropdown-menu', true).first();
26147 getAutoCreate : function()
26152 cls : 'roo-menu-text',
26160 cls : 'fa ' + this.icon
26171 cls : 'dropdown-button btn btn-' + this.weight,
26176 cls : 'dropdown-toggle btn btn-' + this.weight,
26186 cls : 'dropdown-menu'
26192 if(this.pos == 'top'){
26193 cfg.cls += ' dropup';
26196 if(this.isSubMenu){
26199 cls : 'dropdown-menu'
26206 onRender : function(ct, position)
26208 this.isSubMenu = ct.hasClass('dropdown-submenu');
26210 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
26213 initEvents : function()
26215 if(this.isSubMenu){
26219 this.hidden = true;
26221 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
26222 this.triggerEl.on('click', this.onTriggerPress, this);
26224 this.buttonEl = this.el.select('button.dropdown-button', true).first();
26225 this.buttonEl.on('click', this.onClick, this);
26231 if(this.isSubMenu){
26235 return this.el.select('ul.dropdown-menu', true).first();
26238 onClick : function(e)
26240 this.fireEvent("click", this, e);
26243 onTriggerPress : function(e)
26245 if (this.isVisible()) {
26252 isVisible : function(){
26253 return !this.hidden;
26258 this.fireEvent("beforeshow", this);
26260 this.hidden = false;
26261 this.el.addClass('open');
26263 Roo.get(document).on("mouseup", this.onMouseUp, this);
26265 this.fireEvent("show", this);
26272 this.fireEvent("beforehide", this);
26274 this.hidden = true;
26275 this.el.removeClass('open');
26277 Roo.get(document).un("mouseup", this.onMouseUp);
26279 this.fireEvent("hide", this);
26282 onMouseUp : function()
26296 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
26299 * @class Roo.bootstrap.menu.Item
26300 * @extends Roo.bootstrap.Component
26301 * Bootstrap MenuItem class
26302 * @cfg {Boolean} submenu (true | false) default false
26303 * @cfg {String} html text of the item
26304 * @cfg {String} href the link
26305 * @cfg {Boolean} disable (true | false) default false
26306 * @cfg {Boolean} preventDefault (true | false) default true
26307 * @cfg {String} icon Font awesome icon
26308 * @cfg {String} pos Submenu align to (left | right) default right
26312 * Create a new Item
26313 * @param {Object} config The config object
26317 Roo.bootstrap.menu.Item = function(config){
26318 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
26322 * Fires when the mouse is hovering over this menu
26323 * @param {Roo.bootstrap.menu.Item} this
26324 * @param {Roo.EventObject} e
26329 * Fires when the mouse exits this menu
26330 * @param {Roo.bootstrap.menu.Item} this
26331 * @param {Roo.EventObject} e
26337 * The raw click event for the entire grid.
26338 * @param {Roo.EventObject} e
26344 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
26349 preventDefault: true,
26354 getAutoCreate : function()
26359 cls : 'roo-menu-item-text',
26367 cls : 'fa ' + this.icon
26376 href : this.href || '#',
26383 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
26387 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
26389 if(this.pos == 'left'){
26390 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
26397 initEvents : function()
26399 this.el.on('mouseover', this.onMouseOver, this);
26400 this.el.on('mouseout', this.onMouseOut, this);
26402 this.el.select('a', true).first().on('click', this.onClick, this);
26406 onClick : function(e)
26408 if(this.preventDefault){
26409 e.preventDefault();
26412 this.fireEvent("click", this, e);
26415 onMouseOver : function(e)
26417 if(this.submenu && this.pos == 'left'){
26418 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
26421 this.fireEvent("mouseover", this, e);
26424 onMouseOut : function(e)
26426 this.fireEvent("mouseout", this, e);
26438 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
26441 * @class Roo.bootstrap.menu.Separator
26442 * @extends Roo.bootstrap.Component
26443 * Bootstrap Separator class
26446 * Create a new Separator
26447 * @param {Object} config The config object
26451 Roo.bootstrap.menu.Separator = function(config){
26452 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
26455 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
26457 getAutoCreate : function(){
26478 * @class Roo.bootstrap.Tooltip
26479 * Bootstrap Tooltip class
26480 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
26481 * to determine which dom element triggers the tooltip.
26483 * It needs to add support for additional attributes like tooltip-position
26486 * Create a new Toolti
26487 * @param {Object} config The config object
26490 Roo.bootstrap.Tooltip = function(config){
26491 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
26493 this.alignment = Roo.bootstrap.Tooltip.alignment;
26495 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
26496 this.alignment = config.alignment;
26501 Roo.apply(Roo.bootstrap.Tooltip, {
26503 * @function init initialize tooltip monitoring.
26507 currentTip : false,
26508 currentRegion : false,
26514 Roo.get(document).on('mouseover', this.enter ,this);
26515 Roo.get(document).on('mouseout', this.leave, this);
26518 this.currentTip = new Roo.bootstrap.Tooltip();
26521 enter : function(ev)
26523 var dom = ev.getTarget();
26525 //Roo.log(['enter',dom]);
26526 var el = Roo.fly(dom);
26527 if (this.currentEl) {
26529 //Roo.log(this.currentEl);
26530 //Roo.log(this.currentEl.contains(dom));
26531 if (this.currentEl == el) {
26534 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
26540 if (this.currentTip.el) {
26541 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
26545 if(!el || el.dom == document){
26551 // you can not look for children, as if el is the body.. then everythign is the child..
26552 if (!el.attr('tooltip')) { //
26553 if (!el.select("[tooltip]").elements.length) {
26556 // is the mouse over this child...?
26557 bindEl = el.select("[tooltip]").first();
26558 var xy = ev.getXY();
26559 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
26560 //Roo.log("not in region.");
26563 //Roo.log("child element over..");
26566 this.currentEl = bindEl;
26567 this.currentTip.bind(bindEl);
26568 this.currentRegion = Roo.lib.Region.getRegion(dom);
26569 this.currentTip.enter();
26572 leave : function(ev)
26574 var dom = ev.getTarget();
26575 //Roo.log(['leave',dom]);
26576 if (!this.currentEl) {
26581 if (dom != this.currentEl.dom) {
26584 var xy = ev.getXY();
26585 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
26588 // only activate leave if mouse cursor is outside... bounding box..
26593 if (this.currentTip) {
26594 this.currentTip.leave();
26596 //Roo.log('clear currentEl');
26597 this.currentEl = false;
26602 'left' : ['r-l', [-2,0], 'right'],
26603 'right' : ['l-r', [2,0], 'left'],
26604 'bottom' : ['t-b', [0,2], 'top'],
26605 'top' : [ 'b-t', [0,-2], 'bottom']
26611 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
26616 delay : null, // can be { show : 300 , hide: 500}
26620 hoverState : null, //???
26622 placement : 'bottom',
26626 getAutoCreate : function(){
26633 cls : 'tooltip-arrow'
26636 cls : 'tooltip-inner'
26643 bind : function(el)
26649 enter : function () {
26651 if (this.timeout != null) {
26652 clearTimeout(this.timeout);
26655 this.hoverState = 'in';
26656 //Roo.log("enter - show");
26657 if (!this.delay || !this.delay.show) {
26662 this.timeout = setTimeout(function () {
26663 if (_t.hoverState == 'in') {
26666 }, this.delay.show);
26670 clearTimeout(this.timeout);
26672 this.hoverState = 'out';
26673 if (!this.delay || !this.delay.hide) {
26679 this.timeout = setTimeout(function () {
26680 //Roo.log("leave - timeout");
26682 if (_t.hoverState == 'out') {
26684 Roo.bootstrap.Tooltip.currentEl = false;
26689 show : function (msg)
26692 this.render(document.body);
26695 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
26697 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
26699 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
26701 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
26703 var placement = typeof this.placement == 'function' ?
26704 this.placement.call(this, this.el, on_el) :
26707 var autoToken = /\s?auto?\s?/i;
26708 var autoPlace = autoToken.test(placement);
26710 placement = placement.replace(autoToken, '') || 'top';
26714 //this.el.setXY([0,0]);
26716 //this.el.dom.style.display='block';
26718 //this.el.appendTo(on_el);
26720 var p = this.getPosition();
26721 var box = this.el.getBox();
26727 var align = this.alignment[placement];
26729 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
26731 if(placement == 'top' || placement == 'bottom'){
26733 placement = 'right';
26736 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
26737 placement = 'left';
26740 var scroll = Roo.select('body', true).first().getScroll();
26742 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
26746 align = this.alignment[placement];
26749 this.el.alignTo(this.bindEl, align[0],align[1]);
26750 //var arrow = this.el.select('.arrow',true).first();
26751 //arrow.set(align[2],
26753 this.el.addClass(placement);
26755 this.el.addClass('in fade');
26757 this.hoverState = null;
26759 if (this.el.hasClass('fade')) {
26770 //this.el.setXY([0,0]);
26771 this.el.removeClass('in');
26787 * @class Roo.bootstrap.LocationPicker
26788 * @extends Roo.bootstrap.Component
26789 * Bootstrap LocationPicker class
26790 * @cfg {Number} latitude Position when init default 0
26791 * @cfg {Number} longitude Position when init default 0
26792 * @cfg {Number} zoom default 15
26793 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
26794 * @cfg {Boolean} mapTypeControl default false
26795 * @cfg {Boolean} disableDoubleClickZoom default false
26796 * @cfg {Boolean} scrollwheel default true
26797 * @cfg {Boolean} streetViewControl default false
26798 * @cfg {Number} radius default 0
26799 * @cfg {String} locationName
26800 * @cfg {Boolean} draggable default true
26801 * @cfg {Boolean} enableAutocomplete default false
26802 * @cfg {Boolean} enableReverseGeocode default true
26803 * @cfg {String} markerTitle
26806 * Create a new LocationPicker
26807 * @param {Object} config The config object
26811 Roo.bootstrap.LocationPicker = function(config){
26813 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
26818 * Fires when the picker initialized.
26819 * @param {Roo.bootstrap.LocationPicker} this
26820 * @param {Google Location} location
26824 * @event positionchanged
26825 * Fires when the picker position changed.
26826 * @param {Roo.bootstrap.LocationPicker} this
26827 * @param {Google Location} location
26829 positionchanged : true,
26832 * Fires when the map resize.
26833 * @param {Roo.bootstrap.LocationPicker} this
26838 * Fires when the map show.
26839 * @param {Roo.bootstrap.LocationPicker} this
26844 * Fires when the map hide.
26845 * @param {Roo.bootstrap.LocationPicker} this
26850 * Fires when click the map.
26851 * @param {Roo.bootstrap.LocationPicker} this
26852 * @param {Map event} e
26856 * @event mapRightClick
26857 * Fires when right click the map.
26858 * @param {Roo.bootstrap.LocationPicker} this
26859 * @param {Map event} e
26861 mapRightClick : true,
26863 * @event markerClick
26864 * Fires when click the marker.
26865 * @param {Roo.bootstrap.LocationPicker} this
26866 * @param {Map event} e
26868 markerClick : true,
26870 * @event markerRightClick
26871 * Fires when right click the marker.
26872 * @param {Roo.bootstrap.LocationPicker} this
26873 * @param {Map event} e
26875 markerRightClick : true,
26877 * @event OverlayViewDraw
26878 * Fires when OverlayView Draw
26879 * @param {Roo.bootstrap.LocationPicker} this
26881 OverlayViewDraw : true,
26883 * @event OverlayViewOnAdd
26884 * Fires when OverlayView Draw
26885 * @param {Roo.bootstrap.LocationPicker} this
26887 OverlayViewOnAdd : true,
26889 * @event OverlayViewOnRemove
26890 * Fires when OverlayView Draw
26891 * @param {Roo.bootstrap.LocationPicker} this
26893 OverlayViewOnRemove : true,
26895 * @event OverlayViewShow
26896 * Fires when OverlayView Draw
26897 * @param {Roo.bootstrap.LocationPicker} this
26898 * @param {Pixel} cpx
26900 OverlayViewShow : true,
26902 * @event OverlayViewHide
26903 * Fires when OverlayView Draw
26904 * @param {Roo.bootstrap.LocationPicker} this
26906 OverlayViewHide : true,
26908 * @event loadexception
26909 * Fires when load google lib failed.
26910 * @param {Roo.bootstrap.LocationPicker} this
26912 loadexception : true
26917 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
26919 gMapContext: false,
26925 mapTypeControl: false,
26926 disableDoubleClickZoom: false,
26928 streetViewControl: false,
26932 enableAutocomplete: false,
26933 enableReverseGeocode: true,
26936 getAutoCreate: function()
26941 cls: 'roo-location-picker'
26947 initEvents: function(ct, position)
26949 if(!this.el.getWidth() || this.isApplied()){
26953 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26958 initial: function()
26960 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
26961 this.fireEvent('loadexception', this);
26965 if(!this.mapTypeId){
26966 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
26969 this.gMapContext = this.GMapContext();
26971 this.initOverlayView();
26973 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
26977 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
26978 _this.setPosition(_this.gMapContext.marker.position);
26981 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
26982 _this.fireEvent('mapClick', this, event);
26986 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
26987 _this.fireEvent('mapRightClick', this, event);
26991 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
26992 _this.fireEvent('markerClick', this, event);
26996 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
26997 _this.fireEvent('markerRightClick', this, event);
27001 this.setPosition(this.gMapContext.location);
27003 this.fireEvent('initial', this, this.gMapContext.location);
27006 initOverlayView: function()
27010 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
27014 _this.fireEvent('OverlayViewDraw', _this);
27019 _this.fireEvent('OverlayViewOnAdd', _this);
27022 onRemove: function()
27024 _this.fireEvent('OverlayViewOnRemove', _this);
27027 show: function(cpx)
27029 _this.fireEvent('OverlayViewShow', _this, cpx);
27034 _this.fireEvent('OverlayViewHide', _this);
27040 fromLatLngToContainerPixel: function(event)
27042 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
27045 isApplied: function()
27047 return this.getGmapContext() == false ? false : true;
27050 getGmapContext: function()
27052 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
27055 GMapContext: function()
27057 var position = new google.maps.LatLng(this.latitude, this.longitude);
27059 var _map = new google.maps.Map(this.el.dom, {
27062 mapTypeId: this.mapTypeId,
27063 mapTypeControl: this.mapTypeControl,
27064 disableDoubleClickZoom: this.disableDoubleClickZoom,
27065 scrollwheel: this.scrollwheel,
27066 streetViewControl: this.streetViewControl,
27067 locationName: this.locationName,
27068 draggable: this.draggable,
27069 enableAutocomplete: this.enableAutocomplete,
27070 enableReverseGeocode: this.enableReverseGeocode
27073 var _marker = new google.maps.Marker({
27074 position: position,
27076 title: this.markerTitle,
27077 draggable: this.draggable
27084 location: position,
27085 radius: this.radius,
27086 locationName: this.locationName,
27087 addressComponents: {
27088 formatted_address: null,
27089 addressLine1: null,
27090 addressLine2: null,
27092 streetNumber: null,
27096 stateOrProvince: null
27099 domContainer: this.el.dom,
27100 geodecoder: new google.maps.Geocoder()
27104 drawCircle: function(center, radius, options)
27106 if (this.gMapContext.circle != null) {
27107 this.gMapContext.circle.setMap(null);
27111 options = Roo.apply({}, options, {
27112 strokeColor: "#0000FF",
27113 strokeOpacity: .35,
27115 fillColor: "#0000FF",
27119 options.map = this.gMapContext.map;
27120 options.radius = radius;
27121 options.center = center;
27122 this.gMapContext.circle = new google.maps.Circle(options);
27123 return this.gMapContext.circle;
27129 setPosition: function(location)
27131 this.gMapContext.location = location;
27132 this.gMapContext.marker.setPosition(location);
27133 this.gMapContext.map.panTo(location);
27134 this.drawCircle(location, this.gMapContext.radius, {});
27138 if (this.gMapContext.settings.enableReverseGeocode) {
27139 this.gMapContext.geodecoder.geocode({
27140 latLng: this.gMapContext.location
27141 }, function(results, status) {
27143 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
27144 _this.gMapContext.locationName = results[0].formatted_address;
27145 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
27147 _this.fireEvent('positionchanged', this, location);
27154 this.fireEvent('positionchanged', this, location);
27159 google.maps.event.trigger(this.gMapContext.map, "resize");
27161 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
27163 this.fireEvent('resize', this);
27166 setPositionByLatLng: function(latitude, longitude)
27168 this.setPosition(new google.maps.LatLng(latitude, longitude));
27171 getCurrentPosition: function()
27174 latitude: this.gMapContext.location.lat(),
27175 longitude: this.gMapContext.location.lng()
27179 getAddressName: function()
27181 return this.gMapContext.locationName;
27184 getAddressComponents: function()
27186 return this.gMapContext.addressComponents;
27189 address_component_from_google_geocode: function(address_components)
27193 for (var i = 0; i < address_components.length; i++) {
27194 var component = address_components[i];
27195 if (component.types.indexOf("postal_code") >= 0) {
27196 result.postalCode = component.short_name;
27197 } else if (component.types.indexOf("street_number") >= 0) {
27198 result.streetNumber = component.short_name;
27199 } else if (component.types.indexOf("route") >= 0) {
27200 result.streetName = component.short_name;
27201 } else if (component.types.indexOf("neighborhood") >= 0) {
27202 result.city = component.short_name;
27203 } else if (component.types.indexOf("locality") >= 0) {
27204 result.city = component.short_name;
27205 } else if (component.types.indexOf("sublocality") >= 0) {
27206 result.district = component.short_name;
27207 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
27208 result.stateOrProvince = component.short_name;
27209 } else if (component.types.indexOf("country") >= 0) {
27210 result.country = component.short_name;
27214 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
27215 result.addressLine2 = "";
27219 setZoomLevel: function(zoom)
27221 this.gMapContext.map.setZoom(zoom);
27234 this.fireEvent('show', this);
27245 this.fireEvent('hide', this);
27250 Roo.apply(Roo.bootstrap.LocationPicker, {
27252 OverlayView : function(map, options)
27254 options = options || {};
27261 * @class Roo.bootstrap.Alert
27262 * @extends Roo.bootstrap.Component
27263 * Bootstrap Alert class - shows an alert area box
27265 * <div class="alert alert-danger" role="alert"><span class="fa fa-exclamation-triangle"></span><span class="sr-only">Error:</span>
27266 Enter a valid email address
27269 * @cfg {String} title The title of alert
27270 * @cfg {String} html The content of alert
27271 * @cfg {String} weight ( success | info | warning | danger )
27272 * @cfg {String} faicon font-awesomeicon
27275 * Create a new alert
27276 * @param {Object} config The config object
27280 Roo.bootstrap.Alert = function(config){
27281 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
27285 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
27292 getAutoCreate : function()
27301 cls : 'roo-alert-icon'
27306 cls : 'roo-alert-title',
27311 cls : 'roo-alert-text',
27318 cfg.cn[0].cls += ' fa ' + this.faicon;
27322 cfg.cls += ' alert-' + this.weight;
27328 initEvents: function()
27330 this.el.setVisibilityMode(Roo.Element.DISPLAY);
27333 setTitle : function(str)
27335 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
27338 setText : function(str)
27340 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
27343 setWeight : function(weight)
27346 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
27349 this.weight = weight;
27351 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
27354 setIcon : function(icon)
27357 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
27360 this.faicon = icon;
27362 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
27383 * @class Roo.bootstrap.UploadCropbox
27384 * @extends Roo.bootstrap.Component
27385 * Bootstrap UploadCropbox class
27386 * @cfg {String} emptyText show when image has been loaded
27387 * @cfg {String} rotateNotify show when image too small to rotate
27388 * @cfg {Number} errorTimeout default 3000
27389 * @cfg {Number} minWidth default 300
27390 * @cfg {Number} minHeight default 300
27391 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
27392 * @cfg {Boolean} isDocument (true|false) default false
27393 * @cfg {String} url action url
27394 * @cfg {String} paramName default 'imageUpload'
27395 * @cfg {String} method default POST
27396 * @cfg {Boolean} loadMask (true|false) default true
27397 * @cfg {Boolean} loadingText default 'Loading...'
27400 * Create a new UploadCropbox
27401 * @param {Object} config The config object
27404 Roo.bootstrap.UploadCropbox = function(config){
27405 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
27409 * @event beforeselectfile
27410 * Fire before select file
27411 * @param {Roo.bootstrap.UploadCropbox} this
27413 "beforeselectfile" : true,
27416 * Fire after initEvent
27417 * @param {Roo.bootstrap.UploadCropbox} this
27422 * Fire after initEvent
27423 * @param {Roo.bootstrap.UploadCropbox} this
27424 * @param {String} data
27429 * Fire when preparing the file data
27430 * @param {Roo.bootstrap.UploadCropbox} this
27431 * @param {Object} file
27436 * Fire when get exception
27437 * @param {Roo.bootstrap.UploadCropbox} this
27438 * @param {XMLHttpRequest} xhr
27440 "exception" : true,
27442 * @event beforeloadcanvas
27443 * Fire before load the canvas
27444 * @param {Roo.bootstrap.UploadCropbox} this
27445 * @param {String} src
27447 "beforeloadcanvas" : true,
27450 * Fire when trash image
27451 * @param {Roo.bootstrap.UploadCropbox} this
27456 * Fire when download the image
27457 * @param {Roo.bootstrap.UploadCropbox} this
27461 * @event footerbuttonclick
27462 * Fire when footerbuttonclick
27463 * @param {Roo.bootstrap.UploadCropbox} this
27464 * @param {String} type
27466 "footerbuttonclick" : true,
27470 * @param {Roo.bootstrap.UploadCropbox} this
27475 * Fire when rotate the image
27476 * @param {Roo.bootstrap.UploadCropbox} this
27477 * @param {String} pos
27482 * Fire when inspect the file
27483 * @param {Roo.bootstrap.UploadCropbox} this
27484 * @param {Object} file
27489 * Fire when xhr upload the file
27490 * @param {Roo.bootstrap.UploadCropbox} this
27491 * @param {Object} data
27496 * Fire when arrange the file data
27497 * @param {Roo.bootstrap.UploadCropbox} this
27498 * @param {Object} formData
27503 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
27506 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
27508 emptyText : 'Click to upload image',
27509 rotateNotify : 'Image is too small to rotate',
27510 errorTimeout : 3000,
27524 cropType : 'image/jpeg',
27526 canvasLoaded : false,
27527 isDocument : false,
27529 paramName : 'imageUpload',
27531 loadingText : 'Loading...',
27534 getAutoCreate : function()
27538 cls : 'roo-upload-cropbox',
27542 cls : 'roo-upload-cropbox-selector',
27547 cls : 'roo-upload-cropbox-body',
27548 style : 'cursor:pointer',
27552 cls : 'roo-upload-cropbox-preview'
27556 cls : 'roo-upload-cropbox-thumb'
27560 cls : 'roo-upload-cropbox-empty-notify',
27561 html : this.emptyText
27565 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
27566 html : this.rotateNotify
27572 cls : 'roo-upload-cropbox-footer',
27575 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
27585 onRender : function(ct, position)
27587 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
27589 if (this.buttons.length) {
27591 Roo.each(this.buttons, function(bb) {
27593 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
27595 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
27601 this.maskEl = this.el;
27605 initEvents : function()
27607 this.urlAPI = (window.createObjectURL && window) ||
27608 (window.URL && URL.revokeObjectURL && URL) ||
27609 (window.webkitURL && webkitURL);
27611 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
27612 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27614 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
27615 this.selectorEl.hide();
27617 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
27618 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27620 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
27621 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27622 this.thumbEl.hide();
27624 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
27625 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27627 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
27628 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27629 this.errorEl.hide();
27631 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
27632 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27633 this.footerEl.hide();
27635 this.setThumbBoxSize();
27641 this.fireEvent('initial', this);
27648 window.addEventListener("resize", function() { _this.resize(); } );
27650 this.bodyEl.on('click', this.beforeSelectFile, this);
27653 this.bodyEl.on('touchstart', this.onTouchStart, this);
27654 this.bodyEl.on('touchmove', this.onTouchMove, this);
27655 this.bodyEl.on('touchend', this.onTouchEnd, this);
27659 this.bodyEl.on('mousedown', this.onMouseDown, this);
27660 this.bodyEl.on('mousemove', this.onMouseMove, this);
27661 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
27662 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
27663 Roo.get(document).on('mouseup', this.onMouseUp, this);
27666 this.selectorEl.on('change', this.onFileSelected, this);
27672 this.baseScale = 1;
27674 this.baseRotate = 1;
27675 this.dragable = false;
27676 this.pinching = false;
27679 this.cropData = false;
27680 this.notifyEl.dom.innerHTML = this.emptyText;
27682 this.selectorEl.dom.value = '';
27686 resize : function()
27688 if(this.fireEvent('resize', this) != false){
27689 this.setThumbBoxPosition();
27690 this.setCanvasPosition();
27694 onFooterButtonClick : function(e, el, o, type)
27697 case 'rotate-left' :
27698 this.onRotateLeft(e);
27700 case 'rotate-right' :
27701 this.onRotateRight(e);
27704 this.beforeSelectFile(e);
27719 this.fireEvent('footerbuttonclick', this, type);
27722 beforeSelectFile : function(e)
27724 e.preventDefault();
27726 if(this.fireEvent('beforeselectfile', this) != false){
27727 this.selectorEl.dom.click();
27731 onFileSelected : function(e)
27733 e.preventDefault();
27735 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
27739 var file = this.selectorEl.dom.files[0];
27741 if(this.fireEvent('inspect', this, file) != false){
27742 this.prepare(file);
27747 trash : function(e)
27749 this.fireEvent('trash', this);
27752 download : function(e)
27754 this.fireEvent('download', this);
27757 loadCanvas : function(src)
27759 if(this.fireEvent('beforeloadcanvas', this, src) != false){
27763 this.imageEl = document.createElement('img');
27767 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
27769 this.imageEl.src = src;
27773 onLoadCanvas : function()
27775 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
27776 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
27778 this.bodyEl.un('click', this.beforeSelectFile, this);
27780 this.notifyEl.hide();
27781 this.thumbEl.show();
27782 this.footerEl.show();
27784 this.baseRotateLevel();
27786 if(this.isDocument){
27787 this.setThumbBoxSize();
27790 this.setThumbBoxPosition();
27792 this.baseScaleLevel();
27798 this.canvasLoaded = true;
27801 this.maskEl.unmask();
27806 setCanvasPosition : function()
27808 if(!this.canvasEl){
27812 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
27813 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
27815 this.previewEl.setLeft(pw);
27816 this.previewEl.setTop(ph);
27820 onMouseDown : function(e)
27824 this.dragable = true;
27825 this.pinching = false;
27827 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
27828 this.dragable = false;
27832 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27833 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27837 onMouseMove : function(e)
27841 if(!this.canvasLoaded){
27845 if (!this.dragable){
27849 var minX = Math.ceil(this.thumbEl.getLeft(true));
27850 var minY = Math.ceil(this.thumbEl.getTop(true));
27852 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
27853 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
27855 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27856 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27858 x = x - this.mouseX;
27859 y = y - this.mouseY;
27861 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
27862 var bgY = Math.ceil(y + this.previewEl.getTop(true));
27864 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
27865 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
27867 this.previewEl.setLeft(bgX);
27868 this.previewEl.setTop(bgY);
27870 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27871 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27874 onMouseUp : function(e)
27878 this.dragable = false;
27881 onMouseWheel : function(e)
27885 this.startScale = this.scale;
27887 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
27889 if(!this.zoomable()){
27890 this.scale = this.startScale;
27899 zoomable : function()
27901 var minScale = this.thumbEl.getWidth() / this.minWidth;
27903 if(this.minWidth < this.minHeight){
27904 minScale = this.thumbEl.getHeight() / this.minHeight;
27907 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
27908 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
27912 (this.rotate == 0 || this.rotate == 180) &&
27914 width > this.imageEl.OriginWidth ||
27915 height > this.imageEl.OriginHeight ||
27916 (width < this.minWidth && height < this.minHeight)
27924 (this.rotate == 90 || this.rotate == 270) &&
27926 width > this.imageEl.OriginWidth ||
27927 height > this.imageEl.OriginHeight ||
27928 (width < this.minHeight && height < this.minWidth)
27935 !this.isDocument &&
27936 (this.rotate == 0 || this.rotate == 180) &&
27938 width < this.minWidth ||
27939 width > this.imageEl.OriginWidth ||
27940 height < this.minHeight ||
27941 height > this.imageEl.OriginHeight
27948 !this.isDocument &&
27949 (this.rotate == 90 || this.rotate == 270) &&
27951 width < this.minHeight ||
27952 width > this.imageEl.OriginWidth ||
27953 height < this.minWidth ||
27954 height > this.imageEl.OriginHeight
27964 onRotateLeft : function(e)
27966 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27968 var minScale = this.thumbEl.getWidth() / this.minWidth;
27970 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27971 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27973 this.startScale = this.scale;
27975 while (this.getScaleLevel() < minScale){
27977 this.scale = this.scale + 1;
27979 if(!this.zoomable()){
27984 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27985 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27990 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27997 this.scale = this.startScale;
27999 this.onRotateFail();
28004 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
28006 if(this.isDocument){
28007 this.setThumbBoxSize();
28008 this.setThumbBoxPosition();
28009 this.setCanvasPosition();
28014 this.fireEvent('rotate', this, 'left');
28018 onRotateRight : function(e)
28020 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
28022 var minScale = this.thumbEl.getWidth() / this.minWidth;
28024 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
28025 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
28027 this.startScale = this.scale;
28029 while (this.getScaleLevel() < minScale){
28031 this.scale = this.scale + 1;
28033 if(!this.zoomable()){
28038 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
28039 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
28044 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
28051 this.scale = this.startScale;
28053 this.onRotateFail();
28058 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
28060 if(this.isDocument){
28061 this.setThumbBoxSize();
28062 this.setThumbBoxPosition();
28063 this.setCanvasPosition();
28068 this.fireEvent('rotate', this, 'right');
28071 onRotateFail : function()
28073 this.errorEl.show(true);
28077 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
28082 this.previewEl.dom.innerHTML = '';
28084 var canvasEl = document.createElement("canvas");
28086 var contextEl = canvasEl.getContext("2d");
28088 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
28089 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
28090 var center = this.imageEl.OriginWidth / 2;
28092 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
28093 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
28094 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
28095 center = this.imageEl.OriginHeight / 2;
28098 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
28100 contextEl.translate(center, center);
28101 contextEl.rotate(this.rotate * Math.PI / 180);
28103 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
28105 this.canvasEl = document.createElement("canvas");
28107 this.contextEl = this.canvasEl.getContext("2d");
28109 switch (this.rotate) {
28112 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
28113 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
28115 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
28120 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
28121 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
28123 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28124 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);
28128 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
28133 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
28134 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
28136 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28137 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);
28141 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);
28146 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
28147 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
28149 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28150 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
28154 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);
28161 this.previewEl.appendChild(this.canvasEl);
28163 this.setCanvasPosition();
28168 if(!this.canvasLoaded){
28172 var imageCanvas = document.createElement("canvas");
28174 var imageContext = imageCanvas.getContext("2d");
28176 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
28177 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
28179 var center = imageCanvas.width / 2;
28181 imageContext.translate(center, center);
28183 imageContext.rotate(this.rotate * Math.PI / 180);
28185 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
28187 var canvas = document.createElement("canvas");
28189 var context = canvas.getContext("2d");
28191 canvas.width = this.minWidth;
28192 canvas.height = this.minHeight;
28194 switch (this.rotate) {
28197 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
28198 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
28200 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28201 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28203 var targetWidth = this.minWidth - 2 * x;
28204 var targetHeight = this.minHeight - 2 * y;
28208 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28209 scale = targetWidth / width;
28212 if(x > 0 && y == 0){
28213 scale = targetHeight / height;
28216 if(x > 0 && y > 0){
28217 scale = targetWidth / width;
28219 if(width < height){
28220 scale = targetHeight / height;
28224 context.scale(scale, scale);
28226 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28227 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28229 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28230 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28232 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28237 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
28238 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
28240 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28241 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28243 var targetWidth = this.minWidth - 2 * x;
28244 var targetHeight = this.minHeight - 2 * y;
28248 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28249 scale = targetWidth / width;
28252 if(x > 0 && y == 0){
28253 scale = targetHeight / height;
28256 if(x > 0 && y > 0){
28257 scale = targetWidth / width;
28259 if(width < height){
28260 scale = targetHeight / height;
28264 context.scale(scale, scale);
28266 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28267 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28269 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28270 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28272 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
28274 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28279 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
28280 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
28282 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28283 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28285 var targetWidth = this.minWidth - 2 * x;
28286 var targetHeight = this.minHeight - 2 * y;
28290 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28291 scale = targetWidth / width;
28294 if(x > 0 && y == 0){
28295 scale = targetHeight / height;
28298 if(x > 0 && y > 0){
28299 scale = targetWidth / width;
28301 if(width < height){
28302 scale = targetHeight / height;
28306 context.scale(scale, scale);
28308 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28309 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28311 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28312 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28314 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
28315 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
28317 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28322 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
28323 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
28325 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28326 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28328 var targetWidth = this.minWidth - 2 * x;
28329 var targetHeight = this.minHeight - 2 * y;
28333 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28334 scale = targetWidth / width;
28337 if(x > 0 && y == 0){
28338 scale = targetHeight / height;
28341 if(x > 0 && y > 0){
28342 scale = targetWidth / width;
28344 if(width < height){
28345 scale = targetHeight / height;
28349 context.scale(scale, scale);
28351 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28352 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28354 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28355 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28357 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
28359 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28366 this.cropData = canvas.toDataURL(this.cropType);
28368 if(this.fireEvent('crop', this, this.cropData) !== false){
28369 this.process(this.file, this.cropData);
28376 setThumbBoxSize : function()
28380 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
28381 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
28382 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
28384 this.minWidth = width;
28385 this.minHeight = height;
28387 if(this.rotate == 90 || this.rotate == 270){
28388 this.minWidth = height;
28389 this.minHeight = width;
28394 width = Math.ceil(this.minWidth * height / this.minHeight);
28396 if(this.minWidth > this.minHeight){
28398 height = Math.ceil(this.minHeight * width / this.minWidth);
28401 this.thumbEl.setStyle({
28402 width : width + 'px',
28403 height : height + 'px'
28410 setThumbBoxPosition : function()
28412 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
28413 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
28415 this.thumbEl.setLeft(x);
28416 this.thumbEl.setTop(y);
28420 baseRotateLevel : function()
28422 this.baseRotate = 1;
28425 typeof(this.exif) != 'undefined' &&
28426 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
28427 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
28429 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
28432 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
28436 baseScaleLevel : function()
28440 if(this.isDocument){
28442 if(this.baseRotate == 6 || this.baseRotate == 8){
28444 height = this.thumbEl.getHeight();
28445 this.baseScale = height / this.imageEl.OriginWidth;
28447 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
28448 width = this.thumbEl.getWidth();
28449 this.baseScale = width / this.imageEl.OriginHeight;
28455 height = this.thumbEl.getHeight();
28456 this.baseScale = height / this.imageEl.OriginHeight;
28458 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
28459 width = this.thumbEl.getWidth();
28460 this.baseScale = width / this.imageEl.OriginWidth;
28466 if(this.baseRotate == 6 || this.baseRotate == 8){
28468 width = this.thumbEl.getHeight();
28469 this.baseScale = width / this.imageEl.OriginHeight;
28471 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
28472 height = this.thumbEl.getWidth();
28473 this.baseScale = height / this.imageEl.OriginHeight;
28476 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28477 height = this.thumbEl.getWidth();
28478 this.baseScale = height / this.imageEl.OriginHeight;
28480 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
28481 width = this.thumbEl.getHeight();
28482 this.baseScale = width / this.imageEl.OriginWidth;
28489 width = this.thumbEl.getWidth();
28490 this.baseScale = width / this.imageEl.OriginWidth;
28492 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
28493 height = this.thumbEl.getHeight();
28494 this.baseScale = height / this.imageEl.OriginHeight;
28497 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28499 height = this.thumbEl.getHeight();
28500 this.baseScale = height / this.imageEl.OriginHeight;
28502 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
28503 width = this.thumbEl.getWidth();
28504 this.baseScale = width / this.imageEl.OriginWidth;
28512 getScaleLevel : function()
28514 return this.baseScale * Math.pow(1.1, this.scale);
28517 onTouchStart : function(e)
28519 if(!this.canvasLoaded){
28520 this.beforeSelectFile(e);
28524 var touches = e.browserEvent.touches;
28530 if(touches.length == 1){
28531 this.onMouseDown(e);
28535 if(touches.length != 2){
28541 for(var i = 0, finger; finger = touches[i]; i++){
28542 coords.push(finger.pageX, finger.pageY);
28545 var x = Math.pow(coords[0] - coords[2], 2);
28546 var y = Math.pow(coords[1] - coords[3], 2);
28548 this.startDistance = Math.sqrt(x + y);
28550 this.startScale = this.scale;
28552 this.pinching = true;
28553 this.dragable = false;
28557 onTouchMove : function(e)
28559 if(!this.pinching && !this.dragable){
28563 var touches = e.browserEvent.touches;
28570 this.onMouseMove(e);
28576 for(var i = 0, finger; finger = touches[i]; i++){
28577 coords.push(finger.pageX, finger.pageY);
28580 var x = Math.pow(coords[0] - coords[2], 2);
28581 var y = Math.pow(coords[1] - coords[3], 2);
28583 this.endDistance = Math.sqrt(x + y);
28585 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
28587 if(!this.zoomable()){
28588 this.scale = this.startScale;
28596 onTouchEnd : function(e)
28598 this.pinching = false;
28599 this.dragable = false;
28603 process : function(file, crop)
28606 this.maskEl.mask(this.loadingText);
28609 this.xhr = new XMLHttpRequest();
28611 file.xhr = this.xhr;
28613 this.xhr.open(this.method, this.url, true);
28616 "Accept": "application/json",
28617 "Cache-Control": "no-cache",
28618 "X-Requested-With": "XMLHttpRequest"
28621 for (var headerName in headers) {
28622 var headerValue = headers[headerName];
28624 this.xhr.setRequestHeader(headerName, headerValue);
28630 this.xhr.onload = function()
28632 _this.xhrOnLoad(_this.xhr);
28635 this.xhr.onerror = function()
28637 _this.xhrOnError(_this.xhr);
28640 var formData = new FormData();
28642 formData.append('returnHTML', 'NO');
28645 formData.append('crop', crop);
28648 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
28649 formData.append(this.paramName, file, file.name);
28652 if(typeof(file.filename) != 'undefined'){
28653 formData.append('filename', file.filename);
28656 if(typeof(file.mimetype) != 'undefined'){
28657 formData.append('mimetype', file.mimetype);
28660 if(this.fireEvent('arrange', this, formData) != false){
28661 this.xhr.send(formData);
28665 xhrOnLoad : function(xhr)
28668 this.maskEl.unmask();
28671 if (xhr.readyState !== 4) {
28672 this.fireEvent('exception', this, xhr);
28676 var response = Roo.decode(xhr.responseText);
28678 if(!response.success){
28679 this.fireEvent('exception', this, xhr);
28683 var response = Roo.decode(xhr.responseText);
28685 this.fireEvent('upload', this, response);
28689 xhrOnError : function()
28692 this.maskEl.unmask();
28695 Roo.log('xhr on error');
28697 var response = Roo.decode(xhr.responseText);
28703 prepare : function(file)
28706 this.maskEl.mask(this.loadingText);
28712 if(typeof(file) === 'string'){
28713 this.loadCanvas(file);
28717 if(!file || !this.urlAPI){
28722 this.cropType = file.type;
28726 if(this.fireEvent('prepare', this, this.file) != false){
28728 var reader = new FileReader();
28730 reader.onload = function (e) {
28731 if (e.target.error) {
28732 Roo.log(e.target.error);
28736 var buffer = e.target.result,
28737 dataView = new DataView(buffer),
28739 maxOffset = dataView.byteLength - 4,
28743 if (dataView.getUint16(0) === 0xffd8) {
28744 while (offset < maxOffset) {
28745 markerBytes = dataView.getUint16(offset);
28747 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
28748 markerLength = dataView.getUint16(offset + 2) + 2;
28749 if (offset + markerLength > dataView.byteLength) {
28750 Roo.log('Invalid meta data: Invalid segment size.');
28754 if(markerBytes == 0xffe1){
28755 _this.parseExifData(
28762 offset += markerLength;
28772 var url = _this.urlAPI.createObjectURL(_this.file);
28774 _this.loadCanvas(url);
28779 reader.readAsArrayBuffer(this.file);
28785 parseExifData : function(dataView, offset, length)
28787 var tiffOffset = offset + 10,
28791 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28792 // No Exif data, might be XMP data instead
28796 // Check for the ASCII code for "Exif" (0x45786966):
28797 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28798 // No Exif data, might be XMP data instead
28801 if (tiffOffset + 8 > dataView.byteLength) {
28802 Roo.log('Invalid Exif data: Invalid segment size.');
28805 // Check for the two null bytes:
28806 if (dataView.getUint16(offset + 8) !== 0x0000) {
28807 Roo.log('Invalid Exif data: Missing byte alignment offset.');
28810 // Check the byte alignment:
28811 switch (dataView.getUint16(tiffOffset)) {
28813 littleEndian = true;
28816 littleEndian = false;
28819 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
28822 // Check for the TIFF tag marker (0x002A):
28823 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
28824 Roo.log('Invalid Exif data: Missing TIFF marker.');
28827 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
28828 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
28830 this.parseExifTags(
28833 tiffOffset + dirOffset,
28838 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
28843 if (dirOffset + 6 > dataView.byteLength) {
28844 Roo.log('Invalid Exif data: Invalid directory offset.');
28847 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
28848 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
28849 if (dirEndOffset + 4 > dataView.byteLength) {
28850 Roo.log('Invalid Exif data: Invalid directory size.');
28853 for (i = 0; i < tagsNumber; i += 1) {
28857 dirOffset + 2 + 12 * i, // tag offset
28861 // Return the offset to the next directory:
28862 return dataView.getUint32(dirEndOffset, littleEndian);
28865 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
28867 var tag = dataView.getUint16(offset, littleEndian);
28869 this.exif[tag] = this.getExifValue(
28873 dataView.getUint16(offset + 2, littleEndian), // tag type
28874 dataView.getUint32(offset + 4, littleEndian), // tag length
28879 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
28881 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
28890 Roo.log('Invalid Exif data: Invalid tag type.');
28894 tagSize = tagType.size * length;
28895 // Determine if the value is contained in the dataOffset bytes,
28896 // or if the value at the dataOffset is a pointer to the actual data:
28897 dataOffset = tagSize > 4 ?
28898 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
28899 if (dataOffset + tagSize > dataView.byteLength) {
28900 Roo.log('Invalid Exif data: Invalid data offset.');
28903 if (length === 1) {
28904 return tagType.getValue(dataView, dataOffset, littleEndian);
28907 for (i = 0; i < length; i += 1) {
28908 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
28911 if (tagType.ascii) {
28913 // Concatenate the chars:
28914 for (i = 0; i < values.length; i += 1) {
28916 // Ignore the terminating NULL byte(s):
28917 if (c === '\u0000') {
28929 Roo.apply(Roo.bootstrap.UploadCropbox, {
28931 'Orientation': 0x0112
28935 1: 0, //'top-left',
28937 3: 180, //'bottom-right',
28938 // 4: 'bottom-left',
28940 6: 90, //'right-top',
28941 // 7: 'right-bottom',
28942 8: 270 //'left-bottom'
28946 // byte, 8-bit unsigned int:
28948 getValue: function (dataView, dataOffset) {
28949 return dataView.getUint8(dataOffset);
28953 // ascii, 8-bit byte:
28955 getValue: function (dataView, dataOffset) {
28956 return String.fromCharCode(dataView.getUint8(dataOffset));
28961 // short, 16 bit int:
28963 getValue: function (dataView, dataOffset, littleEndian) {
28964 return dataView.getUint16(dataOffset, littleEndian);
28968 // long, 32 bit int:
28970 getValue: function (dataView, dataOffset, littleEndian) {
28971 return dataView.getUint32(dataOffset, littleEndian);
28975 // rational = two long values, first is numerator, second is denominator:
28977 getValue: function (dataView, dataOffset, littleEndian) {
28978 return dataView.getUint32(dataOffset, littleEndian) /
28979 dataView.getUint32(dataOffset + 4, littleEndian);
28983 // slong, 32 bit signed int:
28985 getValue: function (dataView, dataOffset, littleEndian) {
28986 return dataView.getInt32(dataOffset, littleEndian);
28990 // srational, two slongs, first is numerator, second is denominator:
28992 getValue: function (dataView, dataOffset, littleEndian) {
28993 return dataView.getInt32(dataOffset, littleEndian) /
28994 dataView.getInt32(dataOffset + 4, littleEndian);
29004 cls : 'btn-group roo-upload-cropbox-rotate-left',
29005 action : 'rotate-left',
29009 cls : 'btn btn-default',
29010 html : '<i class="fa fa-undo"></i>'
29016 cls : 'btn-group roo-upload-cropbox-picture',
29017 action : 'picture',
29021 cls : 'btn btn-default',
29022 html : '<i class="fa fa-picture-o"></i>'
29028 cls : 'btn-group roo-upload-cropbox-rotate-right',
29029 action : 'rotate-right',
29033 cls : 'btn btn-default',
29034 html : '<i class="fa fa-repeat"></i>'
29042 cls : 'btn-group roo-upload-cropbox-rotate-left',
29043 action : 'rotate-left',
29047 cls : 'btn btn-default',
29048 html : '<i class="fa fa-undo"></i>'
29054 cls : 'btn-group roo-upload-cropbox-download',
29055 action : 'download',
29059 cls : 'btn btn-default',
29060 html : '<i class="fa fa-download"></i>'
29066 cls : 'btn-group roo-upload-cropbox-crop',
29071 cls : 'btn btn-default',
29072 html : '<i class="fa fa-crop"></i>'
29078 cls : 'btn-group roo-upload-cropbox-trash',
29083 cls : 'btn btn-default',
29084 html : '<i class="fa fa-trash"></i>'
29090 cls : 'btn-group roo-upload-cropbox-rotate-right',
29091 action : 'rotate-right',
29095 cls : 'btn btn-default',
29096 html : '<i class="fa fa-repeat"></i>'
29104 cls : 'btn-group roo-upload-cropbox-rotate-left',
29105 action : 'rotate-left',
29109 cls : 'btn btn-default',
29110 html : '<i class="fa fa-undo"></i>'
29116 cls : 'btn-group roo-upload-cropbox-rotate-right',
29117 action : 'rotate-right',
29121 cls : 'btn btn-default',
29122 html : '<i class="fa fa-repeat"></i>'
29135 * @class Roo.bootstrap.DocumentManager
29136 * @extends Roo.bootstrap.Component
29137 * Bootstrap DocumentManager class
29138 * @cfg {String} paramName default 'imageUpload'
29139 * @cfg {String} toolTipName default 'filename'
29140 * @cfg {String} method default POST
29141 * @cfg {String} url action url
29142 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
29143 * @cfg {Boolean} multiple multiple upload default true
29144 * @cfg {Number} thumbSize default 300
29145 * @cfg {String} fieldLabel
29146 * @cfg {Number} labelWidth default 4
29147 * @cfg {String} labelAlign (left|top) default left
29148 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
29149 * @cfg {Number} labellg set the width of label (1-12)
29150 * @cfg {Number} labelmd set the width of label (1-12)
29151 * @cfg {Number} labelsm set the width of label (1-12)
29152 * @cfg {Number} labelxs set the width of label (1-12)
29155 * Create a new DocumentManager
29156 * @param {Object} config The config object
29159 Roo.bootstrap.DocumentManager = function(config){
29160 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
29163 this.delegates = [];
29168 * Fire when initial the DocumentManager
29169 * @param {Roo.bootstrap.DocumentManager} this
29174 * inspect selected file
29175 * @param {Roo.bootstrap.DocumentManager} this
29176 * @param {File} file
29181 * Fire when xhr load exception
29182 * @param {Roo.bootstrap.DocumentManager} this
29183 * @param {XMLHttpRequest} xhr
29185 "exception" : true,
29187 * @event afterupload
29188 * Fire when xhr load exception
29189 * @param {Roo.bootstrap.DocumentManager} this
29190 * @param {XMLHttpRequest} xhr
29192 "afterupload" : true,
29195 * prepare the form data
29196 * @param {Roo.bootstrap.DocumentManager} this
29197 * @param {Object} formData
29202 * Fire when remove the file
29203 * @param {Roo.bootstrap.DocumentManager} this
29204 * @param {Object} file
29209 * Fire after refresh the file
29210 * @param {Roo.bootstrap.DocumentManager} this
29215 * Fire after click the image
29216 * @param {Roo.bootstrap.DocumentManager} this
29217 * @param {Object} file
29222 * Fire when upload a image and editable set to true
29223 * @param {Roo.bootstrap.DocumentManager} this
29224 * @param {Object} file
29228 * @event beforeselectfile
29229 * Fire before select file
29230 * @param {Roo.bootstrap.DocumentManager} this
29232 "beforeselectfile" : true,
29235 * Fire before process file
29236 * @param {Roo.bootstrap.DocumentManager} this
29237 * @param {Object} file
29241 * @event previewrendered
29242 * Fire when preview rendered
29243 * @param {Roo.bootstrap.DocumentManager} this
29244 * @param {Object} file
29246 "previewrendered" : true,
29249 "previewResize" : true
29254 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
29263 paramName : 'imageUpload',
29264 toolTipName : 'filename',
29267 labelAlign : 'left',
29277 getAutoCreate : function()
29279 var managerWidget = {
29281 cls : 'roo-document-manager',
29285 cls : 'roo-document-manager-selector',
29290 cls : 'roo-document-manager-uploader',
29294 cls : 'roo-document-manager-upload-btn',
29295 html : '<i class="fa fa-plus"></i>'
29306 cls : 'column col-md-12',
29311 if(this.fieldLabel.length){
29316 cls : 'column col-md-12',
29317 html : this.fieldLabel
29321 cls : 'column col-md-12',
29326 if(this.labelAlign == 'left'){
29331 html : this.fieldLabel
29340 if(this.labelWidth > 12){
29341 content[0].style = "width: " + this.labelWidth + 'px';
29344 if(this.labelWidth < 13 && this.labelmd == 0){
29345 this.labelmd = this.labelWidth;
29348 if(this.labellg > 0){
29349 content[0].cls += ' col-lg-' + this.labellg;
29350 content[1].cls += ' col-lg-' + (12 - this.labellg);
29353 if(this.labelmd > 0){
29354 content[0].cls += ' col-md-' + this.labelmd;
29355 content[1].cls += ' col-md-' + (12 - this.labelmd);
29358 if(this.labelsm > 0){
29359 content[0].cls += ' col-sm-' + this.labelsm;
29360 content[1].cls += ' col-sm-' + (12 - this.labelsm);
29363 if(this.labelxs > 0){
29364 content[0].cls += ' col-xs-' + this.labelxs;
29365 content[1].cls += ' col-xs-' + (12 - this.labelxs);
29373 cls : 'row clearfix',
29381 initEvents : function()
29383 this.managerEl = this.el.select('.roo-document-manager', true).first();
29384 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29386 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
29387 this.selectorEl.hide();
29390 this.selectorEl.attr('multiple', 'multiple');
29393 this.selectorEl.on('change', this.onFileSelected, this);
29395 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
29396 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29398 this.uploader.on('click', this.onUploaderClick, this);
29400 this.renderProgressDialog();
29404 window.addEventListener("resize", function() { _this.refresh(); } );
29406 this.fireEvent('initial', this);
29409 renderProgressDialog : function()
29413 this.progressDialog = new Roo.bootstrap.Modal({
29414 cls : 'roo-document-manager-progress-dialog',
29415 allow_close : false,
29426 btnclick : function() {
29427 _this.uploadCancel();
29433 this.progressDialog.render(Roo.get(document.body));
29435 this.progress = new Roo.bootstrap.Progress({
29436 cls : 'roo-document-manager-progress',
29441 this.progress.render(this.progressDialog.getChildContainer());
29443 this.progressBar = new Roo.bootstrap.ProgressBar({
29444 cls : 'roo-document-manager-progress-bar',
29447 aria_valuemax : 12,
29451 this.progressBar.render(this.progress.getChildContainer());
29454 onUploaderClick : function(e)
29456 e.preventDefault();
29458 if(this.fireEvent('beforeselectfile', this) != false){
29459 this.selectorEl.dom.click();
29464 onFileSelected : function(e)
29466 e.preventDefault();
29468 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
29472 Roo.each(this.selectorEl.dom.files, function(file){
29473 if(this.fireEvent('inspect', this, file) != false){
29474 this.files.push(file);
29484 this.selectorEl.dom.value = '';
29486 if(!this.files || !this.files.length){
29490 if(this.boxes > 0 && this.files.length > this.boxes){
29491 this.files = this.files.slice(0, this.boxes);
29494 this.uploader.show();
29496 if(this.boxes > 0 && this.files.length > this.boxes - 1){
29497 this.uploader.hide();
29506 Roo.each(this.files, function(file){
29508 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29509 var f = this.renderPreview(file);
29514 if(file.type.indexOf('image') != -1){
29515 this.delegates.push(
29517 _this.process(file);
29518 }).createDelegate(this)
29526 _this.process(file);
29527 }).createDelegate(this)
29532 this.files = files;
29534 this.delegates = this.delegates.concat(docs);
29536 if(!this.delegates.length){
29541 this.progressBar.aria_valuemax = this.delegates.length;
29548 arrange : function()
29550 if(!this.delegates.length){
29551 this.progressDialog.hide();
29556 var delegate = this.delegates.shift();
29558 this.progressDialog.show();
29560 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
29562 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
29567 refresh : function()
29569 this.uploader.show();
29571 if(this.boxes > 0 && this.files.length > this.boxes - 1){
29572 this.uploader.hide();
29575 Roo.isTouch ? this.closable(false) : this.closable(true);
29577 this.fireEvent('refresh', this);
29580 onRemove : function(e, el, o)
29582 e.preventDefault();
29584 this.fireEvent('remove', this, o);
29588 remove : function(o)
29592 Roo.each(this.files, function(file){
29593 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
29602 this.files = files;
29609 Roo.each(this.files, function(file){
29614 file.target.remove();
29623 onClick : function(e, el, o)
29625 e.preventDefault();
29627 this.fireEvent('click', this, o);
29631 closable : function(closable)
29633 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
29635 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29647 xhrOnLoad : function(xhr)
29649 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29653 if (xhr.readyState !== 4) {
29655 this.fireEvent('exception', this, xhr);
29659 var response = Roo.decode(xhr.responseText);
29661 if(!response.success){
29663 this.fireEvent('exception', this, xhr);
29667 var file = this.renderPreview(response.data);
29669 this.files.push(file);
29673 this.fireEvent('afterupload', this, xhr);
29677 xhrOnError : function(xhr)
29679 Roo.log('xhr on error');
29681 var response = Roo.decode(xhr.responseText);
29688 process : function(file)
29690 if(this.fireEvent('process', this, file) !== false){
29691 if(this.editable && file.type.indexOf('image') != -1){
29692 this.fireEvent('edit', this, file);
29696 this.uploadStart(file, false);
29703 uploadStart : function(file, crop)
29705 this.xhr = new XMLHttpRequest();
29707 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29712 file.xhr = this.xhr;
29714 this.managerEl.createChild({
29716 cls : 'roo-document-manager-loading',
29720 tooltip : file.name,
29721 cls : 'roo-document-manager-thumb',
29722 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29728 this.xhr.open(this.method, this.url, true);
29731 "Accept": "application/json",
29732 "Cache-Control": "no-cache",
29733 "X-Requested-With": "XMLHttpRequest"
29736 for (var headerName in headers) {
29737 var headerValue = headers[headerName];
29739 this.xhr.setRequestHeader(headerName, headerValue);
29745 this.xhr.onload = function()
29747 _this.xhrOnLoad(_this.xhr);
29750 this.xhr.onerror = function()
29752 _this.xhrOnError(_this.xhr);
29755 var formData = new FormData();
29757 formData.append('returnHTML', 'NO');
29760 formData.append('crop', crop);
29763 formData.append(this.paramName, file, file.name);
29770 if(this.fireEvent('prepare', this, formData, options) != false){
29772 if(options.manually){
29776 this.xhr.send(formData);
29780 this.uploadCancel();
29783 uploadCancel : function()
29789 this.delegates = [];
29791 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29798 renderPreview : function(file)
29800 if(typeof(file.target) != 'undefined' && file.target){
29804 var img_src = encodeURI(baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename);
29806 var previewEl = this.managerEl.createChild({
29808 cls : 'roo-document-manager-preview',
29812 tooltip : file[this.toolTipName],
29813 cls : 'roo-document-manager-thumb',
29814 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + img_src + '">'
29819 html : '<i class="fa fa-times-circle"></i>'
29824 var close = previewEl.select('button.close', true).first();
29826 close.on('click', this.onRemove, this, file);
29828 file.target = previewEl;
29830 var image = previewEl.select('img', true).first();
29834 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
29836 image.on('click', this.onClick, this, file);
29838 this.fireEvent('previewrendered', this, file);
29844 onPreviewLoad : function(file, image)
29846 if(typeof(file.target) == 'undefined' || !file.target){
29850 var width = image.dom.naturalWidth || image.dom.width;
29851 var height = image.dom.naturalHeight || image.dom.height;
29853 if(!this.previewResize) {
29857 if(width > height){
29858 file.target.addClass('wide');
29862 file.target.addClass('tall');
29867 uploadFromSource : function(file, crop)
29869 this.xhr = new XMLHttpRequest();
29871 this.managerEl.createChild({
29873 cls : 'roo-document-manager-loading',
29877 tooltip : file.name,
29878 cls : 'roo-document-manager-thumb',
29879 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29885 this.xhr.open(this.method, this.url, true);
29888 "Accept": "application/json",
29889 "Cache-Control": "no-cache",
29890 "X-Requested-With": "XMLHttpRequest"
29893 for (var headerName in headers) {
29894 var headerValue = headers[headerName];
29896 this.xhr.setRequestHeader(headerName, headerValue);
29902 this.xhr.onload = function()
29904 _this.xhrOnLoad(_this.xhr);
29907 this.xhr.onerror = function()
29909 _this.xhrOnError(_this.xhr);
29912 var formData = new FormData();
29914 formData.append('returnHTML', 'NO');
29916 formData.append('crop', crop);
29918 if(typeof(file.filename) != 'undefined'){
29919 formData.append('filename', file.filename);
29922 if(typeof(file.mimetype) != 'undefined'){
29923 formData.append('mimetype', file.mimetype);
29928 if(this.fireEvent('prepare', this, formData) != false){
29929 this.xhr.send(formData);
29939 * @class Roo.bootstrap.DocumentViewer
29940 * @extends Roo.bootstrap.Component
29941 * Bootstrap DocumentViewer class
29942 * @cfg {Boolean} showDownload (true|false) show download button (default true)
29943 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
29946 * Create a new DocumentViewer
29947 * @param {Object} config The config object
29950 Roo.bootstrap.DocumentViewer = function(config){
29951 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
29956 * Fire after initEvent
29957 * @param {Roo.bootstrap.DocumentViewer} this
29963 * @param {Roo.bootstrap.DocumentViewer} this
29968 * Fire after download button
29969 * @param {Roo.bootstrap.DocumentViewer} this
29974 * Fire after trash button
29975 * @param {Roo.bootstrap.DocumentViewer} this
29982 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
29984 showDownload : true,
29988 getAutoCreate : function()
29992 cls : 'roo-document-viewer',
29996 cls : 'roo-document-viewer-body',
30000 cls : 'roo-document-viewer-thumb',
30004 cls : 'roo-document-viewer-image'
30012 cls : 'roo-document-viewer-footer',
30015 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
30019 cls : 'btn-group roo-document-viewer-download',
30023 cls : 'btn btn-default',
30024 html : '<i class="fa fa-download"></i>'
30030 cls : 'btn-group roo-document-viewer-trash',
30034 cls : 'btn btn-default',
30035 html : '<i class="fa fa-trash"></i>'
30048 initEvents : function()
30050 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
30051 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
30053 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
30054 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
30056 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
30057 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
30059 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
30060 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
30062 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
30063 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
30065 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
30066 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
30068 this.bodyEl.on('click', this.onClick, this);
30069 this.downloadBtn.on('click', this.onDownload, this);
30070 this.trashBtn.on('click', this.onTrash, this);
30072 this.downloadBtn.hide();
30073 this.trashBtn.hide();
30075 if(this.showDownload){
30076 this.downloadBtn.show();
30079 if(this.showTrash){
30080 this.trashBtn.show();
30083 if(!this.showDownload && !this.showTrash) {
30084 this.footerEl.hide();
30089 initial : function()
30091 this.fireEvent('initial', this);
30095 onClick : function(e)
30097 e.preventDefault();
30099 this.fireEvent('click', this);
30102 onDownload : function(e)
30104 e.preventDefault();
30106 this.fireEvent('download', this);
30109 onTrash : function(e)
30111 e.preventDefault();
30113 this.fireEvent('trash', this);
30125 * @class Roo.bootstrap.NavProgressBar
30126 * @extends Roo.bootstrap.Component
30127 * Bootstrap NavProgressBar class
30130 * Create a new nav progress bar
30131 * @param {Object} config The config object
30134 Roo.bootstrap.NavProgressBar = function(config){
30135 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
30137 this.bullets = this.bullets || [];
30139 // Roo.bootstrap.NavProgressBar.register(this);
30143 * Fires when the active item changes
30144 * @param {Roo.bootstrap.NavProgressBar} this
30145 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
30146 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
30153 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
30158 getAutoCreate : function()
30160 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
30164 cls : 'roo-navigation-bar-group',
30168 cls : 'roo-navigation-top-bar'
30172 cls : 'roo-navigation-bullets-bar',
30176 cls : 'roo-navigation-bar'
30183 cls : 'roo-navigation-bottom-bar'
30193 initEvents: function()
30198 onRender : function(ct, position)
30200 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30202 if(this.bullets.length){
30203 Roo.each(this.bullets, function(b){
30212 addItem : function(cfg)
30214 var item = new Roo.bootstrap.NavProgressItem(cfg);
30216 item.parentId = this.id;
30217 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
30220 var top = new Roo.bootstrap.Element({
30222 cls : 'roo-navigation-bar-text'
30225 var bottom = new Roo.bootstrap.Element({
30227 cls : 'roo-navigation-bar-text'
30230 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
30231 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
30233 var topText = new Roo.bootstrap.Element({
30235 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
30238 var bottomText = new Roo.bootstrap.Element({
30240 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
30243 topText.onRender(top.el, null);
30244 bottomText.onRender(bottom.el, null);
30247 item.bottomEl = bottom;
30250 this.barItems.push(item);
30255 getActive : function()
30257 var active = false;
30259 Roo.each(this.barItems, function(v){
30261 if (!v.isActive()) {
30273 setActiveItem : function(item)
30277 Roo.each(this.barItems, function(v){
30278 if (v.rid == item.rid) {
30282 if (v.isActive()) {
30283 v.setActive(false);
30288 item.setActive(true);
30290 this.fireEvent('changed', this, item, prev);
30293 getBarItem: function(rid)
30297 Roo.each(this.barItems, function(e) {
30298 if (e.rid != rid) {
30309 indexOfItem : function(item)
30313 Roo.each(this.barItems, function(v, i){
30315 if (v.rid != item.rid) {
30326 setActiveNext : function()
30328 var i = this.indexOfItem(this.getActive());
30330 if (i > this.barItems.length) {
30334 this.setActiveItem(this.barItems[i+1]);
30337 setActivePrev : function()
30339 var i = this.indexOfItem(this.getActive());
30345 this.setActiveItem(this.barItems[i-1]);
30348 format : function()
30350 if(!this.barItems.length){
30354 var width = 100 / this.barItems.length;
30356 Roo.each(this.barItems, function(i){
30357 i.el.setStyle('width', width + '%');
30358 i.topEl.el.setStyle('width', width + '%');
30359 i.bottomEl.el.setStyle('width', width + '%');
30368 * Nav Progress Item
30373 * @class Roo.bootstrap.NavProgressItem
30374 * @extends Roo.bootstrap.Component
30375 * Bootstrap NavProgressItem class
30376 * @cfg {String} rid the reference id
30377 * @cfg {Boolean} active (true|false) Is item active default false
30378 * @cfg {Boolean} disabled (true|false) Is item active default false
30379 * @cfg {String} html
30380 * @cfg {String} position (top|bottom) text position default bottom
30381 * @cfg {String} icon show icon instead of number
30384 * Create a new NavProgressItem
30385 * @param {Object} config The config object
30387 Roo.bootstrap.NavProgressItem = function(config){
30388 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
30393 * The raw click event for the entire grid.
30394 * @param {Roo.bootstrap.NavProgressItem} this
30395 * @param {Roo.EventObject} e
30402 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
30408 position : 'bottom',
30411 getAutoCreate : function()
30413 var iconCls = 'roo-navigation-bar-item-icon';
30415 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
30419 cls: 'roo-navigation-bar-item',
30429 cfg.cls += ' active';
30432 cfg.cls += ' disabled';
30438 disable : function()
30440 this.setDisabled(true);
30443 enable : function()
30445 this.setDisabled(false);
30448 initEvents: function()
30450 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
30452 this.iconEl.on('click', this.onClick, this);
30455 onClick : function(e)
30457 e.preventDefault();
30463 if(this.fireEvent('click', this, e) === false){
30467 this.parent().setActiveItem(this);
30470 isActive: function ()
30472 return this.active;
30475 setActive : function(state)
30477 if(this.active == state){
30481 this.active = state;
30484 this.el.addClass('active');
30488 this.el.removeClass('active');
30493 setDisabled : function(state)
30495 if(this.disabled == state){
30499 this.disabled = state;
30502 this.el.addClass('disabled');
30506 this.el.removeClass('disabled');
30509 tooltipEl : function()
30511 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
30524 * @class Roo.bootstrap.FieldLabel
30525 * @extends Roo.bootstrap.Component
30526 * Bootstrap FieldLabel class
30527 * @cfg {String} html contents of the element
30528 * @cfg {String} tag tag of the element default label
30529 * @cfg {String} cls class of the element
30530 * @cfg {String} target label target
30531 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
30532 * @cfg {String} invalidClass DEPRICATED - BS4 uses is-invalid
30533 * @cfg {String} validClass DEPRICATED - BS4 uses is-valid
30534 * @cfg {String} iconTooltip default "This field is required"
30535 * @cfg {String} indicatorpos (left|right) default left
30538 * Create a new FieldLabel
30539 * @param {Object} config The config object
30542 Roo.bootstrap.FieldLabel = function(config){
30543 Roo.bootstrap.Element.superclass.constructor.call(this, config);
30548 * Fires after the field has been marked as invalid.
30549 * @param {Roo.form.FieldLabel} this
30550 * @param {String} msg The validation message
30555 * Fires after the field has been validated with no errors.
30556 * @param {Roo.form.FieldLabel} this
30562 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
30569 invalidClass : 'has-warning',
30570 validClass : 'has-success',
30571 iconTooltip : 'This field is required',
30572 indicatorpos : 'left',
30574 getAutoCreate : function(){
30577 if (!this.allowBlank) {
30583 cls : 'roo-bootstrap-field-label ' + this.cls,
30588 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star ' + cls,
30589 tooltip : this.iconTooltip
30598 if(this.indicatorpos == 'right'){
30601 cls : 'roo-bootstrap-field-label ' + this.cls,
30610 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star '+ cls,
30611 tooltip : this.iconTooltip
30620 initEvents: function()
30622 Roo.bootstrap.Element.superclass.initEvents.call(this);
30624 this.indicator = this.indicatorEl();
30626 if(this.indicator){
30627 this.indicator.removeClass('visible');
30628 this.indicator.addClass('invisible');
30631 Roo.bootstrap.FieldLabel.register(this);
30634 indicatorEl : function()
30636 var indicator = this.el.select('i.roo-required-indicator',true).first();
30647 * Mark this field as valid
30649 markValid : function()
30651 if(this.indicator){
30652 this.indicator.removeClass('visible');
30653 this.indicator.addClass('invisible');
30655 if (Roo.bootstrap.version == 3) {
30656 this.el.removeClass(this.invalidClass);
30657 this.el.addClass(this.validClass);
30659 this.el.removeClass('is-invalid');
30660 this.el.addClass('is-valid');
30664 this.fireEvent('valid', this);
30668 * Mark this field as invalid
30669 * @param {String} msg The validation message
30671 markInvalid : function(msg)
30673 if(this.indicator){
30674 this.indicator.removeClass('invisible');
30675 this.indicator.addClass('visible');
30677 if (Roo.bootstrap.version == 3) {
30678 this.el.removeClass(this.validClass);
30679 this.el.addClass(this.invalidClass);
30681 this.el.removeClass('is-valid');
30682 this.el.addClass('is-invalid');
30686 this.fireEvent('invalid', this, msg);
30692 Roo.apply(Roo.bootstrap.FieldLabel, {
30697 * register a FieldLabel Group
30698 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
30700 register : function(label)
30702 if(this.groups.hasOwnProperty(label.target)){
30706 this.groups[label.target] = label;
30710 * fetch a FieldLabel Group based on the target
30711 * @param {string} target
30712 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
30714 get: function(target) {
30715 if (typeof(this.groups[target]) == 'undefined') {
30719 return this.groups[target] ;
30728 * page DateSplitField.
30734 * @class Roo.bootstrap.DateSplitField
30735 * @extends Roo.bootstrap.Component
30736 * Bootstrap DateSplitField class
30737 * @cfg {string} fieldLabel - the label associated
30738 * @cfg {Number} labelWidth set the width of label (0-12)
30739 * @cfg {String} labelAlign (top|left)
30740 * @cfg {Boolean} dayAllowBlank (true|false) default false
30741 * @cfg {Boolean} monthAllowBlank (true|false) default false
30742 * @cfg {Boolean} yearAllowBlank (true|false) default false
30743 * @cfg {string} dayPlaceholder
30744 * @cfg {string} monthPlaceholder
30745 * @cfg {string} yearPlaceholder
30746 * @cfg {string} dayFormat default 'd'
30747 * @cfg {string} monthFormat default 'm'
30748 * @cfg {string} yearFormat default 'Y'
30749 * @cfg {Number} labellg set the width of label (1-12)
30750 * @cfg {Number} labelmd set the width of label (1-12)
30751 * @cfg {Number} labelsm set the width of label (1-12)
30752 * @cfg {Number} labelxs set the width of label (1-12)
30756 * Create a new DateSplitField
30757 * @param {Object} config The config object
30760 Roo.bootstrap.DateSplitField = function(config){
30761 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
30767 * getting the data of years
30768 * @param {Roo.bootstrap.DateSplitField} this
30769 * @param {Object} years
30774 * getting the data of days
30775 * @param {Roo.bootstrap.DateSplitField} this
30776 * @param {Object} days
30781 * Fires after the field has been marked as invalid.
30782 * @param {Roo.form.Field} this
30783 * @param {String} msg The validation message
30788 * Fires after the field has been validated with no errors.
30789 * @param {Roo.form.Field} this
30795 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
30798 labelAlign : 'top',
30800 dayAllowBlank : false,
30801 monthAllowBlank : false,
30802 yearAllowBlank : false,
30803 dayPlaceholder : '',
30804 monthPlaceholder : '',
30805 yearPlaceholder : '',
30809 isFormField : true,
30815 getAutoCreate : function()
30819 cls : 'row roo-date-split-field-group',
30824 cls : 'form-hidden-field roo-date-split-field-group-value',
30830 var labelCls = 'col-md-12';
30831 var contentCls = 'col-md-4';
30833 if(this.fieldLabel){
30837 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
30841 html : this.fieldLabel
30846 if(this.labelAlign == 'left'){
30848 if(this.labelWidth > 12){
30849 label.style = "width: " + this.labelWidth + 'px';
30852 if(this.labelWidth < 13 && this.labelmd == 0){
30853 this.labelmd = this.labelWidth;
30856 if(this.labellg > 0){
30857 labelCls = ' col-lg-' + this.labellg;
30858 contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
30861 if(this.labelmd > 0){
30862 labelCls = ' col-md-' + this.labelmd;
30863 contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
30866 if(this.labelsm > 0){
30867 labelCls = ' col-sm-' + this.labelsm;
30868 contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
30871 if(this.labelxs > 0){
30872 labelCls = ' col-xs-' + this.labelxs;
30873 contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
30877 label.cls += ' ' + labelCls;
30879 cfg.cn.push(label);
30882 Roo.each(['day', 'month', 'year'], function(t){
30885 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
30892 inputEl: function ()
30894 return this.el.select('.roo-date-split-field-group-value', true).first();
30897 onRender : function(ct, position)
30901 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30903 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
30905 this.dayField = new Roo.bootstrap.ComboBox({
30906 allowBlank : this.dayAllowBlank,
30907 alwaysQuery : true,
30908 displayField : 'value',
30911 forceSelection : true,
30913 placeholder : this.dayPlaceholder,
30914 selectOnFocus : true,
30915 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30916 triggerAction : 'all',
30918 valueField : 'value',
30919 store : new Roo.data.SimpleStore({
30920 data : (function() {
30922 _this.fireEvent('days', _this, days);
30925 fields : [ 'value' ]
30928 select : function (_self, record, index)
30930 _this.setValue(_this.getValue());
30935 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
30937 this.monthField = new Roo.bootstrap.MonthField({
30938 after : '<i class=\"fa fa-calendar\"></i>',
30939 allowBlank : this.monthAllowBlank,
30940 placeholder : this.monthPlaceholder,
30943 render : function (_self)
30945 this.el.select('span.input-group-addon', true).first().on('click', function(e){
30946 e.preventDefault();
30950 select : function (_self, oldvalue, newvalue)
30952 _this.setValue(_this.getValue());
30957 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
30959 this.yearField = new Roo.bootstrap.ComboBox({
30960 allowBlank : this.yearAllowBlank,
30961 alwaysQuery : true,
30962 displayField : 'value',
30965 forceSelection : true,
30967 placeholder : this.yearPlaceholder,
30968 selectOnFocus : true,
30969 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30970 triggerAction : 'all',
30972 valueField : 'value',
30973 store : new Roo.data.SimpleStore({
30974 data : (function() {
30976 _this.fireEvent('years', _this, years);
30979 fields : [ 'value' ]
30982 select : function (_self, record, index)
30984 _this.setValue(_this.getValue());
30989 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
30992 setValue : function(v, format)
30994 this.inputEl.dom.value = v;
30996 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
30998 var d = Date.parseDate(v, f);
31005 this.setDay(d.format(this.dayFormat));
31006 this.setMonth(d.format(this.monthFormat));
31007 this.setYear(d.format(this.yearFormat));
31014 setDay : function(v)
31016 this.dayField.setValue(v);
31017 this.inputEl.dom.value = this.getValue();
31022 setMonth : function(v)
31024 this.monthField.setValue(v, true);
31025 this.inputEl.dom.value = this.getValue();
31030 setYear : function(v)
31032 this.yearField.setValue(v);
31033 this.inputEl.dom.value = this.getValue();
31038 getDay : function()
31040 return this.dayField.getValue();
31043 getMonth : function()
31045 return this.monthField.getValue();
31048 getYear : function()
31050 return this.yearField.getValue();
31053 getValue : function()
31055 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
31057 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
31067 this.inputEl.dom.value = '';
31072 validate : function()
31074 var d = this.dayField.validate();
31075 var m = this.monthField.validate();
31076 var y = this.yearField.validate();
31081 (!this.dayAllowBlank && !d) ||
31082 (!this.monthAllowBlank && !m) ||
31083 (!this.yearAllowBlank && !y)
31088 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
31097 this.markInvalid();
31102 markValid : function()
31105 var label = this.el.select('label', true).first();
31106 var icon = this.el.select('i.fa-star', true).first();
31112 this.fireEvent('valid', this);
31116 * Mark this field as invalid
31117 * @param {String} msg The validation message
31119 markInvalid : function(msg)
31122 var label = this.el.select('label', true).first();
31123 var icon = this.el.select('i.fa-star', true).first();
31125 if(label && !icon){
31126 this.el.select('.roo-date-split-field-label', true).createChild({
31128 cls : 'text-danger fa fa-lg fa-star',
31129 tooltip : 'This field is required',
31130 style : 'margin-right:5px;'
31134 this.fireEvent('invalid', this, msg);
31137 clearInvalid : function()
31139 var label = this.el.select('label', true).first();
31140 var icon = this.el.select('i.fa-star', true).first();
31146 this.fireEvent('valid', this);
31149 getName: function()
31159 * http://masonry.desandro.com
31161 * The idea is to render all the bricks based on vertical width...
31163 * The original code extends 'outlayer' - we might need to use that....
31169 * @class Roo.bootstrap.LayoutMasonry
31170 * @extends Roo.bootstrap.Component
31171 * Bootstrap Layout Masonry class
31174 * Create a new Element
31175 * @param {Object} config The config object
31178 Roo.bootstrap.LayoutMasonry = function(config){
31180 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
31184 Roo.bootstrap.LayoutMasonry.register(this);
31190 * Fire after layout the items
31191 * @param {Roo.bootstrap.LayoutMasonry} this
31192 * @param {Roo.EventObject} e
31199 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
31202 * @cfg {Boolean} isLayoutInstant = no animation?
31204 isLayoutInstant : false, // needed?
31207 * @cfg {Number} boxWidth width of the columns
31212 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
31217 * @cfg {Number} padWidth padding below box..
31222 * @cfg {Number} gutter gutter width..
31227 * @cfg {Number} maxCols maximum number of columns
31233 * @cfg {Boolean} isAutoInitial defalut true
31235 isAutoInitial : true,
31240 * @cfg {Boolean} isHorizontal defalut false
31242 isHorizontal : false,
31244 currentSize : null,
31250 bricks: null, //CompositeElement
31254 _isLayoutInited : false,
31256 // isAlternative : false, // only use for vertical layout...
31259 * @cfg {Number} alternativePadWidth padding below box..
31261 alternativePadWidth : 50,
31263 selectedBrick : [],
31265 getAutoCreate : function(){
31267 var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
31271 cls: 'blog-masonary-wrapper ' + this.cls,
31273 cls : 'mas-boxes masonary'
31280 getChildContainer: function( )
31282 if (this.boxesEl) {
31283 return this.boxesEl;
31286 this.boxesEl = this.el.select('.mas-boxes').first();
31288 return this.boxesEl;
31292 initEvents : function()
31296 if(this.isAutoInitial){
31297 Roo.log('hook children rendered');
31298 this.on('childrenrendered', function() {
31299 Roo.log('children rendered');
31305 initial : function()
31307 this.selectedBrick = [];
31309 this.currentSize = this.el.getBox(true);
31311 Roo.EventManager.onWindowResize(this.resize, this);
31313 if(!this.isAutoInitial){
31321 //this.layout.defer(500,this);
31325 resize : function()
31327 var cs = this.el.getBox(true);
31330 this.currentSize.width == cs.width &&
31331 this.currentSize.x == cs.x &&
31332 this.currentSize.height == cs.height &&
31333 this.currentSize.y == cs.y
31335 Roo.log("no change in with or X or Y");
31339 this.currentSize = cs;
31345 layout : function()
31347 this._resetLayout();
31349 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
31351 this.layoutItems( isInstant );
31353 this._isLayoutInited = true;
31355 this.fireEvent('layout', this);
31359 _resetLayout : function()
31361 if(this.isHorizontal){
31362 this.horizontalMeasureColumns();
31366 this.verticalMeasureColumns();
31370 verticalMeasureColumns : function()
31372 this.getContainerWidth();
31374 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
31375 // this.colWidth = Math.floor(this.containerWidth * 0.8);
31379 var boxWidth = this.boxWidth + this.padWidth;
31381 if(this.containerWidth < this.boxWidth){
31382 boxWidth = this.containerWidth
31385 var containerWidth = this.containerWidth;
31387 var cols = Math.floor(containerWidth / boxWidth);
31389 this.cols = Math.max( cols, 1 );
31391 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
31393 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
31395 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
31397 this.colWidth = boxWidth + avail - this.padWidth;
31399 this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
31400 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
31403 horizontalMeasureColumns : function()
31405 this.getContainerWidth();
31407 var boxWidth = this.boxWidth;
31409 if(this.containerWidth < boxWidth){
31410 boxWidth = this.containerWidth;
31413 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
31415 this.el.setHeight(boxWidth);
31419 getContainerWidth : function()
31421 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
31424 layoutItems : function( isInstant )
31426 Roo.log(this.bricks);
31428 var items = Roo.apply([], this.bricks);
31430 if(this.isHorizontal){
31431 this._horizontalLayoutItems( items , isInstant );
31435 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
31436 // this._verticalAlternativeLayoutItems( items , isInstant );
31440 this._verticalLayoutItems( items , isInstant );
31444 _verticalLayoutItems : function ( items , isInstant)
31446 if ( !items || !items.length ) {
31451 ['xs', 'xs', 'xs', 'tall'],
31452 ['xs', 'xs', 'tall'],
31453 ['xs', 'xs', 'sm'],
31454 ['xs', 'xs', 'xs'],
31460 ['sm', 'xs', 'xs'],
31464 ['tall', 'xs', 'xs', 'xs'],
31465 ['tall', 'xs', 'xs'],
31477 Roo.each(items, function(item, k){
31479 switch (item.size) {
31480 // these layouts take up a full box,
31491 boxes.push([item]);
31514 var filterPattern = function(box, length)
31522 var pattern = box.slice(0, length);
31526 Roo.each(pattern, function(i){
31527 format.push(i.size);
31530 Roo.each(standard, function(s){
31532 if(String(s) != String(format)){
31541 if(!match && length == 1){
31546 filterPattern(box, length - 1);
31550 queue.push(pattern);
31552 box = box.slice(length, box.length);
31554 filterPattern(box, 4);
31560 Roo.each(boxes, function(box, k){
31566 if(box.length == 1){
31571 filterPattern(box, 4);
31575 this._processVerticalLayoutQueue( queue, isInstant );
31579 // _verticalAlternativeLayoutItems : function( items , isInstant )
31581 // if ( !items || !items.length ) {
31585 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
31589 _horizontalLayoutItems : function ( items , isInstant)
31591 if ( !items || !items.length || items.length < 3) {
31597 var eItems = items.slice(0, 3);
31599 items = items.slice(3, items.length);
31602 ['xs', 'xs', 'xs', 'wide'],
31603 ['xs', 'xs', 'wide'],
31604 ['xs', 'xs', 'sm'],
31605 ['xs', 'xs', 'xs'],
31611 ['sm', 'xs', 'xs'],
31615 ['wide', 'xs', 'xs', 'xs'],
31616 ['wide', 'xs', 'xs'],
31629 Roo.each(items, function(item, k){
31631 switch (item.size) {
31642 boxes.push([item]);
31666 var filterPattern = function(box, length)
31674 var pattern = box.slice(0, length);
31678 Roo.each(pattern, function(i){
31679 format.push(i.size);
31682 Roo.each(standard, function(s){
31684 if(String(s) != String(format)){
31693 if(!match && length == 1){
31698 filterPattern(box, length - 1);
31702 queue.push(pattern);
31704 box = box.slice(length, box.length);
31706 filterPattern(box, 4);
31712 Roo.each(boxes, function(box, k){
31718 if(box.length == 1){
31723 filterPattern(box, 4);
31730 var pos = this.el.getBox(true);
31734 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31736 var hit_end = false;
31738 Roo.each(queue, function(box){
31742 Roo.each(box, function(b){
31744 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31754 Roo.each(box, function(b){
31756 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31759 mx = Math.max(mx, b.x);
31763 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
31767 Roo.each(box, function(b){
31769 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31783 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
31786 /** Sets position of item in DOM
31787 * @param {Element} item
31788 * @param {Number} x - horizontal position
31789 * @param {Number} y - vertical position
31790 * @param {Boolean} isInstant - disables transitions
31792 _processVerticalLayoutQueue : function( queue, isInstant )
31794 var pos = this.el.getBox(true);
31799 for (var i = 0; i < this.cols; i++){
31803 Roo.each(queue, function(box, k){
31805 var col = k % this.cols;
31807 Roo.each(box, function(b,kk){
31809 b.el.position('absolute');
31811 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31812 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31814 if(b.size == 'md-left' || b.size == 'md-right'){
31815 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31816 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31819 b.el.setWidth(width);
31820 b.el.setHeight(height);
31822 b.el.select('iframe',true).setSize(width,height);
31826 for (var i = 0; i < this.cols; i++){
31828 if(maxY[i] < maxY[col]){
31833 col = Math.min(col, i);
31837 x = pos.x + col * (this.colWidth + this.padWidth);
31841 var positions = [];
31843 switch (box.length){
31845 positions = this.getVerticalOneBoxColPositions(x, y, box);
31848 positions = this.getVerticalTwoBoxColPositions(x, y, box);
31851 positions = this.getVerticalThreeBoxColPositions(x, y, box);
31854 positions = this.getVerticalFourBoxColPositions(x, y, box);
31860 Roo.each(box, function(b,kk){
31862 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31864 var sz = b.el.getSize();
31866 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
31874 for (var i = 0; i < this.cols; i++){
31875 mY = Math.max(mY, maxY[i]);
31878 this.el.setHeight(mY - pos.y);
31882 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
31884 // var pos = this.el.getBox(true);
31887 // var maxX = pos.right;
31889 // var maxHeight = 0;
31891 // Roo.each(items, function(item, k){
31895 // item.el.position('absolute');
31897 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
31899 // item.el.setWidth(width);
31901 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
31903 // item.el.setHeight(height);
31906 // item.el.setXY([x, y], isInstant ? false : true);
31908 // item.el.setXY([maxX - width, y], isInstant ? false : true);
31911 // y = y + height + this.alternativePadWidth;
31913 // maxHeight = maxHeight + height + this.alternativePadWidth;
31917 // this.el.setHeight(maxHeight);
31921 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
31923 var pos = this.el.getBox(true);
31928 var maxX = pos.right;
31930 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
31932 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31934 Roo.each(queue, function(box, k){
31936 Roo.each(box, function(b, kk){
31938 b.el.position('absolute');
31940 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31941 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31943 if(b.size == 'md-left' || b.size == 'md-right'){
31944 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31945 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31948 b.el.setWidth(width);
31949 b.el.setHeight(height);
31957 var positions = [];
31959 switch (box.length){
31961 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
31964 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
31967 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
31970 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
31976 Roo.each(box, function(b,kk){
31978 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31980 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
31988 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
31990 Roo.each(eItems, function(b,k){
31992 b.size = (k == 0) ? 'sm' : 'xs';
31993 b.x = (k == 0) ? 2 : 1;
31994 b.y = (k == 0) ? 2 : 1;
31996 b.el.position('absolute');
31998 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
32000 b.el.setWidth(width);
32002 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
32004 b.el.setHeight(height);
32008 var positions = [];
32011 x : maxX - this.unitWidth * 2 - this.gutter,
32016 x : maxX - this.unitWidth,
32017 y : minY + (this.unitWidth + this.gutter) * 2
32021 x : maxX - this.unitWidth * 3 - this.gutter * 2,
32025 Roo.each(eItems, function(b,k){
32027 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
32033 getVerticalOneBoxColPositions : function(x, y, box)
32037 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
32039 if(box[0].size == 'md-left'){
32043 if(box[0].size == 'md-right'){
32048 x : x + (this.unitWidth + this.gutter) * rand,
32055 getVerticalTwoBoxColPositions : function(x, y, box)
32059 if(box[0].size == 'xs'){
32063 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
32067 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
32081 x : x + (this.unitWidth + this.gutter) * 2,
32082 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
32089 getVerticalThreeBoxColPositions : function(x, y, box)
32093 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
32101 x : x + (this.unitWidth + this.gutter) * 1,
32106 x : x + (this.unitWidth + this.gutter) * 2,
32114 if(box[0].size == 'xs' && box[1].size == 'xs'){
32123 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
32127 x : x + (this.unitWidth + this.gutter) * 1,
32141 x : x + (this.unitWidth + this.gutter) * 2,
32146 x : x + (this.unitWidth + this.gutter) * 2,
32147 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
32154 getVerticalFourBoxColPositions : function(x, y, box)
32158 if(box[0].size == 'xs'){
32167 y : y + (this.unitHeight + this.gutter) * 1
32172 y : y + (this.unitHeight + this.gutter) * 2
32176 x : x + (this.unitWidth + this.gutter) * 1,
32190 x : x + (this.unitWidth + this.gutter) * 2,
32195 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
32196 y : y + (this.unitHeight + this.gutter) * 1
32200 x : x + (this.unitWidth + this.gutter) * 2,
32201 y : y + (this.unitWidth + this.gutter) * 2
32208 getHorizontalOneBoxColPositions : function(maxX, minY, box)
32212 if(box[0].size == 'md-left'){
32214 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
32221 if(box[0].size == 'md-right'){
32223 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
32224 y : minY + (this.unitWidth + this.gutter) * 1
32230 var rand = Math.floor(Math.random() * (4 - box[0].y));
32233 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32234 y : minY + (this.unitWidth + this.gutter) * rand
32241 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
32245 if(box[0].size == 'xs'){
32248 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32253 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32254 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
32262 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32267 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32268 y : minY + (this.unitWidth + this.gutter) * 2
32275 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
32279 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
32282 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32287 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32288 y : minY + (this.unitWidth + this.gutter) * 1
32292 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32293 y : minY + (this.unitWidth + this.gutter) * 2
32300 if(box[0].size == 'xs' && box[1].size == 'xs'){
32303 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32308 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32313 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32314 y : minY + (this.unitWidth + this.gutter) * 1
32322 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32327 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32328 y : minY + (this.unitWidth + this.gutter) * 2
32332 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32333 y : minY + (this.unitWidth + this.gutter) * 2
32340 getHorizontalFourBoxColPositions : function(maxX, minY, box)
32344 if(box[0].size == 'xs'){
32347 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32352 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].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) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32362 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
32363 y : minY + (this.unitWidth + this.gutter) * 1
32371 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32376 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32377 y : minY + (this.unitWidth + this.gutter) * 2
32381 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].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) - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
32387 y : minY + (this.unitWidth + this.gutter) * 2
32395 * remove a Masonry Brick
32396 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
32398 removeBrick : function(brick_id)
32404 for (var i = 0; i<this.bricks.length; i++) {
32405 if (this.bricks[i].id == brick_id) {
32406 this.bricks.splice(i,1);
32407 this.el.dom.removeChild(Roo.get(brick_id).dom);
32414 * adds a Masonry Brick
32415 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32417 addBrick : function(cfg)
32419 var cn = new Roo.bootstrap.MasonryBrick(cfg);
32420 //this.register(cn);
32421 cn.parentId = this.id;
32422 cn.render(this.el);
32427 * register a Masonry Brick
32428 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32431 register : function(brick)
32433 this.bricks.push(brick);
32434 brick.masonryId = this.id;
32438 * clear all the Masonry Brick
32440 clearAll : function()
32443 //this.getChildContainer().dom.innerHTML = "";
32444 this.el.dom.innerHTML = '';
32447 getSelected : function()
32449 if (!this.selectedBrick) {
32453 return this.selectedBrick;
32457 Roo.apply(Roo.bootstrap.LayoutMasonry, {
32461 * register a Masonry Layout
32462 * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
32465 register : function(layout)
32467 this.groups[layout.id] = layout;
32470 * fetch a Masonry Layout based on the masonry layout ID
32471 * @param {string} the masonry layout to add
32472 * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
32475 get: function(layout_id) {
32476 if (typeof(this.groups[layout_id]) == 'undefined') {
32479 return this.groups[layout_id] ;
32491 * http://masonry.desandro.com
32493 * The idea is to render all the bricks based on vertical width...
32495 * The original code extends 'outlayer' - we might need to use that....
32501 * @class Roo.bootstrap.LayoutMasonryAuto
32502 * @extends Roo.bootstrap.Component
32503 * Bootstrap Layout Masonry class
32506 * Create a new Element
32507 * @param {Object} config The config object
32510 Roo.bootstrap.LayoutMasonryAuto = function(config){
32511 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
32514 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
32517 * @cfg {Boolean} isFitWidth - resize the width..
32519 isFitWidth : false, // options..
32521 * @cfg {Boolean} isOriginLeft = left align?
32523 isOriginLeft : true,
32525 * @cfg {Boolean} isOriginTop = top align?
32527 isOriginTop : false,
32529 * @cfg {Boolean} isLayoutInstant = no animation?
32531 isLayoutInstant : false, // needed?
32533 * @cfg {Boolean} isResizingContainer = not sure if this is used..
32535 isResizingContainer : true,
32537 * @cfg {Number} columnWidth width of the columns
32543 * @cfg {Number} maxCols maximum number of columns
32548 * @cfg {Number} padHeight padding below box..
32554 * @cfg {Boolean} isAutoInitial defalut true
32557 isAutoInitial : true,
32563 initialColumnWidth : 0,
32564 currentSize : null,
32566 colYs : null, // array.
32573 bricks: null, //CompositeElement
32574 cols : 0, // array?
32575 // element : null, // wrapped now this.el
32576 _isLayoutInited : null,
32579 getAutoCreate : function(){
32583 cls: 'blog-masonary-wrapper ' + this.cls,
32585 cls : 'mas-boxes masonary'
32592 getChildContainer: function( )
32594 if (this.boxesEl) {
32595 return this.boxesEl;
32598 this.boxesEl = this.el.select('.mas-boxes').first();
32600 return this.boxesEl;
32604 initEvents : function()
32608 if(this.isAutoInitial){
32609 Roo.log('hook children rendered');
32610 this.on('childrenrendered', function() {
32611 Roo.log('children rendered');
32618 initial : function()
32620 this.reloadItems();
32622 this.currentSize = this.el.getBox(true);
32624 /// was window resize... - let's see if this works..
32625 Roo.EventManager.onWindowResize(this.resize, this);
32627 if(!this.isAutoInitial){
32632 this.layout.defer(500,this);
32635 reloadItems: function()
32637 this.bricks = this.el.select('.masonry-brick', true);
32639 this.bricks.each(function(b) {
32640 //Roo.log(b.getSize());
32641 if (!b.attr('originalwidth')) {
32642 b.attr('originalwidth', b.getSize().width);
32647 Roo.log(this.bricks.elements.length);
32650 resize : function()
32653 var cs = this.el.getBox(true);
32655 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
32656 Roo.log("no change in with or X");
32659 this.currentSize = cs;
32663 layout : function()
32666 this._resetLayout();
32667 //this._manageStamps();
32669 // don't animate first layout
32670 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
32671 this.layoutItems( isInstant );
32673 // flag for initalized
32674 this._isLayoutInited = true;
32677 layoutItems : function( isInstant )
32679 //var items = this._getItemsForLayout( this.items );
32680 // original code supports filtering layout items.. we just ignore it..
32682 this._layoutItems( this.bricks , isInstant );
32684 this._postLayout();
32686 _layoutItems : function ( items , isInstant)
32688 //this.fireEvent( 'layout', this, items );
32691 if ( !items || !items.elements.length ) {
32692 // no items, emit event with empty array
32697 items.each(function(item) {
32698 Roo.log("layout item");
32700 // get x/y object from method
32701 var position = this._getItemLayoutPosition( item );
32703 position.item = item;
32704 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
32705 queue.push( position );
32708 this._processLayoutQueue( queue );
32710 /** Sets position of item in DOM
32711 * @param {Element} item
32712 * @param {Number} x - horizontal position
32713 * @param {Number} y - vertical position
32714 * @param {Boolean} isInstant - disables transitions
32716 _processLayoutQueue : function( queue )
32718 for ( var i=0, len = queue.length; i < len; i++ ) {
32719 var obj = queue[i];
32720 obj.item.position('absolute');
32721 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
32727 * Any logic you want to do after each layout,
32728 * i.e. size the container
32730 _postLayout : function()
32732 this.resizeContainer();
32735 resizeContainer : function()
32737 if ( !this.isResizingContainer ) {
32740 var size = this._getContainerSize();
32742 this.el.setSize(size.width,size.height);
32743 this.boxesEl.setSize(size.width,size.height);
32749 _resetLayout : function()
32751 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
32752 this.colWidth = this.el.getWidth();
32753 //this.gutter = this.el.getWidth();
32755 this.measureColumns();
32761 this.colYs.push( 0 );
32767 measureColumns : function()
32769 this.getContainerWidth();
32770 // if columnWidth is 0, default to outerWidth of first item
32771 if ( !this.columnWidth ) {
32772 var firstItem = this.bricks.first();
32773 Roo.log(firstItem);
32774 this.columnWidth = this.containerWidth;
32775 if (firstItem && firstItem.attr('originalwidth') ) {
32776 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
32778 // columnWidth fall back to item of first element
32779 Roo.log("set column width?");
32780 this.initialColumnWidth = this.columnWidth ;
32782 // if first elem has no width, default to size of container
32787 if (this.initialColumnWidth) {
32788 this.columnWidth = this.initialColumnWidth;
32793 // column width is fixed at the top - however if container width get's smaller we should
32796 // this bit calcs how man columns..
32798 var columnWidth = this.columnWidth += this.gutter;
32800 // calculate columns
32801 var containerWidth = this.containerWidth + this.gutter;
32803 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
32804 // fix rounding errors, typically with gutters
32805 var excess = columnWidth - containerWidth % columnWidth;
32808 // if overshoot is less than a pixel, round up, otherwise floor it
32809 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
32810 cols = Math[ mathMethod ]( cols );
32811 this.cols = Math.max( cols, 1 );
32812 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
32814 // padding positioning..
32815 var totalColWidth = this.cols * this.columnWidth;
32816 var padavail = this.containerWidth - totalColWidth;
32817 // so for 2 columns - we need 3 'pads'
32819 var padNeeded = (1+this.cols) * this.padWidth;
32821 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
32823 this.columnWidth += padExtra
32824 //this.padWidth = Math.floor(padavail / ( this.cols));
32826 // adjust colum width so that padding is fixed??
32828 // we have 3 columns ... total = width * 3
32829 // we have X left over... that should be used by
32831 //if (this.expandC) {
32839 getContainerWidth : function()
32841 /* // container is parent if fit width
32842 var container = this.isFitWidth ? this.element.parentNode : this.element;
32843 // check that this.size and size are there
32844 // IE8 triggers resize on body size change, so they might not be
32846 var size = getSize( container ); //FIXME
32847 this.containerWidth = size && size.innerWidth; //FIXME
32850 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
32854 _getItemLayoutPosition : function( item ) // what is item?
32856 // we resize the item to our columnWidth..
32858 item.setWidth(this.columnWidth);
32859 item.autoBoxAdjust = false;
32861 var sz = item.getSize();
32863 // how many columns does this brick span
32864 var remainder = this.containerWidth % this.columnWidth;
32866 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
32867 // round if off by 1 pixel, otherwise use ceil
32868 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
32869 colSpan = Math.min( colSpan, this.cols );
32871 // normally this should be '1' as we dont' currently allow multi width columns..
32873 var colGroup = this._getColGroup( colSpan );
32874 // get the minimum Y value from the columns
32875 var minimumY = Math.min.apply( Math, colGroup );
32876 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32878 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
32880 // position the brick
32882 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
32883 y: this.currentSize.y + minimumY + this.padHeight
32887 // apply setHeight to necessary columns
32888 var setHeight = minimumY + sz.height + this.padHeight;
32889 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32891 var setSpan = this.cols + 1 - colGroup.length;
32892 for ( var i = 0; i < setSpan; i++ ) {
32893 this.colYs[ shortColIndex + i ] = setHeight ;
32900 * @param {Number} colSpan - number of columns the element spans
32901 * @returns {Array} colGroup
32903 _getColGroup : function( colSpan )
32905 if ( colSpan < 2 ) {
32906 // if brick spans only one column, use all the column Ys
32911 // how many different places could this brick fit horizontally
32912 var groupCount = this.cols + 1 - colSpan;
32913 // for each group potential horizontal position
32914 for ( var i = 0; i < groupCount; i++ ) {
32915 // make an array of colY values for that one group
32916 var groupColYs = this.colYs.slice( i, i + colSpan );
32917 // and get the max value of the array
32918 colGroup[i] = Math.max.apply( Math, groupColYs );
32923 _manageStamp : function( stamp )
32925 var stampSize = stamp.getSize();
32926 var offset = stamp.getBox();
32927 // get the columns that this stamp affects
32928 var firstX = this.isOriginLeft ? offset.x : offset.right;
32929 var lastX = firstX + stampSize.width;
32930 var firstCol = Math.floor( firstX / this.columnWidth );
32931 firstCol = Math.max( 0, firstCol );
32933 var lastCol = Math.floor( lastX / this.columnWidth );
32934 // lastCol should not go over if multiple of columnWidth #425
32935 lastCol -= lastX % this.columnWidth ? 0 : 1;
32936 lastCol = Math.min( this.cols - 1, lastCol );
32938 // set colYs to bottom of the stamp
32939 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
32942 for ( var i = firstCol; i <= lastCol; i++ ) {
32943 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
32948 _getContainerSize : function()
32950 this.maxY = Math.max.apply( Math, this.colYs );
32955 if ( this.isFitWidth ) {
32956 size.width = this._getContainerFitWidth();
32962 _getContainerFitWidth : function()
32964 var unusedCols = 0;
32965 // count unused columns
32968 if ( this.colYs[i] !== 0 ) {
32973 // fit container to columns that have been used
32974 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
32977 needsResizeLayout : function()
32979 var previousWidth = this.containerWidth;
32980 this.getContainerWidth();
32981 return previousWidth !== this.containerWidth;
32996 * @class Roo.bootstrap.MasonryBrick
32997 * @extends Roo.bootstrap.Component
32998 * Bootstrap MasonryBrick class
33001 * Create a new MasonryBrick
33002 * @param {Object} config The config object
33005 Roo.bootstrap.MasonryBrick = function(config){
33007 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
33009 Roo.bootstrap.MasonryBrick.register(this);
33015 * When a MasonryBrick is clcik
33016 * @param {Roo.bootstrap.MasonryBrick} this
33017 * @param {Roo.EventObject} e
33023 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
33026 * @cfg {String} title
33030 * @cfg {String} html
33034 * @cfg {String} bgimage
33038 * @cfg {String} videourl
33042 * @cfg {String} cls
33046 * @cfg {String} href
33050 * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
33055 * @cfg {String} placetitle (center|bottom)
33060 * @cfg {Boolean} isFitContainer defalut true
33062 isFitContainer : true,
33065 * @cfg {Boolean} preventDefault defalut false
33067 preventDefault : false,
33070 * @cfg {Boolean} inverse defalut false
33072 maskInverse : false,
33074 getAutoCreate : function()
33076 if(!this.isFitContainer){
33077 return this.getSplitAutoCreate();
33080 var cls = 'masonry-brick masonry-brick-full';
33082 if(this.href.length){
33083 cls += ' masonry-brick-link';
33086 if(this.bgimage.length){
33087 cls += ' masonry-brick-image';
33090 if(this.maskInverse){
33091 cls += ' mask-inverse';
33094 if(!this.html.length && !this.maskInverse && !this.videourl.length){
33095 cls += ' enable-mask';
33099 cls += ' masonry-' + this.size + '-brick';
33102 if(this.placetitle.length){
33104 switch (this.placetitle) {
33106 cls += ' masonry-center-title';
33109 cls += ' masonry-bottom-title';
33116 if(!this.html.length && !this.bgimage.length){
33117 cls += ' masonry-center-title';
33120 if(!this.html.length && this.bgimage.length){
33121 cls += ' masonry-bottom-title';
33126 cls += ' ' + this.cls;
33130 tag: (this.href.length) ? 'a' : 'div',
33135 cls: 'masonry-brick-mask'
33139 cls: 'masonry-brick-paragraph',
33145 if(this.href.length){
33146 cfg.href = this.href;
33149 var cn = cfg.cn[1].cn;
33151 if(this.title.length){
33154 cls: 'masonry-brick-title',
33159 if(this.html.length){
33162 cls: 'masonry-brick-text',
33167 if (!this.title.length && !this.html.length) {
33168 cfg.cn[1].cls += ' hide';
33171 if(this.bgimage.length){
33174 cls: 'masonry-brick-image-view',
33179 if(this.videourl.length){
33180 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
33181 // youtube support only?
33184 cls: 'masonry-brick-image-view',
33187 allowfullscreen : true
33195 getSplitAutoCreate : function()
33197 var cls = 'masonry-brick masonry-brick-split';
33199 if(this.href.length){
33200 cls += ' masonry-brick-link';
33203 if(this.bgimage.length){
33204 cls += ' masonry-brick-image';
33208 cls += ' masonry-' + this.size + '-brick';
33211 switch (this.placetitle) {
33213 cls += ' masonry-center-title';
33216 cls += ' masonry-bottom-title';
33219 if(!this.bgimage.length){
33220 cls += ' masonry-center-title';
33223 if(this.bgimage.length){
33224 cls += ' masonry-bottom-title';
33230 cls += ' ' + this.cls;
33234 tag: (this.href.length) ? 'a' : 'div',
33239 cls: 'masonry-brick-split-head',
33243 cls: 'masonry-brick-paragraph',
33250 cls: 'masonry-brick-split-body',
33256 if(this.href.length){
33257 cfg.href = this.href;
33260 if(this.title.length){
33261 cfg.cn[0].cn[0].cn.push({
33263 cls: 'masonry-brick-title',
33268 if(this.html.length){
33269 cfg.cn[1].cn.push({
33271 cls: 'masonry-brick-text',
33276 if(this.bgimage.length){
33277 cfg.cn[0].cn.push({
33279 cls: 'masonry-brick-image-view',
33284 if(this.videourl.length){
33285 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
33286 // youtube support only?
33287 cfg.cn[0].cn.cn.push({
33289 cls: 'masonry-brick-image-view',
33292 allowfullscreen : true
33299 initEvents: function()
33301 switch (this.size) {
33334 this.el.on('touchstart', this.onTouchStart, this);
33335 this.el.on('touchmove', this.onTouchMove, this);
33336 this.el.on('touchend', this.onTouchEnd, this);
33337 this.el.on('contextmenu', this.onContextMenu, this);
33339 this.el.on('mouseenter' ,this.enter, this);
33340 this.el.on('mouseleave', this.leave, this);
33341 this.el.on('click', this.onClick, this);
33344 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
33345 this.parent().bricks.push(this);
33350 onClick: function(e, el)
33352 var time = this.endTimer - this.startTimer;
33353 // Roo.log(e.preventDefault());
33356 e.preventDefault();
33361 if(!this.preventDefault){
33365 e.preventDefault();
33367 if (this.activeClass != '') {
33368 this.selectBrick();
33371 this.fireEvent('click', this, e);
33374 enter: function(e, el)
33376 e.preventDefault();
33378 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
33382 if(this.bgimage.length && this.html.length){
33383 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
33387 leave: function(e, el)
33389 e.preventDefault();
33391 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
33395 if(this.bgimage.length && this.html.length){
33396 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
33400 onTouchStart: function(e, el)
33402 // e.preventDefault();
33404 this.touchmoved = false;
33406 if(!this.isFitContainer){
33410 if(!this.bgimage.length || !this.html.length){
33414 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
33416 this.timer = new Date().getTime();
33420 onTouchMove: function(e, el)
33422 this.touchmoved = true;
33425 onContextMenu : function(e,el)
33427 e.preventDefault();
33428 e.stopPropagation();
33432 onTouchEnd: function(e, el)
33434 // e.preventDefault();
33436 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
33443 if(!this.bgimage.length || !this.html.length){
33445 if(this.href.length){
33446 window.location.href = this.href;
33452 if(!this.isFitContainer){
33456 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
33458 window.location.href = this.href;
33461 //selection on single brick only
33462 selectBrick : function() {
33464 if (!this.parentId) {
33468 var m = Roo.bootstrap.LayoutMasonry.get(this.parentId);
33469 var index = m.selectedBrick.indexOf(this.id);
33472 m.selectedBrick.splice(index,1);
33473 this.el.removeClass(this.activeClass);
33477 for(var i = 0; i < m.selectedBrick.length; i++) {
33478 var b = Roo.bootstrap.MasonryBrick.get(m.selectedBrick[i]);
33479 b.el.removeClass(b.activeClass);
33482 m.selectedBrick = [];
33484 m.selectedBrick.push(this.id);
33485 this.el.addClass(this.activeClass);
33489 isSelected : function(){
33490 return this.el.hasClass(this.activeClass);
33495 Roo.apply(Roo.bootstrap.MasonryBrick, {
33498 groups : new Roo.util.MixedCollection(false, function(o) { return o.el.id; }),
33500 * register a Masonry Brick
33501 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
33504 register : function(brick)
33506 //this.groups[brick.id] = brick;
33507 this.groups.add(brick.id, brick);
33510 * fetch a masonry brick based on the masonry brick ID
33511 * @param {string} the masonry brick to add
33512 * @returns {Roo.bootstrap.MasonryBrick} the masonry brick
33515 get: function(brick_id)
33517 // if (typeof(this.groups[brick_id]) == 'undefined') {
33520 // return this.groups[brick_id] ;
33522 if(this.groups.key(brick_id)) {
33523 return this.groups.key(brick_id);
33541 * @class Roo.bootstrap.Brick
33542 * @extends Roo.bootstrap.Component
33543 * Bootstrap Brick class
33546 * Create a new Brick
33547 * @param {Object} config The config object
33550 Roo.bootstrap.Brick = function(config){
33551 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
33557 * When a Brick is click
33558 * @param {Roo.bootstrap.Brick} this
33559 * @param {Roo.EventObject} e
33565 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
33568 * @cfg {String} title
33572 * @cfg {String} html
33576 * @cfg {String} bgimage
33580 * @cfg {String} cls
33584 * @cfg {String} href
33588 * @cfg {String} video
33592 * @cfg {Boolean} square
33596 getAutoCreate : function()
33598 var cls = 'roo-brick';
33600 if(this.href.length){
33601 cls += ' roo-brick-link';
33604 if(this.bgimage.length){
33605 cls += ' roo-brick-image';
33608 if(!this.html.length && !this.bgimage.length){
33609 cls += ' roo-brick-center-title';
33612 if(!this.html.length && this.bgimage.length){
33613 cls += ' roo-brick-bottom-title';
33617 cls += ' ' + this.cls;
33621 tag: (this.href.length) ? 'a' : 'div',
33626 cls: 'roo-brick-paragraph',
33632 if(this.href.length){
33633 cfg.href = this.href;
33636 var cn = cfg.cn[0].cn;
33638 if(this.title.length){
33641 cls: 'roo-brick-title',
33646 if(this.html.length){
33649 cls: 'roo-brick-text',
33656 if(this.bgimage.length){
33659 cls: 'roo-brick-image-view',
33667 initEvents: function()
33669 if(this.title.length || this.html.length){
33670 this.el.on('mouseenter' ,this.enter, this);
33671 this.el.on('mouseleave', this.leave, this);
33674 Roo.EventManager.onWindowResize(this.resize, this);
33676 if(this.bgimage.length){
33677 this.imageEl = this.el.select('.roo-brick-image-view', true).first();
33678 this.imageEl.on('load', this.onImageLoad, this);
33685 onImageLoad : function()
33690 resize : function()
33692 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
33694 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
33696 if(this.bgimage.length){
33697 var image = this.el.select('.roo-brick-image-view', true).first();
33699 image.setWidth(paragraph.getWidth());
33702 image.setHeight(paragraph.getWidth());
33705 this.el.setHeight(image.getHeight());
33706 paragraph.setHeight(image.getHeight());
33712 enter: function(e, el)
33714 e.preventDefault();
33716 if(this.bgimage.length){
33717 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
33718 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
33722 leave: function(e, el)
33724 e.preventDefault();
33726 if(this.bgimage.length){
33727 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
33728 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
33743 * @class Roo.bootstrap.NumberField
33744 * @extends Roo.bootstrap.Input
33745 * Bootstrap NumberField class
33751 * Create a new NumberField
33752 * @param {Object} config The config object
33755 Roo.bootstrap.NumberField = function(config){
33756 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
33759 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
33762 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
33764 allowDecimals : true,
33766 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
33768 decimalSeparator : ".",
33770 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
33772 decimalPrecision : 2,
33774 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
33776 allowNegative : true,
33779 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
33783 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
33785 minValue : Number.NEGATIVE_INFINITY,
33787 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
33789 maxValue : Number.MAX_VALUE,
33791 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
33793 minText : "The minimum value for this field is {0}",
33795 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
33797 maxText : "The maximum value for this field is {0}",
33799 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
33800 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
33802 nanText : "{0} is not a valid number",
33804 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
33806 thousandsDelimiter : false,
33808 * @cfg {String} valueAlign alignment of value
33810 valueAlign : "left",
33812 getAutoCreate : function()
33814 var hiddenInput = {
33818 cls: 'hidden-number-input'
33822 hiddenInput.name = this.name;
33827 var cfg = Roo.bootstrap.NumberField.superclass.getAutoCreate.call(this);
33829 this.name = hiddenInput.name;
33831 if(cfg.cn.length > 0) {
33832 cfg.cn.push(hiddenInput);
33839 initEvents : function()
33841 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
33843 var allowed = "0123456789";
33845 if(this.allowDecimals){
33846 allowed += this.decimalSeparator;
33849 if(this.allowNegative){
33853 if(this.thousandsDelimiter) {
33857 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
33859 var keyPress = function(e){
33861 var k = e.getKey();
33863 var c = e.getCharCode();
33866 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
33867 allowed.indexOf(String.fromCharCode(c)) === -1
33873 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
33877 if(allowed.indexOf(String.fromCharCode(c)) === -1){
33882 this.el.on("keypress", keyPress, this);
33885 validateValue : function(value)
33888 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
33892 var num = this.parseValue(value);
33895 this.markInvalid(String.format(this.nanText, value));
33899 if(num < this.minValue){
33900 this.markInvalid(String.format(this.minText, this.minValue));
33904 if(num > this.maxValue){
33905 this.markInvalid(String.format(this.maxText, this.maxValue));
33912 getValue : function()
33914 var v = this.hiddenEl().getValue();
33916 return this.fixPrecision(this.parseValue(v));
33919 parseValue : function(value)
33921 if(this.thousandsDelimiter) {
33923 r = new RegExp(",", "g");
33924 value = value.replace(r, "");
33927 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
33928 return isNaN(value) ? '' : value;
33931 fixPrecision : function(value)
33933 if(this.thousandsDelimiter) {
33935 r = new RegExp(",", "g");
33936 value = value.replace(r, "");
33939 var nan = isNaN(value);
33941 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
33942 return nan ? '' : value;
33944 return parseFloat(value).toFixed(this.decimalPrecision);
33947 setValue : function(v)
33949 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
33955 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
33957 this.inputEl().dom.value = (v == '') ? '' :
33958 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
33960 if(!this.allowZero && v === '0') {
33961 this.hiddenEl().dom.value = '';
33962 this.inputEl().dom.value = '';
33969 decimalPrecisionFcn : function(v)
33971 return Math.floor(v);
33974 beforeBlur : function()
33976 var v = this.parseValue(this.getRawValue());
33978 if(v || v === 0 || v === ''){
33983 hiddenEl : function()
33985 return this.el.select('input.hidden-number-input',true).first();
33997 * @class Roo.bootstrap.DocumentSlider
33998 * @extends Roo.bootstrap.Component
33999 * Bootstrap DocumentSlider class
34002 * Create a new DocumentViewer
34003 * @param {Object} config The config object
34006 Roo.bootstrap.DocumentSlider = function(config){
34007 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
34014 * Fire after initEvent
34015 * @param {Roo.bootstrap.DocumentSlider} this
34020 * Fire after update
34021 * @param {Roo.bootstrap.DocumentSlider} this
34027 * @param {Roo.bootstrap.DocumentSlider} this
34033 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
34039 getAutoCreate : function()
34043 cls : 'roo-document-slider',
34047 cls : 'roo-document-slider-header',
34051 cls : 'roo-document-slider-header-title'
34057 cls : 'roo-document-slider-body',
34061 cls : 'roo-document-slider-prev',
34065 cls : 'fa fa-chevron-left'
34071 cls : 'roo-document-slider-thumb',
34075 cls : 'roo-document-slider-image'
34081 cls : 'roo-document-slider-next',
34085 cls : 'fa fa-chevron-right'
34097 initEvents : function()
34099 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
34100 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
34102 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
34103 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
34105 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
34106 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
34108 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
34109 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
34111 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
34112 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
34114 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
34115 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
34117 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
34118 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
34120 this.thumbEl.on('click', this.onClick, this);
34122 this.prevIndicator.on('click', this.prev, this);
34124 this.nextIndicator.on('click', this.next, this);
34128 initial : function()
34130 if(this.files.length){
34131 this.indicator = 1;
34135 this.fireEvent('initial', this);
34138 update : function()
34140 this.imageEl.attr('src', this.files[this.indicator - 1]);
34142 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
34144 this.prevIndicator.show();
34146 if(this.indicator == 1){
34147 this.prevIndicator.hide();
34150 this.nextIndicator.show();
34152 if(this.indicator == this.files.length){
34153 this.nextIndicator.hide();
34156 this.thumbEl.scrollTo('top');
34158 this.fireEvent('update', this);
34161 onClick : function(e)
34163 e.preventDefault();
34165 this.fireEvent('click', this);
34170 e.preventDefault();
34172 this.indicator = Math.max(1, this.indicator - 1);
34179 e.preventDefault();
34181 this.indicator = Math.min(this.files.length, this.indicator + 1);
34195 * @class Roo.bootstrap.RadioSet
34196 * @extends Roo.bootstrap.Input
34197 * Bootstrap RadioSet class
34198 * @cfg {String} indicatorpos (left|right) default left
34199 * @cfg {Boolean} inline (true|false) inline the element (default true)
34200 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
34202 * Create a new RadioSet
34203 * @param {Object} config The config object
34206 Roo.bootstrap.RadioSet = function(config){
34208 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
34212 Roo.bootstrap.RadioSet.register(this);
34217 * Fires when the element is checked or unchecked.
34218 * @param {Roo.bootstrap.RadioSet} this This radio
34219 * @param {Roo.bootstrap.Radio} item The checked item
34224 * Fires when the element is click.
34225 * @param {Roo.bootstrap.RadioSet} this This radio set
34226 * @param {Roo.bootstrap.Radio} item The checked item
34227 * @param {Roo.EventObject} e The event object
34234 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
34242 indicatorpos : 'left',
34244 getAutoCreate : function()
34248 cls : 'roo-radio-set-label',
34252 html : this.fieldLabel
34256 if (Roo.bootstrap.version == 3) {
34259 if(this.indicatorpos == 'left'){
34262 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
34263 tooltip : 'This field is required'
34268 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
34269 tooltip : 'This field is required'
34275 cls : 'roo-radio-set-items'
34278 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
34280 if (align === 'left' && this.fieldLabel.length) {
34283 cls : "roo-radio-set-right",
34289 if(this.labelWidth > 12){
34290 label.style = "width: " + this.labelWidth + 'px';
34293 if(this.labelWidth < 13 && this.labelmd == 0){
34294 this.labelmd = this.labelWidth;
34297 if(this.labellg > 0){
34298 label.cls += ' col-lg-' + this.labellg;
34299 items.cls += ' col-lg-' + (12 - this.labellg);
34302 if(this.labelmd > 0){
34303 label.cls += ' col-md-' + this.labelmd;
34304 items.cls += ' col-md-' + (12 - this.labelmd);
34307 if(this.labelsm > 0){
34308 label.cls += ' col-sm-' + this.labelsm;
34309 items.cls += ' col-sm-' + (12 - this.labelsm);
34312 if(this.labelxs > 0){
34313 label.cls += ' col-xs-' + this.labelxs;
34314 items.cls += ' col-xs-' + (12 - this.labelxs);
34320 cls : 'roo-radio-set',
34324 cls : 'roo-radio-set-input',
34327 value : this.value ? this.value : ''
34334 if(this.weight.length){
34335 cfg.cls += ' roo-radio-' + this.weight;
34339 cfg.cls += ' roo-radio-set-inline';
34343 ['xs','sm','md','lg'].map(function(size){
34344 if (settings[size]) {
34345 cfg.cls += ' col-' + size + '-' + settings[size];
34353 initEvents : function()
34355 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
34356 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
34358 if(!this.fieldLabel.length){
34359 this.labelEl.hide();
34362 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
34363 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
34365 this.indicator = this.indicatorEl();
34367 if(this.indicator){
34368 this.indicator.addClass('invisible');
34371 this.originalValue = this.getValue();
34375 inputEl: function ()
34377 return this.el.select('.roo-radio-set-input', true).first();
34380 getChildContainer : function()
34382 return this.itemsEl;
34385 register : function(item)
34387 this.radioes.push(item);
34391 validate : function()
34393 if(this.getVisibilityEl().hasClass('hidden')){
34399 Roo.each(this.radioes, function(i){
34408 if(this.allowBlank) {
34412 if(this.disabled || valid){
34417 this.markInvalid();
34422 markValid : function()
34424 if(this.labelEl.isVisible(true) && this.indicatorEl()){
34425 this.indicatorEl().removeClass('visible');
34426 this.indicatorEl().addClass('invisible');
34430 if (Roo.bootstrap.version == 3) {
34431 this.el.removeClass([this.invalidClass, this.validClass]);
34432 this.el.addClass(this.validClass);
34434 this.el.removeClass(['is-invalid','is-valid']);
34435 this.el.addClass(['is-valid']);
34437 this.fireEvent('valid', this);
34440 markInvalid : function(msg)
34442 if(this.allowBlank || this.disabled){
34446 if(this.labelEl.isVisible(true) && this.indicatorEl()){
34447 this.indicatorEl().removeClass('invisible');
34448 this.indicatorEl().addClass('visible');
34450 if (Roo.bootstrap.version == 3) {
34451 this.el.removeClass([this.invalidClass, this.validClass]);
34452 this.el.addClass(this.invalidClass);
34454 this.el.removeClass(['is-invalid','is-valid']);
34455 this.el.addClass(['is-invalid']);
34458 this.fireEvent('invalid', this, msg);
34462 setValue : function(v, suppressEvent)
34464 if(this.value === v){
34471 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
34474 Roo.each(this.radioes, function(i){
34476 i.el.removeClass('checked');
34479 Roo.each(this.radioes, function(i){
34481 if(i.value === v || i.value.toString() === v.toString()){
34483 i.el.addClass('checked');
34485 if(suppressEvent !== true){
34486 this.fireEvent('check', this, i);
34497 clearInvalid : function(){
34499 if(!this.el || this.preventMark){
34503 this.el.removeClass([this.invalidClass]);
34505 this.fireEvent('valid', this);
34510 Roo.apply(Roo.bootstrap.RadioSet, {
34514 register : function(set)
34516 this.groups[set.name] = set;
34519 get: function(name)
34521 if (typeof(this.groups[name]) == 'undefined') {
34525 return this.groups[name] ;
34531 * Ext JS Library 1.1.1
34532 * Copyright(c) 2006-2007, Ext JS, LLC.
34534 * Originally Released Under LGPL - original licence link has changed is not relivant.
34537 * <script type="text/javascript">
34542 * @class Roo.bootstrap.SplitBar
34543 * @extends Roo.util.Observable
34544 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
34548 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
34549 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
34550 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
34551 split.minSize = 100;
34552 split.maxSize = 600;
34553 split.animate = true;
34554 split.on('moved', splitterMoved);
34557 * Create a new SplitBar
34558 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
34559 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
34560 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34561 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
34562 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
34563 position of the SplitBar).
34565 Roo.bootstrap.SplitBar = function(cfg){
34570 // dragElement : elm
34571 // resizingElement: el,
34573 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
34574 // placement : Roo.bootstrap.SplitBar.LEFT ,
34575 // existingProxy ???
34578 this.el = Roo.get(cfg.dragElement, true);
34579 this.el.dom.unselectable = "on";
34581 this.resizingEl = Roo.get(cfg.resizingElement, true);
34585 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34586 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
34589 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
34592 * The minimum size of the resizing element. (Defaults to 0)
34598 * The maximum size of the resizing element. (Defaults to 2000)
34601 this.maxSize = 2000;
34604 * Whether to animate the transition to the new size
34607 this.animate = false;
34610 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
34613 this.useShim = false;
34618 if(!cfg.existingProxy){
34620 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
34622 this.proxy = Roo.get(cfg.existingProxy).dom;
34625 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
34628 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
34631 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
34634 this.dragSpecs = {};
34637 * @private The adapter to use to positon and resize elements
34639 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34640 this.adapter.init(this);
34642 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34644 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
34645 this.el.addClass("roo-splitbar-h");
34648 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
34649 this.el.addClass("roo-splitbar-v");
34655 * Fires when the splitter is moved (alias for {@link #event-moved})
34656 * @param {Roo.bootstrap.SplitBar} this
34657 * @param {Number} newSize the new width or height
34662 * Fires when the splitter is moved
34663 * @param {Roo.bootstrap.SplitBar} this
34664 * @param {Number} newSize the new width or height
34668 * @event beforeresize
34669 * Fires before the splitter is dragged
34670 * @param {Roo.bootstrap.SplitBar} this
34672 "beforeresize" : true,
34674 "beforeapply" : true
34677 Roo.util.Observable.call(this);
34680 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
34681 onStartProxyDrag : function(x, y){
34682 this.fireEvent("beforeresize", this);
34684 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
34686 o.enableDisplayMode("block");
34687 // all splitbars share the same overlay
34688 Roo.bootstrap.SplitBar.prototype.overlay = o;
34690 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
34691 this.overlay.show();
34692 Roo.get(this.proxy).setDisplayed("block");
34693 var size = this.adapter.getElementSize(this);
34694 this.activeMinSize = this.getMinimumSize();;
34695 this.activeMaxSize = this.getMaximumSize();;
34696 var c1 = size - this.activeMinSize;
34697 var c2 = Math.max(this.activeMaxSize - size, 0);
34698 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34699 this.dd.resetConstraints();
34700 this.dd.setXConstraint(
34701 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
34702 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
34704 this.dd.setYConstraint(0, 0);
34706 this.dd.resetConstraints();
34707 this.dd.setXConstraint(0, 0);
34708 this.dd.setYConstraint(
34709 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
34710 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
34713 this.dragSpecs.startSize = size;
34714 this.dragSpecs.startPoint = [x, y];
34715 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
34719 * @private Called after the drag operation by the DDProxy
34721 onEndProxyDrag : function(e){
34722 Roo.get(this.proxy).setDisplayed(false);
34723 var endPoint = Roo.lib.Event.getXY(e);
34725 this.overlay.hide();
34728 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34729 newSize = this.dragSpecs.startSize +
34730 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
34731 endPoint[0] - this.dragSpecs.startPoint[0] :
34732 this.dragSpecs.startPoint[0] - endPoint[0]
34735 newSize = this.dragSpecs.startSize +
34736 (this.placement == Roo.bootstrap.SplitBar.TOP ?
34737 endPoint[1] - this.dragSpecs.startPoint[1] :
34738 this.dragSpecs.startPoint[1] - endPoint[1]
34741 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
34742 if(newSize != this.dragSpecs.startSize){
34743 if(this.fireEvent('beforeapply', this, newSize) !== false){
34744 this.adapter.setElementSize(this, newSize);
34745 this.fireEvent("moved", this, newSize);
34746 this.fireEvent("resize", this, newSize);
34752 * Get the adapter this SplitBar uses
34753 * @return The adapter object
34755 getAdapter : function(){
34756 return this.adapter;
34760 * Set the adapter this SplitBar uses
34761 * @param {Object} adapter A SplitBar adapter object
34763 setAdapter : function(adapter){
34764 this.adapter = adapter;
34765 this.adapter.init(this);
34769 * Gets the minimum size for the resizing element
34770 * @return {Number} The minimum size
34772 getMinimumSize : function(){
34773 return this.minSize;
34777 * Sets the minimum size for the resizing element
34778 * @param {Number} minSize The minimum size
34780 setMinimumSize : function(minSize){
34781 this.minSize = minSize;
34785 * Gets the maximum size for the resizing element
34786 * @return {Number} The maximum size
34788 getMaximumSize : function(){
34789 return this.maxSize;
34793 * Sets the maximum size for the resizing element
34794 * @param {Number} maxSize The maximum size
34796 setMaximumSize : function(maxSize){
34797 this.maxSize = maxSize;
34801 * Sets the initialize size for the resizing element
34802 * @param {Number} size The initial size
34804 setCurrentSize : function(size){
34805 var oldAnimate = this.animate;
34806 this.animate = false;
34807 this.adapter.setElementSize(this, size);
34808 this.animate = oldAnimate;
34812 * Destroy this splitbar.
34813 * @param {Boolean} removeEl True to remove the element
34815 destroy : function(removeEl){
34817 this.shim.remove();
34820 this.proxy.parentNode.removeChild(this.proxy);
34828 * @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.
34830 Roo.bootstrap.SplitBar.createProxy = function(dir){
34831 var proxy = new Roo.Element(document.createElement("div"));
34832 proxy.unselectable();
34833 var cls = 'roo-splitbar-proxy';
34834 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
34835 document.body.appendChild(proxy.dom);
34840 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
34841 * Default Adapter. It assumes the splitter and resizing element are not positioned
34842 * elements and only gets/sets the width of the element. Generally used for table based layouts.
34844 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
34847 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
34848 // do nothing for now
34849 init : function(s){
34853 * Called before drag operations to get the current size of the resizing element.
34854 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34856 getElementSize : function(s){
34857 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34858 return s.resizingEl.getWidth();
34860 return s.resizingEl.getHeight();
34865 * Called after drag operations to set the size of the resizing element.
34866 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34867 * @param {Number} newSize The new size to set
34868 * @param {Function} onComplete A function to be invoked when resizing is complete
34870 setElementSize : function(s, newSize, onComplete){
34871 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34873 s.resizingEl.setWidth(newSize);
34875 onComplete(s, newSize);
34878 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
34883 s.resizingEl.setHeight(newSize);
34885 onComplete(s, newSize);
34888 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
34895 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
34896 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
34897 * Adapter that moves the splitter element to align with the resized sizing element.
34898 * Used with an absolute positioned SplitBar.
34899 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
34900 * document.body, make sure you assign an id to the body element.
34902 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
34903 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34904 this.container = Roo.get(container);
34907 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
34908 init : function(s){
34909 this.basic.init(s);
34912 getElementSize : function(s){
34913 return this.basic.getElementSize(s);
34916 setElementSize : function(s, newSize, onComplete){
34917 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
34920 moveSplitter : function(s){
34921 var yes = Roo.bootstrap.SplitBar;
34922 switch(s.placement){
34924 s.el.setX(s.resizingEl.getRight());
34927 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
34930 s.el.setY(s.resizingEl.getBottom());
34933 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
34940 * Orientation constant - Create a vertical SplitBar
34944 Roo.bootstrap.SplitBar.VERTICAL = 1;
34947 * Orientation constant - Create a horizontal SplitBar
34951 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
34954 * Placement constant - The resizing element is to the left of the splitter element
34958 Roo.bootstrap.SplitBar.LEFT = 1;
34961 * Placement constant - The resizing element is to the right of the splitter element
34965 Roo.bootstrap.SplitBar.RIGHT = 2;
34968 * Placement constant - The resizing element is positioned above the splitter element
34972 Roo.bootstrap.SplitBar.TOP = 3;
34975 * Placement constant - The resizing element is positioned under splitter element
34979 Roo.bootstrap.SplitBar.BOTTOM = 4;
34980 Roo.namespace("Roo.bootstrap.layout");/*
34982 * Ext JS Library 1.1.1
34983 * Copyright(c) 2006-2007, Ext JS, LLC.
34985 * Originally Released Under LGPL - original licence link has changed is not relivant.
34988 * <script type="text/javascript">
34992 * @class Roo.bootstrap.layout.Manager
34993 * @extends Roo.bootstrap.Component
34994 * Base class for layout managers.
34996 Roo.bootstrap.layout.Manager = function(config)
34998 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
35004 /** false to disable window resize monitoring @type Boolean */
35005 this.monitorWindowResize = true;
35010 * Fires when a layout is performed.
35011 * @param {Roo.LayoutManager} this
35015 * @event regionresized
35016 * Fires when the user resizes a region.
35017 * @param {Roo.LayoutRegion} region The resized region
35018 * @param {Number} newSize The new size (width for east/west, height for north/south)
35020 "regionresized" : true,
35022 * @event regioncollapsed
35023 * Fires when a region is collapsed.
35024 * @param {Roo.LayoutRegion} region The collapsed region
35026 "regioncollapsed" : true,
35028 * @event regionexpanded
35029 * Fires when a region is expanded.
35030 * @param {Roo.LayoutRegion} region The expanded region
35032 "regionexpanded" : true
35034 this.updating = false;
35037 this.el = Roo.get(config.el);
35043 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
35048 monitorWindowResize : true,
35054 onRender : function(ct, position)
35057 this.el = Roo.get(ct);
35060 //this.fireEvent('render',this);
35064 initEvents: function()
35068 // ie scrollbar fix
35069 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
35070 document.body.scroll = "no";
35071 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
35072 this.el.position('relative');
35074 this.id = this.el.id;
35075 this.el.addClass("roo-layout-container");
35076 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
35077 if(this.el.dom != document.body ) {
35078 this.el.on('resize', this.layout,this);
35079 this.el.on('show', this.layout,this);
35085 * Returns true if this layout is currently being updated
35086 * @return {Boolean}
35088 isUpdating : function(){
35089 return this.updating;
35093 * Suspend the LayoutManager from doing auto-layouts while
35094 * making multiple add or remove calls
35096 beginUpdate : function(){
35097 this.updating = true;
35101 * Restore auto-layouts and optionally disable the manager from performing a layout
35102 * @param {Boolean} noLayout true to disable a layout update
35104 endUpdate : function(noLayout){
35105 this.updating = false;
35111 layout: function(){
35115 onRegionResized : function(region, newSize){
35116 this.fireEvent("regionresized", region, newSize);
35120 onRegionCollapsed : function(region){
35121 this.fireEvent("regioncollapsed", region);
35124 onRegionExpanded : function(region){
35125 this.fireEvent("regionexpanded", region);
35129 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
35130 * performs box-model adjustments.
35131 * @return {Object} The size as an object {width: (the width), height: (the height)}
35133 getViewSize : function()
35136 if(this.el.dom != document.body){
35137 size = this.el.getSize();
35139 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
35141 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
35142 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
35147 * Returns the Element this layout is bound to.
35148 * @return {Roo.Element}
35150 getEl : function(){
35155 * Returns the specified region.
35156 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
35157 * @return {Roo.LayoutRegion}
35159 getRegion : function(target){
35160 return this.regions[target.toLowerCase()];
35163 onWindowResize : function(){
35164 if(this.monitorWindowResize){
35171 * Ext JS Library 1.1.1
35172 * Copyright(c) 2006-2007, Ext JS, LLC.
35174 * Originally Released Under LGPL - original licence link has changed is not relivant.
35177 * <script type="text/javascript">
35180 * @class Roo.bootstrap.layout.Border
35181 * @extends Roo.bootstrap.layout.Manager
35182 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
35183 * please see: examples/bootstrap/nested.html<br><br>
35185 <b>The container the layout is rendered into can be either the body element or any other element.
35186 If it is not the body element, the container needs to either be an absolute positioned element,
35187 or you will need to add "position:relative" to the css of the container. You will also need to specify
35188 the container size if it is not the body element.</b>
35191 * Create a new Border
35192 * @param {Object} config Configuration options
35194 Roo.bootstrap.layout.Border = function(config){
35195 config = config || {};
35196 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
35200 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
35201 if(config[region]){
35202 config[region].region = region;
35203 this.addRegion(config[region]);
35209 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
35211 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
35213 parent : false, // this might point to a 'nest' or a ???
35216 * Creates and adds a new region if it doesn't already exist.
35217 * @param {String} target The target region key (north, south, east, west or center).
35218 * @param {Object} config The regions config object
35219 * @return {BorderLayoutRegion} The new region
35221 addRegion : function(config)
35223 if(!this.regions[config.region]){
35224 var r = this.factory(config);
35225 this.bindRegion(r);
35227 return this.regions[config.region];
35231 bindRegion : function(r){
35232 this.regions[r.config.region] = r;
35234 r.on("visibilitychange", this.layout, this);
35235 r.on("paneladded", this.layout, this);
35236 r.on("panelremoved", this.layout, this);
35237 r.on("invalidated", this.layout, this);
35238 r.on("resized", this.onRegionResized, this);
35239 r.on("collapsed", this.onRegionCollapsed, this);
35240 r.on("expanded", this.onRegionExpanded, this);
35244 * Performs a layout update.
35246 layout : function()
35248 if(this.updating) {
35252 // render all the rebions if they have not been done alreayd?
35253 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
35254 if(this.regions[region] && !this.regions[region].bodyEl){
35255 this.regions[region].onRender(this.el)
35259 var size = this.getViewSize();
35260 var w = size.width;
35261 var h = size.height;
35266 //var x = 0, y = 0;
35268 var rs = this.regions;
35269 var north = rs["north"];
35270 var south = rs["south"];
35271 var west = rs["west"];
35272 var east = rs["east"];
35273 var center = rs["center"];
35274 //if(this.hideOnLayout){ // not supported anymore
35275 //c.el.setStyle("display", "none");
35277 if(north && north.isVisible()){
35278 var b = north.getBox();
35279 var m = north.getMargins();
35280 b.width = w - (m.left+m.right);
35283 centerY = b.height + b.y + m.bottom;
35284 centerH -= centerY;
35285 north.updateBox(this.safeBox(b));
35287 if(south && south.isVisible()){
35288 var b = south.getBox();
35289 var m = south.getMargins();
35290 b.width = w - (m.left+m.right);
35292 var totalHeight = (b.height + m.top + m.bottom);
35293 b.y = h - totalHeight + m.top;
35294 centerH -= totalHeight;
35295 south.updateBox(this.safeBox(b));
35297 if(west && west.isVisible()){
35298 var b = west.getBox();
35299 var m = west.getMargins();
35300 b.height = centerH - (m.top+m.bottom);
35302 b.y = centerY + m.top;
35303 var totalWidth = (b.width + m.left + m.right);
35304 centerX += totalWidth;
35305 centerW -= totalWidth;
35306 west.updateBox(this.safeBox(b));
35308 if(east && east.isVisible()){
35309 var b = east.getBox();
35310 var m = east.getMargins();
35311 b.height = centerH - (m.top+m.bottom);
35312 var totalWidth = (b.width + m.left + m.right);
35313 b.x = w - totalWidth + m.left;
35314 b.y = centerY + m.top;
35315 centerW -= totalWidth;
35316 east.updateBox(this.safeBox(b));
35319 var m = center.getMargins();
35321 x: centerX + m.left,
35322 y: centerY + m.top,
35323 width: centerW - (m.left+m.right),
35324 height: centerH - (m.top+m.bottom)
35326 //if(this.hideOnLayout){
35327 //center.el.setStyle("display", "block");
35329 center.updateBox(this.safeBox(centerBox));
35332 this.fireEvent("layout", this);
35336 safeBox : function(box){
35337 box.width = Math.max(0, box.width);
35338 box.height = Math.max(0, box.height);
35343 * Adds a ContentPanel (or subclass) to this layout.
35344 * @param {String} target The target region key (north, south, east, west or center).
35345 * @param {Roo.ContentPanel} panel The panel to add
35346 * @return {Roo.ContentPanel} The added panel
35348 add : function(target, panel){
35350 target = target.toLowerCase();
35351 return this.regions[target].add(panel);
35355 * Remove a ContentPanel (or subclass) to this layout.
35356 * @param {String} target The target region key (north, south, east, west or center).
35357 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
35358 * @return {Roo.ContentPanel} The removed panel
35360 remove : function(target, panel){
35361 target = target.toLowerCase();
35362 return this.regions[target].remove(panel);
35366 * Searches all regions for a panel with the specified id
35367 * @param {String} panelId
35368 * @return {Roo.ContentPanel} The panel or null if it wasn't found
35370 findPanel : function(panelId){
35371 var rs = this.regions;
35372 for(var target in rs){
35373 if(typeof rs[target] != "function"){
35374 var p = rs[target].getPanel(panelId);
35384 * Searches all regions for a panel with the specified id and activates (shows) it.
35385 * @param {String/ContentPanel} panelId The panels id or the panel itself
35386 * @return {Roo.ContentPanel} The shown panel or null
35388 showPanel : function(panelId) {
35389 var rs = this.regions;
35390 for(var target in rs){
35391 var r = rs[target];
35392 if(typeof r != "function"){
35393 if(r.hasPanel(panelId)){
35394 return r.showPanel(panelId);
35402 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
35403 * @param {Roo.state.Provider} provider (optional) An alternate state provider
35406 restoreState : function(provider){
35408 provider = Roo.state.Manager;
35410 var sm = new Roo.LayoutStateManager();
35411 sm.init(this, provider);
35417 * Adds a xtype elements to the layout.
35421 xtype : 'ContentPanel',
35428 xtype : 'NestedLayoutPanel',
35434 items : [ ... list of content panels or nested layout panels.. ]
35438 * @param {Object} cfg Xtype definition of item to add.
35440 addxtype : function(cfg)
35442 // basically accepts a pannel...
35443 // can accept a layout region..!?!?
35444 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
35447 // theory? children can only be panels??
35449 //if (!cfg.xtype.match(/Panel$/)) {
35454 if (typeof(cfg.region) == 'undefined') {
35455 Roo.log("Failed to add Panel, region was not set");
35459 var region = cfg.region;
35465 xitems = cfg.items;
35470 if ( region == 'center') {
35471 Roo.log("Center: " + cfg.title);
35477 case 'Content': // ContentPanel (el, cfg)
35478 case 'Scroll': // ContentPanel (el, cfg)
35480 cfg.autoCreate = cfg.autoCreate || true;
35481 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35483 // var el = this.el.createChild();
35484 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
35487 this.add(region, ret);
35491 case 'TreePanel': // our new panel!
35492 cfg.el = this.el.createChild();
35493 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
35494 this.add(region, ret);
35499 // create a new Layout (which is a Border Layout...
35501 var clayout = cfg.layout;
35502 clayout.el = this.el.createChild();
35503 clayout.items = clayout.items || [];
35507 // replace this exitems with the clayout ones..
35508 xitems = clayout.items;
35510 // force background off if it's in center...
35511 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
35512 cfg.background = false;
35514 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
35517 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35518 //console.log('adding nested layout panel ' + cfg.toSource());
35519 this.add(region, ret);
35520 nb = {}; /// find first...
35525 // needs grid and region
35527 //var el = this.getRegion(region).el.createChild();
35529 *var el = this.el.createChild();
35530 // create the grid first...
35531 cfg.grid.container = el;
35532 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
35535 if (region == 'center' && this.active ) {
35536 cfg.background = false;
35539 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35541 this.add(region, ret);
35543 if (cfg.background) {
35544 // render grid on panel activation (if panel background)
35545 ret.on('activate', function(gp) {
35546 if (!gp.grid.rendered) {
35547 // gp.grid.render(el);
35551 // cfg.grid.render(el);
35557 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
35558 // it was the old xcomponent building that caused this before.
35559 // espeically if border is the top element in the tree.
35569 if (typeof(Roo[cfg.xtype]) != 'undefined') {
35571 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
35572 this.add(region, ret);
35576 throw "Can not add '" + cfg.xtype + "' to Border";
35582 this.beginUpdate();
35586 Roo.each(xitems, function(i) {
35587 region = nb && i.region ? i.region : false;
35589 var add = ret.addxtype(i);
35592 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
35593 if (!i.background) {
35594 abn[region] = nb[region] ;
35601 // make the last non-background panel active..
35602 //if (nb) { Roo.log(abn); }
35605 for(var r in abn) {
35606 region = this.getRegion(r);
35608 // tried using nb[r], but it does not work..
35610 region.showPanel(abn[r]);
35621 factory : function(cfg)
35624 var validRegions = Roo.bootstrap.layout.Border.regions;
35626 var target = cfg.region;
35629 var r = Roo.bootstrap.layout;
35633 return new r.North(cfg);
35635 return new r.South(cfg);
35637 return new r.East(cfg);
35639 return new r.West(cfg);
35641 return new r.Center(cfg);
35643 throw 'Layout region "'+target+'" not supported.';
35650 * Ext JS Library 1.1.1
35651 * Copyright(c) 2006-2007, Ext JS, LLC.
35653 * Originally Released Under LGPL - original licence link has changed is not relivant.
35656 * <script type="text/javascript">
35660 * @class Roo.bootstrap.layout.Basic
35661 * @extends Roo.util.Observable
35662 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
35663 * and does not have a titlebar, tabs or any other features. All it does is size and position
35664 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
35665 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35666 * @cfg {string} region the region that it inhabits..
35667 * @cfg {bool} skipConfig skip config?
35671 Roo.bootstrap.layout.Basic = function(config){
35673 this.mgr = config.mgr;
35675 this.position = config.region;
35677 var skipConfig = config.skipConfig;
35681 * @scope Roo.BasicLayoutRegion
35685 * @event beforeremove
35686 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
35687 * @param {Roo.LayoutRegion} this
35688 * @param {Roo.ContentPanel} panel The panel
35689 * @param {Object} e The cancel event object
35691 "beforeremove" : true,
35693 * @event invalidated
35694 * Fires when the layout for this region is changed.
35695 * @param {Roo.LayoutRegion} this
35697 "invalidated" : true,
35699 * @event visibilitychange
35700 * Fires when this region is shown or hidden
35701 * @param {Roo.LayoutRegion} this
35702 * @param {Boolean} visibility true or false
35704 "visibilitychange" : true,
35706 * @event paneladded
35707 * Fires when a panel is added.
35708 * @param {Roo.LayoutRegion} this
35709 * @param {Roo.ContentPanel} panel The panel
35711 "paneladded" : true,
35713 * @event panelremoved
35714 * Fires when a panel is removed.
35715 * @param {Roo.LayoutRegion} this
35716 * @param {Roo.ContentPanel} panel The panel
35718 "panelremoved" : true,
35720 * @event beforecollapse
35721 * Fires when this region before collapse.
35722 * @param {Roo.LayoutRegion} this
35724 "beforecollapse" : true,
35727 * Fires when this region is collapsed.
35728 * @param {Roo.LayoutRegion} this
35730 "collapsed" : true,
35733 * Fires when this region is expanded.
35734 * @param {Roo.LayoutRegion} this
35739 * Fires when this region is slid into view.
35740 * @param {Roo.LayoutRegion} this
35742 "slideshow" : true,
35745 * Fires when this region slides out of view.
35746 * @param {Roo.LayoutRegion} this
35748 "slidehide" : true,
35750 * @event panelactivated
35751 * Fires when a panel is activated.
35752 * @param {Roo.LayoutRegion} this
35753 * @param {Roo.ContentPanel} panel The activated panel
35755 "panelactivated" : true,
35758 * Fires when the user resizes this region.
35759 * @param {Roo.LayoutRegion} this
35760 * @param {Number} newSize The new size (width for east/west, height for north/south)
35764 /** A collection of panels in this region. @type Roo.util.MixedCollection */
35765 this.panels = new Roo.util.MixedCollection();
35766 this.panels.getKey = this.getPanelId.createDelegate(this);
35768 this.activePanel = null;
35769 // ensure listeners are added...
35771 if (config.listeners || config.events) {
35772 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
35773 listeners : config.listeners || {},
35774 events : config.events || {}
35778 if(skipConfig !== true){
35779 this.applyConfig(config);
35783 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
35785 getPanelId : function(p){
35789 applyConfig : function(config){
35790 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35791 this.config = config;
35796 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
35797 * the width, for horizontal (north, south) the height.
35798 * @param {Number} newSize The new width or height
35800 resizeTo : function(newSize){
35801 var el = this.el ? this.el :
35802 (this.activePanel ? this.activePanel.getEl() : null);
35804 switch(this.position){
35807 el.setWidth(newSize);
35808 this.fireEvent("resized", this, newSize);
35812 el.setHeight(newSize);
35813 this.fireEvent("resized", this, newSize);
35819 getBox : function(){
35820 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
35823 getMargins : function(){
35824 return this.margins;
35827 updateBox : function(box){
35829 var el = this.activePanel.getEl();
35830 el.dom.style.left = box.x + "px";
35831 el.dom.style.top = box.y + "px";
35832 this.activePanel.setSize(box.width, box.height);
35836 * Returns the container element for this region.
35837 * @return {Roo.Element}
35839 getEl : function(){
35840 return this.activePanel;
35844 * Returns true if this region is currently visible.
35845 * @return {Boolean}
35847 isVisible : function(){
35848 return this.activePanel ? true : false;
35851 setActivePanel : function(panel){
35852 panel = this.getPanel(panel);
35853 if(this.activePanel && this.activePanel != panel){
35854 this.activePanel.setActiveState(false);
35855 this.activePanel.getEl().setLeftTop(-10000,-10000);
35857 this.activePanel = panel;
35858 panel.setActiveState(true);
35860 panel.setSize(this.box.width, this.box.height);
35862 this.fireEvent("panelactivated", this, panel);
35863 this.fireEvent("invalidated");
35867 * Show the specified panel.
35868 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
35869 * @return {Roo.ContentPanel} The shown panel or null
35871 showPanel : function(panel){
35872 panel = this.getPanel(panel);
35874 this.setActivePanel(panel);
35880 * Get the active panel for this region.
35881 * @return {Roo.ContentPanel} The active panel or null
35883 getActivePanel : function(){
35884 return this.activePanel;
35888 * Add the passed ContentPanel(s)
35889 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35890 * @return {Roo.ContentPanel} The panel added (if only one was added)
35892 add : function(panel){
35893 if(arguments.length > 1){
35894 for(var i = 0, len = arguments.length; i < len; i++) {
35895 this.add(arguments[i]);
35899 if(this.hasPanel(panel)){
35900 this.showPanel(panel);
35903 var el = panel.getEl();
35904 if(el.dom.parentNode != this.mgr.el.dom){
35905 this.mgr.el.dom.appendChild(el.dom);
35907 if(panel.setRegion){
35908 panel.setRegion(this);
35910 this.panels.add(panel);
35911 el.setStyle("position", "absolute");
35912 if(!panel.background){
35913 this.setActivePanel(panel);
35914 if(this.config.initialSize && this.panels.getCount()==1){
35915 this.resizeTo(this.config.initialSize);
35918 this.fireEvent("paneladded", this, panel);
35923 * Returns true if the panel is in this region.
35924 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35925 * @return {Boolean}
35927 hasPanel : function(panel){
35928 if(typeof panel == "object"){ // must be panel obj
35929 panel = panel.getId();
35931 return this.getPanel(panel) ? true : false;
35935 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35936 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35937 * @param {Boolean} preservePanel Overrides the config preservePanel option
35938 * @return {Roo.ContentPanel} The panel that was removed
35940 remove : function(panel, preservePanel){
35941 panel = this.getPanel(panel);
35946 this.fireEvent("beforeremove", this, panel, e);
35947 if(e.cancel === true){
35950 var panelId = panel.getId();
35951 this.panels.removeKey(panelId);
35956 * Returns the panel specified or null if it's not in this region.
35957 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35958 * @return {Roo.ContentPanel}
35960 getPanel : function(id){
35961 if(typeof id == "object"){ // must be panel obj
35964 return this.panels.get(id);
35968 * Returns this regions position (north/south/east/west/center).
35971 getPosition: function(){
35972 return this.position;
35976 * Ext JS Library 1.1.1
35977 * Copyright(c) 2006-2007, Ext JS, LLC.
35979 * Originally Released Under LGPL - original licence link has changed is not relivant.
35982 * <script type="text/javascript">
35986 * @class Roo.bootstrap.layout.Region
35987 * @extends Roo.bootstrap.layout.Basic
35988 * This class represents a region in a layout manager.
35990 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
35991 * @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})
35992 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
35993 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
35994 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
35995 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
35996 * @cfg {String} title The title for the region (overrides panel titles)
35997 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
35998 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
35999 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
36000 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
36001 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
36002 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
36003 * the space available, similar to FireFox 1.5 tabs (defaults to false)
36004 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
36005 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
36006 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
36008 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
36009 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
36010 * @cfg {Boolean} disableTabTips True to disable tab tooltips
36011 * @cfg {Number} width For East/West panels
36012 * @cfg {Number} height For North/South panels
36013 * @cfg {Boolean} split To show the splitter
36014 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
36016 * @cfg {string} cls Extra CSS classes to add to region
36018 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
36019 * @cfg {string} region the region that it inhabits..
36022 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
36023 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
36025 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
36026 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
36027 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
36029 Roo.bootstrap.layout.Region = function(config)
36031 this.applyConfig(config);
36033 var mgr = config.mgr;
36034 var pos = config.region;
36035 config.skipConfig = true;
36036 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
36039 this.onRender(mgr.el);
36042 this.visible = true;
36043 this.collapsed = false;
36044 this.unrendered_panels = [];
36047 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
36049 position: '', // set by wrapper (eg. north/south etc..)
36050 unrendered_panels : null, // unrendered panels.
36052 tabPosition : false,
36054 mgr: false, // points to 'Border'
36057 createBody : function(){
36058 /** This region's body element
36059 * @type Roo.Element */
36060 this.bodyEl = this.el.createChild({
36062 cls: "roo-layout-panel-body tab-content" // bootstrap added...
36066 onRender: function(ctr, pos)
36068 var dh = Roo.DomHelper;
36069 /** This region's container element
36070 * @type Roo.Element */
36071 this.el = dh.append(ctr.dom, {
36073 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
36075 /** This region's title element
36076 * @type Roo.Element */
36078 this.titleEl = dh.append(this.el.dom, {
36080 unselectable: "on",
36081 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
36083 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
36084 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
36088 this.titleEl.enableDisplayMode();
36089 /** This region's title text element
36090 * @type HTMLElement */
36091 this.titleTextEl = this.titleEl.dom.firstChild;
36092 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
36094 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
36095 this.closeBtn.enableDisplayMode();
36096 this.closeBtn.on("click", this.closeClicked, this);
36097 this.closeBtn.hide();
36099 this.createBody(this.config);
36100 if(this.config.hideWhenEmpty){
36102 this.on("paneladded", this.validateVisibility, this);
36103 this.on("panelremoved", this.validateVisibility, this);
36105 if(this.autoScroll){
36106 this.bodyEl.setStyle("overflow", "auto");
36108 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
36110 //if(c.titlebar !== false){
36111 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
36112 this.titleEl.hide();
36114 this.titleEl.show();
36115 if(this.config.title){
36116 this.titleTextEl.innerHTML = this.config.title;
36120 if(this.config.collapsed){
36121 this.collapse(true);
36123 if(this.config.hidden){
36127 if (this.unrendered_panels && this.unrendered_panels.length) {
36128 for (var i =0;i< this.unrendered_panels.length; i++) {
36129 this.add(this.unrendered_panels[i]);
36131 this.unrendered_panels = null;
36137 applyConfig : function(c)
36140 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
36141 var dh = Roo.DomHelper;
36142 if(c.titlebar !== false){
36143 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
36144 this.collapseBtn.on("click", this.collapse, this);
36145 this.collapseBtn.enableDisplayMode();
36147 if(c.showPin === true || this.showPin){
36148 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
36149 this.stickBtn.enableDisplayMode();
36150 this.stickBtn.on("click", this.expand, this);
36151 this.stickBtn.hide();
36156 /** This region's collapsed element
36157 * @type Roo.Element */
36160 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
36161 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
36164 if(c.floatable !== false){
36165 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
36166 this.collapsedEl.on("click", this.collapseClick, this);
36169 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
36170 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
36171 id: "message", unselectable: "on", style:{"float":"left"}});
36172 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
36174 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
36175 this.expandBtn.on("click", this.expand, this);
36179 if(this.collapseBtn){
36180 this.collapseBtn.setVisible(c.collapsible == true);
36183 this.cmargins = c.cmargins || this.cmargins ||
36184 (this.position == "west" || this.position == "east" ?
36185 {top: 0, left: 2, right:2, bottom: 0} :
36186 {top: 2, left: 0, right:0, bottom: 2});
36188 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
36191 this.tabPosition = [ 'top','bottom', 'west'].indexOf(c.tabPosition) > -1 ? c.tabPosition : "top";
36193 this.autoScroll = c.autoScroll || false;
36198 this.duration = c.duration || .30;
36199 this.slideDuration = c.slideDuration || .45;
36204 * Returns true if this region is currently visible.
36205 * @return {Boolean}
36207 isVisible : function(){
36208 return this.visible;
36212 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
36213 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
36215 //setCollapsedTitle : function(title){
36216 // title = title || " ";
36217 // if(this.collapsedTitleTextEl){
36218 // this.collapsedTitleTextEl.innerHTML = title;
36222 getBox : function(){
36224 // if(!this.collapsed){
36225 b = this.el.getBox(false, true);
36227 // b = this.collapsedEl.getBox(false, true);
36232 getMargins : function(){
36233 return this.margins;
36234 //return this.collapsed ? this.cmargins : this.margins;
36237 highlight : function(){
36238 this.el.addClass("x-layout-panel-dragover");
36241 unhighlight : function(){
36242 this.el.removeClass("x-layout-panel-dragover");
36245 updateBox : function(box)
36247 if (!this.bodyEl) {
36248 return; // not rendered yet..
36252 if(!this.collapsed){
36253 this.el.dom.style.left = box.x + "px";
36254 this.el.dom.style.top = box.y + "px";
36255 this.updateBody(box.width, box.height);
36257 this.collapsedEl.dom.style.left = box.x + "px";
36258 this.collapsedEl.dom.style.top = box.y + "px";
36259 this.collapsedEl.setSize(box.width, box.height);
36262 this.tabs.autoSizeTabs();
36266 updateBody : function(w, h)
36269 this.el.setWidth(w);
36270 w -= this.el.getBorderWidth("rl");
36271 if(this.config.adjustments){
36272 w += this.config.adjustments[0];
36275 if(h !== null && h > 0){
36276 this.el.setHeight(h);
36277 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
36278 h -= this.el.getBorderWidth("tb");
36279 if(this.config.adjustments){
36280 h += this.config.adjustments[1];
36282 this.bodyEl.setHeight(h);
36284 h = this.tabs.syncHeight(h);
36287 if(this.panelSize){
36288 w = w !== null ? w : this.panelSize.width;
36289 h = h !== null ? h : this.panelSize.height;
36291 if(this.activePanel){
36292 var el = this.activePanel.getEl();
36293 w = w !== null ? w : el.getWidth();
36294 h = h !== null ? h : el.getHeight();
36295 this.panelSize = {width: w, height: h};
36296 this.activePanel.setSize(w, h);
36298 if(Roo.isIE && this.tabs){
36299 this.tabs.el.repaint();
36304 * Returns the container element for this region.
36305 * @return {Roo.Element}
36307 getEl : function(){
36312 * Hides this region.
36315 //if(!this.collapsed){
36316 this.el.dom.style.left = "-2000px";
36319 // this.collapsedEl.dom.style.left = "-2000px";
36320 // this.collapsedEl.hide();
36322 this.visible = false;
36323 this.fireEvent("visibilitychange", this, false);
36327 * Shows this region if it was previously hidden.
36330 //if(!this.collapsed){
36333 // this.collapsedEl.show();
36335 this.visible = true;
36336 this.fireEvent("visibilitychange", this, true);
36339 closeClicked : function(){
36340 if(this.activePanel){
36341 this.remove(this.activePanel);
36345 collapseClick : function(e){
36347 e.stopPropagation();
36350 e.stopPropagation();
36356 * Collapses this region.
36357 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
36360 collapse : function(skipAnim, skipCheck = false){
36361 if(this.collapsed) {
36365 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
36367 this.collapsed = true;
36369 this.split.el.hide();
36371 if(this.config.animate && skipAnim !== true){
36372 this.fireEvent("invalidated", this);
36373 this.animateCollapse();
36375 this.el.setLocation(-20000,-20000);
36377 this.collapsedEl.show();
36378 this.fireEvent("collapsed", this);
36379 this.fireEvent("invalidated", this);
36385 animateCollapse : function(){
36390 * Expands this region if it was previously collapsed.
36391 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
36392 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
36395 expand : function(e, skipAnim){
36397 e.stopPropagation();
36399 if(!this.collapsed || this.el.hasActiveFx()) {
36403 this.afterSlideIn();
36406 this.collapsed = false;
36407 if(this.config.animate && skipAnim !== true){
36408 this.animateExpand();
36412 this.split.el.show();
36414 this.collapsedEl.setLocation(-2000,-2000);
36415 this.collapsedEl.hide();
36416 this.fireEvent("invalidated", this);
36417 this.fireEvent("expanded", this);
36421 animateExpand : function(){
36425 initTabs : function()
36427 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
36429 var ts = new Roo.bootstrap.panel.Tabs({
36430 el: this.bodyEl.dom,
36432 tabPosition: this.tabPosition ? this.tabPosition : 'top',
36433 disableTooltips: this.config.disableTabTips,
36434 toolbar : this.config.toolbar
36437 if(this.config.hideTabs){
36438 ts.stripWrap.setDisplayed(false);
36441 ts.resizeTabs = this.config.resizeTabs === true;
36442 ts.minTabWidth = this.config.minTabWidth || 40;
36443 ts.maxTabWidth = this.config.maxTabWidth || 250;
36444 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
36445 ts.monitorResize = false;
36446 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
36447 ts.bodyEl.addClass('roo-layout-tabs-body');
36448 this.panels.each(this.initPanelAsTab, this);
36451 initPanelAsTab : function(panel){
36452 var ti = this.tabs.addTab(
36456 this.config.closeOnTab && panel.isClosable(),
36459 if(panel.tabTip !== undefined){
36460 ti.setTooltip(panel.tabTip);
36462 ti.on("activate", function(){
36463 this.setActivePanel(panel);
36466 if(this.config.closeOnTab){
36467 ti.on("beforeclose", function(t, e){
36469 this.remove(panel);
36473 panel.tabItem = ti;
36478 updatePanelTitle : function(panel, title)
36480 if(this.activePanel == panel){
36481 this.updateTitle(title);
36484 var ti = this.tabs.getTab(panel.getEl().id);
36486 if(panel.tabTip !== undefined){
36487 ti.setTooltip(panel.tabTip);
36492 updateTitle : function(title){
36493 if(this.titleTextEl && !this.config.title){
36494 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
36498 setActivePanel : function(panel)
36500 panel = this.getPanel(panel);
36501 if(this.activePanel && this.activePanel != panel){
36502 if(this.activePanel.setActiveState(false) === false){
36506 this.activePanel = panel;
36507 panel.setActiveState(true);
36508 if(this.panelSize){
36509 panel.setSize(this.panelSize.width, this.panelSize.height);
36512 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
36514 this.updateTitle(panel.getTitle());
36516 this.fireEvent("invalidated", this);
36518 this.fireEvent("panelactivated", this, panel);
36522 * Shows the specified panel.
36523 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
36524 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
36526 showPanel : function(panel)
36528 panel = this.getPanel(panel);
36531 var tab = this.tabs.getTab(panel.getEl().id);
36532 if(tab.isHidden()){
36533 this.tabs.unhideTab(tab.id);
36537 this.setActivePanel(panel);
36544 * Get the active panel for this region.
36545 * @return {Roo.ContentPanel} The active panel or null
36547 getActivePanel : function(){
36548 return this.activePanel;
36551 validateVisibility : function(){
36552 if(this.panels.getCount() < 1){
36553 this.updateTitle(" ");
36554 this.closeBtn.hide();
36557 if(!this.isVisible()){
36564 * Adds the passed ContentPanel(s) to this region.
36565 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
36566 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
36568 add : function(panel)
36570 if(arguments.length > 1){
36571 for(var i = 0, len = arguments.length; i < len; i++) {
36572 this.add(arguments[i]);
36577 // if we have not been rendered yet, then we can not really do much of this..
36578 if (!this.bodyEl) {
36579 this.unrendered_panels.push(panel);
36586 if(this.hasPanel(panel)){
36587 this.showPanel(panel);
36590 panel.setRegion(this);
36591 this.panels.add(panel);
36592 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
36593 // sinle panel - no tab...?? would it not be better to render it with the tabs,
36594 // and hide them... ???
36595 this.bodyEl.dom.appendChild(panel.getEl().dom);
36596 if(panel.background !== true){
36597 this.setActivePanel(panel);
36599 this.fireEvent("paneladded", this, panel);
36606 this.initPanelAsTab(panel);
36610 if(panel.background !== true){
36611 this.tabs.activate(panel.getEl().id);
36613 this.fireEvent("paneladded", this, panel);
36618 * Hides the tab for the specified panel.
36619 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36621 hidePanel : function(panel){
36622 if(this.tabs && (panel = this.getPanel(panel))){
36623 this.tabs.hideTab(panel.getEl().id);
36628 * Unhides the tab for a previously hidden panel.
36629 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36631 unhidePanel : function(panel){
36632 if(this.tabs && (panel = this.getPanel(panel))){
36633 this.tabs.unhideTab(panel.getEl().id);
36637 clearPanels : function(){
36638 while(this.panels.getCount() > 0){
36639 this.remove(this.panels.first());
36644 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
36645 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36646 * @param {Boolean} preservePanel Overrides the config preservePanel option
36647 * @return {Roo.ContentPanel} The panel that was removed
36649 remove : function(panel, preservePanel)
36651 panel = this.getPanel(panel);
36656 this.fireEvent("beforeremove", this, panel, e);
36657 if(e.cancel === true){
36660 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
36661 var panelId = panel.getId();
36662 this.panels.removeKey(panelId);
36664 document.body.appendChild(panel.getEl().dom);
36667 this.tabs.removeTab(panel.getEl().id);
36668 }else if (!preservePanel){
36669 this.bodyEl.dom.removeChild(panel.getEl().dom);
36671 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
36672 var p = this.panels.first();
36673 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
36674 tempEl.appendChild(p.getEl().dom);
36675 this.bodyEl.update("");
36676 this.bodyEl.dom.appendChild(p.getEl().dom);
36678 this.updateTitle(p.getTitle());
36680 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
36681 this.setActivePanel(p);
36683 panel.setRegion(null);
36684 if(this.activePanel == panel){
36685 this.activePanel = null;
36687 if(this.config.autoDestroy !== false && preservePanel !== true){
36688 try{panel.destroy();}catch(e){}
36690 this.fireEvent("panelremoved", this, panel);
36695 * Returns the TabPanel component used by this region
36696 * @return {Roo.TabPanel}
36698 getTabs : function(){
36702 createTool : function(parentEl, className){
36703 var btn = Roo.DomHelper.append(parentEl, {
36705 cls: "x-layout-tools-button",
36708 cls: "roo-layout-tools-button-inner " + className,
36712 btn.addClassOnOver("roo-layout-tools-button-over");
36717 * Ext JS Library 1.1.1
36718 * Copyright(c) 2006-2007, Ext JS, LLC.
36720 * Originally Released Under LGPL - original licence link has changed is not relivant.
36723 * <script type="text/javascript">
36729 * @class Roo.SplitLayoutRegion
36730 * @extends Roo.LayoutRegion
36731 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
36733 Roo.bootstrap.layout.Split = function(config){
36734 this.cursor = config.cursor;
36735 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
36738 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
36740 splitTip : "Drag to resize.",
36741 collapsibleSplitTip : "Drag to resize. Double click to hide.",
36742 useSplitTips : false,
36744 applyConfig : function(config){
36745 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
36748 onRender : function(ctr,pos) {
36750 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
36751 if(!this.config.split){
36756 var splitEl = Roo.DomHelper.append(ctr.dom, {
36758 id: this.el.id + "-split",
36759 cls: "roo-layout-split roo-layout-split-"+this.position,
36762 /** The SplitBar for this region
36763 * @type Roo.SplitBar */
36764 // does not exist yet...
36765 Roo.log([this.position, this.orientation]);
36767 this.split = new Roo.bootstrap.SplitBar({
36768 dragElement : splitEl,
36769 resizingElement: this.el,
36770 orientation : this.orientation
36773 this.split.on("moved", this.onSplitMove, this);
36774 this.split.useShim = this.config.useShim === true;
36775 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
36776 if(this.useSplitTips){
36777 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
36779 //if(config.collapsible){
36780 // this.split.el.on("dblclick", this.collapse, this);
36783 if(typeof this.config.minSize != "undefined"){
36784 this.split.minSize = this.config.minSize;
36786 if(typeof this.config.maxSize != "undefined"){
36787 this.split.maxSize = this.config.maxSize;
36789 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
36790 this.hideSplitter();
36795 getHMaxSize : function(){
36796 var cmax = this.config.maxSize || 10000;
36797 var center = this.mgr.getRegion("center");
36798 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
36801 getVMaxSize : function(){
36802 var cmax = this.config.maxSize || 10000;
36803 var center = this.mgr.getRegion("center");
36804 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
36807 onSplitMove : function(split, newSize){
36808 this.fireEvent("resized", this, newSize);
36812 * Returns the {@link Roo.SplitBar} for this region.
36813 * @return {Roo.SplitBar}
36815 getSplitBar : function(){
36820 this.hideSplitter();
36821 Roo.bootstrap.layout.Split.superclass.hide.call(this);
36824 hideSplitter : function(){
36826 this.split.el.setLocation(-2000,-2000);
36827 this.split.el.hide();
36833 this.split.el.show();
36835 Roo.bootstrap.layout.Split.superclass.show.call(this);
36838 beforeSlide: function(){
36839 if(Roo.isGecko){// firefox overflow auto bug workaround
36840 this.bodyEl.clip();
36842 this.tabs.bodyEl.clip();
36844 if(this.activePanel){
36845 this.activePanel.getEl().clip();
36847 if(this.activePanel.beforeSlide){
36848 this.activePanel.beforeSlide();
36854 afterSlide : function(){
36855 if(Roo.isGecko){// firefox overflow auto bug workaround
36856 this.bodyEl.unclip();
36858 this.tabs.bodyEl.unclip();
36860 if(this.activePanel){
36861 this.activePanel.getEl().unclip();
36862 if(this.activePanel.afterSlide){
36863 this.activePanel.afterSlide();
36869 initAutoHide : function(){
36870 if(this.autoHide !== false){
36871 if(!this.autoHideHd){
36872 var st = new Roo.util.DelayedTask(this.slideIn, this);
36873 this.autoHideHd = {
36874 "mouseout": function(e){
36875 if(!e.within(this.el, true)){
36879 "mouseover" : function(e){
36885 this.el.on(this.autoHideHd);
36889 clearAutoHide : function(){
36890 if(this.autoHide !== false){
36891 this.el.un("mouseout", this.autoHideHd.mouseout);
36892 this.el.un("mouseover", this.autoHideHd.mouseover);
36896 clearMonitor : function(){
36897 Roo.get(document).un("click", this.slideInIf, this);
36900 // these names are backwards but not changed for compat
36901 slideOut : function(){
36902 if(this.isSlid || this.el.hasActiveFx()){
36905 this.isSlid = true;
36906 if(this.collapseBtn){
36907 this.collapseBtn.hide();
36909 this.closeBtnState = this.closeBtn.getStyle('display');
36910 this.closeBtn.hide();
36912 this.stickBtn.show();
36915 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
36916 this.beforeSlide();
36917 this.el.setStyle("z-index", 10001);
36918 this.el.slideIn(this.getSlideAnchor(), {
36919 callback: function(){
36921 this.initAutoHide();
36922 Roo.get(document).on("click", this.slideInIf, this);
36923 this.fireEvent("slideshow", this);
36930 afterSlideIn : function(){
36931 this.clearAutoHide();
36932 this.isSlid = false;
36933 this.clearMonitor();
36934 this.el.setStyle("z-index", "");
36935 if(this.collapseBtn){
36936 this.collapseBtn.show();
36938 this.closeBtn.setStyle('display', this.closeBtnState);
36940 this.stickBtn.hide();
36942 this.fireEvent("slidehide", this);
36945 slideIn : function(cb){
36946 if(!this.isSlid || this.el.hasActiveFx()){
36950 this.isSlid = false;
36951 this.beforeSlide();
36952 this.el.slideOut(this.getSlideAnchor(), {
36953 callback: function(){
36954 this.el.setLeftTop(-10000, -10000);
36956 this.afterSlideIn();
36964 slideInIf : function(e){
36965 if(!e.within(this.el)){
36970 animateCollapse : function(){
36971 this.beforeSlide();
36972 this.el.setStyle("z-index", 20000);
36973 var anchor = this.getSlideAnchor();
36974 this.el.slideOut(anchor, {
36975 callback : function(){
36976 this.el.setStyle("z-index", "");
36977 this.collapsedEl.slideIn(anchor, {duration:.3});
36979 this.el.setLocation(-10000,-10000);
36981 this.fireEvent("collapsed", this);
36988 animateExpand : function(){
36989 this.beforeSlide();
36990 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
36991 this.el.setStyle("z-index", 20000);
36992 this.collapsedEl.hide({
36995 this.el.slideIn(this.getSlideAnchor(), {
36996 callback : function(){
36997 this.el.setStyle("z-index", "");
37000 this.split.el.show();
37002 this.fireEvent("invalidated", this);
37003 this.fireEvent("expanded", this);
37031 getAnchor : function(){
37032 return this.anchors[this.position];
37035 getCollapseAnchor : function(){
37036 return this.canchors[this.position];
37039 getSlideAnchor : function(){
37040 return this.sanchors[this.position];
37043 getAlignAdj : function(){
37044 var cm = this.cmargins;
37045 switch(this.position){
37061 getExpandAdj : function(){
37062 var c = this.collapsedEl, cm = this.cmargins;
37063 switch(this.position){
37065 return [-(cm.right+c.getWidth()+cm.left), 0];
37068 return [cm.right+c.getWidth()+cm.left, 0];
37071 return [0, -(cm.top+cm.bottom+c.getHeight())];
37074 return [0, cm.top+cm.bottom+c.getHeight()];
37080 * Ext JS Library 1.1.1
37081 * Copyright(c) 2006-2007, Ext JS, LLC.
37083 * Originally Released Under LGPL - original licence link has changed is not relivant.
37086 * <script type="text/javascript">
37089 * These classes are private internal classes
37091 Roo.bootstrap.layout.Center = function(config){
37092 config.region = "center";
37093 Roo.bootstrap.layout.Region.call(this, config);
37094 this.visible = true;
37095 this.minWidth = config.minWidth || 20;
37096 this.minHeight = config.minHeight || 20;
37099 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
37101 // center panel can't be hidden
37105 // center panel can't be hidden
37108 getMinWidth: function(){
37109 return this.minWidth;
37112 getMinHeight: function(){
37113 return this.minHeight;
37127 Roo.bootstrap.layout.North = function(config)
37129 config.region = 'north';
37130 config.cursor = 'n-resize';
37132 Roo.bootstrap.layout.Split.call(this, config);
37136 this.split.placement = Roo.bootstrap.SplitBar.TOP;
37137 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
37138 this.split.el.addClass("roo-layout-split-v");
37140 var size = config.initialSize || config.height;
37141 if(typeof size != "undefined"){
37142 this.el.setHeight(size);
37145 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
37147 orientation: Roo.bootstrap.SplitBar.VERTICAL,
37151 getBox : function(){
37152 if(this.collapsed){
37153 return this.collapsedEl.getBox();
37155 var box = this.el.getBox();
37157 box.height += this.split.el.getHeight();
37162 updateBox : function(box){
37163 if(this.split && !this.collapsed){
37164 box.height -= this.split.el.getHeight();
37165 this.split.el.setLeft(box.x);
37166 this.split.el.setTop(box.y+box.height);
37167 this.split.el.setWidth(box.width);
37169 if(this.collapsed){
37170 this.updateBody(box.width, null);
37172 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37180 Roo.bootstrap.layout.South = function(config){
37181 config.region = 'south';
37182 config.cursor = 's-resize';
37183 Roo.bootstrap.layout.Split.call(this, config);
37185 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
37186 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
37187 this.split.el.addClass("roo-layout-split-v");
37189 var size = config.initialSize || config.height;
37190 if(typeof size != "undefined"){
37191 this.el.setHeight(size);
37195 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
37196 orientation: Roo.bootstrap.SplitBar.VERTICAL,
37197 getBox : function(){
37198 if(this.collapsed){
37199 return this.collapsedEl.getBox();
37201 var box = this.el.getBox();
37203 var sh = this.split.el.getHeight();
37210 updateBox : function(box){
37211 if(this.split && !this.collapsed){
37212 var sh = this.split.el.getHeight();
37215 this.split.el.setLeft(box.x);
37216 this.split.el.setTop(box.y-sh);
37217 this.split.el.setWidth(box.width);
37219 if(this.collapsed){
37220 this.updateBody(box.width, null);
37222 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37226 Roo.bootstrap.layout.East = function(config){
37227 config.region = "east";
37228 config.cursor = "e-resize";
37229 Roo.bootstrap.layout.Split.call(this, config);
37231 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
37232 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
37233 this.split.el.addClass("roo-layout-split-h");
37235 var size = config.initialSize || config.width;
37236 if(typeof size != "undefined"){
37237 this.el.setWidth(size);
37240 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
37241 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
37242 getBox : function(){
37243 if(this.collapsed){
37244 return this.collapsedEl.getBox();
37246 var box = this.el.getBox();
37248 var sw = this.split.el.getWidth();
37255 updateBox : function(box){
37256 if(this.split && !this.collapsed){
37257 var sw = this.split.el.getWidth();
37259 this.split.el.setLeft(box.x);
37260 this.split.el.setTop(box.y);
37261 this.split.el.setHeight(box.height);
37264 if(this.collapsed){
37265 this.updateBody(null, box.height);
37267 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37271 Roo.bootstrap.layout.West = function(config){
37272 config.region = "west";
37273 config.cursor = "w-resize";
37275 Roo.bootstrap.layout.Split.call(this, config);
37277 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
37278 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
37279 this.split.el.addClass("roo-layout-split-h");
37283 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
37284 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
37286 onRender: function(ctr, pos)
37288 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
37289 var size = this.config.initialSize || this.config.width;
37290 if(typeof size != "undefined"){
37291 this.el.setWidth(size);
37295 getBox : function(){
37296 if(this.collapsed){
37297 return this.collapsedEl.getBox();
37299 var box = this.el.getBox();
37301 box.width += this.split.el.getWidth();
37306 updateBox : function(box){
37307 if(this.split && !this.collapsed){
37308 var sw = this.split.el.getWidth();
37310 this.split.el.setLeft(box.x+box.width);
37311 this.split.el.setTop(box.y);
37312 this.split.el.setHeight(box.height);
37314 if(this.collapsed){
37315 this.updateBody(null, box.height);
37317 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37319 });Roo.namespace("Roo.bootstrap.panel");/*
37321 * Ext JS Library 1.1.1
37322 * Copyright(c) 2006-2007, Ext JS, LLC.
37324 * Originally Released Under LGPL - original licence link has changed is not relivant.
37327 * <script type="text/javascript">
37330 * @class Roo.ContentPanel
37331 * @extends Roo.util.Observable
37332 * A basic ContentPanel element.
37333 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
37334 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
37335 * @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
37336 * @cfg {Boolean} closable True if the panel can be closed/removed
37337 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
37338 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
37339 * @cfg {Toolbar} toolbar A toolbar for this panel
37340 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
37341 * @cfg {String} title The title for this panel
37342 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
37343 * @cfg {String} url Calls {@link #setUrl} with this value
37344 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
37345 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
37346 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
37347 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
37348 * @cfg {Boolean} badges render the badges
37351 * Create a new ContentPanel.
37352 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
37353 * @param {String/Object} config A string to set only the title or a config object
37354 * @param {String} content (optional) Set the HTML content for this panel
37355 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
37357 Roo.bootstrap.panel.Content = function( config){
37359 this.tpl = config.tpl || false;
37361 var el = config.el;
37362 var content = config.content;
37364 if(config.autoCreate){ // xtype is available if this is called from factory
37367 this.el = Roo.get(el);
37368 if(!this.el && config && config.autoCreate){
37369 if(typeof config.autoCreate == "object"){
37370 if(!config.autoCreate.id){
37371 config.autoCreate.id = config.id||el;
37373 this.el = Roo.DomHelper.append(document.body,
37374 config.autoCreate, true);
37376 var elcfg = { tag: "div",
37377 cls: "roo-layout-inactive-content",
37381 elcfg.html = config.html;
37385 this.el = Roo.DomHelper.append(document.body, elcfg , true);
37388 this.closable = false;
37389 this.loaded = false;
37390 this.active = false;
37393 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
37395 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
37397 this.wrapEl = this.el; //this.el.wrap();
37399 if (config.toolbar.items) {
37400 ti = config.toolbar.items ;
37401 delete config.toolbar.items ;
37405 this.toolbar.render(this.wrapEl, 'before');
37406 for(var i =0;i < ti.length;i++) {
37407 // Roo.log(['add child', items[i]]);
37408 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37410 this.toolbar.items = nitems;
37411 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
37412 delete config.toolbar;
37416 // xtype created footer. - not sure if will work as we normally have to render first..
37417 if (this.footer && !this.footer.el && this.footer.xtype) {
37418 if (!this.wrapEl) {
37419 this.wrapEl = this.el.wrap();
37422 this.footer.container = this.wrapEl.createChild();
37424 this.footer = Roo.factory(this.footer, Roo);
37429 if(typeof config == "string"){
37430 this.title = config;
37432 Roo.apply(this, config);
37436 this.resizeEl = Roo.get(this.resizeEl, true);
37438 this.resizeEl = this.el;
37440 // handle view.xtype
37448 * Fires when this panel is activated.
37449 * @param {Roo.ContentPanel} this
37453 * @event deactivate
37454 * Fires when this panel is activated.
37455 * @param {Roo.ContentPanel} this
37457 "deactivate" : true,
37461 * Fires when this panel is resized if fitToFrame is true.
37462 * @param {Roo.ContentPanel} this
37463 * @param {Number} width The width after any component adjustments
37464 * @param {Number} height The height after any component adjustments
37470 * Fires when this tab is created
37471 * @param {Roo.ContentPanel} this
37482 if(this.autoScroll){
37483 this.resizeEl.setStyle("overflow", "auto");
37485 // fix randome scrolling
37486 //this.el.on('scroll', function() {
37487 // Roo.log('fix random scolling');
37488 // this.scrollTo('top',0);
37491 content = content || this.content;
37493 this.setContent(content);
37495 if(config && config.url){
37496 this.setUrl(this.url, this.params, this.loadOnce);
37501 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
37503 if (this.view && typeof(this.view.xtype) != 'undefined') {
37504 this.view.el = this.el.appendChild(document.createElement("div"));
37505 this.view = Roo.factory(this.view);
37506 this.view.render && this.view.render(false, '');
37510 this.fireEvent('render', this);
37513 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
37517 setRegion : function(region){
37518 this.region = region;
37519 this.setActiveClass(region && !this.background);
37523 setActiveClass: function(state)
37526 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
37527 this.el.setStyle('position','relative');
37529 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
37530 this.el.setStyle('position', 'absolute');
37535 * Returns the toolbar for this Panel if one was configured.
37536 * @return {Roo.Toolbar}
37538 getToolbar : function(){
37539 return this.toolbar;
37542 setActiveState : function(active)
37544 this.active = active;
37545 this.setActiveClass(active);
37547 if(this.fireEvent("deactivate", this) === false){
37552 this.fireEvent("activate", this);
37556 * Updates this panel's element
37557 * @param {String} content The new content
37558 * @param {Boolean} loadScripts (optional) true to look for and process scripts
37560 setContent : function(content, loadScripts){
37561 this.el.update(content, loadScripts);
37564 ignoreResize : function(w, h){
37565 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
37568 this.lastSize = {width: w, height: h};
37573 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
37574 * @return {Roo.UpdateManager} The UpdateManager
37576 getUpdateManager : function(){
37577 return this.el.getUpdateManager();
37580 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
37581 * @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:
37584 url: "your-url.php",
37585 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
37586 callback: yourFunction,
37587 scope: yourObject, //(optional scope)
37590 text: "Loading...",
37595 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
37596 * 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.
37597 * @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}
37598 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
37599 * @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.
37600 * @return {Roo.ContentPanel} this
37603 var um = this.el.getUpdateManager();
37604 um.update.apply(um, arguments);
37610 * 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.
37611 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
37612 * @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)
37613 * @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)
37614 * @return {Roo.UpdateManager} The UpdateManager
37616 setUrl : function(url, params, loadOnce){
37617 if(this.refreshDelegate){
37618 this.removeListener("activate", this.refreshDelegate);
37620 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
37621 this.on("activate", this.refreshDelegate);
37622 return this.el.getUpdateManager();
37625 _handleRefresh : function(url, params, loadOnce){
37626 if(!loadOnce || !this.loaded){
37627 var updater = this.el.getUpdateManager();
37628 updater.update(url, params, this._setLoaded.createDelegate(this));
37632 _setLoaded : function(){
37633 this.loaded = true;
37637 * Returns this panel's id
37640 getId : function(){
37645 * Returns this panel's element - used by regiosn to add.
37646 * @return {Roo.Element}
37648 getEl : function(){
37649 return this.wrapEl || this.el;
37654 adjustForComponents : function(width, height)
37656 //Roo.log('adjustForComponents ');
37657 if(this.resizeEl != this.el){
37658 width -= this.el.getFrameWidth('lr');
37659 height -= this.el.getFrameWidth('tb');
37662 var te = this.toolbar.getEl();
37663 te.setWidth(width);
37664 height -= te.getHeight();
37667 var te = this.footer.getEl();
37668 te.setWidth(width);
37669 height -= te.getHeight();
37673 if(this.adjustments){
37674 width += this.adjustments[0];
37675 height += this.adjustments[1];
37677 return {"width": width, "height": height};
37680 setSize : function(width, height){
37681 if(this.fitToFrame && !this.ignoreResize(width, height)){
37682 if(this.fitContainer && this.resizeEl != this.el){
37683 this.el.setSize(width, height);
37685 var size = this.adjustForComponents(width, height);
37686 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
37687 this.fireEvent('resize', this, size.width, size.height);
37692 * Returns this panel's title
37695 getTitle : function(){
37697 if (typeof(this.title) != 'object') {
37702 for (var k in this.title) {
37703 if (!this.title.hasOwnProperty(k)) {
37707 if (k.indexOf('-') >= 0) {
37708 var s = k.split('-');
37709 for (var i = 0; i<s.length; i++) {
37710 t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
37713 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
37720 * Set this panel's title
37721 * @param {String} title
37723 setTitle : function(title){
37724 this.title = title;
37726 this.region.updatePanelTitle(this, title);
37731 * Returns true is this panel was configured to be closable
37732 * @return {Boolean}
37734 isClosable : function(){
37735 return this.closable;
37738 beforeSlide : function(){
37740 this.resizeEl.clip();
37743 afterSlide : function(){
37745 this.resizeEl.unclip();
37749 * Force a content refresh from the URL specified in the {@link #setUrl} method.
37750 * Will fail silently if the {@link #setUrl} method has not been called.
37751 * This does not activate the panel, just updates its content.
37753 refresh : function(){
37754 if(this.refreshDelegate){
37755 this.loaded = false;
37756 this.refreshDelegate();
37761 * Destroys this panel
37763 destroy : function(){
37764 this.el.removeAllListeners();
37765 var tempEl = document.createElement("span");
37766 tempEl.appendChild(this.el.dom);
37767 tempEl.innerHTML = "";
37773 * form - if the content panel contains a form - this is a reference to it.
37774 * @type {Roo.form.Form}
37778 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
37779 * This contains a reference to it.
37785 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
37795 * @param {Object} cfg Xtype definition of item to add.
37799 getChildContainer: function () {
37800 return this.getEl();
37805 var ret = new Roo.factory(cfg);
37810 if (cfg.xtype.match(/^Form$/)) {
37813 //if (this.footer) {
37814 // el = this.footer.container.insertSibling(false, 'before');
37816 el = this.el.createChild();
37819 this.form = new Roo.form.Form(cfg);
37822 if ( this.form.allItems.length) {
37823 this.form.render(el.dom);
37827 // should only have one of theses..
37828 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
37829 // views.. should not be just added - used named prop 'view''
37831 cfg.el = this.el.appendChild(document.createElement("div"));
37834 var ret = new Roo.factory(cfg);
37836 ret.render && ret.render(false, ''); // render blank..
37846 * @class Roo.bootstrap.panel.Grid
37847 * @extends Roo.bootstrap.panel.Content
37849 * Create a new GridPanel.
37850 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
37851 * @param {Object} config A the config object
37857 Roo.bootstrap.panel.Grid = function(config)
37861 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
37862 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
37864 config.el = this.wrapper;
37865 //this.el = this.wrapper;
37867 if (config.container) {
37868 // ctor'ed from a Border/panel.grid
37871 this.wrapper.setStyle("overflow", "hidden");
37872 this.wrapper.addClass('roo-grid-container');
37877 if(config.toolbar){
37878 var tool_el = this.wrapper.createChild();
37879 this.toolbar = Roo.factory(config.toolbar);
37881 if (config.toolbar.items) {
37882 ti = config.toolbar.items ;
37883 delete config.toolbar.items ;
37887 this.toolbar.render(tool_el);
37888 for(var i =0;i < ti.length;i++) {
37889 // Roo.log(['add child', items[i]]);
37890 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37892 this.toolbar.items = nitems;
37894 delete config.toolbar;
37897 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
37898 config.grid.scrollBody = true;;
37899 config.grid.monitorWindowResize = false; // turn off autosizing
37900 config.grid.autoHeight = false;
37901 config.grid.autoWidth = false;
37903 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
37905 if (config.background) {
37906 // render grid on panel activation (if panel background)
37907 this.on('activate', function(gp) {
37908 if (!gp.grid.rendered) {
37909 gp.grid.render(this.wrapper);
37910 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37915 this.grid.render(this.wrapper);
37916 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37919 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
37920 // ??? needed ??? config.el = this.wrapper;
37925 // xtype created footer. - not sure if will work as we normally have to render first..
37926 if (this.footer && !this.footer.el && this.footer.xtype) {
37928 var ctr = this.grid.getView().getFooterPanel(true);
37929 this.footer.dataSource = this.grid.dataSource;
37930 this.footer = Roo.factory(this.footer, Roo);
37931 this.footer.render(ctr);
37941 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
37942 getId : function(){
37943 return this.grid.id;
37947 * Returns the grid for this panel
37948 * @return {Roo.bootstrap.Table}
37950 getGrid : function(){
37954 setSize : function(width, height){
37955 if(!this.ignoreResize(width, height)){
37956 var grid = this.grid;
37957 var size = this.adjustForComponents(width, height);
37958 var gridel = grid.getGridEl();
37959 gridel.setSize(size.width, size.height);
37961 var thd = grid.getGridEl().select('thead',true).first();
37962 var tbd = grid.getGridEl().select('tbody', true).first();
37964 tbd.setSize(width, height - thd.getHeight());
37973 beforeSlide : function(){
37974 this.grid.getView().scroller.clip();
37977 afterSlide : function(){
37978 this.grid.getView().scroller.unclip();
37981 destroy : function(){
37982 this.grid.destroy();
37984 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
37989 * @class Roo.bootstrap.panel.Nest
37990 * @extends Roo.bootstrap.panel.Content
37992 * Create a new Panel, that can contain a layout.Border.
37995 * @param {Roo.BorderLayout} layout The layout for this panel
37996 * @param {String/Object} config A string to set only the title or a config object
37998 Roo.bootstrap.panel.Nest = function(config)
38000 // construct with only one argument..
38001 /* FIXME - implement nicer consturctors
38002 if (layout.layout) {
38004 layout = config.layout;
38005 delete config.layout;
38007 if (layout.xtype && !layout.getEl) {
38008 // then layout needs constructing..
38009 layout = Roo.factory(layout, Roo);
38013 config.el = config.layout.getEl();
38015 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
38017 config.layout.monitorWindowResize = false; // turn off autosizing
38018 this.layout = config.layout;
38019 this.layout.getEl().addClass("roo-layout-nested-layout");
38020 this.layout.parent = this;
38027 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
38029 setSize : function(width, height){
38030 if(!this.ignoreResize(width, height)){
38031 var size = this.adjustForComponents(width, height);
38032 var el = this.layout.getEl();
38033 if (size.height < 1) {
38034 el.setWidth(size.width);
38036 el.setSize(size.width, size.height);
38038 var touch = el.dom.offsetWidth;
38039 this.layout.layout();
38040 // ie requires a double layout on the first pass
38041 if(Roo.isIE && !this.initialized){
38042 this.initialized = true;
38043 this.layout.layout();
38048 // activate all subpanels if not currently active..
38050 setActiveState : function(active){
38051 this.active = active;
38052 this.setActiveClass(active);
38055 this.fireEvent("deactivate", this);
38059 this.fireEvent("activate", this);
38060 // not sure if this should happen before or after..
38061 if (!this.layout) {
38062 return; // should not happen..
38065 for (var r in this.layout.regions) {
38066 reg = this.layout.getRegion(r);
38067 if (reg.getActivePanel()) {
38068 //reg.showPanel(reg.getActivePanel()); // force it to activate..
38069 reg.setActivePanel(reg.getActivePanel());
38072 if (!reg.panels.length) {
38075 reg.showPanel(reg.getPanel(0));
38084 * Returns the nested BorderLayout for this panel
38085 * @return {Roo.BorderLayout}
38087 getLayout : function(){
38088 return this.layout;
38092 * Adds a xtype elements to the layout of the nested panel
38096 xtype : 'ContentPanel',
38103 xtype : 'NestedLayoutPanel',
38109 items : [ ... list of content panels or nested layout panels.. ]
38113 * @param {Object} cfg Xtype definition of item to add.
38115 addxtype : function(cfg) {
38116 return this.layout.addxtype(cfg);
38121 * Ext JS Library 1.1.1
38122 * Copyright(c) 2006-2007, Ext JS, LLC.
38124 * Originally Released Under LGPL - original licence link has changed is not relivant.
38127 * <script type="text/javascript">
38130 * @class Roo.TabPanel
38131 * @extends Roo.util.Observable
38132 * A lightweight tab container.
38136 // basic tabs 1, built from existing content
38137 var tabs = new Roo.TabPanel("tabs1");
38138 tabs.addTab("script", "View Script");
38139 tabs.addTab("markup", "View Markup");
38140 tabs.activate("script");
38142 // more advanced tabs, built from javascript
38143 var jtabs = new Roo.TabPanel("jtabs");
38144 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
38146 // set up the UpdateManager
38147 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
38148 var updater = tab2.getUpdateManager();
38149 updater.setDefaultUrl("ajax1.htm");
38150 tab2.on('activate', updater.refresh, updater, true);
38152 // Use setUrl for Ajax loading
38153 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
38154 tab3.setUrl("ajax2.htm", null, true);
38157 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
38160 jtabs.activate("jtabs-1");
38163 * Create a new TabPanel.
38164 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
38165 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
38167 Roo.bootstrap.panel.Tabs = function(config){
38169 * The container element for this TabPanel.
38170 * @type Roo.Element
38172 this.el = Roo.get(config.el);
38175 if(typeof config == "boolean"){
38176 this.tabPosition = config ? "bottom" : "top";
38178 Roo.apply(this, config);
38182 if(this.tabPosition == "bottom"){
38183 // if tabs are at the bottom = create the body first.
38184 this.bodyEl = Roo.get(this.createBody(this.el.dom));
38185 this.el.addClass("roo-tabs-bottom");
38187 // next create the tabs holders
38189 if (this.tabPosition == "west"){
38191 var reg = this.region; // fake it..
38193 if (!reg.mgr.parent) {
38196 reg = reg.mgr.parent.region;
38198 Roo.log("got nest?");
38200 if (reg.mgr.getRegion('west')) {
38201 var ctrdom = reg.mgr.getRegion('west').bodyEl.dom;
38202 this.stripWrap = Roo.get(this.createStrip(ctrdom ), true);
38203 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
38204 this.stripEl.setVisibilityMode(Roo.Element.DISPLAY);
38205 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
38213 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
38214 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
38215 this.stripEl.setVisibilityMode(Roo.Element.DISPLAY);
38216 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
38221 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
38224 // finally - if tabs are at the top, then create the body last..
38225 if(this.tabPosition != "bottom"){
38226 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
38227 * @type Roo.Element
38229 this.bodyEl = Roo.get(this.createBody(this.el.dom));
38230 this.el.addClass("roo-tabs-top");
38234 this.bodyEl.setStyle("position", "relative");
38236 this.active = null;
38237 this.activateDelegate = this.activate.createDelegate(this);
38242 * Fires when the active tab changes
38243 * @param {Roo.TabPanel} this
38244 * @param {Roo.TabPanelItem} activePanel The new active tab
38248 * @event beforetabchange
38249 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
38250 * @param {Roo.TabPanel} this
38251 * @param {Object} e Set cancel to true on this object to cancel the tab change
38252 * @param {Roo.TabPanelItem} tab The tab being changed to
38254 "beforetabchange" : true
38257 Roo.EventManager.onWindowResize(this.onResize, this);
38258 this.cpad = this.el.getPadding("lr");
38259 this.hiddenCount = 0;
38262 // toolbar on the tabbar support...
38263 if (this.toolbar) {
38264 alert("no toolbar support yet");
38265 this.toolbar = false;
38267 var tcfg = this.toolbar;
38268 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
38269 this.toolbar = new Roo.Toolbar(tcfg);
38270 if (Roo.isSafari) {
38271 var tbl = tcfg.container.child('table', true);
38272 tbl.setAttribute('width', '100%');
38280 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
38283 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
38285 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
38287 tabPosition : "top",
38289 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
38291 currentTabWidth : 0,
38293 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
38297 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
38301 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
38303 preferredTabWidth : 175,
38305 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
38307 resizeTabs : false,
38309 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
38311 monitorResize : true,
38313 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
38315 toolbar : false, // set by caller..
38317 region : false, /// set by caller
38319 disableTooltips : true, // not used yet...
38322 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
38323 * @param {String} id The id of the div to use <b>or create</b>
38324 * @param {String} text The text for the tab
38325 * @param {String} content (optional) Content to put in the TabPanelItem body
38326 * @param {Boolean} closable (optional) True to create a close icon on the tab
38327 * @return {Roo.TabPanelItem} The created TabPanelItem
38329 addTab : function(id, text, content, closable, tpl)
38331 var item = new Roo.bootstrap.panel.TabItem({
38335 closable : closable,
38338 this.addTabItem(item);
38340 item.setContent(content);
38346 * Returns the {@link Roo.TabPanelItem} with the specified id/index
38347 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
38348 * @return {Roo.TabPanelItem}
38350 getTab : function(id){
38351 return this.items[id];
38355 * Hides the {@link Roo.TabPanelItem} with the specified id/index
38356 * @param {String/Number} id The id or index of the TabPanelItem to hide.
38358 hideTab : function(id){
38359 var t = this.items[id];
38362 this.hiddenCount++;
38363 this.autoSizeTabs();
38368 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
38369 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
38371 unhideTab : function(id){
38372 var t = this.items[id];
38374 t.setHidden(false);
38375 this.hiddenCount--;
38376 this.autoSizeTabs();
38381 * Adds an existing {@link Roo.TabPanelItem}.
38382 * @param {Roo.TabPanelItem} item The TabPanelItem to add
38384 addTabItem : function(item)
38386 this.items[item.id] = item;
38387 this.items.push(item);
38388 this.autoSizeTabs();
38389 // if(this.resizeTabs){
38390 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
38391 // this.autoSizeTabs();
38393 // item.autoSize();
38398 * Removes a {@link Roo.TabPanelItem}.
38399 * @param {String/Number} id The id or index of the TabPanelItem to remove.
38401 removeTab : function(id){
38402 var items = this.items;
38403 var tab = items[id];
38404 if(!tab) { return; }
38405 var index = items.indexOf(tab);
38406 if(this.active == tab && items.length > 1){
38407 var newTab = this.getNextAvailable(index);
38412 this.stripEl.dom.removeChild(tab.pnode.dom);
38413 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
38414 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
38416 items.splice(index, 1);
38417 delete this.items[tab.id];
38418 tab.fireEvent("close", tab);
38419 tab.purgeListeners();
38420 this.autoSizeTabs();
38423 getNextAvailable : function(start){
38424 var items = this.items;
38426 // look for a next tab that will slide over to
38427 // replace the one being removed
38428 while(index < items.length){
38429 var item = items[++index];
38430 if(item && !item.isHidden()){
38434 // if one isn't found select the previous tab (on the left)
38437 var item = items[--index];
38438 if(item && !item.isHidden()){
38446 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
38447 * @param {String/Number} id The id or index of the TabPanelItem to disable.
38449 disableTab : function(id){
38450 var tab = this.items[id];
38451 if(tab && this.active != tab){
38457 * Enables a {@link Roo.TabPanelItem} that is disabled.
38458 * @param {String/Number} id The id or index of the TabPanelItem to enable.
38460 enableTab : function(id){
38461 var tab = this.items[id];
38466 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
38467 * @param {String/Number} id The id or index of the TabPanelItem to activate.
38468 * @return {Roo.TabPanelItem} The TabPanelItem.
38470 activate : function(id)
38472 //Roo.log('activite:' + id);
38474 var tab = this.items[id];
38478 if(tab == this.active || tab.disabled){
38482 this.fireEvent("beforetabchange", this, e, tab);
38483 if(e.cancel !== true && !tab.disabled){
38485 this.active.hide();
38487 this.active = this.items[id];
38488 this.active.show();
38489 this.fireEvent("tabchange", this, this.active);
38495 * Gets the active {@link Roo.TabPanelItem}.
38496 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
38498 getActiveTab : function(){
38499 return this.active;
38503 * Updates the tab body element to fit the height of the container element
38504 * for overflow scrolling
38505 * @param {Number} targetHeight (optional) Override the starting height from the elements height
38507 syncHeight : function(targetHeight){
38508 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
38509 var bm = this.bodyEl.getMargins();
38510 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
38511 this.bodyEl.setHeight(newHeight);
38515 onResize : function(){
38516 if(this.monitorResize){
38517 this.autoSizeTabs();
38522 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
38524 beginUpdate : function(){
38525 this.updating = true;
38529 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
38531 endUpdate : function(){
38532 this.updating = false;
38533 this.autoSizeTabs();
38537 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
38539 autoSizeTabs : function()
38541 var count = this.items.length;
38542 var vcount = count - this.hiddenCount;
38545 this.stripEl.hide();
38547 this.stripEl.show();
38550 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
38555 var w = Math.max(this.el.getWidth() - this.cpad, 10);
38556 var availWidth = Math.floor(w / vcount);
38557 var b = this.stripBody;
38558 if(b.getWidth() > w){
38559 var tabs = this.items;
38560 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
38561 if(availWidth < this.minTabWidth){
38562 /*if(!this.sleft){ // incomplete scrolling code
38563 this.createScrollButtons();
38566 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
38569 if(this.currentTabWidth < this.preferredTabWidth){
38570 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
38576 * Returns the number of tabs in this TabPanel.
38579 getCount : function(){
38580 return this.items.length;
38584 * Resizes all the tabs to the passed width
38585 * @param {Number} The new width
38587 setTabWidth : function(width){
38588 this.currentTabWidth = width;
38589 for(var i = 0, len = this.items.length; i < len; i++) {
38590 if(!this.items[i].isHidden()) {
38591 this.items[i].setWidth(width);
38597 * Destroys this TabPanel
38598 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
38600 destroy : function(removeEl){
38601 Roo.EventManager.removeResizeListener(this.onResize, this);
38602 for(var i = 0, len = this.items.length; i < len; i++){
38603 this.items[i].purgeListeners();
38605 if(removeEl === true){
38606 this.el.update("");
38611 createStrip : function(container)
38613 var strip = document.createElement("nav");
38614 strip.className = Roo.bootstrap.version == 4 ?
38615 "navbar-light bg-light" :
38616 "navbar navbar-default"; //"x-tabs-wrap";
38617 container.appendChild(strip);
38621 createStripList : function(strip)
38623 // div wrapper for retard IE
38624 // returns the "tr" element.
38625 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
38626 //'<div class="x-tabs-strip-wrap">'+
38627 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
38628 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
38629 return strip.firstChild; //.firstChild.firstChild.firstChild;
38631 createBody : function(container)
38633 var body = document.createElement("div");
38634 Roo.id(body, "tab-body");
38635 //Roo.fly(body).addClass("x-tabs-body");
38636 Roo.fly(body).addClass("tab-content");
38637 container.appendChild(body);
38640 createItemBody :function(bodyEl, id){
38641 var body = Roo.getDom(id);
38643 body = document.createElement("div");
38646 //Roo.fly(body).addClass("x-tabs-item-body");
38647 Roo.fly(body).addClass("tab-pane");
38648 bodyEl.insertBefore(body, bodyEl.firstChild);
38652 createStripElements : function(stripEl, text, closable, tpl)
38654 var td = document.createElement("li"); // was td..
38655 td.className = 'nav-item';
38657 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
38660 stripEl.appendChild(td);
38662 td.className = "x-tabs-closable";
38663 if(!this.closeTpl){
38664 this.closeTpl = new Roo.Template(
38665 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38666 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
38667 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
38670 var el = this.closeTpl.overwrite(td, {"text": text});
38671 var close = el.getElementsByTagName("div")[0];
38672 var inner = el.getElementsByTagName("em")[0];
38673 return {"el": el, "close": close, "inner": inner};
38676 // not sure what this is..
38677 // if(!this.tabTpl){
38678 //this.tabTpl = new Roo.Template(
38679 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38680 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
38682 // this.tabTpl = new Roo.Template(
38683 // '<a href="#">' +
38684 // '<span unselectable="on"' +
38685 // (this.disableTooltips ? '' : ' title="{text}"') +
38686 // ' >{text}</span></a>'
38692 var template = tpl || this.tabTpl || false;
38695 template = new Roo.Template(
38696 Roo.bootstrap.version == 4 ?
38698 '<a class="nav-link" href="#" unselectable="on"' +
38699 (this.disableTooltips ? '' : ' title="{text}"') +
38702 '<a class="nav-link" href="#">' +
38703 '<span unselectable="on"' +
38704 (this.disableTooltips ? '' : ' title="{text}"') +
38705 ' >{text}</span></a>'
38710 switch (typeof(template)) {
38714 template = new Roo.Template(template);
38720 var el = template.overwrite(td, {"text": text});
38722 var inner = el.getElementsByTagName("span")[0];
38724 return {"el": el, "inner": inner};
38732 * @class Roo.TabPanelItem
38733 * @extends Roo.util.Observable
38734 * Represents an individual item (tab plus body) in a TabPanel.
38735 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
38736 * @param {String} id The id of this TabPanelItem
38737 * @param {String} text The text for the tab of this TabPanelItem
38738 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
38740 Roo.bootstrap.panel.TabItem = function(config){
38742 * The {@link Roo.TabPanel} this TabPanelItem belongs to
38743 * @type Roo.TabPanel
38745 this.tabPanel = config.panel;
38747 * The id for this TabPanelItem
38750 this.id = config.id;
38752 this.disabled = false;
38754 this.text = config.text;
38756 this.loaded = false;
38757 this.closable = config.closable;
38760 * The body element for this TabPanelItem.
38761 * @type Roo.Element
38763 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
38764 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
38765 this.bodyEl.setStyle("display", "block");
38766 this.bodyEl.setStyle("zoom", "1");
38767 //this.hideAction();
38769 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
38771 this.el = Roo.get(els.el);
38772 this.inner = Roo.get(els.inner, true);
38773 this.textEl = Roo.bootstrap.version == 4 ?
38774 this.el : Roo.get(this.el.dom.firstChild, true);
38776 this.pnode = this.linode = Roo.get(els.el.parentNode, true);
38777 this.status_node = Roo.bootstrap.version == 4 ? this.el : this.linode;
38780 // this.el.on("mousedown", this.onTabMouseDown, this);
38781 this.el.on("click", this.onTabClick, this);
38783 if(config.closable){
38784 var c = Roo.get(els.close, true);
38785 c.dom.title = this.closeText;
38786 c.addClassOnOver("close-over");
38787 c.on("click", this.closeClick, this);
38793 * Fires when this tab becomes the active tab.
38794 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38795 * @param {Roo.TabPanelItem} this
38799 * @event beforeclose
38800 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
38801 * @param {Roo.TabPanelItem} this
38802 * @param {Object} e Set cancel to true on this object to cancel the close.
38804 "beforeclose": true,
38807 * Fires when this tab is closed.
38808 * @param {Roo.TabPanelItem} this
38812 * @event deactivate
38813 * Fires when this tab is no longer the active tab.
38814 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38815 * @param {Roo.TabPanelItem} this
38817 "deactivate" : true
38819 this.hidden = false;
38821 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
38824 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
38826 purgeListeners : function(){
38827 Roo.util.Observable.prototype.purgeListeners.call(this);
38828 this.el.removeAllListeners();
38831 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
38834 this.status_node.addClass("active");
38837 this.tabPanel.stripWrap.repaint();
38839 this.fireEvent("activate", this.tabPanel, this);
38843 * Returns true if this tab is the active tab.
38844 * @return {Boolean}
38846 isActive : function(){
38847 return this.tabPanel.getActiveTab() == this;
38851 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
38854 this.status_node.removeClass("active");
38856 this.fireEvent("deactivate", this.tabPanel, this);
38859 hideAction : function(){
38860 this.bodyEl.hide();
38861 this.bodyEl.setStyle("position", "absolute");
38862 this.bodyEl.setLeft("-20000px");
38863 this.bodyEl.setTop("-20000px");
38866 showAction : function(){
38867 this.bodyEl.setStyle("position", "relative");
38868 this.bodyEl.setTop("");
38869 this.bodyEl.setLeft("");
38870 this.bodyEl.show();
38874 * Set the tooltip for the tab.
38875 * @param {String} tooltip The tab's tooltip
38877 setTooltip : function(text){
38878 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
38879 this.textEl.dom.qtip = text;
38880 this.textEl.dom.removeAttribute('title');
38882 this.textEl.dom.title = text;
38886 onTabClick : function(e){
38887 e.preventDefault();
38888 this.tabPanel.activate(this.id);
38891 onTabMouseDown : function(e){
38892 e.preventDefault();
38893 this.tabPanel.activate(this.id);
38896 getWidth : function(){
38897 return this.inner.getWidth();
38900 setWidth : function(width){
38901 var iwidth = width - this.linode.getPadding("lr");
38902 this.inner.setWidth(iwidth);
38903 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
38904 this.linode.setWidth(width);
38908 * Show or hide the tab
38909 * @param {Boolean} hidden True to hide or false to show.
38911 setHidden : function(hidden){
38912 this.hidden = hidden;
38913 this.linode.setStyle("display", hidden ? "none" : "");
38917 * Returns true if this tab is "hidden"
38918 * @return {Boolean}
38920 isHidden : function(){
38921 return this.hidden;
38925 * Returns the text for this tab
38928 getText : function(){
38932 autoSize : function(){
38933 //this.el.beginMeasure();
38934 this.textEl.setWidth(1);
38936 * #2804 [new] Tabs in Roojs
38937 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
38939 //this.setWidth(this.textEl.dom.scrollWidth+this.linode.getPadding("lr")+this.inner.getPadding("lr") + 2);
38940 //this.el.endMeasure();
38944 * Sets the text for the tab (Note: this also sets the tooltip text)
38945 * @param {String} text The tab's text and tooltip
38947 setText : function(text){
38949 this.textEl.update(text);
38950 this.setTooltip(text);
38951 //if(!this.tabPanel.resizeTabs){
38952 // this.autoSize();
38956 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
38958 activate : function(){
38959 this.tabPanel.activate(this.id);
38963 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
38965 disable : function(){
38966 if(this.tabPanel.active != this){
38967 this.disabled = true;
38968 this.status_node.addClass("disabled");
38973 * Enables this TabPanelItem if it was previously disabled.
38975 enable : function(){
38976 this.disabled = false;
38977 this.status_node.removeClass("disabled");
38981 * Sets the content for this TabPanelItem.
38982 * @param {String} content The content
38983 * @param {Boolean} loadScripts true to look for and load scripts
38985 setContent : function(content, loadScripts){
38986 this.bodyEl.update(content, loadScripts);
38990 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
38991 * @return {Roo.UpdateManager} The UpdateManager
38993 getUpdateManager : function(){
38994 return this.bodyEl.getUpdateManager();
38998 * Set a URL to be used to load the content for this TabPanelItem.
38999 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
39000 * @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)
39001 * @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)
39002 * @return {Roo.UpdateManager} The UpdateManager
39004 setUrl : function(url, params, loadOnce){
39005 if(this.refreshDelegate){
39006 this.un('activate', this.refreshDelegate);
39008 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
39009 this.on("activate", this.refreshDelegate);
39010 return this.bodyEl.getUpdateManager();
39014 _handleRefresh : function(url, params, loadOnce){
39015 if(!loadOnce || !this.loaded){
39016 var updater = this.bodyEl.getUpdateManager();
39017 updater.update(url, params, this._setLoaded.createDelegate(this));
39022 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
39023 * Will fail silently if the setUrl method has not been called.
39024 * This does not activate the panel, just updates its content.
39026 refresh : function(){
39027 if(this.refreshDelegate){
39028 this.loaded = false;
39029 this.refreshDelegate();
39034 _setLoaded : function(){
39035 this.loaded = true;
39039 closeClick : function(e){
39042 this.fireEvent("beforeclose", this, o);
39043 if(o.cancel !== true){
39044 this.tabPanel.removeTab(this.id);
39048 * The text displayed in the tooltip for the close icon.
39051 closeText : "Close this tab"
39054 * This script refer to:
39055 * Title: International Telephone Input
39056 * Author: Jack O'Connor
39057 * Code version: v12.1.12
39058 * Availability: https://github.com/jackocnr/intl-tel-input.git
39061 Roo.bootstrap.PhoneInputData = function() {
39064 "Afghanistan (افغانستان)",
39069 "Albania (Shqipëri)",
39074 "Algeria (الجزائر)",
39099 "Antigua and Barbuda",
39109 "Armenia (Հայաստան)",
39125 "Austria (Österreich)",
39130 "Azerbaijan (Azərbaycan)",
39140 "Bahrain (البحرين)",
39145 "Bangladesh (বাংলাদেশ)",
39155 "Belarus (Беларусь)",
39160 "Belgium (België)",
39190 "Bosnia and Herzegovina (Босна и Херцеговина)",
39205 "British Indian Ocean Territory",
39210 "British Virgin Islands",
39220 "Bulgaria (България)",
39230 "Burundi (Uburundi)",
39235 "Cambodia (កម្ពុជា)",
39240 "Cameroon (Cameroun)",
39249 ["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"]
39252 "Cape Verde (Kabu Verdi)",
39257 "Caribbean Netherlands",
39268 "Central African Republic (République centrafricaine)",
39288 "Christmas Island",
39294 "Cocos (Keeling) Islands",
39305 "Comoros (جزر القمر)",
39310 "Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)",
39315 "Congo (Republic) (Congo-Brazzaville)",
39335 "Croatia (Hrvatska)",
39356 "Czech Republic (Česká republika)",
39361 "Denmark (Danmark)",
39376 "Dominican Republic (República Dominicana)",
39380 ["809", "829", "849"]
39398 "Equatorial Guinea (Guinea Ecuatorial)",
39418 "Falkland Islands (Islas Malvinas)",
39423 "Faroe Islands (Føroyar)",
39444 "French Guiana (Guyane française)",
39449 "French Polynesia (Polynésie française)",
39464 "Georgia (საქართველო)",
39469 "Germany (Deutschland)",
39489 "Greenland (Kalaallit Nunaat)",
39526 "Guinea-Bissau (Guiné Bissau)",
39551 "Hungary (Magyarország)",
39556 "Iceland (Ísland)",
39576 "Iraq (العراق)",
39592 "Israel (ישראל)",
39619 "Jordan (الأردن)",
39624 "Kazakhstan (Казахстан)",
39645 "Kuwait (الكويت)",
39650 "Kyrgyzstan (Кыргызстан)",
39660 "Latvia (Latvija)",
39665 "Lebanon (لبنان)",
39680 "Libya (ليبيا)",
39690 "Lithuania (Lietuva)",
39705 "Macedonia (FYROM) (Македонија)",
39710 "Madagascar (Madagasikara)",
39740 "Marshall Islands",
39750 "Mauritania (موريتانيا)",
39755 "Mauritius (Moris)",
39776 "Moldova (Republica Moldova)",
39786 "Mongolia (Монгол)",
39791 "Montenegro (Crna Gora)",
39801 "Morocco (المغرب)",
39807 "Mozambique (Moçambique)",
39812 "Myanmar (Burma) (မြန်မာ)",
39817 "Namibia (Namibië)",
39832 "Netherlands (Nederland)",
39837 "New Caledonia (Nouvelle-Calédonie)",
39872 "North Korea (조선 민주주의 인민 공화국)",
39877 "Northern Mariana Islands",
39893 "Pakistan (پاکستان)",
39903 "Palestine (فلسطين)",
39913 "Papua New Guinea",
39955 "Réunion (La Réunion)",
39961 "Romania (România)",
39977 "Saint Barthélemy",
39988 "Saint Kitts and Nevis",
39998 "Saint Martin (Saint-Martin (partie française))",
40004 "Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)",
40009 "Saint Vincent and the Grenadines",
40024 "São Tomé and Príncipe (São Tomé e Príncipe)",
40029 "Saudi Arabia (المملكة العربية السعودية)",
40034 "Senegal (Sénégal)",
40064 "Slovakia (Slovensko)",
40069 "Slovenia (Slovenija)",
40079 "Somalia (Soomaaliya)",
40089 "South Korea (대한민국)",
40094 "South Sudan (جنوب السودان)",
40104 "Sri Lanka (ශ්රී ලංකාව)",
40109 "Sudan (السودان)",
40119 "Svalbard and Jan Mayen",
40130 "Sweden (Sverige)",
40135 "Switzerland (Schweiz)",
40140 "Syria (سوريا)",
40185 "Trinidad and Tobago",
40190 "Tunisia (تونس)",
40195 "Turkey (Türkiye)",
40205 "Turks and Caicos Islands",
40215 "U.S. Virgin Islands",
40225 "Ukraine (Україна)",
40230 "United Arab Emirates (الإمارات العربية المتحدة)",
40252 "Uzbekistan (Oʻzbekiston)",
40262 "Vatican City (Città del Vaticano)",
40273 "Vietnam (Việt Nam)",
40278 "Wallis and Futuna (Wallis-et-Futuna)",
40283 "Western Sahara (الصحراء الغربية)",
40289 "Yemen (اليمن)",
40313 * This script refer to:
40314 * Title: International Telephone Input
40315 * Author: Jack O'Connor
40316 * Code version: v12.1.12
40317 * Availability: https://github.com/jackocnr/intl-tel-input.git
40321 * @class Roo.bootstrap.PhoneInput
40322 * @extends Roo.bootstrap.TriggerField
40323 * An input with International dial-code selection
40325 * @cfg {String} defaultDialCode default '+852'
40326 * @cfg {Array} preferedCountries default []
40329 * Create a new PhoneInput.
40330 * @param {Object} config Configuration options
40333 Roo.bootstrap.PhoneInput = function(config) {
40334 Roo.bootstrap.PhoneInput.superclass.constructor.call(this, config);
40337 Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
40339 listWidth: undefined,
40341 selectedClass: 'active',
40343 invalidClass : "has-warning",
40345 validClass: 'has-success',
40347 allowed: '0123456789',
40352 * @cfg {String} defaultDialCode The default dial code when initializing the input
40354 defaultDialCode: '+852',
40357 * @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
40359 preferedCountries: false,
40361 getAutoCreate : function()
40363 var data = Roo.bootstrap.PhoneInputData();
40364 var align = this.labelAlign || this.parentLabelAlign();
40367 this.allCountries = [];
40368 this.dialCodeMapping = [];
40370 for (var i = 0; i < data.length; i++) {
40372 this.allCountries[i] = {
40376 priority: c[3] || 0,
40377 areaCodes: c[4] || null
40379 this.dialCodeMapping[c[2]] = {
40382 priority: c[3] || 0,
40383 areaCodes: c[4] || null
40395 // type: 'number', -- do not use number - we get the flaky up/down arrows.
40396 maxlength: this.max_length,
40397 cls : 'form-control tel-input',
40398 autocomplete: 'new-password'
40401 var hiddenInput = {
40404 cls: 'hidden-tel-input'
40408 hiddenInput.name = this.name;
40411 if (this.disabled) {
40412 input.disabled = true;
40415 var flag_container = {
40432 cls: this.hasFeedback ? 'has-feedback' : '',
40438 cls: 'dial-code-holder',
40445 cls: 'roo-select2-container input-group',
40452 if (this.fieldLabel.length) {
40455 tooltip: 'This field is required'
40461 cls: 'control-label',
40467 html: this.fieldLabel
40470 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40476 if(this.indicatorpos == 'right') {
40477 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40484 if(align == 'left') {
40492 if(this.labelWidth > 12){
40493 label.style = "width: " + this.labelWidth + 'px';
40495 if(this.labelWidth < 13 && this.labelmd == 0){
40496 this.labelmd = this.labelWidth;
40498 if(this.labellg > 0){
40499 label.cls += ' col-lg-' + this.labellg;
40500 input.cls += ' col-lg-' + (12 - this.labellg);
40502 if(this.labelmd > 0){
40503 label.cls += ' col-md-' + this.labelmd;
40504 container.cls += ' col-md-' + (12 - this.labelmd);
40506 if(this.labelsm > 0){
40507 label.cls += ' col-sm-' + this.labelsm;
40508 container.cls += ' col-sm-' + (12 - this.labelsm);
40510 if(this.labelxs > 0){
40511 label.cls += ' col-xs-' + this.labelxs;
40512 container.cls += ' col-xs-' + (12 - this.labelxs);
40522 var settings = this;
40524 ['xs','sm','md','lg'].map(function(size){
40525 if (settings[size]) {
40526 cfg.cls += ' col-' + size + '-' + settings[size];
40530 this.store = new Roo.data.Store({
40531 proxy : new Roo.data.MemoryProxy({}),
40532 reader : new Roo.data.JsonReader({
40543 'name' : 'dialCode',
40547 'name' : 'priority',
40551 'name' : 'areaCodes',
40558 if(!this.preferedCountries) {
40559 this.preferedCountries = [
40566 var p = this.preferedCountries.reverse();
40569 for (var i = 0; i < p.length; i++) {
40570 for (var j = 0; j < this.allCountries.length; j++) {
40571 if(this.allCountries[j].iso2 == p[i]) {
40572 var t = this.allCountries[j];
40573 this.allCountries.splice(j,1);
40574 this.allCountries.unshift(t);
40580 this.store.proxy.data = {
40582 data: this.allCountries
40588 initEvents : function()
40591 Roo.bootstrap.PhoneInput.superclass.initEvents.call(this);
40593 this.indicator = this.indicatorEl();
40594 this.flag = this.flagEl();
40595 this.dialCodeHolder = this.dialCodeHolderEl();
40597 this.trigger = this.el.select('div.flag-box',true).first();
40598 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
40603 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40604 _this.list.setWidth(lw);
40607 this.list.on('mouseover', this.onViewOver, this);
40608 this.list.on('mousemove', this.onViewMove, this);
40609 this.inputEl().on("keyup", this.onKeyUp, this);
40610 this.inputEl().on("keypress", this.onKeyPress, this);
40612 this.tpl = '<li><a href="#"><div class="flag {iso2}"></div>{name} <span class="dial-code">+{dialCode}</span></a></li>';
40614 this.view = new Roo.View(this.list, this.tpl, {
40615 singleSelect:true, store: this.store, selectedClass: this.selectedClass
40618 this.view.on('click', this.onViewClick, this);
40619 this.setValue(this.defaultDialCode);
40622 onTriggerClick : function(e)
40624 Roo.log('trigger click');
40629 if(this.isExpanded()){
40631 this.hasFocus = false;
40633 this.store.load({});
40634 this.hasFocus = true;
40639 isExpanded : function()
40641 return this.list.isVisible();
40644 collapse : function()
40646 if(!this.isExpanded()){
40650 Roo.get(document).un('mousedown', this.collapseIf, this);
40651 Roo.get(document).un('mousewheel', this.collapseIf, this);
40652 this.fireEvent('collapse', this);
40656 expand : function()
40660 if(this.isExpanded() || !this.hasFocus){
40664 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
40665 this.list.setWidth(lw);
40668 this.restrictHeight();
40670 Roo.get(document).on('mousedown', this.collapseIf, this);
40671 Roo.get(document).on('mousewheel', this.collapseIf, this);
40673 this.fireEvent('expand', this);
40676 restrictHeight : function()
40678 this.list.alignTo(this.inputEl(), this.listAlign);
40679 this.list.alignTo(this.inputEl(), this.listAlign);
40682 onViewOver : function(e, t)
40684 if(this.inKeyMode){
40687 var item = this.view.findItemFromChild(t);
40690 var index = this.view.indexOf(item);
40691 this.select(index, false);
40696 onViewClick : function(view, doFocus, el, e)
40698 var index = this.view.getSelectedIndexes()[0];
40700 var r = this.store.getAt(index);
40703 this.onSelect(r, index);
40705 if(doFocus !== false && !this.blockFocus){
40706 this.inputEl().focus();
40710 onViewMove : function(e, t)
40712 this.inKeyMode = false;
40715 select : function(index, scrollIntoView)
40717 this.selectedIndex = index;
40718 this.view.select(index);
40719 if(scrollIntoView !== false){
40720 var el = this.view.getNode(index);
40722 this.list.scrollChildIntoView(el, false);
40727 createList : function()
40729 this.list = Roo.get(document.body).createChild({
40731 cls: 'typeahead typeahead-long dropdown-menu tel-list',
40732 style: 'display:none'
40735 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
40738 collapseIf : function(e)
40740 var in_combo = e.within(this.el);
40741 var in_list = e.within(this.list);
40742 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
40744 if (in_combo || in_list || is_list) {
40750 onSelect : function(record, index)
40752 if(this.fireEvent('beforeselect', this, record, index) !== false){
40754 this.setFlagClass(record.data.iso2);
40755 this.setDialCode(record.data.dialCode);
40756 this.hasFocus = false;
40758 this.fireEvent('select', this, record, index);
40762 flagEl : function()
40764 var flag = this.el.select('div.flag',true).first();
40771 dialCodeHolderEl : function()
40773 var d = this.el.select('input.dial-code-holder',true).first();
40780 setDialCode : function(v)
40782 this.dialCodeHolder.dom.value = '+'+v;
40785 setFlagClass : function(n)
40787 this.flag.dom.className = 'flag '+n;
40790 getValue : function()
40792 var v = this.inputEl().getValue();
40793 if(this.dialCodeHolder) {
40794 v = this.dialCodeHolder.dom.value+this.inputEl().getValue();
40799 setValue : function(v)
40801 var d = this.getDialCode(v);
40803 //invalid dial code
40804 if(v.length == 0 || !d || d.length == 0) {
40806 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
40807 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
40813 this.setFlagClass(this.dialCodeMapping[d].iso2);
40814 this.setDialCode(d);
40815 this.inputEl().dom.value = v.replace('+'+d,'');
40816 this.hiddenEl().dom.value = this.getValue();
40821 getDialCode : function(v)
40825 if (v.length == 0) {
40826 return this.dialCodeHolder.dom.value;
40830 if (v.charAt(0) != "+") {
40833 var numericChars = "";
40834 for (var i = 1; i < v.length; i++) {
40835 var c = v.charAt(i);
40838 if (this.dialCodeMapping[numericChars]) {
40839 dialCode = v.substr(1, i);
40841 if (numericChars.length == 4) {
40851 this.setValue(this.defaultDialCode);
40855 hiddenEl : function()
40857 return this.el.select('input.hidden-tel-input',true).first();
40860 // after setting val
40861 onKeyUp : function(e){
40862 this.setValue(this.getValue());
40865 onKeyPress : function(e){
40866 if(this.allowed.indexOf(String.fromCharCode(e.getCharCode())) === -1){
40873 * @class Roo.bootstrap.MoneyField
40874 * @extends Roo.bootstrap.ComboBox
40875 * Bootstrap MoneyField class
40878 * Create a new MoneyField.
40879 * @param {Object} config Configuration options
40882 Roo.bootstrap.MoneyField = function(config) {
40884 Roo.bootstrap.MoneyField.superclass.constructor.call(this, config);
40888 Roo.extend(Roo.bootstrap.MoneyField, Roo.bootstrap.ComboBox, {
40891 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
40893 allowDecimals : true,
40895 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
40897 decimalSeparator : ".",
40899 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
40901 decimalPrecision : 0,
40903 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
40905 allowNegative : true,
40907 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
40911 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
40913 minValue : Number.NEGATIVE_INFINITY,
40915 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
40917 maxValue : Number.MAX_VALUE,
40919 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
40921 minText : "The minimum value for this field is {0}",
40923 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
40925 maxText : "The maximum value for this field is {0}",
40927 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
40928 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
40930 nanText : "{0} is not a valid number",
40932 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
40936 * @cfg {String} defaults currency of the MoneyField
40937 * value should be in lkey
40939 defaultCurrency : false,
40941 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
40943 thousandsDelimiter : false,
40945 * @cfg {Number} max_length Maximum input field length allowed (defaults to Number.MAX_VALUE)
40956 getAutoCreate : function()
40958 var align = this.labelAlign || this.parentLabelAlign();
40970 cls : 'form-control roo-money-amount-input',
40971 autocomplete: 'new-password'
40974 var hiddenInput = {
40978 cls: 'hidden-number-input'
40981 if(this.max_length) {
40982 input.maxlength = this.max_length;
40986 hiddenInput.name = this.name;
40989 if (this.disabled) {
40990 input.disabled = true;
40993 var clg = 12 - this.inputlg;
40994 var cmd = 12 - this.inputmd;
40995 var csm = 12 - this.inputsm;
40996 var cxs = 12 - this.inputxs;
41000 cls : 'row roo-money-field',
41004 cls : 'roo-money-currency column col-lg-' + clg + ' col-md-' + cmd + ' col-sm-' + csm + ' col-xs-' + cxs,
41008 cls: 'roo-select2-container input-group',
41012 cls : 'form-control roo-money-currency-input',
41013 autocomplete: 'new-password',
41015 name : this.currencyName
41019 cls : 'input-group-addon',
41033 cls : 'roo-money-amount column col-lg-' + this.inputlg + ' col-md-' + this.inputmd + ' col-sm-' + this.inputsm + ' col-xs-' + this.inputxs,
41037 cls: this.hasFeedback ? 'has-feedback' : '',
41048 if (this.fieldLabel.length) {
41051 tooltip: 'This field is required'
41057 cls: 'control-label',
41063 html: this.fieldLabel
41066 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
41072 if(this.indicatorpos == 'right') {
41073 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
41080 if(align == 'left') {
41088 if(this.labelWidth > 12){
41089 label.style = "width: " + this.labelWidth + 'px';
41091 if(this.labelWidth < 13 && this.labelmd == 0){
41092 this.labelmd = this.labelWidth;
41094 if(this.labellg > 0){
41095 label.cls += ' col-lg-' + this.labellg;
41096 input.cls += ' col-lg-' + (12 - this.labellg);
41098 if(this.labelmd > 0){
41099 label.cls += ' col-md-' + this.labelmd;
41100 container.cls += ' col-md-' + (12 - this.labelmd);
41102 if(this.labelsm > 0){
41103 label.cls += ' col-sm-' + this.labelsm;
41104 container.cls += ' col-sm-' + (12 - this.labelsm);
41106 if(this.labelxs > 0){
41107 label.cls += ' col-xs-' + this.labelxs;
41108 container.cls += ' col-xs-' + (12 - this.labelxs);
41119 var settings = this;
41121 ['xs','sm','md','lg'].map(function(size){
41122 if (settings[size]) {
41123 cfg.cls += ' col-' + size + '-' + settings[size];
41130 initEvents : function()
41132 this.indicator = this.indicatorEl();
41134 this.initCurrencyEvent();
41136 this.initNumberEvent();
41139 initCurrencyEvent : function()
41142 throw "can not find store for combo";
41145 this.store = Roo.factory(this.store, Roo.data);
41146 this.store.parent = this;
41150 this.triggerEl = this.el.select('.input-group-addon', true).first();
41152 this.triggerEl.on("click", this.onTriggerClick, this, { preventDefault : true });
41157 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
41158 _this.list.setWidth(lw);
41161 this.list.on('mouseover', this.onViewOver, this);
41162 this.list.on('mousemove', this.onViewMove, this);
41163 this.list.on('scroll', this.onViewScroll, this);
41166 this.tpl = '<li><a href="#">{' + this.currencyField + '}</a></li>';
41169 this.view = new Roo.View(this.list, this.tpl, {
41170 singleSelect:true, store: this.store, selectedClass: this.selectedClass
41173 this.view.on('click', this.onViewClick, this);
41175 this.store.on('beforeload', this.onBeforeLoad, this);
41176 this.store.on('load', this.onLoad, this);
41177 this.store.on('loadexception', this.onLoadException, this);
41179 this.keyNav = new Roo.KeyNav(this.currencyEl(), {
41180 "up" : function(e){
41181 this.inKeyMode = true;
41185 "down" : function(e){
41186 if(!this.isExpanded()){
41187 this.onTriggerClick();
41189 this.inKeyMode = true;
41194 "enter" : function(e){
41197 if(this.fireEvent("specialkey", this, e)){
41198 this.onViewClick(false);
41204 "esc" : function(e){
41208 "tab" : function(e){
41211 if(this.fireEvent("specialkey", this, e)){
41212 this.onViewClick(false);
41220 doRelay : function(foo, bar, hname){
41221 if(hname == 'down' || this.scope.isExpanded()){
41222 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
41230 this.currencyEl().on("click", this.onTriggerClick, this, { preventDefault : true });
41234 initNumberEvent : function(e)
41236 this.inputEl().on("keydown" , this.fireKey, this);
41237 this.inputEl().on("focus", this.onFocus, this);
41238 this.inputEl().on("blur", this.onBlur, this);
41240 this.inputEl().relayEvent('keyup', this);
41242 if(this.indicator){
41243 this.indicator.addClass('invisible');
41246 this.originalValue = this.getValue();
41248 if(this.validationEvent == 'keyup'){
41249 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
41250 this.inputEl().on('keyup', this.filterValidation, this);
41252 else if(this.validationEvent !== false){
41253 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
41256 if(this.selectOnFocus){
41257 this.on("focus", this.preFocus, this);
41260 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
41261 this.inputEl().on("keypress", this.filterKeys, this);
41263 this.inputEl().relayEvent('keypress', this);
41266 var allowed = "0123456789";
41268 if(this.allowDecimals){
41269 allowed += this.decimalSeparator;
41272 if(this.allowNegative){
41276 if(this.thousandsDelimiter) {
41280 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
41282 var keyPress = function(e){
41284 var k = e.getKey();
41286 var c = e.getCharCode();
41289 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
41290 allowed.indexOf(String.fromCharCode(c)) === -1
41296 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
41300 if(allowed.indexOf(String.fromCharCode(c)) === -1){
41305 this.inputEl().on("keypress", keyPress, this);
41309 onTriggerClick : function(e)
41316 this.loadNext = false;
41318 if(this.isExpanded()){
41323 this.hasFocus = true;
41325 if(this.triggerAction == 'all') {
41326 this.doQuery(this.allQuery, true);
41330 this.doQuery(this.getRawValue());
41333 getCurrency : function()
41335 var v = this.currencyEl().getValue();
41340 restrictHeight : function()
41342 this.list.alignTo(this.currencyEl(), this.listAlign);
41343 this.list.alignTo(this.currencyEl(), this.listAlign);
41346 onViewClick : function(view, doFocus, el, e)
41348 var index = this.view.getSelectedIndexes()[0];
41350 var r = this.store.getAt(index);
41353 this.onSelect(r, index);
41357 onSelect : function(record, index){
41359 if(this.fireEvent('beforeselect', this, record, index) !== false){
41361 this.setFromCurrencyData(index > -1 ? record.data : false);
41365 this.fireEvent('select', this, record, index);
41369 setFromCurrencyData : function(o)
41373 this.lastCurrency = o;
41375 if (this.currencyField) {
41376 currency = !o || typeof(o[this.currencyField]) == 'undefined' ? '' : o[this.currencyField];
41378 Roo.log('no currencyField value set for '+ (this.name ? this.name : this.id));
41381 this.lastSelectionText = currency;
41383 //setting default currency
41384 if(o[this.currencyField] * 1 == 0 && this.defaultCurrency) {
41385 this.setCurrency(this.defaultCurrency);
41389 this.setCurrency(currency);
41392 setFromData : function(o)
41396 c[this.currencyField] = !o || typeof(o[this.currencyName]) == 'undefined' ? '' : o[this.currencyName];
41398 this.setFromCurrencyData(c);
41403 value = !o || typeof(o[this.name]) == 'undefined' ? '' : o[this.name];
41405 Roo.log('no value set for '+ (this.name ? this.name : this.id));
41408 this.setValue(value);
41412 setCurrency : function(v)
41414 this.currencyValue = v;
41417 this.currencyEl().dom.value = (v === null || v === undefined ? '' : v);
41422 setValue : function(v)
41424 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
41430 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
41432 this.inputEl().dom.value = (v == '') ? '' :
41433 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
41435 if(!this.allowZero && v === '0') {
41436 this.hiddenEl().dom.value = '';
41437 this.inputEl().dom.value = '';
41444 getRawValue : function()
41446 var v = this.inputEl().getValue();
41451 getValue : function()
41453 return this.fixPrecision(this.parseValue(this.getRawValue()));
41456 parseValue : function(value)
41458 if(this.thousandsDelimiter) {
41460 r = new RegExp(",", "g");
41461 value = value.replace(r, "");
41464 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
41465 return isNaN(value) ? '' : value;
41469 fixPrecision : function(value)
41471 if(this.thousandsDelimiter) {
41473 r = new RegExp(",", "g");
41474 value = value.replace(r, "");
41477 var nan = isNaN(value);
41479 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
41480 return nan ? '' : value;
41482 return parseFloat(value).toFixed(this.decimalPrecision);
41485 decimalPrecisionFcn : function(v)
41487 return Math.floor(v);
41490 validateValue : function(value)
41492 if(!Roo.bootstrap.MoneyField.superclass.validateValue.call(this, value)){
41496 var num = this.parseValue(value);
41499 this.markInvalid(String.format(this.nanText, value));
41503 if(num < this.minValue){
41504 this.markInvalid(String.format(this.minText, this.minValue));
41508 if(num > this.maxValue){
41509 this.markInvalid(String.format(this.maxText, this.maxValue));
41516 validate : function()
41518 if(this.disabled || this.allowBlank){
41523 var currency = this.getCurrency();
41525 if(this.validateValue(this.getRawValue()) && currency.length){
41530 this.markInvalid();
41534 getName: function()
41539 beforeBlur : function()
41545 var v = this.parseValue(this.getRawValue());
41552 onBlur : function()
41556 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
41557 //this.el.removeClass(this.focusClass);
41560 this.hasFocus = false;
41562 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
41566 var v = this.getValue();
41568 if(String(v) !== String(this.startValue)){
41569 this.fireEvent('change', this, v, this.startValue);
41572 this.fireEvent("blur", this);
41575 inputEl : function()
41577 return this.el.select('.roo-money-amount-input', true).first();
41580 currencyEl : function()
41582 return this.el.select('.roo-money-currency-input', true).first();
41585 hiddenEl : function()
41587 return this.el.select('input.hidden-number-input',true).first();
41591 * @class Roo.bootstrap.BezierSignature
41592 * @extends Roo.bootstrap.Component
41593 * Bootstrap BezierSignature class
41594 * This script refer to:
41595 * Title: Signature Pad
41597 * Availability: https://github.com/szimek/signature_pad
41600 * Create a new BezierSignature
41601 * @param {Object} config The config object
41604 Roo.bootstrap.BezierSignature = function(config){
41605 Roo.bootstrap.BezierSignature.superclass.constructor.call(this, config);
41611 Roo.extend(Roo.bootstrap.BezierSignature, Roo.bootstrap.Component,
41618 mouse_btn_down: true,
41621 * @cfg {int} canvas height
41623 canvas_height: '200px',
41626 * @cfg {float|function} Radius of a single dot.
41631 * @cfg {float} Minimum width of a line. Defaults to 0.5.
41636 * @cfg {float} Maximum width of a line. Defaults to 2.5.
41641 * @cfg {integer} Draw the next point at most once per every x milliseconds. Set it to 0 to turn off throttling. Defaults to 16.
41646 * @cfg {integer} Add the next point only if the previous one is farther than x pixels. Defaults to 5.
41651 * @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.
41653 bg_color: 'rgba(0, 0, 0, 0)',
41656 * @cfg {string} Color used to draw the lines. Can be any color format accepted by context.fillStyle. Defaults to "black".
41658 dot_color: 'black',
41661 * @cfg {float} Weight used to modify new velocity based on the previous velocity. Defaults to 0.7.
41663 velocity_filter_weight: 0.7,
41666 * @cfg {function} Callback when stroke begin.
41671 * @cfg {function} Callback when stroke end.
41675 getAutoCreate : function()
41677 var cls = 'roo-signature column';
41680 cls += ' ' + this.cls;
41690 for(var i = 0; i < col_sizes.length; i++) {
41691 if(this[col_sizes[i]]) {
41692 cls += " col-"+col_sizes[i]+"-"+this[col_sizes[i]];
41702 cls: 'roo-signature-body',
41706 cls: 'roo-signature-body-canvas',
41707 height: this.canvas_height,
41708 width: this.canvas_width
41715 style: 'display: none'
41723 initEvents: function()
41725 Roo.bootstrap.BezierSignature.superclass.initEvents.call(this);
41727 var canvas = this.canvasEl();
41729 // mouse && touch event swapping...
41730 canvas.dom.style.touchAction = 'none';
41731 canvas.dom.style.msTouchAction = 'none';
41733 this.mouse_btn_down = false;
41734 canvas.on('mousedown', this._handleMouseDown, this);
41735 canvas.on('mousemove', this._handleMouseMove, this);
41736 Roo.select('html').first().on('mouseup', this._handleMouseUp, this);
41738 if (window.PointerEvent) {
41739 canvas.on('pointerdown', this._handleMouseDown, this);
41740 canvas.on('pointermove', this._handleMouseMove, this);
41741 Roo.select('html').first().on('pointerup', this._handleMouseUp, this);
41744 if ('ontouchstart' in window) {
41745 canvas.on('touchstart', this._handleTouchStart, this);
41746 canvas.on('touchmove', this._handleTouchMove, this);
41747 canvas.on('touchend', this._handleTouchEnd, this);
41750 Roo.EventManager.onWindowResize(this.resize, this, true);
41752 // file input event
41753 this.fileEl().on('change', this.uploadImage, this);
41760 resize: function(){
41762 var canvas = this.canvasEl().dom;
41763 var ctx = this.canvasElCtx();
41764 var img_data = false;
41766 if(canvas.width > 0) {
41767 var img_data = ctx.getImageData(0, 0, canvas.width, canvas.height);
41769 // setting canvas width will clean img data
41772 var style = window.getComputedStyle ?
41773 getComputedStyle(this.el.dom, null) : this.el.dom.currentStyle;
41775 var padding_left = parseInt(style.paddingLeft) || 0;
41776 var padding_right = parseInt(style.paddingRight) || 0;
41778 canvas.width = this.el.dom.clientWidth - padding_left - padding_right;
41781 ctx.putImageData(img_data, 0, 0);
41785 _handleMouseDown: function(e)
41787 if (e.browserEvent.which === 1) {
41788 this.mouse_btn_down = true;
41789 this.strokeBegin(e);
41793 _handleMouseMove: function (e)
41795 if (this.mouse_btn_down) {
41796 this.strokeMoveUpdate(e);
41800 _handleMouseUp: function (e)
41802 if (e.browserEvent.which === 1 && this.mouse_btn_down) {
41803 this.mouse_btn_down = false;
41808 _handleTouchStart: function (e) {
41810 e.preventDefault();
41811 if (e.browserEvent.targetTouches.length === 1) {
41812 // var touch = e.browserEvent.changedTouches[0];
41813 // this.strokeBegin(touch);
41815 this.strokeBegin(e); // assume e catching the correct xy...
41819 _handleTouchMove: function (e) {
41820 e.preventDefault();
41821 // var touch = event.targetTouches[0];
41822 // _this._strokeMoveUpdate(touch);
41823 this.strokeMoveUpdate(e);
41826 _handleTouchEnd: function (e) {
41827 var wasCanvasTouched = e.target === this.canvasEl().dom;
41828 if (wasCanvasTouched) {
41829 e.preventDefault();
41830 // var touch = event.changedTouches[0];
41831 // _this._strokeEnd(touch);
41836 reset: function () {
41837 this._lastPoints = [];
41838 this._lastVelocity = 0;
41839 this._lastWidth = (this.min_width + this.max_width) / 2;
41840 this.canvasElCtx().fillStyle = this.dot_color;
41843 strokeMoveUpdate: function(e)
41845 this.strokeUpdate(e);
41847 if (this.throttle) {
41848 this.throttleStroke(this.strokeUpdate, this.throttle);
41851 this.strokeUpdate(e);
41855 strokeBegin: function(e)
41857 var newPointGroup = {
41858 color: this.dot_color,
41862 if (typeof this.onBegin === 'function') {
41866 this.curve_data.push(newPointGroup);
41868 this.strokeUpdate(e);
41871 strokeUpdate: function(e)
41873 var rect = this.canvasEl().dom.getBoundingClientRect();
41874 var point = new this.Point(e.xy[0] - rect.left, e.xy[1] - rect.top, new Date().getTime());
41875 var lastPointGroup = this.curve_data[this.curve_data.length - 1];
41876 var lastPoints = lastPointGroup.points;
41877 var lastPoint = lastPoints.length > 0 && lastPoints[lastPoints.length - 1];
41878 var isLastPointTooClose = lastPoint
41879 ? point.distanceTo(lastPoint) <= this.min_distance
41881 var color = lastPointGroup.color;
41882 if (!lastPoint || !(lastPoint && isLastPointTooClose)) {
41883 var curve = this.addPoint(point);
41885 this.drawDot({color: color, point: point});
41888 this.drawCurve({color: color, curve: curve});
41898 strokeEnd: function(e)
41900 this.strokeUpdate(e);
41901 if (typeof this.onEnd === 'function') {
41906 addPoint: function (point) {
41907 var _lastPoints = this._lastPoints;
41908 _lastPoints.push(point);
41909 if (_lastPoints.length > 2) {
41910 if (_lastPoints.length === 3) {
41911 _lastPoints.unshift(_lastPoints[0]);
41913 var widths = this.calculateCurveWidths(_lastPoints[1], _lastPoints[2]);
41914 var curve = this.Bezier.fromPoints(_lastPoints, widths, this);
41915 _lastPoints.shift();
41921 calculateCurveWidths: function (startPoint, endPoint) {
41922 var velocity = this.velocity_filter_weight * endPoint.velocityFrom(startPoint) +
41923 (1 - this.velocity_filter_weight) * this._lastVelocity;
41925 var newWidth = Math.max(this.max_width / (velocity + 1), this.min_width);
41928 start: this._lastWidth
41931 this._lastVelocity = velocity;
41932 this._lastWidth = newWidth;
41936 drawDot: function (_a) {
41937 var color = _a.color, point = _a.point;
41938 var ctx = this.canvasElCtx();
41939 var width = typeof this.dot_size === 'function' ? this.dot_size() : this.dot_size;
41941 this.drawCurveSegment(point.x, point.y, width);
41943 ctx.fillStyle = color;
41947 drawCurve: function (_a) {
41948 var color = _a.color, curve = _a.curve;
41949 var ctx = this.canvasElCtx();
41950 var widthDelta = curve.endWidth - curve.startWidth;
41951 var drawSteps = Math.floor(curve.length()) * 2;
41953 ctx.fillStyle = color;
41954 for (var i = 0; i < drawSteps; i += 1) {
41955 var t = i / drawSteps;
41961 var x = uuu * curve.startPoint.x;
41962 x += 3 * uu * t * curve.control1.x;
41963 x += 3 * u * tt * curve.control2.x;
41964 x += ttt * curve.endPoint.x;
41965 var y = uuu * curve.startPoint.y;
41966 y += 3 * uu * t * curve.control1.y;
41967 y += 3 * u * tt * curve.control2.y;
41968 y += ttt * curve.endPoint.y;
41969 var width = curve.startWidth + ttt * widthDelta;
41970 this.drawCurveSegment(x, y, width);
41976 drawCurveSegment: function (x, y, width) {
41977 var ctx = this.canvasElCtx();
41979 ctx.arc(x, y, width, 0, 2 * Math.PI, false);
41980 this.is_empty = false;
41985 var ctx = this.canvasElCtx();
41986 var canvas = this.canvasEl().dom;
41987 ctx.fillStyle = this.bg_color;
41988 ctx.clearRect(0, 0, canvas.width, canvas.height);
41989 ctx.fillRect(0, 0, canvas.width, canvas.height);
41990 this.curve_data = [];
41992 this.is_empty = true;
41997 return this.el.select('input',true).first();
42000 canvasEl: function()
42002 return this.el.select('canvas',true).first();
42005 canvasElCtx: function()
42007 return this.el.select('canvas',true).first().dom.getContext('2d');
42010 getImage: function(type)
42012 if(this.is_empty) {
42017 return this.canvasEl().dom.toDataURL('image/'+type, 1);
42020 drawFromImage: function(img_src)
42022 var img = new Image();
42024 img.onload = function(){
42025 this.canvasElCtx().drawImage(img, 0, 0);
42030 this.is_empty = false;
42033 selectImage: function()
42035 this.fileEl().dom.click();
42038 uploadImage: function(e)
42040 var reader = new FileReader();
42042 reader.onload = function(e){
42043 var img = new Image();
42044 img.onload = function(){
42046 this.canvasElCtx().drawImage(img, 0, 0);
42048 img.src = e.target.result;
42051 reader.readAsDataURL(e.target.files[0]);
42054 // Bezier Point Constructor
42055 Point: (function () {
42056 function Point(x, y, time) {
42059 this.time = time || Date.now();
42061 Point.prototype.distanceTo = function (start) {
42062 return Math.sqrt(Math.pow(this.x - start.x, 2) + Math.pow(this.y - start.y, 2));
42064 Point.prototype.equals = function (other) {
42065 return this.x === other.x && this.y === other.y && this.time === other.time;
42067 Point.prototype.velocityFrom = function (start) {
42068 return this.time !== start.time
42069 ? this.distanceTo(start) / (this.time - start.time)
42076 // Bezier Constructor
42077 Bezier: (function () {
42078 function Bezier(startPoint, control2, control1, endPoint, startWidth, endWidth) {
42079 this.startPoint = startPoint;
42080 this.control2 = control2;
42081 this.control1 = control1;
42082 this.endPoint = endPoint;
42083 this.startWidth = startWidth;
42084 this.endWidth = endWidth;
42086 Bezier.fromPoints = function (points, widths, scope) {
42087 var c2 = this.calculateControlPoints(points[0], points[1], points[2], scope).c2;
42088 var c3 = this.calculateControlPoints(points[1], points[2], points[3], scope).c1;
42089 return new Bezier(points[1], c2, c3, points[2], widths.start, widths.end);
42091 Bezier.calculateControlPoints = function (s1, s2, s3, scope) {
42092 var dx1 = s1.x - s2.x;
42093 var dy1 = s1.y - s2.y;
42094 var dx2 = s2.x - s3.x;
42095 var dy2 = s2.y - s3.y;
42096 var m1 = { x: (s1.x + s2.x) / 2.0, y: (s1.y + s2.y) / 2.0 };
42097 var m2 = { x: (s2.x + s3.x) / 2.0, y: (s2.y + s3.y) / 2.0 };
42098 var l1 = Math.sqrt(dx1 * dx1 + dy1 * dy1);
42099 var l2 = Math.sqrt(dx2 * dx2 + dy2 * dy2);
42100 var dxm = m1.x - m2.x;
42101 var dym = m1.y - m2.y;
42102 var k = l2 / (l1 + l2);
42103 var cm = { x: m2.x + dxm * k, y: m2.y + dym * k };
42104 var tx = s2.x - cm.x;
42105 var ty = s2.y - cm.y;
42107 c1: new scope.Point(m1.x + tx, m1.y + ty),
42108 c2: new scope.Point(m2.x + tx, m2.y + ty)
42111 Bezier.prototype.length = function () {
42116 for (var i = 0; i <= steps; i += 1) {
42118 var cx = this.point(t, this.startPoint.x, this.control1.x, this.control2.x, this.endPoint.x);
42119 var cy = this.point(t, this.startPoint.y, this.control1.y, this.control2.y, this.endPoint.y);
42121 var xdiff = cx - px;
42122 var ydiff = cy - py;
42123 length += Math.sqrt(xdiff * xdiff + ydiff * ydiff);
42130 Bezier.prototype.point = function (t, start, c1, c2, end) {
42131 return (start * (1.0 - t) * (1.0 - t) * (1.0 - t))
42132 + (3.0 * c1 * (1.0 - t) * (1.0 - t) * t)
42133 + (3.0 * c2 * (1.0 - t) * t * t)
42134 + (end * t * t * t);
42139 throttleStroke: function(fn, wait) {
42140 if (wait === void 0) { wait = 250; }
42142 var timeout = null;
42146 var later = function () {
42147 previous = Date.now();
42149 result = fn.apply(storedContext, storedArgs);
42151 storedContext = null;
42155 return function wrapper() {
42157 for (var _i = 0; _i < arguments.length; _i++) {
42158 args[_i] = arguments[_i];
42160 var now = Date.now();
42161 var remaining = wait - (now - previous);
42162 storedContext = this;
42164 if (remaining <= 0 || remaining > wait) {
42166 clearTimeout(timeout);
42170 result = fn.apply(storedContext, storedArgs);
42172 storedContext = null;
42176 else if (!timeout) {
42177 timeout = window.setTimeout(later, remaining);