2 * set the version of bootstrap based on the stylesheet...
6 Roo.bootstrap.version = ( function() {
8 Roo.each(document.styleSheets, function(s) {
9 if ( s.href && s.href.match(/css-bootstrap4/)) {
14 Roo.Element.prototype.visibilityMode = Roo.Element.DISPLAY;
19 * Ext JS Library 1.1.1
20 * Copyright(c) 2006-2007, Ext JS, LLC.
22 * Originally Released Under LGPL - original licence link has changed is not relivant.
25 * <script type="text/javascript">
31 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
32 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
33 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
36 * @param {Object} config The config object
38 Roo.Shadow = function(config){
39 Roo.apply(this, config);
40 if(typeof this.mode != "string"){
41 this.mode = this.defaultMode;
43 var o = this.offset, a = {h: 0};
44 var rad = Math.floor(this.offset/2);
45 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
51 a.l -= this.offset + rad;
52 a.t -= this.offset + rad;
63 a.l -= (this.offset - rad);
64 a.t -= this.offset + rad;
66 a.w -= (this.offset - rad)*2;
77 a.l -= (this.offset - rad);
78 a.t -= (this.offset - rad);
80 a.w -= (this.offset + rad + 1);
81 a.h -= (this.offset + rad);
90 Roo.Shadow.prototype = {
93 * The shadow display mode. Supports the following options:<br />
94 * sides: Shadow displays on both sides and bottom only<br />
95 * frame: Shadow displays equally on all four sides<br />
96 * drop: Traditional bottom-right drop shadow (default)
99 * @cfg {String} offset
100 * The number of pixels to offset the shadow from the element (defaults to 4)
108 * Displays the shadow under the target element
109 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
111 show : function(target){
112 target = Roo.get(target);
114 this.el = Roo.Shadow.Pool.pull();
115 if(this.el.dom.nextSibling != target.dom){
116 this.el.insertBefore(target);
119 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
121 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
124 target.getLeft(true),
129 this.el.dom.style.display = "block";
133 * Returns true if the shadow is visible, else false
135 isVisible : function(){
136 return this.el ? true : false;
140 * Direct alignment when values are already available. Show must be called at least once before
141 * calling this method to ensure it is initialized.
142 * @param {Number} left The target element left position
143 * @param {Number} top The target element top position
144 * @param {Number} width The target element width
145 * @param {Number} height The target element height
147 realign : function(l, t, w, h){
151 var a = this.adjusts, d = this.el.dom, s = d.style;
153 s.left = (l+a.l)+"px";
154 s.top = (t+a.t)+"px";
155 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
157 if(s.width != sws || s.height != shs){
161 var cn = d.childNodes;
162 var sww = Math.max(0, (sw-12))+"px";
163 cn[0].childNodes[1].style.width = sww;
164 cn[1].childNodes[1].style.width = sww;
165 cn[2].childNodes[1].style.width = sww;
166 cn[1].style.height = Math.max(0, (sh-12))+"px";
176 this.el.dom.style.display = "none";
177 Roo.Shadow.Pool.push(this.el);
183 * Adjust the z-index of this shadow
184 * @param {Number} zindex The new z-index
186 setZIndex : function(z){
189 this.el.setStyle("z-index", z);
194 // Private utility class that manages the internal Shadow cache
195 Roo.Shadow.Pool = function(){
197 var markup = Roo.isIE ?
198 '<div class="x-ie-shadow"></div>' :
199 '<div class="x-shadow"><div class="xst"><div class="xstl"></div><div class="xstc"></div><div class="xstr"></div></div><div class="xsc"><div class="xsml"></div><div class="xsmc"></div><div class="xsmr"></div></div><div class="xsb"><div class="xsbl"></div><div class="xsbc"></div><div class="xsbr"></div></div></div>';
204 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
205 sh.autoBoxAdjust = false;
217 * base class for bootstrap elements.
221 Roo.bootstrap = Roo.bootstrap || {};
223 * @class Roo.bootstrap.Component
224 * @extends Roo.Component
225 * Bootstrap Component base class
226 * @cfg {String} cls css class
227 * @cfg {String} style any extra css
228 * @cfg {Object} xattr extra attributes to add to 'element' (used by builder to store stuff.)
229 * @cfg {Boolean} can_build_overlaid True if element can be rebuild from a HTML page
230 * @cfg {string} dataId cutomer id
231 * @cfg {string} name Specifies name attribute
232 * @cfg {string} tooltip Text for the tooltip
233 * @cfg {string} container_method method to fetch parents container element (used by NavHeaderbar - getHeaderChildContainer)
234 * @cfg {string|object} visibilityEl (el|parent) What element to use for visibility (@see getVisibilityEl())
237 * Do not use directly - it does not do anything..
238 * @param {Object} config The config object
243 Roo.bootstrap.Component = function(config){
244 Roo.bootstrap.Component.superclass.constructor.call(this, config);
248 * @event childrenrendered
249 * Fires when the children have been rendered..
250 * @param {Roo.bootstrap.Component} this
252 "childrenrendered" : true
261 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent, {
264 allowDomMove : false, // to stop relocations in parent onRender...
274 * Initialize Events for the element
276 initEvents : function() { },
282 can_build_overlaid : true,
284 container_method : false,
291 // returns the parent component..
292 return Roo.ComponentMgr.get(this.parentId)
298 onRender : function(ct, position)
300 // Roo.log("Call onRender: " + this.xtype);
302 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
305 if (this.el.attr('xtype')) {
306 this.el.attr('xtypex', this.el.attr('xtype'));
307 this.el.dom.removeAttribute('xtype');
317 var cfg = Roo.apply({}, this.getAutoCreate());
319 cfg.id = this.id || Roo.id();
321 // fill in the extra attributes
322 if (this.xattr && typeof(this.xattr) =='object') {
323 for (var i in this.xattr) {
324 cfg[i] = this.xattr[i];
329 cfg.dataId = this.dataId;
333 cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
336 if (this.style) { // fixme needs to support more complex style data.
337 cfg.style = this.style;
341 cfg.name = this.name;
344 this.el = ct.createChild(cfg, position);
347 this.tooltipEl().attr('tooltip', this.tooltip);
350 if(this.tabIndex !== undefined){
351 this.el.dom.setAttribute('tabIndex', this.tabIndex);
358 * Fetch the element to add children to
359 * @return {Roo.Element} defaults to this.el
361 getChildContainer : function()
366 * Fetch the element to display the tooltip on.
367 * @return {Roo.Element} defaults to this.el
369 tooltipEl : function()
374 addxtype : function(tree,cntr)
378 cn = Roo.factory(tree);
379 //Roo.log(['addxtype', cn]);
381 cn.parentType = this.xtype; //??
382 cn.parentId = this.id;
384 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
385 if (typeof(cn.container_method) == 'string') {
386 cntr = cn.container_method;
390 var has_flexy_each = (typeof(tree['flexy:foreach']) != 'undefined');
392 var has_flexy_if = (typeof(tree['flexy:if']) != 'undefined');
394 var build_from_html = Roo.XComponent.build_from_html;
396 var is_body = (tree.xtype == 'Body') ;
398 var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
400 var self_cntr_el = Roo.get(this[cntr](false));
402 // do not try and build conditional elements
403 if ((has_flexy_each || has_flexy_if || this.can_build_overlaid == false ) && build_from_html) {
407 if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
408 if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
409 return this.addxtypeChild(tree,cntr, is_body);
412 var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
415 return this.addxtypeChild(Roo.apply({}, tree),cntr);
418 Roo.log('skipping render');
424 if (!build_from_html) {
428 // this i think handles overlaying multiple children of the same type
429 // with the sam eelement.. - which might be buggy..
431 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
437 if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
441 ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
448 addxtypeChild : function (tree, cntr, is_body)
450 Roo.debug && Roo.log('addxtypeChild:' + cntr);
452 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
455 var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
456 (typeof(tree['flexy:foreach']) != 'undefined');
460 skip_children = false;
461 // render the element if it's not BODY.
464 // if parent was disabled, then do not try and create the children..
465 if(!this[cntr](true)){
470 cn = Roo.factory(tree);
472 cn.parentType = this.xtype; //??
473 cn.parentId = this.id;
475 var build_from_html = Roo.XComponent.build_from_html;
478 // does the container contain child eleemnts with 'xtype' attributes.
479 // that match this xtype..
480 // note - when we render we create these as well..
481 // so we should check to see if body has xtype set.
482 if (build_from_html && Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
484 var self_cntr_el = Roo.get(this[cntr](false));
485 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
487 //Roo.log(Roo.XComponent.build_from_html);
488 //Roo.log("got echild:");
491 // there is a scenario where some of the child elements are flexy:if (and all of the same type)
492 // and are not displayed -this causes this to use up the wrong element when matching.
493 // at present the only work around for this is to nest flexy:if elements in another element that is always rendered.
496 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
497 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
503 //echild.dom.removeAttribute('xtype');
505 Roo.debug && Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
506 Roo.debug && Roo.log(self_cntr_el);
507 Roo.debug && Roo.log(echild);
508 Roo.debug && Roo.log(cn);
514 // if object has flexy:if - then it may or may not be rendered.
515 if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) {
516 // skip a flexy if element.
517 Roo.debug && Roo.log('skipping render');
518 Roo.debug && Roo.log(tree);
520 Roo.debug && Roo.log('skipping all children');
521 skip_children = true;
526 // actually if flexy:foreach is found, we really want to create
527 // multiple copies here...
529 //Roo.log(this[cntr]());
530 // some elements do not have render methods.. like the layouts...
532 if(this[cntr](true) === false){
537 cn.render && cn.render(this[cntr](true));
540 // then add the element..
547 if (typeof (tree.menu) != 'undefined') {
548 tree.menu.parentType = cn.xtype;
549 tree.menu.triggerEl = cn.el;
550 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
554 if (!tree.items || !tree.items.length) {
556 //Roo.log(["no children", this]);
561 var items = tree.items;
564 //Roo.log(items.length);
566 if (!skip_children) {
567 for(var i =0;i < items.length;i++) {
568 // Roo.log(['add child', items[i]]);
569 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
575 //Roo.log("fire childrenrendered");
577 cn.fireEvent('childrenrendered', this);
583 * Set the element that will be used to show or hide
585 setVisibilityEl : function(el)
587 this.visibilityEl = el;
591 * Get the element that will be used to show or hide
593 getVisibilityEl : function()
595 if (typeof(this.visibilityEl) == 'object') {
596 return this.visibilityEl;
599 if (typeof(this.visibilityEl) == 'string') {
600 return this.visibilityEl == 'parent' ? this.parent().getEl() : this.getEl();
607 * Show a component - removes 'hidden' class
611 if(!this.getVisibilityEl()){
615 this.getVisibilityEl().removeClass(['hidden','d-none']);
617 this.fireEvent('show', this);
622 * Hide a component - adds 'hidden' class
626 if(!this.getVisibilityEl()){
630 this.getVisibilityEl().addClass(['hidden','d-none']);
632 this.fireEvent('hide', this);
645 * @class Roo.bootstrap.Element
646 * @extends Roo.bootstrap.Component
647 * Bootstrap Element class
648 * @cfg {String} html contents of the element
649 * @cfg {String} tag tag of the element
650 * @cfg {String} cls class of the element
651 * @cfg {Boolean} preventDefault (true|false) default false
652 * @cfg {Boolean} clickable (true|false) default false
655 * Create a new Element
656 * @param {Object} config The config object
659 Roo.bootstrap.Element = function(config){
660 Roo.bootstrap.Element.superclass.constructor.call(this, config);
666 * When a element is chick
667 * @param {Roo.bootstrap.Element} this
668 * @param {Roo.EventObject} e
674 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
679 preventDefault: false,
682 getAutoCreate : function(){
686 // cls: this.cls, double assign in parent class Component.js :: onRender
693 initEvents: function()
695 Roo.bootstrap.Element.superclass.initEvents.call(this);
698 this.el.on('click', this.onClick, this);
703 onClick : function(e)
705 if(this.preventDefault){
709 this.fireEvent('click', this, e);
712 getValue : function()
714 return this.el.dom.innerHTML;
717 setValue : function(value)
719 this.el.dom.innerHTML = value;
734 * @class Roo.bootstrap.DropTarget
735 * @extends Roo.bootstrap.Element
736 * Bootstrap DropTarget class
738 * @cfg {string} name dropable name
741 * Create a new Dropable Area
742 * @param {Object} config The config object
745 Roo.bootstrap.DropTarget = function(config){
746 Roo.bootstrap.DropTarget.superclass.constructor.call(this, config);
752 * When a element is chick
753 * @param {Roo.bootstrap.Element} this
754 * @param {Roo.EventObject} e
760 Roo.extend(Roo.bootstrap.DropTarget, Roo.bootstrap.Element, {
763 getAutoCreate : function(){
768 initEvents: function()
770 Roo.bootstrap.DropTarget.superclass.initEvents.call(this);
771 this.dropZone = new Roo.dd.DropTarget(this.getEl(), {
774 drop : this.dragDrop.createDelegate(this),
775 enter : this.dragEnter.createDelegate(this),
776 out : this.dragOut.createDelegate(this),
777 over : this.dragOver.createDelegate(this)
781 this.dropZone.DDM.useCache = false // so data gets refreshed when we resize stuff
784 dragDrop : function(source,e,data)
786 // user has to decide how to impliment this.
789 //this.fireEvent('drop', this, source, e ,data);
793 dragEnter : function(n, dd, e, data)
795 // probably want to resize the element to match the dropped element..
797 this.originalSize = this.el.getSize();
798 this.el.setSize( n.el.getSize());
799 this.dropZone.DDM.refreshCache(this.name);
800 Roo.log([n, dd, e, data]);
803 dragOut : function(value)
805 // resize back to normal
807 this.el.setSize(this.originalSize);
808 this.dropZone.resetConstraints();
811 dragOver : function()
828 * @class Roo.bootstrap.Body
829 * @extends Roo.bootstrap.Component
830 * Bootstrap Body class
834 * @param {Object} config The config object
837 Roo.bootstrap.Body = function(config){
839 config = config || {};
841 Roo.bootstrap.Body.superclass.constructor.call(this, config);
842 this.el = Roo.get(config.el ? config.el : document.body );
843 if (this.cls && this.cls.length) {
844 Roo.get(document.body).addClass(this.cls);
848 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
850 is_body : true,// just to make sure it's constructed?
855 onRender : function(ct, position)
857 /* Roo.log("Roo.bootstrap.Body - onRender");
858 if (this.cls && this.cls.length) {
859 Roo.get(document.body).addClass(this.cls);
878 * @class Roo.bootstrap.ButtonGroup
879 * @extends Roo.bootstrap.Component
880 * Bootstrap ButtonGroup class
881 * @cfg {String} size lg | sm | xs (default empty normal)
882 * @cfg {String} align vertical | justified (default none)
883 * @cfg {String} direction up | down (default down)
884 * @cfg {Boolean} toolbar false | true
885 * @cfg {Boolean} btn true | false
890 * @param {Object} config The config object
893 Roo.bootstrap.ButtonGroup = function(config){
894 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
897 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
905 getAutoCreate : function(){
911 cfg.html = this.html || cfg.html;
922 if (['vertical','justified'].indexOf(this.align)!==-1) {
923 cfg.cls = 'btn-group-' + this.align;
925 if (this.align == 'justified') {
926 console.log(this.items);
930 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
931 cfg.cls += ' btn-group-' + this.size;
934 if (this.direction == 'up') {
935 cfg.cls += ' dropup' ;
941 * Add a button to the group (similar to NavItem API.)
943 addItem : function(cfg)
945 var cn = new Roo.bootstrap.Button(cfg);
947 cn.parentId = this.id;
948 cn.onRender(this.el, null);
962 * @class Roo.bootstrap.Button
963 * @extends Roo.bootstrap.Component
964 * Bootstrap Button class
965 * @cfg {String} html The button content
966 * @cfg {String} weight (default|primary|secondary|success|info|warning|danger|link|light|dark) default
967 * @cfg {String} badge_weight (default|primary|secondary|success|info|warning|danger|link|light|dark) default (same as button)
968 * @cfg {Boolean} outline default false (except for weight=default which emulates old behaveiour with an outline)
969 * @cfg {String} size (lg|sm|xs)
970 * @cfg {String} tag (a|input|submit)
971 * @cfg {String} href empty or href
972 * @cfg {Boolean} disabled default false;
973 * @cfg {Boolean} isClose default false;
974 * @cfg {String} glyphicon depricated - use fa
975 * @cfg {String} fa fontawesome icon - eg. 'comment' - without the fa/fas etc..
976 * @cfg {String} badge text for badge
977 * @cfg {String} theme (default|glow)
978 * @cfg {Boolean} inverse dark themed version
979 * @cfg {Boolean} toggle is it a slidy toggle button
980 * @cfg {Boolean} pressed default null - if the button ahs active state
981 * @cfg {String} ontext text for on slidy toggle state
982 * @cfg {String} offtext text for off slidy toggle state
983 * @cfg {Boolean} preventDefault default true (stop click event triggering the URL if it's a link.)
984 * @cfg {Boolean} removeClass remove the standard class..
985 * @cfg {String} target (_self|_blank|_parent|_top|other) target for a href.
986 * @cfg {Boolean} grpup if parent is a btn group - then it turns it into a toogleGroup.
989 * Create a new button
990 * @param {Object} config The config object
994 Roo.bootstrap.Button = function(config){
995 Roo.bootstrap.Button.superclass.constructor.call(this, config);
1001 * When a button is pressed
1002 * @param {Roo.bootstrap.Button} btn
1003 * @param {Roo.EventObject} e
1008 * When a button is double clicked
1009 * @param {Roo.bootstrap.Button} btn
1010 * @param {Roo.EventObject} e
1015 * After the button has been toggles
1016 * @param {Roo.bootstrap.Button} btn
1017 * @param {Roo.EventObject} e
1018 * @param {boolean} pressed (also available as button.pressed)
1024 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
1045 preventDefault: true,
1054 getAutoCreate : function(){
1062 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
1063 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
1064 this.tag = 'button';
1068 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
1070 if (this.toggle == true) {
1073 cls: 'slider-frame roo-button',
1077 'data-on-text':'ON',
1078 'data-off-text':'OFF',
1079 cls: 'slider-button',
1084 // why are we validating the weights?
1085 if (Roo.bootstrap.Button.weights.indexOf(this.weight) > -1) {
1086 cfg.cls += ' ' + this.weight;
1093 cfg.cls += ' close';
1095 cfg["aria-hidden"] = true;
1097 cfg.html = "×";
1103 if (this.theme==='default') {
1104 cfg.cls = 'btn roo-button';
1106 //if (this.parentType != 'Navbar') {
1107 this.weight = this.weight.length ? this.weight : 'default';
1109 if (Roo.bootstrap.Button.weights.indexOf(this.weight) > -1) {
1111 var outline = this.outline || this.weight == 'default' ? 'outline-' : '';
1112 var weight = this.weight == 'default' ? 'secondary' : this.weight;
1113 cfg.cls += ' btn-' + outline + weight;
1114 if (this.weight == 'default') {
1116 cfg.cls += ' btn-' + this.weight;
1119 } else if (this.theme==='glow') {
1122 cfg.cls = 'btn-glow roo-button';
1124 if (Roo.bootstrap.Button.weights.indexOf(this.weight) > -1) {
1126 cfg.cls += ' ' + this.weight;
1132 this.cls += ' inverse';
1136 if (this.active || this.pressed === true) {
1137 cfg.cls += ' active';
1140 if (this.disabled) {
1141 cfg.disabled = 'disabled';
1145 Roo.log('changing to ul' );
1147 this.glyphicon = 'caret';
1148 if (Roo.bootstrap.version == 4) {
1149 this.fa = 'caret-down';
1154 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
1156 //gsRoo.log(this.parentType);
1157 if (this.parentType === 'Navbar' && !this.parent().bar) {
1158 Roo.log('changing to li?');
1167 href : this.href || '#'
1170 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
1171 cfg.cls += ' dropdown';
1178 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
1180 if (this.glyphicon) {
1181 cfg.html = ' ' + cfg.html;
1186 cls: 'glyphicon glyphicon-' + this.glyphicon
1191 cfg.html = ' ' + cfg.html;
1196 cls: 'fa fas fa-' + this.fa
1206 // cfg.cls='btn roo-button';
1210 var value = cfg.html;
1215 cls: 'glyphicon glyphicon-' + this.glyphicon,
1222 cls: 'fa fas fa-' + this.fa,
1227 var bw = this.badge_weight.length ? this.badge_weight :
1228 (this.weight.length ? this.weight : 'secondary');
1229 bw = bw == 'default' ? 'secondary' : bw;
1235 cls: 'badge badge-' + bw,
1244 cfg.cls += ' dropdown';
1245 cfg.html = typeof(cfg.html) != 'undefined' ?
1246 cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
1249 if (cfg.tag !== 'a' && this.href !== '') {
1250 throw "Tag must be a to set href.";
1251 } else if (this.href.length > 0) {
1252 cfg.href = this.href;
1255 if(this.removeClass){
1260 cfg.target = this.target;
1265 initEvents: function() {
1266 // Roo.log('init events?');
1267 // Roo.log(this.el.dom);
1270 if (typeof (this.menu) != 'undefined') {
1271 this.menu.parentType = this.xtype;
1272 this.menu.triggerEl = this.el;
1273 this.addxtype(Roo.apply({}, this.menu));
1277 if (this.el.hasClass('roo-button')) {
1278 this.el.on('click', this.onClick, this);
1279 this.el.on('dblclick', this.onDblClick, this);
1281 this.el.select('.roo-button').on('click', this.onClick, this);
1282 this.el.select('.roo-button').on('dblclick', this.onDblClick, this);
1286 if(this.removeClass){
1287 this.el.on('click', this.onClick, this);
1290 if (this.group === true) {
1291 if (this.pressed === false || this.pressed === true) {
1294 this.pressed = false;
1295 this.setActive(this.pressed);
1300 this.el.enableDisplayMode();
1303 onClick : function(e)
1305 if (this.disabled) {
1309 Roo.log('button on click ');
1310 if(this.preventDefault){
1319 this.setActive(true);
1320 var pi = this.parent().items;
1321 for (var i = 0;i < pi.length;i++) {
1322 if (this == pi[i]) {
1325 if (pi[i].el.hasClass('roo-button')) {
1326 pi[i].setActive(false);
1329 this.fireEvent('click', this, e);
1333 if (this.pressed === true || this.pressed === false) {
1334 this.toggleActive(e);
1338 this.fireEvent('click', this, e);
1340 onDblClick: function(e)
1342 if (this.disabled) {
1345 if(this.preventDefault){
1348 this.fireEvent('dblclick', this, e);
1351 * Enables this button
1355 this.disabled = false;
1356 this.el.removeClass('disabled');
1360 * Disable this button
1362 disable : function()
1364 this.disabled = true;
1365 this.el.addClass('disabled');
1368 * sets the active state on/off,
1369 * @param {Boolean} state (optional) Force a particular state
1371 setActive : function(v) {
1373 this.el[v ? 'addClass' : 'removeClass']('active');
1377 * toggles the current active state
1379 toggleActive : function(e)
1381 this.setActive(!this.pressed); // this modifies pressed...
1382 this.fireEvent('toggle', this, e, this.pressed);
1385 * get the current active state
1386 * @return {boolean} true if it's active
1388 isActive : function()
1390 return this.el.hasClass('active');
1393 * set the text of the first selected button
1395 setText : function(str)
1397 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
1400 * get the text of the first selected button
1402 getText : function()
1404 return this.el.select('.roo-button-text',true).first().dom.innerHTML;
1407 setWeight : function(str)
1409 this.el.removeClass(Roo.bootstrap.Button.weights.map(function(w) { return 'btn-' + w; } ) );
1410 this.el.removeClass(Roo.bootstrap.Button.weights.map(function(w) { return 'btn-outline-' + w; } ) );
1412 var outline = this.outline ? 'outline-' : '';
1413 if (str == 'default') {
1414 this.el.addClass('btn-default btn-outline-secondary');
1417 this.el.addClass('btn-' + outline + str);
1422 // fixme - this is probably generic bootstrap - should go in some kind of enum file.. - like sizes.
1424 Roo.bootstrap.Button.weights = [
1444 * @class Roo.bootstrap.Column
1445 * @extends Roo.bootstrap.Component
1446 * Bootstrap Column class
1447 * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
1448 * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
1449 * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
1450 * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
1451 * @cfg {Number} xsoff colspan offset out of 12 for mobile-sized screens or 0 for hidden
1452 * @cfg {Number} smoff colspan offset out of 12 for tablet-sized screens or 0 for hidden
1453 * @cfg {Number} mdoff colspan offset out of 12 for computer-sized screens or 0 for hidden
1454 * @cfg {Number} lgoff colspan offset out of 12 for large computer-sized screens or 0 for hidden
1457 * @cfg {Boolean} hidden (true|false) hide the element
1458 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
1459 * @cfg {String} fa (ban|check|...) font awesome icon
1460 * @cfg {Number} fasize (1|2|....) font awsome size
1462 * @cfg {String} icon (info-sign|check|...) glyphicon name
1464 * @cfg {String} html content of column.
1467 * Create a new Column
1468 * @param {Object} config The config object
1471 Roo.bootstrap.Column = function(config){
1472 Roo.bootstrap.Column.superclass.constructor.call(this, config);
1475 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
1493 getAutoCreate : function(){
1494 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
1502 var sizes = ['xs','sm','md','lg'];
1503 sizes.map(function(size ,ix){
1504 //Roo.log( size + ':' + settings[size]);
1506 if (settings[size+'off'] !== false) {
1507 cfg.cls += ' col-' + size + '-offset-' + settings[size+'off'] ;
1510 if (settings[size] === false) {
1514 if (!settings[size]) { // 0 = hidden
1515 cfg.cls += ' hidden-' + size + ' hidden-' + size + '-down';
1517 for (var i = ix; i > -1; i--) {
1518 cfg.cls += ' d-' + sizes[i] + '-none';
1524 cfg.cls += ' col-' + size + '-' + settings[size] + (
1525 size == 'xs' ? (' col-' + settings[size] ) : '' // bs4 col-{num} replaces col-xs
1531 cfg.cls += ' hidden';
1534 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1535 cfg.cls +=' alert alert-' + this.alert;
1539 if (this.html.length) {
1540 cfg.html = this.html;
1544 if (this.fasize > 1) {
1545 fasize = ' fa-' + this.fasize + 'x';
1547 cfg.html = '<i class="fa fa-'+this.fa + fasize + '"></i>' + (cfg.html || '');
1552 cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + (cfg.html || '');
1571 * @class Roo.bootstrap.Container
1572 * @extends Roo.bootstrap.Component
1573 * Bootstrap Container class
1574 * @cfg {Boolean} jumbotron is it a jumbotron element
1575 * @cfg {String} html content of element
1576 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
1577 * @cfg {String} panel (default|primary|success|info|warning|danger) render as panel - type - primary/success.....
1578 * @cfg {String} header content of header (for panel)
1579 * @cfg {String} footer content of footer (for panel)
1580 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
1581 * @cfg {String} tag (header|aside|section) type of HTML tag.
1582 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
1583 * @cfg {String} fa font awesome icon
1584 * @cfg {String} icon (info-sign|check|...) glyphicon name
1585 * @cfg {Boolean} hidden (true|false) hide the element
1586 * @cfg {Boolean} expandable (true|false) default false
1587 * @cfg {Boolean} expanded (true|false) default true
1588 * @cfg {String} rheader contet on the right of header
1589 * @cfg {Boolean} clickable (true|false) default false
1593 * Create a new Container
1594 * @param {Object} config The config object
1597 Roo.bootstrap.Container = function(config){
1598 Roo.bootstrap.Container.superclass.constructor.call(this, config);
1604 * After the panel has been expand
1606 * @param {Roo.bootstrap.Container} this
1611 * After the panel has been collapsed
1613 * @param {Roo.bootstrap.Container} this
1618 * When a element is chick
1619 * @param {Roo.bootstrap.Container} this
1620 * @param {Roo.EventObject} e
1626 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
1644 getChildContainer : function() {
1650 if (this.panel.length) {
1651 return this.el.select('.panel-body',true).first();
1658 getAutoCreate : function(){
1661 tag : this.tag || 'div',
1665 if (this.jumbotron) {
1666 cfg.cls = 'jumbotron';
1671 // - this is applied by the parent..
1673 // cfg.cls = this.cls + '';
1676 if (this.sticky.length) {
1678 var bd = Roo.get(document.body);
1679 if (!bd.hasClass('bootstrap-sticky')) {
1680 bd.addClass('bootstrap-sticky');
1681 Roo.select('html',true).setStyle('height', '100%');
1684 cfg.cls += 'bootstrap-sticky-' + this.sticky;
1688 if (this.well.length) {
1689 switch (this.well) {
1692 cfg.cls +=' well well-' +this.well;
1701 cfg.cls += ' hidden';
1705 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1706 cfg.cls +=' alert alert-' + this.alert;
1711 if (this.panel.length) {
1712 cfg.cls += ' panel panel-' + this.panel;
1714 if (this.header.length) {
1718 if(this.expandable){
1720 cfg.cls = cfg.cls + ' expandable';
1724 cls: (this.expanded ? 'fa fa-minus' : 'fa fa-plus')
1732 cls : 'panel-title',
1733 html : (this.expandable ? ' ' : '') + this.header
1737 cls: 'panel-header-right',
1743 cls : 'panel-heading',
1744 style : this.expandable ? 'cursor: pointer' : '',
1752 cls : 'panel-body' + (this.expanded ? '' : ' hide'),
1757 if (this.footer.length) {
1759 cls : 'panel-footer',
1768 body.html = this.html || cfg.html;
1769 // prefix with the icons..
1771 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1774 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1779 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1780 cfg.cls = 'container';
1786 initEvents: function()
1788 if(this.expandable){
1789 var headerEl = this.headerEl();
1792 headerEl.on('click', this.onToggleClick, this);
1797 this.el.on('click', this.onClick, this);
1802 onToggleClick : function()
1804 var headerEl = this.headerEl();
1820 if(this.fireEvent('expand', this)) {
1822 this.expanded = true;
1824 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).show();
1826 this.el.select('.panel-body',true).first().removeClass('hide');
1828 var toggleEl = this.toggleEl();
1834 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-minus']);
1839 collapse : function()
1841 if(this.fireEvent('collapse', this)) {
1843 this.expanded = false;
1845 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).hide();
1846 this.el.select('.panel-body',true).first().addClass('hide');
1848 var toggleEl = this.toggleEl();
1854 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-plus']);
1858 toggleEl : function()
1860 if(!this.el || !this.panel.length || !this.header.length || !this.expandable){
1864 return this.el.select('.panel-heading .fa',true).first();
1867 headerEl : function()
1869 if(!this.el || !this.panel.length || !this.header.length){
1873 return this.el.select('.panel-heading',true).first()
1878 if(!this.el || !this.panel.length){
1882 return this.el.select('.panel-body',true).first()
1885 titleEl : function()
1887 if(!this.el || !this.panel.length || !this.header.length){
1891 return this.el.select('.panel-title',true).first();
1894 setTitle : function(v)
1896 var titleEl = this.titleEl();
1902 titleEl.dom.innerHTML = v;
1905 getTitle : function()
1908 var titleEl = this.titleEl();
1914 return titleEl.dom.innerHTML;
1917 setRightTitle : function(v)
1919 var t = this.el.select('.panel-header-right',true).first();
1925 t.dom.innerHTML = v;
1928 onClick : function(e)
1932 this.fireEvent('click', this, e);
1939 * This is BS4's Card element.. - similar to our containers probably..
1943 * @class Roo.bootstrap.Card
1944 * @extends Roo.bootstrap.Component
1945 * Bootstrap Card class
1948 * possible... may not be implemented..
1949 * @cfg {String} header_image src url of image.
1950 * @cfg {String|Object} header
1951 * @cfg {Number} header_size (0|1|2|3|4|5) H1 or H2 etc.. 0 indicates default
1952 * @cfg {Number} header_weight (primary|secondary|success|info|warning|danger|light|dark)
1954 * @cfg {String} title
1955 * @cfg {String} subtitle
1956 * @cfg {String|Boolean} html -- html contents - or just use children.. use false to hide it..
1957 * @cfg {String} footer
1959 * @cfg {String} weight (primary|warning|info|danger|secondary|success|light|dark)
1961 * @cfg {String} margin (0|1|2|3|4|5|auto)
1962 * @cfg {String} margin_top (0|1|2|3|4|5|auto)
1963 * @cfg {String} margin_bottom (0|1|2|3|4|5|auto)
1964 * @cfg {String} margin_left (0|1|2|3|4|5|auto)
1965 * @cfg {String} margin_right (0|1|2|3|4|5|auto)
1966 * @cfg {String} margin_x (0|1|2|3|4|5|auto)
1967 * @cfg {String} margin_y (0|1|2|3|4|5|auto)
1969 * @cfg {String} padding (0|1|2|3|4|5)
1970 * @cfg {String} padding_top (0|1|2|3|4|5)next_to_card
1971 * @cfg {String} padding_bottom (0|1|2|3|4|5)
1972 * @cfg {String} padding_left (0|1|2|3|4|5)
1973 * @cfg {String} padding_right (0|1|2|3|4|5)
1974 * @cfg {String} padding_x (0|1|2|3|4|5)
1975 * @cfg {String} padding_y (0|1|2|3|4|5)
1977 * @cfg {String} display (none|inline|inline-block|block|table|table-cell|table-row|flex|inline-flex)
1978 * @cfg {String} display_xs (none|inline|inline-block|block|table|table-cell|table-row|flex|inline-flex)
1979 * @cfg {String} display_sm (none|inline|inline-block|block|table|table-cell|table-row|flex|inline-flex)
1980 * @cfg {String} display_lg (none|inline|inline-block|block|table|table-cell|table-row|flex|inline-flex)
1981 * @cfg {String} display_xl (none|inline|inline-block|block|table|table-cell|table-row|flex|inline-flex)
1983 * @config {Boolean} dragable if this card can be dragged.
1984 * @config {String} drag_group group for drag
1985 * @config {Boolean} dropable if this card can recieve other cards being dropped onto it..
1986 * @config {String} drop_group group for drag
1988 * @config {Boolean} collapsable can the body be collapsed.
1989 * @config {Boolean} collapsed is the body collapsed when rendered...
1990 * @config {Boolean} rotateable can the body be rotated by clicking on it..
1991 * @config {Boolean} rotated is the body rotated when rendered...
1994 * Create a new Container
1995 * @param {Object} config The config object
1998 Roo.bootstrap.Card = function(config){
1999 Roo.bootstrap.Card.superclass.constructor.call(this, config);
2005 * When a element a card is dropped
2006 * @param {Roo.bootstrap.Card} this
2009 * @param {Roo.bootstrap.Card} move_card the card being dropped?
2010 * @param {String} position 'above' or 'below'
2011 * @param {Roo.bootstrap.Card} next_to_card What card position is relative to of 'false' for empty list.
2017 * When a element a card is rotate
2018 * @param {Roo.bootstrap.Element} this
2019 * @param {Roo.Element} n the node being dropped?
2020 * @param {Boolean} rotate status
2028 Roo.extend(Roo.bootstrap.Card, Roo.bootstrap.Component, {
2033 margin: '', /// may be better in component?
2063 collapsable : false,
2072 childContainer : false,
2073 dropEl : false, /// the dom placeholde element that indicates drop location.
2074 containerEl: false, // body container
2075 bodyEl: false, // card-body
2076 headerContainerEl : false, //
2079 layoutCls : function()
2083 Roo.log(this.margin_bottom.length);
2084 ['', 'top', 'bottom', 'left', 'right', 'x', 'y' ].forEach(function(v) {
2085 // in theory these can do margin_top : ml-xs-3 ??? but we don't support that yet
2087 if (('' + t['margin' + (v.length ? '_' : '') + v]).length) {
2088 cls += ' m' + (v.length ? v[0] : '') + '-' + t['margin' + (v.length ? '_' : '') + v];
2090 if (('' + t['padding' + (v.length ? '_' : '') + v]).length) {
2091 cls += ' p' + (v.length ? v[0] : '') + '-' + t['padding' + (v.length ? '_' : '') + v];
2095 ['', 'xs', 'sm', 'lg', 'xl'].forEach(function(v) {
2096 if (('' + t['display' + (v.length ? '_' : '') + v]).length) {
2097 cls += ' d' + (v.length ? '-' : '') + v + '-' + t['margin' + (v.length ? '_' : '') + v]
2101 // more generic support?
2109 // Roo.log("Call onRender: " + this.xtype);
2110 /* We are looking at something like this.
2112 <img src="..." class="card-img-top" alt="...">
2113 <div class="card-body">
2114 <h5 class="card-title">Card title</h5>
2115 <h6 class="card-subtitle mb-2 text-muted">Card subtitle</h6>
2117 >> this bit is really the body...
2118 <div> << we will ad dthis in hopefully it will not break shit.
2120 ** card text does not actually have any styling...
2122 <p class="card-text">This is a wider card with supporting text below as a natural lead-in to additional content. This content is a little bit longer.</p>
2125 <a href="#" class="card-link">Card link</a>
2128 <div class="card-footer">
2129 <small class="text-muted">Last updated 3 mins ago</small>
2133 getAutoCreate : function(){
2141 if (this.weight.length && this.weight != 'light') {
2142 cfg.cls += ' text-white';
2144 cfg.cls += ' text-dark'; // need as it's nested..
2146 if (this.weight.length) {
2147 cfg.cls += ' bg-' + this.weight;
2150 cfg.cls += ' ' + this.layoutCls();
2153 var hdr_ctr = false;
2154 if (this.header.length) {
2156 tag : this.header_size > 0 ? 'h' + this.header_size : 'div',
2157 cls : 'card-header ' + (this.header_weight ? 'bg-' + this.header_weight : ''),
2165 cls : 'card-header d-none ' + (this.header_weight ? 'bg-' + this.header_weight : ''),
2171 if (this.collapsable) {
2174 cls : 'd-block user-select-none',
2178 cls : 'roo-collapse-toggle fa fa-chevron-down float-right ' + (this.collapsed ? 'collapsed' : '')
2183 hdr.cn.push(hdr_ctr);
2188 cls: 'roo-card-header-ctr' + ( this.header.length ? '' : ' d-none'),
2193 if (this.header_image.length) {
2196 cls : 'card-img-top',
2197 src: this.header_image // escape?
2202 cls : 'card-img-top d-none'
2208 cls : 'card-body' + (this.html === false ? ' d-none' : ''),
2212 if (this.collapsable || this.rotateable) {
2215 cls : 'roo-collapsable collapse ' + (this.collapsed || this.rotated ? '' : 'show'),
2222 if (this.title.length) {
2226 src: this.title // escape?
2230 if (this.subtitle.length) {
2234 src: this.subtitle // escape?
2240 cls : 'roo-card-body-ctr'
2243 if (this.html.length) {
2249 // fixme ? handle objects?
2251 if (this.footer.length) {
2254 cls : 'card-footer ' + (this.rotated ? 'd-none' : ''),
2259 cfg.cn.push({cls : 'card-footer d-none'});
2268 getCardHeader : function()
2270 var ret = this.el.select('.card-header',true).first();
2271 if (ret.hasClass('d-none')) {
2272 ret.removeClass('d-none');
2277 getCardFooter : function()
2279 var ret = this.el.select('.card-footer',true).first();
2280 if (ret.hasClass('d-none')) {
2281 ret.removeClass('d-none');
2286 getCardImageTop : function()
2288 var ret = this.el.select('.card-img-top',true).first();
2289 if (ret.hasClass('d-none')) {
2290 ret.removeClass('d-none');
2296 getChildContainer : function()
2302 return this.el.select('.roo-card-body-ctr',true).first();
2305 initEvents: function()
2307 this.bodyEl = this.el.select('.card-body',true).first();
2308 this.containerEl = this.getChildContainer();
2310 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
2311 containerScroll: true,
2312 ddGroup: this.drag_group || 'default_card_drag_group'
2314 this.dragZone.getDragData = this.getDragData.createDelegate(this);
2316 if (this.dropable) {
2317 this.dropZone = new Roo.dd.DropZone(this.el.select('.card-body',true).first() , {
2318 containerScroll: true,
2319 ddGroup: this.drop_group || 'default_card_drag_group'
2321 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
2322 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
2323 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
2324 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
2325 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
2328 if (this.collapsable) {
2329 this.el.select('.card-header',true).on('click', this.onToggleCollapse, this);
2331 if (this.rotateable) {
2332 this.el.select('.card-header',true).on('click', this.onToggleRotate, this);
2334 this.collapsableEl = this.el.select('.roo-collapsable').first();
2336 this.footerEl = this.el.select('.card-footer').first();
2337 this.collapsableToggleEl = this.el.select('.roo-collapse-toggle');
2338 this.headerContainerEl = this.el.select('.roo-card-header-ctr').first();
2339 this.headerEl = this.el.select('.card-header',true).first();
2342 this.el.addClass('roo-card-rotated');
2343 this.fireEvent('rotate', this, true);
2347 getDragData : function(e)
2349 var target = this.getEl();
2351 //this.handleSelection(e);
2356 nodes: this.getEl(),
2361 dragData.ddel = target.dom ; // the div element
2362 Roo.log(target.getWidth( ));
2363 dragData.ddel.style.width = target.getWidth() + 'px';
2370 * Part of the Roo.dd.DropZone interface. If no target node is found, the
2371 * whole Element becomes the target, and this causes the drop gesture to append.
2373 getTargetFromEvent : function(e, dragged_card_el)
2375 var target = e.getTarget();
2376 while ((target !== null) && (target.parentNode != this.containerEl.dom)) {
2377 target = target.parentNode;
2388 //Roo.log([ 'target' , target ? target.id : '--nothing--']);
2389 // see if target is one of the 'cards'...
2392 //Roo.log(this.items.length);
2395 var last_card_n = 0;
2397 for (var i = 0;i< this.items.length;i++) {
2399 if (!this.items[i].el.hasClass('card')) {
2402 pos = this.getDropPoint(e, this.items[i].el.dom);
2404 cards_len = ret.cards.length;
2405 //Roo.log(this.items[i].el.dom.id);
2406 ret.cards.push(this.items[i]);
2408 if (ret.card_n < 0 && pos == 'above') {
2409 ret.position = cards_len > 0 ? 'below' : pos;
2410 ret.items_n = i > 0 ? i - 1 : 0;
2411 ret.card_n = cards_len > 0 ? cards_len - 1 : 0;
2412 ret.card = ret.cards[ret.card_n];
2415 if (!ret.cards.length) {
2417 ret.position = 'below';
2421 // could not find a card.. stick it at the end..
2422 if (ret.card_n < 0) {
2423 ret.card_n = last_card_n;
2424 ret.card = ret.cards[last_card_n];
2425 ret.items_n = this.items.indexOf(ret.cards[last_card_n]);
2426 ret.position = 'below';
2429 if (this.items[ret.items_n].el == dragged_card_el) {
2433 if (ret.position == 'below') {
2434 var card_after = ret.card_n+1 == ret.cards.length ? false : ret.cards[ret.card_n+1];
2436 if (card_after && card_after.el == dragged_card_el) {
2443 var card_before = ret.card_n > 0 ? ret.cards[ret.card_n-1] : false;
2445 if (card_before && card_before.el == dragged_card_el) {
2452 onNodeEnter : function(n, dd, e, data){
2455 onNodeOver : function(n, dd, e, data)
2458 var target_info = this.getTargetFromEvent(e,data.source.el);
2459 if (target_info === false) {
2460 this.dropPlaceHolder('hide');
2463 Roo.log(['getTargetFromEvent', target_info ]);
2466 this.dropPlaceHolder('show', target_info,data);
2470 onNodeOut : function(n, dd, e, data){
2471 this.dropPlaceHolder('hide');
2474 onNodeDrop : function(n, dd, e, data)
2477 // call drop - return false if
2479 // this could actually fail - if the Network drops..
2480 // we will ignore this at present..- client should probably reload
2481 // the whole set of cards if stuff like that fails.
2484 var info = this.getTargetFromEvent(e,data.source.el);
2485 if (info === false) {
2488 this.dropPlaceHolder('hide');
2494 this.acceptCard(data.source, info.position, info.card, info.items_n);
2498 firstChildCard : function()
2500 for (var i = 0;i< this.items.length;i++) {
2502 if (!this.items[i].el.hasClass('card')) {
2505 return this.items[i];
2507 return this.items.length ? this.items[this.items.length-1] : false; // don't try and put stuff after the cards...
2512 * - card.acceptCard(move_card, info.position, info.card, info.items_n);
2514 acceptCard : function(move_card, position, next_to_card )
2516 if (this.fireEvent("drop", this, move_card, position, next_to_card) === false) {
2520 var to_items_n = next_to_card ? this.items.indexOf(next_to_card) : 0;
2523 var dom = move_card.el.dom;
2524 dom.parentNode.removeChild(dom);
2525 dom.style.width = ''; // clear with - which is set by drag.
2527 if (next_to_card !== false && next_to_card !== true && next_to_card.el.dom.parentNode) {
2528 var cardel = next_to_card.el.dom;
2530 if (position == 'above' ) {
2531 cardel.parentNode.insertBefore(dom, cardel);
2532 } else if (cardel.nextSibling) {
2533 cardel.parentNode.insertBefore(dom,cardel.nextSibling);
2535 cardel.parentNode.append(dom);
2538 // card container???
2539 this.containerEl.dom.append(dom);
2542 //FIXME HANDLE card = true
2544 // add this to the correct place in items.
2548 // remove Card from items.
2550 var old_parent = move_card.parent();
2552 old_parent.items = old_parent.items.filter(function(e) { return e != move_card });
2554 if (this.items.length) {
2556 //Roo.log([info.items_n, info.position, this.items.length]);
2557 for (var i =0; i < this.items.length; i++) {
2558 if (i == to_items_n && position == 'above') {
2559 nitems.push(move_card);
2561 nitems.push(this.items[i]);
2562 if (i == to_items_n && position == 'below') {
2563 nitems.push(move_card);
2566 this.items = nitems;
2567 Roo.log(this.items);
2569 this.items.push(move_card);
2572 move_card.parentId = this.id;
2580 /** Decide whether to drop above or below a View node. */
2581 getDropPoint : function(e, n, dd)
2586 if (n == this.containerEl.dom) {
2589 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
2590 var c = t + (b - t) / 2;
2591 var y = Roo.lib.Event.getPageY(e);
2598 onToggleCollapse : function(e)
2600 if (this.collapsed) {
2601 this.el.select('.roo-collapse-toggle').removeClass('collapsed');
2602 this.collapsableEl.addClass('show');
2603 this.collapsed = false;
2606 this.el.select('.roo-collapse-toggle').addClass('collapsed');
2607 this.collapsableEl.removeClass('show');
2608 this.collapsed = true;
2613 onToggleRotate : function(e)
2615 this.collapsableEl.removeClass('show');
2616 this.footerEl.removeClass('d-none');
2617 this.el.removeClass('roo-card-rotated');
2618 this.el.removeClass('d-none');
2621 this.collapsableEl.addClass('show');
2622 this.rotated = false;
2623 this.fireEvent('rotate', this, this.rotated);
2626 this.el.addClass('roo-card-rotated');
2627 this.footerEl.addClass('d-none');
2628 this.el.select('.roo-collapsable').removeClass('show');
2630 this.rotated = true;
2631 this.fireEvent('rotate', this, this.rotated);
2635 dropPlaceHolder: function (action, info, data)
2637 if (this.dropEl === false) {
2638 this.dropEl = Roo.DomHelper.append(this.containerEl, {
2642 this.dropEl.removeClass(['d-none', 'd-block']);
2643 if (action == 'hide') {
2645 this.dropEl.addClass('d-none');
2648 // FIXME - info.card == true!!!
2649 this.dropEl.dom.parentNode.removeChild(this.dropEl.dom);
2651 if (info.card !== true) {
2652 var cardel = info.card.el.dom;
2654 if (info.position == 'above') {
2655 cardel.parentNode.insertBefore(this.dropEl.dom, cardel);
2656 } else if (cardel.nextSibling) {
2657 cardel.parentNode.insertBefore(this.dropEl.dom,cardel.nextSibling);
2659 cardel.parentNode.append(this.dropEl.dom);
2662 // card container???
2663 this.containerEl.dom.append(this.dropEl.dom);
2666 this.dropEl.addClass('d-block roo-card-dropzone');
2668 this.dropEl.setHeight( Roo.get(data.ddel).getHeight() );
2675 setHeaderText: function(html)
2677 this.headerContainerEl.dom.innerHTML = html;
2686 * Card header - holder for the card header elements.
2691 * @class Roo.bootstrap.CardHeader
2692 * @extends Roo.bootstrap.Element
2693 * Bootstrap CardHeader class
2695 * Create a new Card Header - that you can embed children into
2696 * @param {Object} config The config object
2699 Roo.bootstrap.CardHeader = function(config){
2700 Roo.bootstrap.CardHeader.superclass.constructor.call(this, config);
2703 Roo.extend(Roo.bootstrap.CardHeader, Roo.bootstrap.Element, {
2706 container_method : 'getCardHeader'
2719 * Card footer - holder for the card footer elements.
2724 * @class Roo.bootstrap.CardFooter
2725 * @extends Roo.bootstrap.Element
2726 * Bootstrap CardFooter class
2728 * Create a new Card Footer - that you can embed children into
2729 * @param {Object} config The config object
2732 Roo.bootstrap.CardFooter = function(config){
2733 Roo.bootstrap.CardFooter.superclass.constructor.call(this, config);
2736 Roo.extend(Roo.bootstrap.CardFooter, Roo.bootstrap.Element, {
2739 container_method : 'getCardFooter'
2752 * Card header - holder for the card header elements.
2757 * @class Roo.bootstrap.CardImageTop
2758 * @extends Roo.bootstrap.Element
2759 * Bootstrap CardImageTop class
2761 * Create a new Card Image Top container
2762 * @param {Object} config The config object
2765 Roo.bootstrap.CardImageTop = function(config){
2766 Roo.bootstrap.CardImageTop.superclass.constructor.call(this, config);
2769 Roo.extend(Roo.bootstrap.CardImageTop, Roo.bootstrap.Element, {
2772 container_method : 'getCardImageTop'
2790 * @class Roo.bootstrap.Img
2791 * @extends Roo.bootstrap.Component
2792 * Bootstrap Img class
2793 * @cfg {Boolean} imgResponsive false | true
2794 * @cfg {String} border rounded | circle | thumbnail
2795 * @cfg {String} src image source
2796 * @cfg {String} alt image alternative text
2797 * @cfg {String} href a tag href
2798 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
2799 * @cfg {String} xsUrl xs image source
2800 * @cfg {String} smUrl sm image source
2801 * @cfg {String} mdUrl md image source
2802 * @cfg {String} lgUrl lg image source
2805 * Create a new Input
2806 * @param {Object} config The config object
2809 Roo.bootstrap.Img = function(config){
2810 Roo.bootstrap.Img.superclass.constructor.call(this, config);
2816 * The img click event for the img.
2817 * @param {Roo.EventObject} e
2823 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
2825 imgResponsive: true,
2835 getAutoCreate : function()
2837 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
2838 return this.createSingleImg();
2843 cls: 'roo-image-responsive-group',
2848 Roo.each(['xs', 'sm', 'md', 'lg'], function(size){
2850 if(!_this[size + 'Url']){
2856 cls: (_this.imgResponsive) ? 'img-responsive' : '',
2857 html: _this.html || cfg.html,
2858 src: _this[size + 'Url']
2861 img.cls += ' roo-image-responsive-' + size;
2863 var s = ['xs', 'sm', 'md', 'lg'];
2865 s.splice(s.indexOf(size), 1);
2867 Roo.each(s, function(ss){
2868 img.cls += ' hidden-' + ss;
2871 if (['rounded','circle','thumbnail'].indexOf(_this.border)>-1) {
2872 cfg.cls += ' img-' + _this.border;
2876 cfg.alt = _this.alt;
2889 a.target = _this.target;
2893 cfg.cn.push((_this.href) ? a : img);
2900 createSingleImg : function()
2904 cls: (this.imgResponsive) ? 'img-responsive' : '',
2906 src : 'about:blank' // just incase src get's set to undefined?!?
2909 cfg.html = this.html || cfg.html;
2911 cfg.src = this.src || cfg.src;
2913 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
2914 cfg.cls += ' img-' + this.border;
2931 a.target = this.target;
2936 return (this.href) ? a : cfg;
2939 initEvents: function()
2942 this.el.on('click', this.onClick, this);
2947 onClick : function(e)
2949 Roo.log('img onclick');
2950 this.fireEvent('click', this, e);
2953 * Sets the url of the image - used to update it
2954 * @param {String} url the url of the image
2957 setSrc : function(url)
2961 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
2962 this.el.dom.src = url;
2966 this.el.select('img', true).first().dom.src = url;
2982 * @class Roo.bootstrap.Link
2983 * @extends Roo.bootstrap.Component
2984 * Bootstrap Link Class
2985 * @cfg {String} alt image alternative text
2986 * @cfg {String} href a tag href
2987 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
2988 * @cfg {String} html the content of the link.
2989 * @cfg {String} anchor name for the anchor link
2990 * @cfg {String} fa - favicon
2992 * @cfg {Boolean} preventDefault (true | false) default false
2996 * Create a new Input
2997 * @param {Object} config The config object
3000 Roo.bootstrap.Link = function(config){
3001 Roo.bootstrap.Link.superclass.constructor.call(this, config);
3007 * The img click event for the img.
3008 * @param {Roo.EventObject} e
3014 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
3018 preventDefault: false,
3024 getAutoCreate : function()
3026 var html = this.html || '';
3028 if (this.fa !== false) {
3029 html = '<i class="fa fa-' + this.fa + '"></i>';
3034 // anchor's do not require html/href...
3035 if (this.anchor === false) {
3037 cfg.href = this.href || '#';
3039 cfg.name = this.anchor;
3040 if (this.html !== false || this.fa !== false) {
3043 if (this.href !== false) {
3044 cfg.href = this.href;
3048 if(this.alt !== false){
3053 if(this.target !== false) {
3054 cfg.target = this.target;
3060 initEvents: function() {
3062 if(!this.href || this.preventDefault){
3063 this.el.on('click', this.onClick, this);
3067 onClick : function(e)
3069 if(this.preventDefault){
3072 //Roo.log('img onclick');
3073 this.fireEvent('click', this, e);
3086 * @class Roo.bootstrap.Header
3087 * @extends Roo.bootstrap.Component
3088 * Bootstrap Header class
3089 * @cfg {String} html content of header
3090 * @cfg {Number} level (1|2|3|4|5|6) default 1
3093 * Create a new Header
3094 * @param {Object} config The config object
3098 Roo.bootstrap.Header = function(config){
3099 Roo.bootstrap.Header.superclass.constructor.call(this, config);
3102 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
3110 getAutoCreate : function(){
3115 tag: 'h' + (1 *this.level),
3116 html: this.html || ''
3128 * Ext JS Library 1.1.1
3129 * Copyright(c) 2006-2007, Ext JS, LLC.
3131 * Originally Released Under LGPL - original licence link has changed is not relivant.
3134 * <script type="text/javascript">
3138 * @class Roo.bootstrap.MenuMgr
3139 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
3142 Roo.bootstrap.MenuMgr = function(){
3143 var menus, active, groups = {}, attached = false, lastShow = new Date();
3145 // private - called when first menu is created
3148 active = new Roo.util.MixedCollection();
3149 Roo.get(document).addKeyListener(27, function(){
3150 if(active.length > 0){
3158 if(active && active.length > 0){
3159 var c = active.clone();
3169 if(active.length < 1){
3170 Roo.get(document).un("mouseup", onMouseDown);
3178 var last = active.last();
3179 lastShow = new Date();
3182 Roo.get(document).on("mouseup", onMouseDown);
3187 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
3188 m.parentMenu.activeChild = m;
3189 }else if(last && last.isVisible()){
3190 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
3195 function onBeforeHide(m){
3197 m.activeChild.hide();
3199 if(m.autoHideTimer){
3200 clearTimeout(m.autoHideTimer);
3201 delete m.autoHideTimer;
3206 function onBeforeShow(m){
3207 var pm = m.parentMenu;
3208 if(!pm && !m.allowOtherMenus){
3210 }else if(pm && pm.activeChild && active != m){
3211 pm.activeChild.hide();
3215 // private this should really trigger on mouseup..
3216 function onMouseDown(e){
3217 Roo.log("on Mouse Up");
3219 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".dropdown-menu") && !e.getTarget('.user-menu')){
3220 Roo.log("MenuManager hideAll");
3229 function onBeforeCheck(mi, state){
3231 var g = groups[mi.group];
3232 for(var i = 0, l = g.length; i < l; i++){
3234 g[i].setChecked(false);
3243 * Hides all menus that are currently visible
3245 hideAll : function(){
3250 register : function(menu){
3254 menus[menu.id] = menu;
3255 menu.on("beforehide", onBeforeHide);
3256 menu.on("hide", onHide);
3257 menu.on("beforeshow", onBeforeShow);
3258 menu.on("show", onShow);
3260 if(g && menu.events["checkchange"]){
3264 groups[g].push(menu);
3265 menu.on("checkchange", onCheck);
3270 * Returns a {@link Roo.menu.Menu} object
3271 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
3272 * be used to generate and return a new Menu instance.
3274 get : function(menu){
3275 if(typeof menu == "string"){ // menu id
3277 }else if(menu.events){ // menu instance
3280 /*else if(typeof menu.length == 'number'){ // array of menu items?
3281 return new Roo.bootstrap.Menu({items:menu});
3282 }else{ // otherwise, must be a config
3283 return new Roo.bootstrap.Menu(menu);
3290 unregister : function(menu){
3291 delete menus[menu.id];
3292 menu.un("beforehide", onBeforeHide);
3293 menu.un("hide", onHide);
3294 menu.un("beforeshow", onBeforeShow);
3295 menu.un("show", onShow);
3297 if(g && menu.events["checkchange"]){
3298 groups[g].remove(menu);
3299 menu.un("checkchange", onCheck);
3304 registerCheckable : function(menuItem){
3305 var g = menuItem.group;
3310 groups[g].push(menuItem);
3311 menuItem.on("beforecheckchange", onBeforeCheck);
3316 unregisterCheckable : function(menuItem){
3317 var g = menuItem.group;
3319 groups[g].remove(menuItem);
3320 menuItem.un("beforecheckchange", onBeforeCheck);
3332 * @class Roo.bootstrap.Menu
3333 * @extends Roo.bootstrap.Component
3334 * Bootstrap Menu class - container for MenuItems
3335 * @cfg {String} type (dropdown|treeview|submenu) type of menu
3336 * @cfg {bool} hidden if the menu should be hidden when rendered.
3337 * @cfg {bool} stopEvent (true|false) Stop event after trigger press (default true)
3338 * @cfg {bool} isLink (true|false) the menu has link disable auto expand and collaspe (default false)
3342 * @param {Object} config The config object
3346 Roo.bootstrap.Menu = function(config){
3347 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
3348 if (this.registerMenu && this.type != 'treeview') {
3349 Roo.bootstrap.MenuMgr.register(this);
3356 * Fires before this menu is displayed (return false to block)
3357 * @param {Roo.menu.Menu} this
3362 * Fires before this menu is hidden (return false to block)
3363 * @param {Roo.menu.Menu} this
3368 * Fires after this menu is displayed
3369 * @param {Roo.menu.Menu} this
3374 * Fires after this menu is hidden
3375 * @param {Roo.menu.Menu} this
3380 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
3381 * @param {Roo.menu.Menu} this
3382 * @param {Roo.menu.Item} menuItem The menu item that was clicked
3383 * @param {Roo.EventObject} e
3388 * Fires when the mouse is hovering over this menu
3389 * @param {Roo.menu.Menu} this
3390 * @param {Roo.EventObject} e
3391 * @param {Roo.menu.Item} menuItem The menu item that was clicked
3396 * Fires when the mouse exits this menu
3397 * @param {Roo.menu.Menu} this
3398 * @param {Roo.EventObject} e
3399 * @param {Roo.menu.Item} menuItem The menu item that was clicked
3404 * Fires when a menu item contained in this menu is clicked
3405 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
3406 * @param {Roo.EventObject} e
3410 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
3413 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
3417 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
3420 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
3422 registerMenu : true,
3424 menuItems :false, // stores the menu items..
3434 getChildContainer : function() {
3438 getAutoCreate : function(){
3440 //if (['right'].indexOf(this.align)!==-1) {
3441 // cfg.cn[1].cls += ' pull-right'
3447 cls : 'dropdown-menu' ,
3448 style : 'z-index:1000'
3452 if (this.type === 'submenu') {
3453 cfg.cls = 'submenu active';
3455 if (this.type === 'treeview') {
3456 cfg.cls = 'treeview-menu';
3461 initEvents : function() {
3463 // Roo.log("ADD event");
3464 // Roo.log(this.triggerEl.dom);
3466 this.triggerEl.on('click', this.onTriggerClick, this);
3468 this.triggerEl.on(Roo.isTouch ? 'touchstart' : 'mouseup', this.onTriggerPress, this);
3471 if (this.triggerEl.hasClass('nav-item')) {
3472 // dropdown toggle on the 'a' in BS4?
3473 this.triggerEl.select('.nav-link',true).first().addClass('dropdown-toggle');
3475 this.triggerEl.addClass('dropdown-toggle');
3478 this.el.on('touchstart' , this.onTouch, this);
3480 this.el.on('click' , this.onClick, this);
3482 this.el.on("mouseover", this.onMouseOver, this);
3483 this.el.on("mouseout", this.onMouseOut, this);
3487 findTargetItem : function(e)
3489 var t = e.getTarget(".dropdown-menu-item", this.el, true);
3493 //Roo.log(t); Roo.log(t.id);
3495 //Roo.log(this.menuitems);
3496 return this.menuitems.get(t.id);
3498 //return this.items.get(t.menuItemId);
3504 onTouch : function(e)
3506 Roo.log("menu.onTouch");
3507 //e.stopEvent(); this make the user popdown broken
3511 onClick : function(e)
3513 Roo.log("menu.onClick");
3515 var t = this.findTargetItem(e);
3516 if(!t || t.isContainer){
3521 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
3522 if(t == this.activeItem && t.shouldDeactivate(e)){
3523 this.activeItem.deactivate();
3524 delete this.activeItem;
3528 this.setActiveItem(t, true);
3536 Roo.log('pass click event');
3540 this.fireEvent("click", this, t, e);
3544 if(!t.href.length || t.href == '#'){
3545 (function() { _this.hide(); }).defer(100);
3550 onMouseOver : function(e){
3551 var t = this.findTargetItem(e);
3554 // if(t.canActivate && !t.disabled){
3555 // this.setActiveItem(t, true);
3559 this.fireEvent("mouseover", this, e, t);
3561 isVisible : function(){
3562 return !this.hidden;
3564 onMouseOut : function(e){
3565 var t = this.findTargetItem(e);
3568 // if(t == this.activeItem && t.shouldDeactivate(e)){
3569 // this.activeItem.deactivate();
3570 // delete this.activeItem;
3573 this.fireEvent("mouseout", this, e, t);
3578 * Displays this menu relative to another element
3579 * @param {String/HTMLElement/Roo.Element} element The element to align to
3580 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
3581 * the element (defaults to this.defaultAlign)
3582 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
3584 show : function(el, pos, parentMenu)
3586 if (false === this.fireEvent("beforeshow", this)) {
3587 Roo.log("show canceled");
3590 this.parentMenu = parentMenu;
3595 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
3598 * Displays this menu at a specific xy position
3599 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
3600 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
3602 showAt : function(xy, parentMenu, /* private: */_e){
3603 this.parentMenu = parentMenu;
3608 this.fireEvent("beforeshow", this);
3609 //xy = this.el.adjustForConstraints(xy);
3613 this.hideMenuItems();
3614 this.hidden = false;
3615 this.triggerEl.addClass('open');
3616 this.el.addClass('show');
3618 // reassign x when hitting right
3619 if(this.el.getWidth() + xy[0] >= Roo.lib.Dom.getViewWidth()){
3620 xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
3623 // reassign y when hitting bottom
3624 if(this.el.getHeight() + xy[1] >= Roo.lib.Dom.getViewHeight()){
3625 xy[1] = xy[1] - this.el.getHeight() - this.triggerEl.getHeight();
3628 // but the list may align on trigger left or trigger top... should it be a properity?
3630 if(this.el.getStyle('top') != 'auto' && this.el.getStyle('top').slice(-1) != "%"){
3635 this.fireEvent("show", this);
3641 this.doFocus.defer(50, this);
3645 doFocus : function(){
3647 this.focusEl.focus();
3652 * Hides this menu and optionally all parent menus
3653 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
3655 hide : function(deep)
3657 if (false === this.fireEvent("beforehide", this)) {
3658 Roo.log("hide canceled");
3661 this.hideMenuItems();
3662 if(this.el && this.isVisible()){
3664 if(this.activeItem){
3665 this.activeItem.deactivate();
3666 this.activeItem = null;
3668 this.triggerEl.removeClass('open');;
3669 this.el.removeClass('show');
3671 this.fireEvent("hide", this);
3673 if(deep === true && this.parentMenu){
3674 this.parentMenu.hide(true);
3678 onTriggerClick : function(e)
3680 Roo.log('trigger click');
3682 var target = e.getTarget();
3684 Roo.log(target.nodeName.toLowerCase());
3686 if(target.nodeName.toLowerCase() === 'i'){
3692 onTriggerPress : function(e)
3694 Roo.log('trigger press');
3695 //Roo.log(e.getTarget());
3696 // Roo.log(this.triggerEl.dom);
3698 // trigger only occurs on normal menu's -- if it's a treeview or dropdown... do not hide/show..
3699 var pel = Roo.get(e.getTarget());
3700 if (pel.findParent('.dropdown-menu') || pel.findParent('.treeview-menu') ) {
3701 Roo.log('is treeview or dropdown?');
3705 if(e.getTarget().nodeName.toLowerCase() !== 'i' && this.isLink){
3709 if (this.isVisible()) {
3714 this.show(this.triggerEl, '?', false);
3717 if(this.stopEvent || e.getTarget().nodeName.toLowerCase() === 'i'){
3724 hideMenuItems : function()
3726 Roo.log("hide Menu Items");
3731 this.el.select('.open',true).each(function(aa) {
3733 aa.removeClass('open');
3737 addxtypeChild : function (tree, cntr) {
3738 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
3740 this.menuitems.add(comp);
3752 this.getEl().dom.innerHTML = '';
3753 this.menuitems.clear();
3767 * @class Roo.bootstrap.MenuItem
3768 * @extends Roo.bootstrap.Component
3769 * Bootstrap MenuItem class
3770 * @cfg {String} html the menu label
3771 * @cfg {String} href the link
3772 * @cfg {Boolean} preventDefault do not trigger A href on clicks (default false).
3773 * @cfg {Boolean} isContainer is it a container - just returns a drop down item..
3774 * @cfg {Boolean} active used on sidebars to highlight active itesm
3775 * @cfg {String} fa favicon to show on left of menu item.
3776 * @cfg {Roo.bootsrap.Menu} menu the child menu.
3780 * Create a new MenuItem
3781 * @param {Object} config The config object
3785 Roo.bootstrap.MenuItem = function(config){
3786 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
3791 * The raw click event for the entire grid.
3792 * @param {Roo.bootstrap.MenuItem} this
3793 * @param {Roo.EventObject} e
3799 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
3803 preventDefault: false,
3804 isContainer : false,
3808 getAutoCreate : function(){
3810 if(this.isContainer){
3813 cls: 'dropdown-menu-item '
3823 cls : 'dropdown-item',
3828 if (this.fa !== false) {
3831 cls : 'fa fa-' + this.fa
3840 cls: 'dropdown-menu-item',
3843 if (this.parent().type == 'treeview') {
3844 cfg.cls = 'treeview-menu';
3847 cfg.cls += ' active';
3852 anc.href = this.href || cfg.cn[0].href ;
3853 ctag.html = this.html || cfg.cn[0].html ;
3857 initEvents: function()
3859 if (this.parent().type == 'treeview') {
3860 this.el.select('a').on('click', this.onClick, this);
3864 this.menu.parentType = this.xtype;
3865 this.menu.triggerEl = this.el;
3866 this.menu = this.addxtype(Roo.apply({}, this.menu));
3870 onClick : function(e)
3872 Roo.log('item on click ');
3874 if(this.preventDefault){
3877 //this.parent().hideMenuItems();
3879 this.fireEvent('click', this, e);
3898 * @class Roo.bootstrap.MenuSeparator
3899 * @extends Roo.bootstrap.Component
3900 * Bootstrap MenuSeparator class
3903 * Create a new MenuItem
3904 * @param {Object} config The config object
3908 Roo.bootstrap.MenuSeparator = function(config){
3909 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
3912 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
3914 getAutoCreate : function(){
3933 * @class Roo.bootstrap.Modal
3934 * @extends Roo.bootstrap.Component
3935 * Bootstrap Modal class
3936 * @cfg {String} title Title of dialog
3937 * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
3938 * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method adn
3939 * @cfg {Boolean} specificTitle default false
3940 * @cfg {Array} buttons Array of buttons or standard button set..
3941 * @cfg {String} buttonPosition (left|right|center) default right (DEPRICATED) - use mr-auto on buttons to put them on the left
3942 * @cfg {Boolean} animate default true
3943 * @cfg {Boolean} allow_close default true
3944 * @cfg {Boolean} fitwindow default false
3945 * @cfg {Number} width fixed width - usefull for chrome extension only really.
3946 * @cfg {Number} height fixed height - usefull for chrome extension only really.
3947 * @cfg {String} size (sm|lg|xl) default empty
3948 * @cfg {Number} max_width set the max width of modal
3949 * @cfg {Boolean} editableTitle can the title be edited
3954 * Create a new Modal Dialog
3955 * @param {Object} config The config object
3958 Roo.bootstrap.Modal = function(config){
3959 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
3964 * The raw btnclick event for the button
3965 * @param {Roo.EventObject} e
3970 * Fire when dialog resize
3971 * @param {Roo.bootstrap.Modal} this
3972 * @param {Roo.EventObject} e
3976 * @event titlechanged
3977 * Fire when the editable title has been changed
3978 * @param {Roo.bootstrap.Modal} this
3979 * @param {Roo.EventObject} value
3981 "titlechanged" : true
3984 this.buttons = this.buttons || [];
3987 this.tmpl = Roo.factory(this.tmpl);
3992 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
3994 title : 'test dialog',
4004 specificTitle: false,
4006 buttonPosition: 'right',
4028 editableTitle : false,
4030 onRender : function(ct, position)
4032 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
4035 var cfg = Roo.apply({}, this.getAutoCreate());
4038 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
4040 //if (!cfg.name.length) {
4044 cfg.cls += ' ' + this.cls;
4047 cfg.style = this.style;
4049 this.el = Roo.get(document.body).createChild(cfg, position);
4051 //var type = this.el.dom.type;
4054 if(this.tabIndex !== undefined){
4055 this.el.dom.setAttribute('tabIndex', this.tabIndex);
4058 this.dialogEl = this.el.select('.modal-dialog',true).first();
4059 this.bodyEl = this.el.select('.modal-body',true).first();
4060 this.closeEl = this.el.select('.modal-header .close', true).first();
4061 this.headerEl = this.el.select('.modal-header',true).first();
4062 this.titleEl = this.el.select('.modal-title',true).first();
4063 this.footerEl = this.el.select('.modal-footer',true).first();
4065 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
4067 //this.el.addClass("x-dlg-modal");
4069 if (this.buttons.length) {
4070 Roo.each(this.buttons, function(bb) {
4071 var b = Roo.apply({}, bb);
4072 b.xns = b.xns || Roo.bootstrap;
4073 b.xtype = b.xtype || 'Button';
4074 if (typeof(b.listeners) == 'undefined') {
4075 b.listeners = { click : this.onButtonClick.createDelegate(this) };
4078 var btn = Roo.factory(b);
4080 btn.render(this.getButtonContainer());
4084 // render the children.
4087 if(typeof(this.items) != 'undefined'){
4088 var items = this.items;
4091 for(var i =0;i < items.length;i++) {
4092 nitems.push(this.addxtype(Roo.apply({}, items[i])));
4096 this.items = nitems;
4098 // where are these used - they used to be body/close/footer
4102 //this.el.addClass([this.fieldClass, this.cls]);
4106 getAutoCreate : function()
4108 // we will default to modal-body-overflow - might need to remove or make optional later.
4110 cls : 'modal-body enable-modal-body-overflow ',
4111 html : this.html || ''
4116 cls : 'modal-title',
4120 if(this.specificTitle){ // WTF is this?
4125 if (this.allow_close && Roo.bootstrap.version == 3) {
4135 if (this.editableTitle) {
4137 cls: 'form-control roo-editable-title d-none',
4143 if (this.allow_close && Roo.bootstrap.version == 4) {
4153 if(this.size.length){
4154 size = 'modal-' + this.size;
4157 var footer = Roo.bootstrap.version == 3 ?
4159 cls : 'modal-footer',
4163 cls: 'btn-' + this.buttonPosition
4168 { // BS4 uses mr-auto on left buttons....
4169 cls : 'modal-footer'
4180 cls: "modal-dialog " + size,
4183 cls : "modal-content",
4186 cls : 'modal-header',
4201 modal.cls += ' fade';
4207 getChildContainer : function() {
4212 getButtonContainer : function() {
4214 return Roo.bootstrap.version == 4 ?
4215 this.el.select('.modal-footer',true).first()
4216 : this.el.select('.modal-footer div',true).first();
4219 initEvents : function()
4221 if (this.allow_close) {
4222 this.closeEl.on('click', this.hide, this);
4224 Roo.EventManager.onWindowResize(this.resize, this, true);
4225 if (this.editableTitle) {
4226 this.headerEditEl = this.headerEl.select('.form-control',true).first();
4227 this.headerEl.on('click', function() { this.toggleHeaderInput(true) } , this);
4228 this.headerEditEl.on('keyup', function(e) {
4229 if([ e.RETURN , e.TAB , e.ESC ].indexOf(e.keyCode) > -1) {
4230 this.toggleHeaderInput(false)
4233 this.headerEditEl.on('blur', function(e) {
4234 this.toggleHeaderInput(false)
4243 this.maskEl.setSize(
4244 Roo.lib.Dom.getViewWidth(true),
4245 Roo.lib.Dom.getViewHeight(true)
4248 if (this.fitwindow) {
4252 this.width || Roo.lib.Dom.getViewportWidth(true) - 30,
4253 this.height || Roo.lib.Dom.getViewportHeight(true) // catering margin-top 30 margin-bottom 30
4258 if(this.max_width !== 0) {
4260 var w = Math.min(this.max_width, Roo.lib.Dom.getViewportWidth(true) - 30);
4263 this.setSize(w, this.height);
4267 if(this.max_height) {
4268 this.setSize(w,Math.min(
4270 Roo.lib.Dom.getViewportHeight(true) - 60
4276 if(!this.fit_content) {
4277 this.setSize(w, Roo.lib.Dom.getViewportHeight(true) - 60);
4281 this.setSize(w, Math.min(
4283 this.headerEl.getHeight() +
4284 this.footerEl.getHeight() +
4285 this.getChildHeight(this.bodyEl.dom.childNodes),
4286 Roo.lib.Dom.getViewportHeight(true) - 60)
4292 setSize : function(w,h)
4303 if (!this.rendered) {
4306 this.toggleHeaderInput(false);
4307 //this.el.setStyle('display', 'block');
4308 this.el.removeClass('hideing');
4309 this.el.dom.style.display='block';
4311 Roo.get(document.body).addClass('modal-open');
4313 if(this.animate){ // element has 'fade' - so stuff happens after .3s ?- not sure why the delay?
4316 this.el.addClass('show');
4317 this.el.addClass('in');
4320 this.el.addClass('show');
4321 this.el.addClass('in');
4324 // not sure how we can show data in here..
4326 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
4329 Roo.get(document.body).addClass("x-body-masked");
4331 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
4332 this.maskEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
4333 this.maskEl.dom.style.display = 'block';
4334 this.maskEl.addClass('show');
4339 this.fireEvent('show', this);
4341 // set zindex here - otherwise it appears to be ignored...
4342 this.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
4345 this.items.forEach( function(e) {
4346 e.layout ? e.layout() : false;
4354 if(this.fireEvent("beforehide", this) !== false){
4356 this.maskEl.removeClass('show');
4358 this.maskEl.dom.style.display = '';
4359 Roo.get(document.body).removeClass("x-body-masked");
4360 this.el.removeClass('in');
4361 this.el.select('.modal-dialog', true).first().setStyle('transform','');
4363 if(this.animate){ // why
4364 this.el.addClass('hideing');
4365 this.el.removeClass('show');
4367 if (!this.el.hasClass('hideing')) {
4368 return; // it's been shown again...
4371 this.el.dom.style.display='';
4373 Roo.get(document.body).removeClass('modal-open');
4374 this.el.removeClass('hideing');
4378 this.el.removeClass('show');
4379 this.el.dom.style.display='';
4380 Roo.get(document.body).removeClass('modal-open');
4383 this.fireEvent('hide', this);
4386 isVisible : function()
4389 return this.el.hasClass('show') && !this.el.hasClass('hideing');
4393 addButton : function(str, cb)
4397 var b = Roo.apply({}, { html : str } );
4398 b.xns = b.xns || Roo.bootstrap;
4399 b.xtype = b.xtype || 'Button';
4400 if (typeof(b.listeners) == 'undefined') {
4401 b.listeners = { click : cb.createDelegate(this) };
4404 var btn = Roo.factory(b);
4406 btn.render(this.getButtonContainer());
4412 setDefaultButton : function(btn)
4414 //this.el.select('.modal-footer').()
4417 resizeTo: function(w,h)
4419 this.dialogEl.setWidth(w);
4421 var diff = this.headerEl.getHeight() + this.footerEl.getHeight() + 60; // dialog margin-bottom: 30
4423 this.bodyEl.setHeight(h - diff);
4425 this.fireEvent('resize', this);
4428 setContentSize : function(w, h)
4432 onButtonClick: function(btn,e)
4435 this.fireEvent('btnclick', btn.name, e);
4438 * Set the title of the Dialog
4439 * @param {String} str new Title
4441 setTitle: function(str) {
4442 this.titleEl.dom.innerHTML = str;
4446 * Set the body of the Dialog
4447 * @param {String} str new Title
4449 setBody: function(str) {
4450 this.bodyEl.dom.innerHTML = str;
4453 * Set the body of the Dialog using the template
4454 * @param {Obj} data - apply this data to the template and replace the body contents.
4456 applyBody: function(obj)
4459 Roo.log("Error - using apply Body without a template");
4462 this.tmpl.overwrite(this.bodyEl, obj);
4465 getChildHeight : function(child_nodes)
4469 child_nodes.length == 0
4474 var child_height = 0;
4476 for(var i = 0; i < child_nodes.length; i++) {
4479 * for modal with tabs...
4480 if(child_nodes[i].classList.contains('roo-layout-panel')) {
4482 var layout_childs = child_nodes[i].childNodes;
4484 for(var j = 0; j < layout_childs.length; j++) {
4486 if(layout_childs[j].classList.contains('roo-layout-panel-body')) {
4488 var layout_body_childs = layout_childs[j].childNodes;
4490 for(var k = 0; k < layout_body_childs.length; k++) {
4492 if(layout_body_childs[k].classList.contains('navbar')) {
4493 child_height += layout_body_childs[k].offsetHeight;
4497 if(layout_body_childs[k].classList.contains('roo-layout-tabs-body')) {
4499 var layout_body_tab_childs = layout_body_childs[k].childNodes;
4501 for(var m = 0; m < layout_body_tab_childs.length; m++) {
4503 if(layout_body_tab_childs[m].classList.contains('roo-layout-active-content')) {
4504 child_height += this.getChildHeight(layout_body_tab_childs[m].childNodes);
4519 child_height += child_nodes[i].offsetHeight;
4520 // Roo.log(child_nodes[i].offsetHeight);
4523 return child_height;
4525 toggleHeaderInput : function(is_edit)
4527 if (!this.editableTitle) {
4528 return; // not editable.
4530 if (is_edit && this.is_header_editing) {
4531 return; // already editing..
4535 this.headerEditEl.dom.value = this.title;
4536 this.headerEditEl.removeClass('d-none');
4537 this.headerEditEl.dom.focus();
4538 this.titleEl.addClass('d-none');
4540 this.is_header_editing = true;
4543 // flip back to not editing.
4544 this.title = this.headerEditEl.dom.value;
4545 this.headerEditEl.addClass('d-none');
4546 this.titleEl.removeClass('d-none');
4547 this.titleEl.dom.innerHTML = String.format('{0}', this.title);
4548 this.is_header_editing = false;
4549 this.fireEvent('titlechanged', this, this.title);
4558 Roo.apply(Roo.bootstrap.Modal, {
4560 * Button config that displays a single OK button
4569 * Button config that displays Yes and No buttons
4585 * Button config that displays OK and Cancel buttons
4600 * Button config that displays Yes, No and Cancel buttons
4625 * messagebox - can be used as a replace
4629 * @class Roo.MessageBox
4630 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
4634 Roo.Msg.alert('Status', 'Changes saved successfully.');
4636 // Prompt for user data:
4637 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
4639 // process text value...
4643 // Show a dialog using config options:
4645 title:'Save Changes?',
4646 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
4647 buttons: Roo.Msg.YESNOCANCEL,
4654 Roo.bootstrap.MessageBox = function(){
4655 var dlg, opt, mask, waitTimer;
4656 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
4657 var buttons, activeTextEl, bwidth;
4661 var handleButton = function(button){
4663 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
4667 var handleHide = function(){
4669 dlg.el.removeClass(opt.cls);
4672 // Roo.TaskMgr.stop(waitTimer);
4673 // waitTimer = null;
4678 var updateButtons = function(b){
4681 buttons["ok"].hide();
4682 buttons["cancel"].hide();
4683 buttons["yes"].hide();
4684 buttons["no"].hide();
4685 dlg.footerEl.hide();
4689 dlg.footerEl.show();
4690 for(var k in buttons){
4691 if(typeof buttons[k] != "function"){
4694 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
4695 width += buttons[k].el.getWidth()+15;
4705 var handleEsc = function(d, k, e){
4706 if(opt && opt.closable !== false){
4716 * Returns a reference to the underlying {@link Roo.BasicDialog} element
4717 * @return {Roo.BasicDialog} The BasicDialog element
4719 getDialog : function(){
4721 dlg = new Roo.bootstrap.Modal( {
4724 //constraintoviewport:false,
4726 //collapsible : false,
4731 //buttonAlign:"center",
4732 closeClick : function(){
4733 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
4736 handleButton("cancel");
4741 dlg.on("hide", handleHide);
4743 //dlg.addKeyListener(27, handleEsc);
4745 this.buttons = buttons;
4746 var bt = this.buttonText;
4747 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
4748 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
4749 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
4750 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
4752 bodyEl = dlg.bodyEl.createChild({
4754 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
4755 '<textarea class="roo-mb-textarea"></textarea>' +
4756 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
4758 msgEl = bodyEl.dom.firstChild;
4759 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
4760 textboxEl.enableDisplayMode();
4761 textboxEl.addKeyListener([10,13], function(){
4762 if(dlg.isVisible() && opt && opt.buttons){
4765 }else if(opt.buttons.yes){
4766 handleButton("yes");
4770 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
4771 textareaEl.enableDisplayMode();
4772 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
4773 progressEl.enableDisplayMode();
4775 // This is supposed to be the progessElement.. but I think it's controlling the height of everything..
4776 var pf = progressEl.dom.firstChild;
4778 pp = Roo.get(pf.firstChild);
4779 pp.setHeight(pf.offsetHeight);
4787 * Updates the message box body text
4788 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
4789 * the XHTML-compliant non-breaking space character '&#160;')
4790 * @return {Roo.MessageBox} This message box
4792 updateText : function(text)
4794 if(!dlg.isVisible() && !opt.width){
4795 dlg.dialogEl.setStyle({ 'max-width' : this.maxWidth});
4796 // dlg.resizeTo(this.maxWidth, 100); // forcing the height breaks long alerts()
4798 msgEl.innerHTML = text || ' ';
4800 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
4801 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
4803 Math.min(opt.width || cw , this.maxWidth),
4804 Math.max(opt.minWidth || this.minWidth, bwidth)
4807 activeTextEl.setWidth(w);
4809 if(dlg.isVisible()){
4810 dlg.fixedcenter = false;
4812 // to big, make it scroll. = But as usual stupid IE does not support
4815 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
4816 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
4817 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
4819 bodyEl.dom.style.height = '';
4820 bodyEl.dom.style.overflowY = '';
4823 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
4825 bodyEl.dom.style.overflowX = '';
4828 dlg.setContentSize(w, bodyEl.getHeight());
4829 if(dlg.isVisible()){
4830 dlg.fixedcenter = true;
4836 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
4837 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
4838 * @param {Number} value Any number between 0 and 1 (e.g., .5)
4839 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
4840 * @return {Roo.MessageBox} This message box
4842 updateProgress : function(value, text){
4844 this.updateText(text);
4847 if (pp) { // weird bug on my firefox - for some reason this is not defined
4848 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
4849 pp.setHeight(Math.floor(progressEl.dom.firstChild.offsetHeight));
4855 * Returns true if the message box is currently displayed
4856 * @return {Boolean} True if the message box is visible, else false
4858 isVisible : function(){
4859 return dlg && dlg.isVisible();
4863 * Hides the message box if it is displayed
4866 if(this.isVisible()){
4872 * Displays a new message box, or reinitializes an existing message box, based on the config options
4873 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
4874 * The following config object properties are supported:
4876 Property Type Description
4877 ---------- --------------- ------------------------------------------------------------------------------------
4878 animEl String/Element An id or Element from which the message box should animate as it opens and
4879 closes (defaults to undefined)
4880 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
4881 cancel:'Bar'}), or false to not show any buttons (defaults to false)
4882 closable Boolean False to hide the top-right close button (defaults to true). Note that
4883 progress and wait dialogs will ignore this property and always hide the
4884 close button as they can only be closed programmatically.
4885 cls String A custom CSS class to apply to the message box element
4886 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
4887 displayed (defaults to 75)
4888 fn Function A callback function to execute after closing the dialog. The arguments to the
4889 function will be btn (the name of the button that was clicked, if applicable,
4890 e.g. "ok"), and text (the value of the active text field, if applicable).
4891 Progress and wait dialogs will ignore this option since they do not respond to
4892 user actions and can only be closed programmatically, so any required function
4893 should be called by the same code after it closes the dialog.
4894 icon String A CSS class that provides a background image to be used as an icon for
4895 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
4896 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
4897 minWidth Number The minimum width in pixels of the message box (defaults to 100)
4898 modal Boolean False to allow user interaction with the page while the message box is
4899 displayed (defaults to true)
4900 msg String A string that will replace the existing message box body text (defaults
4901 to the XHTML-compliant non-breaking space character ' ')
4902 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
4903 progress Boolean True to display a progress bar (defaults to false)
4904 progressText String The text to display inside the progress bar if progress = true (defaults to '')
4905 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
4906 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
4907 title String The title text
4908 value String The string value to set into the active textbox element if displayed
4909 wait Boolean True to display a progress bar (defaults to false)
4910 width Number The width of the dialog in pixels
4917 msg: 'Please enter your address:',
4919 buttons: Roo.MessageBox.OKCANCEL,
4922 animEl: 'addAddressBtn'
4925 * @param {Object} config Configuration options
4926 * @return {Roo.MessageBox} This message box
4928 show : function(options)
4931 // this causes nightmares if you show one dialog after another
4932 // especially on callbacks..
4934 if(this.isVisible()){
4937 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
4938 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
4939 Roo.log("New Dialog Message:" + options.msg )
4940 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
4941 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
4944 var d = this.getDialog();
4946 d.setTitle(opt.title || " ");
4947 d.closeEl.setDisplayed(opt.closable !== false);
4948 activeTextEl = textboxEl;
4949 opt.prompt = opt.prompt || (opt.multiline ? true : false);
4954 textareaEl.setHeight(typeof opt.multiline == "number" ?
4955 opt.multiline : this.defaultTextHeight);
4956 activeTextEl = textareaEl;
4965 progressEl.setDisplayed(opt.progress === true);
4967 d.animate = false; // do not animate progress, as it may not have finished animating before we close it..
4969 this.updateProgress(0);
4970 activeTextEl.dom.value = opt.value || "";
4972 dlg.setDefaultButton(activeTextEl);
4974 var bs = opt.buttons;
4978 }else if(bs && bs.yes){
4979 db = buttons["yes"];
4981 dlg.setDefaultButton(db);
4983 bwidth = updateButtons(opt.buttons);
4984 this.updateText(opt.msg);
4986 d.el.addClass(opt.cls);
4988 d.proxyDrag = opt.proxyDrag === true;
4989 d.modal = opt.modal !== false;
4990 d.mask = opt.modal !== false ? mask : false;
4992 // force it to the end of the z-index stack so it gets a cursor in FF
4993 document.body.appendChild(dlg.el.dom);
4994 d.animateTarget = null;
4995 d.show(options.animEl);
5001 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
5002 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
5003 * and closing the message box when the process is complete.
5004 * @param {String} title The title bar text
5005 * @param {String} msg The message box body text
5006 * @return {Roo.MessageBox} This message box
5008 progress : function(title, msg){
5015 minWidth: this.minProgressWidth,
5022 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
5023 * If a callback function is passed it will be called after the user clicks the button, and the
5024 * id of the button that was clicked will be passed as the only parameter to the callback
5025 * (could also be the top-right close button).
5026 * @param {String} title The title bar text
5027 * @param {String} msg The message box body text
5028 * @param {Function} fn (optional) The callback function invoked after the message box is closed
5029 * @param {Object} scope (optional) The scope of the callback function
5030 * @return {Roo.MessageBox} This message box
5032 alert : function(title, msg, fn, scope)
5047 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
5048 * interaction while waiting for a long-running process to complete that does not have defined intervals.
5049 * You are responsible for closing the message box when the process is complete.
5050 * @param {String} msg The message box body text
5051 * @param {String} title (optional) The title bar text
5052 * @return {Roo.MessageBox} This message box
5054 wait : function(msg, title){
5065 waitTimer = Roo.TaskMgr.start({
5067 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
5075 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
5076 * If a callback function is passed it will be called after the user clicks either button, and the id of the
5077 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
5078 * @param {String} title The title bar text
5079 * @param {String} msg The message box body text
5080 * @param {Function} fn (optional) The callback function invoked after the message box is closed
5081 * @param {Object} scope (optional) The scope of the callback function
5082 * @return {Roo.MessageBox} This message box
5084 confirm : function(title, msg, fn, scope){
5088 buttons: this.YESNO,
5097 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
5098 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
5099 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
5100 * (could also be the top-right close button) and the text that was entered will be passed as the two
5101 * parameters to the callback.
5102 * @param {String} title The title bar text
5103 * @param {String} msg The message box body text
5104 * @param {Function} fn (optional) The callback function invoked after the message box is closed
5105 * @param {Object} scope (optional) The scope of the callback function
5106 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
5107 * property, or the height in pixels to create the textbox (defaults to false / single-line)
5108 * @return {Roo.MessageBox} This message box
5110 prompt : function(title, msg, fn, scope, multiline){
5114 buttons: this.OKCANCEL,
5119 multiline: multiline,
5126 * Button config that displays a single OK button
5131 * Button config that displays Yes and No buttons
5134 YESNO : {yes:true, no:true},
5136 * Button config that displays OK and Cancel buttons
5139 OKCANCEL : {ok:true, cancel:true},
5141 * Button config that displays Yes, No and Cancel buttons
5144 YESNOCANCEL : {yes:true, no:true, cancel:true},
5147 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
5150 defaultTextHeight : 75,
5152 * The maximum width in pixels of the message box (defaults to 600)
5157 * The minimum width in pixels of the message box (defaults to 100)
5162 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
5163 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
5166 minProgressWidth : 250,
5168 * An object containing the default button text strings that can be overriden for localized language support.
5169 * Supported properties are: ok, cancel, yes and no.
5170 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
5183 * Shorthand for {@link Roo.MessageBox}
5185 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
5186 Roo.Msg = Roo.Msg || Roo.MessageBox;
5195 * @class Roo.bootstrap.Navbar
5196 * @extends Roo.bootstrap.Component
5197 * Bootstrap Navbar class
5200 * Create a new Navbar
5201 * @param {Object} config The config object
5205 Roo.bootstrap.Navbar = function(config){
5206 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
5210 * @event beforetoggle
5211 * Fire before toggle the menu
5212 * @param {Roo.EventObject} e
5214 "beforetoggle" : true
5218 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
5227 getAutoCreate : function(){
5230 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
5234 initEvents :function ()
5236 //Roo.log(this.el.select('.navbar-toggle',true));
5237 this.el.select('.navbar-toggle',true).on('click', this.onToggle , this);
5244 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
5246 var size = this.el.getSize();
5247 this.maskEl.setSize(size.width, size.height);
5248 this.maskEl.enableDisplayMode("block");
5257 getChildContainer : function()
5259 if (this.el && this.el.select('.collapse').getCount()) {
5260 return this.el.select('.collapse',true).first();
5275 onToggle : function()
5278 if(this.fireEvent('beforetoggle', this) === false){
5281 var ce = this.el.select('.navbar-collapse',true).first();
5283 if (!ce.hasClass('show')) {
5293 * Expand the navbar pulldown
5295 expand : function ()
5298 var ce = this.el.select('.navbar-collapse',true).first();
5299 if (ce.hasClass('collapsing')) {
5302 ce.dom.style.height = '';
5304 ce.addClass('in'); // old...
5305 ce.removeClass('collapse');
5306 ce.addClass('show');
5307 var h = ce.getHeight();
5309 ce.removeClass('show');
5310 // at this point we should be able to see it..
5311 ce.addClass('collapsing');
5313 ce.setHeight(0); // resize it ...
5314 ce.on('transitionend', function() {
5315 //Roo.log('done transition');
5316 ce.removeClass('collapsing');
5317 ce.addClass('show');
5318 ce.removeClass('collapse');
5320 ce.dom.style.height = '';
5321 }, this, { single: true} );
5323 ce.dom.scrollTop = 0;
5326 * Collapse the navbar pulldown
5328 collapse : function()
5330 var ce = this.el.select('.navbar-collapse',true).first();
5332 if (ce.hasClass('collapsing') || ce.hasClass('collapse') ) {
5333 // it's collapsed or collapsing..
5336 ce.removeClass('in'); // old...
5337 ce.setHeight(ce.getHeight());
5338 ce.removeClass('show');
5339 ce.addClass('collapsing');
5341 ce.on('transitionend', function() {
5342 ce.dom.style.height = '';
5343 ce.removeClass('collapsing');
5344 ce.addClass('collapse');
5345 }, this, { single: true} );
5365 * @class Roo.bootstrap.NavSimplebar
5366 * @extends Roo.bootstrap.Navbar
5367 * Bootstrap Sidebar class
5369 * @cfg {Boolean} inverse is inverted color
5371 * @cfg {String} type (nav | pills | tabs)
5372 * @cfg {Boolean} arrangement stacked | justified
5373 * @cfg {String} align (left | right) alignment
5375 * @cfg {Boolean} main (true|false) main nav bar? default false
5376 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
5378 * @cfg {String} tag (header|footer|nav|div) default is nav
5380 * @cfg {String} weight (light|primary|secondary|success|danger|warning|info|dark|white) default is light.
5384 * Create a new Sidebar
5385 * @param {Object} config The config object
5389 Roo.bootstrap.NavSimplebar = function(config){
5390 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
5393 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
5409 getAutoCreate : function(){
5413 tag : this.tag || 'div',
5414 cls : 'navbar roo-navbar-simple' //navbar-expand-lg ??
5416 if (['light','white'].indexOf(this.weight) > -1) {
5417 cfg.cls += ['light','white'].indexOf(this.weight) > -1 ? ' navbar-light' : ' navbar-dark';
5419 cfg.cls += ' bg-' + this.weight;
5422 cfg.cls += ' navbar-inverse';
5426 // i'm not actually sure these are really used - normally we add a navGroup to a navbar
5428 if (Roo.bootstrap.version == 4 && this.xtype == 'NavSimplebar') {
5437 cls: 'nav nav-' + this.xtype,
5443 this.type = this.type || 'nav';
5444 if (['tabs','pills'].indexOf(this.type) != -1) {
5445 cfg.cn[0].cls += ' nav-' + this.type
5449 if (this.type!=='nav') {
5450 Roo.log('nav type must be nav/tabs/pills')
5452 cfg.cn[0].cls += ' navbar-nav'
5458 if (['stacked','justified'].indexOf(this.arrangement) != -1) {
5459 cfg.cn[0].cls += ' nav-' + this.arrangement;
5463 if (this.align === 'right') {
5464 cfg.cn[0].cls += ' navbar-right';
5489 * navbar-expand-md fixed-top
5493 * @class Roo.bootstrap.NavHeaderbar
5494 * @extends Roo.bootstrap.NavSimplebar
5495 * Bootstrap Sidebar class
5497 * @cfg {String} brand what is brand
5498 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
5499 * @cfg {String} brand_href href of the brand
5500 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
5501 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
5502 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
5503 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
5506 * Create a new Sidebar
5507 * @param {Object} config The config object
5511 Roo.bootstrap.NavHeaderbar = function(config){
5512 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
5516 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
5523 desktopCenter : false,
5526 getAutoCreate : function(){
5529 tag: this.nav || 'nav',
5530 cls: 'navbar navbar-expand-md',
5536 if (this.desktopCenter) {
5537 cn.push({cls : 'container', cn : []});
5545 cls: 'navbar-toggle navbar-toggler',
5546 'data-toggle': 'collapse',
5551 html: 'Toggle navigation'
5555 cls: 'icon-bar navbar-toggler-icon'
5568 cn.push( Roo.bootstrap.version == 4 ? btn : {
5570 cls: 'navbar-header',
5579 cls: Roo.bootstrap.version == 4 ? 'nav flex-row roo-navbar-collapse collapse navbar-collapse' : 'collapse navbar-collapse roo-navbar-collapse',
5583 cfg.cls += this.inverse ? ' navbar-inverse navbar-dark bg-dark' : ' navbar-default';
5585 if (['light','white'].indexOf(this.weight) > -1) {
5586 cfg.cls += ['light','white'].indexOf(this.weight) > -1 ? ' navbar-light' : ' navbar-dark';
5588 cfg.cls += ' bg-' + this.weight;
5591 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
5592 cfg.cls += ' navbar-' + this.position + ' ' + this.position ;
5594 // tag can override this..
5596 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
5599 if (this.brand !== '') {
5600 var cp = Roo.bootstrap.version == 4 ? cn : cn[0].cn;
5601 cp.unshift({ // changed from push ?? BS4 needs it at the start? - does this break or exsiting?
5603 href: this.brand_href ? this.brand_href : '#',
5604 cls: 'navbar-brand',
5612 cfg.cls += ' main-nav';
5620 getHeaderChildContainer : function()
5622 if (this.srButton && this.el.select('.navbar-header').getCount()) {
5623 return this.el.select('.navbar-header',true).first();
5626 return this.getChildContainer();
5629 getChildContainer : function()
5632 return this.el.select('.roo-navbar-collapse',true).first();
5637 initEvents : function()
5639 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
5641 if (this.autohide) {
5646 Roo.get(document).on('scroll',function(e) {
5647 var ns = Roo.get(document).getScroll().top;
5648 var os = prevScroll;
5652 ft.removeClass('slideDown');
5653 ft.addClass('slideUp');
5656 ft.removeClass('slideUp');
5657 ft.addClass('slideDown');
5678 * @class Roo.bootstrap.NavSidebar
5679 * @extends Roo.bootstrap.Navbar
5680 * Bootstrap Sidebar class
5683 * Create a new Sidebar
5684 * @param {Object} config The config object
5688 Roo.bootstrap.NavSidebar = function(config){
5689 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
5692 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
5694 sidebar : true, // used by Navbar Item and NavbarGroup at present...
5696 getAutoCreate : function(){
5701 cls: 'sidebar sidebar-nav'
5723 * @class Roo.bootstrap.NavGroup
5724 * @extends Roo.bootstrap.Component
5725 * Bootstrap NavGroup class
5726 * @cfg {String} align (left|right)
5727 * @cfg {Boolean} inverse
5728 * @cfg {String} type (nav|pills|tab) default nav
5729 * @cfg {String} navId - reference Id for navbar.
5733 * Create a new nav group
5734 * @param {Object} config The config object
5737 Roo.bootstrap.NavGroup = function(config){
5738 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
5741 Roo.bootstrap.NavGroup.register(this);
5745 * Fires when the active item changes
5746 * @param {Roo.bootstrap.NavGroup} this
5747 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
5748 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
5755 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
5766 getAutoCreate : function()
5768 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
5774 if (Roo.bootstrap.version == 4) {
5775 if (['tabs','pills'].indexOf(this.type) != -1) {
5776 cfg.cls += ' nav-' + this.type;
5778 // trying to remove so header bar can right align top?
5779 if (this.parent() && this.parent().xtype != 'NavHeaderbar') {
5780 // do not use on header bar...
5781 cfg.cls += ' navbar-nav';
5786 if (['tabs','pills'].indexOf(this.type) != -1) {
5787 cfg.cls += ' nav-' + this.type
5789 if (this.type !== 'nav') {
5790 Roo.log('nav type must be nav/tabs/pills')
5792 cfg.cls += ' navbar-nav'
5796 if (this.parent() && this.parent().sidebar) {
5799 cls: 'dashboard-menu sidebar-menu'
5805 if (this.form === true) {
5808 cls: 'navbar-form form-inline'
5810 //nav navbar-right ml-md-auto
5811 if (this.align === 'right') {
5812 cfg.cls += ' navbar-right ml-md-auto';
5814 cfg.cls += ' navbar-left';
5818 if (this.align === 'right') {
5819 cfg.cls += ' navbar-right ml-md-auto';
5821 cfg.cls += ' mr-auto';
5825 cfg.cls += ' navbar-inverse';
5833 * sets the active Navigation item
5834 * @param {Roo.bootstrap.NavItem} the new current navitem
5836 setActiveItem : function(item)
5839 Roo.each(this.navItems, function(v){
5844 v.setActive(false, true);
5851 item.setActive(true, true);
5852 this.fireEvent('changed', this, item, prev);
5857 * gets the active Navigation item
5858 * @return {Roo.bootstrap.NavItem} the current navitem
5860 getActive : function()
5864 Roo.each(this.navItems, function(v){
5875 indexOfNav : function()
5879 Roo.each(this.navItems, function(v,i){
5890 * adds a Navigation item
5891 * @param {Roo.bootstrap.NavItem} the navitem to add
5893 addItem : function(cfg)
5895 if (this.form && Roo.bootstrap.version == 4) {
5898 var cn = new Roo.bootstrap.NavItem(cfg);
5900 cn.parentId = this.id;
5901 cn.onRender(this.el, null);
5905 * register a Navigation item
5906 * @param {Roo.bootstrap.NavItem} the navitem to add
5908 register : function(item)
5910 this.navItems.push( item);
5911 item.navId = this.navId;
5916 * clear all the Navigation item
5919 clearAll : function()
5922 this.el.dom.innerHTML = '';
5925 getNavItem: function(tabId)
5928 Roo.each(this.navItems, function(e) {
5929 if (e.tabId == tabId) {
5939 setActiveNext : function()
5941 var i = this.indexOfNav(this.getActive());
5942 if (i > this.navItems.length) {
5945 this.setActiveItem(this.navItems[i+1]);
5947 setActivePrev : function()
5949 var i = this.indexOfNav(this.getActive());
5953 this.setActiveItem(this.navItems[i-1]);
5955 clearWasActive : function(except) {
5956 Roo.each(this.navItems, function(e) {
5957 if (e.tabId != except.tabId && e.was_active) {
5958 e.was_active = false;
5965 getWasActive : function ()
5968 Roo.each(this.navItems, function(e) {
5983 Roo.apply(Roo.bootstrap.NavGroup, {
5987 * register a Navigation Group
5988 * @param {Roo.bootstrap.NavGroup} the navgroup to add
5990 register : function(navgrp)
5992 this.groups[navgrp.navId] = navgrp;
5996 * fetch a Navigation Group based on the navigation ID
5997 * @param {string} the navgroup to add
5998 * @returns {Roo.bootstrap.NavGroup} the navgroup
6000 get: function(navId) {
6001 if (typeof(this.groups[navId]) == 'undefined') {
6003 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
6005 return this.groups[navId] ;
6020 * @class Roo.bootstrap.NavItem
6021 * @extends Roo.bootstrap.Component
6022 * Bootstrap Navbar.NavItem class
6023 * @cfg {String} href link to
6024 * @cfg {String} button_weight (default | primary | secondary | success | info | warning | danger | link ) default none
6026 * @cfg {String} html content of button
6027 * @cfg {String} badge text inside badge
6028 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
6029 * @cfg {String} glyphicon DEPRICATED - use fa
6030 * @cfg {String} icon DEPRICATED - use fa
6031 * @cfg {String} fa - Fontawsome icon name (can add stuff to it like fa-2x)
6032 * @cfg {Boolean} active Is item active
6033 * @cfg {Boolean} disabled Is item disabled
6035 * @cfg {Boolean} preventDefault (true | false) default false
6036 * @cfg {String} tabId the tab that this item activates.
6037 * @cfg {String} tagtype (a|span) render as a href or span?
6038 * @cfg {Boolean} animateRef (true|false) link to element default false
6041 * Create a new Navbar Item
6042 * @param {Object} config The config object
6044 Roo.bootstrap.NavItem = function(config){
6045 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
6050 * The raw click event for the entire grid.
6051 * @param {Roo.EventObject} e
6056 * Fires when the active item active state changes
6057 * @param {Roo.bootstrap.NavItem} this
6058 * @param {boolean} state the new state
6064 * Fires when scroll to element
6065 * @param {Roo.bootstrap.NavItem} this
6066 * @param {Object} options
6067 * @param {Roo.EventObject} e
6075 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
6084 preventDefault : false,
6092 button_outline : false,
6096 getAutoCreate : function(){
6104 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
6106 if (this.disabled) {
6107 cfg.cls += ' disabled';
6111 if (this.button_weight.length) {
6112 cfg.tag = this.href ? 'a' : 'button';
6113 cfg.html = this.html || '';
6114 cfg.cls += ' btn btn' + (this.button_outline ? '-outline' : '') + '-' + this.button_weight;
6116 cfg.href = this.href;
6119 cfg.html = '<i class="fa fas fa-'+this.fa+'"></i> <span>' + this.html + '</span>';
6122 // menu .. should add dropdown-menu class - so no need for carat..
6124 if (this.badge !== '') {
6126 cfg.html += ' <span class="badge badge-secondary">' + this.badge + '</span>';
6131 if (this.href || this.html || this.glyphicon || this.icon || this.fa) {
6135 href : this.href || "#",
6136 html: this.html || ''
6139 if (this.tagtype == 'a') {
6140 cfg.cn[0].cls = 'nav-link';
6143 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>';
6146 cfg.cn[0].html = '<i class="fa fas fa-'+this.fa+'"></i> <span>' + cfg.cn[0].html + '</span>';
6148 if(this.glyphicon) {
6149 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
6154 cfg.cn[0].html += " <span class='caret'></span>";
6158 if (this.badge !== '') {
6160 cfg.cn[0].html += ' <span class="badge badge-secondary">' + this.badge + '</span>';
6168 onRender : function(ct, position)
6170 // Roo.log("Call onRender: " + this.xtype);
6171 if (Roo.bootstrap.version == 4 && ct.dom.type != 'ul') {
6175 var ret = Roo.bootstrap.NavItem.superclass.onRender.call(this, ct, position);
6176 this.navLink = this.el.select('.nav-link',true).first();
6181 initEvents: function()
6183 if (typeof (this.menu) != 'undefined') {
6184 this.menu.parentType = this.xtype;
6185 this.menu.triggerEl = this.el;
6186 this.menu = this.addxtype(Roo.apply({}, this.menu));
6189 this.el.select('a',true).on('click', this.onClick, this);
6191 if(this.tagtype == 'span'){
6192 this.el.select('span',true).on('click', this.onClick, this);
6195 // at this point parent should be available..
6196 this.parent().register(this);
6199 onClick : function(e)
6201 if (e.getTarget('.dropdown-menu-item')) {
6202 // did you click on a menu itemm.... - then don't trigger onclick..
6207 this.preventDefault ||
6210 Roo.log("NavItem - prevent Default?");
6214 if (this.disabled) {
6218 var tg = Roo.bootstrap.TabGroup.get(this.navId);
6219 if (tg && tg.transition) {
6220 Roo.log("waiting for the transitionend");
6226 //Roo.log("fire event clicked");
6227 if(this.fireEvent('click', this, e) === false){
6231 if(this.tagtype == 'span'){
6235 //Roo.log(this.href);
6236 var ael = this.el.select('a',true).first();
6239 if(ael && this.animateRef && this.href.indexOf('#') > -1){
6240 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
6241 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
6242 return; // ignore... - it's a 'hash' to another page.
6244 Roo.log("NavItem - prevent Default?");
6246 this.scrollToElement(e);
6250 var p = this.parent();
6252 if (['tabs','pills'].indexOf(p.type)!==-1) {
6253 if (typeof(p.setActiveItem) !== 'undefined') {
6254 p.setActiveItem(this);
6258 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
6259 if (p.parentType == 'NavHeaderbar' && !this.menu) {
6260 // remove the collapsed menu expand...
6261 p.parent().el.select('.roo-navbar-collapse',true).removeClass('in');
6265 isActive: function () {
6268 setActive : function(state, fire, is_was_active)
6270 if (this.active && !state && this.navId) {
6271 this.was_active = true;
6272 var nv = Roo.bootstrap.NavGroup.get(this.navId);
6274 nv.clearWasActive(this);
6278 this.active = state;
6281 this.el.removeClass('active');
6282 this.navLink ? this.navLink.removeClass('active') : false;
6283 } else if (!this.el.hasClass('active')) {
6285 this.el.addClass('active');
6286 if (Roo.bootstrap.version == 4 && this.navLink ) {
6287 this.navLink.addClass('active');
6292 this.fireEvent('changed', this, state);
6295 // show a panel if it's registered and related..
6297 if (!this.navId || !this.tabId || !state || is_was_active) {
6301 var tg = Roo.bootstrap.TabGroup.get(this.navId);
6305 var pan = tg.getPanelByName(this.tabId);
6309 // if we can not flip to new panel - go back to old nav highlight..
6310 if (false == tg.showPanel(pan)) {
6311 var nv = Roo.bootstrap.NavGroup.get(this.navId);
6313 var onav = nv.getWasActive();
6315 onav.setActive(true, false, true);
6324 // this should not be here...
6325 setDisabled : function(state)
6327 this.disabled = state;
6329 this.el.removeClass('disabled');
6330 } else if (!this.el.hasClass('disabled')) {
6331 this.el.addClass('disabled');
6337 * Fetch the element to display the tooltip on.
6338 * @return {Roo.Element} defaults to this.el
6340 tooltipEl : function()
6342 return this.el.select('' + this.tagtype + '', true).first();
6345 scrollToElement : function(e)
6347 var c = document.body;
6350 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
6352 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
6353 c = document.documentElement;
6356 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
6362 var o = target.calcOffsetsTo(c);
6369 this.fireEvent('scrollto', this, options, e);
6371 Roo.get(c).scrollTo('top', options.value, true);
6384 * <span> icon </span>
6385 * <span> text </span>
6386 * <span>badge </span>
6390 * @class Roo.bootstrap.NavSidebarItem
6391 * @extends Roo.bootstrap.NavItem
6392 * Bootstrap Navbar.NavSidebarItem class
6393 * {String} badgeWeight (default|primary|success|info|warning|danger)the extra classes for the badge
6394 * {Boolean} open is the menu open
6395 * {Boolean} buttonView use button as the tigger el rather that a (default false)
6396 * {String} buttonWeight (default|primary|success|info|warning|danger)the extra classes for the button
6397 * {String} buttonSize (sm|md|lg)the extra classes for the button
6398 * {Boolean} showArrow show arrow next to the text (default true)
6400 * Create a new Navbar Button
6401 * @param {Object} config The config object
6403 Roo.bootstrap.NavSidebarItem = function(config){
6404 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
6409 * The raw click event for the entire grid.
6410 * @param {Roo.EventObject} e
6415 * Fires when the active item active state changes
6416 * @param {Roo.bootstrap.NavSidebarItem} this
6417 * @param {boolean} state the new state
6425 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
6427 badgeWeight : 'default',
6433 buttonWeight : 'default',
6439 getAutoCreate : function(){
6444 href : this.href || '#',
6450 if(this.buttonView){
6453 href : this.href || '#',
6454 cls: 'btn btn-' + this.buttonWeight + ' btn-' + this.buttonSize + 'roo-button-dropdown-toggle',
6467 cfg.cls += ' active';
6470 if (this.disabled) {
6471 cfg.cls += ' disabled';
6474 cfg.cls += ' open x-open';
6477 if (this.glyphicon || this.icon) {
6478 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
6479 a.cn.push({ tag : 'i', cls : c }) ;
6482 if(!this.buttonView){
6485 html : this.html || ''
6492 if (this.badge !== '') {
6493 a.cn.push({ tag: 'span', cls : 'badge pull-right badge-' + this.badgeWeight, html: this.badge });
6499 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
6502 a.cls += ' dropdown-toggle treeview' ;
6508 initEvents : function()
6510 if (typeof (this.menu) != 'undefined') {
6511 this.menu.parentType = this.xtype;
6512 this.menu.triggerEl = this.el;
6513 this.menu = this.addxtype(Roo.apply({}, this.menu));
6516 this.el.on('click', this.onClick, this);
6518 if(this.badge !== ''){
6519 this.badgeEl = this.el.select('.badge', true).first().setVisibilityMode(Roo.Element.DISPLAY);
6524 onClick : function(e)
6531 if(this.preventDefault){
6535 this.fireEvent('click', this, e);
6538 disable : function()
6540 this.setDisabled(true);
6545 this.setDisabled(false);
6548 setDisabled : function(state)
6550 if(this.disabled == state){
6554 this.disabled = state;
6557 this.el.addClass('disabled');
6561 this.el.removeClass('disabled');
6566 setActive : function(state)
6568 if(this.active == state){
6572 this.active = state;
6575 this.el.addClass('active');
6579 this.el.removeClass('active');
6584 isActive: function ()
6589 setBadge : function(str)
6595 this.badgeEl.dom.innerHTML = str;
6612 * @class Roo.bootstrap.Row
6613 * @extends Roo.bootstrap.Component
6614 * Bootstrap Row class (contains columns...)
6618 * @param {Object} config The config object
6621 Roo.bootstrap.Row = function(config){
6622 Roo.bootstrap.Row.superclass.constructor.call(this, config);
6625 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
6627 getAutoCreate : function(){
6646 * @class Roo.bootstrap.Pagination
6647 * @extends Roo.bootstrap.Component
6648 * Bootstrap Pagination class
6649 * @cfg {String} size xs | sm | md | lg
6650 * @cfg {Boolean} inverse false | true
6653 * Create a new Pagination
6654 * @param {Object} config The config object
6657 Roo.bootstrap.Pagination = function(config){
6658 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
6661 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
6667 getAutoCreate : function(){
6673 cfg.cls += ' inverse';
6679 cfg.cls += " " + this.cls;
6697 * @class Roo.bootstrap.PaginationItem
6698 * @extends Roo.bootstrap.Component
6699 * Bootstrap PaginationItem class
6700 * @cfg {String} html text
6701 * @cfg {String} href the link
6702 * @cfg {Boolean} preventDefault (true | false) default true
6703 * @cfg {Boolean} active (true | false) default false
6704 * @cfg {Boolean} disabled default false
6708 * Create a new PaginationItem
6709 * @param {Object} config The config object
6713 Roo.bootstrap.PaginationItem = function(config){
6714 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
6719 * The raw click event for the entire grid.
6720 * @param {Roo.EventObject} e
6726 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
6730 preventDefault: true,
6735 getAutoCreate : function(){
6741 href : this.href ? this.href : '#',
6742 html : this.html ? this.html : ''
6752 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
6756 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
6762 initEvents: function() {
6764 this.el.on('click', this.onClick, this);
6767 onClick : function(e)
6769 Roo.log('PaginationItem on click ');
6770 if(this.preventDefault){
6778 this.fireEvent('click', this, e);
6794 * @class Roo.bootstrap.Slider
6795 * @extends Roo.bootstrap.Component
6796 * Bootstrap Slider class
6799 * Create a new Slider
6800 * @param {Object} config The config object
6803 Roo.bootstrap.Slider = function(config){
6804 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
6807 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
6809 getAutoCreate : function(){
6813 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
6817 cls: 'ui-slider-handle ui-state-default ui-corner-all'
6829 * Ext JS Library 1.1.1
6830 * Copyright(c) 2006-2007, Ext JS, LLC.
6832 * Originally Released Under LGPL - original licence link has changed is not relivant.
6835 * <script type="text/javascript">
6840 * @class Roo.grid.ColumnModel
6841 * @extends Roo.util.Observable
6842 * This is the default implementation of a ColumnModel used by the Grid. It defines
6843 * the columns in the grid.
6846 var colModel = new Roo.grid.ColumnModel([
6847 {header: "Ticker", width: 60, sortable: true, locked: true},
6848 {header: "Company Name", width: 150, sortable: true},
6849 {header: "Market Cap.", width: 100, sortable: true},
6850 {header: "$ Sales", width: 100, sortable: true, renderer: money},
6851 {header: "Employees", width: 100, sortable: true, resizable: false}
6856 * The config options listed for this class are options which may appear in each
6857 * individual column definition.
6858 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
6860 * @param {Object} config An Array of column config objects. See this class's
6861 * config objects for details.
6863 Roo.grid.ColumnModel = function(config){
6865 * The config passed into the constructor
6867 this.config = config;
6870 // if no id, create one
6871 // if the column does not have a dataIndex mapping,
6872 // map it to the order it is in the config
6873 for(var i = 0, len = config.length; i < len; i++){
6875 if(typeof c.dataIndex == "undefined"){
6878 if(typeof c.renderer == "string"){
6879 c.renderer = Roo.util.Format[c.renderer];
6881 if(typeof c.id == "undefined"){
6884 if(c.editor && c.editor.xtype){
6885 c.editor = Roo.factory(c.editor, Roo.grid);
6887 if(c.editor && c.editor.isFormField){
6888 c.editor = new Roo.grid.GridEditor(c.editor);
6890 this.lookup[c.id] = c;
6894 * The width of columns which have no width specified (defaults to 100)
6897 this.defaultWidth = 100;
6900 * Default sortable of columns which have no sortable specified (defaults to false)
6903 this.defaultSortable = false;
6907 * @event widthchange
6908 * Fires when the width of a column changes.
6909 * @param {ColumnModel} this
6910 * @param {Number} columnIndex The column index
6911 * @param {Number} newWidth The new width
6913 "widthchange": true,
6915 * @event headerchange
6916 * Fires when the text of a header changes.
6917 * @param {ColumnModel} this
6918 * @param {Number} columnIndex The column index
6919 * @param {Number} newText The new header text
6921 "headerchange": true,
6923 * @event hiddenchange
6924 * Fires when a column is hidden or "unhidden".
6925 * @param {ColumnModel} this
6926 * @param {Number} columnIndex The column index
6927 * @param {Boolean} hidden true if hidden, false otherwise
6929 "hiddenchange": true,
6931 * @event columnmoved
6932 * Fires when a column is moved.
6933 * @param {ColumnModel} this
6934 * @param {Number} oldIndex
6935 * @param {Number} newIndex
6937 "columnmoved" : true,
6939 * @event columlockchange
6940 * Fires when a column's locked state is changed
6941 * @param {ColumnModel} this
6942 * @param {Number} colIndex
6943 * @param {Boolean} locked true if locked
6945 "columnlockchange" : true
6947 Roo.grid.ColumnModel.superclass.constructor.call(this);
6949 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
6951 * @cfg {String} header The header text to display in the Grid view.
6954 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
6955 * {@link Roo.data.Record} definition from which to draw the column's value. If not
6956 * specified, the column's index is used as an index into the Record's data Array.
6959 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
6960 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
6963 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
6964 * Defaults to the value of the {@link #defaultSortable} property.
6965 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
6968 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
6971 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
6974 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
6977 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
6980 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
6981 * given the cell's data value. See {@link #setRenderer}. If not specified, the
6982 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
6983 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
6986 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
6989 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
6992 * @cfg {String} valign (Optional) Set the CSS vertical-align property of the column (eg. middle, top, bottom etc). Defaults to undefined.
6995 * @cfg {String} cursor (Optional)
6998 * @cfg {String} tooltip (Optional)
7001 * @cfg {Number} xs (Optional)
7004 * @cfg {Number} sm (Optional)
7007 * @cfg {Number} md (Optional)
7010 * @cfg {Number} lg (Optional)
7013 * Returns the id of the column at the specified index.
7014 * @param {Number} index The column index
7015 * @return {String} the id
7017 getColumnId : function(index){
7018 return this.config[index].id;
7022 * Returns the column for a specified id.
7023 * @param {String} id The column id
7024 * @return {Object} the column
7026 getColumnById : function(id){
7027 return this.lookup[id];
7032 * Returns the column for a specified dataIndex.
7033 * @param {String} dataIndex The column dataIndex
7034 * @return {Object|Boolean} the column or false if not found
7036 getColumnByDataIndex: function(dataIndex){
7037 var index = this.findColumnIndex(dataIndex);
7038 return index > -1 ? this.config[index] : false;
7042 * Returns the index for a specified column id.
7043 * @param {String} id The column id
7044 * @return {Number} the index, or -1 if not found
7046 getIndexById : function(id){
7047 for(var i = 0, len = this.config.length; i < len; i++){
7048 if(this.config[i].id == id){
7056 * Returns the index for a specified column dataIndex.
7057 * @param {String} dataIndex The column dataIndex
7058 * @return {Number} the index, or -1 if not found
7061 findColumnIndex : function(dataIndex){
7062 for(var i = 0, len = this.config.length; i < len; i++){
7063 if(this.config[i].dataIndex == dataIndex){
7071 moveColumn : function(oldIndex, newIndex){
7072 var c = this.config[oldIndex];
7073 this.config.splice(oldIndex, 1);
7074 this.config.splice(newIndex, 0, c);
7075 this.dataMap = null;
7076 this.fireEvent("columnmoved", this, oldIndex, newIndex);
7079 isLocked : function(colIndex){
7080 return this.config[colIndex].locked === true;
7083 setLocked : function(colIndex, value, suppressEvent){
7084 if(this.isLocked(colIndex) == value){
7087 this.config[colIndex].locked = value;
7089 this.fireEvent("columnlockchange", this, colIndex, value);
7093 getTotalLockedWidth : function(){
7095 for(var i = 0; i < this.config.length; i++){
7096 if(this.isLocked(i) && !this.isHidden(i)){
7097 this.totalWidth += this.getColumnWidth(i);
7103 getLockedCount : function(){
7104 for(var i = 0, len = this.config.length; i < len; i++){
7105 if(!this.isLocked(i)){
7110 return this.config.length;
7114 * Returns the number of columns.
7117 getColumnCount : function(visibleOnly){
7118 if(visibleOnly === true){
7120 for(var i = 0, len = this.config.length; i < len; i++){
7121 if(!this.isHidden(i)){
7127 return this.config.length;
7131 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
7132 * @param {Function} fn
7133 * @param {Object} scope (optional)
7134 * @return {Array} result
7136 getColumnsBy : function(fn, scope){
7138 for(var i = 0, len = this.config.length; i < len; i++){
7139 var c = this.config[i];
7140 if(fn.call(scope||this, c, i) === true){
7148 * Returns true if the specified column is sortable.
7149 * @param {Number} col The column index
7152 isSortable : function(col){
7153 if(typeof this.config[col].sortable == "undefined"){
7154 return this.defaultSortable;
7156 return this.config[col].sortable;
7160 * Returns the rendering (formatting) function defined for the column.
7161 * @param {Number} col The column index.
7162 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
7164 getRenderer : function(col){
7165 if(!this.config[col].renderer){
7166 return Roo.grid.ColumnModel.defaultRenderer;
7168 return this.config[col].renderer;
7172 * Sets the rendering (formatting) function for a column.
7173 * @param {Number} col The column index
7174 * @param {Function} fn The function to use to process the cell's raw data
7175 * to return HTML markup for the grid view. The render function is called with
7176 * the following parameters:<ul>
7177 * <li>Data value.</li>
7178 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
7179 * <li>css A CSS style string to apply to the table cell.</li>
7180 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
7181 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
7182 * <li>Row index</li>
7183 * <li>Column index</li>
7184 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
7186 setRenderer : function(col, fn){
7187 this.config[col].renderer = fn;
7191 * Returns the width for the specified column.
7192 * @param {Number} col The column index
7195 getColumnWidth : function(col){
7196 return this.config[col].width * 1 || this.defaultWidth;
7200 * Sets the width for a column.
7201 * @param {Number} col The column index
7202 * @param {Number} width The new width
7204 setColumnWidth : function(col, width, suppressEvent){
7205 this.config[col].width = width;
7206 this.totalWidth = null;
7208 this.fireEvent("widthchange", this, col, width);
7213 * Returns the total width of all columns.
7214 * @param {Boolean} includeHidden True to include hidden column widths
7217 getTotalWidth : function(includeHidden){
7218 if(!this.totalWidth){
7219 this.totalWidth = 0;
7220 for(var i = 0, len = this.config.length; i < len; i++){
7221 if(includeHidden || !this.isHidden(i)){
7222 this.totalWidth += this.getColumnWidth(i);
7226 return this.totalWidth;
7230 * Returns the header for the specified column.
7231 * @param {Number} col The column index
7234 getColumnHeader : function(col){
7235 return this.config[col].header;
7239 * Sets the header for a column.
7240 * @param {Number} col The column index
7241 * @param {String} header The new header
7243 setColumnHeader : function(col, header){
7244 this.config[col].header = header;
7245 this.fireEvent("headerchange", this, col, header);
7249 * Returns the tooltip for the specified column.
7250 * @param {Number} col The column index
7253 getColumnTooltip : function(col){
7254 return this.config[col].tooltip;
7257 * Sets the tooltip for a column.
7258 * @param {Number} col The column index
7259 * @param {String} tooltip The new tooltip
7261 setColumnTooltip : function(col, tooltip){
7262 this.config[col].tooltip = tooltip;
7266 * Returns the dataIndex for the specified column.
7267 * @param {Number} col The column index
7270 getDataIndex : function(col){
7271 return this.config[col].dataIndex;
7275 * Sets the dataIndex for a column.
7276 * @param {Number} col The column index
7277 * @param {Number} dataIndex The new dataIndex
7279 setDataIndex : function(col, dataIndex){
7280 this.config[col].dataIndex = dataIndex;
7286 * Returns true if the cell is editable.
7287 * @param {Number} colIndex The column index
7288 * @param {Number} rowIndex The row index - this is nto actually used..?
7291 isCellEditable : function(colIndex, rowIndex){
7292 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
7296 * Returns the editor defined for the cell/column.
7297 * return false or null to disable editing.
7298 * @param {Number} colIndex The column index
7299 * @param {Number} rowIndex The row index
7302 getCellEditor : function(colIndex, rowIndex){
7303 return this.config[colIndex].editor;
7307 * Sets if a column is editable.
7308 * @param {Number} col The column index
7309 * @param {Boolean} editable True if the column is editable
7311 setEditable : function(col, editable){
7312 this.config[col].editable = editable;
7317 * Returns true if the column is hidden.
7318 * @param {Number} colIndex The column index
7321 isHidden : function(colIndex){
7322 return this.config[colIndex].hidden;
7327 * Returns true if the column width cannot be changed
7329 isFixed : function(colIndex){
7330 return this.config[colIndex].fixed;
7334 * Returns true if the column can be resized
7337 isResizable : function(colIndex){
7338 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
7341 * Sets if a column is hidden.
7342 * @param {Number} colIndex The column index
7343 * @param {Boolean} hidden True if the column is hidden
7345 setHidden : function(colIndex, hidden){
7346 this.config[colIndex].hidden = hidden;
7347 this.totalWidth = null;
7348 this.fireEvent("hiddenchange", this, colIndex, hidden);
7352 * Sets the editor for a column.
7353 * @param {Number} col The column index
7354 * @param {Object} editor The editor object
7356 setEditor : function(col, editor){
7357 this.config[col].editor = editor;
7361 Roo.grid.ColumnModel.defaultRenderer = function(value)
7363 if(typeof value == "object") {
7366 if(typeof value == "string" && value.length < 1){
7370 return String.format("{0}", value);
7373 // Alias for backwards compatibility
7374 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
7377 * Ext JS Library 1.1.1
7378 * Copyright(c) 2006-2007, Ext JS, LLC.
7380 * Originally Released Under LGPL - original licence link has changed is not relivant.
7383 * <script type="text/javascript">
7387 * @class Roo.LoadMask
7388 * A simple utility class for generically masking elements while loading data. If the element being masked has
7389 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
7390 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
7391 * element's UpdateManager load indicator and will be destroyed after the initial load.
7393 * Create a new LoadMask
7394 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
7395 * @param {Object} config The config object
7397 Roo.LoadMask = function(el, config){
7398 this.el = Roo.get(el);
7399 Roo.apply(this, config);
7401 this.store.on('beforeload', this.onBeforeLoad, this);
7402 this.store.on('load', this.onLoad, this);
7403 this.store.on('loadexception', this.onLoadException, this);
7404 this.removeMask = false;
7406 var um = this.el.getUpdateManager();
7407 um.showLoadIndicator = false; // disable the default indicator
7408 um.on('beforeupdate', this.onBeforeLoad, this);
7409 um.on('update', this.onLoad, this);
7410 um.on('failure', this.onLoad, this);
7411 this.removeMask = true;
7415 Roo.LoadMask.prototype = {
7417 * @cfg {Boolean} removeMask
7418 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
7419 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
7423 * The text to display in a centered loading message box (defaults to 'Loading...')
7427 * @cfg {String} msgCls
7428 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
7430 msgCls : 'x-mask-loading',
7433 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
7439 * Disables the mask to prevent it from being displayed
7441 disable : function(){
7442 this.disabled = true;
7446 * Enables the mask so that it can be displayed
7448 enable : function(){
7449 this.disabled = false;
7452 onLoadException : function()
7456 if (typeof(arguments[3]) != 'undefined') {
7457 Roo.MessageBox.alert("Error loading",arguments[3]);
7461 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
7462 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
7469 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
7474 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
7478 onBeforeLoad : function(){
7480 (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
7485 destroy : function(){
7487 this.store.un('beforeload', this.onBeforeLoad, this);
7488 this.store.un('load', this.onLoad, this);
7489 this.store.un('loadexception', this.onLoadException, this);
7491 var um = this.el.getUpdateManager();
7492 um.un('beforeupdate', this.onBeforeLoad, this);
7493 um.un('update', this.onLoad, this);
7494 um.un('failure', this.onLoad, this);
7505 * @class Roo.bootstrap.Table
7506 * @extends Roo.bootstrap.Component
7507 * Bootstrap Table class
7508 * @cfg {String} cls table class
7509 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
7510 * @cfg {String} bgcolor Specifies the background color for a table
7511 * @cfg {Number} border Specifies whether the table cells should have borders or not
7512 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
7513 * @cfg {Number} cellspacing Specifies the space between cells
7514 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
7515 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
7516 * @cfg {String} sortable Specifies that the table should be sortable
7517 * @cfg {String} summary Specifies a summary of the content of a table
7518 * @cfg {Number} width Specifies the width of a table
7519 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
7521 * @cfg {boolean} striped Should the rows be alternative striped
7522 * @cfg {boolean} bordered Add borders to the table
7523 * @cfg {boolean} hover Add hover highlighting
7524 * @cfg {boolean} condensed Format condensed
7525 * @cfg {boolean} responsive Format condensed
7526 * @cfg {Boolean} loadMask (true|false) default false
7527 * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
7528 * @cfg {Boolean} headerShow (true|false) generate thead, default true
7529 * @cfg {Boolean} rowSelection (true|false) default false
7530 * @cfg {Boolean} cellSelection (true|false) default false
7531 * @cfg {Boolean} scrollBody (true|false) default false - body scrolled / fixed header
7532 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
7533 * @cfg {Boolean} lazyLoad auto load data while scrolling to the end (default false)
7534 * @cfg {Boolean} auto_hide_footer auto hide footer if only one page (default false)
7538 * Create a new Table
7539 * @param {Object} config The config object
7542 Roo.bootstrap.Table = function(config){
7543 Roo.bootstrap.Table.superclass.constructor.call(this, config);
7548 this.rowSelection = (typeof(config.rowSelection) != 'undefined') ? config.rowSelection : this.rowSelection;
7549 this.cellSelection = (typeof(config.cellSelection) != 'undefined') ? config.cellSelection : this.cellSelection;
7550 this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
7551 this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
7553 this.sm = this.sm || {xtype: 'RowSelectionModel'};
7555 this.sm.grid = this;
7556 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
7557 this.sm = this.selModel;
7558 this.sm.xmodule = this.xmodule || false;
7561 if (this.cm && typeof(this.cm.config) == 'undefined') {
7562 this.colModel = new Roo.grid.ColumnModel(this.cm);
7563 this.cm = this.colModel;
7564 this.cm.xmodule = this.xmodule || false;
7567 this.store= Roo.factory(this.store, Roo.data);
7568 this.ds = this.store;
7569 this.ds.xmodule = this.xmodule || false;
7572 if (this.footer && this.store) {
7573 this.footer.dataSource = this.ds;
7574 this.footer = Roo.factory(this.footer);
7581 * Fires when a cell is clicked
7582 * @param {Roo.bootstrap.Table} this
7583 * @param {Roo.Element} el
7584 * @param {Number} rowIndex
7585 * @param {Number} columnIndex
7586 * @param {Roo.EventObject} e
7590 * @event celldblclick
7591 * Fires when a cell is double clicked
7592 * @param {Roo.bootstrap.Table} this
7593 * @param {Roo.Element} el
7594 * @param {Number} rowIndex
7595 * @param {Number} columnIndex
7596 * @param {Roo.EventObject} e
7598 "celldblclick" : true,
7601 * Fires when a row is clicked
7602 * @param {Roo.bootstrap.Table} this
7603 * @param {Roo.Element} el
7604 * @param {Number} rowIndex
7605 * @param {Roo.EventObject} e
7609 * @event rowdblclick
7610 * Fires when a row is double clicked
7611 * @param {Roo.bootstrap.Table} this
7612 * @param {Roo.Element} el
7613 * @param {Number} rowIndex
7614 * @param {Roo.EventObject} e
7616 "rowdblclick" : true,
7619 * Fires when a mouseover occur
7620 * @param {Roo.bootstrap.Table} this
7621 * @param {Roo.Element} el
7622 * @param {Number} rowIndex
7623 * @param {Number} columnIndex
7624 * @param {Roo.EventObject} e
7629 * Fires when a mouseout occur
7630 * @param {Roo.bootstrap.Table} this
7631 * @param {Roo.Element} el
7632 * @param {Number} rowIndex
7633 * @param {Number} columnIndex
7634 * @param {Roo.EventObject} e
7639 * Fires when a row is rendered, so you can change add a style to it.
7640 * @param {Roo.bootstrap.Table} this
7641 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
7645 * @event rowsrendered
7646 * Fires when all the rows have been rendered
7647 * @param {Roo.bootstrap.Table} this
7649 'rowsrendered' : true,
7651 * @event contextmenu
7652 * The raw contextmenu event for the entire grid.
7653 * @param {Roo.EventObject} e
7655 "contextmenu" : true,
7657 * @event rowcontextmenu
7658 * Fires when a row is right clicked
7659 * @param {Roo.bootstrap.Table} this
7660 * @param {Number} rowIndex
7661 * @param {Roo.EventObject} e
7663 "rowcontextmenu" : true,
7665 * @event cellcontextmenu
7666 * Fires when a cell is right clicked
7667 * @param {Roo.bootstrap.Table} this
7668 * @param {Number} rowIndex
7669 * @param {Number} cellIndex
7670 * @param {Roo.EventObject} e
7672 "cellcontextmenu" : true,
7674 * @event headercontextmenu
7675 * Fires when a header is right clicked
7676 * @param {Roo.bootstrap.Table} this
7677 * @param {Number} columnIndex
7678 * @param {Roo.EventObject} e
7680 "headercontextmenu" : true
7684 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
7710 rowSelection : false,
7711 cellSelection : false,
7714 // Roo.Element - the tbody
7716 // Roo.Element - thead element
7719 container: false, // used by gridpanel...
7725 auto_hide_footer : false,
7727 getAutoCreate : function()
7729 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
7736 if (this.scrollBody) {
7737 cfg.cls += ' table-body-fixed';
7740 cfg.cls += ' table-striped';
7744 cfg.cls += ' table-hover';
7746 if (this.bordered) {
7747 cfg.cls += ' table-bordered';
7749 if (this.condensed) {
7750 cfg.cls += ' table-condensed';
7752 if (this.responsive) {
7753 cfg.cls += ' table-responsive';
7757 cfg.cls+= ' ' +this.cls;
7760 // this lot should be simplifed...
7773 ].forEach(function(k) {
7781 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
7784 if(this.store || this.cm){
7785 if(this.headerShow){
7786 cfg.cn.push(this.renderHeader());
7789 cfg.cn.push(this.renderBody());
7791 if(this.footerShow){
7792 cfg.cn.push(this.renderFooter());
7794 // where does this come from?
7795 //cfg.cls+= ' TableGrid';
7798 return { cn : [ cfg ] };
7801 initEvents : function()
7803 if(!this.store || !this.cm){
7806 if (this.selModel) {
7807 this.selModel.initEvents();
7811 //Roo.log('initEvents with ds!!!!');
7813 this.mainBody = this.el.select('tbody', true).first();
7814 this.mainHead = this.el.select('thead', true).first();
7815 this.mainFoot = this.el.select('tfoot', true).first();
7821 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
7822 e.on('click', _this.sort, _this);
7825 this.mainBody.on("click", this.onClick, this);
7826 this.mainBody.on("dblclick", this.onDblClick, this);
7828 // why is this done????? = it breaks dialogs??
7829 //this.parent().el.setStyle('position', 'relative');
7833 this.footer.parentId = this.id;
7834 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
7837 this.el.select('tfoot tr td').first().addClass('hide');
7842 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
7845 this.store.on('load', this.onLoad, this);
7846 this.store.on('beforeload', this.onBeforeLoad, this);
7847 this.store.on('update', this.onUpdate, this);
7848 this.store.on('add', this.onAdd, this);
7849 this.store.on("clear", this.clear, this);
7851 this.el.on("contextmenu", this.onContextMenu, this);
7853 this.mainBody.on('scroll', this.onBodyScroll, this);
7855 this.cm.on("headerchange", this.onHeaderChange, this);
7857 this.cm.on("hiddenchange", this.onHiddenChange, this, arguments);
7861 onContextMenu : function(e, t)
7863 this.processEvent("contextmenu", e);
7866 processEvent : function(name, e)
7868 if (name != 'touchstart' ) {
7869 this.fireEvent(name, e);
7872 var t = e.getTarget();
7874 var cell = Roo.get(t);
7880 if(cell.findParent('tfoot', false, true)){
7884 if(cell.findParent('thead', false, true)){
7886 if(e.getTarget().nodeName.toLowerCase() != 'th'){
7887 cell = Roo.get(t).findParent('th', false, true);
7889 Roo.log("failed to find th in thead?");
7890 Roo.log(e.getTarget());
7895 var cellIndex = cell.dom.cellIndex;
7897 var ename = name == 'touchstart' ? 'click' : name;
7898 this.fireEvent("header" + ename, this, cellIndex, e);
7903 if(e.getTarget().nodeName.toLowerCase() != 'td'){
7904 cell = Roo.get(t).findParent('td', false, true);
7906 Roo.log("failed to find th in tbody?");
7907 Roo.log(e.getTarget());
7912 var row = cell.findParent('tr', false, true);
7913 var cellIndex = cell.dom.cellIndex;
7914 var rowIndex = row.dom.rowIndex - 1;
7918 this.fireEvent("row" + name, this, rowIndex, e);
7922 this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
7928 onMouseover : function(e, el)
7930 var cell = Roo.get(el);
7936 if(e.getTarget().nodeName.toLowerCase() != 'td'){
7937 cell = cell.findParent('td', false, true);
7940 var row = cell.findParent('tr', false, true);
7941 var cellIndex = cell.dom.cellIndex;
7942 var rowIndex = row.dom.rowIndex - 1; // start from 0
7944 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
7948 onMouseout : function(e, el)
7950 var cell = Roo.get(el);
7956 if(e.getTarget().nodeName.toLowerCase() != 'td'){
7957 cell = cell.findParent('td', false, true);
7960 var row = cell.findParent('tr', false, true);
7961 var cellIndex = cell.dom.cellIndex;
7962 var rowIndex = row.dom.rowIndex - 1; // start from 0
7964 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
7968 onClick : function(e, el)
7970 var cell = Roo.get(el);
7972 if(!cell || (!this.cellSelection && !this.rowSelection)){
7976 if(e.getTarget().nodeName.toLowerCase() != 'td'){
7977 cell = cell.findParent('td', false, true);
7980 if(!cell || typeof(cell) == 'undefined'){
7984 var row = cell.findParent('tr', false, true);
7986 if(!row || typeof(row) == 'undefined'){
7990 var cellIndex = cell.dom.cellIndex;
7991 var rowIndex = this.getRowIndex(row);
7993 // why??? - should these not be based on SelectionModel?
7994 if(this.cellSelection){
7995 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
7998 if(this.rowSelection){
7999 this.fireEvent('rowclick', this, row, rowIndex, e);
8005 onDblClick : function(e,el)
8007 var cell = Roo.get(el);
8009 if(!cell || (!this.cellSelection && !this.rowSelection)){
8013 if(e.getTarget().nodeName.toLowerCase() != 'td'){
8014 cell = cell.findParent('td', false, true);
8017 if(!cell || typeof(cell) == 'undefined'){
8021 var row = cell.findParent('tr', false, true);
8023 if(!row || typeof(row) == 'undefined'){
8027 var cellIndex = cell.dom.cellIndex;
8028 var rowIndex = this.getRowIndex(row);
8030 if(this.cellSelection){
8031 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
8034 if(this.rowSelection){
8035 this.fireEvent('rowdblclick', this, row, rowIndex, e);
8039 sort : function(e,el)
8041 var col = Roo.get(el);
8043 if(!col.hasClass('sortable')){
8047 var sort = col.attr('sort');
8050 if(col.select('i', true).first().hasClass('glyphicon-arrow-up')){
8054 this.store.sortInfo = {field : sort, direction : dir};
8057 Roo.log("calling footer first");
8058 this.footer.onClick('first');
8061 this.store.load({ params : { start : 0 } });
8065 renderHeader : function()
8073 this.totalWidth = 0;
8075 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
8077 var config = cm.config[i];
8081 cls : 'x-hcol-' + i,
8083 html: cm.getColumnHeader(i)
8088 if(typeof(config.sortable) != 'undefined' && config.sortable){
8090 c.html = '<i class="glyphicon"></i>' + c.html;
8093 // could use BS4 hidden-..-down
8095 if(typeof(config.lgHeader) != 'undefined'){
8096 hh += '<span class="hidden-xs hidden-sm hidden-md ">' + config.lgHeader + '</span>';
8099 if(typeof(config.mdHeader) != 'undefined'){
8100 hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
8103 if(typeof(config.smHeader) != 'undefined'){
8104 hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
8107 if(typeof(config.xsHeader) != 'undefined'){
8108 hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
8115 if(typeof(config.tooltip) != 'undefined'){
8116 c.tooltip = config.tooltip;
8119 if(typeof(config.colspan) != 'undefined'){
8120 c.colspan = config.colspan;
8123 if(typeof(config.hidden) != 'undefined' && config.hidden){
8124 c.style += ' display:none;';
8127 if(typeof(config.dataIndex) != 'undefined'){
8128 c.sort = config.dataIndex;
8133 if(typeof(config.align) != 'undefined' && config.align.length){
8134 c.style += ' text-align:' + config.align + ';';
8137 if(typeof(config.width) != 'undefined'){
8138 c.style += ' width:' + config.width + 'px;';
8139 this.totalWidth += config.width;
8141 this.totalWidth += 100; // assume minimum of 100 per column?
8144 if(typeof(config.cls) != 'undefined'){
8145 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
8148 ['xs','sm','md','lg'].map(function(size){
8150 if(typeof(config[size]) == 'undefined'){
8154 if (!config[size]) { // 0 = hidden
8155 // BS 4 '0' is treated as hide that column and below.
8156 c.cls += ' hidden-' + size + ' hidden' + size + '-down';
8160 c.cls += ' col-' + size + '-' + config[size] + (
8161 size == 'xs' ? (' col-' + config[size] ) : '' // bs4 col-{num} replaces col-xs
8173 renderBody : function()
8183 colspan : this.cm.getColumnCount()
8193 renderFooter : function()
8203 colspan : this.cm.getColumnCount()
8217 // Roo.log('ds onload');
8222 var ds = this.store;
8224 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
8225 e.select('i', true).removeClass(['glyphicon-arrow-up', 'glyphicon-arrow-down']);
8226 if (_this.store.sortInfo) {
8228 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
8229 e.select('i', true).addClass(['glyphicon-arrow-up']);
8232 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
8233 e.select('i', true).addClass(['glyphicon-arrow-down']);
8238 var tbody = this.mainBody;
8240 if(ds.getCount() > 0){
8241 ds.data.each(function(d,rowIndex){
8242 var row = this.renderRow(cm, ds, rowIndex);
8244 tbody.createChild(row);
8248 if(row.cellObjects.length){
8249 Roo.each(row.cellObjects, function(r){
8250 _this.renderCellObject(r);
8257 var tfoot = this.el.select('tfoot', true).first();
8259 if(this.footerShow && this.auto_hide_footer && this.mainFoot){
8261 this.mainFoot.setVisibilityMode(Roo.Element.DISPLAY).hide();
8263 var total = this.ds.getTotalCount();
8265 if(this.footer.pageSize < total){
8266 this.mainFoot.show();
8270 Roo.each(this.el.select('tbody td', true).elements, function(e){
8271 e.on('mouseover', _this.onMouseover, _this);
8274 Roo.each(this.el.select('tbody td', true).elements, function(e){
8275 e.on('mouseout', _this.onMouseout, _this);
8277 this.fireEvent('rowsrendered', this);
8283 onUpdate : function(ds,record)
8285 this.refreshRow(record);
8289 onRemove : function(ds, record, index, isUpdate){
8290 if(isUpdate !== true){
8291 this.fireEvent("beforerowremoved", this, index, record);
8293 var bt = this.mainBody.dom;
8295 var rows = this.el.select('tbody > tr', true).elements;
8297 if(typeof(rows[index]) != 'undefined'){
8298 bt.removeChild(rows[index].dom);
8301 // if(bt.rows[index]){
8302 // bt.removeChild(bt.rows[index]);
8305 if(isUpdate !== true){
8306 //this.stripeRows(index);
8307 //this.syncRowHeights(index, index);
8309 this.fireEvent("rowremoved", this, index, record);
8313 onAdd : function(ds, records, rowIndex)
8315 //Roo.log('on Add called');
8316 // - note this does not handle multiple adding very well..
8317 var bt = this.mainBody.dom;
8318 for (var i =0 ; i < records.length;i++) {
8319 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
8320 //Roo.log(records[i]);
8321 //Roo.log(this.store.getAt(rowIndex+i));
8322 this.insertRow(this.store, rowIndex + i, false);
8329 refreshRow : function(record){
8330 var ds = this.store, index;
8331 if(typeof record == 'number'){
8333 record = ds.getAt(index);
8335 index = ds.indexOf(record);
8337 return; // should not happen - but seems to
8340 this.insertRow(ds, index, true);
8342 this.onRemove(ds, record, index+1, true);
8344 //this.syncRowHeights(index, index);
8346 this.fireEvent("rowupdated", this, index, record);
8349 insertRow : function(dm, rowIndex, isUpdate){
8352 this.fireEvent("beforerowsinserted", this, rowIndex);
8354 //var s = this.getScrollState();
8355 var row = this.renderRow(this.cm, this.store, rowIndex);
8356 // insert before rowIndex..
8357 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
8361 if(row.cellObjects.length){
8362 Roo.each(row.cellObjects, function(r){
8363 _this.renderCellObject(r);
8368 this.fireEvent("rowsinserted", this, rowIndex);
8369 //this.syncRowHeights(firstRow, lastRow);
8370 //this.stripeRows(firstRow);
8377 getRowDom : function(rowIndex)
8379 var rows = this.el.select('tbody > tr', true).elements;
8381 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
8384 // returns the object tree for a tr..
8387 renderRow : function(cm, ds, rowIndex)
8389 var d = ds.getAt(rowIndex);
8393 cls : 'x-row-' + rowIndex,
8397 var cellObjects = [];
8399 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
8400 var config = cm.config[i];
8402 var renderer = cm.getRenderer(i);
8406 if(typeof(renderer) !== 'undefined'){
8407 value = renderer(d.data[cm.getDataIndex(i)], false, d);
8409 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
8410 // and are rendered into the cells after the row is rendered - using the id for the element.
8412 if(typeof(value) === 'object'){
8422 rowIndex : rowIndex,
8427 this.fireEvent('rowclass', this, rowcfg);
8431 cls : rowcfg.rowClass + ' x-col-' + i,
8433 html: (typeof(value) === 'object') ? '' : value
8440 if(typeof(config.colspan) != 'undefined'){
8441 td.colspan = config.colspan;
8444 if(typeof(config.hidden) != 'undefined' && config.hidden){
8445 td.style += ' display:none;';
8448 if(typeof(config.align) != 'undefined' && config.align.length){
8449 td.style += ' text-align:' + config.align + ';';
8451 if(typeof(config.valign) != 'undefined' && config.valign.length){
8452 td.style += ' vertical-align:' + config.valign + ';';
8455 if(typeof(config.width) != 'undefined'){
8456 td.style += ' width:' + config.width + 'px;';
8459 if(typeof(config.cursor) != 'undefined'){
8460 td.style += ' cursor:' + config.cursor + ';';
8463 if(typeof(config.cls) != 'undefined'){
8464 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
8467 ['xs','sm','md','lg'].map(function(size){
8469 if(typeof(config[size]) == 'undefined'){
8475 if (!config[size]) { // 0 = hidden
8476 // BS 4 '0' is treated as hide that column and below.
8477 td.cls += ' hidden-' + size + ' hidden' + size + '-down';
8481 td.cls += ' col-' + size + '-' + config[size] + (
8482 size == 'xs' ? (' col-' + config[size] ) : '' // bs4 col-{num} replaces col-xs
8492 row.cellObjects = cellObjects;
8500 onBeforeLoad : function()
8509 this.el.select('tbody', true).first().dom.innerHTML = '';
8512 * Show or hide a row.
8513 * @param {Number} rowIndex to show or hide
8514 * @param {Boolean} state hide
8516 setRowVisibility : function(rowIndex, state)
8518 var bt = this.mainBody.dom;
8520 var rows = this.el.select('tbody > tr', true).elements;
8522 if(typeof(rows[rowIndex]) == 'undefined'){
8525 rows[rowIndex].dom.style.display = state ? '' : 'none';
8529 getSelectionModel : function(){
8531 this.selModel = new Roo.bootstrap.Table.RowSelectionModel({grid: this});
8533 return this.selModel;
8536 * Render the Roo.bootstrap object from renderder
8538 renderCellObject : function(r)
8542 r.cfg.parentId = (typeof(r.container) == 'string') ? r.container : r.container.id;
8544 var t = r.cfg.render(r.container);
8547 Roo.each(r.cfg.cn, function(c){
8549 container: t.getChildContainer(),
8552 _this.renderCellObject(child);
8557 getRowIndex : function(row)
8561 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
8572 * Returns the grid's underlying element = used by panel.Grid
8573 * @return {Element} The element
8575 getGridEl : function(){
8579 * Forces a resize - used by panel.Grid
8580 * @return {Element} The element
8582 autoSize : function()
8584 //var ctr = Roo.get(this.container.dom.parentElement);
8585 var ctr = Roo.get(this.el.dom);
8587 var thd = this.getGridEl().select('thead',true).first();
8588 var tbd = this.getGridEl().select('tbody', true).first();
8589 var tfd = this.getGridEl().select('tfoot', true).first();
8591 var cw = ctr.getWidth();
8595 tbd.setWidth(ctr.getWidth());
8596 // if the body has a max height - and then scrolls - we should perhaps set up the height here
8597 // this needs fixing for various usage - currently only hydra job advers I think..
8599 // ctr.getHeight() - ((thd ? thd.getHeight() : 0) + (tfd ? tfd.getHeight() : 0))
8601 var barsize = (tbd.dom.offsetWidth - tbd.dom.clientWidth);
8604 cw = Math.max(cw, this.totalWidth);
8605 this.getGridEl().select('tbody tr',true).setWidth(cw);
8606 this.getGridEl().select('tfoot tr, tfoot td',true).setWidth(cw);
8607 // resize 'expandable coloumn?
8609 return; // we doe not have a view in this design..
8612 onBodyScroll: function()
8614 //Roo.log("body scrolled');" + this.mainBody.dom.scrollLeft);
8616 this.mainHead.setStyle({
8617 'position' : 'relative',
8618 'left': (-1* this.mainBody.dom.scrollLeft) + 'px'
8624 var scrollHeight = this.mainBody.dom.scrollHeight;
8626 var scrollTop = Math.ceil(this.mainBody.getScroll().top);
8628 var height = this.mainBody.getHeight();
8630 if(scrollHeight - height == scrollTop) {
8632 var total = this.ds.getTotalCount();
8634 if(this.footer.cursor + this.footer.pageSize < total){
8636 this.footer.ds.load({
8638 start : this.footer.cursor + this.footer.pageSize,
8639 limit : this.footer.pageSize
8649 onHeaderChange : function()
8651 var header = this.renderHeader();
8652 var table = this.el.select('table', true).first();
8654 this.mainHead.remove();
8655 this.mainHead = table.createChild(header, this.mainBody, false);
8658 onHiddenChange : function(colModel, colIndex, hidden)
8660 var thSelector = '#' + this.id + ' .x-hcol-' + colIndex;
8661 var tdSelector = '#' + this.id + ' .x-col-' + colIndex;
8663 this.CSS.updateRule(thSelector, "display", "");
8664 this.CSS.updateRule(tdSelector, "display", "");
8667 this.CSS.updateRule(thSelector, "display", "none");
8668 this.CSS.updateRule(tdSelector, "display", "none");
8671 this.onHeaderChange();
8675 setColumnWidth: function(col_index, width)
8677 // width = "md-2 xs-2..."
8678 if(!this.colModel.config[col_index]) {
8682 var w = width.split(" ");
8684 var rows = this.el.dom.getElementsByClassName("x-col-"+col_index);
8686 var h_row = this.el.dom.getElementsByClassName("x-hcol-"+col_index);
8689 for(var j = 0; j < w.length; j++) {
8695 var size_cls = w[j].split("-");
8697 if(!Number.isInteger(size_cls[1] * 1)) {
8701 if(!this.colModel.config[col_index][size_cls[0]]) {
8705 if(!h_row[0].classList.contains("col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]])) {
8709 h_row[0].classList.replace(
8710 "col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]],
8711 "col-"+size_cls[0]+"-"+size_cls[1]
8714 for(var i = 0; i < rows.length; i++) {
8716 var size_cls = w[j].split("-");
8718 if(!Number.isInteger(size_cls[1] * 1)) {
8722 if(!this.colModel.config[col_index][size_cls[0]]) {
8726 if(!rows[i].classList.contains("col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]])) {
8730 rows[i].classList.replace(
8731 "col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]],
8732 "col-"+size_cls[0]+"-"+size_cls[1]
8736 this.colModel.config[col_index][size_cls[0]] = size_cls[1];
8751 * @class Roo.bootstrap.TableCell
8752 * @extends Roo.bootstrap.Component
8753 * Bootstrap TableCell class
8754 * @cfg {String} html cell contain text
8755 * @cfg {String} cls cell class
8756 * @cfg {String} tag cell tag (td|th) default td
8757 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
8758 * @cfg {String} align Aligns the content in a cell
8759 * @cfg {String} axis Categorizes cells
8760 * @cfg {String} bgcolor Specifies the background color of a cell
8761 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
8762 * @cfg {Number} colspan Specifies the number of columns a cell should span
8763 * @cfg {String} headers Specifies one or more header cells a cell is related to
8764 * @cfg {Number} height Sets the height of a cell
8765 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
8766 * @cfg {Number} rowspan Sets the number of rows a cell should span
8767 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
8768 * @cfg {String} valign Vertical aligns the content in a cell
8769 * @cfg {Number} width Specifies the width of a cell
8772 * Create a new TableCell
8773 * @param {Object} config The config object
8776 Roo.bootstrap.TableCell = function(config){
8777 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
8780 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
8800 getAutoCreate : function(){
8801 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
8821 cfg.align=this.align
8827 cfg.bgcolor=this.bgcolor
8830 cfg.charoff=this.charoff
8833 cfg.colspan=this.colspan
8836 cfg.headers=this.headers
8839 cfg.height=this.height
8842 cfg.nowrap=this.nowrap
8845 cfg.rowspan=this.rowspan
8848 cfg.scope=this.scope
8851 cfg.valign=this.valign
8854 cfg.width=this.width
8873 * @class Roo.bootstrap.TableRow
8874 * @extends Roo.bootstrap.Component
8875 * Bootstrap TableRow class
8876 * @cfg {String} cls row class
8877 * @cfg {String} align Aligns the content in a table row
8878 * @cfg {String} bgcolor Specifies a background color for a table row
8879 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
8880 * @cfg {String} valign Vertical aligns the content in a table row
8883 * Create a new TableRow
8884 * @param {Object} config The config object
8887 Roo.bootstrap.TableRow = function(config){
8888 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
8891 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
8899 getAutoCreate : function(){
8900 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
8910 cfg.align = this.align;
8913 cfg.bgcolor = this.bgcolor;
8916 cfg.charoff = this.charoff;
8919 cfg.valign = this.valign;
8937 * @class Roo.bootstrap.TableBody
8938 * @extends Roo.bootstrap.Component
8939 * Bootstrap TableBody class
8940 * @cfg {String} cls element class
8941 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
8942 * @cfg {String} align Aligns the content inside the element
8943 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
8944 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
8947 * Create a new TableBody
8948 * @param {Object} config The config object
8951 Roo.bootstrap.TableBody = function(config){
8952 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
8955 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
8963 getAutoCreate : function(){
8964 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
8978 cfg.align = this.align;
8981 cfg.charoff = this.charoff;
8984 cfg.valign = this.valign;
8991 // initEvents : function()
8998 // this.store = Roo.factory(this.store, Roo.data);
8999 // this.store.on('load', this.onLoad, this);
9001 // this.store.load();
9005 // onLoad: function ()
9007 // this.fireEvent('load', this);
9017 * Ext JS Library 1.1.1
9018 * Copyright(c) 2006-2007, Ext JS, LLC.
9020 * Originally Released Under LGPL - original licence link has changed is not relivant.
9023 * <script type="text/javascript">
9026 // as we use this in bootstrap.
9027 Roo.namespace('Roo.form');
9029 * @class Roo.form.Action
9030 * Internal Class used to handle form actions
9032 * @param {Roo.form.BasicForm} el The form element or its id
9033 * @param {Object} config Configuration options
9038 // define the action interface
9039 Roo.form.Action = function(form, options){
9041 this.options = options || {};
9044 * Client Validation Failed
9047 Roo.form.Action.CLIENT_INVALID = 'client';
9049 * Server Validation Failed
9052 Roo.form.Action.SERVER_INVALID = 'server';
9054 * Connect to Server Failed
9057 Roo.form.Action.CONNECT_FAILURE = 'connect';
9059 * Reading Data from Server Failed
9062 Roo.form.Action.LOAD_FAILURE = 'load';
9064 Roo.form.Action.prototype = {
9066 failureType : undefined,
9067 response : undefined,
9071 run : function(options){
9076 success : function(response){
9081 handleResponse : function(response){
9085 // default connection failure
9086 failure : function(response){
9088 this.response = response;
9089 this.failureType = Roo.form.Action.CONNECT_FAILURE;
9090 this.form.afterAction(this, false);
9093 processResponse : function(response){
9094 this.response = response;
9095 if(!response.responseText){
9098 this.result = this.handleResponse(response);
9102 // utility functions used internally
9103 getUrl : function(appendParams){
9104 var url = this.options.url || this.form.url || this.form.el.dom.action;
9106 var p = this.getParams();
9108 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
9114 getMethod : function(){
9115 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
9118 getParams : function(){
9119 var bp = this.form.baseParams;
9120 var p = this.options.params;
9122 if(typeof p == "object"){
9123 p = Roo.urlEncode(Roo.applyIf(p, bp));
9124 }else if(typeof p == 'string' && bp){
9125 p += '&' + Roo.urlEncode(bp);
9128 p = Roo.urlEncode(bp);
9133 createCallback : function(){
9135 success: this.success,
9136 failure: this.failure,
9138 timeout: (this.form.timeout*1000),
9139 upload: this.form.fileUpload ? this.success : undefined
9144 Roo.form.Action.Submit = function(form, options){
9145 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
9148 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
9151 haveProgress : false,
9152 uploadComplete : false,
9154 // uploadProgress indicator.
9155 uploadProgress : function()
9157 if (!this.form.progressUrl) {
9161 if (!this.haveProgress) {
9162 Roo.MessageBox.progress("Uploading", "Uploading");
9164 if (this.uploadComplete) {
9165 Roo.MessageBox.hide();
9169 this.haveProgress = true;
9171 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
9173 var c = new Roo.data.Connection();
9175 url : this.form.progressUrl,
9180 success : function(req){
9181 //console.log(data);
9185 rdata = Roo.decode(req.responseText)
9187 Roo.log("Invalid data from server..");
9191 if (!rdata || !rdata.success) {
9193 Roo.MessageBox.alert(Roo.encode(rdata));
9196 var data = rdata.data;
9198 if (this.uploadComplete) {
9199 Roo.MessageBox.hide();
9204 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
9205 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
9208 this.uploadProgress.defer(2000,this);
9211 failure: function(data) {
9212 Roo.log('progress url failed ');
9223 // run get Values on the form, so it syncs any secondary forms.
9224 this.form.getValues();
9226 var o = this.options;
9227 var method = this.getMethod();
9228 var isPost = method == 'POST';
9229 if(o.clientValidation === false || this.form.isValid()){
9231 if (this.form.progressUrl) {
9232 this.form.findField('UPLOAD_IDENTIFIER').setValue(
9233 (new Date() * 1) + '' + Math.random());
9238 Roo.Ajax.request(Roo.apply(this.createCallback(), {
9239 form:this.form.el.dom,
9240 url:this.getUrl(!isPost),
9242 params:isPost ? this.getParams() : null,
9243 isUpload: this.form.fileUpload,
9244 formData : this.form.formData
9247 this.uploadProgress();
9249 }else if (o.clientValidation !== false){ // client validation failed
9250 this.failureType = Roo.form.Action.CLIENT_INVALID;
9251 this.form.afterAction(this, false);
9255 success : function(response)
9257 this.uploadComplete= true;
9258 if (this.haveProgress) {
9259 Roo.MessageBox.hide();
9263 var result = this.processResponse(response);
9264 if(result === true || result.success){
9265 this.form.afterAction(this, true);
9269 this.form.markInvalid(result.errors);
9270 this.failureType = Roo.form.Action.SERVER_INVALID;
9272 this.form.afterAction(this, false);
9274 failure : function(response)
9276 this.uploadComplete= true;
9277 if (this.haveProgress) {
9278 Roo.MessageBox.hide();
9281 this.response = response;
9282 this.failureType = Roo.form.Action.CONNECT_FAILURE;
9283 this.form.afterAction(this, false);
9286 handleResponse : function(response){
9287 if(this.form.errorReader){
9288 var rs = this.form.errorReader.read(response);
9291 for(var i = 0, len = rs.records.length; i < len; i++) {
9292 var r = rs.records[i];
9296 if(errors.length < 1){
9300 success : rs.success,
9306 ret = Roo.decode(response.responseText);
9310 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
9320 Roo.form.Action.Load = function(form, options){
9321 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
9322 this.reader = this.form.reader;
9325 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
9330 Roo.Ajax.request(Roo.apply(
9331 this.createCallback(), {
9332 method:this.getMethod(),
9333 url:this.getUrl(false),
9334 params:this.getParams()
9338 success : function(response){
9340 var result = this.processResponse(response);
9341 if(result === true || !result.success || !result.data){
9342 this.failureType = Roo.form.Action.LOAD_FAILURE;
9343 this.form.afterAction(this, false);
9346 this.form.clearInvalid();
9347 this.form.setValues(result.data);
9348 this.form.afterAction(this, true);
9351 handleResponse : function(response){
9352 if(this.form.reader){
9353 var rs = this.form.reader.read(response);
9354 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
9356 success : rs.success,
9360 return Roo.decode(response.responseText);
9364 Roo.form.Action.ACTION_TYPES = {
9365 'load' : Roo.form.Action.Load,
9366 'submit' : Roo.form.Action.Submit
9375 * @class Roo.bootstrap.Form
9376 * @extends Roo.bootstrap.Component
9377 * Bootstrap Form class
9378 * @cfg {String} method GET | POST (default POST)
9379 * @cfg {String} labelAlign top | left (default top)
9380 * @cfg {String} align left | right - for navbars
9381 * @cfg {Boolean} loadMask load mask when submit (default true)
9386 * @param {Object} config The config object
9390 Roo.bootstrap.Form = function(config){
9392 Roo.bootstrap.Form.superclass.constructor.call(this, config);
9394 Roo.bootstrap.Form.popover.apply();
9398 * @event clientvalidation
9399 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
9400 * @param {Form} this
9401 * @param {Boolean} valid true if the form has passed client-side validation
9403 clientvalidation: true,
9405 * @event beforeaction
9406 * Fires before any action is performed. Return false to cancel the action.
9407 * @param {Form} this
9408 * @param {Action} action The action to be performed
9412 * @event actionfailed
9413 * Fires when an action fails.
9414 * @param {Form} this
9415 * @param {Action} action The action that failed
9417 actionfailed : true,
9419 * @event actioncomplete
9420 * Fires when an action is completed.
9421 * @param {Form} this
9422 * @param {Action} action The action that completed
9424 actioncomplete : true
9428 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
9431 * @cfg {String} method
9432 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
9437 * The URL to use for form actions if one isn't supplied in the action options.
9440 * @cfg {Boolean} fileUpload
9441 * Set to true if this form is a file upload.
9445 * @cfg {Object} baseParams
9446 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
9450 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
9454 * @cfg {Sting} align (left|right) for navbar forms
9459 activeAction : null,
9462 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
9463 * element by passing it or its id or mask the form itself by passing in true.
9466 waitMsgTarget : false,
9471 * @cfg {Boolean} errorMask (true|false) default false
9476 * @cfg {Number} maskOffset Default 100
9481 * @cfg {Boolean} maskBody
9485 getAutoCreate : function(){
9489 method : this.method || 'POST',
9490 id : this.id || Roo.id(),
9493 if (this.parent().xtype.match(/^Nav/)) {
9494 cfg.cls = 'navbar-form form-inline navbar-' + this.align;
9498 if (this.labelAlign == 'left' ) {
9499 cfg.cls += ' form-horizontal';
9505 initEvents : function()
9507 this.el.on('submit', this.onSubmit, this);
9508 // this was added as random key presses on the form where triggering form submit.
9509 this.el.on('keypress', function(e) {
9510 if (e.getCharCode() != 13) {
9513 // we might need to allow it for textareas.. and some other items.
9514 // check e.getTarget().
9516 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
9520 Roo.log("keypress blocked");
9528 onSubmit : function(e){
9533 * Returns true if client-side validation on the form is successful.
9536 isValid : function(){
9537 var items = this.getItems();
9541 items.each(function(f){
9547 Roo.log('invalid field: ' + f.name);
9551 if(!target && f.el.isVisible(true)){
9557 if(this.errorMask && !valid){
9558 Roo.bootstrap.Form.popover.mask(this, target);
9565 * Returns true if any fields in this form have changed since their original load.
9568 isDirty : function(){
9570 var items = this.getItems();
9571 items.each(function(f){
9581 * Performs a predefined action (submit or load) or custom actions you define on this form.
9582 * @param {String} actionName The name of the action type
9583 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
9584 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
9585 * accept other config options):
9587 Property Type Description
9588 ---------------- --------------- ----------------------------------------------------------------------------------
9589 url String The url for the action (defaults to the form's url)
9590 method String The form method to use (defaults to the form's method, or POST if not defined)
9591 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
9592 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
9593 validate the form on the client (defaults to false)
9595 * @return {BasicForm} this
9597 doAction : function(action, options){
9598 if(typeof action == 'string'){
9599 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
9601 if(this.fireEvent('beforeaction', this, action) !== false){
9602 this.beforeAction(action);
9603 action.run.defer(100, action);
9609 beforeAction : function(action){
9610 var o = action.options;
9615 Roo.get(document.body).mask(o.waitMsg || "Sending", 'x-mask-loading')
9617 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
9620 // not really supported yet.. ??
9622 //if(this.waitMsgTarget === true){
9623 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
9624 //}else if(this.waitMsgTarget){
9625 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
9626 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
9628 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
9634 afterAction : function(action, success){
9635 this.activeAction = null;
9636 var o = action.options;
9641 Roo.get(document.body).unmask();
9647 //if(this.waitMsgTarget === true){
9648 // this.el.unmask();
9649 //}else if(this.waitMsgTarget){
9650 // this.waitMsgTarget.unmask();
9652 // Roo.MessageBox.updateProgress(1);
9653 // Roo.MessageBox.hide();
9660 Roo.callback(o.success, o.scope, [this, action]);
9661 this.fireEvent('actioncomplete', this, action);
9665 // failure condition..
9666 // we have a scenario where updates need confirming.
9667 // eg. if a locking scenario exists..
9668 // we look for { errors : { needs_confirm : true }} in the response.
9670 (typeof(action.result) != 'undefined') &&
9671 (typeof(action.result.errors) != 'undefined') &&
9672 (typeof(action.result.errors.needs_confirm) != 'undefined')
9675 Roo.log("not supported yet");
9678 Roo.MessageBox.confirm(
9679 "Change requires confirmation",
9680 action.result.errorMsg,
9685 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
9695 Roo.callback(o.failure, o.scope, [this, action]);
9696 // show an error message if no failed handler is set..
9697 if (!this.hasListener('actionfailed')) {
9698 Roo.log("need to add dialog support");
9700 Roo.MessageBox.alert("Error",
9701 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
9702 action.result.errorMsg :
9703 "Saving Failed, please check your entries or try again"
9708 this.fireEvent('actionfailed', this, action);
9713 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
9714 * @param {String} id The value to search for
9717 findField : function(id){
9718 var items = this.getItems();
9719 var field = items.get(id);
9721 items.each(function(f){
9722 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
9729 return field || null;
9732 * Mark fields in this form invalid in bulk.
9733 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
9734 * @return {BasicForm} this
9736 markInvalid : function(errors){
9737 if(errors instanceof Array){
9738 for(var i = 0, len = errors.length; i < len; i++){
9739 var fieldError = errors[i];
9740 var f = this.findField(fieldError.id);
9742 f.markInvalid(fieldError.msg);
9748 if(typeof errors[id] != 'function' && (field = this.findField(id))){
9749 field.markInvalid(errors[id]);
9753 //Roo.each(this.childForms || [], function (f) {
9754 // f.markInvalid(errors);
9761 * Set values for fields in this form in bulk.
9762 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
9763 * @return {BasicForm} this
9765 setValues : function(values){
9766 if(values instanceof Array){ // array of objects
9767 for(var i = 0, len = values.length; i < len; i++){
9769 var f = this.findField(v.id);
9771 f.setValue(v.value);
9772 if(this.trackResetOnLoad){
9773 f.originalValue = f.getValue();
9777 }else{ // object hash
9780 if(typeof values[id] != 'function' && (field = this.findField(id))){
9782 if (field.setFromData &&
9784 field.displayField &&
9785 // combos' with local stores can
9786 // be queried via setValue()
9787 // to set their value..
9788 (field.store && !field.store.isLocal)
9792 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
9793 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
9794 field.setFromData(sd);
9796 } else if(field.setFromData && (field.store && !field.store.isLocal)) {
9798 field.setFromData(values);
9801 field.setValue(values[id]);
9805 if(this.trackResetOnLoad){
9806 field.originalValue = field.getValue();
9812 //Roo.each(this.childForms || [], function (f) {
9813 // f.setValues(values);
9820 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
9821 * they are returned as an array.
9822 * @param {Boolean} asString
9825 getValues : function(asString){
9826 //if (this.childForms) {
9827 // copy values from the child forms
9828 // Roo.each(this.childForms, function (f) {
9829 // this.setValues(f.getValues());
9835 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
9836 if(asString === true){
9839 return Roo.urlDecode(fs);
9843 * Returns the fields in this form as an object with key/value pairs.
9844 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
9847 getFieldValues : function(with_hidden)
9849 var items = this.getItems();
9851 items.each(function(f){
9857 var v = f.getValue();
9859 if (f.inputType =='radio') {
9860 if (typeof(ret[f.getName()]) == 'undefined') {
9861 ret[f.getName()] = ''; // empty..
9864 if (!f.el.dom.checked) {
9872 if(f.xtype == 'MoneyField'){
9873 ret[f.currencyName] = f.getCurrency();
9876 // not sure if this supported any more..
9877 if ((typeof(v) == 'object') && f.getRawValue) {
9878 v = f.getRawValue() ; // dates..
9880 // combo boxes where name != hiddenName...
9881 if (f.name !== false && f.name != '' && f.name != f.getName()) {
9882 ret[f.name] = f.getRawValue();
9884 ret[f.getName()] = v;
9891 * Clears all invalid messages in this form.
9892 * @return {BasicForm} this
9894 clearInvalid : function(){
9895 var items = this.getItems();
9897 items.each(function(f){
9906 * @return {BasicForm} this
9909 var items = this.getItems();
9910 items.each(function(f){
9914 Roo.each(this.childForms || [], function (f) {
9922 getItems : function()
9924 var r=new Roo.util.MixedCollection(false, function(o){
9925 return o.id || (o.id = Roo.id());
9927 var iter = function(el) {
9934 Roo.each(el.items,function(e) {
9943 hideFields : function(items)
9945 Roo.each(items, function(i){
9947 var f = this.findField(i);
9958 showFields : function(items)
9960 Roo.each(items, function(i){
9962 var f = this.findField(i);
9975 Roo.apply(Roo.bootstrap.Form, {
10002 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
10003 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
10004 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
10005 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
10008 this.maskEl.top.enableDisplayMode("block");
10009 this.maskEl.left.enableDisplayMode("block");
10010 this.maskEl.bottom.enableDisplayMode("block");
10011 this.maskEl.right.enableDisplayMode("block");
10013 this.toolTip = new Roo.bootstrap.Tooltip({
10014 cls : 'roo-form-error-popover',
10016 'left' : ['r-l', [-2,0], 'right'],
10017 'right' : ['l-r', [2,0], 'left'],
10018 'bottom' : ['tl-bl', [0,2], 'top'],
10019 'top' : [ 'bl-tl', [0,-2], 'bottom']
10023 this.toolTip.render(Roo.get(document.body));
10025 this.toolTip.el.enableDisplayMode("block");
10027 Roo.get(document.body).on('click', function(){
10031 Roo.get(document.body).on('touchstart', function(){
10035 this.isApplied = true
10038 mask : function(form, target)
10042 this.target = target;
10044 if(!this.form.errorMask || !target.el){
10048 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.modal', 100, true) || Roo.get(document.body);
10050 Roo.log(scrollable);
10052 var ot = this.target.el.calcOffsetsTo(scrollable);
10054 var scrollTo = ot[1] - this.form.maskOffset;
10056 scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
10058 scrollable.scrollTo('top', scrollTo);
10060 var box = this.target.el.getBox();
10062 var zIndex = Roo.bootstrap.Modal.zIndex++;
10065 this.maskEl.top.setStyle('position', 'absolute');
10066 this.maskEl.top.setStyle('z-index', zIndex);
10067 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
10068 this.maskEl.top.setLeft(0);
10069 this.maskEl.top.setTop(0);
10070 this.maskEl.top.show();
10072 this.maskEl.left.setStyle('position', 'absolute');
10073 this.maskEl.left.setStyle('z-index', zIndex);
10074 this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
10075 this.maskEl.left.setLeft(0);
10076 this.maskEl.left.setTop(box.y - this.padding);
10077 this.maskEl.left.show();
10079 this.maskEl.bottom.setStyle('position', 'absolute');
10080 this.maskEl.bottom.setStyle('z-index', zIndex);
10081 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
10082 this.maskEl.bottom.setLeft(0);
10083 this.maskEl.bottom.setTop(box.bottom + this.padding);
10084 this.maskEl.bottom.show();
10086 this.maskEl.right.setStyle('position', 'absolute');
10087 this.maskEl.right.setStyle('z-index', zIndex);
10088 this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
10089 this.maskEl.right.setLeft(box.right + this.padding);
10090 this.maskEl.right.setTop(box.y - this.padding);
10091 this.maskEl.right.show();
10093 this.toolTip.bindEl = this.target.el;
10095 this.toolTip.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
10097 var tip = this.target.blankText;
10099 if(this.target.getValue() !== '' ) {
10101 if (this.target.invalidText.length) {
10102 tip = this.target.invalidText;
10103 } else if (this.target.regexText.length){
10104 tip = this.target.regexText;
10108 this.toolTip.show(tip);
10110 this.intervalID = window.setInterval(function() {
10111 Roo.bootstrap.Form.popover.unmask();
10114 window.onwheel = function(){ return false;};
10116 (function(){ this.isMasked = true; }).defer(500, this);
10120 unmask : function()
10122 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
10126 this.maskEl.top.setStyle('position', 'absolute');
10127 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
10128 this.maskEl.top.hide();
10130 this.maskEl.left.setStyle('position', 'absolute');
10131 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
10132 this.maskEl.left.hide();
10134 this.maskEl.bottom.setStyle('position', 'absolute');
10135 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
10136 this.maskEl.bottom.hide();
10138 this.maskEl.right.setStyle('position', 'absolute');
10139 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
10140 this.maskEl.right.hide();
10142 this.toolTip.hide();
10144 this.toolTip.el.hide();
10146 window.onwheel = function(){ return true;};
10148 if(this.intervalID){
10149 window.clearInterval(this.intervalID);
10150 this.intervalID = false;
10153 this.isMasked = false;
10163 * Ext JS Library 1.1.1
10164 * Copyright(c) 2006-2007, Ext JS, LLC.
10166 * Originally Released Under LGPL - original licence link has changed is not relivant.
10169 * <script type="text/javascript">
10172 * @class Roo.form.VTypes
10173 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
10176 Roo.form.VTypes = function(){
10177 // closure these in so they are only created once.
10178 var alpha = /^[a-zA-Z_]+$/;
10179 var alphanum = /^[a-zA-Z0-9_]+$/;
10180 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
10181 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
10183 // All these messages and functions are configurable
10186 * The function used to validate email addresses
10187 * @param {String} value The email address
10189 'email' : function(v){
10190 return email.test(v);
10193 * The error text to display when the email validation function returns false
10196 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
10198 * The keystroke filter mask to be applied on email input
10201 'emailMask' : /[a-z0-9_\.\-@]/i,
10204 * The function used to validate URLs
10205 * @param {String} value The URL
10207 'url' : function(v){
10208 return url.test(v);
10211 * The error text to display when the url validation function returns false
10214 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
10217 * The function used to validate alpha values
10218 * @param {String} value The value
10220 'alpha' : function(v){
10221 return alpha.test(v);
10224 * The error text to display when the alpha validation function returns false
10227 'alphaText' : 'This field should only contain letters and _',
10229 * The keystroke filter mask to be applied on alpha input
10232 'alphaMask' : /[a-z_]/i,
10235 * The function used to validate alphanumeric values
10236 * @param {String} value The value
10238 'alphanum' : function(v){
10239 return alphanum.test(v);
10242 * The error text to display when the alphanumeric validation function returns false
10245 'alphanumText' : 'This field should only contain letters, numbers and _',
10247 * The keystroke filter mask to be applied on alphanumeric input
10250 'alphanumMask' : /[a-z0-9_]/i
10260 * @class Roo.bootstrap.Input
10261 * @extends Roo.bootstrap.Component
10262 * Bootstrap Input class
10263 * @cfg {Boolean} disabled is it disabled
10264 * @cfg {String} (button|checkbox|email|file|hidden|image|number|password|radio|range|reset|search|submit|text) inputType
10265 * @cfg {String} name name of the input
10266 * @cfg {string} fieldLabel - the label associated
10267 * @cfg {string} placeholder - placeholder to put in text.
10268 * @cfg {string} before - input group add on before
10269 * @cfg {string} after - input group add on after
10270 * @cfg {string} size - (lg|sm) or leave empty..
10271 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
10272 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
10273 * @cfg {Number} md colspan out of 12 for computer-sized screens
10274 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
10275 * @cfg {string} value default value of the input
10276 * @cfg {Number} labelWidth set the width of label
10277 * @cfg {Number} labellg set the width of label (1-12)
10278 * @cfg {Number} labelmd set the width of label (1-12)
10279 * @cfg {Number} labelsm set the width of label (1-12)
10280 * @cfg {Number} labelxs set the width of label (1-12)
10281 * @cfg {String} labelAlign (top|left)
10282 * @cfg {Boolean} readOnly Specifies that the field should be read-only
10283 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
10284 * @cfg {String} indicatorpos (left|right) default left
10285 * @cfg {String} capture (user|camera) use for file input only. (default empty)
10286 * @cfg {String} accept (image|video|audio) use for file input only. (default empty)
10287 * @cfg {Boolean} preventMark Do not show tick or cross if error/success
10289 * @cfg {String} align (left|center|right) Default left
10290 * @cfg {Boolean} forceFeedback (true|false) Default false
10293 * Create a new Input
10294 * @param {Object} config The config object
10297 Roo.bootstrap.Input = function(config){
10299 Roo.bootstrap.Input.superclass.constructor.call(this, config);
10304 * Fires when this field receives input focus.
10305 * @param {Roo.form.Field} this
10310 * Fires when this field loses input focus.
10311 * @param {Roo.form.Field} this
10315 * @event specialkey
10316 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
10317 * {@link Roo.EventObject#getKey} to determine which key was pressed.
10318 * @param {Roo.form.Field} this
10319 * @param {Roo.EventObject} e The event object
10324 * Fires just before the field blurs if the field value has changed.
10325 * @param {Roo.form.Field} this
10326 * @param {Mixed} newValue The new value
10327 * @param {Mixed} oldValue The original value
10332 * Fires after the field has been marked as invalid.
10333 * @param {Roo.form.Field} this
10334 * @param {String} msg The validation message
10339 * Fires after the field has been validated with no errors.
10340 * @param {Roo.form.Field} this
10345 * Fires after the key up
10346 * @param {Roo.form.Field} this
10347 * @param {Roo.EventObject} e The event Object
10353 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
10355 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
10356 automatic validation (defaults to "keyup").
10358 validationEvent : "keyup",
10360 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
10362 validateOnBlur : true,
10364 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
10366 validationDelay : 250,
10368 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
10370 focusClass : "x-form-focus", // not needed???
10374 * @cfg {String} invalidClass DEPRICATED - code uses BS4 - is-valid / is-invalid
10376 invalidClass : "has-warning",
10379 * @cfg {String} validClass DEPRICATED - code uses BS4 - is-valid / is-invalid
10381 validClass : "has-success",
10384 * @cfg {Boolean} hasFeedback (true|false) default true
10386 hasFeedback : true,
10389 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
10391 invalidFeedbackClass : "glyphicon-warning-sign",
10394 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
10396 validFeedbackClass : "glyphicon-ok",
10399 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
10401 selectOnFocus : false,
10404 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
10408 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
10413 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
10415 disableKeyFilter : false,
10418 * @cfg {Boolean} disabled True to disable the field (defaults to false).
10422 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
10426 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
10428 blankText : "Please complete this mandatory field",
10431 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
10435 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
10437 maxLength : Number.MAX_VALUE,
10439 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
10441 minLengthText : "The minimum length for this field is {0}",
10443 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
10445 maxLengthText : "The maximum length for this field is {0}",
10449 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
10450 * If available, this function will be called only after the basic validators all return true, and will be passed the
10451 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
10455 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
10456 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
10457 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
10461 * @cfg {String} regexText -- Depricated - use Invalid Text
10466 * @cfg {String} invalidText The error text to display if {@link #validator} test fails during validation (defaults to "")
10472 autocomplete: false,
10476 inputType : 'text',
10479 placeholder: false,
10484 preventMark: false,
10485 isFormField : true,
10488 labelAlign : false,
10491 formatedValue : false,
10492 forceFeedback : false,
10494 indicatorpos : 'left',
10504 parentLabelAlign : function()
10507 while (parent.parent()) {
10508 parent = parent.parent();
10509 if (typeof(parent.labelAlign) !='undefined') {
10510 return parent.labelAlign;
10517 getAutoCreate : function()
10519 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
10525 if(this.inputType != 'hidden'){
10526 cfg.cls = 'form-group' //input-group
10532 type : this.inputType,
10533 value : this.value,
10534 cls : 'form-control',
10535 placeholder : this.placeholder || '',
10536 autocomplete : this.autocomplete || 'new-password'
10538 if (this.inputType == 'file') {
10539 input.style = 'overflow:hidden'; // why not in CSS?
10542 if(this.capture.length){
10543 input.capture = this.capture;
10546 if(this.accept.length){
10547 input.accept = this.accept + "/*";
10551 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
10554 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
10555 input.maxLength = this.maxLength;
10558 if (this.disabled) {
10559 input.disabled=true;
10562 if (this.readOnly) {
10563 input.readonly=true;
10567 input.name = this.name;
10571 input.cls += ' input-' + this.size;
10575 ['xs','sm','md','lg'].map(function(size){
10576 if (settings[size]) {
10577 cfg.cls += ' col-' + size + '-' + settings[size];
10581 var inputblock = input;
10585 cls: 'glyphicon form-control-feedback'
10588 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10591 cls : 'has-feedback',
10599 if (this.before || this.after) {
10602 cls : 'input-group',
10606 if (this.before && typeof(this.before) == 'string') {
10608 inputblock.cn.push({
10610 cls : 'roo-input-before input-group-addon input-group-prepend input-group-text',
10614 if (this.before && typeof(this.before) == 'object') {
10615 this.before = Roo.factory(this.before);
10617 inputblock.cn.push({
10619 cls : 'roo-input-before input-group-prepend input-group-' +
10620 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
10624 inputblock.cn.push(input);
10626 if (this.after && typeof(this.after) == 'string') {
10627 inputblock.cn.push({
10629 cls : 'roo-input-after input-group-append input-group-text input-group-addon',
10633 if (this.after && typeof(this.after) == 'object') {
10634 this.after = Roo.factory(this.after);
10636 inputblock.cn.push({
10638 cls : 'roo-input-after input-group-append input-group-' +
10639 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
10643 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10644 inputblock.cls += ' has-feedback';
10645 inputblock.cn.push(feedback);
10650 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
10651 tooltip : 'This field is required'
10653 if (this.allowBlank ) {
10654 indicator.style = this.allowBlank ? ' display:none' : '';
10656 if (align ==='left' && this.fieldLabel.length) {
10658 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
10665 cls : 'control-label col-form-label',
10666 html : this.fieldLabel
10677 var labelCfg = cfg.cn[1];
10678 var contentCfg = cfg.cn[2];
10680 if(this.indicatorpos == 'right'){
10685 cls : 'control-label col-form-label',
10689 html : this.fieldLabel
10703 labelCfg = cfg.cn[0];
10704 contentCfg = cfg.cn[1];
10708 if(this.labelWidth > 12){
10709 labelCfg.style = "width: " + this.labelWidth + 'px';
10712 if(this.labelWidth < 13 && this.labelmd == 0){
10713 this.labelmd = this.labelWidth;
10716 if(this.labellg > 0){
10717 labelCfg.cls += ' col-lg-' + this.labellg;
10718 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
10721 if(this.labelmd > 0){
10722 labelCfg.cls += ' col-md-' + this.labelmd;
10723 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
10726 if(this.labelsm > 0){
10727 labelCfg.cls += ' col-sm-' + this.labelsm;
10728 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
10731 if(this.labelxs > 0){
10732 labelCfg.cls += ' col-xs-' + this.labelxs;
10733 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
10737 } else if ( this.fieldLabel.length) {
10744 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10745 tooltip : 'This field is required',
10746 style : this.allowBlank ? ' display:none' : ''
10750 //cls : 'input-group-addon',
10751 html : this.fieldLabel
10759 if(this.indicatorpos == 'right'){
10764 //cls : 'input-group-addon',
10765 html : this.fieldLabel
10770 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10771 tooltip : 'This field is required',
10772 style : this.allowBlank ? ' display:none' : ''
10792 if (this.parentType === 'Navbar' && this.parent().bar) {
10793 cfg.cls += ' navbar-form';
10796 if (this.parentType === 'NavGroup' && !(Roo.bootstrap.version == 4 && this.parent().form)) {
10797 // on BS4 we do this only if not form
10798 cfg.cls += ' navbar-form';
10806 * return the real input element.
10808 inputEl: function ()
10810 return this.el.select('input.form-control',true).first();
10813 tooltipEl : function()
10815 return this.inputEl();
10818 indicatorEl : function()
10820 if (Roo.bootstrap.version == 4) {
10821 return false; // not enabled in v4 yet.
10824 var indicator = this.el.select('i.roo-required-indicator',true).first();
10834 setDisabled : function(v)
10836 var i = this.inputEl().dom;
10838 i.removeAttribute('disabled');
10842 i.setAttribute('disabled','true');
10844 initEvents : function()
10847 this.inputEl().on("keydown" , this.fireKey, this);
10848 this.inputEl().on("focus", this.onFocus, this);
10849 this.inputEl().on("blur", this.onBlur, this);
10851 this.inputEl().relayEvent('keyup', this);
10853 this.indicator = this.indicatorEl();
10855 if(this.indicator){
10856 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible'); // changed from invisible??? -
10859 // reference to original value for reset
10860 this.originalValue = this.getValue();
10861 //Roo.form.TextField.superclass.initEvents.call(this);
10862 if(this.validationEvent == 'keyup'){
10863 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
10864 this.inputEl().on('keyup', this.filterValidation, this);
10866 else if(this.validationEvent !== false){
10867 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
10870 if(this.selectOnFocus){
10871 this.on("focus", this.preFocus, this);
10874 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
10875 this.inputEl().on("keypress", this.filterKeys, this);
10877 this.inputEl().relayEvent('keypress', this);
10880 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
10881 this.el.on("click", this.autoSize, this);
10884 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
10885 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
10888 if (typeof(this.before) == 'object') {
10889 this.before.render(this.el.select('.roo-input-before',true).first());
10891 if (typeof(this.after) == 'object') {
10892 this.after.render(this.el.select('.roo-input-after',true).first());
10895 this.inputEl().on('change', this.onChange, this);
10898 filterValidation : function(e){
10899 if(!e.isNavKeyPress()){
10900 this.validationTask.delay(this.validationDelay);
10904 * Validates the field value
10905 * @return {Boolean} True if the value is valid, else false
10907 validate : function(){
10908 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
10909 if(this.disabled || this.validateValue(this.getRawValue())){
10914 this.markInvalid();
10920 * Validates a value according to the field's validation rules and marks the field as invalid
10921 * if the validation fails
10922 * @param {Mixed} value The value to validate
10923 * @return {Boolean} True if the value is valid, else false
10925 validateValue : function(value)
10927 if(this.getVisibilityEl().hasClass('hidden')){
10931 if(value.length < 1) { // if it's blank
10932 if(this.allowBlank){
10938 if(value.length < this.minLength){
10941 if(value.length > this.maxLength){
10945 var vt = Roo.form.VTypes;
10946 if(!vt[this.vtype](value, this)){
10950 if(typeof this.validator == "function"){
10951 var msg = this.validator(value);
10955 if (typeof(msg) == 'string') {
10956 this.invalidText = msg;
10960 if(this.regex && !this.regex.test(value)){
10968 fireKey : function(e){
10969 //Roo.log('field ' + e.getKey());
10970 if(e.isNavKeyPress()){
10971 this.fireEvent("specialkey", this, e);
10974 focus : function (selectText){
10976 this.inputEl().focus();
10977 if(selectText === true){
10978 this.inputEl().dom.select();
10984 onFocus : function(){
10985 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
10986 // this.el.addClass(this.focusClass);
10988 if(!this.hasFocus){
10989 this.hasFocus = true;
10990 this.startValue = this.getValue();
10991 this.fireEvent("focus", this);
10995 beforeBlur : Roo.emptyFn,
10999 onBlur : function(){
11001 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
11002 //this.el.removeClass(this.focusClass);
11004 this.hasFocus = false;
11005 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
11008 var v = this.getValue();
11009 if(String(v) !== String(this.startValue)){
11010 this.fireEvent('change', this, v, this.startValue);
11012 this.fireEvent("blur", this);
11015 onChange : function(e)
11017 var v = this.getValue();
11018 if(String(v) !== String(this.startValue)){
11019 this.fireEvent('change', this, v, this.startValue);
11025 * Resets the current field value to the originally loaded value and clears any validation messages
11027 reset : function(){
11028 this.setValue(this.originalValue);
11032 * Returns the name of the field
11033 * @return {Mixed} name The name field
11035 getName: function(){
11039 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
11040 * @return {Mixed} value The field value
11042 getValue : function(){
11044 var v = this.inputEl().getValue();
11049 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
11050 * @return {Mixed} value The field value
11052 getRawValue : function(){
11053 var v = this.inputEl().getValue();
11059 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
11060 * @param {Mixed} value The value to set
11062 setRawValue : function(v){
11063 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
11066 selectText : function(start, end){
11067 var v = this.getRawValue();
11069 start = start === undefined ? 0 : start;
11070 end = end === undefined ? v.length : end;
11071 var d = this.inputEl().dom;
11072 if(d.setSelectionRange){
11073 d.setSelectionRange(start, end);
11074 }else if(d.createTextRange){
11075 var range = d.createTextRange();
11076 range.moveStart("character", start);
11077 range.moveEnd("character", v.length-end);
11084 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
11085 * @param {Mixed} value The value to set
11087 setValue : function(v){
11090 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
11096 processValue : function(value){
11097 if(this.stripCharsRe){
11098 var newValue = value.replace(this.stripCharsRe, '');
11099 if(newValue !== value){
11100 this.setRawValue(newValue);
11107 preFocus : function(){
11109 if(this.selectOnFocus){
11110 this.inputEl().dom.select();
11113 filterKeys : function(e){
11114 var k = e.getKey();
11115 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
11118 var c = e.getCharCode(), cc = String.fromCharCode(c);
11119 if(Roo.isIE && (e.isSpecialKey() || !cc)){
11122 if(!this.maskRe.test(cc)){
11127 * Clear any invalid styles/messages for this field
11129 clearInvalid : function(){
11131 if(!this.el || this.preventMark){ // not rendered
11136 this.el.removeClass([this.invalidClass, 'is-invalid']);
11138 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
11140 var feedback = this.el.select('.form-control-feedback', true).first();
11143 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
11148 if(this.indicator){
11149 this.indicator.removeClass('visible');
11150 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
11153 this.fireEvent('valid', this);
11157 * Mark this field as valid
11159 markValid : function()
11161 if(!this.el || this.preventMark){ // not rendered...
11165 this.el.removeClass([this.invalidClass, this.validClass]);
11166 this.inputEl().removeClass(['is-valid', 'is-invalid']);
11168 var feedback = this.el.select('.form-control-feedback', true).first();
11171 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
11174 if(this.indicator){
11175 this.indicator.removeClass('visible');
11176 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
11184 if(this.allowBlank && !this.getRawValue().length){
11187 if (Roo.bootstrap.version == 3) {
11188 this.el.addClass(this.validClass);
11190 this.inputEl().addClass('is-valid');
11193 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
11195 var feedback = this.el.select('.form-control-feedback', true).first();
11198 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
11199 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
11204 this.fireEvent('valid', this);
11208 * Mark this field as invalid
11209 * @param {String} msg The validation message
11211 markInvalid : function(msg)
11213 if(!this.el || this.preventMark){ // not rendered
11217 this.el.removeClass([this.invalidClass, this.validClass]);
11218 this.inputEl().removeClass(['is-valid', 'is-invalid']);
11220 var feedback = this.el.select('.form-control-feedback', true).first();
11223 this.el.select('.form-control-feedback', true).first().removeClass(
11224 [this.invalidFeedbackClass, this.validFeedbackClass]);
11231 if(this.allowBlank && !this.getRawValue().length){
11235 if(this.indicator){
11236 this.indicator.removeClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
11237 this.indicator.addClass('visible');
11239 if (Roo.bootstrap.version == 3) {
11240 this.el.addClass(this.invalidClass);
11242 this.inputEl().addClass('is-invalid');
11247 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
11249 var feedback = this.el.select('.form-control-feedback', true).first();
11252 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
11254 if(this.getValue().length || this.forceFeedback){
11255 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
11262 this.fireEvent('invalid', this, msg);
11265 SafariOnKeyDown : function(event)
11267 // this is a workaround for a password hang bug on chrome/ webkit.
11268 if (this.inputEl().dom.type != 'password') {
11272 var isSelectAll = false;
11274 if(this.inputEl().dom.selectionEnd > 0){
11275 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
11277 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
11278 event.preventDefault();
11283 if(isSelectAll && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
11285 event.preventDefault();
11286 // this is very hacky as keydown always get's upper case.
11288 var cc = String.fromCharCode(event.getCharCode());
11289 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
11293 adjustWidth : function(tag, w){
11294 tag = tag.toLowerCase();
11295 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
11296 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
11297 if(tag == 'input'){
11300 if(tag == 'textarea'){
11303 }else if(Roo.isOpera){
11304 if(tag == 'input'){
11307 if(tag == 'textarea'){
11315 setFieldLabel : function(v)
11317 if(!this.rendered){
11321 if(this.indicatorEl()){
11322 var ar = this.el.select('label > span',true);
11324 if (ar.elements.length) {
11325 this.el.select('label > span',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
11326 this.fieldLabel = v;
11330 var br = this.el.select('label',true);
11332 if(br.elements.length) {
11333 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
11334 this.fieldLabel = v;
11338 Roo.log('Cannot Found any of label > span || label in input');
11342 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
11343 this.fieldLabel = v;
11358 * @class Roo.bootstrap.TextArea
11359 * @extends Roo.bootstrap.Input
11360 * Bootstrap TextArea class
11361 * @cfg {Number} cols Specifies the visible width of a text area
11362 * @cfg {Number} rows Specifies the visible number of lines in a text area
11363 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
11364 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
11365 * @cfg {string} html text
11368 * Create a new TextArea
11369 * @param {Object} config The config object
11372 Roo.bootstrap.TextArea = function(config){
11373 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
11377 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
11387 getAutoCreate : function(){
11389 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
11395 if(this.inputType != 'hidden'){
11396 cfg.cls = 'form-group' //input-group
11404 value : this.value || '',
11405 html: this.html || '',
11406 cls : 'form-control',
11407 placeholder : this.placeholder || ''
11411 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
11412 input.maxLength = this.maxLength;
11416 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
11420 input.cols = this.cols;
11423 if (this.readOnly) {
11424 input.readonly = true;
11428 input.name = this.name;
11432 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
11436 ['xs','sm','md','lg'].map(function(size){
11437 if (settings[size]) {
11438 cfg.cls += ' col-' + size + '-' + settings[size];
11442 var inputblock = input;
11444 if(this.hasFeedback && !this.allowBlank){
11448 cls: 'glyphicon form-control-feedback'
11452 cls : 'has-feedback',
11461 if (this.before || this.after) {
11464 cls : 'input-group',
11468 inputblock.cn.push({
11470 cls : 'input-group-addon',
11475 inputblock.cn.push(input);
11477 if(this.hasFeedback && !this.allowBlank){
11478 inputblock.cls += ' has-feedback';
11479 inputblock.cn.push(feedback);
11483 inputblock.cn.push({
11485 cls : 'input-group-addon',
11492 if (align ==='left' && this.fieldLabel.length) {
11497 cls : 'control-label',
11498 html : this.fieldLabel
11509 if(this.labelWidth > 12){
11510 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
11513 if(this.labelWidth < 13 && this.labelmd == 0){
11514 this.labelmd = this.labelWidth;
11517 if(this.labellg > 0){
11518 cfg.cn[0].cls += ' col-lg-' + this.labellg;
11519 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
11522 if(this.labelmd > 0){
11523 cfg.cn[0].cls += ' col-md-' + this.labelmd;
11524 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
11527 if(this.labelsm > 0){
11528 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
11529 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
11532 if(this.labelxs > 0){
11533 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
11534 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
11537 } else if ( this.fieldLabel.length) {
11542 //cls : 'input-group-addon',
11543 html : this.fieldLabel
11561 if (this.disabled) {
11562 input.disabled=true;
11569 * return the real textarea element.
11571 inputEl: function ()
11573 return this.el.select('textarea.form-control',true).first();
11577 * Clear any invalid styles/messages for this field
11579 clearInvalid : function()
11582 if(!this.el || this.preventMark){ // not rendered
11586 var label = this.el.select('label', true).first();
11587 var icon = this.el.select('i.fa-star', true).first();
11592 this.el.removeClass( this.validClass);
11593 this.inputEl().removeClass('is-invalid');
11595 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
11597 var feedback = this.el.select('.form-control-feedback', true).first();
11600 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
11605 this.fireEvent('valid', this);
11609 * Mark this field as valid
11611 markValid : function()
11613 if(!this.el || this.preventMark){ // not rendered
11617 this.el.removeClass([this.invalidClass, this.validClass]);
11618 this.inputEl().removeClass(['is-valid', 'is-invalid']);
11620 var feedback = this.el.select('.form-control-feedback', true).first();
11623 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
11626 if(this.disabled || this.allowBlank){
11630 var label = this.el.select('label', true).first();
11631 var icon = this.el.select('i.fa-star', true).first();
11636 if (Roo.bootstrap.version == 3) {
11637 this.el.addClass(this.validClass);
11639 this.inputEl().addClass('is-valid');
11643 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
11645 var feedback = this.el.select('.form-control-feedback', true).first();
11648 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
11649 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
11654 this.fireEvent('valid', this);
11658 * Mark this field as invalid
11659 * @param {String} msg The validation message
11661 markInvalid : function(msg)
11663 if(!this.el || this.preventMark){ // not rendered
11667 this.el.removeClass([this.invalidClass, this.validClass]);
11668 this.inputEl().removeClass(['is-valid', 'is-invalid']);
11670 var feedback = this.el.select('.form-control-feedback', true).first();
11673 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
11676 if(this.disabled || this.allowBlank){
11680 var label = this.el.select('label', true).first();
11681 var icon = this.el.select('i.fa-star', true).first();
11683 if(!this.getValue().length && label && !icon){
11684 this.el.createChild({
11686 cls : 'text-danger fa fa-lg fa-star',
11687 tooltip : 'This field is required',
11688 style : 'margin-right:5px;'
11692 if (Roo.bootstrap.version == 3) {
11693 this.el.addClass(this.invalidClass);
11695 this.inputEl().addClass('is-invalid');
11698 // fixme ... this may be depricated need to test..
11699 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
11701 var feedback = this.el.select('.form-control-feedback', true).first();
11704 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
11706 if(this.getValue().length || this.forceFeedback){
11707 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
11714 this.fireEvent('invalid', this, msg);
11722 * trigger field - base class for combo..
11727 * @class Roo.bootstrap.TriggerField
11728 * @extends Roo.bootstrap.Input
11729 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
11730 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
11731 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
11732 * for which you can provide a custom implementation. For example:
11734 var trigger = new Roo.bootstrap.TriggerField();
11735 trigger.onTriggerClick = myTriggerFn;
11736 trigger.applyTo('my-field');
11739 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
11740 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
11741 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
11742 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
11743 * @cfg {String} caret (search|calendar) BS3 only - carat fa name
11746 * Create a new TriggerField.
11747 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
11748 * to the base TextField)
11750 Roo.bootstrap.TriggerField = function(config){
11751 this.mimicing = false;
11752 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
11755 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
11757 * @cfg {String} triggerClass A CSS class to apply to the trigger
11760 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
11765 * @cfg {Boolean} removable (true|false) special filter default false
11769 /** @cfg {Boolean} grow @hide */
11770 /** @cfg {Number} growMin @hide */
11771 /** @cfg {Number} growMax @hide */
11777 autoSize: Roo.emptyFn,
11781 deferHeight : true,
11784 actionMode : 'wrap',
11789 getAutoCreate : function(){
11791 var align = this.labelAlign || this.parentLabelAlign();
11796 cls: 'form-group' //input-group
11803 type : this.inputType,
11804 cls : 'form-control',
11805 autocomplete: 'new-password',
11806 placeholder : this.placeholder || ''
11810 input.name = this.name;
11813 input.cls += ' input-' + this.size;
11816 if (this.disabled) {
11817 input.disabled=true;
11820 var inputblock = input;
11822 if(this.hasFeedback && !this.allowBlank){
11826 cls: 'glyphicon form-control-feedback'
11829 if(this.removable && !this.editable ){
11831 cls : 'has-feedback',
11837 cls : 'roo-combo-removable-btn close'
11844 cls : 'has-feedback',
11853 if(this.removable && !this.editable ){
11855 cls : 'roo-removable',
11861 cls : 'roo-combo-removable-btn close'
11868 if (this.before || this.after) {
11871 cls : 'input-group',
11875 inputblock.cn.push({
11877 cls : 'input-group-addon input-group-prepend input-group-text',
11882 inputblock.cn.push(input);
11884 if(this.hasFeedback && !this.allowBlank){
11885 inputblock.cls += ' has-feedback';
11886 inputblock.cn.push(feedback);
11890 inputblock.cn.push({
11892 cls : 'input-group-addon input-group-append input-group-text',
11901 var ibwrap = inputblock;
11906 cls: 'roo-select2-choices',
11910 cls: 'roo-select2-search-field',
11922 cls: 'roo-select2-container input-group',
11927 cls: 'form-hidden-field'
11933 if(!this.multiple && this.showToggleBtn){
11939 if (this.caret != false) {
11942 cls: 'fa fa-' + this.caret
11949 cls : 'input-group-addon input-group-append input-group-text btn dropdown-toggle',
11951 Roo.bootstrap.version == 3 ? caret : '',
11954 cls: 'combobox-clear',
11968 combobox.cls += ' roo-select2-container-multi';
11972 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
11973 tooltip : 'This field is required'
11975 if (Roo.bootstrap.version == 4) {
11978 style : 'display:none'
11983 if (align ==='left' && this.fieldLabel.length) {
11985 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
11992 cls : 'control-label',
11993 html : this.fieldLabel
12005 var labelCfg = cfg.cn[1];
12006 var contentCfg = cfg.cn[2];
12008 if(this.indicatorpos == 'right'){
12013 cls : 'control-label',
12017 html : this.fieldLabel
12031 labelCfg = cfg.cn[0];
12032 contentCfg = cfg.cn[1];
12035 if(this.labelWidth > 12){
12036 labelCfg.style = "width: " + this.labelWidth + 'px';
12039 if(this.labelWidth < 13 && this.labelmd == 0){
12040 this.labelmd = this.labelWidth;
12043 if(this.labellg > 0){
12044 labelCfg.cls += ' col-lg-' + this.labellg;
12045 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
12048 if(this.labelmd > 0){
12049 labelCfg.cls += ' col-md-' + this.labelmd;
12050 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
12053 if(this.labelsm > 0){
12054 labelCfg.cls += ' col-sm-' + this.labelsm;
12055 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
12058 if(this.labelxs > 0){
12059 labelCfg.cls += ' col-xs-' + this.labelxs;
12060 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
12063 } else if ( this.fieldLabel.length) {
12064 // Roo.log(" label");
12069 //cls : 'input-group-addon',
12070 html : this.fieldLabel
12078 if(this.indicatorpos == 'right'){
12086 html : this.fieldLabel
12100 // Roo.log(" no label && no align");
12107 ['xs','sm','md','lg'].map(function(size){
12108 if (settings[size]) {
12109 cfg.cls += ' col-' + size + '-' + settings[size];
12120 onResize : function(w, h){
12121 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
12122 // if(typeof w == 'number'){
12123 // var x = w - this.trigger.getWidth();
12124 // this.inputEl().setWidth(this.adjustWidth('input', x));
12125 // this.trigger.setStyle('left', x+'px');
12130 adjustSize : Roo.BoxComponent.prototype.adjustSize,
12133 getResizeEl : function(){
12134 return this.inputEl();
12138 getPositionEl : function(){
12139 return this.inputEl();
12143 alignErrorIcon : function(){
12144 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
12148 initEvents : function(){
12152 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
12153 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
12154 if(!this.multiple && this.showToggleBtn){
12155 this.trigger = this.el.select('span.dropdown-toggle',true).first();
12156 if(this.hideTrigger){
12157 this.trigger.setDisplayed(false);
12159 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
12163 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
12166 if(this.removable && !this.editable && !this.tickable){
12167 var close = this.closeTriggerEl();
12170 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
12171 close.on('click', this.removeBtnClick, this, close);
12175 //this.trigger.addClassOnOver('x-form-trigger-over');
12176 //this.trigger.addClassOnClick('x-form-trigger-click');
12179 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
12183 closeTriggerEl : function()
12185 var close = this.el.select('.roo-combo-removable-btn', true).first();
12186 return close ? close : false;
12189 removeBtnClick : function(e, h, el)
12191 e.preventDefault();
12193 if(this.fireEvent("remove", this) !== false){
12195 this.fireEvent("afterremove", this)
12199 createList : function()
12201 this.list = Roo.get(document.body).createChild({
12202 tag: Roo.bootstrap.version == 4 ? 'div' : 'ul',
12203 cls: 'typeahead typeahead-long dropdown-menu',
12204 style: 'display:none'
12207 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
12212 initTrigger : function(){
12217 onDestroy : function(){
12219 this.trigger.removeAllListeners();
12220 // this.trigger.remove();
12223 // this.wrap.remove();
12225 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
12229 onFocus : function(){
12230 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
12232 if(!this.mimicing){
12233 this.wrap.addClass('x-trigger-wrap-focus');
12234 this.mimicing = true;
12235 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
12236 if(this.monitorTab){
12237 this.el.on("keydown", this.checkTab, this);
12244 checkTab : function(e){
12245 if(e.getKey() == e.TAB){
12246 this.triggerBlur();
12251 onBlur : function(){
12256 mimicBlur : function(e, t){
12258 if(!this.wrap.contains(t) && this.validateBlur()){
12259 this.triggerBlur();
12265 triggerBlur : function(){
12266 this.mimicing = false;
12267 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
12268 if(this.monitorTab){
12269 this.el.un("keydown", this.checkTab, this);
12271 //this.wrap.removeClass('x-trigger-wrap-focus');
12272 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
12276 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
12277 validateBlur : function(e, t){
12282 onDisable : function(){
12283 this.inputEl().dom.disabled = true;
12284 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
12286 // this.wrap.addClass('x-item-disabled');
12291 onEnable : function(){
12292 this.inputEl().dom.disabled = false;
12293 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
12295 // this.el.removeClass('x-item-disabled');
12300 onShow : function(){
12301 var ae = this.getActionEl();
12304 ae.dom.style.display = '';
12305 ae.dom.style.visibility = 'visible';
12311 onHide : function(){
12312 var ae = this.getActionEl();
12313 ae.dom.style.display = 'none';
12317 * The function that should handle the trigger's click event. This method does nothing by default until overridden
12318 * by an implementing function.
12320 * @param {EventObject} e
12322 onTriggerClick : Roo.emptyFn
12330 * @class Roo.bootstrap.CardUploader
12331 * @extends Roo.bootstrap.Button
12332 * Bootstrap Card Uploader class - it's a button which when you add files to it, adds cards below with preview and the name...
12333 * @cfg {Number} errorTimeout default 3000
12334 * @cfg {Array} images an array of ?? Img objects ??? when loading existing files..
12335 * @cfg {Array} html The button text.
12339 * Create a new CardUploader
12340 * @param {Object} config The config object
12343 Roo.bootstrap.CardUploader = function(config){
12347 Roo.bootstrap.CardUploader.superclass.constructor.call(this, config);
12350 this.fileCollection = new Roo.util.MixedCollection(false,function(r) {
12357 Roo.extend(Roo.bootstrap.CardUploader, Roo.bootstrap.Input, {
12360 errorTimeout : 3000,
12364 fileCollection : false,
12367 getAutoCreate : function()
12371 cls :'form-group' ,
12376 //cls : 'input-group-addon',
12377 html : this.fieldLabel
12384 value : this.value,
12385 cls : 'd-none form-control'
12390 multiple : 'multiple',
12392 cls : 'd-none roo-card-upload-selector'
12396 cls : 'roo-card-uploader-button-container w-100 mb-2'
12399 cls : 'card-columns roo-card-uploader-container'
12409 getChildContainer : function() /// what children are added to.
12411 return this.containerEl;
12414 getButtonContainer : function() /// what children are added to.
12416 return this.el.select(".roo-card-uploader-button-container").first();
12419 initEvents : function()
12422 Roo.bootstrap.Input.prototype.initEvents.call(this);
12426 xns: Roo.bootstrap,
12429 container_method : 'getButtonContainer' ,
12430 html : this.html, // fix changable?
12433 'click' : function(btn, e) {
12442 this.urlAPI = (window.createObjectURL && window) ||
12443 (window.URL && URL.revokeObjectURL && URL) ||
12444 (window.webkitURL && webkitURL);
12449 this.selectorEl = this.el.select('.roo-card-upload-selector', true).first();
12451 this.selectorEl.on('change', this.onFileSelected, this);
12454 this.images.forEach(function(img) {
12457 this.images = false;
12459 this.containerEl = this.el.select('.roo-card-uploader-container', true).first();
12465 onClick : function(e)
12467 e.preventDefault();
12469 this.selectorEl.dom.click();
12473 onFileSelected : function(e)
12475 e.preventDefault();
12477 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
12481 Roo.each(this.selectorEl.dom.files, function(file){
12482 this.addFile(file);
12491 addFile : function(file)
12494 if(typeof(file) === 'string'){
12495 throw "Add file by name?"; // should not happen
12499 if(!file || !this.urlAPI){
12509 var url = _this.urlAPI.createObjectURL( file);
12512 id : Roo.bootstrap.CardUploader.ID--,
12513 is_uploaded : false,
12516 mimetype : file.type,
12523 addCard : function (data)
12525 // hidden input element?
12526 // if the file is not an image...
12527 //then we need to use something other that and header_image
12532 xns : Roo.bootstrap,
12533 xtype : 'CardFooter',
12536 xns : Roo.bootstrap,
12542 xns : Roo.bootstrap,
12544 html : String.format("<small>{0}</small>", data.title),
12545 cls : 'col-11 text-left',
12550 click : function() {
12551 this.downloadCard(data.id)
12557 xns : Roo.bootstrap,
12565 click : function() {
12566 t.removeCard(data.id)
12578 var cn = this.addxtype(
12581 xns : Roo.bootstrap,
12584 header : !data.mimetype.match(/image/) && !data.preview ? "Document": false,
12585 header_image : data.mimetype.match(/image/) ? data.src : data.preview,
12586 header_image_fit_square: true, // fixme - we probably need to use the 'Img' element to do stuff like this.
12591 initEvents : function() {
12592 Roo.bootstrap.Card.prototype.initEvents.call(this);
12593 this.imgEl = this.el.select('.card-img-top').first();
12595 this.imgEl.on('click', function() { t.previewCard( data.id); }, this);
12596 this.imgEl.set({ 'pointer' : 'cursor' });
12605 // dont' really need ot update items.
12606 // this.items.push(cn);
12607 this.fileCollection.add(cn);
12608 this.updateInput();
12611 removeCard : function(id)
12614 var card = this.fileCollection.get(id);
12615 card.data.is_deleted = 1;
12616 card.data.src = ''; /// delete the source - so it reduces size of not uploaded images etc.
12617 this.fileCollection.remove(card);
12618 //this.items = this.items.filter(function(e) { return e != card });
12619 // dont' really need ot update items.
12620 card.el.dom.parentNode.removeChild(card.el.dom);
12625 this.fileCollection.each(function(card) {
12626 card.el.dom.parentNode.removeChild(card.el.dom);
12628 this.fileCollection.clear();
12629 this.updateInput();
12632 updateInput : function()
12635 this.fileCollection.each(function(e) {
12639 this.inputEl().dom.value = JSON.stringify(data);
12646 Roo.bootstrap.CardUploader.ID = -1;/*
12648 * Ext JS Library 1.1.1
12649 * Copyright(c) 2006-2007, Ext JS, LLC.
12651 * Originally Released Under LGPL - original licence link has changed is not relivant.
12654 * <script type="text/javascript">
12659 * @class Roo.data.SortTypes
12661 * Defines the default sorting (casting?) comparison functions used when sorting data.
12663 Roo.data.SortTypes = {
12665 * Default sort that does nothing
12666 * @param {Mixed} s The value being converted
12667 * @return {Mixed} The comparison value
12669 none : function(s){
12674 * The regular expression used to strip tags
12678 stripTagsRE : /<\/?[^>]+>/gi,
12681 * Strips all HTML tags to sort on text only
12682 * @param {Mixed} s The value being converted
12683 * @return {String} The comparison value
12685 asText : function(s){
12686 return String(s).replace(this.stripTagsRE, "");
12690 * Strips all HTML tags to sort on text only - Case insensitive
12691 * @param {Mixed} s The value being converted
12692 * @return {String} The comparison value
12694 asUCText : function(s){
12695 return String(s).toUpperCase().replace(this.stripTagsRE, "");
12699 * Case insensitive string
12700 * @param {Mixed} s The value being converted
12701 * @return {String} The comparison value
12703 asUCString : function(s) {
12704 return String(s).toUpperCase();
12709 * @param {Mixed} s The value being converted
12710 * @return {Number} The comparison value
12712 asDate : function(s) {
12716 if(s instanceof Date){
12717 return s.getTime();
12719 return Date.parse(String(s));
12724 * @param {Mixed} s The value being converted
12725 * @return {Float} The comparison value
12727 asFloat : function(s) {
12728 var val = parseFloat(String(s).replace(/,/g, ""));
12737 * @param {Mixed} s The value being converted
12738 * @return {Number} The comparison value
12740 asInt : function(s) {
12741 var val = parseInt(String(s).replace(/,/g, ""));
12749 * Ext JS Library 1.1.1
12750 * Copyright(c) 2006-2007, Ext JS, LLC.
12752 * Originally Released Under LGPL - original licence link has changed is not relivant.
12755 * <script type="text/javascript">
12759 * @class Roo.data.Record
12760 * Instances of this class encapsulate both record <em>definition</em> information, and record
12761 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
12762 * to access Records cached in an {@link Roo.data.Store} object.<br>
12764 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
12765 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
12768 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
12770 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
12771 * {@link #create}. The parameters are the same.
12772 * @param {Array} data An associative Array of data values keyed by the field name.
12773 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
12774 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
12775 * not specified an integer id is generated.
12777 Roo.data.Record = function(data, id){
12778 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
12783 * Generate a constructor for a specific record layout.
12784 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
12785 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
12786 * Each field definition object may contain the following properties: <ul>
12787 * <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,
12788 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
12789 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
12790 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
12791 * is being used, then this is a string containing the javascript expression to reference the data relative to
12792 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
12793 * to the data item relative to the record element. If the mapping expression is the same as the field name,
12794 * this may be omitted.</p></li>
12795 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
12796 * <ul><li>auto (Default, implies no conversion)</li>
12801 * <li>date</li></ul></p></li>
12802 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
12803 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
12804 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
12805 * by the Reader into an object that will be stored in the Record. It is passed the
12806 * following parameters:<ul>
12807 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
12809 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
12811 * <br>usage:<br><pre><code>
12812 var TopicRecord = Roo.data.Record.create(
12813 {name: 'title', mapping: 'topic_title'},
12814 {name: 'author', mapping: 'username'},
12815 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
12816 {name: 'lastPost', mapping: 'post_time', type: 'date'},
12817 {name: 'lastPoster', mapping: 'user2'},
12818 {name: 'excerpt', mapping: 'post_text'}
12821 var myNewRecord = new TopicRecord({
12822 title: 'Do my job please',
12825 lastPost: new Date(),
12826 lastPoster: 'Animal',
12827 excerpt: 'No way dude!'
12829 myStore.add(myNewRecord);
12834 Roo.data.Record.create = function(o){
12835 var f = function(){
12836 f.superclass.constructor.apply(this, arguments);
12838 Roo.extend(f, Roo.data.Record);
12839 var p = f.prototype;
12840 p.fields = new Roo.util.MixedCollection(false, function(field){
12843 for(var i = 0, len = o.length; i < len; i++){
12844 p.fields.add(new Roo.data.Field(o[i]));
12846 f.getField = function(name){
12847 return p.fields.get(name);
12852 Roo.data.Record.AUTO_ID = 1000;
12853 Roo.data.Record.EDIT = 'edit';
12854 Roo.data.Record.REJECT = 'reject';
12855 Roo.data.Record.COMMIT = 'commit';
12857 Roo.data.Record.prototype = {
12859 * Readonly flag - true if this record has been modified.
12868 join : function(store){
12869 this.store = store;
12873 * Set the named field to the specified value.
12874 * @param {String} name The name of the field to set.
12875 * @param {Object} value The value to set the field to.
12877 set : function(name, value){
12878 if(this.data[name] == value){
12882 if(!this.modified){
12883 this.modified = {};
12885 if(typeof this.modified[name] == 'undefined'){
12886 this.modified[name] = this.data[name];
12888 this.data[name] = value;
12889 if(!this.editing && this.store){
12890 this.store.afterEdit(this);
12895 * Get the value of the named field.
12896 * @param {String} name The name of the field to get the value of.
12897 * @return {Object} The value of the field.
12899 get : function(name){
12900 return this.data[name];
12904 beginEdit : function(){
12905 this.editing = true;
12906 this.modified = {};
12910 cancelEdit : function(){
12911 this.editing = false;
12912 delete this.modified;
12916 endEdit : function(){
12917 this.editing = false;
12918 if(this.dirty && this.store){
12919 this.store.afterEdit(this);
12924 * Usually called by the {@link Roo.data.Store} which owns the Record.
12925 * Rejects all changes made to the Record since either creation, or the last commit operation.
12926 * Modified fields are reverted to their original values.
12928 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
12929 * of reject operations.
12931 reject : function(){
12932 var m = this.modified;
12934 if(typeof m[n] != "function"){
12935 this.data[n] = m[n];
12938 this.dirty = false;
12939 delete this.modified;
12940 this.editing = false;
12942 this.store.afterReject(this);
12947 * Usually called by the {@link Roo.data.Store} which owns the Record.
12948 * Commits all changes made to the Record since either creation, or the last commit operation.
12950 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
12951 * of commit operations.
12953 commit : function(){
12954 this.dirty = false;
12955 delete this.modified;
12956 this.editing = false;
12958 this.store.afterCommit(this);
12963 hasError : function(){
12964 return this.error != null;
12968 clearError : function(){
12973 * Creates a copy of this record.
12974 * @param {String} id (optional) A new record id if you don't want to use this record's id
12977 copy : function(newId) {
12978 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
12982 * Ext JS Library 1.1.1
12983 * Copyright(c) 2006-2007, Ext JS, LLC.
12985 * Originally Released Under LGPL - original licence link has changed is not relivant.
12988 * <script type="text/javascript">
12994 * @class Roo.data.Store
12995 * @extends Roo.util.Observable
12996 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
12997 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
12999 * 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
13000 * has no knowledge of the format of the data returned by the Proxy.<br>
13002 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
13003 * instances from the data object. These records are cached and made available through accessor functions.
13005 * Creates a new Store.
13006 * @param {Object} config A config object containing the objects needed for the Store to access data,
13007 * and read the data into Records.
13009 Roo.data.Store = function(config){
13010 this.data = new Roo.util.MixedCollection(false);
13011 this.data.getKey = function(o){
13014 this.baseParams = {};
13016 this.paramNames = {
13021 "multisort" : "_multisort"
13024 if(config && config.data){
13025 this.inlineData = config.data;
13026 delete config.data;
13029 Roo.apply(this, config);
13031 if(this.reader){ // reader passed
13032 this.reader = Roo.factory(this.reader, Roo.data);
13033 this.reader.xmodule = this.xmodule || false;
13034 if(!this.recordType){
13035 this.recordType = this.reader.recordType;
13037 if(this.reader.onMetaChange){
13038 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
13042 if(this.recordType){
13043 this.fields = this.recordType.prototype.fields;
13045 this.modified = [];
13049 * @event datachanged
13050 * Fires when the data cache has changed, and a widget which is using this Store
13051 * as a Record cache should refresh its view.
13052 * @param {Store} this
13054 datachanged : true,
13056 * @event metachange
13057 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
13058 * @param {Store} this
13059 * @param {Object} meta The JSON metadata
13064 * Fires when Records have been added to the Store
13065 * @param {Store} this
13066 * @param {Roo.data.Record[]} records The array of Records added
13067 * @param {Number} index The index at which the record(s) were added
13072 * Fires when a Record has been removed from the Store
13073 * @param {Store} this
13074 * @param {Roo.data.Record} record The Record that was removed
13075 * @param {Number} index The index at which the record was removed
13080 * Fires when a Record has been updated
13081 * @param {Store} this
13082 * @param {Roo.data.Record} record The Record that was updated
13083 * @param {String} operation The update operation being performed. Value may be one of:
13085 Roo.data.Record.EDIT
13086 Roo.data.Record.REJECT
13087 Roo.data.Record.COMMIT
13093 * Fires when the data cache has been cleared.
13094 * @param {Store} this
13098 * @event beforeload
13099 * Fires before a request is made for a new data object. If the beforeload handler returns false
13100 * the load action will be canceled.
13101 * @param {Store} this
13102 * @param {Object} options The loading options that were specified (see {@link #load} for details)
13106 * @event beforeloadadd
13107 * Fires after a new set of Records has been loaded.
13108 * @param {Store} this
13109 * @param {Roo.data.Record[]} records The Records that were loaded
13110 * @param {Object} options The loading options that were specified (see {@link #load} for details)
13112 beforeloadadd : true,
13115 * Fires after a new set of Records has been loaded, before they are added to the store.
13116 * @param {Store} this
13117 * @param {Roo.data.Record[]} records The Records that were loaded
13118 * @param {Object} options The loading options that were specified (see {@link #load} for details)
13119 * @params {Object} return from reader
13123 * @event loadexception
13124 * Fires if an exception occurs in the Proxy during loading.
13125 * Called with the signature of the Proxy's "loadexception" event.
13126 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
13129 * @param {Object} return from JsonData.reader() - success, totalRecords, records
13130 * @param {Object} load options
13131 * @param {Object} jsonData from your request (normally this contains the Exception)
13133 loadexception : true
13137 this.proxy = Roo.factory(this.proxy, Roo.data);
13138 this.proxy.xmodule = this.xmodule || false;
13139 this.relayEvents(this.proxy, ["loadexception"]);
13141 this.sortToggle = {};
13142 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
13144 Roo.data.Store.superclass.constructor.call(this);
13146 if(this.inlineData){
13147 this.loadData(this.inlineData);
13148 delete this.inlineData;
13152 Roo.extend(Roo.data.Store, Roo.util.Observable, {
13154 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
13155 * without a remote query - used by combo/forms at present.
13159 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
13162 * @cfg {Array} data Inline data to be loaded when the store is initialized.
13165 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
13166 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
13169 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
13170 * on any HTTP request
13173 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
13176 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
13180 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
13181 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
13183 remoteSort : false,
13186 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
13187 * loaded or when a record is removed. (defaults to false).
13189 pruneModifiedRecords : false,
13192 lastOptions : null,
13195 * Add Records to the Store and fires the add event.
13196 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
13198 add : function(records){
13199 records = [].concat(records);
13200 for(var i = 0, len = records.length; i < len; i++){
13201 records[i].join(this);
13203 var index = this.data.length;
13204 this.data.addAll(records);
13205 this.fireEvent("add", this, records, index);
13209 * Remove a Record from the Store and fires the remove event.
13210 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
13212 remove : function(record){
13213 var index = this.data.indexOf(record);
13214 this.data.removeAt(index);
13216 if(this.pruneModifiedRecords){
13217 this.modified.remove(record);
13219 this.fireEvent("remove", this, record, index);
13223 * Remove all Records from the Store and fires the clear event.
13225 removeAll : function(){
13227 if(this.pruneModifiedRecords){
13228 this.modified = [];
13230 this.fireEvent("clear", this);
13234 * Inserts Records to the Store at the given index and fires the add event.
13235 * @param {Number} index The start index at which to insert the passed Records.
13236 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
13238 insert : function(index, records){
13239 records = [].concat(records);
13240 for(var i = 0, len = records.length; i < len; i++){
13241 this.data.insert(index, records[i]);
13242 records[i].join(this);
13244 this.fireEvent("add", this, records, index);
13248 * Get the index within the cache of the passed Record.
13249 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
13250 * @return {Number} The index of the passed Record. Returns -1 if not found.
13252 indexOf : function(record){
13253 return this.data.indexOf(record);
13257 * Get the index within the cache of the Record with the passed id.
13258 * @param {String} id The id of the Record to find.
13259 * @return {Number} The index of the Record. Returns -1 if not found.
13261 indexOfId : function(id){
13262 return this.data.indexOfKey(id);
13266 * Get the Record with the specified id.
13267 * @param {String} id The id of the Record to find.
13268 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
13270 getById : function(id){
13271 return this.data.key(id);
13275 * Get the Record at the specified index.
13276 * @param {Number} index The index of the Record to find.
13277 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
13279 getAt : function(index){
13280 return this.data.itemAt(index);
13284 * Returns a range of Records between specified indices.
13285 * @param {Number} startIndex (optional) The starting index (defaults to 0)
13286 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
13287 * @return {Roo.data.Record[]} An array of Records
13289 getRange : function(start, end){
13290 return this.data.getRange(start, end);
13294 storeOptions : function(o){
13295 o = Roo.apply({}, o);
13298 this.lastOptions = o;
13302 * Loads the Record cache from the configured Proxy using the configured Reader.
13304 * If using remote paging, then the first load call must specify the <em>start</em>
13305 * and <em>limit</em> properties in the options.params property to establish the initial
13306 * position within the dataset, and the number of Records to cache on each read from the Proxy.
13308 * <strong>It is important to note that for remote data sources, loading is asynchronous,
13309 * and this call will return before the new data has been loaded. Perform any post-processing
13310 * in a callback function, or in a "load" event handler.</strong>
13312 * @param {Object} options An object containing properties which control loading options:<ul>
13313 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
13314 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
13315 * passed the following arguments:<ul>
13316 * <li>r : Roo.data.Record[]</li>
13317 * <li>options: Options object from the load call</li>
13318 * <li>success: Boolean success indicator</li></ul></li>
13319 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
13320 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
13323 load : function(options){
13324 options = options || {};
13325 if(this.fireEvent("beforeload", this, options) !== false){
13326 this.storeOptions(options);
13327 var p = Roo.apply(options.params || {}, this.baseParams);
13328 // if meta was not loaded from remote source.. try requesting it.
13329 if (!this.reader.metaFromRemote) {
13330 p._requestMeta = 1;
13332 if(this.sortInfo && this.remoteSort){
13333 var pn = this.paramNames;
13334 p[pn["sort"]] = this.sortInfo.field;
13335 p[pn["dir"]] = this.sortInfo.direction;
13337 if (this.multiSort) {
13338 var pn = this.paramNames;
13339 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
13342 this.proxy.load(p, this.reader, this.loadRecords, this, options);
13347 * Reloads the Record cache from the configured Proxy using the configured Reader and
13348 * the options from the last load operation performed.
13349 * @param {Object} options (optional) An object containing properties which may override the options
13350 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
13351 * the most recently used options are reused).
13353 reload : function(options){
13354 this.load(Roo.applyIf(options||{}, this.lastOptions));
13358 // Called as a callback by the Reader during a load operation.
13359 loadRecords : function(o, options, success){
13360 if(!o || success === false){
13361 if(success !== false){
13362 this.fireEvent("load", this, [], options, o);
13364 if(options.callback){
13365 options.callback.call(options.scope || this, [], options, false);
13369 // if data returned failure - throw an exception.
13370 if (o.success === false) {
13371 // show a message if no listener is registered.
13372 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
13373 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
13375 // loadmask wil be hooked into this..
13376 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
13379 var r = o.records, t = o.totalRecords || r.length;
13381 this.fireEvent("beforeloadadd", this, r, options, o);
13383 if(!options || options.add !== true){
13384 if(this.pruneModifiedRecords){
13385 this.modified = [];
13387 for(var i = 0, len = r.length; i < len; i++){
13391 this.data = this.snapshot;
13392 delete this.snapshot;
13395 this.data.addAll(r);
13396 this.totalLength = t;
13398 this.fireEvent("datachanged", this);
13400 this.totalLength = Math.max(t, this.data.length+r.length);
13404 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
13406 var e = new Roo.data.Record({});
13408 e.set(this.parent.displayField, this.parent.emptyTitle);
13409 e.set(this.parent.valueField, '');
13414 this.fireEvent("load", this, r, options, o);
13415 if(options.callback){
13416 options.callback.call(options.scope || this, r, options, true);
13422 * Loads data from a passed data block. A Reader which understands the format of the data
13423 * must have been configured in the constructor.
13424 * @param {Object} data The data block from which to read the Records. The format of the data expected
13425 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
13426 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
13428 loadData : function(o, append){
13429 var r = this.reader.readRecords(o);
13430 this.loadRecords(r, {add: append}, true);
13434 * using 'cn' the nested child reader read the child array into it's child stores.
13435 * @param {Object} rec The record with a 'children array
13437 loadDataFromChildren : function(rec)
13439 this.loadData(this.reader.toLoadData(rec));
13444 * Gets the number of cached records.
13446 * <em>If using paging, this may not be the total size of the dataset. If the data object
13447 * used by the Reader contains the dataset size, then the getTotalCount() function returns
13448 * the data set size</em>
13450 getCount : function(){
13451 return this.data.length || 0;
13455 * Gets the total number of records in the dataset as returned by the server.
13457 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
13458 * the dataset size</em>
13460 getTotalCount : function(){
13461 return this.totalLength || 0;
13465 * Returns the sort state of the Store as an object with two properties:
13467 field {String} The name of the field by which the Records are sorted
13468 direction {String} The sort order, "ASC" or "DESC"
13471 getSortState : function(){
13472 return this.sortInfo;
13476 applySort : function(){
13477 if(this.sortInfo && !this.remoteSort){
13478 var s = this.sortInfo, f = s.field;
13479 var st = this.fields.get(f).sortType;
13480 var fn = function(r1, r2){
13481 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
13482 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
13484 this.data.sort(s.direction, fn);
13485 if(this.snapshot && this.snapshot != this.data){
13486 this.snapshot.sort(s.direction, fn);
13492 * Sets the default sort column and order to be used by the next load operation.
13493 * @param {String} fieldName The name of the field to sort by.
13494 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
13496 setDefaultSort : function(field, dir){
13497 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
13501 * Sort the Records.
13502 * If remote sorting is used, the sort is performed on the server, and the cache is
13503 * reloaded. If local sorting is used, the cache is sorted internally.
13504 * @param {String} fieldName The name of the field to sort by.
13505 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
13507 sort : function(fieldName, dir){
13508 var f = this.fields.get(fieldName);
13510 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
13512 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
13513 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
13518 this.sortToggle[f.name] = dir;
13519 this.sortInfo = {field: f.name, direction: dir};
13520 if(!this.remoteSort){
13522 this.fireEvent("datachanged", this);
13524 this.load(this.lastOptions);
13529 * Calls the specified function for each of the Records in the cache.
13530 * @param {Function} fn The function to call. The Record is passed as the first parameter.
13531 * Returning <em>false</em> aborts and exits the iteration.
13532 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
13534 each : function(fn, scope){
13535 this.data.each(fn, scope);
13539 * Gets all records modified since the last commit. Modified records are persisted across load operations
13540 * (e.g., during paging).
13541 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
13543 getModifiedRecords : function(){
13544 return this.modified;
13548 createFilterFn : function(property, value, anyMatch){
13549 if(!value.exec){ // not a regex
13550 value = String(value);
13551 if(value.length == 0){
13554 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
13556 return function(r){
13557 return value.test(r.data[property]);
13562 * Sums the value of <i>property</i> for each record between start and end and returns the result.
13563 * @param {String} property A field on your records
13564 * @param {Number} start The record index to start at (defaults to 0)
13565 * @param {Number} end The last record index to include (defaults to length - 1)
13566 * @return {Number} The sum
13568 sum : function(property, start, end){
13569 var rs = this.data.items, v = 0;
13570 start = start || 0;
13571 end = (end || end === 0) ? end : rs.length-1;
13573 for(var i = start; i <= end; i++){
13574 v += (rs[i].data[property] || 0);
13580 * Filter the records by a specified property.
13581 * @param {String} field A field on your records
13582 * @param {String/RegExp} value Either a string that the field
13583 * should start with or a RegExp to test against the field
13584 * @param {Boolean} anyMatch True to match any part not just the beginning
13586 filter : function(property, value, anyMatch){
13587 var fn = this.createFilterFn(property, value, anyMatch);
13588 return fn ? this.filterBy(fn) : this.clearFilter();
13592 * Filter by a function. The specified function will be called with each
13593 * record in this data source. If the function returns true the record is included,
13594 * otherwise it is filtered.
13595 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
13596 * @param {Object} scope (optional) The scope of the function (defaults to this)
13598 filterBy : function(fn, scope){
13599 this.snapshot = this.snapshot || this.data;
13600 this.data = this.queryBy(fn, scope||this);
13601 this.fireEvent("datachanged", this);
13605 * Query the records by a specified property.
13606 * @param {String} field A field on your records
13607 * @param {String/RegExp} value Either a string that the field
13608 * should start with or a RegExp to test against the field
13609 * @param {Boolean} anyMatch True to match any part not just the beginning
13610 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
13612 query : function(property, value, anyMatch){
13613 var fn = this.createFilterFn(property, value, anyMatch);
13614 return fn ? this.queryBy(fn) : this.data.clone();
13618 * Query by a function. The specified function will be called with each
13619 * record in this data source. If the function returns true the record is included
13621 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
13622 * @param {Object} scope (optional) The scope of the function (defaults to this)
13623 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
13625 queryBy : function(fn, scope){
13626 var data = this.snapshot || this.data;
13627 return data.filterBy(fn, scope||this);
13631 * Collects unique values for a particular dataIndex from this store.
13632 * @param {String} dataIndex The property to collect
13633 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
13634 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
13635 * @return {Array} An array of the unique values
13637 collect : function(dataIndex, allowNull, bypassFilter){
13638 var d = (bypassFilter === true && this.snapshot) ?
13639 this.snapshot.items : this.data.items;
13640 var v, sv, r = [], l = {};
13641 for(var i = 0, len = d.length; i < len; i++){
13642 v = d[i].data[dataIndex];
13644 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
13653 * Revert to a view of the Record cache with no filtering applied.
13654 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
13656 clearFilter : function(suppressEvent){
13657 if(this.snapshot && this.snapshot != this.data){
13658 this.data = this.snapshot;
13659 delete this.snapshot;
13660 if(suppressEvent !== true){
13661 this.fireEvent("datachanged", this);
13667 afterEdit : function(record){
13668 if(this.modified.indexOf(record) == -1){
13669 this.modified.push(record);
13671 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
13675 afterReject : function(record){
13676 this.modified.remove(record);
13677 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
13681 afterCommit : function(record){
13682 this.modified.remove(record);
13683 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
13687 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
13688 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
13690 commitChanges : function(){
13691 var m = this.modified.slice(0);
13692 this.modified = [];
13693 for(var i = 0, len = m.length; i < len; i++){
13699 * Cancel outstanding changes on all changed records.
13701 rejectChanges : function(){
13702 var m = this.modified.slice(0);
13703 this.modified = [];
13704 for(var i = 0, len = m.length; i < len; i++){
13709 onMetaChange : function(meta, rtype, o){
13710 this.recordType = rtype;
13711 this.fields = rtype.prototype.fields;
13712 delete this.snapshot;
13713 this.sortInfo = meta.sortInfo || this.sortInfo;
13714 this.modified = [];
13715 this.fireEvent('metachange', this, this.reader.meta);
13718 moveIndex : function(data, type)
13720 var index = this.indexOf(data);
13722 var newIndex = index + type;
13726 this.insert(newIndex, data);
13731 * Ext JS Library 1.1.1
13732 * Copyright(c) 2006-2007, Ext JS, LLC.
13734 * Originally Released Under LGPL - original licence link has changed is not relivant.
13737 * <script type="text/javascript">
13741 * @class Roo.data.SimpleStore
13742 * @extends Roo.data.Store
13743 * Small helper class to make creating Stores from Array data easier.
13744 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
13745 * @cfg {Array} fields An array of field definition objects, or field name strings.
13746 * @cfg {Object} an existing reader (eg. copied from another store)
13747 * @cfg {Array} data The multi-dimensional array of data
13749 * @param {Object} config
13751 Roo.data.SimpleStore = function(config)
13753 Roo.data.SimpleStore.superclass.constructor.call(this, {
13755 reader: typeof(config.reader) != 'undefined' ? config.reader : new Roo.data.ArrayReader({
13758 Roo.data.Record.create(config.fields)
13760 proxy : new Roo.data.MemoryProxy(config.data)
13764 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
13766 * Ext JS Library 1.1.1
13767 * Copyright(c) 2006-2007, Ext JS, LLC.
13769 * Originally Released Under LGPL - original licence link has changed is not relivant.
13772 * <script type="text/javascript">
13777 * @extends Roo.data.Store
13778 * @class Roo.data.JsonStore
13779 * Small helper class to make creating Stores for JSON data easier. <br/>
13781 var store = new Roo.data.JsonStore({
13782 url: 'get-images.php',
13784 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
13787 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
13788 * JsonReader and HttpProxy (unless inline data is provided).</b>
13789 * @cfg {Array} fields An array of field definition objects, or field name strings.
13791 * @param {Object} config
13793 Roo.data.JsonStore = function(c){
13794 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
13795 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
13796 reader: new Roo.data.JsonReader(c, c.fields)
13799 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
13801 * Ext JS Library 1.1.1
13802 * Copyright(c) 2006-2007, Ext JS, LLC.
13804 * Originally Released Under LGPL - original licence link has changed is not relivant.
13807 * <script type="text/javascript">
13811 Roo.data.Field = function(config){
13812 if(typeof config == "string"){
13813 config = {name: config};
13815 Roo.apply(this, config);
13818 this.type = "auto";
13821 var st = Roo.data.SortTypes;
13822 // named sortTypes are supported, here we look them up
13823 if(typeof this.sortType == "string"){
13824 this.sortType = st[this.sortType];
13827 // set default sortType for strings and dates
13828 if(!this.sortType){
13831 this.sortType = st.asUCString;
13834 this.sortType = st.asDate;
13837 this.sortType = st.none;
13842 var stripRe = /[\$,%]/g;
13844 // prebuilt conversion function for this field, instead of
13845 // switching every time we're reading a value
13847 var cv, dateFormat = this.dateFormat;
13852 cv = function(v){ return v; };
13855 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
13859 return v !== undefined && v !== null && v !== '' ?
13860 parseInt(String(v).replace(stripRe, ""), 10) : '';
13865 return v !== undefined && v !== null && v !== '' ?
13866 parseFloat(String(v).replace(stripRe, ""), 10) : '';
13871 cv = function(v){ return v === true || v === "true" || v == 1; };
13878 if(v instanceof Date){
13882 if(dateFormat == "timestamp"){
13883 return new Date(v*1000);
13885 return Date.parseDate(v, dateFormat);
13887 var parsed = Date.parse(v);
13888 return parsed ? new Date(parsed) : null;
13897 Roo.data.Field.prototype = {
13905 * Ext JS Library 1.1.1
13906 * Copyright(c) 2006-2007, Ext JS, LLC.
13908 * Originally Released Under LGPL - original licence link has changed is not relivant.
13911 * <script type="text/javascript">
13914 // Base class for reading structured data from a data source. This class is intended to be
13915 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
13918 * @class Roo.data.DataReader
13919 * Base class for reading structured data from a data source. This class is intended to be
13920 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
13923 Roo.data.DataReader = function(meta, recordType){
13927 this.recordType = recordType instanceof Array ?
13928 Roo.data.Record.create(recordType) : recordType;
13931 Roo.data.DataReader.prototype = {
13934 readerType : 'Data',
13936 * Create an empty record
13937 * @param {Object} data (optional) - overlay some values
13938 * @return {Roo.data.Record} record created.
13940 newRow : function(d) {
13942 this.recordType.prototype.fields.each(function(c) {
13944 case 'int' : da[c.name] = 0; break;
13945 case 'date' : da[c.name] = new Date(); break;
13946 case 'float' : da[c.name] = 0.0; break;
13947 case 'boolean' : da[c.name] = false; break;
13948 default : da[c.name] = ""; break;
13952 return new this.recordType(Roo.apply(da, d));
13958 * Ext JS Library 1.1.1
13959 * Copyright(c) 2006-2007, Ext JS, LLC.
13961 * Originally Released Under LGPL - original licence link has changed is not relivant.
13964 * <script type="text/javascript">
13968 * @class Roo.data.DataProxy
13969 * @extends Roo.data.Observable
13970 * This class is an abstract base class for implementations which provide retrieval of
13971 * unformatted data objects.<br>
13973 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
13974 * (of the appropriate type which knows how to parse the data object) to provide a block of
13975 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
13977 * Custom implementations must implement the load method as described in
13978 * {@link Roo.data.HttpProxy#load}.
13980 Roo.data.DataProxy = function(){
13983 * @event beforeload
13984 * Fires before a network request is made to retrieve a data object.
13985 * @param {Object} This DataProxy object.
13986 * @param {Object} params The params parameter to the load function.
13991 * Fires before the load method's callback is called.
13992 * @param {Object} This DataProxy object.
13993 * @param {Object} o The data object.
13994 * @param {Object} arg The callback argument object passed to the load function.
13998 * @event loadexception
13999 * Fires if an Exception occurs during data retrieval.
14000 * @param {Object} This DataProxy object.
14001 * @param {Object} o The data object.
14002 * @param {Object} arg The callback argument object passed to the load function.
14003 * @param {Object} e The Exception.
14005 loadexception : true
14007 Roo.data.DataProxy.superclass.constructor.call(this);
14010 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
14013 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
14017 * Ext JS Library 1.1.1
14018 * Copyright(c) 2006-2007, Ext JS, LLC.
14020 * Originally Released Under LGPL - original licence link has changed is not relivant.
14023 * <script type="text/javascript">
14026 * @class Roo.data.MemoryProxy
14027 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
14028 * to the Reader when its load method is called.
14030 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
14032 Roo.data.MemoryProxy = function(data){
14036 Roo.data.MemoryProxy.superclass.constructor.call(this);
14040 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
14043 * Load data from the requested source (in this case an in-memory
14044 * data object passed to the constructor), read the data object into
14045 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
14046 * process that block using the passed callback.
14047 * @param {Object} params This parameter is not used by the MemoryProxy class.
14048 * @param {Roo.data.DataReader} reader The Reader object which converts the data
14049 * object into a block of Roo.data.Records.
14050 * @param {Function} callback The function into which to pass the block of Roo.data.records.
14051 * The function must be passed <ul>
14052 * <li>The Record block object</li>
14053 * <li>The "arg" argument from the load function</li>
14054 * <li>A boolean success indicator</li>
14056 * @param {Object} scope The scope in which to call the callback
14057 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
14059 load : function(params, reader, callback, scope, arg){
14060 params = params || {};
14063 result = reader.readRecords(params.data ? params.data :this.data);
14065 this.fireEvent("loadexception", this, arg, null, e);
14066 callback.call(scope, null, arg, false);
14069 callback.call(scope, result, arg, true);
14073 update : function(params, records){
14078 * Ext JS Library 1.1.1
14079 * Copyright(c) 2006-2007, Ext JS, LLC.
14081 * Originally Released Under LGPL - original licence link has changed is not relivant.
14084 * <script type="text/javascript">
14087 * @class Roo.data.HttpProxy
14088 * @extends Roo.data.DataProxy
14089 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
14090 * configured to reference a certain URL.<br><br>
14092 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
14093 * from which the running page was served.<br><br>
14095 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
14097 * Be aware that to enable the browser to parse an XML document, the server must set
14098 * the Content-Type header in the HTTP response to "text/xml".
14100 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
14101 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
14102 * will be used to make the request.
14104 Roo.data.HttpProxy = function(conn){
14105 Roo.data.HttpProxy.superclass.constructor.call(this);
14106 // is conn a conn config or a real conn?
14108 this.useAjax = !conn || !conn.events;
14112 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
14113 // thse are take from connection...
14116 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
14119 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
14120 * extra parameters to each request made by this object. (defaults to undefined)
14123 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
14124 * to each request made by this object. (defaults to undefined)
14127 * @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)
14130 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
14133 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
14139 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
14143 * Return the {@link Roo.data.Connection} object being used by this Proxy.
14144 * @return {Connection} The Connection object. This object may be used to subscribe to events on
14145 * a finer-grained basis than the DataProxy events.
14147 getConnection : function(){
14148 return this.useAjax ? Roo.Ajax : this.conn;
14152 * Load data from the configured {@link Roo.data.Connection}, read the data object into
14153 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
14154 * process that block using the passed callback.
14155 * @param {Object} params An object containing properties which are to be used as HTTP parameters
14156 * for the request to the remote server.
14157 * @param {Roo.data.DataReader} reader The Reader object which converts the data
14158 * object into a block of Roo.data.Records.
14159 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
14160 * The function must be passed <ul>
14161 * <li>The Record block object</li>
14162 * <li>The "arg" argument from the load function</li>
14163 * <li>A boolean success indicator</li>
14165 * @param {Object} scope The scope in which to call the callback
14166 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
14168 load : function(params, reader, callback, scope, arg){
14169 if(this.fireEvent("beforeload", this, params) !== false){
14171 params : params || {},
14173 callback : callback,
14178 callback : this.loadResponse,
14182 Roo.applyIf(o, this.conn);
14183 if(this.activeRequest){
14184 Roo.Ajax.abort(this.activeRequest);
14186 this.activeRequest = Roo.Ajax.request(o);
14188 this.conn.request(o);
14191 callback.call(scope||this, null, arg, false);
14196 loadResponse : function(o, success, response){
14197 delete this.activeRequest;
14199 this.fireEvent("loadexception", this, o, response);
14200 o.request.callback.call(o.request.scope, null, o.request.arg, false);
14205 result = o.reader.read(response);
14207 this.fireEvent("loadexception", this, o, response, e);
14208 o.request.callback.call(o.request.scope, null, o.request.arg, false);
14212 this.fireEvent("load", this, o, o.request.arg);
14213 o.request.callback.call(o.request.scope, result, o.request.arg, true);
14217 update : function(dataSet){
14222 updateResponse : function(dataSet){
14227 * Ext JS Library 1.1.1
14228 * Copyright(c) 2006-2007, Ext JS, LLC.
14230 * Originally Released Under LGPL - original licence link has changed is not relivant.
14233 * <script type="text/javascript">
14237 * @class Roo.data.ScriptTagProxy
14238 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
14239 * other than the originating domain of the running page.<br><br>
14241 * <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
14242 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
14244 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
14245 * source code that is used as the source inside a <script> tag.<br><br>
14247 * In order for the browser to process the returned data, the server must wrap the data object
14248 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
14249 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
14250 * depending on whether the callback name was passed:
14253 boolean scriptTag = false;
14254 String cb = request.getParameter("callback");
14257 response.setContentType("text/javascript");
14259 response.setContentType("application/x-json");
14261 Writer out = response.getWriter();
14263 out.write(cb + "(");
14265 out.print(dataBlock.toJsonString());
14272 * @param {Object} config A configuration object.
14274 Roo.data.ScriptTagProxy = function(config){
14275 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
14276 Roo.apply(this, config);
14277 this.head = document.getElementsByTagName("head")[0];
14280 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
14282 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
14284 * @cfg {String} url The URL from which to request the data object.
14287 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
14291 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
14292 * the server the name of the callback function set up by the load call to process the returned data object.
14293 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
14294 * javascript output which calls this named function passing the data object as its only parameter.
14296 callbackParam : "callback",
14298 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
14299 * name to the request.
14304 * Load data from the configured URL, read the data object into
14305 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
14306 * process that block using the passed callback.
14307 * @param {Object} params An object containing properties which are to be used as HTTP parameters
14308 * for the request to the remote server.
14309 * @param {Roo.data.DataReader} reader The Reader object which converts the data
14310 * object into a block of Roo.data.Records.
14311 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
14312 * The function must be passed <ul>
14313 * <li>The Record block object</li>
14314 * <li>The "arg" argument from the load function</li>
14315 * <li>A boolean success indicator</li>
14317 * @param {Object} scope The scope in which to call the callback
14318 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
14320 load : function(params, reader, callback, scope, arg){
14321 if(this.fireEvent("beforeload", this, params) !== false){
14323 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
14325 var url = this.url;
14326 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
14328 url += "&_dc=" + (new Date().getTime());
14330 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
14333 cb : "stcCallback"+transId,
14334 scriptId : "stcScript"+transId,
14338 callback : callback,
14344 window[trans.cb] = function(o){
14345 conn.handleResponse(o, trans);
14348 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
14350 if(this.autoAbort !== false){
14354 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
14356 var script = document.createElement("script");
14357 script.setAttribute("src", url);
14358 script.setAttribute("type", "text/javascript");
14359 script.setAttribute("id", trans.scriptId);
14360 this.head.appendChild(script);
14362 this.trans = trans;
14364 callback.call(scope||this, null, arg, false);
14369 isLoading : function(){
14370 return this.trans ? true : false;
14374 * Abort the current server request.
14376 abort : function(){
14377 if(this.isLoading()){
14378 this.destroyTrans(this.trans);
14383 destroyTrans : function(trans, isLoaded){
14384 this.head.removeChild(document.getElementById(trans.scriptId));
14385 clearTimeout(trans.timeoutId);
14387 window[trans.cb] = undefined;
14389 delete window[trans.cb];
14392 // if hasn't been loaded, wait for load to remove it to prevent script error
14393 window[trans.cb] = function(){
14394 window[trans.cb] = undefined;
14396 delete window[trans.cb];
14403 handleResponse : function(o, trans){
14404 this.trans = false;
14405 this.destroyTrans(trans, true);
14408 result = trans.reader.readRecords(o);
14410 this.fireEvent("loadexception", this, o, trans.arg, e);
14411 trans.callback.call(trans.scope||window, null, trans.arg, false);
14414 this.fireEvent("load", this, o, trans.arg);
14415 trans.callback.call(trans.scope||window, result, trans.arg, true);
14419 handleFailure : function(trans){
14420 this.trans = false;
14421 this.destroyTrans(trans, false);
14422 this.fireEvent("loadexception", this, null, trans.arg);
14423 trans.callback.call(trans.scope||window, null, trans.arg, false);
14427 * Ext JS Library 1.1.1
14428 * Copyright(c) 2006-2007, Ext JS, LLC.
14430 * Originally Released Under LGPL - original licence link has changed is not relivant.
14433 * <script type="text/javascript">
14437 * @class Roo.data.JsonReader
14438 * @extends Roo.data.DataReader
14439 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
14440 * based on mappings in a provided Roo.data.Record constructor.
14442 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
14443 * in the reply previously.
14448 var RecordDef = Roo.data.Record.create([
14449 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
14450 {name: 'occupation'} // This field will use "occupation" as the mapping.
14452 var myReader = new Roo.data.JsonReader({
14453 totalProperty: "results", // The property which contains the total dataset size (optional)
14454 root: "rows", // The property which contains an Array of row objects
14455 id: "id" // The property within each row object that provides an ID for the record (optional)
14459 * This would consume a JSON file like this:
14461 { 'results': 2, 'rows': [
14462 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
14463 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
14466 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
14467 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
14468 * paged from the remote server.
14469 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
14470 * @cfg {String} root name of the property which contains the Array of row objects.
14471 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
14472 * @cfg {Array} fields Array of field definition objects
14474 * Create a new JsonReader
14475 * @param {Object} meta Metadata configuration options
14476 * @param {Object} recordType Either an Array of field definition objects,
14477 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
14479 Roo.data.JsonReader = function(meta, recordType){
14482 // set some defaults:
14483 Roo.applyIf(meta, {
14484 totalProperty: 'total',
14485 successProperty : 'success',
14490 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
14492 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
14494 readerType : 'Json',
14497 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
14498 * Used by Store query builder to append _requestMeta to params.
14501 metaFromRemote : false,
14503 * This method is only used by a DataProxy which has retrieved data from a remote server.
14504 * @param {Object} response The XHR object which contains the JSON data in its responseText.
14505 * @return {Object} data A data block which is used by an Roo.data.Store object as
14506 * a cache of Roo.data.Records.
14508 read : function(response){
14509 var json = response.responseText;
14511 var o = /* eval:var:o */ eval("("+json+")");
14513 throw {message: "JsonReader.read: Json object not found"};
14519 this.metaFromRemote = true;
14520 this.meta = o.metaData;
14521 this.recordType = Roo.data.Record.create(o.metaData.fields);
14522 this.onMetaChange(this.meta, this.recordType, o);
14524 return this.readRecords(o);
14527 // private function a store will implement
14528 onMetaChange : function(meta, recordType, o){
14535 simpleAccess: function(obj, subsc) {
14542 getJsonAccessor: function(){
14544 return function(expr) {
14546 return(re.test(expr))
14547 ? new Function("obj", "return obj." + expr)
14552 return Roo.emptyFn;
14557 * Create a data block containing Roo.data.Records from an XML document.
14558 * @param {Object} o An object which contains an Array of row objects in the property specified
14559 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
14560 * which contains the total size of the dataset.
14561 * @return {Object} data A data block which is used by an Roo.data.Store object as
14562 * a cache of Roo.data.Records.
14564 readRecords : function(o){
14566 * After any data loads, the raw JSON data is available for further custom processing.
14570 var s = this.meta, Record = this.recordType,
14571 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
14573 // Generate extraction functions for the totalProperty, the root, the id, and for each field
14575 if(s.totalProperty) {
14576 this.getTotal = this.getJsonAccessor(s.totalProperty);
14578 if(s.successProperty) {
14579 this.getSuccess = this.getJsonAccessor(s.successProperty);
14581 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
14583 var g = this.getJsonAccessor(s.id);
14584 this.getId = function(rec) {
14586 return (r === undefined || r === "") ? null : r;
14589 this.getId = function(){return null;};
14592 for(var jj = 0; jj < fl; jj++){
14594 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
14595 this.ef[jj] = this.getJsonAccessor(map);
14599 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
14600 if(s.totalProperty){
14601 var vt = parseInt(this.getTotal(o), 10);
14606 if(s.successProperty){
14607 var vs = this.getSuccess(o);
14608 if(vs === false || vs === 'false'){
14613 for(var i = 0; i < c; i++){
14616 var id = this.getId(n);
14617 for(var j = 0; j < fl; j++){
14619 var v = this.ef[j](n);
14621 Roo.log('missing convert for ' + f.name);
14625 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
14627 var record = new Record(values, id);
14629 records[i] = record;
14635 totalRecords : totalRecords
14638 // used when loading children.. @see loadDataFromChildren
14639 toLoadData: function(rec)
14641 // expect rec just to be an array.. eg [a,b,c, [...] << cn ]
14642 var data = typeof(rec.data.cn) == 'undefined' ? [] : rec.data.cn;
14643 return { data : data, total : data.length };
14648 * Ext JS Library 1.1.1
14649 * Copyright(c) 2006-2007, Ext JS, LLC.
14651 * Originally Released Under LGPL - original licence link has changed is not relivant.
14654 * <script type="text/javascript">
14658 * @class Roo.data.ArrayReader
14659 * @extends Roo.data.DataReader
14660 * Data reader class to create an Array of Roo.data.Record objects from an Array.
14661 * Each element of that Array represents a row of data fields. The
14662 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
14663 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
14667 var RecordDef = Roo.data.Record.create([
14668 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
14669 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
14671 var myReader = new Roo.data.ArrayReader({
14672 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
14676 * This would consume an Array like this:
14678 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
14682 * Create a new JsonReader
14683 * @param {Object} meta Metadata configuration options.
14684 * @param {Object|Array} recordType Either an Array of field definition objects
14686 * @cfg {Array} fields Array of field definition objects
14687 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
14688 * as specified to {@link Roo.data.Record#create},
14689 * or an {@link Roo.data.Record} object
14692 * created using {@link Roo.data.Record#create}.
14694 Roo.data.ArrayReader = function(meta, recordType)
14696 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType||meta.fields);
14699 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
14702 * Create a data block containing Roo.data.Records from an XML document.
14703 * @param {Object} o An Array of row objects which represents the dataset.
14704 * @return {Object} A data block which is used by an {@link Roo.data.Store} object as
14705 * a cache of Roo.data.Records.
14707 readRecords : function(o)
14709 var sid = this.meta ? this.meta.id : null;
14710 var recordType = this.recordType, fields = recordType.prototype.fields;
14713 for(var i = 0; i < root.length; i++){
14716 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
14717 for(var j = 0, jlen = fields.length; j < jlen; j++){
14718 var f = fields.items[j];
14719 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
14720 var v = n[k] !== undefined ? n[k] : f.defaultValue;
14722 values[f.name] = v;
14724 var record = new recordType(values, id);
14726 records[records.length] = record;
14730 totalRecords : records.length
14733 // used when loading children.. @see loadDataFromChildren
14734 toLoadData: function(rec)
14736 // expect rec just to be an array.. eg [a,b,c, [...] << cn ]
14737 return typeof(rec.data.cn) == 'undefined' ? [] : rec.data.cn;
14748 * @class Roo.bootstrap.ComboBox
14749 * @extends Roo.bootstrap.TriggerField
14750 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
14751 * @cfg {Boolean} append (true|false) default false
14752 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
14753 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
14754 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
14755 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
14756 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
14757 * @cfg {Boolean} animate default true
14758 * @cfg {Boolean} emptyResultText only for touch device
14759 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
14760 * @cfg {String} emptyTitle default ''
14761 * @cfg {Number} width fixed with? experimental
14763 * Create a new ComboBox.
14764 * @param {Object} config Configuration options
14766 Roo.bootstrap.ComboBox = function(config){
14767 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
14771 * Fires when the dropdown list is expanded
14772 * @param {Roo.bootstrap.ComboBox} combo This combo box
14777 * Fires when the dropdown list is collapsed
14778 * @param {Roo.bootstrap.ComboBox} combo This combo box
14782 * @event beforeselect
14783 * Fires before a list item is selected. Return false to cancel the selection.
14784 * @param {Roo.bootstrap.ComboBox} combo This combo box
14785 * @param {Roo.data.Record} record The data record returned from the underlying store
14786 * @param {Number} index The index of the selected item in the dropdown list
14788 'beforeselect' : true,
14791 * Fires when a list item is selected
14792 * @param {Roo.bootstrap.ComboBox} combo This combo box
14793 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
14794 * @param {Number} index The index of the selected item in the dropdown list
14798 * @event beforequery
14799 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
14800 * The event object passed has these properties:
14801 * @param {Roo.bootstrap.ComboBox} combo This combo box
14802 * @param {String} query The query
14803 * @param {Boolean} forceAll true to force "all" query
14804 * @param {Boolean} cancel true to cancel the query
14805 * @param {Object} e The query event object
14807 'beforequery': true,
14810 * Fires when the 'add' icon is pressed (add a listener to enable add button)
14811 * @param {Roo.bootstrap.ComboBox} combo This combo box
14816 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
14817 * @param {Roo.bootstrap.ComboBox} combo This combo box
14818 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
14823 * Fires when the remove value from the combobox array
14824 * @param {Roo.bootstrap.ComboBox} combo This combo box
14828 * @event afterremove
14829 * Fires when the remove value from the combobox array
14830 * @param {Roo.bootstrap.ComboBox} combo This combo box
14832 'afterremove' : true,
14834 * @event specialfilter
14835 * Fires when specialfilter
14836 * @param {Roo.bootstrap.ComboBox} combo This combo box
14838 'specialfilter' : true,
14841 * Fires when tick the element
14842 * @param {Roo.bootstrap.ComboBox} combo This combo box
14846 * @event touchviewdisplay
14847 * Fires when touch view require special display (default is using displayField)
14848 * @param {Roo.bootstrap.ComboBox} combo This combo box
14849 * @param {Object} cfg set html .
14851 'touchviewdisplay' : true
14856 this.tickItems = [];
14858 this.selectedIndex = -1;
14859 if(this.mode == 'local'){
14860 if(config.queryDelay === undefined){
14861 this.queryDelay = 10;
14863 if(config.minChars === undefined){
14869 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
14872 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
14873 * rendering into an Roo.Editor, defaults to false)
14876 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
14877 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
14880 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
14883 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
14884 * the dropdown list (defaults to undefined, with no header element)
14888 * @cfg {String/Roo.Template} tpl The template to use to render the output default is '<a class="dropdown-item" href="#">{' + this.displayField + '}</a>'
14892 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
14894 listWidth: undefined,
14896 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
14897 * mode = 'remote' or 'text' if mode = 'local')
14899 displayField: undefined,
14902 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
14903 * mode = 'remote' or 'value' if mode = 'local').
14904 * Note: use of a valueField requires the user make a selection
14905 * in order for a value to be mapped.
14907 valueField: undefined,
14909 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
14914 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
14915 * field's data value (defaults to the underlying DOM element's name)
14917 hiddenName: undefined,
14919 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
14923 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
14925 selectedClass: 'active',
14928 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
14932 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
14933 * anchor positions (defaults to 'tl-bl')
14935 listAlign: 'tl-bl?',
14937 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
14941 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
14942 * query specified by the allQuery config option (defaults to 'query')
14944 triggerAction: 'query',
14946 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
14947 * (defaults to 4, does not apply if editable = false)
14951 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
14952 * delay (typeAheadDelay) if it matches a known value (defaults to false)
14956 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
14957 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
14961 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
14962 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
14966 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
14967 * when editable = true (defaults to false)
14969 selectOnFocus:false,
14971 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
14973 queryParam: 'query',
14975 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
14976 * when mode = 'remote' (defaults to 'Loading...')
14978 loadingText: 'Loading...',
14980 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
14984 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
14988 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
14989 * traditional select (defaults to true)
14993 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
14997 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
15001 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
15002 * listWidth has a higher value)
15006 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
15007 * allow the user to set arbitrary text into the field (defaults to false)
15009 forceSelection:false,
15011 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
15012 * if typeAhead = true (defaults to 250)
15014 typeAheadDelay : 250,
15016 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
15017 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
15019 valueNotFoundText : undefined,
15021 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
15023 blockFocus : false,
15026 * @cfg {Boolean} disableClear Disable showing of clear button.
15028 disableClear : false,
15030 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
15032 alwaysQuery : false,
15035 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
15040 * @cfg {String} invalidClass DEPRICATED - uses BS4 is-valid now
15042 invalidClass : "has-warning",
15045 * @cfg {String} validClass DEPRICATED - uses BS4 is-valid now
15047 validClass : "has-success",
15050 * @cfg {Boolean} specialFilter (true|false) special filter default false
15052 specialFilter : false,
15055 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
15057 mobileTouchView : true,
15060 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
15062 useNativeIOS : false,
15065 * @cfg {Boolean} mobile_restrict_height (true|false) restrict height for touch view
15067 mobile_restrict_height : false,
15069 ios_options : false,
15081 btnPosition : 'right',
15082 triggerList : true,
15083 showToggleBtn : true,
15085 emptyResultText: 'Empty',
15086 triggerText : 'Select',
15090 // element that contains real text value.. (when hidden is used..)
15092 getAutoCreate : function()
15097 * Render classic select for iso
15100 if(Roo.isIOS && this.useNativeIOS){
15101 cfg = this.getAutoCreateNativeIOS();
15109 if(Roo.isTouch && this.mobileTouchView){
15110 cfg = this.getAutoCreateTouchView();
15117 if(!this.tickable){
15118 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
15123 * ComboBox with tickable selections
15126 var align = this.labelAlign || this.parentLabelAlign();
15129 cls : 'form-group roo-combobox-tickable' //input-group
15132 var btn_text_select = '';
15133 var btn_text_done = '';
15134 var btn_text_cancel = '';
15136 if (this.btn_text_show) {
15137 btn_text_select = 'Select';
15138 btn_text_done = 'Done';
15139 btn_text_cancel = 'Cancel';
15144 cls : 'tickable-buttons',
15149 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
15150 //html : this.triggerText
15151 html: btn_text_select
15157 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
15159 html: btn_text_done
15165 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
15167 html: btn_text_cancel
15173 buttons.cn.unshift({
15175 cls: 'roo-select2-search-field-input'
15181 Roo.each(buttons.cn, function(c){
15183 c.cls += ' btn-' + _this.size;
15186 if (_this.disabled) {
15193 style : 'display: contents',
15198 cls: 'form-hidden-field'
15202 cls: 'roo-select2-choices',
15206 cls: 'roo-select2-search-field',
15217 cls: 'roo-select2-container input-group roo-select2-container-multi',
15223 // cls: 'typeahead typeahead-long dropdown-menu',
15224 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
15229 if(this.hasFeedback && !this.allowBlank){
15233 cls: 'glyphicon form-control-feedback'
15236 combobox.cn.push(feedback);
15243 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
15244 tooltip : 'This field is required'
15246 if (Roo.bootstrap.version == 4) {
15249 style : 'display:none'
15252 if (align ==='left' && this.fieldLabel.length) {
15254 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
15261 cls : 'control-label col-form-label',
15262 html : this.fieldLabel
15274 var labelCfg = cfg.cn[1];
15275 var contentCfg = cfg.cn[2];
15278 if(this.indicatorpos == 'right'){
15284 cls : 'control-label col-form-label',
15288 html : this.fieldLabel
15304 labelCfg = cfg.cn[0];
15305 contentCfg = cfg.cn[1];
15309 if(this.labelWidth > 12){
15310 labelCfg.style = "width: " + this.labelWidth + 'px';
15312 if(this.width * 1 > 0){
15313 contentCfg.style = "width: " + this.width + 'px';
15315 if(this.labelWidth < 13 && this.labelmd == 0){
15316 this.labelmd = this.labelWidth;
15319 if(this.labellg > 0){
15320 labelCfg.cls += ' col-lg-' + this.labellg;
15321 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
15324 if(this.labelmd > 0){
15325 labelCfg.cls += ' col-md-' + this.labelmd;
15326 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
15329 if(this.labelsm > 0){
15330 labelCfg.cls += ' col-sm-' + this.labelsm;
15331 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
15334 if(this.labelxs > 0){
15335 labelCfg.cls += ' col-xs-' + this.labelxs;
15336 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
15340 } else if ( this.fieldLabel.length) {
15341 // Roo.log(" label");
15346 //cls : 'input-group-addon',
15347 html : this.fieldLabel
15352 if(this.indicatorpos == 'right'){
15356 //cls : 'input-group-addon',
15357 html : this.fieldLabel
15367 // Roo.log(" no label && no align");
15374 ['xs','sm','md','lg'].map(function(size){
15375 if (settings[size]) {
15376 cfg.cls += ' col-' + size + '-' + settings[size];
15384 _initEventsCalled : false,
15387 initEvents: function()
15389 if (this._initEventsCalled) { // as we call render... prevent looping...
15392 this._initEventsCalled = true;
15395 throw "can not find store for combo";
15398 this.indicator = this.indicatorEl();
15400 this.store = Roo.factory(this.store, Roo.data);
15401 this.store.parent = this;
15403 // if we are building from html. then this element is so complex, that we can not really
15404 // use the rendered HTML.
15405 // so we have to trash and replace the previous code.
15406 if (Roo.XComponent.build_from_html) {
15407 // remove this element....
15408 var e = this.el.dom, k=0;
15409 while (e ) { e = e.previousSibling; ++k;}
15414 this.rendered = false;
15416 this.render(this.parent().getChildContainer(true), k);
15419 if(Roo.isIOS && this.useNativeIOS){
15420 this.initIOSView();
15428 if(Roo.isTouch && this.mobileTouchView){
15429 this.initTouchView();
15434 this.initTickableEvents();
15438 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
15440 if(this.hiddenName){
15442 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
15444 this.hiddenField.dom.value =
15445 this.hiddenValue !== undefined ? this.hiddenValue :
15446 this.value !== undefined ? this.value : '';
15448 // prevent input submission
15449 this.el.dom.removeAttribute('name');
15450 this.hiddenField.dom.setAttribute('name', this.hiddenName);
15455 // this.el.dom.setAttribute('autocomplete', 'off');
15458 var cls = 'x-combo-list';
15460 //this.list = new Roo.Layer({
15461 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
15467 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
15468 _this.list.setWidth(lw);
15471 this.list.on('mouseover', this.onViewOver, this);
15472 this.list.on('mousemove', this.onViewMove, this);
15473 this.list.on('scroll', this.onViewScroll, this);
15476 this.list.swallowEvent('mousewheel');
15477 this.assetHeight = 0;
15480 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
15481 this.assetHeight += this.header.getHeight();
15484 this.innerList = this.list.createChild({cls:cls+'-inner'});
15485 this.innerList.on('mouseover', this.onViewOver, this);
15486 this.innerList.on('mousemove', this.onViewMove, this);
15487 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
15489 if(this.allowBlank && !this.pageSize && !this.disableClear){
15490 this.footer = this.list.createChild({cls:cls+'-ft'});
15491 this.pageTb = new Roo.Toolbar(this.footer);
15495 this.footer = this.list.createChild({cls:cls+'-ft'});
15496 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
15497 {pageSize: this.pageSize});
15501 if (this.pageTb && this.allowBlank && !this.disableClear) {
15503 this.pageTb.add(new Roo.Toolbar.Fill(), {
15504 cls: 'x-btn-icon x-btn-clear',
15506 handler: function()
15509 _this.clearValue();
15510 _this.onSelect(false, -1);
15515 this.assetHeight += this.footer.getHeight();
15520 this.tpl = Roo.bootstrap.version == 4 ?
15521 '<a class="dropdown-item" href="#">{' + this.displayField + '}</a>' : // 4 does not need <li> and it get's really confisued.
15522 '<li><a class="dropdown-item" href="#">{' + this.displayField + '}</a></li>';
15525 this.view = new Roo.View(this.list, this.tpl, {
15526 singleSelect:true, store: this.store, selectedClass: this.selectedClass
15528 //this.view.wrapEl.setDisplayed(false);
15529 this.view.on('click', this.onViewClick, this);
15532 this.store.on('beforeload', this.onBeforeLoad, this);
15533 this.store.on('load', this.onLoad, this);
15534 this.store.on('loadexception', this.onLoadException, this);
15536 if(this.resizable){
15537 this.resizer = new Roo.Resizable(this.list, {
15538 pinned:true, handles:'se'
15540 this.resizer.on('resize', function(r, w, h){
15541 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
15542 this.listWidth = w;
15543 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
15544 this.restrictHeight();
15546 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
15549 if(!this.editable){
15550 this.editable = true;
15551 this.setEditable(false);
15556 if (typeof(this.events.add.listeners) != 'undefined') {
15558 this.addicon = this.wrap.createChild(
15559 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
15561 this.addicon.on('click', function(e) {
15562 this.fireEvent('add', this);
15565 if (typeof(this.events.edit.listeners) != 'undefined') {
15567 this.editicon = this.wrap.createChild(
15568 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
15569 if (this.addicon) {
15570 this.editicon.setStyle('margin-left', '40px');
15572 this.editicon.on('click', function(e) {
15574 // we fire even if inothing is selected..
15575 this.fireEvent('edit', this, this.lastData );
15581 this.keyNav = new Roo.KeyNav(this.inputEl(), {
15582 "up" : function(e){
15583 this.inKeyMode = true;
15587 "down" : function(e){
15588 if(!this.isExpanded()){
15589 this.onTriggerClick();
15591 this.inKeyMode = true;
15596 "enter" : function(e){
15597 // this.onViewClick();
15601 if(this.fireEvent("specialkey", this, e)){
15602 this.onViewClick(false);
15608 "esc" : function(e){
15612 "tab" : function(e){
15615 if(this.fireEvent("specialkey", this, e)){
15616 this.onViewClick(false);
15624 doRelay : function(foo, bar, hname){
15625 if(hname == 'down' || this.scope.isExpanded()){
15626 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
15635 this.queryDelay = Math.max(this.queryDelay || 10,
15636 this.mode == 'local' ? 10 : 250);
15639 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
15641 if(this.typeAhead){
15642 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
15644 if(this.editable !== false){
15645 this.inputEl().on("keyup", this.onKeyUp, this);
15647 if(this.forceSelection){
15648 this.inputEl().on('blur', this.doForce, this);
15652 this.choices = this.el.select('ul.roo-select2-choices', true).first();
15653 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
15657 initTickableEvents: function()
15661 if(this.hiddenName){
15663 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
15665 this.hiddenField.dom.value =
15666 this.hiddenValue !== undefined ? this.hiddenValue :
15667 this.value !== undefined ? this.value : '';
15669 // prevent input submission
15670 this.el.dom.removeAttribute('name');
15671 this.hiddenField.dom.setAttribute('name', this.hiddenName);
15676 // this.list = this.el.select('ul.dropdown-menu',true).first();
15678 this.choices = this.el.select('ul.roo-select2-choices', true).first();
15679 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
15680 if(this.triggerList){
15681 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
15684 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
15685 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
15687 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
15688 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
15690 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
15691 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
15693 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
15694 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
15695 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
15698 this.cancelBtn.hide();
15703 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
15704 _this.list.setWidth(lw);
15707 this.list.on('mouseover', this.onViewOver, this);
15708 this.list.on('mousemove', this.onViewMove, this);
15710 this.list.on('scroll', this.onViewScroll, this);
15713 this.tpl = '<li class="roo-select2-result"><div class="checkbox"><input id="{roo-id}"' +
15714 'type="checkbox" {roo-data-checked}><label for="{roo-id}"><b>{' + this.displayField + '}</b></label></div></li>';
15717 this.view = new Roo.View(this.list, this.tpl, {
15722 selectedClass: this.selectedClass
15725 //this.view.wrapEl.setDisplayed(false);
15726 this.view.on('click', this.onViewClick, this);
15730 this.store.on('beforeload', this.onBeforeLoad, this);
15731 this.store.on('load', this.onLoad, this);
15732 this.store.on('loadexception', this.onLoadException, this);
15735 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
15736 "up" : function(e){
15737 this.inKeyMode = true;
15741 "down" : function(e){
15742 this.inKeyMode = true;
15746 "enter" : function(e){
15747 if(this.fireEvent("specialkey", this, e)){
15748 this.onViewClick(false);
15754 "esc" : function(e){
15755 this.onTickableFooterButtonClick(e, false, false);
15758 "tab" : function(e){
15759 this.fireEvent("specialkey", this, e);
15761 this.onTickableFooterButtonClick(e, false, false);
15768 doRelay : function(e, fn, key){
15769 if(this.scope.isExpanded()){
15770 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
15779 this.queryDelay = Math.max(this.queryDelay || 10,
15780 this.mode == 'local' ? 10 : 250);
15783 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
15785 if(this.typeAhead){
15786 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
15789 if(this.editable !== false){
15790 this.tickableInputEl().on("keyup", this.onKeyUp, this);
15793 this.indicator = this.indicatorEl();
15795 if(this.indicator){
15796 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
15797 this.indicator.hide();
15802 onDestroy : function(){
15804 this.view.setStore(null);
15805 this.view.el.removeAllListeners();
15806 this.view.el.remove();
15807 this.view.purgeListeners();
15810 this.list.dom.innerHTML = '';
15814 this.store.un('beforeload', this.onBeforeLoad, this);
15815 this.store.un('load', this.onLoad, this);
15816 this.store.un('loadexception', this.onLoadException, this);
15818 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
15822 fireKey : function(e){
15823 if(e.isNavKeyPress() && !this.list.isVisible()){
15824 this.fireEvent("specialkey", this, e);
15829 onResize: function(w, h)
15833 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
15835 // if(typeof w != 'number'){
15836 // // we do not handle it!?!?
15839 // var tw = this.trigger.getWidth();
15840 // // tw += this.addicon ? this.addicon.getWidth() : 0;
15841 // // tw += this.editicon ? this.editicon.getWidth() : 0;
15843 // this.inputEl().setWidth( this.adjustWidth('input', x));
15845 // //this.trigger.setStyle('left', x+'px');
15847 // if(this.list && this.listWidth === undefined){
15848 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
15849 // this.list.setWidth(lw);
15850 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
15858 * Allow or prevent the user from directly editing the field text. If false is passed,
15859 * the user will only be able to select from the items defined in the dropdown list. This method
15860 * is the runtime equivalent of setting the 'editable' config option at config time.
15861 * @param {Boolean} value True to allow the user to directly edit the field text
15863 setEditable : function(value){
15864 if(value == this.editable){
15867 this.editable = value;
15869 this.inputEl().dom.setAttribute('readOnly', true);
15870 this.inputEl().on('mousedown', this.onTriggerClick, this);
15871 this.inputEl().addClass('x-combo-noedit');
15873 this.inputEl().dom.setAttribute('readOnly', false);
15874 this.inputEl().un('mousedown', this.onTriggerClick, this);
15875 this.inputEl().removeClass('x-combo-noedit');
15881 onBeforeLoad : function(combo,opts){
15882 if(!this.hasFocus){
15886 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
15888 this.restrictHeight();
15889 this.selectedIndex = -1;
15893 onLoad : function(){
15895 this.hasQuery = false;
15897 if(!this.hasFocus){
15901 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
15902 this.loading.hide();
15905 if(this.store.getCount() > 0){
15908 this.restrictHeight();
15909 if(this.lastQuery == this.allQuery){
15910 if(this.editable && !this.tickable){
15911 this.inputEl().dom.select();
15915 !this.selectByValue(this.value, true) &&
15918 !this.store.lastOptions ||
15919 typeof(this.store.lastOptions.add) == 'undefined' ||
15920 this.store.lastOptions.add != true
15923 this.select(0, true);
15926 if(this.autoFocus){
15929 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
15930 this.taTask.delay(this.typeAheadDelay);
15934 this.onEmptyResults();
15940 onLoadException : function()
15942 this.hasQuery = false;
15944 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
15945 this.loading.hide();
15948 if(this.tickable && this.editable){
15953 // only causes errors at present
15954 //Roo.log(this.store.reader.jsonData);
15955 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
15957 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
15963 onTypeAhead : function(){
15964 if(this.store.getCount() > 0){
15965 var r = this.store.getAt(0);
15966 var newValue = r.data[this.displayField];
15967 var len = newValue.length;
15968 var selStart = this.getRawValue().length;
15970 if(selStart != len){
15971 this.setRawValue(newValue);
15972 this.selectText(selStart, newValue.length);
15978 onSelect : function(record, index){
15980 if(this.fireEvent('beforeselect', this, record, index) !== false){
15982 this.setFromData(index > -1 ? record.data : false);
15985 this.fireEvent('select', this, record, index);
15990 * Returns the currently selected field value or empty string if no value is set.
15991 * @return {String} value The selected value
15993 getValue : function()
15995 if(Roo.isIOS && this.useNativeIOS){
15996 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
16000 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
16003 if(this.valueField){
16004 return typeof this.value != 'undefined' ? this.value : '';
16006 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
16010 getRawValue : function()
16012 if(Roo.isIOS && this.useNativeIOS){
16013 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
16016 var v = this.inputEl().getValue();
16022 * Clears any text/value currently set in the field
16024 clearValue : function(){
16026 if(this.hiddenField){
16027 this.hiddenField.dom.value = '';
16030 this.setRawValue('');
16031 this.lastSelectionText = '';
16032 this.lastData = false;
16034 var close = this.closeTriggerEl();
16045 * Sets the specified value into the field. If the value finds a match, the corresponding record text
16046 * will be displayed in the field. If the value does not match the data value of an existing item,
16047 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
16048 * Otherwise the field will be blank (although the value will still be set).
16049 * @param {String} value The value to match
16051 setValue : function(v)
16053 if(Roo.isIOS && this.useNativeIOS){
16054 this.setIOSValue(v);
16064 if(this.valueField){
16065 var r = this.findRecord(this.valueField, v);
16067 text = r.data[this.displayField];
16068 }else if(this.valueNotFoundText !== undefined){
16069 text = this.valueNotFoundText;
16072 this.lastSelectionText = text;
16073 if(this.hiddenField){
16074 this.hiddenField.dom.value = v;
16076 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
16079 var close = this.closeTriggerEl();
16082 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
16088 * @property {Object} the last set data for the element
16093 * Sets the value of the field based on a object which is related to the record format for the store.
16094 * @param {Object} value the value to set as. or false on reset?
16096 setFromData : function(o){
16103 var dv = ''; // display value
16104 var vv = ''; // value value..
16106 if (this.displayField) {
16107 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
16109 // this is an error condition!!!
16110 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
16113 if(this.valueField){
16114 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
16117 var close = this.closeTriggerEl();
16120 if(dv.length || vv * 1 > 0){
16122 this.blockFocus=true;
16128 if(this.hiddenField){
16129 this.hiddenField.dom.value = vv;
16131 this.lastSelectionText = dv;
16132 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
16136 // no hidden field.. - we store the value in 'value', but still display
16137 // display field!!!!
16138 this.lastSelectionText = dv;
16139 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
16146 reset : function(){
16147 // overridden so that last data is reset..
16154 this.setValue(this.originalValue);
16155 //this.clearInvalid();
16156 this.lastData = false;
16158 this.view.clearSelections();
16164 findRecord : function(prop, value){
16166 if(this.store.getCount() > 0){
16167 this.store.each(function(r){
16168 if(r.data[prop] == value){
16178 getName: function()
16180 // returns hidden if it's set..
16181 if (!this.rendered) {return ''};
16182 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
16186 onViewMove : function(e, t){
16187 this.inKeyMode = false;
16191 onViewOver : function(e, t){
16192 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
16195 var item = this.view.findItemFromChild(t);
16198 var index = this.view.indexOf(item);
16199 this.select(index, false);
16204 onViewClick : function(view, doFocus, el, e)
16206 var index = this.view.getSelectedIndexes()[0];
16208 var r = this.store.getAt(index);
16212 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
16219 Roo.each(this.tickItems, function(v,k){
16221 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
16223 _this.tickItems.splice(k, 1);
16225 if(typeof(e) == 'undefined' && view == false){
16226 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
16238 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
16239 this.tickItems.push(r.data);
16242 if(typeof(e) == 'undefined' && view == false){
16243 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
16250 this.onSelect(r, index);
16252 if(doFocus !== false && !this.blockFocus){
16253 this.inputEl().focus();
16258 restrictHeight : function(){
16259 //this.innerList.dom.style.height = '';
16260 //var inner = this.innerList.dom;
16261 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
16262 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
16263 //this.list.beginUpdate();
16264 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
16265 this.list.alignTo(this.inputEl(), this.listAlign);
16266 this.list.alignTo(this.inputEl(), this.listAlign);
16267 //this.list.endUpdate();
16271 onEmptyResults : function(){
16273 if(this.tickable && this.editable){
16274 this.hasFocus = false;
16275 this.restrictHeight();
16283 * Returns true if the dropdown list is expanded, else false.
16285 isExpanded : function(){
16286 return this.list.isVisible();
16290 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
16291 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
16292 * @param {String} value The data value of the item to select
16293 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
16294 * selected item if it is not currently in view (defaults to true)
16295 * @return {Boolean} True if the value matched an item in the list, else false
16297 selectByValue : function(v, scrollIntoView){
16298 if(v !== undefined && v !== null){
16299 var r = this.findRecord(this.valueField || this.displayField, v);
16301 this.select(this.store.indexOf(r), scrollIntoView);
16309 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
16310 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
16311 * @param {Number} index The zero-based index of the list item to select
16312 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
16313 * selected item if it is not currently in view (defaults to true)
16315 select : function(index, scrollIntoView){
16316 this.selectedIndex = index;
16317 this.view.select(index);
16318 if(scrollIntoView !== false){
16319 var el = this.view.getNode(index);
16321 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
16324 this.list.scrollChildIntoView(el, false);
16330 selectNext : function(){
16331 var ct = this.store.getCount();
16333 if(this.selectedIndex == -1){
16335 }else if(this.selectedIndex < ct-1){
16336 this.select(this.selectedIndex+1);
16342 selectPrev : function(){
16343 var ct = this.store.getCount();
16345 if(this.selectedIndex == -1){
16347 }else if(this.selectedIndex != 0){
16348 this.select(this.selectedIndex-1);
16354 onKeyUp : function(e){
16355 if(this.editable !== false && !e.isSpecialKey()){
16356 this.lastKey = e.getKey();
16357 this.dqTask.delay(this.queryDelay);
16362 validateBlur : function(){
16363 return !this.list || !this.list.isVisible();
16367 initQuery : function(){
16369 var v = this.getRawValue();
16371 if(this.tickable && this.editable){
16372 v = this.tickableInputEl().getValue();
16379 doForce : function(){
16380 if(this.inputEl().dom.value.length > 0){
16381 this.inputEl().dom.value =
16382 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
16388 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
16389 * query allowing the query action to be canceled if needed.
16390 * @param {String} query The SQL query to execute
16391 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
16392 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
16393 * saved in the current store (defaults to false)
16395 doQuery : function(q, forceAll){
16397 if(q === undefined || q === null){
16402 forceAll: forceAll,
16406 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
16411 forceAll = qe.forceAll;
16412 if(forceAll === true || (q.length >= this.minChars)){
16414 this.hasQuery = true;
16416 if(this.lastQuery != q || this.alwaysQuery){
16417 this.lastQuery = q;
16418 if(this.mode == 'local'){
16419 this.selectedIndex = -1;
16421 this.store.clearFilter();
16424 if(this.specialFilter){
16425 this.fireEvent('specialfilter', this);
16430 this.store.filter(this.displayField, q);
16433 this.store.fireEvent("datachanged", this.store);
16440 this.store.baseParams[this.queryParam] = q;
16442 var options = {params : this.getParams(q)};
16445 options.add = true;
16446 options.params.start = this.page * this.pageSize;
16449 this.store.load(options);
16452 * this code will make the page width larger, at the beginning, the list not align correctly,
16453 * we should expand the list on onLoad
16454 * so command out it
16459 this.selectedIndex = -1;
16464 this.loadNext = false;
16468 getParams : function(q){
16470 //p[this.queryParam] = q;
16474 p.limit = this.pageSize;
16480 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
16482 collapse : function(){
16483 if(!this.isExpanded()){
16489 this.hasFocus = false;
16493 this.cancelBtn.hide();
16494 this.trigger.show();
16497 this.tickableInputEl().dom.value = '';
16498 this.tickableInputEl().blur();
16503 Roo.get(document).un('mousedown', this.collapseIf, this);
16504 Roo.get(document).un('mousewheel', this.collapseIf, this);
16505 if (!this.editable) {
16506 Roo.get(document).un('keydown', this.listKeyPress, this);
16508 this.fireEvent('collapse', this);
16514 collapseIf : function(e){
16515 var in_combo = e.within(this.el);
16516 var in_list = e.within(this.list);
16517 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
16519 if (in_combo || in_list || is_list) {
16520 //e.stopPropagation();
16525 this.onTickableFooterButtonClick(e, false, false);
16533 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
16535 expand : function(){
16537 if(this.isExpanded() || !this.hasFocus){
16541 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
16542 this.list.setWidth(lw);
16548 this.restrictHeight();
16552 this.tickItems = Roo.apply([], this.item);
16555 this.cancelBtn.show();
16556 this.trigger.hide();
16559 this.tickableInputEl().focus();
16564 Roo.get(document).on('mousedown', this.collapseIf, this);
16565 Roo.get(document).on('mousewheel', this.collapseIf, this);
16566 if (!this.editable) {
16567 Roo.get(document).on('keydown', this.listKeyPress, this);
16570 this.fireEvent('expand', this);
16574 // Implements the default empty TriggerField.onTriggerClick function
16575 onTriggerClick : function(e)
16577 Roo.log('trigger click');
16579 if(this.disabled || !this.triggerList){
16584 this.loadNext = false;
16586 if(this.isExpanded()){
16588 if (!this.blockFocus) {
16589 this.inputEl().focus();
16593 this.hasFocus = true;
16594 if(this.triggerAction == 'all') {
16595 this.doQuery(this.allQuery, true);
16597 this.doQuery(this.getRawValue());
16599 if (!this.blockFocus) {
16600 this.inputEl().focus();
16605 onTickableTriggerClick : function(e)
16612 this.loadNext = false;
16613 this.hasFocus = true;
16615 if(this.triggerAction == 'all') {
16616 this.doQuery(this.allQuery, true);
16618 this.doQuery(this.getRawValue());
16622 onSearchFieldClick : function(e)
16624 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
16625 this.onTickableFooterButtonClick(e, false, false);
16629 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
16634 this.loadNext = false;
16635 this.hasFocus = true;
16637 if(this.triggerAction == 'all') {
16638 this.doQuery(this.allQuery, true);
16640 this.doQuery(this.getRawValue());
16644 listKeyPress : function(e)
16646 //Roo.log('listkeypress');
16647 // scroll to first matching element based on key pres..
16648 if (e.isSpecialKey()) {
16651 var k = String.fromCharCode(e.getKey()).toUpperCase();
16654 var csel = this.view.getSelectedNodes();
16655 var cselitem = false;
16657 var ix = this.view.indexOf(csel[0]);
16658 cselitem = this.store.getAt(ix);
16659 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
16665 this.store.each(function(v) {
16667 // start at existing selection.
16668 if (cselitem.id == v.id) {
16674 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
16675 match = this.store.indexOf(v);
16681 if (match === false) {
16682 return true; // no more action?
16685 this.view.select(match);
16686 var sn = Roo.get(this.view.getSelectedNodes()[0]);
16687 sn.scrollIntoView(sn.dom.parentNode, false);
16690 onViewScroll : function(e, t){
16692 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){
16696 this.hasQuery = true;
16698 this.loading = this.list.select('.loading', true).first();
16700 if(this.loading === null){
16701 this.list.createChild({
16703 cls: 'loading roo-select2-more-results roo-select2-active',
16704 html: 'Loading more results...'
16707 this.loading = this.list.select('.loading', true).first();
16709 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
16711 this.loading.hide();
16714 this.loading.show();
16719 this.loadNext = true;
16721 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
16726 addItem : function(o)
16728 var dv = ''; // display value
16730 if (this.displayField) {
16731 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
16733 // this is an error condition!!!
16734 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
16741 var choice = this.choices.createChild({
16743 cls: 'roo-select2-search-choice',
16752 cls: 'roo-select2-search-choice-close fa fa-times',
16757 }, this.searchField);
16759 var close = choice.select('a.roo-select2-search-choice-close', true).first();
16761 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
16769 this.inputEl().dom.value = '';
16774 onRemoveItem : function(e, _self, o)
16776 e.preventDefault();
16778 this.lastItem = Roo.apply([], this.item);
16780 var index = this.item.indexOf(o.data) * 1;
16783 Roo.log('not this item?!');
16787 this.item.splice(index, 1);
16792 this.fireEvent('remove', this, e);
16798 syncValue : function()
16800 if(!this.item.length){
16807 Roo.each(this.item, function(i){
16808 if(_this.valueField){
16809 value.push(i[_this.valueField]);
16816 this.value = value.join(',');
16818 if(this.hiddenField){
16819 this.hiddenField.dom.value = this.value;
16822 this.store.fireEvent("datachanged", this.store);
16827 clearItem : function()
16829 if(!this.multiple){
16835 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
16843 if(this.tickable && !Roo.isTouch){
16844 this.view.refresh();
16848 inputEl: function ()
16850 if(Roo.isIOS && this.useNativeIOS){
16851 return this.el.select('select.roo-ios-select', true).first();
16854 if(Roo.isTouch && this.mobileTouchView){
16855 return this.el.select('input.form-control',true).first();
16859 return this.searchField;
16862 return this.el.select('input.form-control',true).first();
16865 onTickableFooterButtonClick : function(e, btn, el)
16867 e.preventDefault();
16869 this.lastItem = Roo.apply([], this.item);
16871 if(btn && btn.name == 'cancel'){
16872 this.tickItems = Roo.apply([], this.item);
16881 Roo.each(this.tickItems, function(o){
16889 validate : function()
16891 if(this.getVisibilityEl().hasClass('hidden')){
16895 var v = this.getRawValue();
16898 v = this.getValue();
16901 if(this.disabled || this.allowBlank || v.length){
16906 this.markInvalid();
16910 tickableInputEl : function()
16912 if(!this.tickable || !this.editable){
16913 return this.inputEl();
16916 return this.inputEl().select('.roo-select2-search-field-input', true).first();
16920 getAutoCreateTouchView : function()
16925 cls: 'form-group' //input-group
16931 type : this.inputType,
16932 cls : 'form-control x-combo-noedit',
16933 autocomplete: 'new-password',
16934 placeholder : this.placeholder || '',
16939 input.name = this.name;
16943 input.cls += ' input-' + this.size;
16946 if (this.disabled) {
16947 input.disabled = true;
16951 cls : 'roo-combobox-wrap',
16958 inputblock.cls += ' input-group';
16960 inputblock.cn.unshift({
16962 cls : 'input-group-addon input-group-prepend input-group-text',
16967 if(this.removable && !this.multiple){
16968 inputblock.cls += ' roo-removable';
16970 inputblock.cn.push({
16973 cls : 'roo-combo-removable-btn close'
16977 if(this.hasFeedback && !this.allowBlank){
16979 inputblock.cls += ' has-feedback';
16981 inputblock.cn.push({
16983 cls: 'glyphicon form-control-feedback'
16990 inputblock.cls += (this.before) ? '' : ' input-group';
16992 inputblock.cn.push({
16994 cls : 'input-group-addon input-group-append input-group-text',
17000 var ibwrap = inputblock;
17005 cls: 'roo-select2-choices',
17009 cls: 'roo-select2-search-field',
17022 cls: 'roo-select2-container input-group roo-touchview-combobox ',
17027 cls: 'form-hidden-field'
17033 if(!this.multiple && this.showToggleBtn){
17039 if (this.caret != false) {
17042 cls: 'fa fa-' + this.caret
17049 cls : 'input-group-addon input-group-append input-group-text btn dropdown-toggle',
17051 Roo.bootstrap.version == 3 ? caret : '',
17054 cls: 'combobox-clear',
17068 combobox.cls += ' roo-select2-container-multi';
17071 var align = this.labelAlign || this.parentLabelAlign();
17073 if (align ==='left' && this.fieldLabel.length) {
17078 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
17079 tooltip : 'This field is required'
17083 cls : 'control-label col-form-label',
17084 html : this.fieldLabel
17088 cls : 'roo-combobox-wrap ',
17095 var labelCfg = cfg.cn[1];
17096 var contentCfg = cfg.cn[2];
17099 if(this.indicatorpos == 'right'){
17104 cls : 'control-label col-form-label',
17108 html : this.fieldLabel
17112 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
17113 tooltip : 'This field is required'
17118 cls : "roo-combobox-wrap ",
17126 labelCfg = cfg.cn[0];
17127 contentCfg = cfg.cn[1];
17132 if(this.labelWidth > 12){
17133 labelCfg.style = "width: " + this.labelWidth + 'px';
17136 if(this.labelWidth < 13 && this.labelmd == 0){
17137 this.labelmd = this.labelWidth;
17140 if(this.labellg > 0){
17141 labelCfg.cls += ' col-lg-' + this.labellg;
17142 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
17145 if(this.labelmd > 0){
17146 labelCfg.cls += ' col-md-' + this.labelmd;
17147 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
17150 if(this.labelsm > 0){
17151 labelCfg.cls += ' col-sm-' + this.labelsm;
17152 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
17155 if(this.labelxs > 0){
17156 labelCfg.cls += ' col-xs-' + this.labelxs;
17157 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
17161 } else if ( this.fieldLabel.length) {
17165 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
17166 tooltip : 'This field is required'
17170 cls : 'control-label',
17171 html : this.fieldLabel
17182 if(this.indicatorpos == 'right'){
17186 cls : 'control-label',
17187 html : this.fieldLabel,
17191 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
17192 tooltip : 'This field is required'
17209 var settings = this;
17211 ['xs','sm','md','lg'].map(function(size){
17212 if (settings[size]) {
17213 cfg.cls += ' col-' + size + '-' + settings[size];
17220 initTouchView : function()
17222 this.renderTouchView();
17224 this.touchViewEl.on('scroll', function(){
17225 this.el.dom.scrollTop = 0;
17228 this.originalValue = this.getValue();
17230 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
17232 this.inputEl().on("click", this.showTouchView, this);
17233 if (this.triggerEl) {
17234 this.triggerEl.on("click", this.showTouchView, this);
17238 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
17239 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
17241 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
17243 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
17244 this.store.on('load', this.onTouchViewLoad, this);
17245 this.store.on('loadexception', this.onTouchViewLoadException, this);
17247 if(this.hiddenName){
17249 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
17251 this.hiddenField.dom.value =
17252 this.hiddenValue !== undefined ? this.hiddenValue :
17253 this.value !== undefined ? this.value : '';
17255 this.el.dom.removeAttribute('name');
17256 this.hiddenField.dom.setAttribute('name', this.hiddenName);
17260 this.choices = this.el.select('ul.roo-select2-choices', true).first();
17261 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
17264 if(this.removable && !this.multiple){
17265 var close = this.closeTriggerEl();
17267 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
17268 close.on('click', this.removeBtnClick, this, close);
17272 * fix the bug in Safari iOS8
17274 this.inputEl().on("focus", function(e){
17275 document.activeElement.blur();
17278 this._touchViewMask = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
17285 renderTouchView : function()
17287 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
17288 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
17290 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
17291 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
17293 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
17294 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
17295 this.touchViewBodyEl.setStyle('overflow', 'auto');
17297 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
17298 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
17300 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
17301 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
17305 showTouchView : function()
17311 this.touchViewHeaderEl.hide();
17313 if(this.modalTitle.length){
17314 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
17315 this.touchViewHeaderEl.show();
17318 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
17319 this.touchViewEl.show();
17321 this.touchViewEl.select('.modal-dialog', true).first().setStyle({ margin : '0px', width : '100%'});
17323 //this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
17324 // Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
17326 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
17328 if(this.modalTitle.length){
17329 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
17332 this.touchViewBodyEl.setHeight(bodyHeight);
17336 (function(){ _this.touchViewEl.addClass(['in','show']); }).defer(50);
17338 this.touchViewEl.addClass(['in','show']);
17341 if(this._touchViewMask){
17342 Roo.get(document.body).addClass("x-body-masked");
17343 this._touchViewMask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
17344 this._touchViewMask.setStyle('z-index', 10000);
17345 this._touchViewMask.addClass('show');
17348 this.doTouchViewQuery();
17352 hideTouchView : function()
17354 this.touchViewEl.removeClass(['in','show']);
17358 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
17360 this.touchViewEl.setStyle('display', 'none');
17363 if(this._touchViewMask){
17364 this._touchViewMask.removeClass('show');
17365 Roo.get(document.body).removeClass("x-body-masked");
17369 setTouchViewValue : function()
17376 Roo.each(this.tickItems, function(o){
17381 this.hideTouchView();
17384 doTouchViewQuery : function()
17393 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
17397 if(!this.alwaysQuery || this.mode == 'local'){
17398 this.onTouchViewLoad();
17405 onTouchViewBeforeLoad : function(combo,opts)
17411 onTouchViewLoad : function()
17413 if(this.store.getCount() < 1){
17414 this.onTouchViewEmptyResults();
17418 this.clearTouchView();
17420 var rawValue = this.getRawValue();
17422 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
17424 this.tickItems = [];
17426 this.store.data.each(function(d, rowIndex){
17427 var row = this.touchViewListGroup.createChild(template);
17429 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
17430 row.addClass(d.data.cls);
17433 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
17436 html : d.data[this.displayField]
17439 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
17440 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
17443 row.removeClass('selected');
17444 if(!this.multiple && this.valueField &&
17445 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
17448 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
17449 row.addClass('selected');
17452 if(this.multiple && this.valueField &&
17453 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
17457 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
17458 this.tickItems.push(d.data);
17461 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
17465 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
17467 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
17469 if(this.modalTitle.length){
17470 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
17473 var listHeight = this.touchViewListGroup.getHeight() + this.touchViewBodyEl.getPadding('tb') * 2;
17475 if(this.mobile_restrict_height && listHeight < bodyHeight){
17476 this.touchViewBodyEl.setHeight(listHeight);
17481 if(firstChecked && listHeight > bodyHeight){
17482 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
17487 onTouchViewLoadException : function()
17489 this.hideTouchView();
17492 onTouchViewEmptyResults : function()
17494 this.clearTouchView();
17496 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
17498 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
17502 clearTouchView : function()
17504 this.touchViewListGroup.dom.innerHTML = '';
17507 onTouchViewClick : function(e, el, o)
17509 e.preventDefault();
17512 var rowIndex = o.rowIndex;
17514 var r = this.store.getAt(rowIndex);
17516 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
17518 if(!this.multiple){
17519 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
17520 c.dom.removeAttribute('checked');
17523 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
17525 this.setFromData(r.data);
17527 var close = this.closeTriggerEl();
17533 this.hideTouchView();
17535 this.fireEvent('select', this, r, rowIndex);
17540 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
17541 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
17542 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
17546 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
17547 this.addItem(r.data);
17548 this.tickItems.push(r.data);
17552 getAutoCreateNativeIOS : function()
17555 cls: 'form-group' //input-group,
17560 cls : 'roo-ios-select'
17564 combobox.name = this.name;
17567 if (this.disabled) {
17568 combobox.disabled = true;
17571 var settings = this;
17573 ['xs','sm','md','lg'].map(function(size){
17574 if (settings[size]) {
17575 cfg.cls += ' col-' + size + '-' + settings[size];
17585 initIOSView : function()
17587 this.store.on('load', this.onIOSViewLoad, this);
17592 onIOSViewLoad : function()
17594 if(this.store.getCount() < 1){
17598 this.clearIOSView();
17600 if(this.allowBlank) {
17602 var default_text = '-- SELECT --';
17604 if(this.placeholder.length){
17605 default_text = this.placeholder;
17608 if(this.emptyTitle.length){
17609 default_text += ' - ' + this.emptyTitle + ' -';
17612 var opt = this.inputEl().createChild({
17615 html : default_text
17619 o[this.valueField] = 0;
17620 o[this.displayField] = default_text;
17622 this.ios_options.push({
17629 this.store.data.each(function(d, rowIndex){
17633 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
17634 html = d.data[this.displayField];
17639 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
17640 value = d.data[this.valueField];
17649 if(this.value == d.data[this.valueField]){
17650 option['selected'] = true;
17653 var opt = this.inputEl().createChild(option);
17655 this.ios_options.push({
17662 this.inputEl().on('change', function(){
17663 this.fireEvent('select', this);
17668 clearIOSView: function()
17670 this.inputEl().dom.innerHTML = '';
17672 this.ios_options = [];
17675 setIOSValue: function(v)
17679 if(!this.ios_options){
17683 Roo.each(this.ios_options, function(opts){
17685 opts.el.dom.removeAttribute('selected');
17687 if(opts.data[this.valueField] != v){
17691 opts.el.dom.setAttribute('selected', true);
17697 * @cfg {Boolean} grow
17701 * @cfg {Number} growMin
17705 * @cfg {Number} growMax
17714 Roo.apply(Roo.bootstrap.ComboBox, {
17718 cls: 'modal-header',
17740 cls: 'list-group-item',
17744 cls: 'roo-combobox-list-group-item-value'
17748 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
17762 listItemCheckbox : {
17764 cls: 'list-group-item',
17768 cls: 'roo-combobox-list-group-item-value'
17772 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
17788 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
17793 cls: 'modal-footer',
17801 cls: 'col-xs-6 text-left',
17804 cls: 'btn btn-danger roo-touch-view-cancel',
17810 cls: 'col-xs-6 text-right',
17813 cls: 'btn btn-success roo-touch-view-ok',
17824 Roo.apply(Roo.bootstrap.ComboBox, {
17826 touchViewTemplate : {
17828 cls: 'modal fade roo-combobox-touch-view',
17832 cls: 'modal-dialog',
17833 style : 'position:fixed', // we have to fix position....
17837 cls: 'modal-content',
17839 Roo.bootstrap.ComboBox.header,
17840 Roo.bootstrap.ComboBox.body,
17841 Roo.bootstrap.ComboBox.footer
17850 * Ext JS Library 1.1.1
17851 * Copyright(c) 2006-2007, Ext JS, LLC.
17853 * Originally Released Under LGPL - original licence link has changed is not relivant.
17856 * <script type="text/javascript">
17861 * @extends Roo.util.Observable
17862 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
17863 * This class also supports single and multi selection modes. <br>
17864 * Create a data model bound view:
17866 var store = new Roo.data.Store(...);
17868 var view = new Roo.View({
17870 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
17872 singleSelect: true,
17873 selectedClass: "ydataview-selected",
17877 // listen for node click?
17878 view.on("click", function(vw, index, node, e){
17879 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
17883 dataModel.load("foobar.xml");
17885 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
17887 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
17888 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
17890 * Note: old style constructor is still suported (container, template, config)
17893 * Create a new View
17894 * @param {Object} config The config object
17897 Roo.View = function(config, depreciated_tpl, depreciated_config){
17899 this.parent = false;
17901 if (typeof(depreciated_tpl) == 'undefined') {
17902 // new way.. - universal constructor.
17903 Roo.apply(this, config);
17904 this.el = Roo.get(this.el);
17907 this.el = Roo.get(config);
17908 this.tpl = depreciated_tpl;
17909 Roo.apply(this, depreciated_config);
17911 this.wrapEl = this.el.wrap().wrap();
17912 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
17915 if(typeof(this.tpl) == "string"){
17916 this.tpl = new Roo.Template(this.tpl);
17918 // support xtype ctors..
17919 this.tpl = new Roo.factory(this.tpl, Roo);
17923 this.tpl.compile();
17928 * @event beforeclick
17929 * Fires before a click is processed. Returns false to cancel the default action.
17930 * @param {Roo.View} this
17931 * @param {Number} index The index of the target node
17932 * @param {HTMLElement} node The target node
17933 * @param {Roo.EventObject} e The raw event object
17935 "beforeclick" : true,
17938 * Fires when a template node is clicked.
17939 * @param {Roo.View} this
17940 * @param {Number} index The index of the target node
17941 * @param {HTMLElement} node The target node
17942 * @param {Roo.EventObject} e The raw event object
17947 * Fires when a template node is double clicked.
17948 * @param {Roo.View} this
17949 * @param {Number} index The index of the target node
17950 * @param {HTMLElement} node The target node
17951 * @param {Roo.EventObject} e The raw event object
17955 * @event contextmenu
17956 * Fires when a template node is right clicked.
17957 * @param {Roo.View} this
17958 * @param {Number} index The index of the target node
17959 * @param {HTMLElement} node The target node
17960 * @param {Roo.EventObject} e The raw event object
17962 "contextmenu" : true,
17964 * @event selectionchange
17965 * Fires when the selected nodes change.
17966 * @param {Roo.View} this
17967 * @param {Array} selections Array of the selected nodes
17969 "selectionchange" : true,
17972 * @event beforeselect
17973 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
17974 * @param {Roo.View} this
17975 * @param {HTMLElement} node The node to be selected
17976 * @param {Array} selections Array of currently selected nodes
17978 "beforeselect" : true,
17980 * @event preparedata
17981 * Fires on every row to render, to allow you to change the data.
17982 * @param {Roo.View} this
17983 * @param {Object} data to be rendered (change this)
17985 "preparedata" : true
17993 "click": this.onClick,
17994 "dblclick": this.onDblClick,
17995 "contextmenu": this.onContextMenu,
17999 this.selections = [];
18001 this.cmp = new Roo.CompositeElementLite([]);
18003 this.store = Roo.factory(this.store, Roo.data);
18004 this.setStore(this.store, true);
18007 if ( this.footer && this.footer.xtype) {
18009 var fctr = this.wrapEl.appendChild(document.createElement("div"));
18011 this.footer.dataSource = this.store;
18012 this.footer.container = fctr;
18013 this.footer = Roo.factory(this.footer, Roo);
18014 fctr.insertFirst(this.el);
18016 // this is a bit insane - as the paging toolbar seems to detach the el..
18017 // dom.parentNode.parentNode.parentNode
18018 // they get detached?
18022 Roo.View.superclass.constructor.call(this);
18027 Roo.extend(Roo.View, Roo.util.Observable, {
18030 * @cfg {Roo.data.Store} store Data store to load data from.
18035 * @cfg {String|Roo.Element} el The container element.
18040 * @cfg {String|Roo.Template} tpl The template used by this View
18044 * @cfg {String} dataName the named area of the template to use as the data area
18045 * Works with domtemplates roo-name="name"
18049 * @cfg {String} selectedClass The css class to add to selected nodes
18051 selectedClass : "x-view-selected",
18053 * @cfg {String} emptyText The empty text to show when nothing is loaded.
18058 * @cfg {String} text to display on mask (default Loading)
18062 * @cfg {Boolean} multiSelect Allow multiple selection
18064 multiSelect : false,
18066 * @cfg {Boolean} singleSelect Allow single selection
18068 singleSelect: false,
18071 * @cfg {Boolean} toggleSelect - selecting
18073 toggleSelect : false,
18076 * @cfg {Boolean} tickable - selecting
18081 * Returns the element this view is bound to.
18082 * @return {Roo.Element}
18084 getEl : function(){
18085 return this.wrapEl;
18091 * Refreshes the view. - called by datachanged on the store. - do not call directly.
18093 refresh : function(){
18094 //Roo.log('refresh');
18097 // if we are using something like 'domtemplate', then
18098 // the what gets used is:
18099 // t.applySubtemplate(NAME, data, wrapping data..)
18100 // the outer template then get' applied with
18101 // the store 'extra data'
18102 // and the body get's added to the
18103 // roo-name="data" node?
18104 // <span class='roo-tpl-{name}'></span> ?????
18108 this.clearSelections();
18109 this.el.update("");
18111 var records = this.store.getRange();
18112 if(records.length < 1) {
18114 // is this valid?? = should it render a template??
18116 this.el.update(this.emptyText);
18120 if (this.dataName) {
18121 this.el.update(t.apply(this.store.meta)); //????
18122 el = this.el.child('.roo-tpl-' + this.dataName);
18125 for(var i = 0, len = records.length; i < len; i++){
18126 var data = this.prepareData(records[i].data, i, records[i]);
18127 this.fireEvent("preparedata", this, data, i, records[i]);
18129 var d = Roo.apply({}, data);
18132 Roo.apply(d, {'roo-id' : Roo.id()});
18136 Roo.each(this.parent.item, function(item){
18137 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
18140 Roo.apply(d, {'roo-data-checked' : 'checked'});
18144 html[html.length] = Roo.util.Format.trim(
18146 t.applySubtemplate(this.dataName, d, this.store.meta) :
18153 el.update(html.join(""));
18154 this.nodes = el.dom.childNodes;
18155 this.updateIndexes(0);
18160 * Function to override to reformat the data that is sent to
18161 * the template for each node.
18162 * DEPRICATED - use the preparedata event handler.
18163 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
18164 * a JSON object for an UpdateManager bound view).
18166 prepareData : function(data, index, record)
18168 this.fireEvent("preparedata", this, data, index, record);
18172 onUpdate : function(ds, record){
18173 // Roo.log('on update');
18174 this.clearSelections();
18175 var index = this.store.indexOf(record);
18176 var n = this.nodes[index];
18177 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
18178 n.parentNode.removeChild(n);
18179 this.updateIndexes(index, index);
18185 onAdd : function(ds, records, index)
18187 //Roo.log(['on Add', ds, records, index] );
18188 this.clearSelections();
18189 if(this.nodes.length == 0){
18193 var n = this.nodes[index];
18194 for(var i = 0, len = records.length; i < len; i++){
18195 var d = this.prepareData(records[i].data, i, records[i]);
18197 this.tpl.insertBefore(n, d);
18200 this.tpl.append(this.el, d);
18203 this.updateIndexes(index);
18206 onRemove : function(ds, record, index){
18207 // Roo.log('onRemove');
18208 this.clearSelections();
18209 var el = this.dataName ?
18210 this.el.child('.roo-tpl-' + this.dataName) :
18213 el.dom.removeChild(this.nodes[index]);
18214 this.updateIndexes(index);
18218 * Refresh an individual node.
18219 * @param {Number} index
18221 refreshNode : function(index){
18222 this.onUpdate(this.store, this.store.getAt(index));
18225 updateIndexes : function(startIndex, endIndex){
18226 var ns = this.nodes;
18227 startIndex = startIndex || 0;
18228 endIndex = endIndex || ns.length - 1;
18229 for(var i = startIndex; i <= endIndex; i++){
18230 ns[i].nodeIndex = i;
18235 * Changes the data store this view uses and refresh the view.
18236 * @param {Store} store
18238 setStore : function(store, initial){
18239 if(!initial && this.store){
18240 this.store.un("datachanged", this.refresh);
18241 this.store.un("add", this.onAdd);
18242 this.store.un("remove", this.onRemove);
18243 this.store.un("update", this.onUpdate);
18244 this.store.un("clear", this.refresh);
18245 this.store.un("beforeload", this.onBeforeLoad);
18246 this.store.un("load", this.onLoad);
18247 this.store.un("loadexception", this.onLoad);
18251 store.on("datachanged", this.refresh, this);
18252 store.on("add", this.onAdd, this);
18253 store.on("remove", this.onRemove, this);
18254 store.on("update", this.onUpdate, this);
18255 store.on("clear", this.refresh, this);
18256 store.on("beforeload", this.onBeforeLoad, this);
18257 store.on("load", this.onLoad, this);
18258 store.on("loadexception", this.onLoad, this);
18266 * onbeforeLoad - masks the loading area.
18269 onBeforeLoad : function(store,opts)
18271 //Roo.log('onBeforeLoad');
18273 this.el.update("");
18275 this.el.mask(this.mask ? this.mask : "Loading" );
18277 onLoad : function ()
18284 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
18285 * @param {HTMLElement} node
18286 * @return {HTMLElement} The template node
18288 findItemFromChild : function(node){
18289 var el = this.dataName ?
18290 this.el.child('.roo-tpl-' + this.dataName,true) :
18293 if(!node || node.parentNode == el){
18296 var p = node.parentNode;
18297 while(p && p != el){
18298 if(p.parentNode == el){
18307 onClick : function(e){
18308 var item = this.findItemFromChild(e.getTarget());
18310 var index = this.indexOf(item);
18311 if(this.onItemClick(item, index, e) !== false){
18312 this.fireEvent("click", this, index, item, e);
18315 this.clearSelections();
18320 onContextMenu : function(e){
18321 var item = this.findItemFromChild(e.getTarget());
18323 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
18328 onDblClick : function(e){
18329 var item = this.findItemFromChild(e.getTarget());
18331 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
18335 onItemClick : function(item, index, e)
18337 if(this.fireEvent("beforeclick", this, index, item, e) === false){
18340 if (this.toggleSelect) {
18341 var m = this.isSelected(item) ? 'unselect' : 'select';
18344 _t[m](item, true, false);
18347 if(this.multiSelect || this.singleSelect){
18348 if(this.multiSelect && e.shiftKey && this.lastSelection){
18349 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
18351 this.select(item, this.multiSelect && e.ctrlKey);
18352 this.lastSelection = item;
18355 if(!this.tickable){
18356 e.preventDefault();
18364 * Get the number of selected nodes.
18367 getSelectionCount : function(){
18368 return this.selections.length;
18372 * Get the currently selected nodes.
18373 * @return {Array} An array of HTMLElements
18375 getSelectedNodes : function(){
18376 return this.selections;
18380 * Get the indexes of the selected nodes.
18383 getSelectedIndexes : function(){
18384 var indexes = [], s = this.selections;
18385 for(var i = 0, len = s.length; i < len; i++){
18386 indexes.push(s[i].nodeIndex);
18392 * Clear all selections
18393 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
18395 clearSelections : function(suppressEvent){
18396 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
18397 this.cmp.elements = this.selections;
18398 this.cmp.removeClass(this.selectedClass);
18399 this.selections = [];
18400 if(!suppressEvent){
18401 this.fireEvent("selectionchange", this, this.selections);
18407 * Returns true if the passed node is selected
18408 * @param {HTMLElement/Number} node The node or node index
18409 * @return {Boolean}
18411 isSelected : function(node){
18412 var s = this.selections;
18416 node = this.getNode(node);
18417 return s.indexOf(node) !== -1;
18422 * @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
18423 * @param {Boolean} keepExisting (optional) true to keep existing selections
18424 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
18426 select : function(nodeInfo, keepExisting, suppressEvent){
18427 if(nodeInfo instanceof Array){
18429 this.clearSelections(true);
18431 for(var i = 0, len = nodeInfo.length; i < len; i++){
18432 this.select(nodeInfo[i], true, true);
18436 var node = this.getNode(nodeInfo);
18437 if(!node || this.isSelected(node)){
18438 return; // already selected.
18441 this.clearSelections(true);
18444 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
18445 Roo.fly(node).addClass(this.selectedClass);
18446 this.selections.push(node);
18447 if(!suppressEvent){
18448 this.fireEvent("selectionchange", this, this.selections);
18456 * @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
18457 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
18458 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
18460 unselect : function(nodeInfo, keepExisting, suppressEvent)
18462 if(nodeInfo instanceof Array){
18463 Roo.each(this.selections, function(s) {
18464 this.unselect(s, nodeInfo);
18468 var node = this.getNode(nodeInfo);
18469 if(!node || !this.isSelected(node)){
18470 //Roo.log("not selected");
18471 return; // not selected.
18475 Roo.each(this.selections, function(s) {
18477 Roo.fly(node).removeClass(this.selectedClass);
18484 this.selections= ns;
18485 this.fireEvent("selectionchange", this, this.selections);
18489 * Gets a template node.
18490 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
18491 * @return {HTMLElement} The node or null if it wasn't found
18493 getNode : function(nodeInfo){
18494 if(typeof nodeInfo == "string"){
18495 return document.getElementById(nodeInfo);
18496 }else if(typeof nodeInfo == "number"){
18497 return this.nodes[nodeInfo];
18503 * Gets a range template nodes.
18504 * @param {Number} startIndex
18505 * @param {Number} endIndex
18506 * @return {Array} An array of nodes
18508 getNodes : function(start, end){
18509 var ns = this.nodes;
18510 start = start || 0;
18511 end = typeof end == "undefined" ? ns.length - 1 : end;
18514 for(var i = start; i <= end; i++){
18518 for(var i = start; i >= end; i--){
18526 * Finds the index of the passed node
18527 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
18528 * @return {Number} The index of the node or -1
18530 indexOf : function(node){
18531 node = this.getNode(node);
18532 if(typeof node.nodeIndex == "number"){
18533 return node.nodeIndex;
18535 var ns = this.nodes;
18536 for(var i = 0, len = ns.length; i < len; i++){
18547 * based on jquery fullcalendar
18551 Roo.bootstrap = Roo.bootstrap || {};
18553 * @class Roo.bootstrap.Calendar
18554 * @extends Roo.bootstrap.Component
18555 * Bootstrap Calendar class
18556 * @cfg {Boolean} loadMask (true|false) default false
18557 * @cfg {Object} header generate the user specific header of the calendar, default false
18560 * Create a new Container
18561 * @param {Object} config The config object
18566 Roo.bootstrap.Calendar = function(config){
18567 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
18571 * Fires when a date is selected
18572 * @param {DatePicker} this
18573 * @param {Date} date The selected date
18577 * @event monthchange
18578 * Fires when the displayed month changes
18579 * @param {DatePicker} this
18580 * @param {Date} date The selected month
18582 'monthchange': true,
18584 * @event evententer
18585 * Fires when mouse over an event
18586 * @param {Calendar} this
18587 * @param {event} Event
18589 'evententer': true,
18591 * @event eventleave
18592 * Fires when the mouse leaves an
18593 * @param {Calendar} this
18596 'eventleave': true,
18598 * @event eventclick
18599 * Fires when the mouse click an
18600 * @param {Calendar} this
18609 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
18612 * @cfg {Number} startDay
18613 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
18621 getAutoCreate : function(){
18624 var fc_button = function(name, corner, style, content ) {
18625 return Roo.apply({},{
18627 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
18629 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
18632 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
18643 style : 'width:100%',
18650 cls : 'fc-header-left',
18652 fc_button('prev', 'left', 'arrow', '‹' ),
18653 fc_button('next', 'right', 'arrow', '›' ),
18654 { tag: 'span', cls: 'fc-header-space' },
18655 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
18663 cls : 'fc-header-center',
18667 cls: 'fc-header-title',
18670 html : 'month / year'
18678 cls : 'fc-header-right',
18680 /* fc_button('month', 'left', '', 'month' ),
18681 fc_button('week', '', '', 'week' ),
18682 fc_button('day', 'right', '', 'day' )
18694 header = this.header;
18697 var cal_heads = function() {
18699 // fixme - handle this.
18701 for (var i =0; i < Date.dayNames.length; i++) {
18702 var d = Date.dayNames[i];
18705 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
18706 html : d.substring(0,3)
18710 ret[0].cls += ' fc-first';
18711 ret[6].cls += ' fc-last';
18714 var cal_cell = function(n) {
18717 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
18722 cls: 'fc-day-number',
18726 cls: 'fc-day-content',
18730 style: 'position: relative;' // height: 17px;
18742 var cal_rows = function() {
18745 for (var r = 0; r < 6; r++) {
18752 for (var i =0; i < Date.dayNames.length; i++) {
18753 var d = Date.dayNames[i];
18754 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
18757 row.cn[0].cls+=' fc-first';
18758 row.cn[0].cn[0].style = 'min-height:90px';
18759 row.cn[6].cls+=' fc-last';
18763 ret[0].cls += ' fc-first';
18764 ret[4].cls += ' fc-prev-last';
18765 ret[5].cls += ' fc-last';
18772 cls: 'fc-border-separate',
18773 style : 'width:100%',
18781 cls : 'fc-first fc-last',
18799 cls : 'fc-content',
18800 style : "position: relative;",
18803 cls : 'fc-view fc-view-month fc-grid',
18804 style : 'position: relative',
18805 unselectable : 'on',
18808 cls : 'fc-event-container',
18809 style : 'position:absolute;z-index:8;top:0;left:0;'
18827 initEvents : function()
18830 throw "can not find store for calendar";
18836 style: "text-align:center",
18840 style: "background-color:white;width:50%;margin:250 auto",
18844 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
18855 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
18857 var size = this.el.select('.fc-content', true).first().getSize();
18858 this.maskEl.setSize(size.width, size.height);
18859 this.maskEl.enableDisplayMode("block");
18860 if(!this.loadMask){
18861 this.maskEl.hide();
18864 this.store = Roo.factory(this.store, Roo.data);
18865 this.store.on('load', this.onLoad, this);
18866 this.store.on('beforeload', this.onBeforeLoad, this);
18870 this.cells = this.el.select('.fc-day',true);
18871 //Roo.log(this.cells);
18872 this.textNodes = this.el.query('.fc-day-number');
18873 this.cells.addClassOnOver('fc-state-hover');
18875 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
18876 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
18877 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
18878 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
18880 this.on('monthchange', this.onMonthChange, this);
18882 this.update(new Date().clearTime());
18885 resize : function() {
18886 var sz = this.el.getSize();
18888 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
18889 this.el.select('.fc-day-content div',true).setHeight(34);
18894 showPrevMonth : function(e){
18895 this.update(this.activeDate.add("mo", -1));
18897 showToday : function(e){
18898 this.update(new Date().clearTime());
18901 showNextMonth : function(e){
18902 this.update(this.activeDate.add("mo", 1));
18906 showPrevYear : function(){
18907 this.update(this.activeDate.add("y", -1));
18911 showNextYear : function(){
18912 this.update(this.activeDate.add("y", 1));
18917 update : function(date)
18919 var vd = this.activeDate;
18920 this.activeDate = date;
18921 // if(vd && this.el){
18922 // var t = date.getTime();
18923 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
18924 // Roo.log('using add remove');
18926 // this.fireEvent('monthchange', this, date);
18928 // this.cells.removeClass("fc-state-highlight");
18929 // this.cells.each(function(c){
18930 // if(c.dateValue == t){
18931 // c.addClass("fc-state-highlight");
18932 // setTimeout(function(){
18933 // try{c.dom.firstChild.focus();}catch(e){}
18943 var days = date.getDaysInMonth();
18945 var firstOfMonth = date.getFirstDateOfMonth();
18946 var startingPos = firstOfMonth.getDay()-this.startDay;
18948 if(startingPos < this.startDay){
18952 var pm = date.add(Date.MONTH, -1);
18953 var prevStart = pm.getDaysInMonth()-startingPos;
18955 this.cells = this.el.select('.fc-day',true);
18956 this.textNodes = this.el.query('.fc-day-number');
18957 this.cells.addClassOnOver('fc-state-hover');
18959 var cells = this.cells.elements;
18960 var textEls = this.textNodes;
18962 Roo.each(cells, function(cell){
18963 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
18966 days += startingPos;
18968 // convert everything to numbers so it's fast
18969 var day = 86400000;
18970 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
18973 //Roo.log(prevStart);
18975 var today = new Date().clearTime().getTime();
18976 var sel = date.clearTime().getTime();
18977 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
18978 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
18979 var ddMatch = this.disabledDatesRE;
18980 var ddText = this.disabledDatesText;
18981 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
18982 var ddaysText = this.disabledDaysText;
18983 var format = this.format;
18985 var setCellClass = function(cal, cell){
18989 //Roo.log('set Cell Class');
18991 var t = d.getTime();
18995 cell.dateValue = t;
18997 cell.className += " fc-today";
18998 cell.className += " fc-state-highlight";
18999 cell.title = cal.todayText;
19002 // disable highlight in other month..
19003 //cell.className += " fc-state-highlight";
19008 cell.className = " fc-state-disabled";
19009 cell.title = cal.minText;
19013 cell.className = " fc-state-disabled";
19014 cell.title = cal.maxText;
19018 if(ddays.indexOf(d.getDay()) != -1){
19019 cell.title = ddaysText;
19020 cell.className = " fc-state-disabled";
19023 if(ddMatch && format){
19024 var fvalue = d.dateFormat(format);
19025 if(ddMatch.test(fvalue)){
19026 cell.title = ddText.replace("%0", fvalue);
19027 cell.className = " fc-state-disabled";
19031 if (!cell.initialClassName) {
19032 cell.initialClassName = cell.dom.className;
19035 cell.dom.className = cell.initialClassName + ' ' + cell.className;
19040 for(; i < startingPos; i++) {
19041 textEls[i].innerHTML = (++prevStart);
19042 d.setDate(d.getDate()+1);
19044 cells[i].className = "fc-past fc-other-month";
19045 setCellClass(this, cells[i]);
19050 for(; i < days; i++){
19051 intDay = i - startingPos + 1;
19052 textEls[i].innerHTML = (intDay);
19053 d.setDate(d.getDate()+1);
19055 cells[i].className = ''; // "x-date-active";
19056 setCellClass(this, cells[i]);
19060 for(; i < 42; i++) {
19061 textEls[i].innerHTML = (++extraDays);
19062 d.setDate(d.getDate()+1);
19064 cells[i].className = "fc-future fc-other-month";
19065 setCellClass(this, cells[i]);
19068 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
19070 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
19072 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
19073 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
19075 if(totalRows != 6){
19076 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
19077 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
19080 this.fireEvent('monthchange', this, date);
19084 if(!this.internalRender){
19085 var main = this.el.dom.firstChild;
19086 var w = main.offsetWidth;
19087 this.el.setWidth(w + this.el.getBorderWidth("lr"));
19088 Roo.fly(main).setWidth(w);
19089 this.internalRender = true;
19090 // opera does not respect the auto grow header center column
19091 // then, after it gets a width opera refuses to recalculate
19092 // without a second pass
19093 if(Roo.isOpera && !this.secondPass){
19094 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
19095 this.secondPass = true;
19096 this.update.defer(10, this, [date]);
19103 findCell : function(dt) {
19104 dt = dt.clearTime().getTime();
19106 this.cells.each(function(c){
19107 //Roo.log("check " +c.dateValue + '?=' + dt);
19108 if(c.dateValue == dt){
19118 findCells : function(ev) {
19119 var s = ev.start.clone().clearTime().getTime();
19121 var e= ev.end.clone().clearTime().getTime();
19124 this.cells.each(function(c){
19125 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
19127 if(c.dateValue > e){
19130 if(c.dateValue < s){
19139 // findBestRow: function(cells)
19143 // for (var i =0 ; i < cells.length;i++) {
19144 // ret = Math.max(cells[i].rows || 0,ret);
19151 addItem : function(ev)
19153 // look for vertical location slot in
19154 var cells = this.findCells(ev);
19156 // ev.row = this.findBestRow(cells);
19158 // work out the location.
19162 for(var i =0; i < cells.length; i++) {
19164 cells[i].row = cells[0].row;
19167 cells[i].row = cells[i].row + 1;
19177 if (crow.start.getY() == cells[i].getY()) {
19179 crow.end = cells[i];
19196 cells[0].events.push(ev);
19198 this.calevents.push(ev);
19201 clearEvents: function() {
19203 if(!this.calevents){
19207 Roo.each(this.cells.elements, function(c){
19213 Roo.each(this.calevents, function(e) {
19214 Roo.each(e.els, function(el) {
19215 el.un('mouseenter' ,this.onEventEnter, this);
19216 el.un('mouseleave' ,this.onEventLeave, this);
19221 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
19227 renderEvents: function()
19231 this.cells.each(function(c) {
19240 if(c.row != c.events.length){
19241 r = 4 - (4 - (c.row - c.events.length));
19244 c.events = ev.slice(0, r);
19245 c.more = ev.slice(r);
19247 if(c.more.length && c.more.length == 1){
19248 c.events.push(c.more.pop());
19251 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
19255 this.cells.each(function(c) {
19257 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
19260 for (var e = 0; e < c.events.length; e++){
19261 var ev = c.events[e];
19262 var rows = ev.rows;
19264 for(var i = 0; i < rows.length; i++) {
19266 // how many rows should it span..
19269 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
19270 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
19272 unselectable : "on",
19275 cls: 'fc-event-inner',
19279 // cls: 'fc-event-time',
19280 // html : cells.length > 1 ? '' : ev.time
19284 cls: 'fc-event-title',
19285 html : String.format('{0}', ev.title)
19292 cls: 'ui-resizable-handle ui-resizable-e',
19293 html : '  '
19300 cfg.cls += ' fc-event-start';
19302 if ((i+1) == rows.length) {
19303 cfg.cls += ' fc-event-end';
19306 var ctr = _this.el.select('.fc-event-container',true).first();
19307 var cg = ctr.createChild(cfg);
19309 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
19310 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
19312 var r = (c.more.length) ? 1 : 0;
19313 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
19314 cg.setWidth(ebox.right - sbox.x -2);
19316 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
19317 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
19318 cg.on('click', _this.onEventClick, _this, ev);
19329 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
19330 style : 'position: absolute',
19331 unselectable : "on",
19334 cls: 'fc-event-inner',
19338 cls: 'fc-event-title',
19346 cls: 'ui-resizable-handle ui-resizable-e',
19347 html : '  '
19353 var ctr = _this.el.select('.fc-event-container',true).first();
19354 var cg = ctr.createChild(cfg);
19356 var sbox = c.select('.fc-day-content',true).first().getBox();
19357 var ebox = c.select('.fc-day-content',true).first().getBox();
19359 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
19360 cg.setWidth(ebox.right - sbox.x -2);
19362 cg.on('click', _this.onMoreEventClick, _this, c.more);
19372 onEventEnter: function (e, el,event,d) {
19373 this.fireEvent('evententer', this, el, event);
19376 onEventLeave: function (e, el,event,d) {
19377 this.fireEvent('eventleave', this, el, event);
19380 onEventClick: function (e, el,event,d) {
19381 this.fireEvent('eventclick', this, el, event);
19384 onMonthChange: function () {
19388 onMoreEventClick: function(e, el, more)
19392 this.calpopover.placement = 'right';
19393 this.calpopover.setTitle('More');
19395 this.calpopover.setContent('');
19397 var ctr = this.calpopover.el.select('.popover-content', true).first();
19399 Roo.each(more, function(m){
19401 cls : 'fc-event-hori fc-event-draggable',
19404 var cg = ctr.createChild(cfg);
19406 cg.on('click', _this.onEventClick, _this, m);
19409 this.calpopover.show(el);
19414 onLoad: function ()
19416 this.calevents = [];
19419 if(this.store.getCount() > 0){
19420 this.store.data.each(function(d){
19423 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
19424 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
19425 time : d.data.start_time,
19426 title : d.data.title,
19427 description : d.data.description,
19428 venue : d.data.venue
19433 this.renderEvents();
19435 if(this.calevents.length && this.loadMask){
19436 this.maskEl.hide();
19440 onBeforeLoad: function()
19442 this.clearEvents();
19444 this.maskEl.show();
19458 * @class Roo.bootstrap.Popover
19459 * @extends Roo.bootstrap.Component
19460 * Bootstrap Popover class
19461 * @cfg {String} html contents of the popover (or false to use children..)
19462 * @cfg {String} title of popover (or false to hide)
19463 * @cfg {String} placement how it is placed
19464 * @cfg {String} trigger click || hover (or false to trigger manually)
19465 * @cfg {String} over what (parent or false to trigger manually.)
19466 * @cfg {Number} delay - delay before showing
19469 * Create a new Popover
19470 * @param {Object} config The config object
19473 Roo.bootstrap.Popover = function(config){
19474 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
19480 * After the popover show
19482 * @param {Roo.bootstrap.Popover} this
19487 * After the popover hide
19489 * @param {Roo.bootstrap.Popover} this
19495 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
19497 title: 'Fill in a title',
19500 placement : 'right',
19501 trigger : 'hover', // hover
19507 can_build_overlaid : false,
19509 getChildContainer : function()
19511 return this.el.select('.popover-content',true).first();
19514 getAutoCreate : function(){
19517 cls : 'popover roo-dynamic',
19518 style: 'display:block',
19524 cls : 'popover-inner',
19528 cls: 'popover-title popover-header',
19532 cls : 'popover-content popover-body',
19543 setTitle: function(str)
19546 this.el.select('.popover-title',true).first().dom.innerHTML = str;
19548 setContent: function(str)
19551 this.el.select('.popover-content',true).first().dom.innerHTML = str;
19553 // as it get's added to the bottom of the page.
19554 onRender : function(ct, position)
19556 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
19558 var cfg = Roo.apply({}, this.getAutoCreate());
19562 cfg.cls += ' ' + this.cls;
19565 cfg.style = this.style;
19567 //Roo.log("adding to ");
19568 this.el = Roo.get(document.body).createChild(cfg, position);
19569 // Roo.log(this.el);
19574 initEvents : function()
19576 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
19577 this.el.enableDisplayMode('block');
19579 if (this.over === false) {
19582 if (this.triggers === false) {
19585 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
19586 var triggers = this.trigger ? this.trigger.split(' ') : [];
19587 Roo.each(triggers, function(trigger) {
19589 if (trigger == 'click') {
19590 on_el.on('click', this.toggle, this);
19591 } else if (trigger != 'manual') {
19592 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
19593 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
19595 on_el.on(eventIn ,this.enter, this);
19596 on_el.on(eventOut, this.leave, this);
19607 toggle : function () {
19608 this.hoverState == 'in' ? this.leave() : this.enter();
19611 enter : function () {
19613 clearTimeout(this.timeout);
19615 this.hoverState = 'in';
19617 if (!this.delay || !this.delay.show) {
19622 this.timeout = setTimeout(function () {
19623 if (_t.hoverState == 'in') {
19626 }, this.delay.show)
19629 leave : function() {
19630 clearTimeout(this.timeout);
19632 this.hoverState = 'out';
19634 if (!this.delay || !this.delay.hide) {
19639 this.timeout = setTimeout(function () {
19640 if (_t.hoverState == 'out') {
19643 }, this.delay.hide)
19646 show : function (on_el)
19649 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
19653 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
19654 if (this.html !== false) {
19655 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
19657 this.el.removeClass([
19658 'fade','top','bottom', 'left', 'right','in',
19659 'bs-popover-top','bs-popover-bottom', 'bs-popover-left', 'bs-popover-right'
19661 if (!this.title.length) {
19662 this.el.select('.popover-title',true).hide();
19665 var placement = typeof this.placement == 'function' ?
19666 this.placement.call(this, this.el, on_el) :
19669 var autoToken = /\s?auto?\s?/i;
19670 var autoPlace = autoToken.test(placement);
19672 placement = placement.replace(autoToken, '') || 'top';
19676 //this.el.setXY([0,0]);
19678 this.el.dom.style.display='block';
19679 this.el.addClass(placement);
19681 //this.el.appendTo(on_el);
19683 var p = this.getPosition();
19684 var box = this.el.getBox();
19689 var align = Roo.bootstrap.Popover.alignment[placement];
19692 this.el.alignTo(on_el, align[0],align[1]);
19693 //var arrow = this.el.select('.arrow',true).first();
19694 //arrow.set(align[2],
19696 this.el.addClass('in');
19699 if (this.el.hasClass('fade')) {
19703 this.hoverState = 'in';
19705 this.fireEvent('show', this);
19710 this.el.setXY([0,0]);
19711 this.el.removeClass('in');
19713 this.hoverState = null;
19715 this.fireEvent('hide', this);
19720 Roo.bootstrap.Popover.alignment = {
19721 'left' : ['r-l', [-10,0], 'right bs-popover-right'],
19722 'right' : ['l-r', [10,0], 'left bs-popover-left'],
19723 'bottom' : ['t-b', [0,10], 'top bs-popover-top'],
19724 'top' : [ 'b-t', [0,-10], 'bottom bs-popover-bottom']
19735 * @class Roo.bootstrap.Progress
19736 * @extends Roo.bootstrap.Component
19737 * Bootstrap Progress class
19738 * @cfg {Boolean} striped striped of the progress bar
19739 * @cfg {Boolean} active animated of the progress bar
19743 * Create a new Progress
19744 * @param {Object} config The config object
19747 Roo.bootstrap.Progress = function(config){
19748 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
19751 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
19756 getAutoCreate : function(){
19764 cfg.cls += ' progress-striped';
19768 cfg.cls += ' active';
19787 * @class Roo.bootstrap.ProgressBar
19788 * @extends Roo.bootstrap.Component
19789 * Bootstrap ProgressBar class
19790 * @cfg {Number} aria_valuenow aria-value now
19791 * @cfg {Number} aria_valuemin aria-value min
19792 * @cfg {Number} aria_valuemax aria-value max
19793 * @cfg {String} label label for the progress bar
19794 * @cfg {String} panel (success | info | warning | danger )
19795 * @cfg {String} role role of the progress bar
19796 * @cfg {String} sr_only text
19800 * Create a new ProgressBar
19801 * @param {Object} config The config object
19804 Roo.bootstrap.ProgressBar = function(config){
19805 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
19808 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
19812 aria_valuemax : 100,
19818 getAutoCreate : function()
19823 cls: 'progress-bar',
19824 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
19836 cfg.role = this.role;
19839 if(this.aria_valuenow){
19840 cfg['aria-valuenow'] = this.aria_valuenow;
19843 if(this.aria_valuemin){
19844 cfg['aria-valuemin'] = this.aria_valuemin;
19847 if(this.aria_valuemax){
19848 cfg['aria-valuemax'] = this.aria_valuemax;
19851 if(this.label && !this.sr_only){
19852 cfg.html = this.label;
19856 cfg.cls += ' progress-bar-' + this.panel;
19862 update : function(aria_valuenow)
19864 this.aria_valuenow = aria_valuenow;
19866 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
19881 * @class Roo.bootstrap.TabGroup
19882 * @extends Roo.bootstrap.Column
19883 * Bootstrap Column class
19884 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
19885 * @cfg {Boolean} carousel true to make the group behave like a carousel
19886 * @cfg {Boolean} bullets show bullets for the panels
19887 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
19888 * @cfg {Number} timer auto slide timer .. default 0 millisecond
19889 * @cfg {Boolean} showarrow (true|false) show arrow default true
19892 * Create a new TabGroup
19893 * @param {Object} config The config object
19896 Roo.bootstrap.TabGroup = function(config){
19897 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
19899 this.navId = Roo.id();
19902 Roo.bootstrap.TabGroup.register(this);
19906 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
19909 transition : false,
19914 slideOnTouch : false,
19917 getAutoCreate : function()
19919 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
19921 cfg.cls += ' tab-content';
19923 if (this.carousel) {
19924 cfg.cls += ' carousel slide';
19927 cls : 'carousel-inner',
19931 if(this.bullets && !Roo.isTouch){
19934 cls : 'carousel-bullets',
19938 if(this.bullets_cls){
19939 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
19946 cfg.cn[0].cn.push(bullets);
19949 if(this.showarrow){
19950 cfg.cn[0].cn.push({
19952 class : 'carousel-arrow',
19956 class : 'carousel-prev',
19960 class : 'fa fa-chevron-left'
19966 class : 'carousel-next',
19970 class : 'fa fa-chevron-right'
19983 initEvents: function()
19985 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
19986 // this.el.on("touchstart", this.onTouchStart, this);
19989 if(this.autoslide){
19992 this.slideFn = window.setInterval(function() {
19993 _this.showPanelNext();
19997 if(this.showarrow){
19998 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
19999 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
20005 // onTouchStart : function(e, el, o)
20007 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
20011 // this.showPanelNext();
20015 getChildContainer : function()
20017 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
20021 * register a Navigation item
20022 * @param {Roo.bootstrap.NavItem} the navitem to add
20024 register : function(item)
20026 this.tabs.push( item);
20027 item.navId = this.navId; // not really needed..
20032 getActivePanel : function()
20035 Roo.each(this.tabs, function(t) {
20045 getPanelByName : function(n)
20048 Roo.each(this.tabs, function(t) {
20049 if (t.tabId == n) {
20057 indexOfPanel : function(p)
20060 Roo.each(this.tabs, function(t,i) {
20061 if (t.tabId == p.tabId) {
20070 * show a specific panel
20071 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
20072 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
20074 showPanel : function (pan)
20076 if(this.transition || typeof(pan) == 'undefined'){
20077 Roo.log("waiting for the transitionend");
20081 if (typeof(pan) == 'number') {
20082 pan = this.tabs[pan];
20085 if (typeof(pan) == 'string') {
20086 pan = this.getPanelByName(pan);
20089 var cur = this.getActivePanel();
20092 Roo.log('pan or acitve pan is undefined');
20096 if (pan.tabId == this.getActivePanel().tabId) {
20100 if (false === cur.fireEvent('beforedeactivate')) {
20104 if(this.bullets > 0 && !Roo.isTouch){
20105 this.setActiveBullet(this.indexOfPanel(pan));
20108 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
20110 //class="carousel-item carousel-item-next carousel-item-left"
20112 this.transition = true;
20113 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
20114 var lr = dir == 'next' ? 'left' : 'right';
20115 pan.el.addClass(dir); // or prev
20116 pan.el.addClass('carousel-item-' + dir); // or prev
20117 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
20118 cur.el.addClass(lr); // or right
20119 pan.el.addClass(lr);
20120 cur.el.addClass('carousel-item-' +lr); // or right
20121 pan.el.addClass('carousel-item-' +lr);
20125 cur.el.on('transitionend', function() {
20126 Roo.log("trans end?");
20128 pan.el.removeClass([lr,dir, 'carousel-item-' + lr, 'carousel-item-' + dir]);
20129 pan.setActive(true);
20131 cur.el.removeClass([lr, 'carousel-item-' + lr]);
20132 cur.setActive(false);
20134 _this.transition = false;
20136 }, this, { single: true } );
20141 cur.setActive(false);
20142 pan.setActive(true);
20147 showPanelNext : function()
20149 var i = this.indexOfPanel(this.getActivePanel());
20151 if (i >= this.tabs.length - 1 && !this.autoslide) {
20155 if (i >= this.tabs.length - 1 && this.autoslide) {
20159 this.showPanel(this.tabs[i+1]);
20162 showPanelPrev : function()
20164 var i = this.indexOfPanel(this.getActivePanel());
20166 if (i < 1 && !this.autoslide) {
20170 if (i < 1 && this.autoslide) {
20171 i = this.tabs.length;
20174 this.showPanel(this.tabs[i-1]);
20178 addBullet: function()
20180 if(!this.bullets || Roo.isTouch){
20183 var ctr = this.el.select('.carousel-bullets',true).first();
20184 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
20185 var bullet = ctr.createChild({
20186 cls : 'bullet bullet-' + i
20187 },ctr.dom.lastChild);
20192 bullet.on('click', (function(e, el, o, ii, t){
20194 e.preventDefault();
20196 this.showPanel(ii);
20198 if(this.autoslide && this.slideFn){
20199 clearInterval(this.slideFn);
20200 this.slideFn = window.setInterval(function() {
20201 _this.showPanelNext();
20205 }).createDelegate(this, [i, bullet], true));
20210 setActiveBullet : function(i)
20216 Roo.each(this.el.select('.bullet', true).elements, function(el){
20217 el.removeClass('selected');
20220 var bullet = this.el.select('.bullet-' + i, true).first();
20226 bullet.addClass('selected');
20237 Roo.apply(Roo.bootstrap.TabGroup, {
20241 * register a Navigation Group
20242 * @param {Roo.bootstrap.NavGroup} the navgroup to add
20244 register : function(navgrp)
20246 this.groups[navgrp.navId] = navgrp;
20250 * fetch a Navigation Group based on the navigation ID
20251 * if one does not exist , it will get created.
20252 * @param {string} the navgroup to add
20253 * @returns {Roo.bootstrap.NavGroup} the navgroup
20255 get: function(navId) {
20256 if (typeof(this.groups[navId]) == 'undefined') {
20257 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
20259 return this.groups[navId] ;
20274 * @class Roo.bootstrap.TabPanel
20275 * @extends Roo.bootstrap.Component
20276 * Bootstrap TabPanel class
20277 * @cfg {Boolean} active panel active
20278 * @cfg {String} html panel content
20279 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
20280 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
20281 * @cfg {String} href click to link..
20282 * @cfg {Boolean} touchSlide if swiping slides tab to next panel (default off)
20286 * Create a new TabPanel
20287 * @param {Object} config The config object
20290 Roo.bootstrap.TabPanel = function(config){
20291 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
20295 * Fires when the active status changes
20296 * @param {Roo.bootstrap.TabPanel} this
20297 * @param {Boolean} state the new state
20302 * @event beforedeactivate
20303 * Fires before a tab is de-activated - can be used to do validation on a form.
20304 * @param {Roo.bootstrap.TabPanel} this
20305 * @return {Boolean} false if there is an error
20308 'beforedeactivate': true
20311 this.tabId = this.tabId || Roo.id();
20315 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
20322 touchSlide : false,
20323 getAutoCreate : function(){
20328 // item is needed for carousel - not sure if it has any effect otherwise
20329 cls: 'carousel-item tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
20330 html: this.html || ''
20334 cfg.cls += ' active';
20338 cfg.tabId = this.tabId;
20346 initEvents: function()
20348 var p = this.parent();
20350 this.navId = this.navId || p.navId;
20352 if (typeof(this.navId) != 'undefined') {
20353 // not really needed.. but just in case.. parent should be a NavGroup.
20354 var tg = Roo.bootstrap.TabGroup.get(this.navId);
20358 var i = tg.tabs.length - 1;
20360 if(this.active && tg.bullets > 0 && i < tg.bullets){
20361 tg.setActiveBullet(i);
20365 this.el.on('click', this.onClick, this);
20367 if(Roo.isTouch && this.touchSlide){
20368 this.el.on("touchstart", this.onTouchStart, this);
20369 this.el.on("touchmove", this.onTouchMove, this);
20370 this.el.on("touchend", this.onTouchEnd, this);
20375 onRender : function(ct, position)
20377 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
20380 setActive : function(state)
20382 Roo.log("panel - set active " + this.tabId + "=" + state);
20384 this.active = state;
20386 this.el.removeClass('active');
20388 } else if (!this.el.hasClass('active')) {
20389 this.el.addClass('active');
20392 this.fireEvent('changed', this, state);
20395 onClick : function(e)
20397 e.preventDefault();
20399 if(!this.href.length){
20403 window.location.href = this.href;
20412 onTouchStart : function(e)
20414 this.swiping = false;
20416 this.startX = e.browserEvent.touches[0].clientX;
20417 this.startY = e.browserEvent.touches[0].clientY;
20420 onTouchMove : function(e)
20422 this.swiping = true;
20424 this.endX = e.browserEvent.touches[0].clientX;
20425 this.endY = e.browserEvent.touches[0].clientY;
20428 onTouchEnd : function(e)
20435 var tabGroup = this.parent();
20437 if(this.endX > this.startX){ // swiping right
20438 tabGroup.showPanelPrev();
20442 if(this.startX > this.endX){ // swiping left
20443 tabGroup.showPanelNext();
20462 * @class Roo.bootstrap.DateField
20463 * @extends Roo.bootstrap.Input
20464 * Bootstrap DateField class
20465 * @cfg {Number} weekStart default 0
20466 * @cfg {String} viewMode default empty, (months|years)
20467 * @cfg {String} minViewMode default empty, (months|years)
20468 * @cfg {Number} startDate default -Infinity
20469 * @cfg {Number} endDate default Infinity
20470 * @cfg {Boolean} todayHighlight default false
20471 * @cfg {Boolean} todayBtn default false
20472 * @cfg {Boolean} calendarWeeks default false
20473 * @cfg {Object} daysOfWeekDisabled default empty
20474 * @cfg {Boolean} singleMode default false (true | false)
20476 * @cfg {Boolean} keyboardNavigation default true
20477 * @cfg {String} language default en
20480 * Create a new DateField
20481 * @param {Object} config The config object
20484 Roo.bootstrap.DateField = function(config){
20485 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
20489 * Fires when this field show.
20490 * @param {Roo.bootstrap.DateField} this
20491 * @param {Mixed} date The date value
20496 * Fires when this field hide.
20497 * @param {Roo.bootstrap.DateField} this
20498 * @param {Mixed} date The date value
20503 * Fires when select a date.
20504 * @param {Roo.bootstrap.DateField} this
20505 * @param {Mixed} date The date value
20509 * @event beforeselect
20510 * Fires when before select a date.
20511 * @param {Roo.bootstrap.DateField} this
20512 * @param {Mixed} date The date value
20514 beforeselect : true
20518 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
20521 * @cfg {String} format
20522 * The default date format string which can be overriden for localization support. The format must be
20523 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
20527 * @cfg {String} altFormats
20528 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
20529 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
20531 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
20539 todayHighlight : false,
20545 keyboardNavigation: true,
20547 calendarWeeks: false,
20549 startDate: -Infinity,
20553 daysOfWeekDisabled: [],
20557 singleMode : false,
20559 UTCDate: function()
20561 return new Date(Date.UTC.apply(Date, arguments));
20564 UTCToday: function()
20566 var today = new Date();
20567 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
20570 getDate: function() {
20571 var d = this.getUTCDate();
20572 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
20575 getUTCDate: function() {
20579 setDate: function(d) {
20580 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
20583 setUTCDate: function(d) {
20585 this.setValue(this.formatDate(this.date));
20588 onRender: function(ct, position)
20591 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
20593 this.language = this.language || 'en';
20594 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
20595 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
20597 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
20598 this.format = this.format || 'm/d/y';
20599 this.isInline = false;
20600 this.isInput = true;
20601 this.component = this.el.select('.add-on', true).first() || false;
20602 this.component = (this.component && this.component.length === 0) ? false : this.component;
20603 this.hasInput = this.component && this.inputEl().length;
20605 if (typeof(this.minViewMode === 'string')) {
20606 switch (this.minViewMode) {
20608 this.minViewMode = 1;
20611 this.minViewMode = 2;
20614 this.minViewMode = 0;
20619 if (typeof(this.viewMode === 'string')) {
20620 switch (this.viewMode) {
20633 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
20635 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
20637 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
20639 this.picker().on('mousedown', this.onMousedown, this);
20640 this.picker().on('click', this.onClick, this);
20642 this.picker().addClass('datepicker-dropdown');
20644 this.startViewMode = this.viewMode;
20646 if(this.singleMode){
20647 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
20648 v.setVisibilityMode(Roo.Element.DISPLAY);
20652 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
20653 v.setStyle('width', '189px');
20657 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
20658 if(!this.calendarWeeks){
20663 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
20664 v.attr('colspan', function(i, val){
20665 return parseInt(val) + 1;
20670 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
20672 this.setStartDate(this.startDate);
20673 this.setEndDate(this.endDate);
20675 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
20682 if(this.isInline) {
20687 picker : function()
20689 return this.pickerEl;
20690 // return this.el.select('.datepicker', true).first();
20693 fillDow: function()
20695 var dowCnt = this.weekStart;
20704 if(this.calendarWeeks){
20712 while (dowCnt < this.weekStart + 7) {
20716 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
20720 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
20723 fillMonths: function()
20726 var months = this.picker().select('>.datepicker-months td', true).first();
20728 months.dom.innerHTML = '';
20734 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
20737 months.createChild(month);
20744 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;
20746 if (this.date < this.startDate) {
20747 this.viewDate = new Date(this.startDate);
20748 } else if (this.date > this.endDate) {
20749 this.viewDate = new Date(this.endDate);
20751 this.viewDate = new Date(this.date);
20759 var d = new Date(this.viewDate),
20760 year = d.getUTCFullYear(),
20761 month = d.getUTCMonth(),
20762 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
20763 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
20764 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
20765 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
20766 currentDate = this.date && this.date.valueOf(),
20767 today = this.UTCToday();
20769 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
20771 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
20773 // this.picker.select('>tfoot th.today').
20774 // .text(dates[this.language].today)
20775 // .toggle(this.todayBtn !== false);
20777 this.updateNavArrows();
20780 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
20782 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
20784 prevMonth.setUTCDate(day);
20786 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
20788 var nextMonth = new Date(prevMonth);
20790 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
20792 nextMonth = nextMonth.valueOf();
20794 var fillMonths = false;
20796 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
20798 while(prevMonth.valueOf() <= nextMonth) {
20801 if (prevMonth.getUTCDay() === this.weekStart) {
20803 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
20811 if(this.calendarWeeks){
20812 // ISO 8601: First week contains first thursday.
20813 // ISO also states week starts on Monday, but we can be more abstract here.
20815 // Start of current week: based on weekstart/current date
20816 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
20817 // Thursday of this week
20818 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
20819 // First Thursday of year, year from thursday
20820 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
20821 // Calendar week: ms between thursdays, div ms per day, div 7 days
20822 calWeek = (th - yth) / 864e5 / 7 + 1;
20824 fillMonths.cn.push({
20832 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
20834 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
20837 if (this.todayHighlight &&
20838 prevMonth.getUTCFullYear() == today.getFullYear() &&
20839 prevMonth.getUTCMonth() == today.getMonth() &&
20840 prevMonth.getUTCDate() == today.getDate()) {
20841 clsName += ' today';
20844 if (currentDate && prevMonth.valueOf() === currentDate) {
20845 clsName += ' active';
20848 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
20849 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
20850 clsName += ' disabled';
20853 fillMonths.cn.push({
20855 cls: 'day ' + clsName,
20856 html: prevMonth.getDate()
20859 prevMonth.setDate(prevMonth.getDate()+1);
20862 var currentYear = this.date && this.date.getUTCFullYear();
20863 var currentMonth = this.date && this.date.getUTCMonth();
20865 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
20867 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
20868 v.removeClass('active');
20870 if(currentYear === year && k === currentMonth){
20871 v.addClass('active');
20874 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
20875 v.addClass('disabled');
20881 year = parseInt(year/10, 10) * 10;
20883 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
20885 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
20888 for (var i = -1; i < 11; i++) {
20889 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
20891 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
20899 showMode: function(dir)
20902 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
20905 Roo.each(this.picker().select('>div',true).elements, function(v){
20906 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
20909 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
20914 if(this.isInline) {
20918 this.picker().removeClass(['bottom', 'top']);
20920 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
20922 * place to the top of element!
20926 this.picker().addClass('top');
20927 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
20932 this.picker().addClass('bottom');
20934 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
20937 parseDate : function(value)
20939 if(!value || value instanceof Date){
20942 var v = Date.parseDate(value, this.format);
20943 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
20944 v = Date.parseDate(value, 'Y-m-d');
20946 if(!v && this.altFormats){
20947 if(!this.altFormatsArray){
20948 this.altFormatsArray = this.altFormats.split("|");
20950 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
20951 v = Date.parseDate(value, this.altFormatsArray[i]);
20957 formatDate : function(date, fmt)
20959 return (!date || !(date instanceof Date)) ?
20960 date : date.dateFormat(fmt || this.format);
20963 onFocus : function()
20965 Roo.bootstrap.DateField.superclass.onFocus.call(this);
20969 onBlur : function()
20971 Roo.bootstrap.DateField.superclass.onBlur.call(this);
20973 var d = this.inputEl().getValue();
20980 showPopup : function()
20982 this.picker().show();
20986 this.fireEvent('showpopup', this, this.date);
20989 hidePopup : function()
20991 if(this.isInline) {
20994 this.picker().hide();
20995 this.viewMode = this.startViewMode;
20998 this.fireEvent('hidepopup', this, this.date);
21002 onMousedown: function(e)
21004 e.stopPropagation();
21005 e.preventDefault();
21010 Roo.bootstrap.DateField.superclass.keyup.call(this);
21014 setValue: function(v)
21016 if(this.fireEvent('beforeselect', this, v) !== false){
21017 var d = new Date(this.parseDate(v) ).clearTime();
21019 if(isNaN(d.getTime())){
21020 this.date = this.viewDate = '';
21021 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
21025 v = this.formatDate(d);
21027 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
21029 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
21033 this.fireEvent('select', this, this.date);
21037 getValue: function()
21039 return this.formatDate(this.date);
21042 fireKey: function(e)
21044 if (!this.picker().isVisible()){
21045 if (e.keyCode == 27) { // allow escape to hide and re-show picker
21051 var dateChanged = false,
21053 newDate, newViewDate;
21058 e.preventDefault();
21062 if (!this.keyboardNavigation) {
21065 dir = e.keyCode == 37 ? -1 : 1;
21068 newDate = this.moveYear(this.date, dir);
21069 newViewDate = this.moveYear(this.viewDate, dir);
21070 } else if (e.shiftKey){
21071 newDate = this.moveMonth(this.date, dir);
21072 newViewDate = this.moveMonth(this.viewDate, dir);
21074 newDate = new Date(this.date);
21075 newDate.setUTCDate(this.date.getUTCDate() + dir);
21076 newViewDate = new Date(this.viewDate);
21077 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
21079 if (this.dateWithinRange(newDate)){
21080 this.date = newDate;
21081 this.viewDate = newViewDate;
21082 this.setValue(this.formatDate(this.date));
21084 e.preventDefault();
21085 dateChanged = true;
21090 if (!this.keyboardNavigation) {
21093 dir = e.keyCode == 38 ? -1 : 1;
21095 newDate = this.moveYear(this.date, dir);
21096 newViewDate = this.moveYear(this.viewDate, dir);
21097 } else if (e.shiftKey){
21098 newDate = this.moveMonth(this.date, dir);
21099 newViewDate = this.moveMonth(this.viewDate, dir);
21101 newDate = new Date(this.date);
21102 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
21103 newViewDate = new Date(this.viewDate);
21104 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
21106 if (this.dateWithinRange(newDate)){
21107 this.date = newDate;
21108 this.viewDate = newViewDate;
21109 this.setValue(this.formatDate(this.date));
21111 e.preventDefault();
21112 dateChanged = true;
21116 this.setValue(this.formatDate(this.date));
21118 e.preventDefault();
21121 this.setValue(this.formatDate(this.date));
21135 onClick: function(e)
21137 e.stopPropagation();
21138 e.preventDefault();
21140 var target = e.getTarget();
21142 if(target.nodeName.toLowerCase() === 'i'){
21143 target = Roo.get(target).dom.parentNode;
21146 var nodeName = target.nodeName;
21147 var className = target.className;
21148 var html = target.innerHTML;
21149 //Roo.log(nodeName);
21151 switch(nodeName.toLowerCase()) {
21153 switch(className) {
21159 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
21160 switch(this.viewMode){
21162 this.viewDate = this.moveMonth(this.viewDate, dir);
21166 this.viewDate = this.moveYear(this.viewDate, dir);
21172 var date = new Date();
21173 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
21175 this.setValue(this.formatDate(this.date));
21182 if (className.indexOf('disabled') < 0) {
21183 this.viewDate.setUTCDate(1);
21184 if (className.indexOf('month') > -1) {
21185 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
21187 var year = parseInt(html, 10) || 0;
21188 this.viewDate.setUTCFullYear(year);
21192 if(this.singleMode){
21193 this.setValue(this.formatDate(this.viewDate));
21204 //Roo.log(className);
21205 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
21206 var day = parseInt(html, 10) || 1;
21207 var year = this.viewDate.getUTCFullYear(),
21208 month = this.viewDate.getUTCMonth();
21210 if (className.indexOf('old') > -1) {
21217 } else if (className.indexOf('new') > -1) {
21225 //Roo.log([year,month,day]);
21226 this.date = this.UTCDate(year, month, day,0,0,0,0);
21227 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
21229 //Roo.log(this.formatDate(this.date));
21230 this.setValue(this.formatDate(this.date));
21237 setStartDate: function(startDate)
21239 this.startDate = startDate || -Infinity;
21240 if (this.startDate !== -Infinity) {
21241 this.startDate = this.parseDate(this.startDate);
21244 this.updateNavArrows();
21247 setEndDate: function(endDate)
21249 this.endDate = endDate || Infinity;
21250 if (this.endDate !== Infinity) {
21251 this.endDate = this.parseDate(this.endDate);
21254 this.updateNavArrows();
21257 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
21259 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
21260 if (typeof(this.daysOfWeekDisabled) !== 'object') {
21261 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
21263 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
21264 return parseInt(d, 10);
21267 this.updateNavArrows();
21270 updateNavArrows: function()
21272 if(this.singleMode){
21276 var d = new Date(this.viewDate),
21277 year = d.getUTCFullYear(),
21278 month = d.getUTCMonth();
21280 Roo.each(this.picker().select('.prev', true).elements, function(v){
21282 switch (this.viewMode) {
21285 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
21291 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
21298 Roo.each(this.picker().select('.next', true).elements, function(v){
21300 switch (this.viewMode) {
21303 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
21309 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
21317 moveMonth: function(date, dir)
21322 var new_date = new Date(date.valueOf()),
21323 day = new_date.getUTCDate(),
21324 month = new_date.getUTCMonth(),
21325 mag = Math.abs(dir),
21327 dir = dir > 0 ? 1 : -1;
21330 // If going back one month, make sure month is not current month
21331 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
21333 return new_date.getUTCMonth() == month;
21335 // If going forward one month, make sure month is as expected
21336 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
21338 return new_date.getUTCMonth() != new_month;
21340 new_month = month + dir;
21341 new_date.setUTCMonth(new_month);
21342 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
21343 if (new_month < 0 || new_month > 11) {
21344 new_month = (new_month + 12) % 12;
21347 // For magnitudes >1, move one month at a time...
21348 for (var i=0; i<mag; i++) {
21349 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
21350 new_date = this.moveMonth(new_date, dir);
21352 // ...then reset the day, keeping it in the new month
21353 new_month = new_date.getUTCMonth();
21354 new_date.setUTCDate(day);
21356 return new_month != new_date.getUTCMonth();
21359 // Common date-resetting loop -- if date is beyond end of month, make it
21362 new_date.setUTCDate(--day);
21363 new_date.setUTCMonth(new_month);
21368 moveYear: function(date, dir)
21370 return this.moveMonth(date, dir*12);
21373 dateWithinRange: function(date)
21375 return date >= this.startDate && date <= this.endDate;
21381 this.picker().remove();
21384 validateValue : function(value)
21386 if(this.getVisibilityEl().hasClass('hidden')){
21390 if(value.length < 1) {
21391 if(this.allowBlank){
21397 if(value.length < this.minLength){
21400 if(value.length > this.maxLength){
21404 var vt = Roo.form.VTypes;
21405 if(!vt[this.vtype](value, this)){
21409 if(typeof this.validator == "function"){
21410 var msg = this.validator(value);
21416 if(this.regex && !this.regex.test(value)){
21420 if(typeof(this.parseDate(value)) == 'undefined'){
21424 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
21428 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
21438 this.date = this.viewDate = '';
21440 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
21445 Roo.apply(Roo.bootstrap.DateField, {
21456 html: '<i class="fa fa-arrow-left"/>'
21466 html: '<i class="fa fa-arrow-right"/>'
21508 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
21509 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
21510 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
21511 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
21512 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
21525 navFnc: 'FullYear',
21530 navFnc: 'FullYear',
21535 Roo.apply(Roo.bootstrap.DateField, {
21539 cls: 'datepicker dropdown-menu roo-dynamic',
21543 cls: 'datepicker-days',
21547 cls: 'table-condensed',
21549 Roo.bootstrap.DateField.head,
21553 Roo.bootstrap.DateField.footer
21560 cls: 'datepicker-months',
21564 cls: 'table-condensed',
21566 Roo.bootstrap.DateField.head,
21567 Roo.bootstrap.DateField.content,
21568 Roo.bootstrap.DateField.footer
21575 cls: 'datepicker-years',
21579 cls: 'table-condensed',
21581 Roo.bootstrap.DateField.head,
21582 Roo.bootstrap.DateField.content,
21583 Roo.bootstrap.DateField.footer
21602 * @class Roo.bootstrap.TimeField
21603 * @extends Roo.bootstrap.Input
21604 * Bootstrap DateField class
21608 * Create a new TimeField
21609 * @param {Object} config The config object
21612 Roo.bootstrap.TimeField = function(config){
21613 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
21617 * Fires when this field show.
21618 * @param {Roo.bootstrap.DateField} thisthis
21619 * @param {Mixed} date The date value
21624 * Fires when this field hide.
21625 * @param {Roo.bootstrap.DateField} this
21626 * @param {Mixed} date The date value
21631 * Fires when select a date.
21632 * @param {Roo.bootstrap.DateField} this
21633 * @param {Mixed} date The date value
21639 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
21642 * @cfg {String} format
21643 * The default time format string which can be overriden for localization support. The format must be
21644 * valid according to {@link Date#parseDate} (defaults to 'H:i').
21648 onRender: function(ct, position)
21651 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
21653 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
21655 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
21657 this.pop = this.picker().select('>.datepicker-time',true).first();
21658 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
21660 this.picker().on('mousedown', this.onMousedown, this);
21661 this.picker().on('click', this.onClick, this);
21663 this.picker().addClass('datepicker-dropdown');
21668 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
21669 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
21670 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
21671 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
21672 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
21673 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
21677 fireKey: function(e){
21678 if (!this.picker().isVisible()){
21679 if (e.keyCode == 27) { // allow escape to hide and re-show picker
21685 e.preventDefault();
21693 this.onTogglePeriod();
21696 this.onIncrementMinutes();
21699 this.onDecrementMinutes();
21708 onClick: function(e) {
21709 e.stopPropagation();
21710 e.preventDefault();
21713 picker : function()
21715 return this.el.select('.datepicker', true).first();
21718 fillTime: function()
21720 var time = this.pop.select('tbody', true).first();
21722 time.dom.innerHTML = '';
21737 cls: 'hours-up glyphicon glyphicon-chevron-up'
21757 cls: 'minutes-up glyphicon glyphicon-chevron-up'
21778 cls: 'timepicker-hour',
21793 cls: 'timepicker-minute',
21808 cls: 'btn btn-primary period',
21830 cls: 'hours-down glyphicon glyphicon-chevron-down'
21850 cls: 'minutes-down glyphicon glyphicon-chevron-down'
21868 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
21875 var hours = this.time.getHours();
21876 var minutes = this.time.getMinutes();
21889 hours = hours - 12;
21893 hours = '0' + hours;
21897 minutes = '0' + minutes;
21900 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
21901 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
21902 this.pop.select('button', true).first().dom.innerHTML = period;
21908 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
21910 var cls = ['bottom'];
21912 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
21919 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
21924 this.picker().addClass(cls.join('-'));
21928 Roo.each(cls, function(c){
21930 _this.picker().setTop(_this.inputEl().getHeight());
21934 _this.picker().setTop(0 - _this.picker().getHeight());
21939 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
21943 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
21950 onFocus : function()
21952 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
21956 onBlur : function()
21958 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
21964 this.picker().show();
21969 this.fireEvent('show', this, this.date);
21974 this.picker().hide();
21977 this.fireEvent('hide', this, this.date);
21980 setTime : function()
21983 this.setValue(this.time.format(this.format));
21985 this.fireEvent('select', this, this.date);
21990 onMousedown: function(e){
21991 e.stopPropagation();
21992 e.preventDefault();
21995 onIncrementHours: function()
21997 Roo.log('onIncrementHours');
21998 this.time = this.time.add(Date.HOUR, 1);
22003 onDecrementHours: function()
22005 Roo.log('onDecrementHours');
22006 this.time = this.time.add(Date.HOUR, -1);
22010 onIncrementMinutes: function()
22012 Roo.log('onIncrementMinutes');
22013 this.time = this.time.add(Date.MINUTE, 1);
22017 onDecrementMinutes: function()
22019 Roo.log('onDecrementMinutes');
22020 this.time = this.time.add(Date.MINUTE, -1);
22024 onTogglePeriod: function()
22026 Roo.log('onTogglePeriod');
22027 this.time = this.time.add(Date.HOUR, 12);
22034 Roo.apply(Roo.bootstrap.TimeField, {
22064 cls: 'btn btn-info ok',
22076 Roo.apply(Roo.bootstrap.TimeField, {
22080 cls: 'datepicker dropdown-menu',
22084 cls: 'datepicker-time',
22088 cls: 'table-condensed',
22090 Roo.bootstrap.TimeField.content,
22091 Roo.bootstrap.TimeField.footer
22110 * @class Roo.bootstrap.MonthField
22111 * @extends Roo.bootstrap.Input
22112 * Bootstrap MonthField class
22114 * @cfg {String} language default en
22117 * Create a new MonthField
22118 * @param {Object} config The config object
22121 Roo.bootstrap.MonthField = function(config){
22122 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
22127 * Fires when this field show.
22128 * @param {Roo.bootstrap.MonthField} this
22129 * @param {Mixed} date The date value
22134 * Fires when this field hide.
22135 * @param {Roo.bootstrap.MonthField} this
22136 * @param {Mixed} date The date value
22141 * Fires when select a date.
22142 * @param {Roo.bootstrap.MonthField} this
22143 * @param {String} oldvalue The old value
22144 * @param {String} newvalue The new value
22150 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
22152 onRender: function(ct, position)
22155 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
22157 this.language = this.language || 'en';
22158 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
22159 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
22161 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
22162 this.isInline = false;
22163 this.isInput = true;
22164 this.component = this.el.select('.add-on', true).first() || false;
22165 this.component = (this.component && this.component.length === 0) ? false : this.component;
22166 this.hasInput = this.component && this.inputEL().length;
22168 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
22170 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
22172 this.picker().on('mousedown', this.onMousedown, this);
22173 this.picker().on('click', this.onClick, this);
22175 this.picker().addClass('datepicker-dropdown');
22177 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
22178 v.setStyle('width', '189px');
22185 if(this.isInline) {
22191 setValue: function(v, suppressEvent)
22193 var o = this.getValue();
22195 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
22199 if(suppressEvent !== true){
22200 this.fireEvent('select', this, o, v);
22205 getValue: function()
22210 onClick: function(e)
22212 e.stopPropagation();
22213 e.preventDefault();
22215 var target = e.getTarget();
22217 if(target.nodeName.toLowerCase() === 'i'){
22218 target = Roo.get(target).dom.parentNode;
22221 var nodeName = target.nodeName;
22222 var className = target.className;
22223 var html = target.innerHTML;
22225 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
22229 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
22231 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
22237 picker : function()
22239 return this.pickerEl;
22242 fillMonths: function()
22245 var months = this.picker().select('>.datepicker-months td', true).first();
22247 months.dom.innerHTML = '';
22253 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
22256 months.createChild(month);
22265 if(typeof(this.vIndex) == 'undefined' && this.value.length){
22266 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
22269 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
22270 e.removeClass('active');
22272 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
22273 e.addClass('active');
22280 if(this.isInline) {
22284 this.picker().removeClass(['bottom', 'top']);
22286 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
22288 * place to the top of element!
22292 this.picker().addClass('top');
22293 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
22298 this.picker().addClass('bottom');
22300 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
22303 onFocus : function()
22305 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
22309 onBlur : function()
22311 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
22313 var d = this.inputEl().getValue();
22322 this.picker().show();
22323 this.picker().select('>.datepicker-months', true).first().show();
22327 this.fireEvent('show', this, this.date);
22332 if(this.isInline) {
22335 this.picker().hide();
22336 this.fireEvent('hide', this, this.date);
22340 onMousedown: function(e)
22342 e.stopPropagation();
22343 e.preventDefault();
22348 Roo.bootstrap.MonthField.superclass.keyup.call(this);
22352 fireKey: function(e)
22354 if (!this.picker().isVisible()){
22355 if (e.keyCode == 27) {// allow escape to hide and re-show picker
22366 e.preventDefault();
22370 dir = e.keyCode == 37 ? -1 : 1;
22372 this.vIndex = this.vIndex + dir;
22374 if(this.vIndex < 0){
22378 if(this.vIndex > 11){
22382 if(isNaN(this.vIndex)){
22386 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
22392 dir = e.keyCode == 38 ? -1 : 1;
22394 this.vIndex = this.vIndex + dir * 4;
22396 if(this.vIndex < 0){
22400 if(this.vIndex > 11){
22404 if(isNaN(this.vIndex)){
22408 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
22413 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
22414 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
22418 e.preventDefault();
22421 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
22422 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
22438 this.picker().remove();
22443 Roo.apply(Roo.bootstrap.MonthField, {
22462 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
22463 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
22468 Roo.apply(Roo.bootstrap.MonthField, {
22472 cls: 'datepicker dropdown-menu roo-dynamic',
22476 cls: 'datepicker-months',
22480 cls: 'table-condensed',
22482 Roo.bootstrap.DateField.content
22502 * @class Roo.bootstrap.CheckBox
22503 * @extends Roo.bootstrap.Input
22504 * Bootstrap CheckBox class
22506 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
22507 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
22508 * @cfg {String} boxLabel The text that appears beside the checkbox
22509 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
22510 * @cfg {Boolean} checked initnal the element
22511 * @cfg {Boolean} inline inline the element (default false)
22512 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
22513 * @cfg {String} tooltip label tooltip
22516 * Create a new CheckBox
22517 * @param {Object} config The config object
22520 Roo.bootstrap.CheckBox = function(config){
22521 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
22526 * Fires when the element is checked or unchecked.
22527 * @param {Roo.bootstrap.CheckBox} this This input
22528 * @param {Boolean} checked The new checked value
22533 * Fires when the element is click.
22534 * @param {Roo.bootstrap.CheckBox} this This input
22541 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
22543 inputType: 'checkbox',
22552 // checkbox success does not make any sense really..
22557 getAutoCreate : function()
22559 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
22565 cfg.cls = 'form-group form-check ' + this.inputType; //input-group
22568 cfg.cls += ' ' + this.inputType + '-inline form-check-inline';
22574 type : this.inputType,
22575 value : this.inputValue,
22576 cls : 'roo-' + this.inputType, //'form-box',
22577 placeholder : this.placeholder || ''
22581 if(this.inputType != 'radio'){
22585 cls : 'roo-hidden-value',
22586 value : this.checked ? this.inputValue : this.valueOff
22591 if (this.weight) { // Validity check?
22592 cfg.cls += " " + this.inputType + "-" + this.weight;
22595 if (this.disabled) {
22596 input.disabled=true;
22600 input.checked = this.checked;
22605 input.name = this.name;
22607 if(this.inputType != 'radio'){
22608 hidden.name = this.name;
22609 input.name = '_hidden_' + this.name;
22614 input.cls += ' input-' + this.size;
22619 ['xs','sm','md','lg'].map(function(size){
22620 if (settings[size]) {
22621 cfg.cls += ' col-' + size + '-' + settings[size];
22625 var inputblock = input;
22627 if (this.before || this.after) {
22630 cls : 'input-group',
22635 inputblock.cn.push({
22637 cls : 'input-group-addon',
22642 inputblock.cn.push(input);
22644 if(this.inputType != 'radio'){
22645 inputblock.cn.push(hidden);
22649 inputblock.cn.push({
22651 cls : 'input-group-addon',
22657 var boxLabelCfg = false;
22663 //'for': id, // box label is handled by onclick - so no for...
22665 html: this.boxLabel
22668 boxLabelCfg.tooltip = this.tooltip;
22674 if (align ==='left' && this.fieldLabel.length) {
22675 // Roo.log("left and has label");
22680 cls : 'control-label',
22681 html : this.fieldLabel
22692 cfg.cn[1].cn.push(boxLabelCfg);
22695 if(this.labelWidth > 12){
22696 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
22699 if(this.labelWidth < 13 && this.labelmd == 0){
22700 this.labelmd = this.labelWidth;
22703 if(this.labellg > 0){
22704 cfg.cn[0].cls += ' col-lg-' + this.labellg;
22705 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
22708 if(this.labelmd > 0){
22709 cfg.cn[0].cls += ' col-md-' + this.labelmd;
22710 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
22713 if(this.labelsm > 0){
22714 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
22715 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
22718 if(this.labelxs > 0){
22719 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
22720 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
22723 } else if ( this.fieldLabel.length) {
22724 // Roo.log(" label");
22728 tag: this.boxLabel ? 'span' : 'label',
22730 cls: 'control-label box-input-label',
22731 //cls : 'input-group-addon',
22732 html : this.fieldLabel
22739 cfg.cn.push(boxLabelCfg);
22744 // Roo.log(" no label && no align");
22745 cfg.cn = [ inputblock ] ;
22747 cfg.cn.push(boxLabelCfg);
22755 if(this.inputType != 'radio'){
22756 cfg.cn.push(hidden);
22764 * return the real input element.
22766 inputEl: function ()
22768 return this.el.select('input.roo-' + this.inputType,true).first();
22770 hiddenEl: function ()
22772 return this.el.select('input.roo-hidden-value',true).first();
22775 labelEl: function()
22777 return this.el.select('label.control-label',true).first();
22779 /* depricated... */
22783 return this.labelEl();
22786 boxLabelEl: function()
22788 return this.el.select('label.box-label',true).first();
22791 initEvents : function()
22793 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
22795 this.inputEl().on('click', this.onClick, this);
22797 if (this.boxLabel) {
22798 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
22801 this.startValue = this.getValue();
22804 Roo.bootstrap.CheckBox.register(this);
22808 onClick : function(e)
22810 if(this.fireEvent('click', this, e) !== false){
22811 this.setChecked(!this.checked);
22816 setChecked : function(state,suppressEvent)
22818 this.startValue = this.getValue();
22820 if(this.inputType == 'radio'){
22822 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
22823 e.dom.checked = false;
22826 this.inputEl().dom.checked = true;
22828 this.inputEl().dom.value = this.inputValue;
22830 if(suppressEvent !== true){
22831 this.fireEvent('check', this, true);
22839 this.checked = state;
22841 this.inputEl().dom.checked = state;
22844 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
22846 if(suppressEvent !== true){
22847 this.fireEvent('check', this, state);
22853 getValue : function()
22855 if(this.inputType == 'radio'){
22856 return this.getGroupValue();
22859 return this.hiddenEl().dom.value;
22863 getGroupValue : function()
22865 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
22869 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
22872 setValue : function(v,suppressEvent)
22874 if(this.inputType == 'radio'){
22875 this.setGroupValue(v, suppressEvent);
22879 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
22884 setGroupValue : function(v, suppressEvent)
22886 this.startValue = this.getValue();
22888 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
22889 e.dom.checked = false;
22891 if(e.dom.value == v){
22892 e.dom.checked = true;
22896 if(suppressEvent !== true){
22897 this.fireEvent('check', this, true);
22905 validate : function()
22907 if(this.getVisibilityEl().hasClass('hidden')){
22913 (this.inputType == 'radio' && this.validateRadio()) ||
22914 (this.inputType == 'checkbox' && this.validateCheckbox())
22920 this.markInvalid();
22924 validateRadio : function()
22926 if(this.getVisibilityEl().hasClass('hidden')){
22930 if(this.allowBlank){
22936 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
22937 if(!e.dom.checked){
22949 validateCheckbox : function()
22952 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
22953 //return (this.getValue() == this.inputValue) ? true : false;
22956 var group = Roo.bootstrap.CheckBox.get(this.groupId);
22964 for(var i in group){
22965 if(group[i].el.isVisible(true)){
22973 for(var i in group){
22978 r = (group[i].getValue() == group[i].inputValue) ? true : false;
22985 * Mark this field as valid
22987 markValid : function()
22991 this.fireEvent('valid', this);
22993 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
22996 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
23003 if(this.inputType == 'radio'){
23004 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
23005 var fg = e.findParent('.form-group', false, true);
23006 if (Roo.bootstrap.version == 3) {
23007 fg.removeClass([_this.invalidClass, _this.validClass]);
23008 fg.addClass(_this.validClass);
23010 fg.removeClass(['is-valid', 'is-invalid']);
23011 fg.addClass('is-valid');
23019 var fg = this.el.findParent('.form-group', false, true);
23020 if (Roo.bootstrap.version == 3) {
23021 fg.removeClass([this.invalidClass, this.validClass]);
23022 fg.addClass(this.validClass);
23024 fg.removeClass(['is-valid', 'is-invalid']);
23025 fg.addClass('is-valid');
23030 var group = Roo.bootstrap.CheckBox.get(this.groupId);
23036 for(var i in group){
23037 var fg = group[i].el.findParent('.form-group', false, true);
23038 if (Roo.bootstrap.version == 3) {
23039 fg.removeClass([this.invalidClass, this.validClass]);
23040 fg.addClass(this.validClass);
23042 fg.removeClass(['is-valid', 'is-invalid']);
23043 fg.addClass('is-valid');
23049 * Mark this field as invalid
23050 * @param {String} msg The validation message
23052 markInvalid : function(msg)
23054 if(this.allowBlank){
23060 this.fireEvent('invalid', this, msg);
23062 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
23065 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
23069 label.markInvalid();
23072 if(this.inputType == 'radio'){
23074 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
23075 var fg = e.findParent('.form-group', false, true);
23076 if (Roo.bootstrap.version == 3) {
23077 fg.removeClass([_this.invalidClass, _this.validClass]);
23078 fg.addClass(_this.invalidClass);
23080 fg.removeClass(['is-invalid', 'is-valid']);
23081 fg.addClass('is-invalid');
23089 var fg = this.el.findParent('.form-group', false, true);
23090 if (Roo.bootstrap.version == 3) {
23091 fg.removeClass([_this.invalidClass, _this.validClass]);
23092 fg.addClass(_this.invalidClass);
23094 fg.removeClass(['is-invalid', 'is-valid']);
23095 fg.addClass('is-invalid');
23100 var group = Roo.bootstrap.CheckBox.get(this.groupId);
23106 for(var i in group){
23107 var fg = group[i].el.findParent('.form-group', false, true);
23108 if (Roo.bootstrap.version == 3) {
23109 fg.removeClass([_this.invalidClass, _this.validClass]);
23110 fg.addClass(_this.invalidClass);
23112 fg.removeClass(['is-invalid', 'is-valid']);
23113 fg.addClass('is-invalid');
23119 clearInvalid : function()
23121 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
23123 // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
23125 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
23127 if (label && label.iconEl) {
23128 label.iconEl.removeClass([ label.validClass, label.invalidClass ]);
23129 label.iconEl.removeClass(['is-invalid', 'is-valid']);
23133 disable : function()
23135 if(this.inputType != 'radio'){
23136 Roo.bootstrap.CheckBox.superclass.disable.call(this);
23143 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
23144 _this.getActionEl().addClass(this.disabledClass);
23145 e.dom.disabled = true;
23149 this.disabled = true;
23150 this.fireEvent("disable", this);
23154 enable : function()
23156 if(this.inputType != 'radio'){
23157 Roo.bootstrap.CheckBox.superclass.enable.call(this);
23164 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
23165 _this.getActionEl().removeClass(this.disabledClass);
23166 e.dom.disabled = false;
23170 this.disabled = false;
23171 this.fireEvent("enable", this);
23175 setBoxLabel : function(v)
23180 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
23186 Roo.apply(Roo.bootstrap.CheckBox, {
23191 * register a CheckBox Group
23192 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
23194 register : function(checkbox)
23196 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
23197 this.groups[checkbox.groupId] = {};
23200 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
23204 this.groups[checkbox.groupId][checkbox.name] = checkbox;
23208 * fetch a CheckBox Group based on the group ID
23209 * @param {string} the group ID
23210 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
23212 get: function(groupId) {
23213 if (typeof(this.groups[groupId]) == 'undefined') {
23217 return this.groups[groupId] ;
23230 * @class Roo.bootstrap.Radio
23231 * @extends Roo.bootstrap.Component
23232 * Bootstrap Radio class
23233 * @cfg {String} boxLabel - the label associated
23234 * @cfg {String} value - the value of radio
23237 * Create a new Radio
23238 * @param {Object} config The config object
23240 Roo.bootstrap.Radio = function(config){
23241 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
23245 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
23251 getAutoCreate : function()
23255 cls : 'form-group radio',
23260 html : this.boxLabel
23268 initEvents : function()
23270 this.parent().register(this);
23272 this.el.on('click', this.onClick, this);
23276 onClick : function(e)
23278 if(this.parent().fireEvent('click', this.parent(), this, e) !== false){
23279 this.setChecked(true);
23283 setChecked : function(state, suppressEvent)
23285 this.parent().setValue(this.value, suppressEvent);
23289 setBoxLabel : function(v)
23294 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
23309 * @class Roo.bootstrap.SecurePass
23310 * @extends Roo.bootstrap.Input
23311 * Bootstrap SecurePass class
23315 * Create a new SecurePass
23316 * @param {Object} config The config object
23319 Roo.bootstrap.SecurePass = function (config) {
23320 // these go here, so the translation tool can replace them..
23322 PwdEmpty: "Please type a password, and then retype it to confirm.",
23323 PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
23324 PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
23325 PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
23326 IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
23327 FNInPwd: "Your password can't contain your first name. Please type a different password.",
23328 LNInPwd: "Your password can't contain your last name. Please type a different password.",
23329 TooWeak: "Your password is Too Weak."
23331 this.meterLabel = "Password strength:";
23332 this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
23333 this.meterClass = [
23334 "roo-password-meter-tooweak",
23335 "roo-password-meter-weak",
23336 "roo-password-meter-medium",
23337 "roo-password-meter-strong",
23338 "roo-password-meter-grey"
23343 Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
23346 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
23348 * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
23350 * PwdEmpty: "Please type a password, and then retype it to confirm.",
23351 * PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
23352 * PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
23353 * PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
23354 * IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
23355 * FNInPwd: "Your password can't contain your first name. Please type a different password.",
23356 * LNInPwd: "Your password can't contain your last name. Please type a different password."
23366 * @cfg {String/Object} Label for the strength meter (defaults to
23367 * 'Password strength:')
23372 * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
23373 * ['Weak', 'Medium', 'Strong'])
23376 pwdStrengths: false,
23389 initEvents: function ()
23391 Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
23393 if (this.el.is('input[type=password]') && Roo.isSafari) {
23394 this.el.on('keydown', this.SafariOnKeyDown, this);
23397 this.el.on('keyup', this.checkStrength, this, {buffer: 50});
23400 onRender: function (ct, position)
23402 Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
23403 this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
23404 this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
23406 this.trigger.createChild({
23411 cls: 'roo-password-meter-grey col-xs-12',
23414 //width: this.meterWidth + 'px'
23418 cls: 'roo-password-meter-text'
23424 if (this.hideTrigger) {
23425 this.trigger.setDisplayed(false);
23427 this.setSize(this.width || '', this.height || '');
23430 onDestroy: function ()
23432 if (this.trigger) {
23433 this.trigger.removeAllListeners();
23434 this.trigger.remove();
23437 this.wrap.remove();
23439 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
23442 checkStrength: function ()
23444 var pwd = this.inputEl().getValue();
23445 if (pwd == this._lastPwd) {
23450 if (this.ClientSideStrongPassword(pwd)) {
23452 } else if (this.ClientSideMediumPassword(pwd)) {
23454 } else if (this.ClientSideWeakPassword(pwd)) {
23460 Roo.log('strength1: ' + strength);
23462 //var pm = this.trigger.child('div/div/div').dom;
23463 var pm = this.trigger.child('div/div');
23464 pm.removeClass(this.meterClass);
23465 pm.addClass(this.meterClass[strength]);
23468 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
23470 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
23472 this._lastPwd = pwd;
23476 Roo.bootstrap.SecurePass.superclass.reset.call(this);
23478 this._lastPwd = '';
23480 var pm = this.trigger.child('div/div');
23481 pm.removeClass(this.meterClass);
23482 pm.addClass('roo-password-meter-grey');
23485 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
23488 this.inputEl().dom.type='password';
23491 validateValue: function (value)
23493 if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
23496 if (value.length == 0) {
23497 if (this.allowBlank) {
23498 this.clearInvalid();
23502 this.markInvalid(this.errors.PwdEmpty);
23503 this.errorMsg = this.errors.PwdEmpty;
23511 if (!value.match(/[\x21-\x7e]+/)) {
23512 this.markInvalid(this.errors.PwdBadChar);
23513 this.errorMsg = this.errors.PwdBadChar;
23516 if (value.length < 6) {
23517 this.markInvalid(this.errors.PwdShort);
23518 this.errorMsg = this.errors.PwdShort;
23521 if (value.length > 16) {
23522 this.markInvalid(this.errors.PwdLong);
23523 this.errorMsg = this.errors.PwdLong;
23527 if (this.ClientSideStrongPassword(value)) {
23529 } else if (this.ClientSideMediumPassword(value)) {
23531 } else if (this.ClientSideWeakPassword(value)) {
23538 if (strength < 2) {
23539 //this.markInvalid(this.errors.TooWeak);
23540 this.errorMsg = this.errors.TooWeak;
23545 console.log('strength2: ' + strength);
23547 //var pm = this.trigger.child('div/div/div').dom;
23549 var pm = this.trigger.child('div/div');
23550 pm.removeClass(this.meterClass);
23551 pm.addClass(this.meterClass[strength]);
23553 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
23555 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
23557 this.errorMsg = '';
23561 CharacterSetChecks: function (type)
23564 this.fResult = false;
23567 isctype: function (character, type)
23570 case this.kCapitalLetter:
23571 if (character >= 'A' && character <= 'Z') {
23576 case this.kSmallLetter:
23577 if (character >= 'a' && character <= 'z') {
23583 if (character >= '0' && character <= '9') {
23588 case this.kPunctuation:
23589 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
23600 IsLongEnough: function (pwd, size)
23602 return !(pwd == null || isNaN(size) || pwd.length < size);
23605 SpansEnoughCharacterSets: function (word, nb)
23607 if (!this.IsLongEnough(word, nb))
23612 var characterSetChecks = new Array(
23613 new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
23614 new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
23617 for (var index = 0; index < word.length; ++index) {
23618 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
23619 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
23620 characterSetChecks[nCharSet].fResult = true;
23627 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
23628 if (characterSetChecks[nCharSet].fResult) {
23633 if (nCharSets < nb) {
23639 ClientSideStrongPassword: function (pwd)
23641 return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
23644 ClientSideMediumPassword: function (pwd)
23646 return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
23649 ClientSideWeakPassword: function (pwd)
23651 return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
23654 })//<script type="text/javascript">
23657 * Based Ext JS Library 1.1.1
23658 * Copyright(c) 2006-2007, Ext JS, LLC.
23664 * @class Roo.HtmlEditorCore
23665 * @extends Roo.Component
23666 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
23668 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
23671 Roo.HtmlEditorCore = function(config){
23674 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
23679 * @event initialize
23680 * Fires when the editor is fully initialized (including the iframe)
23681 * @param {Roo.HtmlEditorCore} this
23686 * Fires when the editor is first receives the focus. Any insertion must wait
23687 * until after this event.
23688 * @param {Roo.HtmlEditorCore} this
23692 * @event beforesync
23693 * Fires before the textarea is updated with content from the editor iframe. Return false
23694 * to cancel the sync.
23695 * @param {Roo.HtmlEditorCore} this
23696 * @param {String} html
23700 * @event beforepush
23701 * Fires before the iframe editor is updated with content from the textarea. Return false
23702 * to cancel the push.
23703 * @param {Roo.HtmlEditorCore} this
23704 * @param {String} html
23709 * Fires when the textarea is updated with content from the editor iframe.
23710 * @param {Roo.HtmlEditorCore} this
23711 * @param {String} html
23716 * Fires when the iframe editor is updated with content from the textarea.
23717 * @param {Roo.HtmlEditorCore} this
23718 * @param {String} html
23723 * @event editorevent
23724 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
23725 * @param {Roo.HtmlEditorCore} this
23731 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
23733 // defaults : white / black...
23734 this.applyBlacklists();
23741 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
23745 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
23751 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
23756 * @cfg {Number} height (in pixels)
23760 * @cfg {Number} width (in pixels)
23765 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
23768 stylesheets: false,
23773 // private properties
23774 validationEvent : false,
23776 initialized : false,
23778 sourceEditMode : false,
23779 onFocus : Roo.emptyFn,
23781 hideMode:'offsets',
23785 // blacklist + whitelisted elements..
23792 * Protected method that will not generally be called directly. It
23793 * is called when the editor initializes the iframe with HTML contents. Override this method if you
23794 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
23796 getDocMarkup : function(){
23800 // inherit styels from page...??
23801 if (this.stylesheets === false) {
23803 Roo.get(document.head).select('style').each(function(node) {
23804 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
23807 Roo.get(document.head).select('link').each(function(node) {
23808 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
23811 } else if (!this.stylesheets.length) {
23813 st = '<style type="text/css">' +
23814 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
23817 for (var i in this.stylesheets) {
23818 st += '<link rel="stylesheet" href="' + this.stylesheets[i] +'" type="text/css">';
23823 st += '<style type="text/css">' +
23824 'IMG { cursor: pointer } ' +
23827 var cls = 'roo-htmleditor-body';
23829 if(this.bodyCls.length){
23830 cls += ' ' + this.bodyCls;
23833 return '<html><head>' + st +
23834 //<style type="text/css">' +
23835 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
23837 ' </head><body contenteditable="true" data-enable-grammerly="true" class="' + cls + '"></body></html>';
23841 onRender : function(ct, position)
23844 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
23845 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
23848 this.el.dom.style.border = '0 none';
23849 this.el.dom.setAttribute('tabIndex', -1);
23850 this.el.addClass('x-hidden hide');
23854 if(Roo.isIE){ // fix IE 1px bogus margin
23855 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
23859 this.frameId = Roo.id();
23863 var iframe = this.owner.wrap.createChild({
23865 cls: 'form-control', // bootstrap..
23867 name: this.frameId,
23868 frameBorder : 'no',
23869 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
23874 this.iframe = iframe.dom;
23876 this.assignDocWin();
23878 this.doc.designMode = 'on';
23881 this.doc.write(this.getDocMarkup());
23885 var task = { // must defer to wait for browser to be ready
23887 //console.log("run task?" + this.doc.readyState);
23888 this.assignDocWin();
23889 if(this.doc.body || this.doc.readyState == 'complete'){
23891 this.doc.designMode="on";
23895 Roo.TaskMgr.stop(task);
23896 this.initEditor.defer(10, this);
23903 Roo.TaskMgr.start(task);
23908 onResize : function(w, h)
23910 Roo.log('resize: ' +w + ',' + h );
23911 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
23915 if(typeof w == 'number'){
23917 this.iframe.style.width = w + 'px';
23919 if(typeof h == 'number'){
23921 this.iframe.style.height = h + 'px';
23923 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
23930 * Toggles the editor between standard and source edit mode.
23931 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
23933 toggleSourceEdit : function(sourceEditMode){
23935 this.sourceEditMode = sourceEditMode === true;
23937 if(this.sourceEditMode){
23939 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
23942 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
23943 //this.iframe.className = '';
23946 //this.setSize(this.owner.wrap.getSize());
23947 //this.fireEvent('editmodechange', this, this.sourceEditMode);
23954 * Protected method that will not generally be called directly. If you need/want
23955 * custom HTML cleanup, this is the method you should override.
23956 * @param {String} html The HTML to be cleaned
23957 * return {String} The cleaned HTML
23959 cleanHtml : function(html){
23960 html = String(html);
23961 if(html.length > 5){
23962 if(Roo.isSafari){ // strip safari nonsense
23963 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
23966 if(html == ' '){
23973 * HTML Editor -> Textarea
23974 * Protected method that will not generally be called directly. Syncs the contents
23975 * of the editor iframe with the textarea.
23977 syncValue : function(){
23978 if(this.initialized){
23979 var bd = (this.doc.body || this.doc.documentElement);
23980 //this.cleanUpPaste(); -- this is done else where and causes havoc..
23981 var html = bd.innerHTML;
23983 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
23984 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
23986 html = '<div style="'+m[0]+'">' + html + '</div>';
23989 html = this.cleanHtml(html);
23990 // fix up the special chars.. normaly like back quotes in word...
23991 // however we do not want to do this with chinese..
23992 html = html.replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]|[\u0080-\uFFFF]/g, function(match) {
23994 var cc = match.charCodeAt();
23996 // Get the character value, handling surrogate pairs
23997 if (match.length == 2) {
23998 // It's a surrogate pair, calculate the Unicode code point
23999 var high = match.charCodeAt(0) - 0xD800;
24000 var low = match.charCodeAt(1) - 0xDC00;
24001 cc = (high * 0x400) + low + 0x10000;
24003 (cc >= 0x4E00 && cc < 0xA000 ) ||
24004 (cc >= 0x3400 && cc < 0x4E00 ) ||
24005 (cc >= 0xf900 && cc < 0xfb00 )
24010 // No, use a numeric entity. Here we brazenly (and possibly mistakenly)
24011 return "&#" + cc + ";";
24018 if(this.owner.fireEvent('beforesync', this, html) !== false){
24019 this.el.dom.value = html;
24020 this.owner.fireEvent('sync', this, html);
24026 * Protected method that will not generally be called directly. Pushes the value of the textarea
24027 * into the iframe editor.
24029 pushValue : function(){
24030 if(this.initialized){
24031 var v = this.el.dom.value.trim();
24033 // if(v.length < 1){
24037 if(this.owner.fireEvent('beforepush', this, v) !== false){
24038 var d = (this.doc.body || this.doc.documentElement);
24040 this.cleanUpPaste();
24041 this.el.dom.value = d.innerHTML;
24042 this.owner.fireEvent('push', this, v);
24048 deferFocus : function(){
24049 this.focus.defer(10, this);
24053 focus : function(){
24054 if(this.win && !this.sourceEditMode){
24061 assignDocWin: function()
24063 var iframe = this.iframe;
24066 this.doc = iframe.contentWindow.document;
24067 this.win = iframe.contentWindow;
24069 // if (!Roo.get(this.frameId)) {
24072 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
24073 // this.win = Roo.get(this.frameId).dom.contentWindow;
24075 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
24079 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
24080 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
24085 initEditor : function(){
24086 //console.log("INIT EDITOR");
24087 this.assignDocWin();
24091 this.doc.designMode="on";
24093 this.doc.write(this.getDocMarkup());
24096 var dbody = (this.doc.body || this.doc.documentElement);
24097 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
24098 // this copies styles from the containing element into thsi one..
24099 // not sure why we need all of this..
24100 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
24102 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
24103 //ss['background-attachment'] = 'fixed'; // w3c
24104 dbody.bgProperties = 'fixed'; // ie
24105 //Roo.DomHelper.applyStyles(dbody, ss);
24106 Roo.EventManager.on(this.doc, {
24107 //'mousedown': this.onEditorEvent,
24108 'mouseup': this.onEditorEvent,
24109 'dblclick': this.onEditorEvent,
24110 'click': this.onEditorEvent,
24111 'keyup': this.onEditorEvent,
24116 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
24118 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
24119 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
24121 this.initialized = true;
24123 this.owner.fireEvent('initialize', this);
24128 onDestroy : function(){
24134 //for (var i =0; i < this.toolbars.length;i++) {
24135 // // fixme - ask toolbars for heights?
24136 // this.toolbars[i].onDestroy();
24139 //this.wrap.dom.innerHTML = '';
24140 //this.wrap.remove();
24145 onFirstFocus : function(){
24147 this.assignDocWin();
24150 this.activated = true;
24153 if(Roo.isGecko){ // prevent silly gecko errors
24155 var s = this.win.getSelection();
24156 if(!s.focusNode || s.focusNode.nodeType != 3){
24157 var r = s.getRangeAt(0);
24158 r.selectNodeContents((this.doc.body || this.doc.documentElement));
24163 this.execCmd('useCSS', true);
24164 this.execCmd('styleWithCSS', false);
24167 this.owner.fireEvent('activate', this);
24171 adjustFont: function(btn){
24172 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
24173 //if(Roo.isSafari){ // safari
24176 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
24177 if(Roo.isSafari){ // safari
24178 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
24179 v = (v < 10) ? 10 : v;
24180 v = (v > 48) ? 48 : v;
24181 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
24186 v = Math.max(1, v+adjust);
24188 this.execCmd('FontSize', v );
24191 onEditorEvent : function(e)
24193 this.owner.fireEvent('editorevent', this, e);
24194 // this.updateToolbar();
24195 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
24198 insertTag : function(tg)
24200 // could be a bit smarter... -> wrap the current selected tRoo..
24201 if (tg.toLowerCase() == 'span' ||
24202 tg.toLowerCase() == 'code' ||
24203 tg.toLowerCase() == 'sup' ||
24204 tg.toLowerCase() == 'sub'
24207 range = this.createRange(this.getSelection());
24208 var wrappingNode = this.doc.createElement(tg.toLowerCase());
24209 wrappingNode.appendChild(range.extractContents());
24210 range.insertNode(wrappingNode);
24217 this.execCmd("formatblock", tg);
24221 insertText : function(txt)
24225 var range = this.createRange();
24226 range.deleteContents();
24227 //alert(Sender.getAttribute('label'));
24229 range.insertNode(this.doc.createTextNode(txt));
24235 * Executes a Midas editor command on the editor document and performs necessary focus and
24236 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
24237 * @param {String} cmd The Midas command
24238 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
24240 relayCmd : function(cmd, value){
24242 this.execCmd(cmd, value);
24243 this.owner.fireEvent('editorevent', this);
24244 //this.updateToolbar();
24245 this.owner.deferFocus();
24249 * Executes a Midas editor command directly on the editor document.
24250 * For visual commands, you should use {@link #relayCmd} instead.
24251 * <b>This should only be called after the editor is initialized.</b>
24252 * @param {String} cmd The Midas command
24253 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
24255 execCmd : function(cmd, value){
24256 this.doc.execCommand(cmd, false, value === undefined ? null : value);
24263 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
24265 * @param {String} text | dom node..
24267 insertAtCursor : function(text)
24270 if(!this.activated){
24276 var r = this.doc.selection.createRange();
24287 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
24291 // from jquery ui (MIT licenced)
24293 var win = this.win;
24295 if (win.getSelection && win.getSelection().getRangeAt) {
24296 range = win.getSelection().getRangeAt(0);
24297 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
24298 range.insertNode(node);
24299 } else if (win.document.selection && win.document.selection.createRange) {
24300 // no firefox support
24301 var txt = typeof(text) == 'string' ? text : text.outerHTML;
24302 win.document.selection.createRange().pasteHTML(txt);
24304 // no firefox support
24305 var txt = typeof(text) == 'string' ? text : text.outerHTML;
24306 this.execCmd('InsertHTML', txt);
24315 mozKeyPress : function(e){
24317 var c = e.getCharCode(), cmd;
24320 c = String.fromCharCode(c).toLowerCase();
24334 this.cleanUpPaste.defer(100, this);
24342 e.preventDefault();
24350 fixKeys : function(){ // load time branching for fastest keydown performance
24352 return function(e){
24353 var k = e.getKey(), r;
24356 r = this.doc.selection.createRange();
24359 r.pasteHTML('    ');
24366 r = this.doc.selection.createRange();
24368 var target = r.parentElement();
24369 if(!target || target.tagName.toLowerCase() != 'li'){
24371 r.pasteHTML('<br />');
24377 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
24378 this.cleanUpPaste.defer(100, this);
24384 }else if(Roo.isOpera){
24385 return function(e){
24386 var k = e.getKey();
24390 this.execCmd('InsertHTML','    ');
24393 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
24394 this.cleanUpPaste.defer(100, this);
24399 }else if(Roo.isSafari){
24400 return function(e){
24401 var k = e.getKey();
24405 this.execCmd('InsertText','\t');
24409 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
24410 this.cleanUpPaste.defer(100, this);
24418 getAllAncestors: function()
24420 var p = this.getSelectedNode();
24423 a.push(p); // push blank onto stack..
24424 p = this.getParentElement();
24428 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
24432 a.push(this.doc.body);
24436 lastSelNode : false,
24439 getSelection : function()
24441 this.assignDocWin();
24442 return Roo.isIE ? this.doc.selection : this.win.getSelection();
24445 getSelectedNode: function()
24447 // this may only work on Gecko!!!
24449 // should we cache this!!!!
24454 var range = this.createRange(this.getSelection()).cloneRange();
24457 var parent = range.parentElement();
24459 var testRange = range.duplicate();
24460 testRange.moveToElementText(parent);
24461 if (testRange.inRange(range)) {
24464 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
24467 parent = parent.parentElement;
24472 // is ancestor a text element.
24473 var ac = range.commonAncestorContainer;
24474 if (ac.nodeType == 3) {
24475 ac = ac.parentNode;
24478 var ar = ac.childNodes;
24481 var other_nodes = [];
24482 var has_other_nodes = false;
24483 for (var i=0;i<ar.length;i++) {
24484 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
24487 // fullly contained node.
24489 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
24494 // probably selected..
24495 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
24496 other_nodes.push(ar[i]);
24500 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
24505 has_other_nodes = true;
24507 if (!nodes.length && other_nodes.length) {
24508 nodes= other_nodes;
24510 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
24516 createRange: function(sel)
24518 // this has strange effects when using with
24519 // top toolbar - not sure if it's a great idea.
24520 //this.editor.contentWindow.focus();
24521 if (typeof sel != "undefined") {
24523 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
24525 return this.doc.createRange();
24528 return this.doc.createRange();
24531 getParentElement: function()
24534 this.assignDocWin();
24535 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
24537 var range = this.createRange(sel);
24540 var p = range.commonAncestorContainer;
24541 while (p.nodeType == 3) { // text node
24552 * Range intersection.. the hard stuff...
24556 * [ -- selected range --- ]
24560 * if end is before start or hits it. fail.
24561 * if start is after end or hits it fail.
24563 * if either hits (but other is outside. - then it's not
24569 // @see http://www.thismuchiknow.co.uk/?p=64.
24570 rangeIntersectsNode : function(range, node)
24572 var nodeRange = node.ownerDocument.createRange();
24574 nodeRange.selectNode(node);
24576 nodeRange.selectNodeContents(node);
24579 var rangeStartRange = range.cloneRange();
24580 rangeStartRange.collapse(true);
24582 var rangeEndRange = range.cloneRange();
24583 rangeEndRange.collapse(false);
24585 var nodeStartRange = nodeRange.cloneRange();
24586 nodeStartRange.collapse(true);
24588 var nodeEndRange = nodeRange.cloneRange();
24589 nodeEndRange.collapse(false);
24591 return rangeStartRange.compareBoundaryPoints(
24592 Range.START_TO_START, nodeEndRange) == -1 &&
24593 rangeEndRange.compareBoundaryPoints(
24594 Range.START_TO_START, nodeStartRange) == 1;
24598 rangeCompareNode : function(range, node)
24600 var nodeRange = node.ownerDocument.createRange();
24602 nodeRange.selectNode(node);
24604 nodeRange.selectNodeContents(node);
24608 range.collapse(true);
24610 nodeRange.collapse(true);
24612 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
24613 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
24615 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
24617 var nodeIsBefore = ss == 1;
24618 var nodeIsAfter = ee == -1;
24620 if (nodeIsBefore && nodeIsAfter) {
24623 if (!nodeIsBefore && nodeIsAfter) {
24624 return 1; //right trailed.
24627 if (nodeIsBefore && !nodeIsAfter) {
24628 return 2; // left trailed.
24634 // private? - in a new class?
24635 cleanUpPaste : function()
24637 // cleans up the whole document..
24638 Roo.log('cleanuppaste');
24640 this.cleanUpChildren(this.doc.body);
24641 var clean = this.cleanWordChars(this.doc.body.innerHTML);
24642 if (clean != this.doc.body.innerHTML) {
24643 this.doc.body.innerHTML = clean;
24648 cleanWordChars : function(input) {// change the chars to hex code
24649 var he = Roo.HtmlEditorCore;
24651 var output = input;
24652 Roo.each(he.swapCodes, function(sw) {
24653 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
24655 output = output.replace(swapper, sw[1]);
24662 cleanUpChildren : function (n)
24664 if (!n.childNodes.length) {
24667 for (var i = n.childNodes.length-1; i > -1 ; i--) {
24668 this.cleanUpChild(n.childNodes[i]);
24675 cleanUpChild : function (node)
24678 //console.log(node);
24679 if (node.nodeName == "#text") {
24680 // clean up silly Windows -- stuff?
24683 if (node.nodeName == "#comment") {
24684 node.parentNode.removeChild(node);
24685 // clean up silly Windows -- stuff?
24688 var lcname = node.tagName.toLowerCase();
24689 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
24690 // whitelist of tags..
24692 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
24694 node.parentNode.removeChild(node);
24699 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
24701 // spans with no attributes - just remove them..
24702 if ((!node.attributes || !node.attributes.length) && lcname == 'span') {
24703 remove_keep_children = true;
24706 // remove <a name=....> as rendering on yahoo mailer is borked with this.
24707 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
24709 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
24710 // remove_keep_children = true;
24713 if (remove_keep_children) {
24714 this.cleanUpChildren(node);
24715 // inserts everything just before this node...
24716 while (node.childNodes.length) {
24717 var cn = node.childNodes[0];
24718 node.removeChild(cn);
24719 node.parentNode.insertBefore(cn, node);
24721 node.parentNode.removeChild(node);
24725 if (!node.attributes || !node.attributes.length) {
24730 this.cleanUpChildren(node);
24734 function cleanAttr(n,v)
24737 if (v.match(/^\./) || v.match(/^\//)) {
24740 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/) || v.match(/^ftp:/)) {
24743 if (v.match(/^#/)) {
24746 if (v.match(/^\{/)) { // allow template editing.
24749 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
24750 node.removeAttribute(n);
24754 var cwhite = this.cwhite;
24755 var cblack = this.cblack;
24757 function cleanStyle(n,v)
24759 if (v.match(/expression/)) { //XSS?? should we even bother..
24760 node.removeAttribute(n);
24764 var parts = v.split(/;/);
24767 Roo.each(parts, function(p) {
24768 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
24772 var l = p.split(':').shift().replace(/\s+/g,'');
24773 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
24775 if ( cwhite.length && cblack.indexOf(l) > -1) {
24776 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
24777 //node.removeAttribute(n);
24781 // only allow 'c whitelisted system attributes'
24782 if ( cwhite.length && cwhite.indexOf(l) < 0) {
24783 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
24784 //node.removeAttribute(n);
24794 if (clean.length) {
24795 node.setAttribute(n, clean.join(';'));
24797 node.removeAttribute(n);
24803 for (var i = node.attributes.length-1; i > -1 ; i--) {
24804 var a = node.attributes[i];
24807 if (a.name.toLowerCase().substr(0,2)=='on') {
24808 node.removeAttribute(a.name);
24811 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
24812 node.removeAttribute(a.name);
24815 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
24816 cleanAttr(a.name,a.value); // fixme..
24819 if (a.name == 'style') {
24820 cleanStyle(a.name,a.value);
24823 /// clean up MS crap..
24824 // tecnically this should be a list of valid class'es..
24827 if (a.name == 'class') {
24828 if (a.value.match(/^Mso/)) {
24829 node.removeAttribute('class');
24832 if (a.value.match(/^body$/)) {
24833 node.removeAttribute('class');
24844 this.cleanUpChildren(node);
24850 * Clean up MS wordisms...
24852 cleanWord : function(node)
24855 this.cleanWord(this.doc.body);
24860 node.nodeName == 'SPAN' &&
24861 !node.hasAttributes() &&
24862 node.childNodes.length == 1 &&
24863 node.firstChild.nodeName == "#text"
24865 var textNode = node.firstChild;
24866 node.removeChild(textNode);
24867 if (node.getAttribute('lang') != 'zh-CN') { // do not space pad on chinese characters..
24868 node.parentNode.insertBefore(node.ownerDocument.createTextNode(" "), node);
24870 node.parentNode.insertBefore(textNode, node);
24871 if (node.getAttribute('lang') != 'zh-CN') { // do not space pad on chinese characters..
24872 node.parentNode.insertBefore(node.ownerDocument.createTextNode(" ") , node);
24874 node.parentNode.removeChild(node);
24877 if (node.nodeName == "#text") {
24878 // clean up silly Windows -- stuff?
24881 if (node.nodeName == "#comment") {
24882 node.parentNode.removeChild(node);
24883 // clean up silly Windows -- stuff?
24887 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
24888 node.parentNode.removeChild(node);
24891 //Roo.log(node.tagName);
24892 // remove - but keep children..
24893 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|v:|font)/)) {
24894 //Roo.log('-- removed');
24895 while (node.childNodes.length) {
24896 var cn = node.childNodes[0];
24897 node.removeChild(cn);
24898 node.parentNode.insertBefore(cn, node);
24899 // move node to parent - and clean it..
24900 this.cleanWord(cn);
24902 node.parentNode.removeChild(node);
24903 /// no need to iterate chidlren = it's got none..
24904 //this.iterateChildren(node, this.cleanWord);
24908 if (node.className.length) {
24910 var cn = node.className.split(/\W+/);
24912 Roo.each(cn, function(cls) {
24913 if (cls.match(/Mso[a-zA-Z]+/)) {
24918 node.className = cna.length ? cna.join(' ') : '';
24920 node.removeAttribute("class");
24924 if (node.hasAttribute("lang")) {
24925 node.removeAttribute("lang");
24928 if (node.hasAttribute("style")) {
24930 var styles = node.getAttribute("style").split(";");
24932 Roo.each(styles, function(s) {
24933 if (!s.match(/:/)) {
24936 var kv = s.split(":");
24937 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
24940 // what ever is left... we allow.
24943 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
24944 if (!nstyle.length) {
24945 node.removeAttribute('style');
24948 this.iterateChildren(node, this.cleanWord);
24954 * iterateChildren of a Node, calling fn each time, using this as the scole..
24955 * @param {DomNode} node node to iterate children of.
24956 * @param {Function} fn method of this class to call on each item.
24958 iterateChildren : function(node, fn)
24960 if (!node.childNodes.length) {
24963 for (var i = node.childNodes.length-1; i > -1 ; i--) {
24964 fn.call(this, node.childNodes[i])
24970 * cleanTableWidths.
24972 * Quite often pasting from word etc.. results in tables with column and widths.
24973 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
24976 cleanTableWidths : function(node)
24981 this.cleanTableWidths(this.doc.body);
24986 if (node.nodeName == "#text" || node.nodeName == "#comment") {
24989 Roo.log(node.tagName);
24990 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
24991 this.iterateChildren(node, this.cleanTableWidths);
24994 if (node.hasAttribute('width')) {
24995 node.removeAttribute('width');
24999 if (node.hasAttribute("style")) {
25002 var styles = node.getAttribute("style").split(";");
25004 Roo.each(styles, function(s) {
25005 if (!s.match(/:/)) {
25008 var kv = s.split(":");
25009 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
25012 // what ever is left... we allow.
25015 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
25016 if (!nstyle.length) {
25017 node.removeAttribute('style');
25021 this.iterateChildren(node, this.cleanTableWidths);
25029 domToHTML : function(currentElement, depth, nopadtext) {
25031 depth = depth || 0;
25032 nopadtext = nopadtext || false;
25034 if (!currentElement) {
25035 return this.domToHTML(this.doc.body);
25038 //Roo.log(currentElement);
25040 var allText = false;
25041 var nodeName = currentElement.nodeName;
25042 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
25044 if (nodeName == '#text') {
25046 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
25051 if (nodeName != 'BODY') {
25054 // Prints the node tagName, such as <A>, <IMG>, etc
25057 for(i = 0; i < currentElement.attributes.length;i++) {
25059 var aname = currentElement.attributes.item(i).name;
25060 if (!currentElement.attributes.item(i).value.length) {
25063 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
25066 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
25075 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
25078 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
25083 // Traverse the tree
25085 var currentElementChild = currentElement.childNodes.item(i);
25086 var allText = true;
25087 var innerHTML = '';
25089 while (currentElementChild) {
25090 // Formatting code (indent the tree so it looks nice on the screen)
25091 var nopad = nopadtext;
25092 if (lastnode == 'SPAN') {
25096 if (currentElementChild.nodeName == '#text') {
25097 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
25098 toadd = nopadtext ? toadd : toadd.trim();
25099 if (!nopad && toadd.length > 80) {
25100 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
25102 innerHTML += toadd;
25105 currentElementChild = currentElement.childNodes.item(i);
25111 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
25113 // Recursively traverse the tree structure of the child node
25114 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
25115 lastnode = currentElementChild.nodeName;
25117 currentElementChild=currentElement.childNodes.item(i);
25123 // The remaining code is mostly for formatting the tree
25124 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
25129 ret+= "</"+tagName+">";
25135 applyBlacklists : function()
25137 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
25138 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
25142 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
25143 if (b.indexOf(tag) > -1) {
25146 this.white.push(tag);
25150 Roo.each(w, function(tag) {
25151 if (b.indexOf(tag) > -1) {
25154 if (this.white.indexOf(tag) > -1) {
25157 this.white.push(tag);
25162 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
25163 if (w.indexOf(tag) > -1) {
25166 this.black.push(tag);
25170 Roo.each(b, function(tag) {
25171 if (w.indexOf(tag) > -1) {
25174 if (this.black.indexOf(tag) > -1) {
25177 this.black.push(tag);
25182 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
25183 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
25187 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
25188 if (b.indexOf(tag) > -1) {
25191 this.cwhite.push(tag);
25195 Roo.each(w, function(tag) {
25196 if (b.indexOf(tag) > -1) {
25199 if (this.cwhite.indexOf(tag) > -1) {
25202 this.cwhite.push(tag);
25207 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
25208 if (w.indexOf(tag) > -1) {
25211 this.cblack.push(tag);
25215 Roo.each(b, function(tag) {
25216 if (w.indexOf(tag) > -1) {
25219 if (this.cblack.indexOf(tag) > -1) {
25222 this.cblack.push(tag);
25227 setStylesheets : function(stylesheets)
25229 if(typeof(stylesheets) == 'string'){
25230 Roo.get(this.iframe.contentDocument.head).createChild({
25232 rel : 'stylesheet',
25241 Roo.each(stylesheets, function(s) {
25246 Roo.get(_this.iframe.contentDocument.head).createChild({
25248 rel : 'stylesheet',
25257 removeStylesheets : function()
25261 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
25266 setStyle : function(style)
25268 Roo.get(this.iframe.contentDocument.head).createChild({
25277 // hide stuff that is not compatible
25291 * @event specialkey
25295 * @cfg {String} fieldClass @hide
25298 * @cfg {String} focusClass @hide
25301 * @cfg {String} autoCreate @hide
25304 * @cfg {String} inputType @hide
25307 * @cfg {String} invalidClass @hide
25310 * @cfg {String} invalidText @hide
25313 * @cfg {String} msgFx @hide
25316 * @cfg {String} validateOnBlur @hide
25320 Roo.HtmlEditorCore.white = [
25321 'area', 'br', 'img', 'input', 'hr', 'wbr',
25323 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
25324 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
25325 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
25326 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
25327 'table', 'ul', 'xmp',
25329 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
25332 'dir', 'menu', 'ol', 'ul', 'dl',
25338 Roo.HtmlEditorCore.black = [
25339 // 'embed', 'object', // enable - backend responsiblity to clean thiese
25341 'base', 'basefont', 'bgsound', 'blink', 'body',
25342 'frame', 'frameset', 'head', 'html', 'ilayer',
25343 'iframe', 'layer', 'link', 'meta', 'object',
25344 'script', 'style' ,'title', 'xml' // clean later..
25346 Roo.HtmlEditorCore.clean = [
25347 'script', 'style', 'title', 'xml'
25349 Roo.HtmlEditorCore.remove = [
25354 Roo.HtmlEditorCore.ablack = [
25358 Roo.HtmlEditorCore.aclean = [
25359 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
25363 Roo.HtmlEditorCore.pwhite= [
25364 'http', 'https', 'mailto'
25367 // white listed style attributes.
25368 Roo.HtmlEditorCore.cwhite= [
25369 // 'text-align', /// default is to allow most things..
25375 // black listed style attributes.
25376 Roo.HtmlEditorCore.cblack= [
25377 // 'font-size' -- this can be set by the project
25381 Roo.HtmlEditorCore.swapCodes =[
25400 * @class Roo.bootstrap.HtmlEditor
25401 * @extends Roo.bootstrap.TextArea
25402 * Bootstrap HtmlEditor class
25405 * Create a new HtmlEditor
25406 * @param {Object} config The config object
25409 Roo.bootstrap.HtmlEditor = function(config){
25410 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
25411 if (!this.toolbars) {
25412 this.toolbars = [];
25415 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
25418 * @event initialize
25419 * Fires when the editor is fully initialized (including the iframe)
25420 * @param {HtmlEditor} this
25425 * Fires when the editor is first receives the focus. Any insertion must wait
25426 * until after this event.
25427 * @param {HtmlEditor} this
25431 * @event beforesync
25432 * Fires before the textarea is updated with content from the editor iframe. Return false
25433 * to cancel the sync.
25434 * @param {HtmlEditor} this
25435 * @param {String} html
25439 * @event beforepush
25440 * Fires before the iframe editor is updated with content from the textarea. Return false
25441 * to cancel the push.
25442 * @param {HtmlEditor} this
25443 * @param {String} html
25448 * Fires when the textarea is updated with content from the editor iframe.
25449 * @param {HtmlEditor} this
25450 * @param {String} html
25455 * Fires when the iframe editor is updated with content from the textarea.
25456 * @param {HtmlEditor} this
25457 * @param {String} html
25461 * @event editmodechange
25462 * Fires when the editor switches edit modes
25463 * @param {HtmlEditor} this
25464 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
25466 editmodechange: true,
25468 * @event editorevent
25469 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
25470 * @param {HtmlEditor} this
25474 * @event firstfocus
25475 * Fires when on first focus - needed by toolbars..
25476 * @param {HtmlEditor} this
25481 * Auto save the htmlEditor value as a file into Events
25482 * @param {HtmlEditor} this
25486 * @event savedpreview
25487 * preview the saved version of htmlEditor
25488 * @param {HtmlEditor} this
25495 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
25499 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
25504 * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
25509 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
25514 * @cfg {Number} height (in pixels)
25518 * @cfg {Number} width (in pixels)
25523 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
25526 stylesheets: false,
25531 // private properties
25532 validationEvent : false,
25534 initialized : false,
25537 onFocus : Roo.emptyFn,
25539 hideMode:'offsets',
25541 tbContainer : false,
25545 toolbarContainer :function() {
25546 return this.wrap.select('.x-html-editor-tb',true).first();
25550 * Protected method that will not generally be called directly. It
25551 * is called when the editor creates its toolbar. Override this method if you need to
25552 * add custom toolbar buttons.
25553 * @param {HtmlEditor} editor
25555 createToolbar : function(){
25556 Roo.log('renewing');
25557 Roo.log("create toolbars");
25559 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
25560 this.toolbars[0].render(this.toolbarContainer());
25564 // if (!editor.toolbars || !editor.toolbars.length) {
25565 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
25568 // for (var i =0 ; i < editor.toolbars.length;i++) {
25569 // editor.toolbars[i] = Roo.factory(
25570 // typeof(editor.toolbars[i]) == 'string' ?
25571 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
25572 // Roo.bootstrap.HtmlEditor);
25573 // editor.toolbars[i].init(editor);
25579 onRender : function(ct, position)
25581 // Roo.log("Call onRender: " + this.xtype);
25583 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
25585 this.wrap = this.inputEl().wrap({
25586 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
25589 this.editorcore.onRender(ct, position);
25591 if (this.resizable) {
25592 this.resizeEl = new Roo.Resizable(this.wrap, {
25596 minHeight : this.height,
25597 height: this.height,
25598 handles : this.resizable,
25601 resize : function(r, w, h) {
25602 _t.onResize(w,h); // -something
25608 this.createToolbar(this);
25611 if(!this.width && this.resizable){
25612 this.setSize(this.wrap.getSize());
25614 if (this.resizeEl) {
25615 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
25616 // should trigger onReize..
25622 onResize : function(w, h)
25624 Roo.log('resize: ' +w + ',' + h );
25625 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
25629 if(this.inputEl() ){
25630 if(typeof w == 'number'){
25631 var aw = w - this.wrap.getFrameWidth('lr');
25632 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
25635 if(typeof h == 'number'){
25636 var tbh = -11; // fixme it needs to tool bar size!
25637 for (var i =0; i < this.toolbars.length;i++) {
25638 // fixme - ask toolbars for heights?
25639 tbh += this.toolbars[i].el.getHeight();
25640 //if (this.toolbars[i].footer) {
25641 // tbh += this.toolbars[i].footer.el.getHeight();
25649 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
25650 ah -= 5; // knock a few pixes off for look..
25651 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
25655 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
25656 this.editorcore.onResize(ew,eh);
25661 * Toggles the editor between standard and source edit mode.
25662 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
25664 toggleSourceEdit : function(sourceEditMode)
25666 this.editorcore.toggleSourceEdit(sourceEditMode);
25668 if(this.editorcore.sourceEditMode){
25669 Roo.log('editor - showing textarea');
25672 // Roo.log(this.syncValue());
25674 this.inputEl().removeClass(['hide', 'x-hidden']);
25675 this.inputEl().dom.removeAttribute('tabIndex');
25676 this.inputEl().focus();
25678 Roo.log('editor - hiding textarea');
25680 // Roo.log(this.pushValue());
25683 this.inputEl().addClass(['hide', 'x-hidden']);
25684 this.inputEl().dom.setAttribute('tabIndex', -1);
25685 //this.deferFocus();
25688 if(this.resizable){
25689 this.setSize(this.wrap.getSize());
25692 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
25695 // private (for BoxComponent)
25696 adjustSize : Roo.BoxComponent.prototype.adjustSize,
25698 // private (for BoxComponent)
25699 getResizeEl : function(){
25703 // private (for BoxComponent)
25704 getPositionEl : function(){
25709 initEvents : function(){
25710 this.originalValue = this.getValue();
25714 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
25717 // markInvalid : Roo.emptyFn,
25719 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
25722 // clearInvalid : Roo.emptyFn,
25724 setValue : function(v){
25725 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
25726 this.editorcore.pushValue();
25731 deferFocus : function(){
25732 this.focus.defer(10, this);
25736 focus : function(){
25737 this.editorcore.focus();
25743 onDestroy : function(){
25749 for (var i =0; i < this.toolbars.length;i++) {
25750 // fixme - ask toolbars for heights?
25751 this.toolbars[i].onDestroy();
25754 this.wrap.dom.innerHTML = '';
25755 this.wrap.remove();
25760 onFirstFocus : function(){
25761 //Roo.log("onFirstFocus");
25762 this.editorcore.onFirstFocus();
25763 for (var i =0; i < this.toolbars.length;i++) {
25764 this.toolbars[i].onFirstFocus();
25770 syncValue : function()
25772 this.editorcore.syncValue();
25775 pushValue : function()
25777 this.editorcore.pushValue();
25781 // hide stuff that is not compatible
25795 * @event specialkey
25799 * @cfg {String} fieldClass @hide
25802 * @cfg {String} focusClass @hide
25805 * @cfg {String} autoCreate @hide
25808 * @cfg {String} inputType @hide
25812 * @cfg {String} invalidText @hide
25815 * @cfg {String} msgFx @hide
25818 * @cfg {String} validateOnBlur @hide
25827 Roo.namespace('Roo.bootstrap.htmleditor');
25829 * @class Roo.bootstrap.HtmlEditorToolbar1
25835 new Roo.bootstrap.HtmlEditor({
25838 new Roo.bootstrap.HtmlEditorToolbar1({
25839 disable : { fonts: 1 , format: 1, ..., ... , ...],
25845 * @cfg {Object} disable List of elements to disable..
25846 * @cfg {Array} btns List of additional buttons.
25850 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
25853 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
25856 Roo.apply(this, config);
25858 // default disabled, based on 'good practice'..
25859 this.disable = this.disable || {};
25860 Roo.applyIf(this.disable, {
25863 specialElements : true
25865 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
25867 this.editor = config.editor;
25868 this.editorcore = config.editor.editorcore;
25870 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
25872 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
25873 // dont call parent... till later.
25875 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
25880 editorcore : false,
25885 "h1","h2","h3","h4","h5","h6",
25887 "abbr", "acronym", "address", "cite", "samp", "var",
25891 onRender : function(ct, position)
25893 // Roo.log("Call onRender: " + this.xtype);
25895 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
25897 this.el.dom.style.marginBottom = '0';
25899 var editorcore = this.editorcore;
25900 var editor= this.editor;
25903 var btn = function(id,cmd , toggle, handler, html){
25905 var event = toggle ? 'toggle' : 'click';
25910 xns: Roo.bootstrap,
25914 enableToggle:toggle !== false,
25916 pressed : toggle ? false : null,
25919 a.listeners[toggle ? 'toggle' : 'click'] = function() {
25920 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
25926 // var cb_box = function...
25931 xns: Roo.bootstrap,
25936 xns: Roo.bootstrap,
25940 Roo.each(this.formats, function(f) {
25941 style.menu.items.push({
25943 xns: Roo.bootstrap,
25944 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
25949 editorcore.insertTag(this.tagname);
25956 children.push(style);
25958 btn('bold',false,true);
25959 btn('italic',false,true);
25960 btn('align-left', 'justifyleft',true);
25961 btn('align-center', 'justifycenter',true);
25962 btn('align-right' , 'justifyright',true);
25963 btn('link', false, false, function(btn) {
25964 //Roo.log("create link?");
25965 var url = prompt(this.createLinkText, this.defaultLinkValue);
25966 if(url && url != 'http:/'+'/'){
25967 this.editorcore.relayCmd('createlink', url);
25970 btn('list','insertunorderedlist',true);
25971 btn('pencil', false,true, function(btn){
25973 this.toggleSourceEdit(btn.pressed);
25976 if (this.editor.btns.length > 0) {
25977 for (var i = 0; i<this.editor.btns.length; i++) {
25978 children.push(this.editor.btns[i]);
25986 xns: Roo.bootstrap,
25991 xns: Roo.bootstrap,
25996 cog.menu.items.push({
25998 xns: Roo.bootstrap,
25999 html : Clean styles,
26004 editorcore.insertTag(this.tagname);
26013 this.xtype = 'NavSimplebar';
26015 for(var i=0;i< children.length;i++) {
26017 this.buttons.add(this.addxtypeChild(children[i]));
26021 editor.on('editorevent', this.updateToolbar, this);
26023 onBtnClick : function(id)
26025 this.editorcore.relayCmd(id);
26026 this.editorcore.focus();
26030 * Protected method that will not generally be called directly. It triggers
26031 * a toolbar update by reading the markup state of the current selection in the editor.
26033 updateToolbar: function(){
26035 if(!this.editorcore.activated){
26036 this.editor.onFirstFocus(); // is this neeed?
26040 var btns = this.buttons;
26041 var doc = this.editorcore.doc;
26042 btns.get('bold').setActive(doc.queryCommandState('bold'));
26043 btns.get('italic').setActive(doc.queryCommandState('italic'));
26044 //btns.get('underline').setActive(doc.queryCommandState('underline'));
26046 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
26047 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
26048 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
26050 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
26051 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
26054 var ans = this.editorcore.getAllAncestors();
26055 if (this.formatCombo) {
26058 var store = this.formatCombo.store;
26059 this.formatCombo.setValue("");
26060 for (var i =0; i < ans.length;i++) {
26061 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
26063 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
26071 // hides menus... - so this cant be on a menu...
26072 Roo.bootstrap.MenuMgr.hideAll();
26074 Roo.bootstrap.MenuMgr.hideAll();
26075 //this.editorsyncValue();
26077 onFirstFocus: function() {
26078 this.buttons.each(function(item){
26082 toggleSourceEdit : function(sourceEditMode){
26085 if(sourceEditMode){
26086 Roo.log("disabling buttons");
26087 this.buttons.each( function(item){
26088 if(item.cmd != 'pencil'){
26094 Roo.log("enabling buttons");
26095 if(this.editorcore.initialized){
26096 this.buttons.each( function(item){
26102 Roo.log("calling toggole on editor");
26103 // tell the editor that it's been pressed..
26104 this.editor.toggleSourceEdit(sourceEditMode);
26118 * @class Roo.bootstrap.Markdown
26119 * @extends Roo.bootstrap.TextArea
26120 * Bootstrap Showdown editable area
26121 * @cfg {string} content
26124 * Create a new Showdown
26127 Roo.bootstrap.Markdown = function(config){
26128 Roo.bootstrap.Markdown.superclass.constructor.call(this, config);
26132 Roo.extend(Roo.bootstrap.Markdown, Roo.bootstrap.TextArea, {
26136 initEvents : function()
26139 Roo.bootstrap.TextArea.prototype.initEvents.call(this);
26140 this.markdownEl = this.el.createChild({
26141 cls : 'roo-markdown-area'
26143 this.inputEl().addClass('d-none');
26144 this.markdownEl.dom.innerHTML = Roo.Markdown.toHtml(Roo.util.Format.htmlEncode(this.getValue()));
26145 this.markdownEl.on('click', this.toggleTextEdit, this);
26146 this.on('blur', this.toggleTextEdit, this);
26147 this.on('specialkey', this.resizeTextArea, this);
26150 toggleTextEdit : function()
26152 var sh = this.markdownEl.getHeight();
26153 this.inputEl().addClass('d-none');
26154 this.markdownEl.addClass('d-none');
26155 if (!this.editing) {
26157 this.inputEl().setHeight(Math.min(500, Math.max(sh,(this.getValue().split("\n").length+1) * 30)));
26158 this.inputEl().removeClass('d-none');
26159 this.inputEl().focus();
26160 this.editing = true;
26163 // show showdown...
26164 this.updateMarkdown();
26165 this.markdownEl.removeClass('d-none');
26166 this.editing = false;
26169 updateMarkdown : function()
26171 if (this.getValue() == '') {
26172 this.markdownEl.dom.innerHTML = String.format('<span class="roo-placeholder">{0}</span>', this.placeholder);
26175 this.markdownEl.dom.innerHTML = Roo.Markdown.toHtml(Roo.util.Format.htmlEncode(this.getValue()));
26178 resizeTextArea: function () {
26181 Roo.log([sh, this.getValue().split("\n").length * 30]);
26182 this.inputEl().setHeight(Math.min(500, Math.max(sh, (this.getValue().split("\n").length +1) * 30)));
26184 setValue : function(val)
26186 Roo.bootstrap.TextArea.prototype.setValue.call(this,val);
26187 if (!this.editing) {
26188 this.updateMarkdown();
26194 if (!this.editing) {
26195 this.toggleTextEdit();
26203 * @class Roo.bootstrap.Table.AbstractSelectionModel
26204 * @extends Roo.util.Observable
26205 * Abstract base class for grid SelectionModels. It provides the interface that should be
26206 * implemented by descendant classes. This class should not be directly instantiated.
26209 Roo.bootstrap.Table.AbstractSelectionModel = function(){
26210 this.locked = false;
26211 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
26215 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
26216 /** @ignore Called by the grid automatically. Do not call directly. */
26217 init : function(grid){
26223 * Locks the selections.
26226 this.locked = true;
26230 * Unlocks the selections.
26232 unlock : function(){
26233 this.locked = false;
26237 * Returns true if the selections are locked.
26238 * @return {Boolean}
26240 isLocked : function(){
26241 return this.locked;
26245 initEvents : function ()
26251 * @extends Roo.bootstrap.Table.AbstractSelectionModel
26252 * @class Roo.bootstrap.Table.RowSelectionModel
26253 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
26254 * It supports multiple selections and keyboard selection/navigation.
26256 * @param {Object} config
26259 Roo.bootstrap.Table.RowSelectionModel = function(config){
26260 Roo.apply(this, config);
26261 this.selections = new Roo.util.MixedCollection(false, function(o){
26266 this.lastActive = false;
26270 * @event selectionchange
26271 * Fires when the selection changes
26272 * @param {SelectionModel} this
26274 "selectionchange" : true,
26276 * @event afterselectionchange
26277 * Fires after the selection changes (eg. by key press or clicking)
26278 * @param {SelectionModel} this
26280 "afterselectionchange" : true,
26282 * @event beforerowselect
26283 * Fires when a row is selected being selected, return false to cancel.
26284 * @param {SelectionModel} this
26285 * @param {Number} rowIndex The selected index
26286 * @param {Boolean} keepExisting False if other selections will be cleared
26288 "beforerowselect" : true,
26291 * Fires when a row is selected.
26292 * @param {SelectionModel} this
26293 * @param {Number} rowIndex The selected index
26294 * @param {Roo.data.Record} r The record
26296 "rowselect" : true,
26298 * @event rowdeselect
26299 * Fires when a row is deselected.
26300 * @param {SelectionModel} this
26301 * @param {Number} rowIndex The selected index
26303 "rowdeselect" : true
26305 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
26306 this.locked = false;
26309 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
26311 * @cfg {Boolean} singleSelect
26312 * True to allow selection of only one row at a time (defaults to false)
26314 singleSelect : false,
26317 initEvents : function()
26320 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
26321 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
26322 //}else{ // allow click to work like normal
26323 // this.grid.on("rowclick", this.handleDragableRowClick, this);
26325 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
26326 this.grid.on("rowclick", this.handleMouseDown, this);
26328 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
26329 "up" : function(e){
26331 this.selectPrevious(e.shiftKey);
26332 }else if(this.last !== false && this.lastActive !== false){
26333 var last = this.last;
26334 this.selectRange(this.last, this.lastActive-1);
26335 this.grid.getView().focusRow(this.lastActive);
26336 if(last !== false){
26340 this.selectFirstRow();
26342 this.fireEvent("afterselectionchange", this);
26344 "down" : function(e){
26346 this.selectNext(e.shiftKey);
26347 }else if(this.last !== false && this.lastActive !== false){
26348 var last = this.last;
26349 this.selectRange(this.last, this.lastActive+1);
26350 this.grid.getView().focusRow(this.lastActive);
26351 if(last !== false){
26355 this.selectFirstRow();
26357 this.fireEvent("afterselectionchange", this);
26361 this.grid.store.on('load', function(){
26362 this.selections.clear();
26365 var view = this.grid.view;
26366 view.on("refresh", this.onRefresh, this);
26367 view.on("rowupdated", this.onRowUpdated, this);
26368 view.on("rowremoved", this.onRemove, this);
26373 onRefresh : function()
26375 var ds = this.grid.store, i, v = this.grid.view;
26376 var s = this.selections;
26377 s.each(function(r){
26378 if((i = ds.indexOfId(r.id)) != -1){
26387 onRemove : function(v, index, r){
26388 this.selections.remove(r);
26392 onRowUpdated : function(v, index, r){
26393 if(this.isSelected(r)){
26394 v.onRowSelect(index);
26400 * @param {Array} records The records to select
26401 * @param {Boolean} keepExisting (optional) True to keep existing selections
26403 selectRecords : function(records, keepExisting)
26406 this.clearSelections();
26408 var ds = this.grid.store;
26409 for(var i = 0, len = records.length; i < len; i++){
26410 this.selectRow(ds.indexOf(records[i]), true);
26415 * Gets the number of selected rows.
26418 getCount : function(){
26419 return this.selections.length;
26423 * Selects the first row in the grid.
26425 selectFirstRow : function(){
26430 * Select the last row.
26431 * @param {Boolean} keepExisting (optional) True to keep existing selections
26433 selectLastRow : function(keepExisting){
26434 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
26435 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
26439 * Selects the row immediately following the last selected row.
26440 * @param {Boolean} keepExisting (optional) True to keep existing selections
26442 selectNext : function(keepExisting)
26444 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
26445 this.selectRow(this.last+1, keepExisting);
26446 this.grid.getView().focusRow(this.last);
26451 * Selects the row that precedes the last selected row.
26452 * @param {Boolean} keepExisting (optional) True to keep existing selections
26454 selectPrevious : function(keepExisting){
26456 this.selectRow(this.last-1, keepExisting);
26457 this.grid.getView().focusRow(this.last);
26462 * Returns the selected records
26463 * @return {Array} Array of selected records
26465 getSelections : function(){
26466 return [].concat(this.selections.items);
26470 * Returns the first selected record.
26473 getSelected : function(){
26474 return this.selections.itemAt(0);
26479 * Clears all selections.
26481 clearSelections : function(fast)
26487 var ds = this.grid.store;
26488 var s = this.selections;
26489 s.each(function(r){
26490 this.deselectRow(ds.indexOfId(r.id));
26494 this.selections.clear();
26501 * Selects all rows.
26503 selectAll : function(){
26507 this.selections.clear();
26508 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
26509 this.selectRow(i, true);
26514 * Returns True if there is a selection.
26515 * @return {Boolean}
26517 hasSelection : function(){
26518 return this.selections.length > 0;
26522 * Returns True if the specified row is selected.
26523 * @param {Number/Record} record The record or index of the record to check
26524 * @return {Boolean}
26526 isSelected : function(index){
26527 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
26528 return (r && this.selections.key(r.id) ? true : false);
26532 * Returns True if the specified record id is selected.
26533 * @param {String} id The id of record to check
26534 * @return {Boolean}
26536 isIdSelected : function(id){
26537 return (this.selections.key(id) ? true : false);
26542 handleMouseDBClick : function(e, t){
26546 handleMouseDown : function(e, t)
26548 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
26549 if(this.isLocked() || rowIndex < 0 ){
26552 if(e.shiftKey && this.last !== false){
26553 var last = this.last;
26554 this.selectRange(last, rowIndex, e.ctrlKey);
26555 this.last = last; // reset the last
26559 var isSelected = this.isSelected(rowIndex);
26560 //Roo.log("select row:" + rowIndex);
26562 this.deselectRow(rowIndex);
26564 this.selectRow(rowIndex, true);
26568 if(e.button !== 0 && isSelected){
26569 alert('rowIndex 2: ' + rowIndex);
26570 view.focusRow(rowIndex);
26571 }else if(e.ctrlKey && isSelected){
26572 this.deselectRow(rowIndex);
26573 }else if(!isSelected){
26574 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
26575 view.focusRow(rowIndex);
26579 this.fireEvent("afterselectionchange", this);
26582 handleDragableRowClick : function(grid, rowIndex, e)
26584 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
26585 this.selectRow(rowIndex, false);
26586 grid.view.focusRow(rowIndex);
26587 this.fireEvent("afterselectionchange", this);
26592 * Selects multiple rows.
26593 * @param {Array} rows Array of the indexes of the row to select
26594 * @param {Boolean} keepExisting (optional) True to keep existing selections
26596 selectRows : function(rows, keepExisting){
26598 this.clearSelections();
26600 for(var i = 0, len = rows.length; i < len; i++){
26601 this.selectRow(rows[i], true);
26606 * Selects a range of rows. All rows in between startRow and endRow are also selected.
26607 * @param {Number} startRow The index of the first row in the range
26608 * @param {Number} endRow The index of the last row in the range
26609 * @param {Boolean} keepExisting (optional) True to retain existing selections
26611 selectRange : function(startRow, endRow, keepExisting){
26616 this.clearSelections();
26618 if(startRow <= endRow){
26619 for(var i = startRow; i <= endRow; i++){
26620 this.selectRow(i, true);
26623 for(var i = startRow; i >= endRow; i--){
26624 this.selectRow(i, true);
26630 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
26631 * @param {Number} startRow The index of the first row in the range
26632 * @param {Number} endRow The index of the last row in the range
26634 deselectRange : function(startRow, endRow, preventViewNotify){
26638 for(var i = startRow; i <= endRow; i++){
26639 this.deselectRow(i, preventViewNotify);
26645 * @param {Number} row The index of the row to select
26646 * @param {Boolean} keepExisting (optional) True to keep existing selections
26648 selectRow : function(index, keepExisting, preventViewNotify)
26650 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
26653 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
26654 if(!keepExisting || this.singleSelect){
26655 this.clearSelections();
26658 var r = this.grid.store.getAt(index);
26659 //console.log('selectRow - record id :' + r.id);
26661 this.selections.add(r);
26662 this.last = this.lastActive = index;
26663 if(!preventViewNotify){
26664 var proxy = new Roo.Element(
26665 this.grid.getRowDom(index)
26667 proxy.addClass('bg-info info');
26669 this.fireEvent("rowselect", this, index, r);
26670 this.fireEvent("selectionchange", this);
26676 * @param {Number} row The index of the row to deselect
26678 deselectRow : function(index, preventViewNotify)
26683 if(this.last == index){
26686 if(this.lastActive == index){
26687 this.lastActive = false;
26690 var r = this.grid.store.getAt(index);
26695 this.selections.remove(r);
26696 //.console.log('deselectRow - record id :' + r.id);
26697 if(!preventViewNotify){
26699 var proxy = new Roo.Element(
26700 this.grid.getRowDom(index)
26702 proxy.removeClass('bg-info info');
26704 this.fireEvent("rowdeselect", this, index);
26705 this.fireEvent("selectionchange", this);
26709 restoreLast : function(){
26711 this.last = this._last;
26716 acceptsNav : function(row, col, cm){
26717 return !cm.isHidden(col) && cm.isCellEditable(col, row);
26721 onEditorKey : function(field, e){
26722 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
26727 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
26729 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
26731 }else if(k == e.ENTER && !e.ctrlKey){
26735 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
26737 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
26739 }else if(k == e.ESC){
26743 g.startEditing(newCell[0], newCell[1]);
26749 * Ext JS Library 1.1.1
26750 * Copyright(c) 2006-2007, Ext JS, LLC.
26752 * Originally Released Under LGPL - original licence link has changed is not relivant.
26755 * <script type="text/javascript">
26759 * @class Roo.bootstrap.PagingToolbar
26760 * @extends Roo.bootstrap.NavSimplebar
26761 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
26763 * Create a new PagingToolbar
26764 * @param {Object} config The config object
26765 * @param {Roo.data.Store} store
26767 Roo.bootstrap.PagingToolbar = function(config)
26769 // old args format still supported... - xtype is prefered..
26770 // created from xtype...
26772 this.ds = config.dataSource;
26774 if (config.store && !this.ds) {
26775 this.store= Roo.factory(config.store, Roo.data);
26776 this.ds = this.store;
26777 this.ds.xmodule = this.xmodule || false;
26780 this.toolbarItems = [];
26781 if (config.items) {
26782 this.toolbarItems = config.items;
26785 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
26790 this.bind(this.ds);
26793 if (Roo.bootstrap.version == 4) {
26794 this.navgroup = new Roo.bootstrap.ButtonGroup({ cls: 'pagination' });
26796 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
26801 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
26803 * @cfg {Roo.data.Store} dataSource
26804 * The underlying data store providing the paged data
26807 * @cfg {String/HTMLElement/Element} container
26808 * container The id or element that will contain the toolbar
26811 * @cfg {Boolean} displayInfo
26812 * True to display the displayMsg (defaults to false)
26815 * @cfg {Number} pageSize
26816 * The number of records to display per page (defaults to 20)
26820 * @cfg {String} displayMsg
26821 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
26823 displayMsg : 'Displaying {0} - {1} of {2}',
26825 * @cfg {String} emptyMsg
26826 * The message to display when no records are found (defaults to "No data to display")
26828 emptyMsg : 'No data to display',
26830 * Customizable piece of the default paging text (defaults to "Page")
26833 beforePageText : "Page",
26835 * Customizable piece of the default paging text (defaults to "of %0")
26838 afterPageText : "of {0}",
26840 * Customizable piece of the default paging text (defaults to "First Page")
26843 firstText : "First Page",
26845 * Customizable piece of the default paging text (defaults to "Previous Page")
26848 prevText : "Previous Page",
26850 * Customizable piece of the default paging text (defaults to "Next Page")
26853 nextText : "Next Page",
26855 * Customizable piece of the default paging text (defaults to "Last Page")
26858 lastText : "Last Page",
26860 * Customizable piece of the default paging text (defaults to "Refresh")
26863 refreshText : "Refresh",
26867 onRender : function(ct, position)
26869 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
26870 this.navgroup.parentId = this.id;
26871 this.navgroup.onRender(this.el, null);
26872 // add the buttons to the navgroup
26874 if(this.displayInfo){
26875 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
26876 this.displayEl = this.el.select('.x-paging-info', true).first();
26877 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
26878 // this.displayEl = navel.el.select('span',true).first();
26884 Roo.each(_this.buttons, function(e){ // this might need to use render????
26885 Roo.factory(e).render(_this.el);
26889 Roo.each(_this.toolbarItems, function(e) {
26890 _this.navgroup.addItem(e);
26894 this.first = this.navgroup.addItem({
26895 tooltip: this.firstText,
26896 cls: "prev btn-outline-secondary",
26897 html : ' <i class="fa fa-step-backward"></i>',
26899 preventDefault: true,
26900 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
26903 this.prev = this.navgroup.addItem({
26904 tooltip: this.prevText,
26905 cls: "prev btn-outline-secondary",
26906 html : ' <i class="fa fa-backward"></i>',
26908 preventDefault: true,
26909 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
26911 //this.addSeparator();
26914 var field = this.navgroup.addItem( {
26916 cls : 'x-paging-position btn-outline-secondary',
26918 html : this.beforePageText +
26919 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
26920 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
26923 this.field = field.el.select('input', true).first();
26924 this.field.on("keydown", this.onPagingKeydown, this);
26925 this.field.on("focus", function(){this.dom.select();});
26928 this.afterTextEl = field.el.select('.x-paging-after',true).first();
26929 //this.field.setHeight(18);
26930 //this.addSeparator();
26931 this.next = this.navgroup.addItem({
26932 tooltip: this.nextText,
26933 cls: "next btn-outline-secondary",
26934 html : ' <i class="fa fa-forward"></i>',
26936 preventDefault: true,
26937 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
26939 this.last = this.navgroup.addItem({
26940 tooltip: this.lastText,
26941 html : ' <i class="fa fa-step-forward"></i>',
26942 cls: "next btn-outline-secondary",
26944 preventDefault: true,
26945 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
26947 //this.addSeparator();
26948 this.loading = this.navgroup.addItem({
26949 tooltip: this.refreshText,
26950 cls: "btn-outline-secondary",
26951 html : ' <i class="fa fa-refresh"></i>',
26952 preventDefault: true,
26953 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
26959 updateInfo : function(){
26960 if(this.displayEl){
26961 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
26962 var msg = count == 0 ?
26966 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
26968 this.displayEl.update(msg);
26973 onLoad : function(ds, r, o)
26975 this.cursor = o.params.start ? o.params.start : 0;
26977 var d = this.getPageData(),
26982 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
26983 this.field.dom.value = ap;
26984 this.first.setDisabled(ap == 1);
26985 this.prev.setDisabled(ap == 1);
26986 this.next.setDisabled(ap == ps);
26987 this.last.setDisabled(ap == ps);
26988 this.loading.enable();
26993 getPageData : function(){
26994 var total = this.ds.getTotalCount();
26997 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
26998 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
27003 onLoadError : function(){
27004 this.loading.enable();
27008 onPagingKeydown : function(e){
27009 var k = e.getKey();
27010 var d = this.getPageData();
27012 var v = this.field.dom.value, pageNum;
27013 if(!v || isNaN(pageNum = parseInt(v, 10))){
27014 this.field.dom.value = d.activePage;
27017 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
27018 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
27021 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))
27023 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
27024 this.field.dom.value = pageNum;
27025 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
27028 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
27030 var v = this.field.dom.value, pageNum;
27031 var increment = (e.shiftKey) ? 10 : 1;
27032 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
27035 if(!v || isNaN(pageNum = parseInt(v, 10))) {
27036 this.field.dom.value = d.activePage;
27039 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
27041 this.field.dom.value = parseInt(v, 10) + increment;
27042 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
27043 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
27050 beforeLoad : function(){
27052 this.loading.disable();
27057 onClick : function(which){
27066 ds.load({params:{start: 0, limit: this.pageSize}});
27069 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
27072 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
27075 var total = ds.getTotalCount();
27076 var extra = total % this.pageSize;
27077 var lastStart = extra ? (total - extra) : total-this.pageSize;
27078 ds.load({params:{start: lastStart, limit: this.pageSize}});
27081 ds.load({params:{start: this.cursor, limit: this.pageSize}});
27087 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
27088 * @param {Roo.data.Store} store The data store to unbind
27090 unbind : function(ds){
27091 ds.un("beforeload", this.beforeLoad, this);
27092 ds.un("load", this.onLoad, this);
27093 ds.un("loadexception", this.onLoadError, this);
27094 ds.un("remove", this.updateInfo, this);
27095 ds.un("add", this.updateInfo, this);
27096 this.ds = undefined;
27100 * Binds the paging toolbar to the specified {@link Roo.data.Store}
27101 * @param {Roo.data.Store} store The data store to bind
27103 bind : function(ds){
27104 ds.on("beforeload", this.beforeLoad, this);
27105 ds.on("load", this.onLoad, this);
27106 ds.on("loadexception", this.onLoadError, this);
27107 ds.on("remove", this.updateInfo, this);
27108 ds.on("add", this.updateInfo, this);
27119 * @class Roo.bootstrap.MessageBar
27120 * @extends Roo.bootstrap.Component
27121 * Bootstrap MessageBar class
27122 * @cfg {String} html contents of the MessageBar
27123 * @cfg {String} weight (info | success | warning | danger) default info
27124 * @cfg {String} beforeClass insert the bar before the given class
27125 * @cfg {Boolean} closable (true | false) default false
27126 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
27129 * Create a new Element
27130 * @param {Object} config The config object
27133 Roo.bootstrap.MessageBar = function(config){
27134 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
27137 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
27143 beforeClass: 'bootstrap-sticky-wrap',
27145 getAutoCreate : function(){
27149 cls: 'alert alert-dismissable alert-' + this.weight,
27154 html: this.html || ''
27160 cfg.cls += ' alert-messages-fixed';
27174 onRender : function(ct, position)
27176 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
27179 var cfg = Roo.apply({}, this.getAutoCreate());
27183 cfg.cls += ' ' + this.cls;
27186 cfg.style = this.style;
27188 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
27190 this.el.setVisibilityMode(Roo.Element.DISPLAY);
27193 this.el.select('>button.close').on('click', this.hide, this);
27199 if (!this.rendered) {
27205 this.fireEvent('show', this);
27211 if (!this.rendered) {
27217 this.fireEvent('hide', this);
27220 update : function()
27222 // var e = this.el.dom.firstChild;
27224 // if(this.closable){
27225 // e = e.nextSibling;
27228 // e.data = this.html || '';
27230 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
27246 * @class Roo.bootstrap.Graph
27247 * @extends Roo.bootstrap.Component
27248 * Bootstrap Graph class
27252 @cfg {String} graphtype bar | vbar | pie
27253 @cfg {number} g_x coodinator | centre x (pie)
27254 @cfg {number} g_y coodinator | centre y (pie)
27255 @cfg {number} g_r radius (pie)
27256 @cfg {number} g_height height of the chart (respected by all elements in the set)
27257 @cfg {number} g_width width of the chart (respected by all elements in the set)
27258 @cfg {Object} title The title of the chart
27261 -opts (object) options for the chart
27263 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
27264 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
27266 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.
27267 o stacked (boolean) whether or not to tread values as in a stacked bar chart
27269 o stretch (boolean)
27271 -opts (object) options for the pie
27274 o startAngle (number)
27275 o endAngle (number)
27279 * Create a new Input
27280 * @param {Object} config The config object
27283 Roo.bootstrap.Graph = function(config){
27284 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
27290 * The img click event for the img.
27291 * @param {Roo.EventObject} e
27297 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
27308 //g_colors: this.colors,
27315 getAutoCreate : function(){
27326 onRender : function(ct,position){
27329 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
27331 if (typeof(Raphael) == 'undefined') {
27332 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
27336 this.raphael = Raphael(this.el.dom);
27338 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
27339 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
27340 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
27341 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
27343 r.text(160, 10, "Single Series Chart").attr(txtattr);
27344 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
27345 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
27346 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
27348 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
27349 r.barchart(330, 10, 300, 220, data1);
27350 r.barchart(10, 250, 300, 220, data2, {stacked: true});
27351 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
27354 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
27355 // r.barchart(30, 30, 560, 250, xdata, {
27356 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
27357 // axis : "0 0 1 1",
27358 // axisxlabels : xdata
27359 // //yvalues : cols,
27362 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
27364 // this.load(null,xdata,{
27365 // axis : "0 0 1 1",
27366 // axisxlabels : xdata
27371 load : function(graphtype,xdata,opts)
27373 this.raphael.clear();
27375 graphtype = this.graphtype;
27380 var r = this.raphael,
27381 fin = function () {
27382 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
27384 fout = function () {
27385 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
27387 pfin = function() {
27388 this.sector.stop();
27389 this.sector.scale(1.1, 1.1, this.cx, this.cy);
27392 this.label[0].stop();
27393 this.label[0].attr({ r: 7.5 });
27394 this.label[1].attr({ "font-weight": 800 });
27397 pfout = function() {
27398 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
27401 this.label[0].animate({ r: 5 }, 500, "bounce");
27402 this.label[1].attr({ "font-weight": 400 });
27408 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
27411 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
27414 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
27415 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
27417 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
27424 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
27429 setTitle: function(o)
27434 initEvents: function() {
27437 this.el.on('click', this.onClick, this);
27441 onClick : function(e)
27443 Roo.log('img onclick');
27444 this.fireEvent('click', this, e);
27456 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
27459 * @class Roo.bootstrap.dash.NumberBox
27460 * @extends Roo.bootstrap.Component
27461 * Bootstrap NumberBox class
27462 * @cfg {String} headline Box headline
27463 * @cfg {String} content Box content
27464 * @cfg {String} icon Box icon
27465 * @cfg {String} footer Footer text
27466 * @cfg {String} fhref Footer href
27469 * Create a new NumberBox
27470 * @param {Object} config The config object
27474 Roo.bootstrap.dash.NumberBox = function(config){
27475 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
27479 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
27488 getAutoCreate : function(){
27492 cls : 'small-box ',
27500 cls : 'roo-headline',
27501 html : this.headline
27505 cls : 'roo-content',
27506 html : this.content
27520 cls : 'ion ' + this.icon
27529 cls : 'small-box-footer',
27530 href : this.fhref || '#',
27534 cfg.cn.push(footer);
27541 onRender : function(ct,position){
27542 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
27549 setHeadline: function (value)
27551 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
27554 setFooter: function (value, href)
27556 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
27559 this.el.select('a.small-box-footer',true).first().attr('href', href);
27564 setContent: function (value)
27566 this.el.select('.roo-content',true).first().dom.innerHTML = value;
27569 initEvents: function()
27583 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
27586 * @class Roo.bootstrap.dash.TabBox
27587 * @extends Roo.bootstrap.Component
27588 * Bootstrap TabBox class
27589 * @cfg {String} title Title of the TabBox
27590 * @cfg {String} icon Icon of the TabBox
27591 * @cfg {Boolean} showtabs (true|false) show the tabs default true
27592 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
27595 * Create a new TabBox
27596 * @param {Object} config The config object
27600 Roo.bootstrap.dash.TabBox = function(config){
27601 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
27606 * When a pane is added
27607 * @param {Roo.bootstrap.dash.TabPane} pane
27611 * @event activatepane
27612 * When a pane is activated
27613 * @param {Roo.bootstrap.dash.TabPane} pane
27615 "activatepane" : true
27623 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
27628 tabScrollable : false,
27630 getChildContainer : function()
27632 return this.el.select('.tab-content', true).first();
27635 getAutoCreate : function(){
27639 cls: 'pull-left header',
27647 cls: 'fa ' + this.icon
27653 cls: 'nav nav-tabs pull-right',
27659 if(this.tabScrollable){
27666 cls: 'nav nav-tabs pull-right',
27677 cls: 'nav-tabs-custom',
27682 cls: 'tab-content no-padding',
27690 initEvents : function()
27692 //Roo.log('add add pane handler');
27693 this.on('addpane', this.onAddPane, this);
27696 * Updates the box title
27697 * @param {String} html to set the title to.
27699 setTitle : function(value)
27701 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
27703 onAddPane : function(pane)
27705 this.panes.push(pane);
27706 //Roo.log('addpane');
27708 // tabs are rendere left to right..
27709 if(!this.showtabs){
27713 var ctr = this.el.select('.nav-tabs', true).first();
27716 var existing = ctr.select('.nav-tab',true);
27717 var qty = existing.getCount();;
27720 var tab = ctr.createChild({
27722 cls : 'nav-tab' + (qty ? '' : ' active'),
27730 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
27733 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
27735 pane.el.addClass('active');
27740 onTabClick : function(ev,un,ob,pane)
27742 //Roo.log('tab - prev default');
27743 ev.preventDefault();
27746 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
27747 pane.tab.addClass('active');
27748 //Roo.log(pane.title);
27749 this.getChildContainer().select('.tab-pane',true).removeClass('active');
27750 // technically we should have a deactivate event.. but maybe add later.
27751 // and it should not de-activate the selected tab...
27752 this.fireEvent('activatepane', pane);
27753 pane.el.addClass('active');
27754 pane.fireEvent('activate');
27759 getActivePane : function()
27762 Roo.each(this.panes, function(p) {
27763 if(p.el.hasClass('active')){
27784 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
27786 * @class Roo.bootstrap.TabPane
27787 * @extends Roo.bootstrap.Component
27788 * Bootstrap TabPane class
27789 * @cfg {Boolean} active (false | true) Default false
27790 * @cfg {String} title title of panel
27794 * Create a new TabPane
27795 * @param {Object} config The config object
27798 Roo.bootstrap.dash.TabPane = function(config){
27799 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
27805 * When a pane is activated
27806 * @param {Roo.bootstrap.dash.TabPane} pane
27813 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
27818 // the tabBox that this is attached to.
27821 getAutoCreate : function()
27829 cfg.cls += ' active';
27834 initEvents : function()
27836 //Roo.log('trigger add pane handler');
27837 this.parent().fireEvent('addpane', this)
27841 * Updates the tab title
27842 * @param {String} html to set the title to.
27844 setTitle: function(str)
27850 this.tab.select('a', true).first().dom.innerHTML = str;
27867 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
27870 * @class Roo.bootstrap.menu.Menu
27871 * @extends Roo.bootstrap.Component
27872 * Bootstrap Menu class - container for Menu
27873 * @cfg {String} html Text of the menu
27874 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
27875 * @cfg {String} icon Font awesome icon
27876 * @cfg {String} pos Menu align to (top | bottom) default bottom
27880 * Create a new Menu
27881 * @param {Object} config The config object
27885 Roo.bootstrap.menu.Menu = function(config){
27886 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
27890 * @event beforeshow
27891 * Fires before this menu is displayed
27892 * @param {Roo.bootstrap.menu.Menu} this
27896 * @event beforehide
27897 * Fires before this menu is hidden
27898 * @param {Roo.bootstrap.menu.Menu} this
27903 * Fires after this menu is displayed
27904 * @param {Roo.bootstrap.menu.Menu} this
27909 * Fires after this menu is hidden
27910 * @param {Roo.bootstrap.menu.Menu} this
27915 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
27916 * @param {Roo.bootstrap.menu.Menu} this
27917 * @param {Roo.EventObject} e
27924 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
27928 weight : 'default',
27933 getChildContainer : function() {
27934 if(this.isSubMenu){
27938 return this.el.select('ul.dropdown-menu', true).first();
27941 getAutoCreate : function()
27946 cls : 'roo-menu-text',
27954 cls : 'fa ' + this.icon
27965 cls : 'dropdown-button btn btn-' + this.weight,
27970 cls : 'dropdown-toggle btn btn-' + this.weight,
27980 cls : 'dropdown-menu'
27986 if(this.pos == 'top'){
27987 cfg.cls += ' dropup';
27990 if(this.isSubMenu){
27993 cls : 'dropdown-menu'
28000 onRender : function(ct, position)
28002 this.isSubMenu = ct.hasClass('dropdown-submenu');
28004 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
28007 initEvents : function()
28009 if(this.isSubMenu){
28013 this.hidden = true;
28015 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
28016 this.triggerEl.on('click', this.onTriggerPress, this);
28018 this.buttonEl = this.el.select('button.dropdown-button', true).first();
28019 this.buttonEl.on('click', this.onClick, this);
28025 if(this.isSubMenu){
28029 return this.el.select('ul.dropdown-menu', true).first();
28032 onClick : function(e)
28034 this.fireEvent("click", this, e);
28037 onTriggerPress : function(e)
28039 if (this.isVisible()) {
28046 isVisible : function(){
28047 return !this.hidden;
28052 this.fireEvent("beforeshow", this);
28054 this.hidden = false;
28055 this.el.addClass('open');
28057 Roo.get(document).on("mouseup", this.onMouseUp, this);
28059 this.fireEvent("show", this);
28066 this.fireEvent("beforehide", this);
28068 this.hidden = true;
28069 this.el.removeClass('open');
28071 Roo.get(document).un("mouseup", this.onMouseUp);
28073 this.fireEvent("hide", this);
28076 onMouseUp : function()
28090 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
28093 * @class Roo.bootstrap.menu.Item
28094 * @extends Roo.bootstrap.Component
28095 * Bootstrap MenuItem class
28096 * @cfg {Boolean} submenu (true | false) default false
28097 * @cfg {String} html text of the item
28098 * @cfg {String} href the link
28099 * @cfg {Boolean} disable (true | false) default false
28100 * @cfg {Boolean} preventDefault (true | false) default true
28101 * @cfg {String} icon Font awesome icon
28102 * @cfg {String} pos Submenu align to (left | right) default right
28106 * Create a new Item
28107 * @param {Object} config The config object
28111 Roo.bootstrap.menu.Item = function(config){
28112 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
28116 * Fires when the mouse is hovering over this menu
28117 * @param {Roo.bootstrap.menu.Item} this
28118 * @param {Roo.EventObject} e
28123 * Fires when the mouse exits this menu
28124 * @param {Roo.bootstrap.menu.Item} this
28125 * @param {Roo.EventObject} e
28131 * The raw click event for the entire grid.
28132 * @param {Roo.EventObject} e
28138 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
28143 preventDefault: true,
28148 getAutoCreate : function()
28153 cls : 'roo-menu-item-text',
28161 cls : 'fa ' + this.icon
28170 href : this.href || '#',
28177 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
28181 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
28183 if(this.pos == 'left'){
28184 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
28191 initEvents : function()
28193 this.el.on('mouseover', this.onMouseOver, this);
28194 this.el.on('mouseout', this.onMouseOut, this);
28196 this.el.select('a', true).first().on('click', this.onClick, this);
28200 onClick : function(e)
28202 if(this.preventDefault){
28203 e.preventDefault();
28206 this.fireEvent("click", this, e);
28209 onMouseOver : function(e)
28211 if(this.submenu && this.pos == 'left'){
28212 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
28215 this.fireEvent("mouseover", this, e);
28218 onMouseOut : function(e)
28220 this.fireEvent("mouseout", this, e);
28232 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
28235 * @class Roo.bootstrap.menu.Separator
28236 * @extends Roo.bootstrap.Component
28237 * Bootstrap Separator class
28240 * Create a new Separator
28241 * @param {Object} config The config object
28245 Roo.bootstrap.menu.Separator = function(config){
28246 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
28249 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
28251 getAutoCreate : function(){
28272 * @class Roo.bootstrap.Tooltip
28273 * Bootstrap Tooltip class
28274 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
28275 * to determine which dom element triggers the tooltip.
28277 * It needs to add support for additional attributes like tooltip-position
28280 * Create a new Toolti
28281 * @param {Object} config The config object
28284 Roo.bootstrap.Tooltip = function(config){
28285 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
28287 this.alignment = Roo.bootstrap.Tooltip.alignment;
28289 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
28290 this.alignment = config.alignment;
28295 Roo.apply(Roo.bootstrap.Tooltip, {
28297 * @function init initialize tooltip monitoring.
28301 currentTip : false,
28302 currentRegion : false,
28308 Roo.get(document).on('mouseover', this.enter ,this);
28309 Roo.get(document).on('mouseout', this.leave, this);
28312 this.currentTip = new Roo.bootstrap.Tooltip();
28315 enter : function(ev)
28317 var dom = ev.getTarget();
28319 //Roo.log(['enter',dom]);
28320 var el = Roo.fly(dom);
28321 if (this.currentEl) {
28323 //Roo.log(this.currentEl);
28324 //Roo.log(this.currentEl.contains(dom));
28325 if (this.currentEl == el) {
28328 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
28334 if (this.currentTip.el) {
28335 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
28339 if(!el || el.dom == document){
28345 // you can not look for children, as if el is the body.. then everythign is the child..
28346 if (!el.attr('tooltip')) { //
28347 if (!el.select("[tooltip]").elements.length) {
28350 // is the mouse over this child...?
28351 bindEl = el.select("[tooltip]").first();
28352 var xy = ev.getXY();
28353 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
28354 //Roo.log("not in region.");
28357 //Roo.log("child element over..");
28360 this.currentEl = bindEl;
28361 this.currentTip.bind(bindEl);
28362 this.currentRegion = Roo.lib.Region.getRegion(dom);
28363 this.currentTip.enter();
28366 leave : function(ev)
28368 var dom = ev.getTarget();
28369 //Roo.log(['leave',dom]);
28370 if (!this.currentEl) {
28375 if (dom != this.currentEl.dom) {
28378 var xy = ev.getXY();
28379 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
28382 // only activate leave if mouse cursor is outside... bounding box..
28387 if (this.currentTip) {
28388 this.currentTip.leave();
28390 //Roo.log('clear currentEl');
28391 this.currentEl = false;
28396 'left' : ['r-l', [-2,0], 'right'],
28397 'right' : ['l-r', [2,0], 'left'],
28398 'bottom' : ['t-b', [0,2], 'top'],
28399 'top' : [ 'b-t', [0,-2], 'bottom']
28405 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
28410 delay : null, // can be { show : 300 , hide: 500}
28414 hoverState : null, //???
28416 placement : 'bottom',
28420 getAutoCreate : function(){
28427 cls : 'tooltip-arrow arrow'
28430 cls : 'tooltip-inner'
28437 bind : function(el)
28442 initEvents : function()
28444 this.arrowEl = this.el.select('.arrow', true).first();
28445 this.innerEl = this.el.select('.tooltip-inner', true).first();
28448 enter : function () {
28450 if (this.timeout != null) {
28451 clearTimeout(this.timeout);
28454 this.hoverState = 'in';
28455 //Roo.log("enter - show");
28456 if (!this.delay || !this.delay.show) {
28461 this.timeout = setTimeout(function () {
28462 if (_t.hoverState == 'in') {
28465 }, this.delay.show);
28469 clearTimeout(this.timeout);
28471 this.hoverState = 'out';
28472 if (!this.delay || !this.delay.hide) {
28478 this.timeout = setTimeout(function () {
28479 //Roo.log("leave - timeout");
28481 if (_t.hoverState == 'out') {
28483 Roo.bootstrap.Tooltip.currentEl = false;
28488 show : function (msg)
28491 this.render(document.body);
28494 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
28496 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
28498 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
28500 this.el.removeClass(['fade','top','bottom', 'left', 'right','in',
28501 'bs-tooltip-top','bs-tooltip-bottom', 'bs-tooltip-left', 'bs-tooltip-right']);
28503 var placement = typeof this.placement == 'function' ?
28504 this.placement.call(this, this.el, on_el) :
28507 var autoToken = /\s?auto?\s?/i;
28508 var autoPlace = autoToken.test(placement);
28510 placement = placement.replace(autoToken, '') || 'top';
28514 //this.el.setXY([0,0]);
28516 //this.el.dom.style.display='block';
28518 //this.el.appendTo(on_el);
28520 var p = this.getPosition();
28521 var box = this.el.getBox();
28527 var align = this.alignment[placement];
28529 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
28531 if(placement == 'top' || placement == 'bottom'){
28533 placement = 'right';
28536 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
28537 placement = 'left';
28540 var scroll = Roo.select('body', true).first().getScroll();
28542 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
28546 align = this.alignment[placement];
28548 this.arrowEl.setLeft((this.innerEl.getWidth()/2) - 5);
28552 this.el.alignTo(this.bindEl, align[0],align[1]);
28553 //var arrow = this.el.select('.arrow',true).first();
28554 //arrow.set(align[2],
28556 this.el.addClass(placement);
28557 this.el.addClass("bs-tooltip-"+ placement);
28559 this.el.addClass('in fade show');
28561 this.hoverState = null;
28563 if (this.el.hasClass('fade')) {
28578 //this.el.setXY([0,0]);
28579 this.el.removeClass(['show', 'in']);
28595 * @class Roo.bootstrap.LocationPicker
28596 * @extends Roo.bootstrap.Component
28597 * Bootstrap LocationPicker class
28598 * @cfg {Number} latitude Position when init default 0
28599 * @cfg {Number} longitude Position when init default 0
28600 * @cfg {Number} zoom default 15
28601 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
28602 * @cfg {Boolean} mapTypeControl default false
28603 * @cfg {Boolean} disableDoubleClickZoom default false
28604 * @cfg {Boolean} scrollwheel default true
28605 * @cfg {Boolean} streetViewControl default false
28606 * @cfg {Number} radius default 0
28607 * @cfg {String} locationName
28608 * @cfg {Boolean} draggable default true
28609 * @cfg {Boolean} enableAutocomplete default false
28610 * @cfg {Boolean} enableReverseGeocode default true
28611 * @cfg {String} markerTitle
28614 * Create a new LocationPicker
28615 * @param {Object} config The config object
28619 Roo.bootstrap.LocationPicker = function(config){
28621 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
28626 * Fires when the picker initialized.
28627 * @param {Roo.bootstrap.LocationPicker} this
28628 * @param {Google Location} location
28632 * @event positionchanged
28633 * Fires when the picker position changed.
28634 * @param {Roo.bootstrap.LocationPicker} this
28635 * @param {Google Location} location
28637 positionchanged : true,
28640 * Fires when the map resize.
28641 * @param {Roo.bootstrap.LocationPicker} this
28646 * Fires when the map show.
28647 * @param {Roo.bootstrap.LocationPicker} this
28652 * Fires when the map hide.
28653 * @param {Roo.bootstrap.LocationPicker} this
28658 * Fires when click the map.
28659 * @param {Roo.bootstrap.LocationPicker} this
28660 * @param {Map event} e
28664 * @event mapRightClick
28665 * Fires when right click the map.
28666 * @param {Roo.bootstrap.LocationPicker} this
28667 * @param {Map event} e
28669 mapRightClick : true,
28671 * @event markerClick
28672 * Fires when click the marker.
28673 * @param {Roo.bootstrap.LocationPicker} this
28674 * @param {Map event} e
28676 markerClick : true,
28678 * @event markerRightClick
28679 * Fires when right click the marker.
28680 * @param {Roo.bootstrap.LocationPicker} this
28681 * @param {Map event} e
28683 markerRightClick : true,
28685 * @event OverlayViewDraw
28686 * Fires when OverlayView Draw
28687 * @param {Roo.bootstrap.LocationPicker} this
28689 OverlayViewDraw : true,
28691 * @event OverlayViewOnAdd
28692 * Fires when OverlayView Draw
28693 * @param {Roo.bootstrap.LocationPicker} this
28695 OverlayViewOnAdd : true,
28697 * @event OverlayViewOnRemove
28698 * Fires when OverlayView Draw
28699 * @param {Roo.bootstrap.LocationPicker} this
28701 OverlayViewOnRemove : true,
28703 * @event OverlayViewShow
28704 * Fires when OverlayView Draw
28705 * @param {Roo.bootstrap.LocationPicker} this
28706 * @param {Pixel} cpx
28708 OverlayViewShow : true,
28710 * @event OverlayViewHide
28711 * Fires when OverlayView Draw
28712 * @param {Roo.bootstrap.LocationPicker} this
28714 OverlayViewHide : true,
28716 * @event loadexception
28717 * Fires when load google lib failed.
28718 * @param {Roo.bootstrap.LocationPicker} this
28720 loadexception : true
28725 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
28727 gMapContext: false,
28733 mapTypeControl: false,
28734 disableDoubleClickZoom: false,
28736 streetViewControl: false,
28740 enableAutocomplete: false,
28741 enableReverseGeocode: true,
28744 getAutoCreate: function()
28749 cls: 'roo-location-picker'
28755 initEvents: function(ct, position)
28757 if(!this.el.getWidth() || this.isApplied()){
28761 this.el.setVisibilityMode(Roo.Element.DISPLAY);
28766 initial: function()
28768 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
28769 this.fireEvent('loadexception', this);
28773 if(!this.mapTypeId){
28774 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
28777 this.gMapContext = this.GMapContext();
28779 this.initOverlayView();
28781 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
28785 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
28786 _this.setPosition(_this.gMapContext.marker.position);
28789 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
28790 _this.fireEvent('mapClick', this, event);
28794 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
28795 _this.fireEvent('mapRightClick', this, event);
28799 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
28800 _this.fireEvent('markerClick', this, event);
28804 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
28805 _this.fireEvent('markerRightClick', this, event);
28809 this.setPosition(this.gMapContext.location);
28811 this.fireEvent('initial', this, this.gMapContext.location);
28814 initOverlayView: function()
28818 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
28822 _this.fireEvent('OverlayViewDraw', _this);
28827 _this.fireEvent('OverlayViewOnAdd', _this);
28830 onRemove: function()
28832 _this.fireEvent('OverlayViewOnRemove', _this);
28835 show: function(cpx)
28837 _this.fireEvent('OverlayViewShow', _this, cpx);
28842 _this.fireEvent('OverlayViewHide', _this);
28848 fromLatLngToContainerPixel: function(event)
28850 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
28853 isApplied: function()
28855 return this.getGmapContext() == false ? false : true;
28858 getGmapContext: function()
28860 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
28863 GMapContext: function()
28865 var position = new google.maps.LatLng(this.latitude, this.longitude);
28867 var _map = new google.maps.Map(this.el.dom, {
28870 mapTypeId: this.mapTypeId,
28871 mapTypeControl: this.mapTypeControl,
28872 disableDoubleClickZoom: this.disableDoubleClickZoom,
28873 scrollwheel: this.scrollwheel,
28874 streetViewControl: this.streetViewControl,
28875 locationName: this.locationName,
28876 draggable: this.draggable,
28877 enableAutocomplete: this.enableAutocomplete,
28878 enableReverseGeocode: this.enableReverseGeocode
28881 var _marker = new google.maps.Marker({
28882 position: position,
28884 title: this.markerTitle,
28885 draggable: this.draggable
28892 location: position,
28893 radius: this.radius,
28894 locationName: this.locationName,
28895 addressComponents: {
28896 formatted_address: null,
28897 addressLine1: null,
28898 addressLine2: null,
28900 streetNumber: null,
28904 stateOrProvince: null
28907 domContainer: this.el.dom,
28908 geodecoder: new google.maps.Geocoder()
28912 drawCircle: function(center, radius, options)
28914 if (this.gMapContext.circle != null) {
28915 this.gMapContext.circle.setMap(null);
28919 options = Roo.apply({}, options, {
28920 strokeColor: "#0000FF",
28921 strokeOpacity: .35,
28923 fillColor: "#0000FF",
28927 options.map = this.gMapContext.map;
28928 options.radius = radius;
28929 options.center = center;
28930 this.gMapContext.circle = new google.maps.Circle(options);
28931 return this.gMapContext.circle;
28937 setPosition: function(location)
28939 this.gMapContext.location = location;
28940 this.gMapContext.marker.setPosition(location);
28941 this.gMapContext.map.panTo(location);
28942 this.drawCircle(location, this.gMapContext.radius, {});
28946 if (this.gMapContext.settings.enableReverseGeocode) {
28947 this.gMapContext.geodecoder.geocode({
28948 latLng: this.gMapContext.location
28949 }, function(results, status) {
28951 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
28952 _this.gMapContext.locationName = results[0].formatted_address;
28953 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
28955 _this.fireEvent('positionchanged', this, location);
28962 this.fireEvent('positionchanged', this, location);
28967 google.maps.event.trigger(this.gMapContext.map, "resize");
28969 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
28971 this.fireEvent('resize', this);
28974 setPositionByLatLng: function(latitude, longitude)
28976 this.setPosition(new google.maps.LatLng(latitude, longitude));
28979 getCurrentPosition: function()
28982 latitude: this.gMapContext.location.lat(),
28983 longitude: this.gMapContext.location.lng()
28987 getAddressName: function()
28989 return this.gMapContext.locationName;
28992 getAddressComponents: function()
28994 return this.gMapContext.addressComponents;
28997 address_component_from_google_geocode: function(address_components)
29001 for (var i = 0; i < address_components.length; i++) {
29002 var component = address_components[i];
29003 if (component.types.indexOf("postal_code") >= 0) {
29004 result.postalCode = component.short_name;
29005 } else if (component.types.indexOf("street_number") >= 0) {
29006 result.streetNumber = component.short_name;
29007 } else if (component.types.indexOf("route") >= 0) {
29008 result.streetName = component.short_name;
29009 } else if (component.types.indexOf("neighborhood") >= 0) {
29010 result.city = component.short_name;
29011 } else if (component.types.indexOf("locality") >= 0) {
29012 result.city = component.short_name;
29013 } else if (component.types.indexOf("sublocality") >= 0) {
29014 result.district = component.short_name;
29015 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
29016 result.stateOrProvince = component.short_name;
29017 } else if (component.types.indexOf("country") >= 0) {
29018 result.country = component.short_name;
29022 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
29023 result.addressLine2 = "";
29027 setZoomLevel: function(zoom)
29029 this.gMapContext.map.setZoom(zoom);
29042 this.fireEvent('show', this);
29053 this.fireEvent('hide', this);
29058 Roo.apply(Roo.bootstrap.LocationPicker, {
29060 OverlayView : function(map, options)
29062 options = options || {};
29069 * @class Roo.bootstrap.Alert
29070 * @extends Roo.bootstrap.Component
29071 * Bootstrap Alert class - shows an alert area box
29073 * <div class="alert alert-danger" role="alert"><span class="fa fa-exclamation-triangle"></span><span class="sr-only">Error:</span>
29074 Enter a valid email address
29077 * @cfg {String} title The title of alert
29078 * @cfg {String} html The content of alert
29079 * @cfg {String} weight ( success | info | warning | danger )
29080 * @cfg {String} faicon font-awesomeicon
29083 * Create a new alert
29084 * @param {Object} config The config object
29088 Roo.bootstrap.Alert = function(config){
29089 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
29093 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
29100 getAutoCreate : function()
29109 cls : 'roo-alert-icon'
29114 cls : 'roo-alert-title',
29119 cls : 'roo-alert-text',
29126 cfg.cn[0].cls += ' fa ' + this.faicon;
29130 cfg.cls += ' alert-' + this.weight;
29136 initEvents: function()
29138 this.el.setVisibilityMode(Roo.Element.DISPLAY);
29141 setTitle : function(str)
29143 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
29146 setText : function(str)
29148 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
29151 setWeight : function(weight)
29154 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
29157 this.weight = weight;
29159 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
29162 setIcon : function(icon)
29165 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
29168 this.faicon = icon;
29170 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
29191 * @class Roo.bootstrap.UploadCropbox
29192 * @extends Roo.bootstrap.Component
29193 * Bootstrap UploadCropbox class
29194 * @cfg {String} emptyText show when image has been loaded
29195 * @cfg {String} rotateNotify show when image too small to rotate
29196 * @cfg {Number} errorTimeout default 3000
29197 * @cfg {Number} minWidth default 300
29198 * @cfg {Number} minHeight default 300
29199 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
29200 * @cfg {Boolean} isDocument (true|false) default false
29201 * @cfg {String} url action url
29202 * @cfg {String} paramName default 'imageUpload'
29203 * @cfg {String} method default POST
29204 * @cfg {Boolean} loadMask (true|false) default true
29205 * @cfg {Boolean} loadingText default 'Loading...'
29208 * Create a new UploadCropbox
29209 * @param {Object} config The config object
29212 Roo.bootstrap.UploadCropbox = function(config){
29213 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
29217 * @event beforeselectfile
29218 * Fire before select file
29219 * @param {Roo.bootstrap.UploadCropbox} this
29221 "beforeselectfile" : true,
29224 * Fire after initEvent
29225 * @param {Roo.bootstrap.UploadCropbox} this
29230 * Fire after initEvent
29231 * @param {Roo.bootstrap.UploadCropbox} this
29232 * @param {String} data
29237 * Fire when preparing the file data
29238 * @param {Roo.bootstrap.UploadCropbox} this
29239 * @param {Object} file
29244 * Fire when get exception
29245 * @param {Roo.bootstrap.UploadCropbox} this
29246 * @param {XMLHttpRequest} xhr
29248 "exception" : true,
29250 * @event beforeloadcanvas
29251 * Fire before load the canvas
29252 * @param {Roo.bootstrap.UploadCropbox} this
29253 * @param {String} src
29255 "beforeloadcanvas" : true,
29258 * Fire when trash image
29259 * @param {Roo.bootstrap.UploadCropbox} this
29264 * Fire when download the image
29265 * @param {Roo.bootstrap.UploadCropbox} this
29269 * @event footerbuttonclick
29270 * Fire when footerbuttonclick
29271 * @param {Roo.bootstrap.UploadCropbox} this
29272 * @param {String} type
29274 "footerbuttonclick" : true,
29278 * @param {Roo.bootstrap.UploadCropbox} this
29283 * Fire when rotate the image
29284 * @param {Roo.bootstrap.UploadCropbox} this
29285 * @param {String} pos
29290 * Fire when inspect the file
29291 * @param {Roo.bootstrap.UploadCropbox} this
29292 * @param {Object} file
29297 * Fire when xhr upload the file
29298 * @param {Roo.bootstrap.UploadCropbox} this
29299 * @param {Object} data
29304 * Fire when arrange the file data
29305 * @param {Roo.bootstrap.UploadCropbox} this
29306 * @param {Object} formData
29311 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
29314 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
29316 emptyText : 'Click to upload image',
29317 rotateNotify : 'Image is too small to rotate',
29318 errorTimeout : 3000,
29332 cropType : 'image/jpeg',
29334 canvasLoaded : false,
29335 isDocument : false,
29337 paramName : 'imageUpload',
29339 loadingText : 'Loading...',
29342 getAutoCreate : function()
29346 cls : 'roo-upload-cropbox',
29350 cls : 'roo-upload-cropbox-selector',
29355 cls : 'roo-upload-cropbox-body',
29356 style : 'cursor:pointer',
29360 cls : 'roo-upload-cropbox-preview'
29364 cls : 'roo-upload-cropbox-thumb'
29368 cls : 'roo-upload-cropbox-empty-notify',
29369 html : this.emptyText
29373 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
29374 html : this.rotateNotify
29380 cls : 'roo-upload-cropbox-footer',
29383 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
29393 onRender : function(ct, position)
29395 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
29397 if (this.buttons.length) {
29399 Roo.each(this.buttons, function(bb) {
29401 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
29403 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
29409 this.maskEl = this.el;
29413 initEvents : function()
29415 this.urlAPI = (window.createObjectURL && window) ||
29416 (window.URL && URL.revokeObjectURL && URL) ||
29417 (window.webkitURL && webkitURL);
29419 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
29420 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29422 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
29423 this.selectorEl.hide();
29425 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
29426 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29428 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
29429 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29430 this.thumbEl.hide();
29432 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
29433 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29435 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
29436 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29437 this.errorEl.hide();
29439 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
29440 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29441 this.footerEl.hide();
29443 this.setThumbBoxSize();
29449 this.fireEvent('initial', this);
29456 window.addEventListener("resize", function() { _this.resize(); } );
29458 this.bodyEl.on('click', this.beforeSelectFile, this);
29461 this.bodyEl.on('touchstart', this.onTouchStart, this);
29462 this.bodyEl.on('touchmove', this.onTouchMove, this);
29463 this.bodyEl.on('touchend', this.onTouchEnd, this);
29467 this.bodyEl.on('mousedown', this.onMouseDown, this);
29468 this.bodyEl.on('mousemove', this.onMouseMove, this);
29469 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
29470 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
29471 Roo.get(document).on('mouseup', this.onMouseUp, this);
29474 this.selectorEl.on('change', this.onFileSelected, this);
29480 this.baseScale = 1;
29482 this.baseRotate = 1;
29483 this.dragable = false;
29484 this.pinching = false;
29487 this.cropData = false;
29488 this.notifyEl.dom.innerHTML = this.emptyText;
29490 this.selectorEl.dom.value = '';
29494 resize : function()
29496 if(this.fireEvent('resize', this) != false){
29497 this.setThumbBoxPosition();
29498 this.setCanvasPosition();
29502 onFooterButtonClick : function(e, el, o, type)
29505 case 'rotate-left' :
29506 this.onRotateLeft(e);
29508 case 'rotate-right' :
29509 this.onRotateRight(e);
29512 this.beforeSelectFile(e);
29527 this.fireEvent('footerbuttonclick', this, type);
29530 beforeSelectFile : function(e)
29532 e.preventDefault();
29534 if(this.fireEvent('beforeselectfile', this) != false){
29535 this.selectorEl.dom.click();
29539 onFileSelected : function(e)
29541 e.preventDefault();
29543 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
29547 var file = this.selectorEl.dom.files[0];
29549 if(this.fireEvent('inspect', this, file) != false){
29550 this.prepare(file);
29555 trash : function(e)
29557 this.fireEvent('trash', this);
29560 download : function(e)
29562 this.fireEvent('download', this);
29565 loadCanvas : function(src)
29567 if(this.fireEvent('beforeloadcanvas', this, src) != false){
29571 this.imageEl = document.createElement('img');
29575 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
29577 this.imageEl.src = src;
29581 onLoadCanvas : function()
29583 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
29584 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
29586 this.bodyEl.un('click', this.beforeSelectFile, this);
29588 this.notifyEl.hide();
29589 this.thumbEl.show();
29590 this.footerEl.show();
29592 this.baseRotateLevel();
29594 if(this.isDocument){
29595 this.setThumbBoxSize();
29598 this.setThumbBoxPosition();
29600 this.baseScaleLevel();
29606 this.canvasLoaded = true;
29609 this.maskEl.unmask();
29614 setCanvasPosition : function()
29616 if(!this.canvasEl){
29620 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
29621 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
29623 this.previewEl.setLeft(pw);
29624 this.previewEl.setTop(ph);
29628 onMouseDown : function(e)
29632 this.dragable = true;
29633 this.pinching = false;
29635 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
29636 this.dragable = false;
29640 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
29641 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
29645 onMouseMove : function(e)
29649 if(!this.canvasLoaded){
29653 if (!this.dragable){
29657 var minX = Math.ceil(this.thumbEl.getLeft(true));
29658 var minY = Math.ceil(this.thumbEl.getTop(true));
29660 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
29661 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
29663 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
29664 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
29666 x = x - this.mouseX;
29667 y = y - this.mouseY;
29669 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
29670 var bgY = Math.ceil(y + this.previewEl.getTop(true));
29672 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
29673 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
29675 this.previewEl.setLeft(bgX);
29676 this.previewEl.setTop(bgY);
29678 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
29679 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
29682 onMouseUp : function(e)
29686 this.dragable = false;
29689 onMouseWheel : function(e)
29693 this.startScale = this.scale;
29695 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
29697 if(!this.zoomable()){
29698 this.scale = this.startScale;
29707 zoomable : function()
29709 var minScale = this.thumbEl.getWidth() / this.minWidth;
29711 if(this.minWidth < this.minHeight){
29712 minScale = this.thumbEl.getHeight() / this.minHeight;
29715 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
29716 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
29720 (this.rotate == 0 || this.rotate == 180) &&
29722 width > this.imageEl.OriginWidth ||
29723 height > this.imageEl.OriginHeight ||
29724 (width < this.minWidth && height < this.minHeight)
29732 (this.rotate == 90 || this.rotate == 270) &&
29734 width > this.imageEl.OriginWidth ||
29735 height > this.imageEl.OriginHeight ||
29736 (width < this.minHeight && height < this.minWidth)
29743 !this.isDocument &&
29744 (this.rotate == 0 || this.rotate == 180) &&
29746 width < this.minWidth ||
29747 width > this.imageEl.OriginWidth ||
29748 height < this.minHeight ||
29749 height > this.imageEl.OriginHeight
29756 !this.isDocument &&
29757 (this.rotate == 90 || this.rotate == 270) &&
29759 width < this.minHeight ||
29760 width > this.imageEl.OriginWidth ||
29761 height < this.minWidth ||
29762 height > this.imageEl.OriginHeight
29772 onRotateLeft : function(e)
29774 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
29776 var minScale = this.thumbEl.getWidth() / this.minWidth;
29778 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
29779 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
29781 this.startScale = this.scale;
29783 while (this.getScaleLevel() < minScale){
29785 this.scale = this.scale + 1;
29787 if(!this.zoomable()){
29792 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
29793 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
29798 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
29805 this.scale = this.startScale;
29807 this.onRotateFail();
29812 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
29814 if(this.isDocument){
29815 this.setThumbBoxSize();
29816 this.setThumbBoxPosition();
29817 this.setCanvasPosition();
29822 this.fireEvent('rotate', this, 'left');
29826 onRotateRight : function(e)
29828 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
29830 var minScale = this.thumbEl.getWidth() / this.minWidth;
29832 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
29833 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
29835 this.startScale = this.scale;
29837 while (this.getScaleLevel() < minScale){
29839 this.scale = this.scale + 1;
29841 if(!this.zoomable()){
29846 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
29847 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
29852 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
29859 this.scale = this.startScale;
29861 this.onRotateFail();
29866 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
29868 if(this.isDocument){
29869 this.setThumbBoxSize();
29870 this.setThumbBoxPosition();
29871 this.setCanvasPosition();
29876 this.fireEvent('rotate', this, 'right');
29879 onRotateFail : function()
29881 this.errorEl.show(true);
29885 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
29890 this.previewEl.dom.innerHTML = '';
29892 var canvasEl = document.createElement("canvas");
29894 var contextEl = canvasEl.getContext("2d");
29896 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
29897 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
29898 var center = this.imageEl.OriginWidth / 2;
29900 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
29901 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
29902 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
29903 center = this.imageEl.OriginHeight / 2;
29906 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
29908 contextEl.translate(center, center);
29909 contextEl.rotate(this.rotate * Math.PI / 180);
29911 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
29913 this.canvasEl = document.createElement("canvas");
29915 this.contextEl = this.canvasEl.getContext("2d");
29917 switch (this.rotate) {
29920 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
29921 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
29923 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
29928 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
29929 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
29931 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
29932 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);
29936 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
29941 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
29942 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
29944 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
29945 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);
29949 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);
29954 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
29955 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
29957 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
29958 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
29962 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);
29969 this.previewEl.appendChild(this.canvasEl);
29971 this.setCanvasPosition();
29976 if(!this.canvasLoaded){
29980 var imageCanvas = document.createElement("canvas");
29982 var imageContext = imageCanvas.getContext("2d");
29984 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
29985 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
29987 var center = imageCanvas.width / 2;
29989 imageContext.translate(center, center);
29991 imageContext.rotate(this.rotate * Math.PI / 180);
29993 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
29995 var canvas = document.createElement("canvas");
29997 var context = canvas.getContext("2d");
29999 canvas.width = this.minWidth;
30000 canvas.height = this.minHeight;
30002 switch (this.rotate) {
30005 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
30006 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
30008 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
30009 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
30011 var targetWidth = this.minWidth - 2 * x;
30012 var targetHeight = this.minHeight - 2 * y;
30016 if((x == 0 && y == 0) || (x == 0 && y > 0)){
30017 scale = targetWidth / width;
30020 if(x > 0 && y == 0){
30021 scale = targetHeight / height;
30024 if(x > 0 && y > 0){
30025 scale = targetWidth / width;
30027 if(width < height){
30028 scale = targetHeight / height;
30032 context.scale(scale, scale);
30034 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
30035 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
30037 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
30038 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
30040 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
30045 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
30046 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
30048 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
30049 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
30051 var targetWidth = this.minWidth - 2 * x;
30052 var targetHeight = this.minHeight - 2 * y;
30056 if((x == 0 && y == 0) || (x == 0 && y > 0)){
30057 scale = targetWidth / width;
30060 if(x > 0 && y == 0){
30061 scale = targetHeight / height;
30064 if(x > 0 && y > 0){
30065 scale = targetWidth / width;
30067 if(width < height){
30068 scale = targetHeight / height;
30072 context.scale(scale, scale);
30074 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
30075 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
30077 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
30078 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
30080 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
30082 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
30087 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
30088 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
30090 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
30091 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
30093 var targetWidth = this.minWidth - 2 * x;
30094 var targetHeight = this.minHeight - 2 * y;
30098 if((x == 0 && y == 0) || (x == 0 && y > 0)){
30099 scale = targetWidth / width;
30102 if(x > 0 && y == 0){
30103 scale = targetHeight / height;
30106 if(x > 0 && y > 0){
30107 scale = targetWidth / width;
30109 if(width < height){
30110 scale = targetHeight / height;
30114 context.scale(scale, scale);
30116 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
30117 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
30119 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
30120 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
30122 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
30123 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
30125 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
30130 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
30131 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
30133 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
30134 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
30136 var targetWidth = this.minWidth - 2 * x;
30137 var targetHeight = this.minHeight - 2 * y;
30141 if((x == 0 && y == 0) || (x == 0 && y > 0)){
30142 scale = targetWidth / width;
30145 if(x > 0 && y == 0){
30146 scale = targetHeight / height;
30149 if(x > 0 && y > 0){
30150 scale = targetWidth / width;
30152 if(width < height){
30153 scale = targetHeight / height;
30157 context.scale(scale, scale);
30159 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
30160 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
30162 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
30163 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
30165 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
30167 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
30174 this.cropData = canvas.toDataURL(this.cropType);
30176 if(this.fireEvent('crop', this, this.cropData) !== false){
30177 this.process(this.file, this.cropData);
30184 setThumbBoxSize : function()
30188 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
30189 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
30190 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
30192 this.minWidth = width;
30193 this.minHeight = height;
30195 if(this.rotate == 90 || this.rotate == 270){
30196 this.minWidth = height;
30197 this.minHeight = width;
30202 width = Math.ceil(this.minWidth * height / this.minHeight);
30204 if(this.minWidth > this.minHeight){
30206 height = Math.ceil(this.minHeight * width / this.minWidth);
30209 this.thumbEl.setStyle({
30210 width : width + 'px',
30211 height : height + 'px'
30218 setThumbBoxPosition : function()
30220 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
30221 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
30223 this.thumbEl.setLeft(x);
30224 this.thumbEl.setTop(y);
30228 baseRotateLevel : function()
30230 this.baseRotate = 1;
30233 typeof(this.exif) != 'undefined' &&
30234 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
30235 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
30237 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
30240 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
30244 baseScaleLevel : function()
30248 if(this.isDocument){
30250 if(this.baseRotate == 6 || this.baseRotate == 8){
30252 height = this.thumbEl.getHeight();
30253 this.baseScale = height / this.imageEl.OriginWidth;
30255 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
30256 width = this.thumbEl.getWidth();
30257 this.baseScale = width / this.imageEl.OriginHeight;
30263 height = this.thumbEl.getHeight();
30264 this.baseScale = height / this.imageEl.OriginHeight;
30266 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
30267 width = this.thumbEl.getWidth();
30268 this.baseScale = width / this.imageEl.OriginWidth;
30274 if(this.baseRotate == 6 || this.baseRotate == 8){
30276 width = this.thumbEl.getHeight();
30277 this.baseScale = width / this.imageEl.OriginHeight;
30279 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
30280 height = this.thumbEl.getWidth();
30281 this.baseScale = height / this.imageEl.OriginHeight;
30284 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
30285 height = this.thumbEl.getWidth();
30286 this.baseScale = height / this.imageEl.OriginHeight;
30288 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
30289 width = this.thumbEl.getHeight();
30290 this.baseScale = width / this.imageEl.OriginWidth;
30297 width = this.thumbEl.getWidth();
30298 this.baseScale = width / this.imageEl.OriginWidth;
30300 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
30301 height = this.thumbEl.getHeight();
30302 this.baseScale = height / this.imageEl.OriginHeight;
30305 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
30307 height = this.thumbEl.getHeight();
30308 this.baseScale = height / this.imageEl.OriginHeight;
30310 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
30311 width = this.thumbEl.getWidth();
30312 this.baseScale = width / this.imageEl.OriginWidth;
30320 getScaleLevel : function()
30322 return this.baseScale * Math.pow(1.1, this.scale);
30325 onTouchStart : function(e)
30327 if(!this.canvasLoaded){
30328 this.beforeSelectFile(e);
30332 var touches = e.browserEvent.touches;
30338 if(touches.length == 1){
30339 this.onMouseDown(e);
30343 if(touches.length != 2){
30349 for(var i = 0, finger; finger = touches[i]; i++){
30350 coords.push(finger.pageX, finger.pageY);
30353 var x = Math.pow(coords[0] - coords[2], 2);
30354 var y = Math.pow(coords[1] - coords[3], 2);
30356 this.startDistance = Math.sqrt(x + y);
30358 this.startScale = this.scale;
30360 this.pinching = true;
30361 this.dragable = false;
30365 onTouchMove : function(e)
30367 if(!this.pinching && !this.dragable){
30371 var touches = e.browserEvent.touches;
30378 this.onMouseMove(e);
30384 for(var i = 0, finger; finger = touches[i]; i++){
30385 coords.push(finger.pageX, finger.pageY);
30388 var x = Math.pow(coords[0] - coords[2], 2);
30389 var y = Math.pow(coords[1] - coords[3], 2);
30391 this.endDistance = Math.sqrt(x + y);
30393 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
30395 if(!this.zoomable()){
30396 this.scale = this.startScale;
30404 onTouchEnd : function(e)
30406 this.pinching = false;
30407 this.dragable = false;
30411 process : function(file, crop)
30414 this.maskEl.mask(this.loadingText);
30417 this.xhr = new XMLHttpRequest();
30419 file.xhr = this.xhr;
30421 this.xhr.open(this.method, this.url, true);
30424 "Accept": "application/json",
30425 "Cache-Control": "no-cache",
30426 "X-Requested-With": "XMLHttpRequest"
30429 for (var headerName in headers) {
30430 var headerValue = headers[headerName];
30432 this.xhr.setRequestHeader(headerName, headerValue);
30438 this.xhr.onload = function()
30440 _this.xhrOnLoad(_this.xhr);
30443 this.xhr.onerror = function()
30445 _this.xhrOnError(_this.xhr);
30448 var formData = new FormData();
30450 formData.append('returnHTML', 'NO');
30453 formData.append('crop', crop);
30456 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
30457 formData.append(this.paramName, file, file.name);
30460 if(typeof(file.filename) != 'undefined'){
30461 formData.append('filename', file.filename);
30464 if(typeof(file.mimetype) != 'undefined'){
30465 formData.append('mimetype', file.mimetype);
30468 if(this.fireEvent('arrange', this, formData) != false){
30469 this.xhr.send(formData);
30473 xhrOnLoad : function(xhr)
30476 this.maskEl.unmask();
30479 if (xhr.readyState !== 4) {
30480 this.fireEvent('exception', this, xhr);
30484 var response = Roo.decode(xhr.responseText);
30486 if(!response.success){
30487 this.fireEvent('exception', this, xhr);
30491 var response = Roo.decode(xhr.responseText);
30493 this.fireEvent('upload', this, response);
30497 xhrOnError : function()
30500 this.maskEl.unmask();
30503 Roo.log('xhr on error');
30505 var response = Roo.decode(xhr.responseText);
30511 prepare : function(file)
30514 this.maskEl.mask(this.loadingText);
30520 if(typeof(file) === 'string'){
30521 this.loadCanvas(file);
30525 if(!file || !this.urlAPI){
30530 this.cropType = file.type;
30534 if(this.fireEvent('prepare', this, this.file) != false){
30536 var reader = new FileReader();
30538 reader.onload = function (e) {
30539 if (e.target.error) {
30540 Roo.log(e.target.error);
30544 var buffer = e.target.result,
30545 dataView = new DataView(buffer),
30547 maxOffset = dataView.byteLength - 4,
30551 if (dataView.getUint16(0) === 0xffd8) {
30552 while (offset < maxOffset) {
30553 markerBytes = dataView.getUint16(offset);
30555 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
30556 markerLength = dataView.getUint16(offset + 2) + 2;
30557 if (offset + markerLength > dataView.byteLength) {
30558 Roo.log('Invalid meta data: Invalid segment size.');
30562 if(markerBytes == 0xffe1){
30563 _this.parseExifData(
30570 offset += markerLength;
30580 var url = _this.urlAPI.createObjectURL(_this.file);
30582 _this.loadCanvas(url);
30587 reader.readAsArrayBuffer(this.file);
30593 parseExifData : function(dataView, offset, length)
30595 var tiffOffset = offset + 10,
30599 if (dataView.getUint32(offset + 4) !== 0x45786966) {
30600 // No Exif data, might be XMP data instead
30604 // Check for the ASCII code for "Exif" (0x45786966):
30605 if (dataView.getUint32(offset + 4) !== 0x45786966) {
30606 // No Exif data, might be XMP data instead
30609 if (tiffOffset + 8 > dataView.byteLength) {
30610 Roo.log('Invalid Exif data: Invalid segment size.');
30613 // Check for the two null bytes:
30614 if (dataView.getUint16(offset + 8) !== 0x0000) {
30615 Roo.log('Invalid Exif data: Missing byte alignment offset.');
30618 // Check the byte alignment:
30619 switch (dataView.getUint16(tiffOffset)) {
30621 littleEndian = true;
30624 littleEndian = false;
30627 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
30630 // Check for the TIFF tag marker (0x002A):
30631 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
30632 Roo.log('Invalid Exif data: Missing TIFF marker.');
30635 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
30636 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
30638 this.parseExifTags(
30641 tiffOffset + dirOffset,
30646 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
30651 if (dirOffset + 6 > dataView.byteLength) {
30652 Roo.log('Invalid Exif data: Invalid directory offset.');
30655 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
30656 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
30657 if (dirEndOffset + 4 > dataView.byteLength) {
30658 Roo.log('Invalid Exif data: Invalid directory size.');
30661 for (i = 0; i < tagsNumber; i += 1) {
30665 dirOffset + 2 + 12 * i, // tag offset
30669 // Return the offset to the next directory:
30670 return dataView.getUint32(dirEndOffset, littleEndian);
30673 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
30675 var tag = dataView.getUint16(offset, littleEndian);
30677 this.exif[tag] = this.getExifValue(
30681 dataView.getUint16(offset + 2, littleEndian), // tag type
30682 dataView.getUint32(offset + 4, littleEndian), // tag length
30687 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
30689 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
30698 Roo.log('Invalid Exif data: Invalid tag type.');
30702 tagSize = tagType.size * length;
30703 // Determine if the value is contained in the dataOffset bytes,
30704 // or if the value at the dataOffset is a pointer to the actual data:
30705 dataOffset = tagSize > 4 ?
30706 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
30707 if (dataOffset + tagSize > dataView.byteLength) {
30708 Roo.log('Invalid Exif data: Invalid data offset.');
30711 if (length === 1) {
30712 return tagType.getValue(dataView, dataOffset, littleEndian);
30715 for (i = 0; i < length; i += 1) {
30716 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
30719 if (tagType.ascii) {
30721 // Concatenate the chars:
30722 for (i = 0; i < values.length; i += 1) {
30724 // Ignore the terminating NULL byte(s):
30725 if (c === '\u0000') {
30737 Roo.apply(Roo.bootstrap.UploadCropbox, {
30739 'Orientation': 0x0112
30743 1: 0, //'top-left',
30745 3: 180, //'bottom-right',
30746 // 4: 'bottom-left',
30748 6: 90, //'right-top',
30749 // 7: 'right-bottom',
30750 8: 270 //'left-bottom'
30754 // byte, 8-bit unsigned int:
30756 getValue: function (dataView, dataOffset) {
30757 return dataView.getUint8(dataOffset);
30761 // ascii, 8-bit byte:
30763 getValue: function (dataView, dataOffset) {
30764 return String.fromCharCode(dataView.getUint8(dataOffset));
30769 // short, 16 bit int:
30771 getValue: function (dataView, dataOffset, littleEndian) {
30772 return dataView.getUint16(dataOffset, littleEndian);
30776 // long, 32 bit int:
30778 getValue: function (dataView, dataOffset, littleEndian) {
30779 return dataView.getUint32(dataOffset, littleEndian);
30783 // rational = two long values, first is numerator, second is denominator:
30785 getValue: function (dataView, dataOffset, littleEndian) {
30786 return dataView.getUint32(dataOffset, littleEndian) /
30787 dataView.getUint32(dataOffset + 4, littleEndian);
30791 // slong, 32 bit signed int:
30793 getValue: function (dataView, dataOffset, littleEndian) {
30794 return dataView.getInt32(dataOffset, littleEndian);
30798 // srational, two slongs, first is numerator, second is denominator:
30800 getValue: function (dataView, dataOffset, littleEndian) {
30801 return dataView.getInt32(dataOffset, littleEndian) /
30802 dataView.getInt32(dataOffset + 4, littleEndian);
30812 cls : 'btn-group roo-upload-cropbox-rotate-left',
30813 action : 'rotate-left',
30817 cls : 'btn btn-default',
30818 html : '<i class="fa fa-undo"></i>'
30824 cls : 'btn-group roo-upload-cropbox-picture',
30825 action : 'picture',
30829 cls : 'btn btn-default',
30830 html : '<i class="fa fa-picture-o"></i>'
30836 cls : 'btn-group roo-upload-cropbox-rotate-right',
30837 action : 'rotate-right',
30841 cls : 'btn btn-default',
30842 html : '<i class="fa fa-repeat"></i>'
30850 cls : 'btn-group roo-upload-cropbox-rotate-left',
30851 action : 'rotate-left',
30855 cls : 'btn btn-default',
30856 html : '<i class="fa fa-undo"></i>'
30862 cls : 'btn-group roo-upload-cropbox-download',
30863 action : 'download',
30867 cls : 'btn btn-default',
30868 html : '<i class="fa fa-download"></i>'
30874 cls : 'btn-group roo-upload-cropbox-crop',
30879 cls : 'btn btn-default',
30880 html : '<i class="fa fa-crop"></i>'
30886 cls : 'btn-group roo-upload-cropbox-trash',
30891 cls : 'btn btn-default',
30892 html : '<i class="fa fa-trash"></i>'
30898 cls : 'btn-group roo-upload-cropbox-rotate-right',
30899 action : 'rotate-right',
30903 cls : 'btn btn-default',
30904 html : '<i class="fa fa-repeat"></i>'
30912 cls : 'btn-group roo-upload-cropbox-rotate-left',
30913 action : 'rotate-left',
30917 cls : 'btn btn-default',
30918 html : '<i class="fa fa-undo"></i>'
30924 cls : 'btn-group roo-upload-cropbox-rotate-right',
30925 action : 'rotate-right',
30929 cls : 'btn btn-default',
30930 html : '<i class="fa fa-repeat"></i>'
30943 * @class Roo.bootstrap.DocumentManager
30944 * @extends Roo.bootstrap.Component
30945 * Bootstrap DocumentManager class
30946 * @cfg {String} paramName default 'imageUpload'
30947 * @cfg {String} toolTipName default 'filename'
30948 * @cfg {String} method default POST
30949 * @cfg {String} url action url
30950 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
30951 * @cfg {Boolean} multiple multiple upload default true
30952 * @cfg {Number} thumbSize default 300
30953 * @cfg {String} fieldLabel
30954 * @cfg {Number} labelWidth default 4
30955 * @cfg {String} labelAlign (left|top) default left
30956 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
30957 * @cfg {Number} labellg set the width of label (1-12)
30958 * @cfg {Number} labelmd set the width of label (1-12)
30959 * @cfg {Number} labelsm set the width of label (1-12)
30960 * @cfg {Number} labelxs set the width of label (1-12)
30963 * Create a new DocumentManager
30964 * @param {Object} config The config object
30967 Roo.bootstrap.DocumentManager = function(config){
30968 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
30971 this.delegates = [];
30976 * Fire when initial the DocumentManager
30977 * @param {Roo.bootstrap.DocumentManager} this
30982 * inspect selected file
30983 * @param {Roo.bootstrap.DocumentManager} this
30984 * @param {File} file
30989 * Fire when xhr load exception
30990 * @param {Roo.bootstrap.DocumentManager} this
30991 * @param {XMLHttpRequest} xhr
30993 "exception" : true,
30995 * @event afterupload
30996 * Fire when xhr load exception
30997 * @param {Roo.bootstrap.DocumentManager} this
30998 * @param {XMLHttpRequest} xhr
31000 "afterupload" : true,
31003 * prepare the form data
31004 * @param {Roo.bootstrap.DocumentManager} this
31005 * @param {Object} formData
31010 * Fire when remove the file
31011 * @param {Roo.bootstrap.DocumentManager} this
31012 * @param {Object} file
31017 * Fire after refresh the file
31018 * @param {Roo.bootstrap.DocumentManager} this
31023 * Fire after click the image
31024 * @param {Roo.bootstrap.DocumentManager} this
31025 * @param {Object} file
31030 * Fire when upload a image and editable set to true
31031 * @param {Roo.bootstrap.DocumentManager} this
31032 * @param {Object} file
31036 * @event beforeselectfile
31037 * Fire before select file
31038 * @param {Roo.bootstrap.DocumentManager} this
31040 "beforeselectfile" : true,
31043 * Fire before process file
31044 * @param {Roo.bootstrap.DocumentManager} this
31045 * @param {Object} file
31049 * @event previewrendered
31050 * Fire when preview rendered
31051 * @param {Roo.bootstrap.DocumentManager} this
31052 * @param {Object} file
31054 "previewrendered" : true,
31057 "previewResize" : true
31062 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
31071 paramName : 'imageUpload',
31072 toolTipName : 'filename',
31075 labelAlign : 'left',
31085 getAutoCreate : function()
31087 var managerWidget = {
31089 cls : 'roo-document-manager',
31093 cls : 'roo-document-manager-selector',
31098 cls : 'roo-document-manager-uploader',
31102 cls : 'roo-document-manager-upload-btn',
31103 html : '<i class="fa fa-plus"></i>'
31114 cls : 'column col-md-12',
31119 if(this.fieldLabel.length){
31124 cls : 'column col-md-12',
31125 html : this.fieldLabel
31129 cls : 'column col-md-12',
31134 if(this.labelAlign == 'left'){
31139 html : this.fieldLabel
31148 if(this.labelWidth > 12){
31149 content[0].style = "width: " + this.labelWidth + 'px';
31152 if(this.labelWidth < 13 && this.labelmd == 0){
31153 this.labelmd = this.labelWidth;
31156 if(this.labellg > 0){
31157 content[0].cls += ' col-lg-' + this.labellg;
31158 content[1].cls += ' col-lg-' + (12 - this.labellg);
31161 if(this.labelmd > 0){
31162 content[0].cls += ' col-md-' + this.labelmd;
31163 content[1].cls += ' col-md-' + (12 - this.labelmd);
31166 if(this.labelsm > 0){
31167 content[0].cls += ' col-sm-' + this.labelsm;
31168 content[1].cls += ' col-sm-' + (12 - this.labelsm);
31171 if(this.labelxs > 0){
31172 content[0].cls += ' col-xs-' + this.labelxs;
31173 content[1].cls += ' col-xs-' + (12 - this.labelxs);
31181 cls : 'row clearfix',
31189 initEvents : function()
31191 this.managerEl = this.el.select('.roo-document-manager', true).first();
31192 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
31194 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
31195 this.selectorEl.hide();
31198 this.selectorEl.attr('multiple', 'multiple');
31201 this.selectorEl.on('change', this.onFileSelected, this);
31203 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
31204 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
31206 this.uploader.on('click', this.onUploaderClick, this);
31208 this.renderProgressDialog();
31212 window.addEventListener("resize", function() { _this.refresh(); } );
31214 this.fireEvent('initial', this);
31217 renderProgressDialog : function()
31221 this.progressDialog = new Roo.bootstrap.Modal({
31222 cls : 'roo-document-manager-progress-dialog',
31223 allow_close : false,
31234 btnclick : function() {
31235 _this.uploadCancel();
31241 this.progressDialog.render(Roo.get(document.body));
31243 this.progress = new Roo.bootstrap.Progress({
31244 cls : 'roo-document-manager-progress',
31249 this.progress.render(this.progressDialog.getChildContainer());
31251 this.progressBar = new Roo.bootstrap.ProgressBar({
31252 cls : 'roo-document-manager-progress-bar',
31255 aria_valuemax : 12,
31259 this.progressBar.render(this.progress.getChildContainer());
31262 onUploaderClick : function(e)
31264 e.preventDefault();
31266 if(this.fireEvent('beforeselectfile', this) != false){
31267 this.selectorEl.dom.click();
31272 onFileSelected : function(e)
31274 e.preventDefault();
31276 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
31280 Roo.each(this.selectorEl.dom.files, function(file){
31281 if(this.fireEvent('inspect', this, file) != false){
31282 this.files.push(file);
31292 this.selectorEl.dom.value = '';
31294 if(!this.files || !this.files.length){
31298 if(this.boxes > 0 && this.files.length > this.boxes){
31299 this.files = this.files.slice(0, this.boxes);
31302 this.uploader.show();
31304 if(this.boxes > 0 && this.files.length > this.boxes - 1){
31305 this.uploader.hide();
31314 Roo.each(this.files, function(file){
31316 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
31317 var f = this.renderPreview(file);
31322 if(file.type.indexOf('image') != -1){
31323 this.delegates.push(
31325 _this.process(file);
31326 }).createDelegate(this)
31334 _this.process(file);
31335 }).createDelegate(this)
31340 this.files = files;
31342 this.delegates = this.delegates.concat(docs);
31344 if(!this.delegates.length){
31349 this.progressBar.aria_valuemax = this.delegates.length;
31356 arrange : function()
31358 if(!this.delegates.length){
31359 this.progressDialog.hide();
31364 var delegate = this.delegates.shift();
31366 this.progressDialog.show();
31368 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
31370 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
31375 refresh : function()
31377 this.uploader.show();
31379 if(this.boxes > 0 && this.files.length > this.boxes - 1){
31380 this.uploader.hide();
31383 Roo.isTouch ? this.closable(false) : this.closable(true);
31385 this.fireEvent('refresh', this);
31388 onRemove : function(e, el, o)
31390 e.preventDefault();
31392 this.fireEvent('remove', this, o);
31396 remove : function(o)
31400 Roo.each(this.files, function(file){
31401 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
31410 this.files = files;
31417 Roo.each(this.files, function(file){
31422 file.target.remove();
31431 onClick : function(e, el, o)
31433 e.preventDefault();
31435 this.fireEvent('click', this, o);
31439 closable : function(closable)
31441 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
31443 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
31455 xhrOnLoad : function(xhr)
31457 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
31461 if (xhr.readyState !== 4) {
31463 this.fireEvent('exception', this, xhr);
31467 var response = Roo.decode(xhr.responseText);
31469 if(!response.success){
31471 this.fireEvent('exception', this, xhr);
31475 var file = this.renderPreview(response.data);
31477 this.files.push(file);
31481 this.fireEvent('afterupload', this, xhr);
31485 xhrOnError : function(xhr)
31487 Roo.log('xhr on error');
31489 var response = Roo.decode(xhr.responseText);
31496 process : function(file)
31498 if(this.fireEvent('process', this, file) !== false){
31499 if(this.editable && file.type.indexOf('image') != -1){
31500 this.fireEvent('edit', this, file);
31504 this.uploadStart(file, false);
31511 uploadStart : function(file, crop)
31513 this.xhr = new XMLHttpRequest();
31515 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
31520 file.xhr = this.xhr;
31522 this.managerEl.createChild({
31524 cls : 'roo-document-manager-loading',
31528 tooltip : file.name,
31529 cls : 'roo-document-manager-thumb',
31530 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
31536 this.xhr.open(this.method, this.url, true);
31539 "Accept": "application/json",
31540 "Cache-Control": "no-cache",
31541 "X-Requested-With": "XMLHttpRequest"
31544 for (var headerName in headers) {
31545 var headerValue = headers[headerName];
31547 this.xhr.setRequestHeader(headerName, headerValue);
31553 this.xhr.onload = function()
31555 _this.xhrOnLoad(_this.xhr);
31558 this.xhr.onerror = function()
31560 _this.xhrOnError(_this.xhr);
31563 var formData = new FormData();
31565 formData.append('returnHTML', 'NO');
31568 formData.append('crop', crop);
31571 formData.append(this.paramName, file, file.name);
31578 if(this.fireEvent('prepare', this, formData, options) != false){
31580 if(options.manually){
31584 this.xhr.send(formData);
31588 this.uploadCancel();
31591 uploadCancel : function()
31597 this.delegates = [];
31599 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
31606 renderPreview : function(file)
31608 if(typeof(file.target) != 'undefined' && file.target){
31612 var img_src = encodeURI(baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename);
31614 var previewEl = this.managerEl.createChild({
31616 cls : 'roo-document-manager-preview',
31620 tooltip : file[this.toolTipName],
31621 cls : 'roo-document-manager-thumb',
31622 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + img_src + '">'
31627 html : '<i class="fa fa-times-circle"></i>'
31632 var close = previewEl.select('button.close', true).first();
31634 close.on('click', this.onRemove, this, file);
31636 file.target = previewEl;
31638 var image = previewEl.select('img', true).first();
31642 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
31644 image.on('click', this.onClick, this, file);
31646 this.fireEvent('previewrendered', this, file);
31652 onPreviewLoad : function(file, image)
31654 if(typeof(file.target) == 'undefined' || !file.target){
31658 var width = image.dom.naturalWidth || image.dom.width;
31659 var height = image.dom.naturalHeight || image.dom.height;
31661 if(!this.previewResize) {
31665 if(width > height){
31666 file.target.addClass('wide');
31670 file.target.addClass('tall');
31675 uploadFromSource : function(file, crop)
31677 this.xhr = new XMLHttpRequest();
31679 this.managerEl.createChild({
31681 cls : 'roo-document-manager-loading',
31685 tooltip : file.name,
31686 cls : 'roo-document-manager-thumb',
31687 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
31693 this.xhr.open(this.method, this.url, true);
31696 "Accept": "application/json",
31697 "Cache-Control": "no-cache",
31698 "X-Requested-With": "XMLHttpRequest"
31701 for (var headerName in headers) {
31702 var headerValue = headers[headerName];
31704 this.xhr.setRequestHeader(headerName, headerValue);
31710 this.xhr.onload = function()
31712 _this.xhrOnLoad(_this.xhr);
31715 this.xhr.onerror = function()
31717 _this.xhrOnError(_this.xhr);
31720 var formData = new FormData();
31722 formData.append('returnHTML', 'NO');
31724 formData.append('crop', crop);
31726 if(typeof(file.filename) != 'undefined'){
31727 formData.append('filename', file.filename);
31730 if(typeof(file.mimetype) != 'undefined'){
31731 formData.append('mimetype', file.mimetype);
31736 if(this.fireEvent('prepare', this, formData) != false){
31737 this.xhr.send(formData);
31747 * @class Roo.bootstrap.DocumentViewer
31748 * @extends Roo.bootstrap.Component
31749 * Bootstrap DocumentViewer class
31750 * @cfg {Boolean} showDownload (true|false) show download button (default true)
31751 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
31754 * Create a new DocumentViewer
31755 * @param {Object} config The config object
31758 Roo.bootstrap.DocumentViewer = function(config){
31759 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
31764 * Fire after initEvent
31765 * @param {Roo.bootstrap.DocumentViewer} this
31771 * @param {Roo.bootstrap.DocumentViewer} this
31776 * Fire after download button
31777 * @param {Roo.bootstrap.DocumentViewer} this
31782 * Fire after trash button
31783 * @param {Roo.bootstrap.DocumentViewer} this
31790 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
31792 showDownload : true,
31796 getAutoCreate : function()
31800 cls : 'roo-document-viewer',
31804 cls : 'roo-document-viewer-body',
31808 cls : 'roo-document-viewer-thumb',
31812 cls : 'roo-document-viewer-image'
31820 cls : 'roo-document-viewer-footer',
31823 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
31827 cls : 'btn-group roo-document-viewer-download',
31831 cls : 'btn btn-default',
31832 html : '<i class="fa fa-download"></i>'
31838 cls : 'btn-group roo-document-viewer-trash',
31842 cls : 'btn btn-default',
31843 html : '<i class="fa fa-trash"></i>'
31856 initEvents : function()
31858 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
31859 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
31861 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
31862 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
31864 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
31865 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
31867 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
31868 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
31870 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
31871 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
31873 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
31874 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
31876 this.bodyEl.on('click', this.onClick, this);
31877 this.downloadBtn.on('click', this.onDownload, this);
31878 this.trashBtn.on('click', this.onTrash, this);
31880 this.downloadBtn.hide();
31881 this.trashBtn.hide();
31883 if(this.showDownload){
31884 this.downloadBtn.show();
31887 if(this.showTrash){
31888 this.trashBtn.show();
31891 if(!this.showDownload && !this.showTrash) {
31892 this.footerEl.hide();
31897 initial : function()
31899 this.fireEvent('initial', this);
31903 onClick : function(e)
31905 e.preventDefault();
31907 this.fireEvent('click', this);
31910 onDownload : function(e)
31912 e.preventDefault();
31914 this.fireEvent('download', this);
31917 onTrash : function(e)
31919 e.preventDefault();
31921 this.fireEvent('trash', this);
31933 * @class Roo.bootstrap.NavProgressBar
31934 * @extends Roo.bootstrap.Component
31935 * Bootstrap NavProgressBar class
31938 * Create a new nav progress bar
31939 * @param {Object} config The config object
31942 Roo.bootstrap.NavProgressBar = function(config){
31943 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
31945 this.bullets = this.bullets || [];
31947 // Roo.bootstrap.NavProgressBar.register(this);
31951 * Fires when the active item changes
31952 * @param {Roo.bootstrap.NavProgressBar} this
31953 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
31954 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
31961 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
31966 getAutoCreate : function()
31968 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
31972 cls : 'roo-navigation-bar-group',
31976 cls : 'roo-navigation-top-bar'
31980 cls : 'roo-navigation-bullets-bar',
31984 cls : 'roo-navigation-bar'
31991 cls : 'roo-navigation-bottom-bar'
32001 initEvents: function()
32006 onRender : function(ct, position)
32008 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
32010 if(this.bullets.length){
32011 Roo.each(this.bullets, function(b){
32020 addItem : function(cfg)
32022 var item = new Roo.bootstrap.NavProgressItem(cfg);
32024 item.parentId = this.id;
32025 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
32028 var top = new Roo.bootstrap.Element({
32030 cls : 'roo-navigation-bar-text'
32033 var bottom = new Roo.bootstrap.Element({
32035 cls : 'roo-navigation-bar-text'
32038 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
32039 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
32041 var topText = new Roo.bootstrap.Element({
32043 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
32046 var bottomText = new Roo.bootstrap.Element({
32048 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
32051 topText.onRender(top.el, null);
32052 bottomText.onRender(bottom.el, null);
32055 item.bottomEl = bottom;
32058 this.barItems.push(item);
32063 getActive : function()
32065 var active = false;
32067 Roo.each(this.barItems, function(v){
32069 if (!v.isActive()) {
32081 setActiveItem : function(item)
32085 Roo.each(this.barItems, function(v){
32086 if (v.rid == item.rid) {
32090 if (v.isActive()) {
32091 v.setActive(false);
32096 item.setActive(true);
32098 this.fireEvent('changed', this, item, prev);
32101 getBarItem: function(rid)
32105 Roo.each(this.barItems, function(e) {
32106 if (e.rid != rid) {
32117 indexOfItem : function(item)
32121 Roo.each(this.barItems, function(v, i){
32123 if (v.rid != item.rid) {
32134 setActiveNext : function()
32136 var i = this.indexOfItem(this.getActive());
32138 if (i > this.barItems.length) {
32142 this.setActiveItem(this.barItems[i+1]);
32145 setActivePrev : function()
32147 var i = this.indexOfItem(this.getActive());
32153 this.setActiveItem(this.barItems[i-1]);
32156 format : function()
32158 if(!this.barItems.length){
32162 var width = 100 / this.barItems.length;
32164 Roo.each(this.barItems, function(i){
32165 i.el.setStyle('width', width + '%');
32166 i.topEl.el.setStyle('width', width + '%');
32167 i.bottomEl.el.setStyle('width', width + '%');
32176 * Nav Progress Item
32181 * @class Roo.bootstrap.NavProgressItem
32182 * @extends Roo.bootstrap.Component
32183 * Bootstrap NavProgressItem class
32184 * @cfg {String} rid the reference id
32185 * @cfg {Boolean} active (true|false) Is item active default false
32186 * @cfg {Boolean} disabled (true|false) Is item active default false
32187 * @cfg {String} html
32188 * @cfg {String} position (top|bottom) text position default bottom
32189 * @cfg {String} icon show icon instead of number
32192 * Create a new NavProgressItem
32193 * @param {Object} config The config object
32195 Roo.bootstrap.NavProgressItem = function(config){
32196 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
32201 * The raw click event for the entire grid.
32202 * @param {Roo.bootstrap.NavProgressItem} this
32203 * @param {Roo.EventObject} e
32210 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
32216 position : 'bottom',
32219 getAutoCreate : function()
32221 var iconCls = 'roo-navigation-bar-item-icon';
32223 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
32227 cls: 'roo-navigation-bar-item',
32237 cfg.cls += ' active';
32240 cfg.cls += ' disabled';
32246 disable : function()
32248 this.setDisabled(true);
32251 enable : function()
32253 this.setDisabled(false);
32256 initEvents: function()
32258 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
32260 this.iconEl.on('click', this.onClick, this);
32263 onClick : function(e)
32265 e.preventDefault();
32271 if(this.fireEvent('click', this, e) === false){
32275 this.parent().setActiveItem(this);
32278 isActive: function ()
32280 return this.active;
32283 setActive : function(state)
32285 if(this.active == state){
32289 this.active = state;
32292 this.el.addClass('active');
32296 this.el.removeClass('active');
32301 setDisabled : function(state)
32303 if(this.disabled == state){
32307 this.disabled = state;
32310 this.el.addClass('disabled');
32314 this.el.removeClass('disabled');
32317 tooltipEl : function()
32319 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
32332 * @class Roo.bootstrap.FieldLabel
32333 * @extends Roo.bootstrap.Component
32334 * Bootstrap FieldLabel class
32335 * @cfg {String} html contents of the element
32336 * @cfg {String} tag tag of the element default label
32337 * @cfg {String} cls class of the element
32338 * @cfg {String} target label target
32339 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
32340 * @cfg {String} invalidClass DEPRICATED - BS4 uses is-invalid
32341 * @cfg {String} validClass DEPRICATED - BS4 uses is-valid
32342 * @cfg {String} iconTooltip default "This field is required"
32343 * @cfg {String} indicatorpos (left|right) default left
32346 * Create a new FieldLabel
32347 * @param {Object} config The config object
32350 Roo.bootstrap.FieldLabel = function(config){
32351 Roo.bootstrap.Element.superclass.constructor.call(this, config);
32356 * Fires after the field has been marked as invalid.
32357 * @param {Roo.form.FieldLabel} this
32358 * @param {String} msg The validation message
32363 * Fires after the field has been validated with no errors.
32364 * @param {Roo.form.FieldLabel} this
32370 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
32377 invalidClass : 'has-warning',
32378 validClass : 'has-success',
32379 iconTooltip : 'This field is required',
32380 indicatorpos : 'left',
32382 getAutoCreate : function(){
32385 if (!this.allowBlank) {
32391 cls : 'roo-bootstrap-field-label ' + this.cls,
32396 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star ' + cls,
32397 tooltip : this.iconTooltip
32406 if(this.indicatorpos == 'right'){
32409 cls : 'roo-bootstrap-field-label ' + this.cls,
32418 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star '+ cls,
32419 tooltip : this.iconTooltip
32428 initEvents: function()
32430 Roo.bootstrap.Element.superclass.initEvents.call(this);
32432 this.indicator = this.indicatorEl();
32434 if(this.indicator){
32435 this.indicator.removeClass('visible');
32436 this.indicator.addClass('invisible');
32439 Roo.bootstrap.FieldLabel.register(this);
32442 indicatorEl : function()
32444 var indicator = this.el.select('i.roo-required-indicator',true).first();
32455 * Mark this field as valid
32457 markValid : function()
32459 if(this.indicator){
32460 this.indicator.removeClass('visible');
32461 this.indicator.addClass('invisible');
32463 if (Roo.bootstrap.version == 3) {
32464 this.el.removeClass(this.invalidClass);
32465 this.el.addClass(this.validClass);
32467 this.el.removeClass('is-invalid');
32468 this.el.addClass('is-valid');
32472 this.fireEvent('valid', this);
32476 * Mark this field as invalid
32477 * @param {String} msg The validation message
32479 markInvalid : function(msg)
32481 if(this.indicator){
32482 this.indicator.removeClass('invisible');
32483 this.indicator.addClass('visible');
32485 if (Roo.bootstrap.version == 3) {
32486 this.el.removeClass(this.validClass);
32487 this.el.addClass(this.invalidClass);
32489 this.el.removeClass('is-valid');
32490 this.el.addClass('is-invalid');
32494 this.fireEvent('invalid', this, msg);
32500 Roo.apply(Roo.bootstrap.FieldLabel, {
32505 * register a FieldLabel Group
32506 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
32508 register : function(label)
32510 if(this.groups.hasOwnProperty(label.target)){
32514 this.groups[label.target] = label;
32518 * fetch a FieldLabel Group based on the target
32519 * @param {string} target
32520 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
32522 get: function(target) {
32523 if (typeof(this.groups[target]) == 'undefined') {
32527 return this.groups[target] ;
32536 * page DateSplitField.
32542 * @class Roo.bootstrap.DateSplitField
32543 * @extends Roo.bootstrap.Component
32544 * Bootstrap DateSplitField class
32545 * @cfg {string} fieldLabel - the label associated
32546 * @cfg {Number} labelWidth set the width of label (0-12)
32547 * @cfg {String} labelAlign (top|left)
32548 * @cfg {Boolean} dayAllowBlank (true|false) default false
32549 * @cfg {Boolean} monthAllowBlank (true|false) default false
32550 * @cfg {Boolean} yearAllowBlank (true|false) default false
32551 * @cfg {string} dayPlaceholder
32552 * @cfg {string} monthPlaceholder
32553 * @cfg {string} yearPlaceholder
32554 * @cfg {string} dayFormat default 'd'
32555 * @cfg {string} monthFormat default 'm'
32556 * @cfg {string} yearFormat default 'Y'
32557 * @cfg {Number} labellg set the width of label (1-12)
32558 * @cfg {Number} labelmd set the width of label (1-12)
32559 * @cfg {Number} labelsm set the width of label (1-12)
32560 * @cfg {Number} labelxs set the width of label (1-12)
32564 * Create a new DateSplitField
32565 * @param {Object} config The config object
32568 Roo.bootstrap.DateSplitField = function(config){
32569 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
32575 * getting the data of years
32576 * @param {Roo.bootstrap.DateSplitField} this
32577 * @param {Object} years
32582 * getting the data of days
32583 * @param {Roo.bootstrap.DateSplitField} this
32584 * @param {Object} days
32589 * Fires after the field has been marked as invalid.
32590 * @param {Roo.form.Field} this
32591 * @param {String} msg The validation message
32596 * Fires after the field has been validated with no errors.
32597 * @param {Roo.form.Field} this
32603 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
32606 labelAlign : 'top',
32608 dayAllowBlank : false,
32609 monthAllowBlank : false,
32610 yearAllowBlank : false,
32611 dayPlaceholder : '',
32612 monthPlaceholder : '',
32613 yearPlaceholder : '',
32617 isFormField : true,
32623 getAutoCreate : function()
32627 cls : 'row roo-date-split-field-group',
32632 cls : 'form-hidden-field roo-date-split-field-group-value',
32638 var labelCls = 'col-md-12';
32639 var contentCls = 'col-md-4';
32641 if(this.fieldLabel){
32645 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
32649 html : this.fieldLabel
32654 if(this.labelAlign == 'left'){
32656 if(this.labelWidth > 12){
32657 label.style = "width: " + this.labelWidth + 'px';
32660 if(this.labelWidth < 13 && this.labelmd == 0){
32661 this.labelmd = this.labelWidth;
32664 if(this.labellg > 0){
32665 labelCls = ' col-lg-' + this.labellg;
32666 contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
32669 if(this.labelmd > 0){
32670 labelCls = ' col-md-' + this.labelmd;
32671 contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
32674 if(this.labelsm > 0){
32675 labelCls = ' col-sm-' + this.labelsm;
32676 contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
32679 if(this.labelxs > 0){
32680 labelCls = ' col-xs-' + this.labelxs;
32681 contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
32685 label.cls += ' ' + labelCls;
32687 cfg.cn.push(label);
32690 Roo.each(['day', 'month', 'year'], function(t){
32693 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
32700 inputEl: function ()
32702 return this.el.select('.roo-date-split-field-group-value', true).first();
32705 onRender : function(ct, position)
32709 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
32711 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
32713 this.dayField = new Roo.bootstrap.ComboBox({
32714 allowBlank : this.dayAllowBlank,
32715 alwaysQuery : true,
32716 displayField : 'value',
32719 forceSelection : true,
32721 placeholder : this.dayPlaceholder,
32722 selectOnFocus : true,
32723 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
32724 triggerAction : 'all',
32726 valueField : 'value',
32727 store : new Roo.data.SimpleStore({
32728 data : (function() {
32730 _this.fireEvent('days', _this, days);
32733 fields : [ 'value' ]
32736 select : function (_self, record, index)
32738 _this.setValue(_this.getValue());
32743 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
32745 this.monthField = new Roo.bootstrap.MonthField({
32746 after : '<i class=\"fa fa-calendar\"></i>',
32747 allowBlank : this.monthAllowBlank,
32748 placeholder : this.monthPlaceholder,
32751 render : function (_self)
32753 this.el.select('span.input-group-addon', true).first().on('click', function(e){
32754 e.preventDefault();
32758 select : function (_self, oldvalue, newvalue)
32760 _this.setValue(_this.getValue());
32765 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
32767 this.yearField = new Roo.bootstrap.ComboBox({
32768 allowBlank : this.yearAllowBlank,
32769 alwaysQuery : true,
32770 displayField : 'value',
32773 forceSelection : true,
32775 placeholder : this.yearPlaceholder,
32776 selectOnFocus : true,
32777 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
32778 triggerAction : 'all',
32780 valueField : 'value',
32781 store : new Roo.data.SimpleStore({
32782 data : (function() {
32784 _this.fireEvent('years', _this, years);
32787 fields : [ 'value' ]
32790 select : function (_self, record, index)
32792 _this.setValue(_this.getValue());
32797 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
32800 setValue : function(v, format)
32802 this.inputEl.dom.value = v;
32804 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
32806 var d = Date.parseDate(v, f);
32813 this.setDay(d.format(this.dayFormat));
32814 this.setMonth(d.format(this.monthFormat));
32815 this.setYear(d.format(this.yearFormat));
32822 setDay : function(v)
32824 this.dayField.setValue(v);
32825 this.inputEl.dom.value = this.getValue();
32830 setMonth : function(v)
32832 this.monthField.setValue(v, true);
32833 this.inputEl.dom.value = this.getValue();
32838 setYear : function(v)
32840 this.yearField.setValue(v);
32841 this.inputEl.dom.value = this.getValue();
32846 getDay : function()
32848 return this.dayField.getValue();
32851 getMonth : function()
32853 return this.monthField.getValue();
32856 getYear : function()
32858 return this.yearField.getValue();
32861 getValue : function()
32863 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
32865 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
32875 this.inputEl.dom.value = '';
32880 validate : function()
32882 var d = this.dayField.validate();
32883 var m = this.monthField.validate();
32884 var y = this.yearField.validate();
32889 (!this.dayAllowBlank && !d) ||
32890 (!this.monthAllowBlank && !m) ||
32891 (!this.yearAllowBlank && !y)
32896 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
32905 this.markInvalid();
32910 markValid : function()
32913 var label = this.el.select('label', true).first();
32914 var icon = this.el.select('i.fa-star', true).first();
32920 this.fireEvent('valid', this);
32924 * Mark this field as invalid
32925 * @param {String} msg The validation message
32927 markInvalid : function(msg)
32930 var label = this.el.select('label', true).first();
32931 var icon = this.el.select('i.fa-star', true).first();
32933 if(label && !icon){
32934 this.el.select('.roo-date-split-field-label', true).createChild({
32936 cls : 'text-danger fa fa-lg fa-star',
32937 tooltip : 'This field is required',
32938 style : 'margin-right:5px;'
32942 this.fireEvent('invalid', this, msg);
32945 clearInvalid : function()
32947 var label = this.el.select('label', true).first();
32948 var icon = this.el.select('i.fa-star', true).first();
32954 this.fireEvent('valid', this);
32957 getName: function()
32967 * http://masonry.desandro.com
32969 * The idea is to render all the bricks based on vertical width...
32971 * The original code extends 'outlayer' - we might need to use that....
32977 * @class Roo.bootstrap.LayoutMasonry
32978 * @extends Roo.bootstrap.Component
32979 * Bootstrap Layout Masonry class
32982 * Create a new Element
32983 * @param {Object} config The config object
32986 Roo.bootstrap.LayoutMasonry = function(config){
32988 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
32992 Roo.bootstrap.LayoutMasonry.register(this);
32998 * Fire after layout the items
32999 * @param {Roo.bootstrap.LayoutMasonry} this
33000 * @param {Roo.EventObject} e
33007 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
33010 * @cfg {Boolean} isLayoutInstant = no animation?
33012 isLayoutInstant : false, // needed?
33015 * @cfg {Number} boxWidth width of the columns
33020 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
33025 * @cfg {Number} padWidth padding below box..
33030 * @cfg {Number} gutter gutter width..
33035 * @cfg {Number} maxCols maximum number of columns
33041 * @cfg {Boolean} isAutoInitial defalut true
33043 isAutoInitial : true,
33048 * @cfg {Boolean} isHorizontal defalut false
33050 isHorizontal : false,
33052 currentSize : null,
33058 bricks: null, //CompositeElement
33062 _isLayoutInited : false,
33064 // isAlternative : false, // only use for vertical layout...
33067 * @cfg {Number} alternativePadWidth padding below box..
33069 alternativePadWidth : 50,
33071 selectedBrick : [],
33073 getAutoCreate : function(){
33075 var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
33079 cls: 'blog-masonary-wrapper ' + this.cls,
33081 cls : 'mas-boxes masonary'
33088 getChildContainer: function( )
33090 if (this.boxesEl) {
33091 return this.boxesEl;
33094 this.boxesEl = this.el.select('.mas-boxes').first();
33096 return this.boxesEl;
33100 initEvents : function()
33104 if(this.isAutoInitial){
33105 Roo.log('hook children rendered');
33106 this.on('childrenrendered', function() {
33107 Roo.log('children rendered');
33113 initial : function()
33115 this.selectedBrick = [];
33117 this.currentSize = this.el.getBox(true);
33119 Roo.EventManager.onWindowResize(this.resize, this);
33121 if(!this.isAutoInitial){
33129 //this.layout.defer(500,this);
33133 resize : function()
33135 var cs = this.el.getBox(true);
33138 this.currentSize.width == cs.width &&
33139 this.currentSize.x == cs.x &&
33140 this.currentSize.height == cs.height &&
33141 this.currentSize.y == cs.y
33143 Roo.log("no change in with or X or Y");
33147 this.currentSize = cs;
33153 layout : function()
33155 this._resetLayout();
33157 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
33159 this.layoutItems( isInstant );
33161 this._isLayoutInited = true;
33163 this.fireEvent('layout', this);
33167 _resetLayout : function()
33169 if(this.isHorizontal){
33170 this.horizontalMeasureColumns();
33174 this.verticalMeasureColumns();
33178 verticalMeasureColumns : function()
33180 this.getContainerWidth();
33182 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
33183 // this.colWidth = Math.floor(this.containerWidth * 0.8);
33187 var boxWidth = this.boxWidth + this.padWidth;
33189 if(this.containerWidth < this.boxWidth){
33190 boxWidth = this.containerWidth
33193 var containerWidth = this.containerWidth;
33195 var cols = Math.floor(containerWidth / boxWidth);
33197 this.cols = Math.max( cols, 1 );
33199 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
33201 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
33203 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
33205 this.colWidth = boxWidth + avail - this.padWidth;
33207 this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
33208 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
33211 horizontalMeasureColumns : function()
33213 this.getContainerWidth();
33215 var boxWidth = this.boxWidth;
33217 if(this.containerWidth < boxWidth){
33218 boxWidth = this.containerWidth;
33221 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
33223 this.el.setHeight(boxWidth);
33227 getContainerWidth : function()
33229 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
33232 layoutItems : function( isInstant )
33234 Roo.log(this.bricks);
33236 var items = Roo.apply([], this.bricks);
33238 if(this.isHorizontal){
33239 this._horizontalLayoutItems( items , isInstant );
33243 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
33244 // this._verticalAlternativeLayoutItems( items , isInstant );
33248 this._verticalLayoutItems( items , isInstant );
33252 _verticalLayoutItems : function ( items , isInstant)
33254 if ( !items || !items.length ) {
33259 ['xs', 'xs', 'xs', 'tall'],
33260 ['xs', 'xs', 'tall'],
33261 ['xs', 'xs', 'sm'],
33262 ['xs', 'xs', 'xs'],
33268 ['sm', 'xs', 'xs'],
33272 ['tall', 'xs', 'xs', 'xs'],
33273 ['tall', 'xs', 'xs'],
33285 Roo.each(items, function(item, k){
33287 switch (item.size) {
33288 // these layouts take up a full box,
33299 boxes.push([item]);
33322 var filterPattern = function(box, length)
33330 var pattern = box.slice(0, length);
33334 Roo.each(pattern, function(i){
33335 format.push(i.size);
33338 Roo.each(standard, function(s){
33340 if(String(s) != String(format)){
33349 if(!match && length == 1){
33354 filterPattern(box, length - 1);
33358 queue.push(pattern);
33360 box = box.slice(length, box.length);
33362 filterPattern(box, 4);
33368 Roo.each(boxes, function(box, k){
33374 if(box.length == 1){
33379 filterPattern(box, 4);
33383 this._processVerticalLayoutQueue( queue, isInstant );
33387 // _verticalAlternativeLayoutItems : function( items , isInstant )
33389 // if ( !items || !items.length ) {
33393 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
33397 _horizontalLayoutItems : function ( items , isInstant)
33399 if ( !items || !items.length || items.length < 3) {
33405 var eItems = items.slice(0, 3);
33407 items = items.slice(3, items.length);
33410 ['xs', 'xs', 'xs', 'wide'],
33411 ['xs', 'xs', 'wide'],
33412 ['xs', 'xs', 'sm'],
33413 ['xs', 'xs', 'xs'],
33419 ['sm', 'xs', 'xs'],
33423 ['wide', 'xs', 'xs', 'xs'],
33424 ['wide', 'xs', 'xs'],
33437 Roo.each(items, function(item, k){
33439 switch (item.size) {
33450 boxes.push([item]);
33474 var filterPattern = function(box, length)
33482 var pattern = box.slice(0, length);
33486 Roo.each(pattern, function(i){
33487 format.push(i.size);
33490 Roo.each(standard, function(s){
33492 if(String(s) != String(format)){
33501 if(!match && length == 1){
33506 filterPattern(box, length - 1);
33510 queue.push(pattern);
33512 box = box.slice(length, box.length);
33514 filterPattern(box, 4);
33520 Roo.each(boxes, function(box, k){
33526 if(box.length == 1){
33531 filterPattern(box, 4);
33538 var pos = this.el.getBox(true);
33542 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
33544 var hit_end = false;
33546 Roo.each(queue, function(box){
33550 Roo.each(box, function(b){
33552 b.el.setVisibilityMode(Roo.Element.DISPLAY);
33562 Roo.each(box, function(b){
33564 b.el.setVisibilityMode(Roo.Element.DISPLAY);
33567 mx = Math.max(mx, b.x);
33571 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
33575 Roo.each(box, function(b){
33577 b.el.setVisibilityMode(Roo.Element.DISPLAY);
33591 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
33594 /** Sets position of item in DOM
33595 * @param {Element} item
33596 * @param {Number} x - horizontal position
33597 * @param {Number} y - vertical position
33598 * @param {Boolean} isInstant - disables transitions
33600 _processVerticalLayoutQueue : function( queue, isInstant )
33602 var pos = this.el.getBox(true);
33607 for (var i = 0; i < this.cols; i++){
33611 Roo.each(queue, function(box, k){
33613 var col = k % this.cols;
33615 Roo.each(box, function(b,kk){
33617 b.el.position('absolute');
33619 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
33620 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
33622 if(b.size == 'md-left' || b.size == 'md-right'){
33623 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
33624 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
33627 b.el.setWidth(width);
33628 b.el.setHeight(height);
33630 b.el.select('iframe',true).setSize(width,height);
33634 for (var i = 0; i < this.cols; i++){
33636 if(maxY[i] < maxY[col]){
33641 col = Math.min(col, i);
33645 x = pos.x + col * (this.colWidth + this.padWidth);
33649 var positions = [];
33651 switch (box.length){
33653 positions = this.getVerticalOneBoxColPositions(x, y, box);
33656 positions = this.getVerticalTwoBoxColPositions(x, y, box);
33659 positions = this.getVerticalThreeBoxColPositions(x, y, box);
33662 positions = this.getVerticalFourBoxColPositions(x, y, box);
33668 Roo.each(box, function(b,kk){
33670 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
33672 var sz = b.el.getSize();
33674 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
33682 for (var i = 0; i < this.cols; i++){
33683 mY = Math.max(mY, maxY[i]);
33686 this.el.setHeight(mY - pos.y);
33690 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
33692 // var pos = this.el.getBox(true);
33695 // var maxX = pos.right;
33697 // var maxHeight = 0;
33699 // Roo.each(items, function(item, k){
33703 // item.el.position('absolute');
33705 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
33707 // item.el.setWidth(width);
33709 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
33711 // item.el.setHeight(height);
33714 // item.el.setXY([x, y], isInstant ? false : true);
33716 // item.el.setXY([maxX - width, y], isInstant ? false : true);
33719 // y = y + height + this.alternativePadWidth;
33721 // maxHeight = maxHeight + height + this.alternativePadWidth;
33725 // this.el.setHeight(maxHeight);
33729 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
33731 var pos = this.el.getBox(true);
33736 var maxX = pos.right;
33738 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
33740 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
33742 Roo.each(queue, function(box, k){
33744 Roo.each(box, function(b, kk){
33746 b.el.position('absolute');
33748 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
33749 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
33751 if(b.size == 'md-left' || b.size == 'md-right'){
33752 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
33753 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
33756 b.el.setWidth(width);
33757 b.el.setHeight(height);
33765 var positions = [];
33767 switch (box.length){
33769 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
33772 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
33775 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
33778 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
33784 Roo.each(box, function(b,kk){
33786 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
33788 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
33796 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
33798 Roo.each(eItems, function(b,k){
33800 b.size = (k == 0) ? 'sm' : 'xs';
33801 b.x = (k == 0) ? 2 : 1;
33802 b.y = (k == 0) ? 2 : 1;
33804 b.el.position('absolute');
33806 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
33808 b.el.setWidth(width);
33810 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
33812 b.el.setHeight(height);
33816 var positions = [];
33819 x : maxX - this.unitWidth * 2 - this.gutter,
33824 x : maxX - this.unitWidth,
33825 y : minY + (this.unitWidth + this.gutter) * 2
33829 x : maxX - this.unitWidth * 3 - this.gutter * 2,
33833 Roo.each(eItems, function(b,k){
33835 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
33841 getVerticalOneBoxColPositions : function(x, y, box)
33845 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
33847 if(box[0].size == 'md-left'){
33851 if(box[0].size == 'md-right'){
33856 x : x + (this.unitWidth + this.gutter) * rand,
33863 getVerticalTwoBoxColPositions : function(x, y, box)
33867 if(box[0].size == 'xs'){
33871 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
33875 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
33889 x : x + (this.unitWidth + this.gutter) * 2,
33890 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
33897 getVerticalThreeBoxColPositions : function(x, y, box)
33901 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
33909 x : x + (this.unitWidth + this.gutter) * 1,
33914 x : x + (this.unitWidth + this.gutter) * 2,
33922 if(box[0].size == 'xs' && box[1].size == 'xs'){
33931 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
33935 x : x + (this.unitWidth + this.gutter) * 1,
33949 x : x + (this.unitWidth + this.gutter) * 2,
33954 x : x + (this.unitWidth + this.gutter) * 2,
33955 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
33962 getVerticalFourBoxColPositions : function(x, y, box)
33966 if(box[0].size == 'xs'){
33975 y : y + (this.unitHeight + this.gutter) * 1
33980 y : y + (this.unitHeight + this.gutter) * 2
33984 x : x + (this.unitWidth + this.gutter) * 1,
33998 x : x + (this.unitWidth + this.gutter) * 2,
34003 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
34004 y : y + (this.unitHeight + this.gutter) * 1
34008 x : x + (this.unitWidth + this.gutter) * 2,
34009 y : y + (this.unitWidth + this.gutter) * 2
34016 getHorizontalOneBoxColPositions : function(maxX, minY, box)
34020 if(box[0].size == 'md-left'){
34022 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
34029 if(box[0].size == 'md-right'){
34031 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
34032 y : minY + (this.unitWidth + this.gutter) * 1
34038 var rand = Math.floor(Math.random() * (4 - box[0].y));
34041 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
34042 y : minY + (this.unitWidth + this.gutter) * rand
34049 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
34053 if(box[0].size == 'xs'){
34056 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
34061 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
34062 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
34070 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
34075 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
34076 y : minY + (this.unitWidth + this.gutter) * 2
34083 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
34087 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
34090 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
34095 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
34096 y : minY + (this.unitWidth + this.gutter) * 1
34100 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
34101 y : minY + (this.unitWidth + this.gutter) * 2
34108 if(box[0].size == 'xs' && box[1].size == 'xs'){
34111 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
34116 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
34121 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
34122 y : minY + (this.unitWidth + this.gutter) * 1
34130 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
34135 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
34136 y : minY + (this.unitWidth + this.gutter) * 2
34140 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
34141 y : minY + (this.unitWidth + this.gutter) * 2
34148 getHorizontalFourBoxColPositions : function(maxX, minY, box)
34152 if(box[0].size == 'xs'){
34155 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
34160 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
34165 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),
34170 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
34171 y : minY + (this.unitWidth + this.gutter) * 1
34179 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
34184 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
34185 y : minY + (this.unitWidth + this.gutter) * 2
34189 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
34190 y : minY + (this.unitWidth + this.gutter) * 2
34194 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),
34195 y : minY + (this.unitWidth + this.gutter) * 2
34203 * remove a Masonry Brick
34204 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
34206 removeBrick : function(brick_id)
34212 for (var i = 0; i<this.bricks.length; i++) {
34213 if (this.bricks[i].id == brick_id) {
34214 this.bricks.splice(i,1);
34215 this.el.dom.removeChild(Roo.get(brick_id).dom);
34222 * adds a Masonry Brick
34223 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
34225 addBrick : function(cfg)
34227 var cn = new Roo.bootstrap.MasonryBrick(cfg);
34228 //this.register(cn);
34229 cn.parentId = this.id;
34230 cn.render(this.el);
34235 * register a Masonry Brick
34236 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
34239 register : function(brick)
34241 this.bricks.push(brick);
34242 brick.masonryId = this.id;
34246 * clear all the Masonry Brick
34248 clearAll : function()
34251 //this.getChildContainer().dom.innerHTML = "";
34252 this.el.dom.innerHTML = '';
34255 getSelected : function()
34257 if (!this.selectedBrick) {
34261 return this.selectedBrick;
34265 Roo.apply(Roo.bootstrap.LayoutMasonry, {
34269 * register a Masonry Layout
34270 * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
34273 register : function(layout)
34275 this.groups[layout.id] = layout;
34278 * fetch a Masonry Layout based on the masonry layout ID
34279 * @param {string} the masonry layout to add
34280 * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
34283 get: function(layout_id) {
34284 if (typeof(this.groups[layout_id]) == 'undefined') {
34287 return this.groups[layout_id] ;
34299 * http://masonry.desandro.com
34301 * The idea is to render all the bricks based on vertical width...
34303 * The original code extends 'outlayer' - we might need to use that....
34309 * @class Roo.bootstrap.LayoutMasonryAuto
34310 * @extends Roo.bootstrap.Component
34311 * Bootstrap Layout Masonry class
34314 * Create a new Element
34315 * @param {Object} config The config object
34318 Roo.bootstrap.LayoutMasonryAuto = function(config){
34319 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
34322 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
34325 * @cfg {Boolean} isFitWidth - resize the width..
34327 isFitWidth : false, // options..
34329 * @cfg {Boolean} isOriginLeft = left align?
34331 isOriginLeft : true,
34333 * @cfg {Boolean} isOriginTop = top align?
34335 isOriginTop : false,
34337 * @cfg {Boolean} isLayoutInstant = no animation?
34339 isLayoutInstant : false, // needed?
34341 * @cfg {Boolean} isResizingContainer = not sure if this is used..
34343 isResizingContainer : true,
34345 * @cfg {Number} columnWidth width of the columns
34351 * @cfg {Number} maxCols maximum number of columns
34356 * @cfg {Number} padHeight padding below box..
34362 * @cfg {Boolean} isAutoInitial defalut true
34365 isAutoInitial : true,
34371 initialColumnWidth : 0,
34372 currentSize : null,
34374 colYs : null, // array.
34381 bricks: null, //CompositeElement
34382 cols : 0, // array?
34383 // element : null, // wrapped now this.el
34384 _isLayoutInited : null,
34387 getAutoCreate : function(){
34391 cls: 'blog-masonary-wrapper ' + this.cls,
34393 cls : 'mas-boxes masonary'
34400 getChildContainer: function( )
34402 if (this.boxesEl) {
34403 return this.boxesEl;
34406 this.boxesEl = this.el.select('.mas-boxes').first();
34408 return this.boxesEl;
34412 initEvents : function()
34416 if(this.isAutoInitial){
34417 Roo.log('hook children rendered');
34418 this.on('childrenrendered', function() {
34419 Roo.log('children rendered');
34426 initial : function()
34428 this.reloadItems();
34430 this.currentSize = this.el.getBox(true);
34432 /// was window resize... - let's see if this works..
34433 Roo.EventManager.onWindowResize(this.resize, this);
34435 if(!this.isAutoInitial){
34440 this.layout.defer(500,this);
34443 reloadItems: function()
34445 this.bricks = this.el.select('.masonry-brick', true);
34447 this.bricks.each(function(b) {
34448 //Roo.log(b.getSize());
34449 if (!b.attr('originalwidth')) {
34450 b.attr('originalwidth', b.getSize().width);
34455 Roo.log(this.bricks.elements.length);
34458 resize : function()
34461 var cs = this.el.getBox(true);
34463 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
34464 Roo.log("no change in with or X");
34467 this.currentSize = cs;
34471 layout : function()
34474 this._resetLayout();
34475 //this._manageStamps();
34477 // don't animate first layout
34478 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
34479 this.layoutItems( isInstant );
34481 // flag for initalized
34482 this._isLayoutInited = true;
34485 layoutItems : function( isInstant )
34487 //var items = this._getItemsForLayout( this.items );
34488 // original code supports filtering layout items.. we just ignore it..
34490 this._layoutItems( this.bricks , isInstant );
34492 this._postLayout();
34494 _layoutItems : function ( items , isInstant)
34496 //this.fireEvent( 'layout', this, items );
34499 if ( !items || !items.elements.length ) {
34500 // no items, emit event with empty array
34505 items.each(function(item) {
34506 Roo.log("layout item");
34508 // get x/y object from method
34509 var position = this._getItemLayoutPosition( item );
34511 position.item = item;
34512 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
34513 queue.push( position );
34516 this._processLayoutQueue( queue );
34518 /** Sets position of item in DOM
34519 * @param {Element} item
34520 * @param {Number} x - horizontal position
34521 * @param {Number} y - vertical position
34522 * @param {Boolean} isInstant - disables transitions
34524 _processLayoutQueue : function( queue )
34526 for ( var i=0, len = queue.length; i < len; i++ ) {
34527 var obj = queue[i];
34528 obj.item.position('absolute');
34529 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
34535 * Any logic you want to do after each layout,
34536 * i.e. size the container
34538 _postLayout : function()
34540 this.resizeContainer();
34543 resizeContainer : function()
34545 if ( !this.isResizingContainer ) {
34548 var size = this._getContainerSize();
34550 this.el.setSize(size.width,size.height);
34551 this.boxesEl.setSize(size.width,size.height);
34557 _resetLayout : function()
34559 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
34560 this.colWidth = this.el.getWidth();
34561 //this.gutter = this.el.getWidth();
34563 this.measureColumns();
34569 this.colYs.push( 0 );
34575 measureColumns : function()
34577 this.getContainerWidth();
34578 // if columnWidth is 0, default to outerWidth of first item
34579 if ( !this.columnWidth ) {
34580 var firstItem = this.bricks.first();
34581 Roo.log(firstItem);
34582 this.columnWidth = this.containerWidth;
34583 if (firstItem && firstItem.attr('originalwidth') ) {
34584 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
34586 // columnWidth fall back to item of first element
34587 Roo.log("set column width?");
34588 this.initialColumnWidth = this.columnWidth ;
34590 // if first elem has no width, default to size of container
34595 if (this.initialColumnWidth) {
34596 this.columnWidth = this.initialColumnWidth;
34601 // column width is fixed at the top - however if container width get's smaller we should
34604 // this bit calcs how man columns..
34606 var columnWidth = this.columnWidth += this.gutter;
34608 // calculate columns
34609 var containerWidth = this.containerWidth + this.gutter;
34611 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
34612 // fix rounding errors, typically with gutters
34613 var excess = columnWidth - containerWidth % columnWidth;
34616 // if overshoot is less than a pixel, round up, otherwise floor it
34617 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
34618 cols = Math[ mathMethod ]( cols );
34619 this.cols = Math.max( cols, 1 );
34620 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
34622 // padding positioning..
34623 var totalColWidth = this.cols * this.columnWidth;
34624 var padavail = this.containerWidth - totalColWidth;
34625 // so for 2 columns - we need 3 'pads'
34627 var padNeeded = (1+this.cols) * this.padWidth;
34629 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
34631 this.columnWidth += padExtra
34632 //this.padWidth = Math.floor(padavail / ( this.cols));
34634 // adjust colum width so that padding is fixed??
34636 // we have 3 columns ... total = width * 3
34637 // we have X left over... that should be used by
34639 //if (this.expandC) {
34647 getContainerWidth : function()
34649 /* // container is parent if fit width
34650 var container = this.isFitWidth ? this.element.parentNode : this.element;
34651 // check that this.size and size are there
34652 // IE8 triggers resize on body size change, so they might not be
34654 var size = getSize( container ); //FIXME
34655 this.containerWidth = size && size.innerWidth; //FIXME
34658 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
34662 _getItemLayoutPosition : function( item ) // what is item?
34664 // we resize the item to our columnWidth..
34666 item.setWidth(this.columnWidth);
34667 item.autoBoxAdjust = false;
34669 var sz = item.getSize();
34671 // how many columns does this brick span
34672 var remainder = this.containerWidth % this.columnWidth;
34674 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
34675 // round if off by 1 pixel, otherwise use ceil
34676 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
34677 colSpan = Math.min( colSpan, this.cols );
34679 // normally this should be '1' as we dont' currently allow multi width columns..
34681 var colGroup = this._getColGroup( colSpan );
34682 // get the minimum Y value from the columns
34683 var minimumY = Math.min.apply( Math, colGroup );
34684 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
34686 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
34688 // position the brick
34690 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
34691 y: this.currentSize.y + minimumY + this.padHeight
34695 // apply setHeight to necessary columns
34696 var setHeight = minimumY + sz.height + this.padHeight;
34697 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
34699 var setSpan = this.cols + 1 - colGroup.length;
34700 for ( var i = 0; i < setSpan; i++ ) {
34701 this.colYs[ shortColIndex + i ] = setHeight ;
34708 * @param {Number} colSpan - number of columns the element spans
34709 * @returns {Array} colGroup
34711 _getColGroup : function( colSpan )
34713 if ( colSpan < 2 ) {
34714 // if brick spans only one column, use all the column Ys
34719 // how many different places could this brick fit horizontally
34720 var groupCount = this.cols + 1 - colSpan;
34721 // for each group potential horizontal position
34722 for ( var i = 0; i < groupCount; i++ ) {
34723 // make an array of colY values for that one group
34724 var groupColYs = this.colYs.slice( i, i + colSpan );
34725 // and get the max value of the array
34726 colGroup[i] = Math.max.apply( Math, groupColYs );
34731 _manageStamp : function( stamp )
34733 var stampSize = stamp.getSize();
34734 var offset = stamp.getBox();
34735 // get the columns that this stamp affects
34736 var firstX = this.isOriginLeft ? offset.x : offset.right;
34737 var lastX = firstX + stampSize.width;
34738 var firstCol = Math.floor( firstX / this.columnWidth );
34739 firstCol = Math.max( 0, firstCol );
34741 var lastCol = Math.floor( lastX / this.columnWidth );
34742 // lastCol should not go over if multiple of columnWidth #425
34743 lastCol -= lastX % this.columnWidth ? 0 : 1;
34744 lastCol = Math.min( this.cols - 1, lastCol );
34746 // set colYs to bottom of the stamp
34747 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
34750 for ( var i = firstCol; i <= lastCol; i++ ) {
34751 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
34756 _getContainerSize : function()
34758 this.maxY = Math.max.apply( Math, this.colYs );
34763 if ( this.isFitWidth ) {
34764 size.width = this._getContainerFitWidth();
34770 _getContainerFitWidth : function()
34772 var unusedCols = 0;
34773 // count unused columns
34776 if ( this.colYs[i] !== 0 ) {
34781 // fit container to columns that have been used
34782 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
34785 needsResizeLayout : function()
34787 var previousWidth = this.containerWidth;
34788 this.getContainerWidth();
34789 return previousWidth !== this.containerWidth;
34804 * @class Roo.bootstrap.MasonryBrick
34805 * @extends Roo.bootstrap.Component
34806 * Bootstrap MasonryBrick class
34809 * Create a new MasonryBrick
34810 * @param {Object} config The config object
34813 Roo.bootstrap.MasonryBrick = function(config){
34815 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
34817 Roo.bootstrap.MasonryBrick.register(this);
34823 * When a MasonryBrick is clcik
34824 * @param {Roo.bootstrap.MasonryBrick} this
34825 * @param {Roo.EventObject} e
34831 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
34834 * @cfg {String} title
34838 * @cfg {String} html
34842 * @cfg {String} bgimage
34846 * @cfg {String} videourl
34850 * @cfg {String} cls
34854 * @cfg {String} href
34858 * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
34863 * @cfg {String} placetitle (center|bottom)
34868 * @cfg {Boolean} isFitContainer defalut true
34870 isFitContainer : true,
34873 * @cfg {Boolean} preventDefault defalut false
34875 preventDefault : false,
34878 * @cfg {Boolean} inverse defalut false
34880 maskInverse : false,
34882 getAutoCreate : function()
34884 if(!this.isFitContainer){
34885 return this.getSplitAutoCreate();
34888 var cls = 'masonry-brick masonry-brick-full';
34890 if(this.href.length){
34891 cls += ' masonry-brick-link';
34894 if(this.bgimage.length){
34895 cls += ' masonry-brick-image';
34898 if(this.maskInverse){
34899 cls += ' mask-inverse';
34902 if(!this.html.length && !this.maskInverse && !this.videourl.length){
34903 cls += ' enable-mask';
34907 cls += ' masonry-' + this.size + '-brick';
34910 if(this.placetitle.length){
34912 switch (this.placetitle) {
34914 cls += ' masonry-center-title';
34917 cls += ' masonry-bottom-title';
34924 if(!this.html.length && !this.bgimage.length){
34925 cls += ' masonry-center-title';
34928 if(!this.html.length && this.bgimage.length){
34929 cls += ' masonry-bottom-title';
34934 cls += ' ' + this.cls;
34938 tag: (this.href.length) ? 'a' : 'div',
34943 cls: 'masonry-brick-mask'
34947 cls: 'masonry-brick-paragraph',
34953 if(this.href.length){
34954 cfg.href = this.href;
34957 var cn = cfg.cn[1].cn;
34959 if(this.title.length){
34962 cls: 'masonry-brick-title',
34967 if(this.html.length){
34970 cls: 'masonry-brick-text',
34975 if (!this.title.length && !this.html.length) {
34976 cfg.cn[1].cls += ' hide';
34979 if(this.bgimage.length){
34982 cls: 'masonry-brick-image-view',
34987 if(this.videourl.length){
34988 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
34989 // youtube support only?
34992 cls: 'masonry-brick-image-view',
34995 allowfullscreen : true
35003 getSplitAutoCreate : function()
35005 var cls = 'masonry-brick masonry-brick-split';
35007 if(this.href.length){
35008 cls += ' masonry-brick-link';
35011 if(this.bgimage.length){
35012 cls += ' masonry-brick-image';
35016 cls += ' masonry-' + this.size + '-brick';
35019 switch (this.placetitle) {
35021 cls += ' masonry-center-title';
35024 cls += ' masonry-bottom-title';
35027 if(!this.bgimage.length){
35028 cls += ' masonry-center-title';
35031 if(this.bgimage.length){
35032 cls += ' masonry-bottom-title';
35038 cls += ' ' + this.cls;
35042 tag: (this.href.length) ? 'a' : 'div',
35047 cls: 'masonry-brick-split-head',
35051 cls: 'masonry-brick-paragraph',
35058 cls: 'masonry-brick-split-body',
35064 if(this.href.length){
35065 cfg.href = this.href;
35068 if(this.title.length){
35069 cfg.cn[0].cn[0].cn.push({
35071 cls: 'masonry-brick-title',
35076 if(this.html.length){
35077 cfg.cn[1].cn.push({
35079 cls: 'masonry-brick-text',
35084 if(this.bgimage.length){
35085 cfg.cn[0].cn.push({
35087 cls: 'masonry-brick-image-view',
35092 if(this.videourl.length){
35093 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
35094 // youtube support only?
35095 cfg.cn[0].cn.cn.push({
35097 cls: 'masonry-brick-image-view',
35100 allowfullscreen : true
35107 initEvents: function()
35109 switch (this.size) {
35142 this.el.on('touchstart', this.onTouchStart, this);
35143 this.el.on('touchmove', this.onTouchMove, this);
35144 this.el.on('touchend', this.onTouchEnd, this);
35145 this.el.on('contextmenu', this.onContextMenu, this);
35147 this.el.on('mouseenter' ,this.enter, this);
35148 this.el.on('mouseleave', this.leave, this);
35149 this.el.on('click', this.onClick, this);
35152 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
35153 this.parent().bricks.push(this);
35158 onClick: function(e, el)
35160 var time = this.endTimer - this.startTimer;
35161 // Roo.log(e.preventDefault());
35164 e.preventDefault();
35169 if(!this.preventDefault){
35173 e.preventDefault();
35175 if (this.activeClass != '') {
35176 this.selectBrick();
35179 this.fireEvent('click', this, e);
35182 enter: function(e, el)
35184 e.preventDefault();
35186 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
35190 if(this.bgimage.length && this.html.length){
35191 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
35195 leave: function(e, el)
35197 e.preventDefault();
35199 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
35203 if(this.bgimage.length && this.html.length){
35204 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
35208 onTouchStart: function(e, el)
35210 // e.preventDefault();
35212 this.touchmoved = false;
35214 if(!this.isFitContainer){
35218 if(!this.bgimage.length || !this.html.length){
35222 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
35224 this.timer = new Date().getTime();
35228 onTouchMove: function(e, el)
35230 this.touchmoved = true;
35233 onContextMenu : function(e,el)
35235 e.preventDefault();
35236 e.stopPropagation();
35240 onTouchEnd: function(e, el)
35242 // e.preventDefault();
35244 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
35251 if(!this.bgimage.length || !this.html.length){
35253 if(this.href.length){
35254 window.location.href = this.href;
35260 if(!this.isFitContainer){
35264 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
35266 window.location.href = this.href;
35269 //selection on single brick only
35270 selectBrick : function() {
35272 if (!this.parentId) {
35276 var m = Roo.bootstrap.LayoutMasonry.get(this.parentId);
35277 var index = m.selectedBrick.indexOf(this.id);
35280 m.selectedBrick.splice(index,1);
35281 this.el.removeClass(this.activeClass);
35285 for(var i = 0; i < m.selectedBrick.length; i++) {
35286 var b = Roo.bootstrap.MasonryBrick.get(m.selectedBrick[i]);
35287 b.el.removeClass(b.activeClass);
35290 m.selectedBrick = [];
35292 m.selectedBrick.push(this.id);
35293 this.el.addClass(this.activeClass);
35297 isSelected : function(){
35298 return this.el.hasClass(this.activeClass);
35303 Roo.apply(Roo.bootstrap.MasonryBrick, {
35306 groups : new Roo.util.MixedCollection(false, function(o) { return o.el.id; }),
35308 * register a Masonry Brick
35309 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
35312 register : function(brick)
35314 //this.groups[brick.id] = brick;
35315 this.groups.add(brick.id, brick);
35318 * fetch a masonry brick based on the masonry brick ID
35319 * @param {string} the masonry brick to add
35320 * @returns {Roo.bootstrap.MasonryBrick} the masonry brick
35323 get: function(brick_id)
35325 // if (typeof(this.groups[brick_id]) == 'undefined') {
35328 // return this.groups[brick_id] ;
35330 if(this.groups.key(brick_id)) {
35331 return this.groups.key(brick_id);
35349 * @class Roo.bootstrap.Brick
35350 * @extends Roo.bootstrap.Component
35351 * Bootstrap Brick class
35354 * Create a new Brick
35355 * @param {Object} config The config object
35358 Roo.bootstrap.Brick = function(config){
35359 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
35365 * When a Brick is click
35366 * @param {Roo.bootstrap.Brick} this
35367 * @param {Roo.EventObject} e
35373 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
35376 * @cfg {String} title
35380 * @cfg {String} html
35384 * @cfg {String} bgimage
35388 * @cfg {String} cls
35392 * @cfg {String} href
35396 * @cfg {String} video
35400 * @cfg {Boolean} square
35404 getAutoCreate : function()
35406 var cls = 'roo-brick';
35408 if(this.href.length){
35409 cls += ' roo-brick-link';
35412 if(this.bgimage.length){
35413 cls += ' roo-brick-image';
35416 if(!this.html.length && !this.bgimage.length){
35417 cls += ' roo-brick-center-title';
35420 if(!this.html.length && this.bgimage.length){
35421 cls += ' roo-brick-bottom-title';
35425 cls += ' ' + this.cls;
35429 tag: (this.href.length) ? 'a' : 'div',
35434 cls: 'roo-brick-paragraph',
35440 if(this.href.length){
35441 cfg.href = this.href;
35444 var cn = cfg.cn[0].cn;
35446 if(this.title.length){
35449 cls: 'roo-brick-title',
35454 if(this.html.length){
35457 cls: 'roo-brick-text',
35464 if(this.bgimage.length){
35467 cls: 'roo-brick-image-view',
35475 initEvents: function()
35477 if(this.title.length || this.html.length){
35478 this.el.on('mouseenter' ,this.enter, this);
35479 this.el.on('mouseleave', this.leave, this);
35482 Roo.EventManager.onWindowResize(this.resize, this);
35484 if(this.bgimage.length){
35485 this.imageEl = this.el.select('.roo-brick-image-view', true).first();
35486 this.imageEl.on('load', this.onImageLoad, this);
35493 onImageLoad : function()
35498 resize : function()
35500 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
35502 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
35504 if(this.bgimage.length){
35505 var image = this.el.select('.roo-brick-image-view', true).first();
35507 image.setWidth(paragraph.getWidth());
35510 image.setHeight(paragraph.getWidth());
35513 this.el.setHeight(image.getHeight());
35514 paragraph.setHeight(image.getHeight());
35520 enter: function(e, el)
35522 e.preventDefault();
35524 if(this.bgimage.length){
35525 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
35526 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
35530 leave: function(e, el)
35532 e.preventDefault();
35534 if(this.bgimage.length){
35535 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
35536 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
35551 * @class Roo.bootstrap.NumberField
35552 * @extends Roo.bootstrap.Input
35553 * Bootstrap NumberField class
35559 * Create a new NumberField
35560 * @param {Object} config The config object
35563 Roo.bootstrap.NumberField = function(config){
35564 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
35567 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
35570 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
35572 allowDecimals : true,
35574 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
35576 decimalSeparator : ".",
35578 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
35580 decimalPrecision : 2,
35582 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
35584 allowNegative : true,
35587 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
35591 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
35593 minValue : Number.NEGATIVE_INFINITY,
35595 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
35597 maxValue : Number.MAX_VALUE,
35599 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
35601 minText : "The minimum value for this field is {0}",
35603 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
35605 maxText : "The maximum value for this field is {0}",
35607 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
35608 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
35610 nanText : "{0} is not a valid number",
35612 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
35614 thousandsDelimiter : false,
35616 * @cfg {String} valueAlign alignment of value
35618 valueAlign : "left",
35620 getAutoCreate : function()
35622 var hiddenInput = {
35626 cls: 'hidden-number-input'
35630 hiddenInput.name = this.name;
35635 var cfg = Roo.bootstrap.NumberField.superclass.getAutoCreate.call(this);
35637 this.name = hiddenInput.name;
35639 if(cfg.cn.length > 0) {
35640 cfg.cn.push(hiddenInput);
35647 initEvents : function()
35649 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
35651 var allowed = "0123456789";
35653 if(this.allowDecimals){
35654 allowed += this.decimalSeparator;
35657 if(this.allowNegative){
35661 if(this.thousandsDelimiter) {
35665 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
35667 var keyPress = function(e){
35669 var k = e.getKey();
35671 var c = e.getCharCode();
35674 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
35675 allowed.indexOf(String.fromCharCode(c)) === -1
35681 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
35685 if(allowed.indexOf(String.fromCharCode(c)) === -1){
35690 this.el.on("keypress", keyPress, this);
35693 validateValue : function(value)
35696 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
35700 var num = this.parseValue(value);
35703 this.markInvalid(String.format(this.nanText, value));
35707 if(num < this.minValue){
35708 this.markInvalid(String.format(this.minText, this.minValue));
35712 if(num > this.maxValue){
35713 this.markInvalid(String.format(this.maxText, this.maxValue));
35720 getValue : function()
35722 var v = this.hiddenEl().getValue();
35724 return this.fixPrecision(this.parseValue(v));
35727 parseValue : function(value)
35729 if(this.thousandsDelimiter) {
35731 r = new RegExp(",", "g");
35732 value = value.replace(r, "");
35735 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
35736 return isNaN(value) ? '' : value;
35739 fixPrecision : function(value)
35741 if(this.thousandsDelimiter) {
35743 r = new RegExp(",", "g");
35744 value = value.replace(r, "");
35747 var nan = isNaN(value);
35749 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
35750 return nan ? '' : value;
35752 return parseFloat(value).toFixed(this.decimalPrecision);
35755 setValue : function(v)
35757 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
35763 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
35765 this.inputEl().dom.value = (v == '') ? '' :
35766 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
35768 if(!this.allowZero && v === '0') {
35769 this.hiddenEl().dom.value = '';
35770 this.inputEl().dom.value = '';
35777 decimalPrecisionFcn : function(v)
35779 return Math.floor(v);
35782 beforeBlur : function()
35784 var v = this.parseValue(this.getRawValue());
35786 if(v || v === 0 || v === ''){
35791 hiddenEl : function()
35793 return this.el.select('input.hidden-number-input',true).first();
35805 * @class Roo.bootstrap.DocumentSlider
35806 * @extends Roo.bootstrap.Component
35807 * Bootstrap DocumentSlider class
35810 * Create a new DocumentViewer
35811 * @param {Object} config The config object
35814 Roo.bootstrap.DocumentSlider = function(config){
35815 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
35822 * Fire after initEvent
35823 * @param {Roo.bootstrap.DocumentSlider} this
35828 * Fire after update
35829 * @param {Roo.bootstrap.DocumentSlider} this
35835 * @param {Roo.bootstrap.DocumentSlider} this
35841 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
35847 getAutoCreate : function()
35851 cls : 'roo-document-slider',
35855 cls : 'roo-document-slider-header',
35859 cls : 'roo-document-slider-header-title'
35865 cls : 'roo-document-slider-body',
35869 cls : 'roo-document-slider-prev',
35873 cls : 'fa fa-chevron-left'
35879 cls : 'roo-document-slider-thumb',
35883 cls : 'roo-document-slider-image'
35889 cls : 'roo-document-slider-next',
35893 cls : 'fa fa-chevron-right'
35905 initEvents : function()
35907 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
35908 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
35910 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
35911 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
35913 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
35914 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
35916 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
35917 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
35919 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
35920 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
35922 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
35923 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
35925 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
35926 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
35928 this.thumbEl.on('click', this.onClick, this);
35930 this.prevIndicator.on('click', this.prev, this);
35932 this.nextIndicator.on('click', this.next, this);
35936 initial : function()
35938 if(this.files.length){
35939 this.indicator = 1;
35943 this.fireEvent('initial', this);
35946 update : function()
35948 this.imageEl.attr('src', this.files[this.indicator - 1]);
35950 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
35952 this.prevIndicator.show();
35954 if(this.indicator == 1){
35955 this.prevIndicator.hide();
35958 this.nextIndicator.show();
35960 if(this.indicator == this.files.length){
35961 this.nextIndicator.hide();
35964 this.thumbEl.scrollTo('top');
35966 this.fireEvent('update', this);
35969 onClick : function(e)
35971 e.preventDefault();
35973 this.fireEvent('click', this);
35978 e.preventDefault();
35980 this.indicator = Math.max(1, this.indicator - 1);
35987 e.preventDefault();
35989 this.indicator = Math.min(this.files.length, this.indicator + 1);
36003 * @class Roo.bootstrap.RadioSet
36004 * @extends Roo.bootstrap.Input
36005 * Bootstrap RadioSet class
36006 * @cfg {String} indicatorpos (left|right) default left
36007 * @cfg {Boolean} inline (true|false) inline the element (default true)
36008 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
36010 * Create a new RadioSet
36011 * @param {Object} config The config object
36014 Roo.bootstrap.RadioSet = function(config){
36016 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
36020 Roo.bootstrap.RadioSet.register(this);
36025 * Fires when the element is checked or unchecked.
36026 * @param {Roo.bootstrap.RadioSet} this This radio
36027 * @param {Roo.bootstrap.Radio} item The checked item
36032 * Fires when the element is click.
36033 * @param {Roo.bootstrap.RadioSet} this This radio set
36034 * @param {Roo.bootstrap.Radio} item The checked item
36035 * @param {Roo.EventObject} e The event object
36042 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
36050 indicatorpos : 'left',
36052 getAutoCreate : function()
36056 cls : 'roo-radio-set-label',
36060 html : this.fieldLabel
36064 if (Roo.bootstrap.version == 3) {
36067 if(this.indicatorpos == 'left'){
36070 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
36071 tooltip : 'This field is required'
36076 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
36077 tooltip : 'This field is required'
36083 cls : 'roo-radio-set-items'
36086 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
36088 if (align === 'left' && this.fieldLabel.length) {
36091 cls : "roo-radio-set-right",
36097 if(this.labelWidth > 12){
36098 label.style = "width: " + this.labelWidth + 'px';
36101 if(this.labelWidth < 13 && this.labelmd == 0){
36102 this.labelmd = this.labelWidth;
36105 if(this.labellg > 0){
36106 label.cls += ' col-lg-' + this.labellg;
36107 items.cls += ' col-lg-' + (12 - this.labellg);
36110 if(this.labelmd > 0){
36111 label.cls += ' col-md-' + this.labelmd;
36112 items.cls += ' col-md-' + (12 - this.labelmd);
36115 if(this.labelsm > 0){
36116 label.cls += ' col-sm-' + this.labelsm;
36117 items.cls += ' col-sm-' + (12 - this.labelsm);
36120 if(this.labelxs > 0){
36121 label.cls += ' col-xs-' + this.labelxs;
36122 items.cls += ' col-xs-' + (12 - this.labelxs);
36128 cls : 'roo-radio-set',
36132 cls : 'roo-radio-set-input',
36135 value : this.value ? this.value : ''
36142 if(this.weight.length){
36143 cfg.cls += ' roo-radio-' + this.weight;
36147 cfg.cls += ' roo-radio-set-inline';
36151 ['xs','sm','md','lg'].map(function(size){
36152 if (settings[size]) {
36153 cfg.cls += ' col-' + size + '-' + settings[size];
36161 initEvents : function()
36163 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
36164 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
36166 if(!this.fieldLabel.length){
36167 this.labelEl.hide();
36170 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
36171 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
36173 this.indicator = this.indicatorEl();
36175 if(this.indicator){
36176 this.indicator.addClass('invisible');
36179 this.originalValue = this.getValue();
36183 inputEl: function ()
36185 return this.el.select('.roo-radio-set-input', true).first();
36188 getChildContainer : function()
36190 return this.itemsEl;
36193 register : function(item)
36195 this.radioes.push(item);
36199 validate : function()
36201 if(this.getVisibilityEl().hasClass('hidden')){
36207 Roo.each(this.radioes, function(i){
36216 if(this.allowBlank) {
36220 if(this.disabled || valid){
36225 this.markInvalid();
36230 markValid : function()
36232 if(this.labelEl.isVisible(true) && this.indicatorEl()){
36233 this.indicatorEl().removeClass('visible');
36234 this.indicatorEl().addClass('invisible');
36238 if (Roo.bootstrap.version == 3) {
36239 this.el.removeClass([this.invalidClass, this.validClass]);
36240 this.el.addClass(this.validClass);
36242 this.el.removeClass(['is-invalid','is-valid']);
36243 this.el.addClass(['is-valid']);
36245 this.fireEvent('valid', this);
36248 markInvalid : function(msg)
36250 if(this.allowBlank || this.disabled){
36254 if(this.labelEl.isVisible(true) && this.indicatorEl()){
36255 this.indicatorEl().removeClass('invisible');
36256 this.indicatorEl().addClass('visible');
36258 if (Roo.bootstrap.version == 3) {
36259 this.el.removeClass([this.invalidClass, this.validClass]);
36260 this.el.addClass(this.invalidClass);
36262 this.el.removeClass(['is-invalid','is-valid']);
36263 this.el.addClass(['is-invalid']);
36266 this.fireEvent('invalid', this, msg);
36270 setValue : function(v, suppressEvent)
36272 if(this.value === v){
36279 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
36282 Roo.each(this.radioes, function(i){
36284 i.el.removeClass('checked');
36287 Roo.each(this.radioes, function(i){
36289 if(i.value === v || i.value.toString() === v.toString()){
36291 i.el.addClass('checked');
36293 if(suppressEvent !== true){
36294 this.fireEvent('check', this, i);
36305 clearInvalid : function(){
36307 if(!this.el || this.preventMark){
36311 this.el.removeClass([this.invalidClass]);
36313 this.fireEvent('valid', this);
36318 Roo.apply(Roo.bootstrap.RadioSet, {
36322 register : function(set)
36324 this.groups[set.name] = set;
36327 get: function(name)
36329 if (typeof(this.groups[name]) == 'undefined') {
36333 return this.groups[name] ;
36339 * Ext JS Library 1.1.1
36340 * Copyright(c) 2006-2007, Ext JS, LLC.
36342 * Originally Released Under LGPL - original licence link has changed is not relivant.
36345 * <script type="text/javascript">
36350 * @class Roo.bootstrap.SplitBar
36351 * @extends Roo.util.Observable
36352 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
36356 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
36357 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
36358 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
36359 split.minSize = 100;
36360 split.maxSize = 600;
36361 split.animate = true;
36362 split.on('moved', splitterMoved);
36365 * Create a new SplitBar
36366 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
36367 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
36368 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
36369 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
36370 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
36371 position of the SplitBar).
36373 Roo.bootstrap.SplitBar = function(cfg){
36378 // dragElement : elm
36379 // resizingElement: el,
36381 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
36382 // placement : Roo.bootstrap.SplitBar.LEFT ,
36383 // existingProxy ???
36386 this.el = Roo.get(cfg.dragElement, true);
36387 this.el.dom.unselectable = "on";
36389 this.resizingEl = Roo.get(cfg.resizingElement, true);
36393 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
36394 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
36397 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
36400 * The minimum size of the resizing element. (Defaults to 0)
36406 * The maximum size of the resizing element. (Defaults to 2000)
36409 this.maxSize = 2000;
36412 * Whether to animate the transition to the new size
36415 this.animate = false;
36418 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
36421 this.useShim = false;
36426 if(!cfg.existingProxy){
36428 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
36430 this.proxy = Roo.get(cfg.existingProxy).dom;
36433 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
36436 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
36439 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
36442 this.dragSpecs = {};
36445 * @private The adapter to use to positon and resize elements
36447 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
36448 this.adapter.init(this);
36450 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
36452 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
36453 this.el.addClass("roo-splitbar-h");
36456 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
36457 this.el.addClass("roo-splitbar-v");
36463 * Fires when the splitter is moved (alias for {@link #event-moved})
36464 * @param {Roo.bootstrap.SplitBar} this
36465 * @param {Number} newSize the new width or height
36470 * Fires when the splitter is moved
36471 * @param {Roo.bootstrap.SplitBar} this
36472 * @param {Number} newSize the new width or height
36476 * @event beforeresize
36477 * Fires before the splitter is dragged
36478 * @param {Roo.bootstrap.SplitBar} this
36480 "beforeresize" : true,
36482 "beforeapply" : true
36485 Roo.util.Observable.call(this);
36488 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
36489 onStartProxyDrag : function(x, y){
36490 this.fireEvent("beforeresize", this);
36492 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
36494 o.enableDisplayMode("block");
36495 // all splitbars share the same overlay
36496 Roo.bootstrap.SplitBar.prototype.overlay = o;
36498 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
36499 this.overlay.show();
36500 Roo.get(this.proxy).setDisplayed("block");
36501 var size = this.adapter.getElementSize(this);
36502 this.activeMinSize = this.getMinimumSize();;
36503 this.activeMaxSize = this.getMaximumSize();;
36504 var c1 = size - this.activeMinSize;
36505 var c2 = Math.max(this.activeMaxSize - size, 0);
36506 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
36507 this.dd.resetConstraints();
36508 this.dd.setXConstraint(
36509 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
36510 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
36512 this.dd.setYConstraint(0, 0);
36514 this.dd.resetConstraints();
36515 this.dd.setXConstraint(0, 0);
36516 this.dd.setYConstraint(
36517 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
36518 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
36521 this.dragSpecs.startSize = size;
36522 this.dragSpecs.startPoint = [x, y];
36523 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
36527 * @private Called after the drag operation by the DDProxy
36529 onEndProxyDrag : function(e){
36530 Roo.get(this.proxy).setDisplayed(false);
36531 var endPoint = Roo.lib.Event.getXY(e);
36533 this.overlay.hide();
36536 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
36537 newSize = this.dragSpecs.startSize +
36538 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
36539 endPoint[0] - this.dragSpecs.startPoint[0] :
36540 this.dragSpecs.startPoint[0] - endPoint[0]
36543 newSize = this.dragSpecs.startSize +
36544 (this.placement == Roo.bootstrap.SplitBar.TOP ?
36545 endPoint[1] - this.dragSpecs.startPoint[1] :
36546 this.dragSpecs.startPoint[1] - endPoint[1]
36549 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
36550 if(newSize != this.dragSpecs.startSize){
36551 if(this.fireEvent('beforeapply', this, newSize) !== false){
36552 this.adapter.setElementSize(this, newSize);
36553 this.fireEvent("moved", this, newSize);
36554 this.fireEvent("resize", this, newSize);
36560 * Get the adapter this SplitBar uses
36561 * @return The adapter object
36563 getAdapter : function(){
36564 return this.adapter;
36568 * Set the adapter this SplitBar uses
36569 * @param {Object} adapter A SplitBar adapter object
36571 setAdapter : function(adapter){
36572 this.adapter = adapter;
36573 this.adapter.init(this);
36577 * Gets the minimum size for the resizing element
36578 * @return {Number} The minimum size
36580 getMinimumSize : function(){
36581 return this.minSize;
36585 * Sets the minimum size for the resizing element
36586 * @param {Number} minSize The minimum size
36588 setMinimumSize : function(minSize){
36589 this.minSize = minSize;
36593 * Gets the maximum size for the resizing element
36594 * @return {Number} The maximum size
36596 getMaximumSize : function(){
36597 return this.maxSize;
36601 * Sets the maximum size for the resizing element
36602 * @param {Number} maxSize The maximum size
36604 setMaximumSize : function(maxSize){
36605 this.maxSize = maxSize;
36609 * Sets the initialize size for the resizing element
36610 * @param {Number} size The initial size
36612 setCurrentSize : function(size){
36613 var oldAnimate = this.animate;
36614 this.animate = false;
36615 this.adapter.setElementSize(this, size);
36616 this.animate = oldAnimate;
36620 * Destroy this splitbar.
36621 * @param {Boolean} removeEl True to remove the element
36623 destroy : function(removeEl){
36625 this.shim.remove();
36628 this.proxy.parentNode.removeChild(this.proxy);
36636 * @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.
36638 Roo.bootstrap.SplitBar.createProxy = function(dir){
36639 var proxy = new Roo.Element(document.createElement("div"));
36640 proxy.unselectable();
36641 var cls = 'roo-splitbar-proxy';
36642 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
36643 document.body.appendChild(proxy.dom);
36648 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
36649 * Default Adapter. It assumes the splitter and resizing element are not positioned
36650 * elements and only gets/sets the width of the element. Generally used for table based layouts.
36652 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
36655 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
36656 // do nothing for now
36657 init : function(s){
36661 * Called before drag operations to get the current size of the resizing element.
36662 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
36664 getElementSize : function(s){
36665 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
36666 return s.resizingEl.getWidth();
36668 return s.resizingEl.getHeight();
36673 * Called after drag operations to set the size of the resizing element.
36674 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
36675 * @param {Number} newSize The new size to set
36676 * @param {Function} onComplete A function to be invoked when resizing is complete
36678 setElementSize : function(s, newSize, onComplete){
36679 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
36681 s.resizingEl.setWidth(newSize);
36683 onComplete(s, newSize);
36686 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
36691 s.resizingEl.setHeight(newSize);
36693 onComplete(s, newSize);
36696 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
36703 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
36704 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
36705 * Adapter that moves the splitter element to align with the resized sizing element.
36706 * Used with an absolute positioned SplitBar.
36707 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
36708 * document.body, make sure you assign an id to the body element.
36710 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
36711 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
36712 this.container = Roo.get(container);
36715 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
36716 init : function(s){
36717 this.basic.init(s);
36720 getElementSize : function(s){
36721 return this.basic.getElementSize(s);
36724 setElementSize : function(s, newSize, onComplete){
36725 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
36728 moveSplitter : function(s){
36729 var yes = Roo.bootstrap.SplitBar;
36730 switch(s.placement){
36732 s.el.setX(s.resizingEl.getRight());
36735 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
36738 s.el.setY(s.resizingEl.getBottom());
36741 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
36748 * Orientation constant - Create a vertical SplitBar
36752 Roo.bootstrap.SplitBar.VERTICAL = 1;
36755 * Orientation constant - Create a horizontal SplitBar
36759 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
36762 * Placement constant - The resizing element is to the left of the splitter element
36766 Roo.bootstrap.SplitBar.LEFT = 1;
36769 * Placement constant - The resizing element is to the right of the splitter element
36773 Roo.bootstrap.SplitBar.RIGHT = 2;
36776 * Placement constant - The resizing element is positioned above the splitter element
36780 Roo.bootstrap.SplitBar.TOP = 3;
36783 * Placement constant - The resizing element is positioned under splitter element
36787 Roo.bootstrap.SplitBar.BOTTOM = 4;
36788 Roo.namespace("Roo.bootstrap.layout");/*
36790 * Ext JS Library 1.1.1
36791 * Copyright(c) 2006-2007, Ext JS, LLC.
36793 * Originally Released Under LGPL - original licence link has changed is not relivant.
36796 * <script type="text/javascript">
36800 * @class Roo.bootstrap.layout.Manager
36801 * @extends Roo.bootstrap.Component
36802 * Base class for layout managers.
36804 Roo.bootstrap.layout.Manager = function(config)
36806 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
36812 /** false to disable window resize monitoring @type Boolean */
36813 this.monitorWindowResize = true;
36818 * Fires when a layout is performed.
36819 * @param {Roo.LayoutManager} this
36823 * @event regionresized
36824 * Fires when the user resizes a region.
36825 * @param {Roo.LayoutRegion} region The resized region
36826 * @param {Number} newSize The new size (width for east/west, height for north/south)
36828 "regionresized" : true,
36830 * @event regioncollapsed
36831 * Fires when a region is collapsed.
36832 * @param {Roo.LayoutRegion} region The collapsed region
36834 "regioncollapsed" : true,
36836 * @event regionexpanded
36837 * Fires when a region is expanded.
36838 * @param {Roo.LayoutRegion} region The expanded region
36840 "regionexpanded" : true
36842 this.updating = false;
36845 this.el = Roo.get(config.el);
36851 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
36856 monitorWindowResize : true,
36862 onRender : function(ct, position)
36865 this.el = Roo.get(ct);
36868 //this.fireEvent('render',this);
36872 initEvents: function()
36876 // ie scrollbar fix
36877 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
36878 document.body.scroll = "no";
36879 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
36880 this.el.position('relative');
36882 this.id = this.el.id;
36883 this.el.addClass("roo-layout-container");
36884 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
36885 if(this.el.dom != document.body ) {
36886 this.el.on('resize', this.layout,this);
36887 this.el.on('show', this.layout,this);
36893 * Returns true if this layout is currently being updated
36894 * @return {Boolean}
36896 isUpdating : function(){
36897 return this.updating;
36901 * Suspend the LayoutManager from doing auto-layouts while
36902 * making multiple add or remove calls
36904 beginUpdate : function(){
36905 this.updating = true;
36909 * Restore auto-layouts and optionally disable the manager from performing a layout
36910 * @param {Boolean} noLayout true to disable a layout update
36912 endUpdate : function(noLayout){
36913 this.updating = false;
36919 layout: function(){
36923 onRegionResized : function(region, newSize){
36924 this.fireEvent("regionresized", region, newSize);
36928 onRegionCollapsed : function(region){
36929 this.fireEvent("regioncollapsed", region);
36932 onRegionExpanded : function(region){
36933 this.fireEvent("regionexpanded", region);
36937 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
36938 * performs box-model adjustments.
36939 * @return {Object} The size as an object {width: (the width), height: (the height)}
36941 getViewSize : function()
36944 if(this.el.dom != document.body){
36945 size = this.el.getSize();
36947 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
36949 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
36950 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
36955 * Returns the Element this layout is bound to.
36956 * @return {Roo.Element}
36958 getEl : function(){
36963 * Returns the specified region.
36964 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
36965 * @return {Roo.LayoutRegion}
36967 getRegion : function(target){
36968 return this.regions[target.toLowerCase()];
36971 onWindowResize : function(){
36972 if(this.monitorWindowResize){
36979 * Ext JS Library 1.1.1
36980 * Copyright(c) 2006-2007, Ext JS, LLC.
36982 * Originally Released Under LGPL - original licence link has changed is not relivant.
36985 * <script type="text/javascript">
36988 * @class Roo.bootstrap.layout.Border
36989 * @extends Roo.bootstrap.layout.Manager
36990 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
36991 * please see: examples/bootstrap/nested.html<br><br>
36993 <b>The container the layout is rendered into can be either the body element or any other element.
36994 If it is not the body element, the container needs to either be an absolute positioned element,
36995 or you will need to add "position:relative" to the css of the container. You will also need to specify
36996 the container size if it is not the body element.</b>
36999 * Create a new Border
37000 * @param {Object} config Configuration options
37002 Roo.bootstrap.layout.Border = function(config){
37003 config = config || {};
37004 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
37008 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
37009 if(config[region]){
37010 config[region].region = region;
37011 this.addRegion(config[region]);
37017 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
37019 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
37021 parent : false, // this might point to a 'nest' or a ???
37024 * Creates and adds a new region if it doesn't already exist.
37025 * @param {String} target The target region key (north, south, east, west or center).
37026 * @param {Object} config The regions config object
37027 * @return {BorderLayoutRegion} The new region
37029 addRegion : function(config)
37031 if(!this.regions[config.region]){
37032 var r = this.factory(config);
37033 this.bindRegion(r);
37035 return this.regions[config.region];
37039 bindRegion : function(r){
37040 this.regions[r.config.region] = r;
37042 r.on("visibilitychange", this.layout, this);
37043 r.on("paneladded", this.layout, this);
37044 r.on("panelremoved", this.layout, this);
37045 r.on("invalidated", this.layout, this);
37046 r.on("resized", this.onRegionResized, this);
37047 r.on("collapsed", this.onRegionCollapsed, this);
37048 r.on("expanded", this.onRegionExpanded, this);
37052 * Performs a layout update.
37054 layout : function()
37056 if(this.updating) {
37060 // render all the rebions if they have not been done alreayd?
37061 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
37062 if(this.regions[region] && !this.regions[region].bodyEl){
37063 this.regions[region].onRender(this.el)
37067 var size = this.getViewSize();
37068 var w = size.width;
37069 var h = size.height;
37074 //var x = 0, y = 0;
37076 var rs = this.regions;
37077 var north = rs["north"];
37078 var south = rs["south"];
37079 var west = rs["west"];
37080 var east = rs["east"];
37081 var center = rs["center"];
37082 //if(this.hideOnLayout){ // not supported anymore
37083 //c.el.setStyle("display", "none");
37085 if(north && north.isVisible()){
37086 var b = north.getBox();
37087 var m = north.getMargins();
37088 b.width = w - (m.left+m.right);
37091 centerY = b.height + b.y + m.bottom;
37092 centerH -= centerY;
37093 north.updateBox(this.safeBox(b));
37095 if(south && south.isVisible()){
37096 var b = south.getBox();
37097 var m = south.getMargins();
37098 b.width = w - (m.left+m.right);
37100 var totalHeight = (b.height + m.top + m.bottom);
37101 b.y = h - totalHeight + m.top;
37102 centerH -= totalHeight;
37103 south.updateBox(this.safeBox(b));
37105 if(west && west.isVisible()){
37106 var b = west.getBox();
37107 var m = west.getMargins();
37108 b.height = centerH - (m.top+m.bottom);
37110 b.y = centerY + m.top;
37111 var totalWidth = (b.width + m.left + m.right);
37112 centerX += totalWidth;
37113 centerW -= totalWidth;
37114 west.updateBox(this.safeBox(b));
37116 if(east && east.isVisible()){
37117 var b = east.getBox();
37118 var m = east.getMargins();
37119 b.height = centerH - (m.top+m.bottom);
37120 var totalWidth = (b.width + m.left + m.right);
37121 b.x = w - totalWidth + m.left;
37122 b.y = centerY + m.top;
37123 centerW -= totalWidth;
37124 east.updateBox(this.safeBox(b));
37127 var m = center.getMargins();
37129 x: centerX + m.left,
37130 y: centerY + m.top,
37131 width: centerW - (m.left+m.right),
37132 height: centerH - (m.top+m.bottom)
37134 //if(this.hideOnLayout){
37135 //center.el.setStyle("display", "block");
37137 center.updateBox(this.safeBox(centerBox));
37140 this.fireEvent("layout", this);
37144 safeBox : function(box){
37145 box.width = Math.max(0, box.width);
37146 box.height = Math.max(0, box.height);
37151 * Adds a ContentPanel (or subclass) to this layout.
37152 * @param {String} target The target region key (north, south, east, west or center).
37153 * @param {Roo.ContentPanel} panel The panel to add
37154 * @return {Roo.ContentPanel} The added panel
37156 add : function(target, panel){
37158 target = target.toLowerCase();
37159 return this.regions[target].add(panel);
37163 * Remove a ContentPanel (or subclass) to this layout.
37164 * @param {String} target The target region key (north, south, east, west or center).
37165 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
37166 * @return {Roo.ContentPanel} The removed panel
37168 remove : function(target, panel){
37169 target = target.toLowerCase();
37170 return this.regions[target].remove(panel);
37174 * Searches all regions for a panel with the specified id
37175 * @param {String} panelId
37176 * @return {Roo.ContentPanel} The panel or null if it wasn't found
37178 findPanel : function(panelId){
37179 var rs = this.regions;
37180 for(var target in rs){
37181 if(typeof rs[target] != "function"){
37182 var p = rs[target].getPanel(panelId);
37192 * Searches all regions for a panel with the specified id and activates (shows) it.
37193 * @param {String/ContentPanel} panelId The panels id or the panel itself
37194 * @return {Roo.ContentPanel} The shown panel or null
37196 showPanel : function(panelId) {
37197 var rs = this.regions;
37198 for(var target in rs){
37199 var r = rs[target];
37200 if(typeof r != "function"){
37201 if(r.hasPanel(panelId)){
37202 return r.showPanel(panelId);
37210 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
37211 * @param {Roo.state.Provider} provider (optional) An alternate state provider
37214 restoreState : function(provider){
37216 provider = Roo.state.Manager;
37218 var sm = new Roo.LayoutStateManager();
37219 sm.init(this, provider);
37225 * Adds a xtype elements to the layout.
37229 xtype : 'ContentPanel',
37236 xtype : 'NestedLayoutPanel',
37242 items : [ ... list of content panels or nested layout panels.. ]
37246 * @param {Object} cfg Xtype definition of item to add.
37248 addxtype : function(cfg)
37250 // basically accepts a pannel...
37251 // can accept a layout region..!?!?
37252 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
37255 // theory? children can only be panels??
37257 //if (!cfg.xtype.match(/Panel$/)) {
37262 if (typeof(cfg.region) == 'undefined') {
37263 Roo.log("Failed to add Panel, region was not set");
37267 var region = cfg.region;
37273 xitems = cfg.items;
37278 if ( region == 'center') {
37279 Roo.log("Center: " + cfg.title);
37285 case 'Content': // ContentPanel (el, cfg)
37286 case 'Scroll': // ContentPanel (el, cfg)
37288 cfg.autoCreate = cfg.autoCreate || true;
37289 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
37291 // var el = this.el.createChild();
37292 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
37295 this.add(region, ret);
37299 case 'TreePanel': // our new panel!
37300 cfg.el = this.el.createChild();
37301 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
37302 this.add(region, ret);
37307 // create a new Layout (which is a Border Layout...
37309 var clayout = cfg.layout;
37310 clayout.el = this.el.createChild();
37311 clayout.items = clayout.items || [];
37315 // replace this exitems with the clayout ones..
37316 xitems = clayout.items;
37318 // force background off if it's in center...
37319 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
37320 cfg.background = false;
37322 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
37325 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
37326 //console.log('adding nested layout panel ' + cfg.toSource());
37327 this.add(region, ret);
37328 nb = {}; /// find first...
37333 // needs grid and region
37335 //var el = this.getRegion(region).el.createChild();
37337 *var el = this.el.createChild();
37338 // create the grid first...
37339 cfg.grid.container = el;
37340 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
37343 if (region == 'center' && this.active ) {
37344 cfg.background = false;
37347 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
37349 this.add(region, ret);
37351 if (cfg.background) {
37352 // render grid on panel activation (if panel background)
37353 ret.on('activate', function(gp) {
37354 if (!gp.grid.rendered) {
37355 // gp.grid.render(el);
37359 // cfg.grid.render(el);
37365 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
37366 // it was the old xcomponent building that caused this before.
37367 // espeically if border is the top element in the tree.
37377 if (typeof(Roo[cfg.xtype]) != 'undefined') {
37379 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
37380 this.add(region, ret);
37384 throw "Can not add '" + cfg.xtype + "' to Border";
37390 this.beginUpdate();
37394 Roo.each(xitems, function(i) {
37395 region = nb && i.region ? i.region : false;
37397 var add = ret.addxtype(i);
37400 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
37401 if (!i.background) {
37402 abn[region] = nb[region] ;
37409 // make the last non-background panel active..
37410 //if (nb) { Roo.log(abn); }
37413 for(var r in abn) {
37414 region = this.getRegion(r);
37416 // tried using nb[r], but it does not work..
37418 region.showPanel(abn[r]);
37429 factory : function(cfg)
37432 var validRegions = Roo.bootstrap.layout.Border.regions;
37434 var target = cfg.region;
37437 var r = Roo.bootstrap.layout;
37441 return new r.North(cfg);
37443 return new r.South(cfg);
37445 return new r.East(cfg);
37447 return new r.West(cfg);
37449 return new r.Center(cfg);
37451 throw 'Layout region "'+target+'" not supported.';
37458 * Ext JS Library 1.1.1
37459 * Copyright(c) 2006-2007, Ext JS, LLC.
37461 * Originally Released Under LGPL - original licence link has changed is not relivant.
37464 * <script type="text/javascript">
37468 * @class Roo.bootstrap.layout.Basic
37469 * @extends Roo.util.Observable
37470 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
37471 * and does not have a titlebar, tabs or any other features. All it does is size and position
37472 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
37473 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
37474 * @cfg {string} region the region that it inhabits..
37475 * @cfg {bool} skipConfig skip config?
37479 Roo.bootstrap.layout.Basic = function(config){
37481 this.mgr = config.mgr;
37483 this.position = config.region;
37485 var skipConfig = config.skipConfig;
37489 * @scope Roo.BasicLayoutRegion
37493 * @event beforeremove
37494 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
37495 * @param {Roo.LayoutRegion} this
37496 * @param {Roo.ContentPanel} panel The panel
37497 * @param {Object} e The cancel event object
37499 "beforeremove" : true,
37501 * @event invalidated
37502 * Fires when the layout for this region is changed.
37503 * @param {Roo.LayoutRegion} this
37505 "invalidated" : true,
37507 * @event visibilitychange
37508 * Fires when this region is shown or hidden
37509 * @param {Roo.LayoutRegion} this
37510 * @param {Boolean} visibility true or false
37512 "visibilitychange" : true,
37514 * @event paneladded
37515 * Fires when a panel is added.
37516 * @param {Roo.LayoutRegion} this
37517 * @param {Roo.ContentPanel} panel The panel
37519 "paneladded" : true,
37521 * @event panelremoved
37522 * Fires when a panel is removed.
37523 * @param {Roo.LayoutRegion} this
37524 * @param {Roo.ContentPanel} panel The panel
37526 "panelremoved" : true,
37528 * @event beforecollapse
37529 * Fires when this region before collapse.
37530 * @param {Roo.LayoutRegion} this
37532 "beforecollapse" : true,
37535 * Fires when this region is collapsed.
37536 * @param {Roo.LayoutRegion} this
37538 "collapsed" : true,
37541 * Fires when this region is expanded.
37542 * @param {Roo.LayoutRegion} this
37547 * Fires when this region is slid into view.
37548 * @param {Roo.LayoutRegion} this
37550 "slideshow" : true,
37553 * Fires when this region slides out of view.
37554 * @param {Roo.LayoutRegion} this
37556 "slidehide" : true,
37558 * @event panelactivated
37559 * Fires when a panel is activated.
37560 * @param {Roo.LayoutRegion} this
37561 * @param {Roo.ContentPanel} panel The activated panel
37563 "panelactivated" : true,
37566 * Fires when the user resizes this region.
37567 * @param {Roo.LayoutRegion} this
37568 * @param {Number} newSize The new size (width for east/west, height for north/south)
37572 /** A collection of panels in this region. @type Roo.util.MixedCollection */
37573 this.panels = new Roo.util.MixedCollection();
37574 this.panels.getKey = this.getPanelId.createDelegate(this);
37576 this.activePanel = null;
37577 // ensure listeners are added...
37579 if (config.listeners || config.events) {
37580 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
37581 listeners : config.listeners || {},
37582 events : config.events || {}
37586 if(skipConfig !== true){
37587 this.applyConfig(config);
37591 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
37593 getPanelId : function(p){
37597 applyConfig : function(config){
37598 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
37599 this.config = config;
37604 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
37605 * the width, for horizontal (north, south) the height.
37606 * @param {Number} newSize The new width or height
37608 resizeTo : function(newSize){
37609 var el = this.el ? this.el :
37610 (this.activePanel ? this.activePanel.getEl() : null);
37612 switch(this.position){
37615 el.setWidth(newSize);
37616 this.fireEvent("resized", this, newSize);
37620 el.setHeight(newSize);
37621 this.fireEvent("resized", this, newSize);
37627 getBox : function(){
37628 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
37631 getMargins : function(){
37632 return this.margins;
37635 updateBox : function(box){
37637 var el = this.activePanel.getEl();
37638 el.dom.style.left = box.x + "px";
37639 el.dom.style.top = box.y + "px";
37640 this.activePanel.setSize(box.width, box.height);
37644 * Returns the container element for this region.
37645 * @return {Roo.Element}
37647 getEl : function(){
37648 return this.activePanel;
37652 * Returns true if this region is currently visible.
37653 * @return {Boolean}
37655 isVisible : function(){
37656 return this.activePanel ? true : false;
37659 setActivePanel : function(panel){
37660 panel = this.getPanel(panel);
37661 if(this.activePanel && this.activePanel != panel){
37662 this.activePanel.setActiveState(false);
37663 this.activePanel.getEl().setLeftTop(-10000,-10000);
37665 this.activePanel = panel;
37666 panel.setActiveState(true);
37668 panel.setSize(this.box.width, this.box.height);
37670 this.fireEvent("panelactivated", this, panel);
37671 this.fireEvent("invalidated");
37675 * Show the specified panel.
37676 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
37677 * @return {Roo.ContentPanel} The shown panel or null
37679 showPanel : function(panel){
37680 panel = this.getPanel(panel);
37682 this.setActivePanel(panel);
37688 * Get the active panel for this region.
37689 * @return {Roo.ContentPanel} The active panel or null
37691 getActivePanel : function(){
37692 return this.activePanel;
37696 * Add the passed ContentPanel(s)
37697 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
37698 * @return {Roo.ContentPanel} The panel added (if only one was added)
37700 add : function(panel){
37701 if(arguments.length > 1){
37702 for(var i = 0, len = arguments.length; i < len; i++) {
37703 this.add(arguments[i]);
37707 if(this.hasPanel(panel)){
37708 this.showPanel(panel);
37711 var el = panel.getEl();
37712 if(el.dom.parentNode != this.mgr.el.dom){
37713 this.mgr.el.dom.appendChild(el.dom);
37715 if(panel.setRegion){
37716 panel.setRegion(this);
37718 this.panels.add(panel);
37719 el.setStyle("position", "absolute");
37720 if(!panel.background){
37721 this.setActivePanel(panel);
37722 if(this.config.initialSize && this.panels.getCount()==1){
37723 this.resizeTo(this.config.initialSize);
37726 this.fireEvent("paneladded", this, panel);
37731 * Returns true if the panel is in this region.
37732 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
37733 * @return {Boolean}
37735 hasPanel : function(panel){
37736 if(typeof panel == "object"){ // must be panel obj
37737 panel = panel.getId();
37739 return this.getPanel(panel) ? true : false;
37743 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
37744 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
37745 * @param {Boolean} preservePanel Overrides the config preservePanel option
37746 * @return {Roo.ContentPanel} The panel that was removed
37748 remove : function(panel, preservePanel){
37749 panel = this.getPanel(panel);
37754 this.fireEvent("beforeremove", this, panel, e);
37755 if(e.cancel === true){
37758 var panelId = panel.getId();
37759 this.panels.removeKey(panelId);
37764 * Returns the panel specified or null if it's not in this region.
37765 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
37766 * @return {Roo.ContentPanel}
37768 getPanel : function(id){
37769 if(typeof id == "object"){ // must be panel obj
37772 return this.panels.get(id);
37776 * Returns this regions position (north/south/east/west/center).
37779 getPosition: function(){
37780 return this.position;
37784 * Ext JS Library 1.1.1
37785 * Copyright(c) 2006-2007, Ext JS, LLC.
37787 * Originally Released Under LGPL - original licence link has changed is not relivant.
37790 * <script type="text/javascript">
37794 * @class Roo.bootstrap.layout.Region
37795 * @extends Roo.bootstrap.layout.Basic
37796 * This class represents a region in a layout manager.
37798 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
37799 * @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})
37800 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
37801 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
37802 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
37803 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
37804 * @cfg {String} title The title for the region (overrides panel titles)
37805 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
37806 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
37807 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
37808 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
37809 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
37810 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
37811 * the space available, similar to FireFox 1.5 tabs (defaults to false)
37812 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
37813 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
37814 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
37816 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
37817 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
37818 * @cfg {Boolean} disableTabTips True to disable tab tooltips
37819 * @cfg {Number} width For East/West panels
37820 * @cfg {Number} height For North/South panels
37821 * @cfg {Boolean} split To show the splitter
37822 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
37824 * @cfg {string} cls Extra CSS classes to add to region
37826 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
37827 * @cfg {string} region the region that it inhabits..
37830 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
37831 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
37833 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
37834 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
37835 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
37837 Roo.bootstrap.layout.Region = function(config)
37839 this.applyConfig(config);
37841 var mgr = config.mgr;
37842 var pos = config.region;
37843 config.skipConfig = true;
37844 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
37847 this.onRender(mgr.el);
37850 this.visible = true;
37851 this.collapsed = false;
37852 this.unrendered_panels = [];
37855 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
37857 position: '', // set by wrapper (eg. north/south etc..)
37858 unrendered_panels : null, // unrendered panels.
37860 tabPosition : false,
37862 mgr: false, // points to 'Border'
37865 createBody : function(){
37866 /** This region's body element
37867 * @type Roo.Element */
37868 this.bodyEl = this.el.createChild({
37870 cls: "roo-layout-panel-body tab-content" // bootstrap added...
37874 onRender: function(ctr, pos)
37876 var dh = Roo.DomHelper;
37877 /** This region's container element
37878 * @type Roo.Element */
37879 this.el = dh.append(ctr.dom, {
37881 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
37883 /** This region's title element
37884 * @type Roo.Element */
37886 this.titleEl = dh.append(this.el.dom, {
37888 unselectable: "on",
37889 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
37891 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
37892 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
37896 this.titleEl.enableDisplayMode();
37897 /** This region's title text element
37898 * @type HTMLElement */
37899 this.titleTextEl = this.titleEl.dom.firstChild;
37900 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
37902 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
37903 this.closeBtn.enableDisplayMode();
37904 this.closeBtn.on("click", this.closeClicked, this);
37905 this.closeBtn.hide();
37907 this.createBody(this.config);
37908 if(this.config.hideWhenEmpty){
37910 this.on("paneladded", this.validateVisibility, this);
37911 this.on("panelremoved", this.validateVisibility, this);
37913 if(this.autoScroll){
37914 this.bodyEl.setStyle("overflow", "auto");
37916 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
37918 //if(c.titlebar !== false){
37919 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
37920 this.titleEl.hide();
37922 this.titleEl.show();
37923 if(this.config.title){
37924 this.titleTextEl.innerHTML = this.config.title;
37928 if(this.config.collapsed){
37929 this.collapse(true);
37931 if(this.config.hidden){
37935 if (this.unrendered_panels && this.unrendered_panels.length) {
37936 for (var i =0;i< this.unrendered_panels.length; i++) {
37937 this.add(this.unrendered_panels[i]);
37939 this.unrendered_panels = null;
37945 applyConfig : function(c)
37948 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
37949 var dh = Roo.DomHelper;
37950 if(c.titlebar !== false){
37951 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
37952 this.collapseBtn.on("click", this.collapse, this);
37953 this.collapseBtn.enableDisplayMode();
37955 if(c.showPin === true || this.showPin){
37956 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
37957 this.stickBtn.enableDisplayMode();
37958 this.stickBtn.on("click", this.expand, this);
37959 this.stickBtn.hide();
37964 /** This region's collapsed element
37965 * @type Roo.Element */
37968 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
37969 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
37972 if(c.floatable !== false){
37973 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
37974 this.collapsedEl.on("click", this.collapseClick, this);
37977 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
37978 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
37979 id: "message", unselectable: "on", style:{"float":"left"}});
37980 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
37982 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
37983 this.expandBtn.on("click", this.expand, this);
37987 if(this.collapseBtn){
37988 this.collapseBtn.setVisible(c.collapsible == true);
37991 this.cmargins = c.cmargins || this.cmargins ||
37992 (this.position == "west" || this.position == "east" ?
37993 {top: 0, left: 2, right:2, bottom: 0} :
37994 {top: 2, left: 0, right:0, bottom: 2});
37996 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
37999 this.tabPosition = [ 'top','bottom', 'west'].indexOf(c.tabPosition) > -1 ? c.tabPosition : "top";
38001 this.autoScroll = c.autoScroll || false;
38006 this.duration = c.duration || .30;
38007 this.slideDuration = c.slideDuration || .45;
38012 * Returns true if this region is currently visible.
38013 * @return {Boolean}
38015 isVisible : function(){
38016 return this.visible;
38020 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
38021 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
38023 //setCollapsedTitle : function(title){
38024 // title = title || " ";
38025 // if(this.collapsedTitleTextEl){
38026 // this.collapsedTitleTextEl.innerHTML = title;
38030 getBox : function(){
38032 // if(!this.collapsed){
38033 b = this.el.getBox(false, true);
38035 // b = this.collapsedEl.getBox(false, true);
38040 getMargins : function(){
38041 return this.margins;
38042 //return this.collapsed ? this.cmargins : this.margins;
38045 highlight : function(){
38046 this.el.addClass("x-layout-panel-dragover");
38049 unhighlight : function(){
38050 this.el.removeClass("x-layout-panel-dragover");
38053 updateBox : function(box)
38055 if (!this.bodyEl) {
38056 return; // not rendered yet..
38060 if(!this.collapsed){
38061 this.el.dom.style.left = box.x + "px";
38062 this.el.dom.style.top = box.y + "px";
38063 this.updateBody(box.width, box.height);
38065 this.collapsedEl.dom.style.left = box.x + "px";
38066 this.collapsedEl.dom.style.top = box.y + "px";
38067 this.collapsedEl.setSize(box.width, box.height);
38070 this.tabs.autoSizeTabs();
38074 updateBody : function(w, h)
38077 this.el.setWidth(w);
38078 w -= this.el.getBorderWidth("rl");
38079 if(this.config.adjustments){
38080 w += this.config.adjustments[0];
38083 if(h !== null && h > 0){
38084 this.el.setHeight(h);
38085 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
38086 h -= this.el.getBorderWidth("tb");
38087 if(this.config.adjustments){
38088 h += this.config.adjustments[1];
38090 this.bodyEl.setHeight(h);
38092 h = this.tabs.syncHeight(h);
38095 if(this.panelSize){
38096 w = w !== null ? w : this.panelSize.width;
38097 h = h !== null ? h : this.panelSize.height;
38099 if(this.activePanel){
38100 var el = this.activePanel.getEl();
38101 w = w !== null ? w : el.getWidth();
38102 h = h !== null ? h : el.getHeight();
38103 this.panelSize = {width: w, height: h};
38104 this.activePanel.setSize(w, h);
38106 if(Roo.isIE && this.tabs){
38107 this.tabs.el.repaint();
38112 * Returns the container element for this region.
38113 * @return {Roo.Element}
38115 getEl : function(){
38120 * Hides this region.
38123 //if(!this.collapsed){
38124 this.el.dom.style.left = "-2000px";
38127 // this.collapsedEl.dom.style.left = "-2000px";
38128 // this.collapsedEl.hide();
38130 this.visible = false;
38131 this.fireEvent("visibilitychange", this, false);
38135 * Shows this region if it was previously hidden.
38138 //if(!this.collapsed){
38141 // this.collapsedEl.show();
38143 this.visible = true;
38144 this.fireEvent("visibilitychange", this, true);
38147 closeClicked : function(){
38148 if(this.activePanel){
38149 this.remove(this.activePanel);
38153 collapseClick : function(e){
38155 e.stopPropagation();
38158 e.stopPropagation();
38164 * Collapses this region.
38165 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
38168 collapse : function(skipAnim, skipCheck = false){
38169 if(this.collapsed) {
38173 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
38175 this.collapsed = true;
38177 this.split.el.hide();
38179 if(this.config.animate && skipAnim !== true){
38180 this.fireEvent("invalidated", this);
38181 this.animateCollapse();
38183 this.el.setLocation(-20000,-20000);
38185 this.collapsedEl.show();
38186 this.fireEvent("collapsed", this);
38187 this.fireEvent("invalidated", this);
38193 animateCollapse : function(){
38198 * Expands this region if it was previously collapsed.
38199 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
38200 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
38203 expand : function(e, skipAnim){
38205 e.stopPropagation();
38207 if(!this.collapsed || this.el.hasActiveFx()) {
38211 this.afterSlideIn();
38214 this.collapsed = false;
38215 if(this.config.animate && skipAnim !== true){
38216 this.animateExpand();
38220 this.split.el.show();
38222 this.collapsedEl.setLocation(-2000,-2000);
38223 this.collapsedEl.hide();
38224 this.fireEvent("invalidated", this);
38225 this.fireEvent("expanded", this);
38229 animateExpand : function(){
38233 initTabs : function()
38235 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
38237 var ts = new Roo.bootstrap.panel.Tabs({
38238 el: this.bodyEl.dom,
38240 tabPosition: this.tabPosition ? this.tabPosition : 'top',
38241 disableTooltips: this.config.disableTabTips,
38242 toolbar : this.config.toolbar
38245 if(this.config.hideTabs){
38246 ts.stripWrap.setDisplayed(false);
38249 ts.resizeTabs = this.config.resizeTabs === true;
38250 ts.minTabWidth = this.config.minTabWidth || 40;
38251 ts.maxTabWidth = this.config.maxTabWidth || 250;
38252 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
38253 ts.monitorResize = false;
38254 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
38255 ts.bodyEl.addClass('roo-layout-tabs-body');
38256 this.panels.each(this.initPanelAsTab, this);
38259 initPanelAsTab : function(panel){
38260 var ti = this.tabs.addTab(
38264 this.config.closeOnTab && panel.isClosable(),
38267 if(panel.tabTip !== undefined){
38268 ti.setTooltip(panel.tabTip);
38270 ti.on("activate", function(){
38271 this.setActivePanel(panel);
38274 if(this.config.closeOnTab){
38275 ti.on("beforeclose", function(t, e){
38277 this.remove(panel);
38281 panel.tabItem = ti;
38286 updatePanelTitle : function(panel, title)
38288 if(this.activePanel == panel){
38289 this.updateTitle(title);
38292 var ti = this.tabs.getTab(panel.getEl().id);
38294 if(panel.tabTip !== undefined){
38295 ti.setTooltip(panel.tabTip);
38300 updateTitle : function(title){
38301 if(this.titleTextEl && !this.config.title){
38302 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
38306 setActivePanel : function(panel)
38308 panel = this.getPanel(panel);
38309 if(this.activePanel && this.activePanel != panel){
38310 if(this.activePanel.setActiveState(false) === false){
38314 this.activePanel = panel;
38315 panel.setActiveState(true);
38316 if(this.panelSize){
38317 panel.setSize(this.panelSize.width, this.panelSize.height);
38320 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
38322 this.updateTitle(panel.getTitle());
38324 this.fireEvent("invalidated", this);
38326 this.fireEvent("panelactivated", this, panel);
38330 * Shows the specified panel.
38331 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
38332 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
38334 showPanel : function(panel)
38336 panel = this.getPanel(panel);
38339 var tab = this.tabs.getTab(panel.getEl().id);
38340 if(tab.isHidden()){
38341 this.tabs.unhideTab(tab.id);
38345 this.setActivePanel(panel);
38352 * Get the active panel for this region.
38353 * @return {Roo.ContentPanel} The active panel or null
38355 getActivePanel : function(){
38356 return this.activePanel;
38359 validateVisibility : function(){
38360 if(this.panels.getCount() < 1){
38361 this.updateTitle(" ");
38362 this.closeBtn.hide();
38365 if(!this.isVisible()){
38372 * Adds the passed ContentPanel(s) to this region.
38373 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
38374 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
38376 add : function(panel)
38378 if(arguments.length > 1){
38379 for(var i = 0, len = arguments.length; i < len; i++) {
38380 this.add(arguments[i]);
38385 // if we have not been rendered yet, then we can not really do much of this..
38386 if (!this.bodyEl) {
38387 this.unrendered_panels.push(panel);
38394 if(this.hasPanel(panel)){
38395 this.showPanel(panel);
38398 panel.setRegion(this);
38399 this.panels.add(panel);
38400 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
38401 // sinle panel - no tab...?? would it not be better to render it with the tabs,
38402 // and hide them... ???
38403 this.bodyEl.dom.appendChild(panel.getEl().dom);
38404 if(panel.background !== true){
38405 this.setActivePanel(panel);
38407 this.fireEvent("paneladded", this, panel);
38414 this.initPanelAsTab(panel);
38418 if(panel.background !== true){
38419 this.tabs.activate(panel.getEl().id);
38421 this.fireEvent("paneladded", this, panel);
38426 * Hides the tab for the specified panel.
38427 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
38429 hidePanel : function(panel){
38430 if(this.tabs && (panel = this.getPanel(panel))){
38431 this.tabs.hideTab(panel.getEl().id);
38436 * Unhides the tab for a previously hidden panel.
38437 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
38439 unhidePanel : function(panel){
38440 if(this.tabs && (panel = this.getPanel(panel))){
38441 this.tabs.unhideTab(panel.getEl().id);
38445 clearPanels : function(){
38446 while(this.panels.getCount() > 0){
38447 this.remove(this.panels.first());
38452 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
38453 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
38454 * @param {Boolean} preservePanel Overrides the config preservePanel option
38455 * @return {Roo.ContentPanel} The panel that was removed
38457 remove : function(panel, preservePanel)
38459 panel = this.getPanel(panel);
38464 this.fireEvent("beforeremove", this, panel, e);
38465 if(e.cancel === true){
38468 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
38469 var panelId = panel.getId();
38470 this.panels.removeKey(panelId);
38472 document.body.appendChild(panel.getEl().dom);
38475 this.tabs.removeTab(panel.getEl().id);
38476 }else if (!preservePanel){
38477 this.bodyEl.dom.removeChild(panel.getEl().dom);
38479 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
38480 var p = this.panels.first();
38481 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
38482 tempEl.appendChild(p.getEl().dom);
38483 this.bodyEl.update("");
38484 this.bodyEl.dom.appendChild(p.getEl().dom);
38486 this.updateTitle(p.getTitle());
38488 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
38489 this.setActivePanel(p);
38491 panel.setRegion(null);
38492 if(this.activePanel == panel){
38493 this.activePanel = null;
38495 if(this.config.autoDestroy !== false && preservePanel !== true){
38496 try{panel.destroy();}catch(e){}
38498 this.fireEvent("panelremoved", this, panel);
38503 * Returns the TabPanel component used by this region
38504 * @return {Roo.TabPanel}
38506 getTabs : function(){
38510 createTool : function(parentEl, className){
38511 var btn = Roo.DomHelper.append(parentEl, {
38513 cls: "x-layout-tools-button",
38516 cls: "roo-layout-tools-button-inner " + className,
38520 btn.addClassOnOver("roo-layout-tools-button-over");
38525 * Ext JS Library 1.1.1
38526 * Copyright(c) 2006-2007, Ext JS, LLC.
38528 * Originally Released Under LGPL - original licence link has changed is not relivant.
38531 * <script type="text/javascript">
38537 * @class Roo.SplitLayoutRegion
38538 * @extends Roo.LayoutRegion
38539 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
38541 Roo.bootstrap.layout.Split = function(config){
38542 this.cursor = config.cursor;
38543 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
38546 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
38548 splitTip : "Drag to resize.",
38549 collapsibleSplitTip : "Drag to resize. Double click to hide.",
38550 useSplitTips : false,
38552 applyConfig : function(config){
38553 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
38556 onRender : function(ctr,pos) {
38558 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
38559 if(!this.config.split){
38564 var splitEl = Roo.DomHelper.append(ctr.dom, {
38566 id: this.el.id + "-split",
38567 cls: "roo-layout-split roo-layout-split-"+this.position,
38570 /** The SplitBar for this region
38571 * @type Roo.SplitBar */
38572 // does not exist yet...
38573 Roo.log([this.position, this.orientation]);
38575 this.split = new Roo.bootstrap.SplitBar({
38576 dragElement : splitEl,
38577 resizingElement: this.el,
38578 orientation : this.orientation
38581 this.split.on("moved", this.onSplitMove, this);
38582 this.split.useShim = this.config.useShim === true;
38583 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
38584 if(this.useSplitTips){
38585 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
38587 //if(config.collapsible){
38588 // this.split.el.on("dblclick", this.collapse, this);
38591 if(typeof this.config.minSize != "undefined"){
38592 this.split.minSize = this.config.minSize;
38594 if(typeof this.config.maxSize != "undefined"){
38595 this.split.maxSize = this.config.maxSize;
38597 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
38598 this.hideSplitter();
38603 getHMaxSize : function(){
38604 var cmax = this.config.maxSize || 10000;
38605 var center = this.mgr.getRegion("center");
38606 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
38609 getVMaxSize : function(){
38610 var cmax = this.config.maxSize || 10000;
38611 var center = this.mgr.getRegion("center");
38612 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
38615 onSplitMove : function(split, newSize){
38616 this.fireEvent("resized", this, newSize);
38620 * Returns the {@link Roo.SplitBar} for this region.
38621 * @return {Roo.SplitBar}
38623 getSplitBar : function(){
38628 this.hideSplitter();
38629 Roo.bootstrap.layout.Split.superclass.hide.call(this);
38632 hideSplitter : function(){
38634 this.split.el.setLocation(-2000,-2000);
38635 this.split.el.hide();
38641 this.split.el.show();
38643 Roo.bootstrap.layout.Split.superclass.show.call(this);
38646 beforeSlide: function(){
38647 if(Roo.isGecko){// firefox overflow auto bug workaround
38648 this.bodyEl.clip();
38650 this.tabs.bodyEl.clip();
38652 if(this.activePanel){
38653 this.activePanel.getEl().clip();
38655 if(this.activePanel.beforeSlide){
38656 this.activePanel.beforeSlide();
38662 afterSlide : function(){
38663 if(Roo.isGecko){// firefox overflow auto bug workaround
38664 this.bodyEl.unclip();
38666 this.tabs.bodyEl.unclip();
38668 if(this.activePanel){
38669 this.activePanel.getEl().unclip();
38670 if(this.activePanel.afterSlide){
38671 this.activePanel.afterSlide();
38677 initAutoHide : function(){
38678 if(this.autoHide !== false){
38679 if(!this.autoHideHd){
38680 var st = new Roo.util.DelayedTask(this.slideIn, this);
38681 this.autoHideHd = {
38682 "mouseout": function(e){
38683 if(!e.within(this.el, true)){
38687 "mouseover" : function(e){
38693 this.el.on(this.autoHideHd);
38697 clearAutoHide : function(){
38698 if(this.autoHide !== false){
38699 this.el.un("mouseout", this.autoHideHd.mouseout);
38700 this.el.un("mouseover", this.autoHideHd.mouseover);
38704 clearMonitor : function(){
38705 Roo.get(document).un("click", this.slideInIf, this);
38708 // these names are backwards but not changed for compat
38709 slideOut : function(){
38710 if(this.isSlid || this.el.hasActiveFx()){
38713 this.isSlid = true;
38714 if(this.collapseBtn){
38715 this.collapseBtn.hide();
38717 this.closeBtnState = this.closeBtn.getStyle('display');
38718 this.closeBtn.hide();
38720 this.stickBtn.show();
38723 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
38724 this.beforeSlide();
38725 this.el.setStyle("z-index", 10001);
38726 this.el.slideIn(this.getSlideAnchor(), {
38727 callback: function(){
38729 this.initAutoHide();
38730 Roo.get(document).on("click", this.slideInIf, this);
38731 this.fireEvent("slideshow", this);
38738 afterSlideIn : function(){
38739 this.clearAutoHide();
38740 this.isSlid = false;
38741 this.clearMonitor();
38742 this.el.setStyle("z-index", "");
38743 if(this.collapseBtn){
38744 this.collapseBtn.show();
38746 this.closeBtn.setStyle('display', this.closeBtnState);
38748 this.stickBtn.hide();
38750 this.fireEvent("slidehide", this);
38753 slideIn : function(cb){
38754 if(!this.isSlid || this.el.hasActiveFx()){
38758 this.isSlid = false;
38759 this.beforeSlide();
38760 this.el.slideOut(this.getSlideAnchor(), {
38761 callback: function(){
38762 this.el.setLeftTop(-10000, -10000);
38764 this.afterSlideIn();
38772 slideInIf : function(e){
38773 if(!e.within(this.el)){
38778 animateCollapse : function(){
38779 this.beforeSlide();
38780 this.el.setStyle("z-index", 20000);
38781 var anchor = this.getSlideAnchor();
38782 this.el.slideOut(anchor, {
38783 callback : function(){
38784 this.el.setStyle("z-index", "");
38785 this.collapsedEl.slideIn(anchor, {duration:.3});
38787 this.el.setLocation(-10000,-10000);
38789 this.fireEvent("collapsed", this);
38796 animateExpand : function(){
38797 this.beforeSlide();
38798 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
38799 this.el.setStyle("z-index", 20000);
38800 this.collapsedEl.hide({
38803 this.el.slideIn(this.getSlideAnchor(), {
38804 callback : function(){
38805 this.el.setStyle("z-index", "");
38808 this.split.el.show();
38810 this.fireEvent("invalidated", this);
38811 this.fireEvent("expanded", this);
38839 getAnchor : function(){
38840 return this.anchors[this.position];
38843 getCollapseAnchor : function(){
38844 return this.canchors[this.position];
38847 getSlideAnchor : function(){
38848 return this.sanchors[this.position];
38851 getAlignAdj : function(){
38852 var cm = this.cmargins;
38853 switch(this.position){
38869 getExpandAdj : function(){
38870 var c = this.collapsedEl, cm = this.cmargins;
38871 switch(this.position){
38873 return [-(cm.right+c.getWidth()+cm.left), 0];
38876 return [cm.right+c.getWidth()+cm.left, 0];
38879 return [0, -(cm.top+cm.bottom+c.getHeight())];
38882 return [0, cm.top+cm.bottom+c.getHeight()];
38888 * Ext JS Library 1.1.1
38889 * Copyright(c) 2006-2007, Ext JS, LLC.
38891 * Originally Released Under LGPL - original licence link has changed is not relivant.
38894 * <script type="text/javascript">
38897 * These classes are private internal classes
38899 Roo.bootstrap.layout.Center = function(config){
38900 config.region = "center";
38901 Roo.bootstrap.layout.Region.call(this, config);
38902 this.visible = true;
38903 this.minWidth = config.minWidth || 20;
38904 this.minHeight = config.minHeight || 20;
38907 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
38909 // center panel can't be hidden
38913 // center panel can't be hidden
38916 getMinWidth: function(){
38917 return this.minWidth;
38920 getMinHeight: function(){
38921 return this.minHeight;
38935 Roo.bootstrap.layout.North = function(config)
38937 config.region = 'north';
38938 config.cursor = 'n-resize';
38940 Roo.bootstrap.layout.Split.call(this, config);
38944 this.split.placement = Roo.bootstrap.SplitBar.TOP;
38945 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
38946 this.split.el.addClass("roo-layout-split-v");
38948 var size = config.initialSize || config.height;
38949 if(typeof size != "undefined"){
38950 this.el.setHeight(size);
38953 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
38955 orientation: Roo.bootstrap.SplitBar.VERTICAL,
38959 getBox : function(){
38960 if(this.collapsed){
38961 return this.collapsedEl.getBox();
38963 var box = this.el.getBox();
38965 box.height += this.split.el.getHeight();
38970 updateBox : function(box){
38971 if(this.split && !this.collapsed){
38972 box.height -= this.split.el.getHeight();
38973 this.split.el.setLeft(box.x);
38974 this.split.el.setTop(box.y+box.height);
38975 this.split.el.setWidth(box.width);
38977 if(this.collapsed){
38978 this.updateBody(box.width, null);
38980 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
38988 Roo.bootstrap.layout.South = function(config){
38989 config.region = 'south';
38990 config.cursor = 's-resize';
38991 Roo.bootstrap.layout.Split.call(this, config);
38993 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
38994 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
38995 this.split.el.addClass("roo-layout-split-v");
38997 var size = config.initialSize || config.height;
38998 if(typeof size != "undefined"){
38999 this.el.setHeight(size);
39003 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
39004 orientation: Roo.bootstrap.SplitBar.VERTICAL,
39005 getBox : function(){
39006 if(this.collapsed){
39007 return this.collapsedEl.getBox();
39009 var box = this.el.getBox();
39011 var sh = this.split.el.getHeight();
39018 updateBox : function(box){
39019 if(this.split && !this.collapsed){
39020 var sh = this.split.el.getHeight();
39023 this.split.el.setLeft(box.x);
39024 this.split.el.setTop(box.y-sh);
39025 this.split.el.setWidth(box.width);
39027 if(this.collapsed){
39028 this.updateBody(box.width, null);
39030 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
39034 Roo.bootstrap.layout.East = function(config){
39035 config.region = "east";
39036 config.cursor = "e-resize";
39037 Roo.bootstrap.layout.Split.call(this, config);
39039 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
39040 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
39041 this.split.el.addClass("roo-layout-split-h");
39043 var size = config.initialSize || config.width;
39044 if(typeof size != "undefined"){
39045 this.el.setWidth(size);
39048 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
39049 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
39050 getBox : function(){
39051 if(this.collapsed){
39052 return this.collapsedEl.getBox();
39054 var box = this.el.getBox();
39056 var sw = this.split.el.getWidth();
39063 updateBox : function(box){
39064 if(this.split && !this.collapsed){
39065 var sw = this.split.el.getWidth();
39067 this.split.el.setLeft(box.x);
39068 this.split.el.setTop(box.y);
39069 this.split.el.setHeight(box.height);
39072 if(this.collapsed){
39073 this.updateBody(null, box.height);
39075 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
39079 Roo.bootstrap.layout.West = function(config){
39080 config.region = "west";
39081 config.cursor = "w-resize";
39083 Roo.bootstrap.layout.Split.call(this, config);
39085 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
39086 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
39087 this.split.el.addClass("roo-layout-split-h");
39091 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
39092 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
39094 onRender: function(ctr, pos)
39096 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
39097 var size = this.config.initialSize || this.config.width;
39098 if(typeof size != "undefined"){
39099 this.el.setWidth(size);
39103 getBox : function(){
39104 if(this.collapsed){
39105 return this.collapsedEl.getBox();
39107 var box = this.el.getBox();
39109 box.width += this.split.el.getWidth();
39114 updateBox : function(box){
39115 if(this.split && !this.collapsed){
39116 var sw = this.split.el.getWidth();
39118 this.split.el.setLeft(box.x+box.width);
39119 this.split.el.setTop(box.y);
39120 this.split.el.setHeight(box.height);
39122 if(this.collapsed){
39123 this.updateBody(null, box.height);
39125 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
39127 });Roo.namespace("Roo.bootstrap.panel");/*
39129 * Ext JS Library 1.1.1
39130 * Copyright(c) 2006-2007, Ext JS, LLC.
39132 * Originally Released Under LGPL - original licence link has changed is not relivant.
39135 * <script type="text/javascript">
39138 * @class Roo.ContentPanel
39139 * @extends Roo.util.Observable
39140 * A basic ContentPanel element.
39141 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
39142 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
39143 * @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
39144 * @cfg {Boolean} closable True if the panel can be closed/removed
39145 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
39146 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
39147 * @cfg {Toolbar} toolbar A toolbar for this panel
39148 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
39149 * @cfg {String} title The title for this panel
39150 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
39151 * @cfg {String} url Calls {@link #setUrl} with this value
39152 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
39153 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
39154 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
39155 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
39156 * @cfg {Boolean} badges render the badges
39157 * @cfg {String} cls extra classes to use
39158 * @cfg {String} background (primary|secondary|success|info|warning|danger|light|dark)
39161 * Create a new ContentPanel.
39162 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
39163 * @param {String/Object} config A string to set only the title or a config object
39164 * @param {String} content (optional) Set the HTML content for this panel
39165 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
39167 Roo.bootstrap.panel.Content = function( config){
39169 this.tpl = config.tpl || false;
39171 var el = config.el;
39172 var content = config.content;
39174 if(config.autoCreate){ // xtype is available if this is called from factory
39177 this.el = Roo.get(el);
39178 if(!this.el && config && config.autoCreate){
39179 if(typeof config.autoCreate == "object"){
39180 if(!config.autoCreate.id){
39181 config.autoCreate.id = config.id||el;
39183 this.el = Roo.DomHelper.append(document.body,
39184 config.autoCreate, true);
39188 cls: (config.cls || '') +
39189 (config.background ? ' bg-' + config.background : '') +
39190 " roo-layout-inactive-content",
39194 elcfg.html = config.html;
39198 this.el = Roo.DomHelper.append(document.body, elcfg , true);
39201 this.closable = false;
39202 this.loaded = false;
39203 this.active = false;
39206 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
39208 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
39210 this.wrapEl = this.el; //this.el.wrap();
39212 if (config.toolbar.items) {
39213 ti = config.toolbar.items ;
39214 delete config.toolbar.items ;
39218 this.toolbar.render(this.wrapEl, 'before');
39219 for(var i =0;i < ti.length;i++) {
39220 // Roo.log(['add child', items[i]]);
39221 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
39223 this.toolbar.items = nitems;
39224 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
39225 delete config.toolbar;
39229 // xtype created footer. - not sure if will work as we normally have to render first..
39230 if (this.footer && !this.footer.el && this.footer.xtype) {
39231 if (!this.wrapEl) {
39232 this.wrapEl = this.el.wrap();
39235 this.footer.container = this.wrapEl.createChild();
39237 this.footer = Roo.factory(this.footer, Roo);
39242 if(typeof config == "string"){
39243 this.title = config;
39245 Roo.apply(this, config);
39249 this.resizeEl = Roo.get(this.resizeEl, true);
39251 this.resizeEl = this.el;
39253 // handle view.xtype
39261 * Fires when this panel is activated.
39262 * @param {Roo.ContentPanel} this
39266 * @event deactivate
39267 * Fires when this panel is activated.
39268 * @param {Roo.ContentPanel} this
39270 "deactivate" : true,
39274 * Fires when this panel is resized if fitToFrame is true.
39275 * @param {Roo.ContentPanel} this
39276 * @param {Number} width The width after any component adjustments
39277 * @param {Number} height The height after any component adjustments
39283 * Fires when this tab is created
39284 * @param {Roo.ContentPanel} this
39295 if(this.autoScroll){
39296 this.resizeEl.setStyle("overflow", "auto");
39298 // fix randome scrolling
39299 //this.el.on('scroll', function() {
39300 // Roo.log('fix random scolling');
39301 // this.scrollTo('top',0);
39304 content = content || this.content;
39306 this.setContent(content);
39308 if(config && config.url){
39309 this.setUrl(this.url, this.params, this.loadOnce);
39314 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
39316 if (this.view && typeof(this.view.xtype) != 'undefined') {
39317 this.view.el = this.el.appendChild(document.createElement("div"));
39318 this.view = Roo.factory(this.view);
39319 this.view.render && this.view.render(false, '');
39323 this.fireEvent('render', this);
39326 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
39333 setRegion : function(region){
39334 this.region = region;
39335 this.setActiveClass(region && !this.background);
39339 setActiveClass: function(state)
39342 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
39343 this.el.setStyle('position','relative');
39345 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
39346 this.el.setStyle('position', 'absolute');
39351 * Returns the toolbar for this Panel if one was configured.
39352 * @return {Roo.Toolbar}
39354 getToolbar : function(){
39355 return this.toolbar;
39358 setActiveState : function(active)
39360 this.active = active;
39361 this.setActiveClass(active);
39363 if(this.fireEvent("deactivate", this) === false){
39368 this.fireEvent("activate", this);
39372 * Updates this panel's element
39373 * @param {String} content The new content
39374 * @param {Boolean} loadScripts (optional) true to look for and process scripts
39376 setContent : function(content, loadScripts){
39377 this.el.update(content, loadScripts);
39380 ignoreResize : function(w, h){
39381 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
39384 this.lastSize = {width: w, height: h};
39389 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
39390 * @return {Roo.UpdateManager} The UpdateManager
39392 getUpdateManager : function(){
39393 return this.el.getUpdateManager();
39396 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
39397 * @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:
39400 url: "your-url.php",
39401 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
39402 callback: yourFunction,
39403 scope: yourObject, //(optional scope)
39406 text: "Loading...",
39411 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
39412 * 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.
39413 * @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}
39414 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
39415 * @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.
39416 * @return {Roo.ContentPanel} this
39419 var um = this.el.getUpdateManager();
39420 um.update.apply(um, arguments);
39426 * 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.
39427 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
39428 * @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)
39429 * @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)
39430 * @return {Roo.UpdateManager} The UpdateManager
39432 setUrl : function(url, params, loadOnce){
39433 if(this.refreshDelegate){
39434 this.removeListener("activate", this.refreshDelegate);
39436 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
39437 this.on("activate", this.refreshDelegate);
39438 return this.el.getUpdateManager();
39441 _handleRefresh : function(url, params, loadOnce){
39442 if(!loadOnce || !this.loaded){
39443 var updater = this.el.getUpdateManager();
39444 updater.update(url, params, this._setLoaded.createDelegate(this));
39448 _setLoaded : function(){
39449 this.loaded = true;
39453 * Returns this panel's id
39456 getId : function(){
39461 * Returns this panel's element - used by regiosn to add.
39462 * @return {Roo.Element}
39464 getEl : function(){
39465 return this.wrapEl || this.el;
39470 adjustForComponents : function(width, height)
39472 //Roo.log('adjustForComponents ');
39473 if(this.resizeEl != this.el){
39474 width -= this.el.getFrameWidth('lr');
39475 height -= this.el.getFrameWidth('tb');
39478 var te = this.toolbar.getEl();
39479 te.setWidth(width);
39480 height -= te.getHeight();
39483 var te = this.footer.getEl();
39484 te.setWidth(width);
39485 height -= te.getHeight();
39489 if(this.adjustments){
39490 width += this.adjustments[0];
39491 height += this.adjustments[1];
39493 return {"width": width, "height": height};
39496 setSize : function(width, height){
39497 if(this.fitToFrame && !this.ignoreResize(width, height)){
39498 if(this.fitContainer && this.resizeEl != this.el){
39499 this.el.setSize(width, height);
39501 var size = this.adjustForComponents(width, height);
39502 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
39503 this.fireEvent('resize', this, size.width, size.height);
39508 * Returns this panel's title
39511 getTitle : function(){
39513 if (typeof(this.title) != 'object') {
39518 for (var k in this.title) {
39519 if (!this.title.hasOwnProperty(k)) {
39523 if (k.indexOf('-') >= 0) {
39524 var s = k.split('-');
39525 for (var i = 0; i<s.length; i++) {
39526 t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
39529 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
39536 * Set this panel's title
39537 * @param {String} title
39539 setTitle : function(title){
39540 this.title = title;
39542 this.region.updatePanelTitle(this, title);
39547 * Returns true is this panel was configured to be closable
39548 * @return {Boolean}
39550 isClosable : function(){
39551 return this.closable;
39554 beforeSlide : function(){
39556 this.resizeEl.clip();
39559 afterSlide : function(){
39561 this.resizeEl.unclip();
39565 * Force a content refresh from the URL specified in the {@link #setUrl} method.
39566 * Will fail silently if the {@link #setUrl} method has not been called.
39567 * This does not activate the panel, just updates its content.
39569 refresh : function(){
39570 if(this.refreshDelegate){
39571 this.loaded = false;
39572 this.refreshDelegate();
39577 * Destroys this panel
39579 destroy : function(){
39580 this.el.removeAllListeners();
39581 var tempEl = document.createElement("span");
39582 tempEl.appendChild(this.el.dom);
39583 tempEl.innerHTML = "";
39589 * form - if the content panel contains a form - this is a reference to it.
39590 * @type {Roo.form.Form}
39594 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
39595 * This contains a reference to it.
39601 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
39611 * @param {Object} cfg Xtype definition of item to add.
39615 getChildContainer: function () {
39616 return this.getEl();
39621 var ret = new Roo.factory(cfg);
39626 if (cfg.xtype.match(/^Form$/)) {
39629 //if (this.footer) {
39630 // el = this.footer.container.insertSibling(false, 'before');
39632 el = this.el.createChild();
39635 this.form = new Roo.form.Form(cfg);
39638 if ( this.form.allItems.length) {
39639 this.form.render(el.dom);
39643 // should only have one of theses..
39644 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
39645 // views.. should not be just added - used named prop 'view''
39647 cfg.el = this.el.appendChild(document.createElement("div"));
39650 var ret = new Roo.factory(cfg);
39652 ret.render && ret.render(false, ''); // render blank..
39662 * @class Roo.bootstrap.panel.Grid
39663 * @extends Roo.bootstrap.panel.Content
39665 * Create a new GridPanel.
39666 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
39667 * @param {Object} config A the config object
39673 Roo.bootstrap.panel.Grid = function(config)
39677 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
39678 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
39680 config.el = this.wrapper;
39681 //this.el = this.wrapper;
39683 if (config.container) {
39684 // ctor'ed from a Border/panel.grid
39687 this.wrapper.setStyle("overflow", "hidden");
39688 this.wrapper.addClass('roo-grid-container');
39693 if(config.toolbar){
39694 var tool_el = this.wrapper.createChild();
39695 this.toolbar = Roo.factory(config.toolbar);
39697 if (config.toolbar.items) {
39698 ti = config.toolbar.items ;
39699 delete config.toolbar.items ;
39703 this.toolbar.render(tool_el);
39704 for(var i =0;i < ti.length;i++) {
39705 // Roo.log(['add child', items[i]]);
39706 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
39708 this.toolbar.items = nitems;
39710 delete config.toolbar;
39713 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
39714 config.grid.scrollBody = true;;
39715 config.grid.monitorWindowResize = false; // turn off autosizing
39716 config.grid.autoHeight = false;
39717 config.grid.autoWidth = false;
39719 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
39721 if (config.background) {
39722 // render grid on panel activation (if panel background)
39723 this.on('activate', function(gp) {
39724 if (!gp.grid.rendered) {
39725 gp.grid.render(this.wrapper);
39726 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
39731 this.grid.render(this.wrapper);
39732 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
39735 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
39736 // ??? needed ??? config.el = this.wrapper;
39741 // xtype created footer. - not sure if will work as we normally have to render first..
39742 if (this.footer && !this.footer.el && this.footer.xtype) {
39744 var ctr = this.grid.getView().getFooterPanel(true);
39745 this.footer.dataSource = this.grid.dataSource;
39746 this.footer = Roo.factory(this.footer, Roo);
39747 this.footer.render(ctr);
39757 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
39758 getId : function(){
39759 return this.grid.id;
39763 * Returns the grid for this panel
39764 * @return {Roo.bootstrap.Table}
39766 getGrid : function(){
39770 setSize : function(width, height){
39771 if(!this.ignoreResize(width, height)){
39772 var grid = this.grid;
39773 var size = this.adjustForComponents(width, height);
39774 // tfoot is not a footer?
39777 var gridel = grid.getGridEl();
39778 gridel.setSize(size.width, size.height);
39780 var tbd = grid.getGridEl().select('tbody', true).first();
39781 var thd = grid.getGridEl().select('thead',true).first();
39782 var tbf= grid.getGridEl().select('tfoot', true).first();
39785 size.height -= thd.getHeight();
39788 size.height -= thd.getHeight();
39791 tbd.setSize(size.width, size.height );
39792 // this is for the account management tab -seems to work there.
39793 var thd = grid.getGridEl().select('thead',true).first();
39795 // tbd.setSize(size.width, size.height - thd.getHeight());
39804 beforeSlide : function(){
39805 this.grid.getView().scroller.clip();
39808 afterSlide : function(){
39809 this.grid.getView().scroller.unclip();
39812 destroy : function(){
39813 this.grid.destroy();
39815 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
39820 * @class Roo.bootstrap.panel.Nest
39821 * @extends Roo.bootstrap.panel.Content
39823 * Create a new Panel, that can contain a layout.Border.
39826 * @param {Roo.BorderLayout} layout The layout for this panel
39827 * @param {String/Object} config A string to set only the title or a config object
39829 Roo.bootstrap.panel.Nest = function(config)
39831 // construct with only one argument..
39832 /* FIXME - implement nicer consturctors
39833 if (layout.layout) {
39835 layout = config.layout;
39836 delete config.layout;
39838 if (layout.xtype && !layout.getEl) {
39839 // then layout needs constructing..
39840 layout = Roo.factory(layout, Roo);
39844 config.el = config.layout.getEl();
39846 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
39848 config.layout.monitorWindowResize = false; // turn off autosizing
39849 this.layout = config.layout;
39850 this.layout.getEl().addClass("roo-layout-nested-layout");
39851 this.layout.parent = this;
39858 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
39860 setSize : function(width, height){
39861 if(!this.ignoreResize(width, height)){
39862 var size = this.adjustForComponents(width, height);
39863 var el = this.layout.getEl();
39864 if (size.height < 1) {
39865 el.setWidth(size.width);
39867 el.setSize(size.width, size.height);
39869 var touch = el.dom.offsetWidth;
39870 this.layout.layout();
39871 // ie requires a double layout on the first pass
39872 if(Roo.isIE && !this.initialized){
39873 this.initialized = true;
39874 this.layout.layout();
39879 // activate all subpanels if not currently active..
39881 setActiveState : function(active){
39882 this.active = active;
39883 this.setActiveClass(active);
39886 this.fireEvent("deactivate", this);
39890 this.fireEvent("activate", this);
39891 // not sure if this should happen before or after..
39892 if (!this.layout) {
39893 return; // should not happen..
39896 for (var r in this.layout.regions) {
39897 reg = this.layout.getRegion(r);
39898 if (reg.getActivePanel()) {
39899 //reg.showPanel(reg.getActivePanel()); // force it to activate..
39900 reg.setActivePanel(reg.getActivePanel());
39903 if (!reg.panels.length) {
39906 reg.showPanel(reg.getPanel(0));
39915 * Returns the nested BorderLayout for this panel
39916 * @return {Roo.BorderLayout}
39918 getLayout : function(){
39919 return this.layout;
39923 * Adds a xtype elements to the layout of the nested panel
39927 xtype : 'ContentPanel',
39934 xtype : 'NestedLayoutPanel',
39940 items : [ ... list of content panels or nested layout panels.. ]
39944 * @param {Object} cfg Xtype definition of item to add.
39946 addxtype : function(cfg) {
39947 return this.layout.addxtype(cfg);
39952 * Ext JS Library 1.1.1
39953 * Copyright(c) 2006-2007, Ext JS, LLC.
39955 * Originally Released Under LGPL - original licence link has changed is not relivant.
39958 * <script type="text/javascript">
39961 * @class Roo.TabPanel
39962 * @extends Roo.util.Observable
39963 * A lightweight tab container.
39967 // basic tabs 1, built from existing content
39968 var tabs = new Roo.TabPanel("tabs1");
39969 tabs.addTab("script", "View Script");
39970 tabs.addTab("markup", "View Markup");
39971 tabs.activate("script");
39973 // more advanced tabs, built from javascript
39974 var jtabs = new Roo.TabPanel("jtabs");
39975 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
39977 // set up the UpdateManager
39978 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
39979 var updater = tab2.getUpdateManager();
39980 updater.setDefaultUrl("ajax1.htm");
39981 tab2.on('activate', updater.refresh, updater, true);
39983 // Use setUrl for Ajax loading
39984 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
39985 tab3.setUrl("ajax2.htm", null, true);
39988 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
39991 jtabs.activate("jtabs-1");
39994 * Create a new TabPanel.
39995 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
39996 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
39998 Roo.bootstrap.panel.Tabs = function(config){
40000 * The container element for this TabPanel.
40001 * @type Roo.Element
40003 this.el = Roo.get(config.el);
40006 if(typeof config == "boolean"){
40007 this.tabPosition = config ? "bottom" : "top";
40009 Roo.apply(this, config);
40013 if(this.tabPosition == "bottom"){
40014 // if tabs are at the bottom = create the body first.
40015 this.bodyEl = Roo.get(this.createBody(this.el.dom));
40016 this.el.addClass("roo-tabs-bottom");
40018 // next create the tabs holders
40020 if (this.tabPosition == "west"){
40022 var reg = this.region; // fake it..
40024 if (!reg.mgr.parent) {
40027 reg = reg.mgr.parent.region;
40029 Roo.log("got nest?");
40031 if (reg.mgr.getRegion('west')) {
40032 var ctrdom = reg.mgr.getRegion('west').bodyEl.dom;
40033 this.stripWrap = Roo.get(this.createStrip(ctrdom ), true);
40034 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
40035 this.stripEl.setVisibilityMode(Roo.Element.DISPLAY);
40036 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
40044 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
40045 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
40046 this.stripEl.setVisibilityMode(Roo.Element.DISPLAY);
40047 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
40052 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
40055 // finally - if tabs are at the top, then create the body last..
40056 if(this.tabPosition != "bottom"){
40057 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
40058 * @type Roo.Element
40060 this.bodyEl = Roo.get(this.createBody(this.el.dom));
40061 this.el.addClass("roo-tabs-top");
40065 this.bodyEl.setStyle("position", "relative");
40067 this.active = null;
40068 this.activateDelegate = this.activate.createDelegate(this);
40073 * Fires when the active tab changes
40074 * @param {Roo.TabPanel} this
40075 * @param {Roo.TabPanelItem} activePanel The new active tab
40079 * @event beforetabchange
40080 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
40081 * @param {Roo.TabPanel} this
40082 * @param {Object} e Set cancel to true on this object to cancel the tab change
40083 * @param {Roo.TabPanelItem} tab The tab being changed to
40085 "beforetabchange" : true
40088 Roo.EventManager.onWindowResize(this.onResize, this);
40089 this.cpad = this.el.getPadding("lr");
40090 this.hiddenCount = 0;
40093 // toolbar on the tabbar support...
40094 if (this.toolbar) {
40095 alert("no toolbar support yet");
40096 this.toolbar = false;
40098 var tcfg = this.toolbar;
40099 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
40100 this.toolbar = new Roo.Toolbar(tcfg);
40101 if (Roo.isSafari) {
40102 var tbl = tcfg.container.child('table', true);
40103 tbl.setAttribute('width', '100%');
40111 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
40114 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
40116 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
40118 tabPosition : "top",
40120 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
40122 currentTabWidth : 0,
40124 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
40128 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
40132 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
40134 preferredTabWidth : 175,
40136 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
40138 resizeTabs : false,
40140 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
40142 monitorResize : true,
40144 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
40146 toolbar : false, // set by caller..
40148 region : false, /// set by caller
40150 disableTooltips : true, // not used yet...
40153 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
40154 * @param {String} id The id of the div to use <b>or create</b>
40155 * @param {String} text The text for the tab
40156 * @param {String} content (optional) Content to put in the TabPanelItem body
40157 * @param {Boolean} closable (optional) True to create a close icon on the tab
40158 * @return {Roo.TabPanelItem} The created TabPanelItem
40160 addTab : function(id, text, content, closable, tpl)
40162 var item = new Roo.bootstrap.panel.TabItem({
40166 closable : closable,
40169 this.addTabItem(item);
40171 item.setContent(content);
40177 * Returns the {@link Roo.TabPanelItem} with the specified id/index
40178 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
40179 * @return {Roo.TabPanelItem}
40181 getTab : function(id){
40182 return this.items[id];
40186 * Hides the {@link Roo.TabPanelItem} with the specified id/index
40187 * @param {String/Number} id The id or index of the TabPanelItem to hide.
40189 hideTab : function(id){
40190 var t = this.items[id];
40193 this.hiddenCount++;
40194 this.autoSizeTabs();
40199 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
40200 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
40202 unhideTab : function(id){
40203 var t = this.items[id];
40205 t.setHidden(false);
40206 this.hiddenCount--;
40207 this.autoSizeTabs();
40212 * Adds an existing {@link Roo.TabPanelItem}.
40213 * @param {Roo.TabPanelItem} item The TabPanelItem to add
40215 addTabItem : function(item)
40217 this.items[item.id] = item;
40218 this.items.push(item);
40219 this.autoSizeTabs();
40220 // if(this.resizeTabs){
40221 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
40222 // this.autoSizeTabs();
40224 // item.autoSize();
40229 * Removes a {@link Roo.TabPanelItem}.
40230 * @param {String/Number} id The id or index of the TabPanelItem to remove.
40232 removeTab : function(id){
40233 var items = this.items;
40234 var tab = items[id];
40235 if(!tab) { return; }
40236 var index = items.indexOf(tab);
40237 if(this.active == tab && items.length > 1){
40238 var newTab = this.getNextAvailable(index);
40243 this.stripEl.dom.removeChild(tab.pnode.dom);
40244 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
40245 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
40247 items.splice(index, 1);
40248 delete this.items[tab.id];
40249 tab.fireEvent("close", tab);
40250 tab.purgeListeners();
40251 this.autoSizeTabs();
40254 getNextAvailable : function(start){
40255 var items = this.items;
40257 // look for a next tab that will slide over to
40258 // replace the one being removed
40259 while(index < items.length){
40260 var item = items[++index];
40261 if(item && !item.isHidden()){
40265 // if one isn't found select the previous tab (on the left)
40268 var item = items[--index];
40269 if(item && !item.isHidden()){
40277 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
40278 * @param {String/Number} id The id or index of the TabPanelItem to disable.
40280 disableTab : function(id){
40281 var tab = this.items[id];
40282 if(tab && this.active != tab){
40288 * Enables a {@link Roo.TabPanelItem} that is disabled.
40289 * @param {String/Number} id The id or index of the TabPanelItem to enable.
40291 enableTab : function(id){
40292 var tab = this.items[id];
40297 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
40298 * @param {String/Number} id The id or index of the TabPanelItem to activate.
40299 * @return {Roo.TabPanelItem} The TabPanelItem.
40301 activate : function(id)
40303 //Roo.log('activite:' + id);
40305 var tab = this.items[id];
40309 if(tab == this.active || tab.disabled){
40313 this.fireEvent("beforetabchange", this, e, tab);
40314 if(e.cancel !== true && !tab.disabled){
40316 this.active.hide();
40318 this.active = this.items[id];
40319 this.active.show();
40320 this.fireEvent("tabchange", this, this.active);
40326 * Gets the active {@link Roo.TabPanelItem}.
40327 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
40329 getActiveTab : function(){
40330 return this.active;
40334 * Updates the tab body element to fit the height of the container element
40335 * for overflow scrolling
40336 * @param {Number} targetHeight (optional) Override the starting height from the elements height
40338 syncHeight : function(targetHeight){
40339 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
40340 var bm = this.bodyEl.getMargins();
40341 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
40342 this.bodyEl.setHeight(newHeight);
40346 onResize : function(){
40347 if(this.monitorResize){
40348 this.autoSizeTabs();
40353 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
40355 beginUpdate : function(){
40356 this.updating = true;
40360 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
40362 endUpdate : function(){
40363 this.updating = false;
40364 this.autoSizeTabs();
40368 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
40370 autoSizeTabs : function()
40372 var count = this.items.length;
40373 var vcount = count - this.hiddenCount;
40376 this.stripEl.hide();
40378 this.stripEl.show();
40381 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
40386 var w = Math.max(this.el.getWidth() - this.cpad, 10);
40387 var availWidth = Math.floor(w / vcount);
40388 var b = this.stripBody;
40389 if(b.getWidth() > w){
40390 var tabs = this.items;
40391 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
40392 if(availWidth < this.minTabWidth){
40393 /*if(!this.sleft){ // incomplete scrolling code
40394 this.createScrollButtons();
40397 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
40400 if(this.currentTabWidth < this.preferredTabWidth){
40401 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
40407 * Returns the number of tabs in this TabPanel.
40410 getCount : function(){
40411 return this.items.length;
40415 * Resizes all the tabs to the passed width
40416 * @param {Number} The new width
40418 setTabWidth : function(width){
40419 this.currentTabWidth = width;
40420 for(var i = 0, len = this.items.length; i < len; i++) {
40421 if(!this.items[i].isHidden()) {
40422 this.items[i].setWidth(width);
40428 * Destroys this TabPanel
40429 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
40431 destroy : function(removeEl){
40432 Roo.EventManager.removeResizeListener(this.onResize, this);
40433 for(var i = 0, len = this.items.length; i < len; i++){
40434 this.items[i].purgeListeners();
40436 if(removeEl === true){
40437 this.el.update("");
40442 createStrip : function(container)
40444 var strip = document.createElement("nav");
40445 strip.className = Roo.bootstrap.version == 4 ?
40446 "navbar-light bg-light" :
40447 "navbar navbar-default"; //"x-tabs-wrap";
40448 container.appendChild(strip);
40452 createStripList : function(strip)
40454 // div wrapper for retard IE
40455 // returns the "tr" element.
40456 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
40457 //'<div class="x-tabs-strip-wrap">'+
40458 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
40459 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
40460 return strip.firstChild; //.firstChild.firstChild.firstChild;
40462 createBody : function(container)
40464 var body = document.createElement("div");
40465 Roo.id(body, "tab-body");
40466 //Roo.fly(body).addClass("x-tabs-body");
40467 Roo.fly(body).addClass("tab-content");
40468 container.appendChild(body);
40471 createItemBody :function(bodyEl, id){
40472 var body = Roo.getDom(id);
40474 body = document.createElement("div");
40477 //Roo.fly(body).addClass("x-tabs-item-body");
40478 Roo.fly(body).addClass("tab-pane");
40479 bodyEl.insertBefore(body, bodyEl.firstChild);
40483 createStripElements : function(stripEl, text, closable, tpl)
40485 var td = document.createElement("li"); // was td..
40486 td.className = 'nav-item';
40488 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
40491 stripEl.appendChild(td);
40493 td.className = "x-tabs-closable";
40494 if(!this.closeTpl){
40495 this.closeTpl = new Roo.Template(
40496 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
40497 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
40498 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
40501 var el = this.closeTpl.overwrite(td, {"text": text});
40502 var close = el.getElementsByTagName("div")[0];
40503 var inner = el.getElementsByTagName("em")[0];
40504 return {"el": el, "close": close, "inner": inner};
40507 // not sure what this is..
40508 // if(!this.tabTpl){
40509 //this.tabTpl = new Roo.Template(
40510 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
40511 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
40513 // this.tabTpl = new Roo.Template(
40514 // '<a href="#">' +
40515 // '<span unselectable="on"' +
40516 // (this.disableTooltips ? '' : ' title="{text}"') +
40517 // ' >{text}</span></a>'
40523 var template = tpl || this.tabTpl || false;
40526 template = new Roo.Template(
40527 Roo.bootstrap.version == 4 ?
40529 '<a class="nav-link" href="#" unselectable="on"' +
40530 (this.disableTooltips ? '' : ' title="{text}"') +
40533 '<a class="nav-link" href="#">' +
40534 '<span unselectable="on"' +
40535 (this.disableTooltips ? '' : ' title="{text}"') +
40536 ' >{text}</span></a>'
40541 switch (typeof(template)) {
40545 template = new Roo.Template(template);
40551 var el = template.overwrite(td, {"text": text});
40553 var inner = el.getElementsByTagName("span")[0];
40555 return {"el": el, "inner": inner};
40563 * @class Roo.TabPanelItem
40564 * @extends Roo.util.Observable
40565 * Represents an individual item (tab plus body) in a TabPanel.
40566 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
40567 * @param {String} id The id of this TabPanelItem
40568 * @param {String} text The text for the tab of this TabPanelItem
40569 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
40571 Roo.bootstrap.panel.TabItem = function(config){
40573 * The {@link Roo.TabPanel} this TabPanelItem belongs to
40574 * @type Roo.TabPanel
40576 this.tabPanel = config.panel;
40578 * The id for this TabPanelItem
40581 this.id = config.id;
40583 this.disabled = false;
40585 this.text = config.text;
40587 this.loaded = false;
40588 this.closable = config.closable;
40591 * The body element for this TabPanelItem.
40592 * @type Roo.Element
40594 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
40595 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
40596 this.bodyEl.setStyle("display", "block");
40597 this.bodyEl.setStyle("zoom", "1");
40598 //this.hideAction();
40600 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
40602 this.el = Roo.get(els.el);
40603 this.inner = Roo.get(els.inner, true);
40604 this.textEl = Roo.bootstrap.version == 4 ?
40605 this.el : Roo.get(this.el.dom.firstChild, true);
40607 this.pnode = this.linode = Roo.get(els.el.parentNode, true);
40608 this.status_node = Roo.bootstrap.version == 4 ? this.el : this.linode;
40611 // this.el.on("mousedown", this.onTabMouseDown, this);
40612 this.el.on("click", this.onTabClick, this);
40614 if(config.closable){
40615 var c = Roo.get(els.close, true);
40616 c.dom.title = this.closeText;
40617 c.addClassOnOver("close-over");
40618 c.on("click", this.closeClick, this);
40624 * Fires when this tab becomes the active tab.
40625 * @param {Roo.TabPanel} tabPanel The parent TabPanel
40626 * @param {Roo.TabPanelItem} this
40630 * @event beforeclose
40631 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
40632 * @param {Roo.TabPanelItem} this
40633 * @param {Object} e Set cancel to true on this object to cancel the close.
40635 "beforeclose": true,
40638 * Fires when this tab is closed.
40639 * @param {Roo.TabPanelItem} this
40643 * @event deactivate
40644 * Fires when this tab is no longer the active tab.
40645 * @param {Roo.TabPanel} tabPanel The parent TabPanel
40646 * @param {Roo.TabPanelItem} this
40648 "deactivate" : true
40650 this.hidden = false;
40652 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
40655 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
40657 purgeListeners : function(){
40658 Roo.util.Observable.prototype.purgeListeners.call(this);
40659 this.el.removeAllListeners();
40662 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
40665 this.status_node.addClass("active");
40668 this.tabPanel.stripWrap.repaint();
40670 this.fireEvent("activate", this.tabPanel, this);
40674 * Returns true if this tab is the active tab.
40675 * @return {Boolean}
40677 isActive : function(){
40678 return this.tabPanel.getActiveTab() == this;
40682 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
40685 this.status_node.removeClass("active");
40687 this.fireEvent("deactivate", this.tabPanel, this);
40690 hideAction : function(){
40691 this.bodyEl.hide();
40692 this.bodyEl.setStyle("position", "absolute");
40693 this.bodyEl.setLeft("-20000px");
40694 this.bodyEl.setTop("-20000px");
40697 showAction : function(){
40698 this.bodyEl.setStyle("position", "relative");
40699 this.bodyEl.setTop("");
40700 this.bodyEl.setLeft("");
40701 this.bodyEl.show();
40705 * Set the tooltip for the tab.
40706 * @param {String} tooltip The tab's tooltip
40708 setTooltip : function(text){
40709 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
40710 this.textEl.dom.qtip = text;
40711 this.textEl.dom.removeAttribute('title');
40713 this.textEl.dom.title = text;
40717 onTabClick : function(e){
40718 e.preventDefault();
40719 this.tabPanel.activate(this.id);
40722 onTabMouseDown : function(e){
40723 e.preventDefault();
40724 this.tabPanel.activate(this.id);
40727 getWidth : function(){
40728 return this.inner.getWidth();
40731 setWidth : function(width){
40732 var iwidth = width - this.linode.getPadding("lr");
40733 this.inner.setWidth(iwidth);
40734 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
40735 this.linode.setWidth(width);
40739 * Show or hide the tab
40740 * @param {Boolean} hidden True to hide or false to show.
40742 setHidden : function(hidden){
40743 this.hidden = hidden;
40744 this.linode.setStyle("display", hidden ? "none" : "");
40748 * Returns true if this tab is "hidden"
40749 * @return {Boolean}
40751 isHidden : function(){
40752 return this.hidden;
40756 * Returns the text for this tab
40759 getText : function(){
40763 autoSize : function(){
40764 //this.el.beginMeasure();
40765 this.textEl.setWidth(1);
40767 * #2804 [new] Tabs in Roojs
40768 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
40770 //this.setWidth(this.textEl.dom.scrollWidth+this.linode.getPadding("lr")+this.inner.getPadding("lr") + 2);
40771 //this.el.endMeasure();
40775 * Sets the text for the tab (Note: this also sets the tooltip text)
40776 * @param {String} text The tab's text and tooltip
40778 setText : function(text){
40780 this.textEl.update(text);
40781 this.setTooltip(text);
40782 //if(!this.tabPanel.resizeTabs){
40783 // this.autoSize();
40787 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
40789 activate : function(){
40790 this.tabPanel.activate(this.id);
40794 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
40796 disable : function(){
40797 if(this.tabPanel.active != this){
40798 this.disabled = true;
40799 this.status_node.addClass("disabled");
40804 * Enables this TabPanelItem if it was previously disabled.
40806 enable : function(){
40807 this.disabled = false;
40808 this.status_node.removeClass("disabled");
40812 * Sets the content for this TabPanelItem.
40813 * @param {String} content The content
40814 * @param {Boolean} loadScripts true to look for and load scripts
40816 setContent : function(content, loadScripts){
40817 this.bodyEl.update(content, loadScripts);
40821 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
40822 * @return {Roo.UpdateManager} The UpdateManager
40824 getUpdateManager : function(){
40825 return this.bodyEl.getUpdateManager();
40829 * Set a URL to be used to load the content for this TabPanelItem.
40830 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
40831 * @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)
40832 * @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)
40833 * @return {Roo.UpdateManager} The UpdateManager
40835 setUrl : function(url, params, loadOnce){
40836 if(this.refreshDelegate){
40837 this.un('activate', this.refreshDelegate);
40839 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
40840 this.on("activate", this.refreshDelegate);
40841 return this.bodyEl.getUpdateManager();
40845 _handleRefresh : function(url, params, loadOnce){
40846 if(!loadOnce || !this.loaded){
40847 var updater = this.bodyEl.getUpdateManager();
40848 updater.update(url, params, this._setLoaded.createDelegate(this));
40853 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
40854 * Will fail silently if the setUrl method has not been called.
40855 * This does not activate the panel, just updates its content.
40857 refresh : function(){
40858 if(this.refreshDelegate){
40859 this.loaded = false;
40860 this.refreshDelegate();
40865 _setLoaded : function(){
40866 this.loaded = true;
40870 closeClick : function(e){
40873 this.fireEvent("beforeclose", this, o);
40874 if(o.cancel !== true){
40875 this.tabPanel.removeTab(this.id);
40879 * The text displayed in the tooltip for the close icon.
40882 closeText : "Close this tab"
40885 * This script refer to:
40886 * Title: International Telephone Input
40887 * Author: Jack O'Connor
40888 * Code version: v12.1.12
40889 * Availability: https://github.com/jackocnr/intl-tel-input.git
40892 Roo.bootstrap.PhoneInputData = function() {
40895 "Afghanistan (افغانستان)",
40900 "Albania (Shqipëri)",
40905 "Algeria (الجزائر)",
40930 "Antigua and Barbuda",
40940 "Armenia (Հայաստան)",
40956 "Austria (Österreich)",
40961 "Azerbaijan (Azərbaycan)",
40971 "Bahrain (البحرين)",
40976 "Bangladesh (বাংলাদেশ)",
40986 "Belarus (Беларусь)",
40991 "Belgium (België)",
41021 "Bosnia and Herzegovina (Босна и Херцеговина)",
41036 "British Indian Ocean Territory",
41041 "British Virgin Islands",
41051 "Bulgaria (България)",
41061 "Burundi (Uburundi)",
41066 "Cambodia (កម្ពុជា)",
41071 "Cameroon (Cameroun)",
41080 ["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"]
41083 "Cape Verde (Kabu Verdi)",
41088 "Caribbean Netherlands",
41099 "Central African Republic (République centrafricaine)",
41119 "Christmas Island",
41125 "Cocos (Keeling) Islands",
41136 "Comoros (جزر القمر)",
41141 "Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)",
41146 "Congo (Republic) (Congo-Brazzaville)",
41166 "Croatia (Hrvatska)",
41187 "Czech Republic (Česká republika)",
41192 "Denmark (Danmark)",
41207 "Dominican Republic (República Dominicana)",
41211 ["809", "829", "849"]
41229 "Equatorial Guinea (Guinea Ecuatorial)",
41249 "Falkland Islands (Islas Malvinas)",
41254 "Faroe Islands (Føroyar)",
41275 "French Guiana (Guyane française)",
41280 "French Polynesia (Polynésie française)",
41295 "Georgia (საქართველო)",
41300 "Germany (Deutschland)",
41320 "Greenland (Kalaallit Nunaat)",
41357 "Guinea-Bissau (Guiné Bissau)",
41382 "Hungary (Magyarország)",
41387 "Iceland (Ísland)",
41407 "Iraq (العراق)",
41423 "Israel (ישראל)",
41450 "Jordan (الأردن)",
41455 "Kazakhstan (Казахстан)",
41476 "Kuwait (الكويت)",
41481 "Kyrgyzstan (Кыргызстан)",
41491 "Latvia (Latvija)",
41496 "Lebanon (لبنان)",
41511 "Libya (ليبيا)",
41521 "Lithuania (Lietuva)",
41536 "Macedonia (FYROM) (Македонија)",
41541 "Madagascar (Madagasikara)",
41571 "Marshall Islands",
41581 "Mauritania (موريتانيا)",
41586 "Mauritius (Moris)",
41607 "Moldova (Republica Moldova)",
41617 "Mongolia (Монгол)",
41622 "Montenegro (Crna Gora)",
41632 "Morocco (المغرب)",
41638 "Mozambique (Moçambique)",
41643 "Myanmar (Burma) (မြန်မာ)",
41648 "Namibia (Namibië)",
41663 "Netherlands (Nederland)",
41668 "New Caledonia (Nouvelle-Calédonie)",
41703 "North Korea (조선 민주주의 인민 공화국)",
41708 "Northern Mariana Islands",
41724 "Pakistan (پاکستان)",
41734 "Palestine (فلسطين)",
41744 "Papua New Guinea",
41786 "Réunion (La Réunion)",
41792 "Romania (România)",
41808 "Saint Barthélemy",
41819 "Saint Kitts and Nevis",
41829 "Saint Martin (Saint-Martin (partie française))",
41835 "Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)",
41840 "Saint Vincent and the Grenadines",
41855 "São Tomé and Príncipe (São Tomé e Príncipe)",
41860 "Saudi Arabia (المملكة العربية السعودية)",
41865 "Senegal (Sénégal)",
41895 "Slovakia (Slovensko)",
41900 "Slovenia (Slovenija)",
41910 "Somalia (Soomaaliya)",
41920 "South Korea (대한민국)",
41925 "South Sudan (جنوب السودان)",
41935 "Sri Lanka (ශ්රී ලංකාව)",
41940 "Sudan (السودان)",
41950 "Svalbard and Jan Mayen",
41961 "Sweden (Sverige)",
41966 "Switzerland (Schweiz)",
41971 "Syria (سوريا)",
42016 "Trinidad and Tobago",
42021 "Tunisia (تونس)",
42026 "Turkey (Türkiye)",
42036 "Turks and Caicos Islands",
42046 "U.S. Virgin Islands",
42056 "Ukraine (Україна)",
42061 "United Arab Emirates (الإمارات العربية المتحدة)",
42083 "Uzbekistan (Oʻzbekiston)",
42093 "Vatican City (Città del Vaticano)",
42104 "Vietnam (Việt Nam)",
42109 "Wallis and Futuna (Wallis-et-Futuna)",
42114 "Western Sahara (الصحراء الغربية)",
42120 "Yemen (اليمن)",
42144 * This script refer to:
42145 * Title: International Telephone Input
42146 * Author: Jack O'Connor
42147 * Code version: v12.1.12
42148 * Availability: https://github.com/jackocnr/intl-tel-input.git
42152 * @class Roo.bootstrap.PhoneInput
42153 * @extends Roo.bootstrap.TriggerField
42154 * An input with International dial-code selection
42156 * @cfg {String} defaultDialCode default '+852'
42157 * @cfg {Array} preferedCountries default []
42160 * Create a new PhoneInput.
42161 * @param {Object} config Configuration options
42164 Roo.bootstrap.PhoneInput = function(config) {
42165 Roo.bootstrap.PhoneInput.superclass.constructor.call(this, config);
42168 Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
42170 listWidth: undefined,
42172 selectedClass: 'active',
42174 invalidClass : "has-warning",
42176 validClass: 'has-success',
42178 allowed: '0123456789',
42183 * @cfg {String} defaultDialCode The default dial code when initializing the input
42185 defaultDialCode: '+852',
42188 * @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
42190 preferedCountries: false,
42192 getAutoCreate : function()
42194 var data = Roo.bootstrap.PhoneInputData();
42195 var align = this.labelAlign || this.parentLabelAlign();
42198 this.allCountries = [];
42199 this.dialCodeMapping = [];
42201 for (var i = 0; i < data.length; i++) {
42203 this.allCountries[i] = {
42207 priority: c[3] || 0,
42208 areaCodes: c[4] || null
42210 this.dialCodeMapping[c[2]] = {
42213 priority: c[3] || 0,
42214 areaCodes: c[4] || null
42226 // type: 'number', -- do not use number - we get the flaky up/down arrows.
42227 maxlength: this.max_length,
42228 cls : 'form-control tel-input',
42229 autocomplete: 'new-password'
42232 var hiddenInput = {
42235 cls: 'hidden-tel-input'
42239 hiddenInput.name = this.name;
42242 if (this.disabled) {
42243 input.disabled = true;
42246 var flag_container = {
42263 cls: this.hasFeedback ? 'has-feedback' : '',
42269 cls: 'dial-code-holder',
42276 cls: 'roo-select2-container input-group',
42283 if (this.fieldLabel.length) {
42286 tooltip: 'This field is required'
42292 cls: 'control-label',
42298 html: this.fieldLabel
42301 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
42307 if(this.indicatorpos == 'right') {
42308 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
42315 if(align == 'left') {
42323 if(this.labelWidth > 12){
42324 label.style = "width: " + this.labelWidth + 'px';
42326 if(this.labelWidth < 13 && this.labelmd == 0){
42327 this.labelmd = this.labelWidth;
42329 if(this.labellg > 0){
42330 label.cls += ' col-lg-' + this.labellg;
42331 input.cls += ' col-lg-' + (12 - this.labellg);
42333 if(this.labelmd > 0){
42334 label.cls += ' col-md-' + this.labelmd;
42335 container.cls += ' col-md-' + (12 - this.labelmd);
42337 if(this.labelsm > 0){
42338 label.cls += ' col-sm-' + this.labelsm;
42339 container.cls += ' col-sm-' + (12 - this.labelsm);
42341 if(this.labelxs > 0){
42342 label.cls += ' col-xs-' + this.labelxs;
42343 container.cls += ' col-xs-' + (12 - this.labelxs);
42353 var settings = this;
42355 ['xs','sm','md','lg'].map(function(size){
42356 if (settings[size]) {
42357 cfg.cls += ' col-' + size + '-' + settings[size];
42361 this.store = new Roo.data.Store({
42362 proxy : new Roo.data.MemoryProxy({}),
42363 reader : new Roo.data.JsonReader({
42374 'name' : 'dialCode',
42378 'name' : 'priority',
42382 'name' : 'areaCodes',
42389 if(!this.preferedCountries) {
42390 this.preferedCountries = [
42397 var p = this.preferedCountries.reverse();
42400 for (var i = 0; i < p.length; i++) {
42401 for (var j = 0; j < this.allCountries.length; j++) {
42402 if(this.allCountries[j].iso2 == p[i]) {
42403 var t = this.allCountries[j];
42404 this.allCountries.splice(j,1);
42405 this.allCountries.unshift(t);
42411 this.store.proxy.data = {
42413 data: this.allCountries
42419 initEvents : function()
42422 Roo.bootstrap.PhoneInput.superclass.initEvents.call(this);
42424 this.indicator = this.indicatorEl();
42425 this.flag = this.flagEl();
42426 this.dialCodeHolder = this.dialCodeHolderEl();
42428 this.trigger = this.el.select('div.flag-box',true).first();
42429 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
42434 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
42435 _this.list.setWidth(lw);
42438 this.list.on('mouseover', this.onViewOver, this);
42439 this.list.on('mousemove', this.onViewMove, this);
42440 this.inputEl().on("keyup", this.onKeyUp, this);
42441 this.inputEl().on("keypress", this.onKeyPress, this);
42443 this.tpl = '<li><a href="#"><div class="flag {iso2}"></div>{name} <span class="dial-code">+{dialCode}</span></a></li>';
42445 this.view = new Roo.View(this.list, this.tpl, {
42446 singleSelect:true, store: this.store, selectedClass: this.selectedClass
42449 this.view.on('click', this.onViewClick, this);
42450 this.setValue(this.defaultDialCode);
42453 onTriggerClick : function(e)
42455 Roo.log('trigger click');
42460 if(this.isExpanded()){
42462 this.hasFocus = false;
42464 this.store.load({});
42465 this.hasFocus = true;
42470 isExpanded : function()
42472 return this.list.isVisible();
42475 collapse : function()
42477 if(!this.isExpanded()){
42481 Roo.get(document).un('mousedown', this.collapseIf, this);
42482 Roo.get(document).un('mousewheel', this.collapseIf, this);
42483 this.fireEvent('collapse', this);
42487 expand : function()
42491 if(this.isExpanded() || !this.hasFocus){
42495 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
42496 this.list.setWidth(lw);
42499 this.restrictHeight();
42501 Roo.get(document).on('mousedown', this.collapseIf, this);
42502 Roo.get(document).on('mousewheel', this.collapseIf, this);
42504 this.fireEvent('expand', this);
42507 restrictHeight : function()
42509 this.list.alignTo(this.inputEl(), this.listAlign);
42510 this.list.alignTo(this.inputEl(), this.listAlign);
42513 onViewOver : function(e, t)
42515 if(this.inKeyMode){
42518 var item = this.view.findItemFromChild(t);
42521 var index = this.view.indexOf(item);
42522 this.select(index, false);
42527 onViewClick : function(view, doFocus, el, e)
42529 var index = this.view.getSelectedIndexes()[0];
42531 var r = this.store.getAt(index);
42534 this.onSelect(r, index);
42536 if(doFocus !== false && !this.blockFocus){
42537 this.inputEl().focus();
42541 onViewMove : function(e, t)
42543 this.inKeyMode = false;
42546 select : function(index, scrollIntoView)
42548 this.selectedIndex = index;
42549 this.view.select(index);
42550 if(scrollIntoView !== false){
42551 var el = this.view.getNode(index);
42553 this.list.scrollChildIntoView(el, false);
42558 createList : function()
42560 this.list = Roo.get(document.body).createChild({
42562 cls: 'typeahead typeahead-long dropdown-menu tel-list',
42563 style: 'display:none'
42566 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
42569 collapseIf : function(e)
42571 var in_combo = e.within(this.el);
42572 var in_list = e.within(this.list);
42573 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
42575 if (in_combo || in_list || is_list) {
42581 onSelect : function(record, index)
42583 if(this.fireEvent('beforeselect', this, record, index) !== false){
42585 this.setFlagClass(record.data.iso2);
42586 this.setDialCode(record.data.dialCode);
42587 this.hasFocus = false;
42589 this.fireEvent('select', this, record, index);
42593 flagEl : function()
42595 var flag = this.el.select('div.flag',true).first();
42602 dialCodeHolderEl : function()
42604 var d = this.el.select('input.dial-code-holder',true).first();
42611 setDialCode : function(v)
42613 this.dialCodeHolder.dom.value = '+'+v;
42616 setFlagClass : function(n)
42618 this.flag.dom.className = 'flag '+n;
42621 getValue : function()
42623 var v = this.inputEl().getValue();
42624 if(this.dialCodeHolder) {
42625 v = this.dialCodeHolder.dom.value+this.inputEl().getValue();
42630 setValue : function(v)
42632 var d = this.getDialCode(v);
42634 //invalid dial code
42635 if(v.length == 0 || !d || d.length == 0) {
42637 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
42638 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
42644 this.setFlagClass(this.dialCodeMapping[d].iso2);
42645 this.setDialCode(d);
42646 this.inputEl().dom.value = v.replace('+'+d,'');
42647 this.hiddenEl().dom.value = this.getValue();
42652 getDialCode : function(v)
42656 if (v.length == 0) {
42657 return this.dialCodeHolder.dom.value;
42661 if (v.charAt(0) != "+") {
42664 var numericChars = "";
42665 for (var i = 1; i < v.length; i++) {
42666 var c = v.charAt(i);
42669 if (this.dialCodeMapping[numericChars]) {
42670 dialCode = v.substr(1, i);
42672 if (numericChars.length == 4) {
42682 this.setValue(this.defaultDialCode);
42686 hiddenEl : function()
42688 return this.el.select('input.hidden-tel-input',true).first();
42691 // after setting val
42692 onKeyUp : function(e){
42693 this.setValue(this.getValue());
42696 onKeyPress : function(e){
42697 if(this.allowed.indexOf(String.fromCharCode(e.getCharCode())) === -1){
42704 * @class Roo.bootstrap.MoneyField
42705 * @extends Roo.bootstrap.ComboBox
42706 * Bootstrap MoneyField class
42709 * Create a new MoneyField.
42710 * @param {Object} config Configuration options
42713 Roo.bootstrap.MoneyField = function(config) {
42715 Roo.bootstrap.MoneyField.superclass.constructor.call(this, config);
42719 Roo.extend(Roo.bootstrap.MoneyField, Roo.bootstrap.ComboBox, {
42722 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
42724 allowDecimals : true,
42726 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
42728 decimalSeparator : ".",
42730 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
42732 decimalPrecision : 0,
42734 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
42736 allowNegative : true,
42738 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
42742 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
42744 minValue : Number.NEGATIVE_INFINITY,
42746 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
42748 maxValue : Number.MAX_VALUE,
42750 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
42752 minText : "The minimum value for this field is {0}",
42754 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
42756 maxText : "The maximum value for this field is {0}",
42758 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
42759 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
42761 nanText : "{0} is not a valid number",
42763 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
42767 * @cfg {String} defaults currency of the MoneyField
42768 * value should be in lkey
42770 defaultCurrency : false,
42772 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
42774 thousandsDelimiter : false,
42776 * @cfg {Number} max_length Maximum input field length allowed (defaults to Number.MAX_VALUE)
42787 getAutoCreate : function()
42789 var align = this.labelAlign || this.parentLabelAlign();
42801 cls : 'form-control roo-money-amount-input',
42802 autocomplete: 'new-password'
42805 var hiddenInput = {
42809 cls: 'hidden-number-input'
42812 if(this.max_length) {
42813 input.maxlength = this.max_length;
42817 hiddenInput.name = this.name;
42820 if (this.disabled) {
42821 input.disabled = true;
42824 var clg = 12 - this.inputlg;
42825 var cmd = 12 - this.inputmd;
42826 var csm = 12 - this.inputsm;
42827 var cxs = 12 - this.inputxs;
42831 cls : 'row roo-money-field',
42835 cls : 'roo-money-currency column col-lg-' + clg + ' col-md-' + cmd + ' col-sm-' + csm + ' col-xs-' + cxs,
42839 cls: 'roo-select2-container input-group',
42843 cls : 'form-control roo-money-currency-input',
42844 autocomplete: 'new-password',
42846 name : this.currencyName
42850 cls : 'input-group-addon',
42864 cls : 'roo-money-amount column col-lg-' + this.inputlg + ' col-md-' + this.inputmd + ' col-sm-' + this.inputsm + ' col-xs-' + this.inputxs,
42868 cls: this.hasFeedback ? 'has-feedback' : '',
42879 if (this.fieldLabel.length) {
42882 tooltip: 'This field is required'
42888 cls: 'control-label',
42894 html: this.fieldLabel
42897 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
42903 if(this.indicatorpos == 'right') {
42904 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
42911 if(align == 'left') {
42919 if(this.labelWidth > 12){
42920 label.style = "width: " + this.labelWidth + 'px';
42922 if(this.labelWidth < 13 && this.labelmd == 0){
42923 this.labelmd = this.labelWidth;
42925 if(this.labellg > 0){
42926 label.cls += ' col-lg-' + this.labellg;
42927 input.cls += ' col-lg-' + (12 - this.labellg);
42929 if(this.labelmd > 0){
42930 label.cls += ' col-md-' + this.labelmd;
42931 container.cls += ' col-md-' + (12 - this.labelmd);
42933 if(this.labelsm > 0){
42934 label.cls += ' col-sm-' + this.labelsm;
42935 container.cls += ' col-sm-' + (12 - this.labelsm);
42937 if(this.labelxs > 0){
42938 label.cls += ' col-xs-' + this.labelxs;
42939 container.cls += ' col-xs-' + (12 - this.labelxs);
42950 var settings = this;
42952 ['xs','sm','md','lg'].map(function(size){
42953 if (settings[size]) {
42954 cfg.cls += ' col-' + size + '-' + settings[size];
42961 initEvents : function()
42963 this.indicator = this.indicatorEl();
42965 this.initCurrencyEvent();
42967 this.initNumberEvent();
42970 initCurrencyEvent : function()
42973 throw "can not find store for combo";
42976 this.store = Roo.factory(this.store, Roo.data);
42977 this.store.parent = this;
42981 this.triggerEl = this.el.select('.input-group-addon', true).first();
42983 this.triggerEl.on("click", this.onTriggerClick, this, { preventDefault : true });
42988 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
42989 _this.list.setWidth(lw);
42992 this.list.on('mouseover', this.onViewOver, this);
42993 this.list.on('mousemove', this.onViewMove, this);
42994 this.list.on('scroll', this.onViewScroll, this);
42997 this.tpl = '<li><a href="#">{' + this.currencyField + '}</a></li>';
43000 this.view = new Roo.View(this.list, this.tpl, {
43001 singleSelect:true, store: this.store, selectedClass: this.selectedClass
43004 this.view.on('click', this.onViewClick, this);
43006 this.store.on('beforeload', this.onBeforeLoad, this);
43007 this.store.on('load', this.onLoad, this);
43008 this.store.on('loadexception', this.onLoadException, this);
43010 this.keyNav = new Roo.KeyNav(this.currencyEl(), {
43011 "up" : function(e){
43012 this.inKeyMode = true;
43016 "down" : function(e){
43017 if(!this.isExpanded()){
43018 this.onTriggerClick();
43020 this.inKeyMode = true;
43025 "enter" : function(e){
43028 if(this.fireEvent("specialkey", this, e)){
43029 this.onViewClick(false);
43035 "esc" : function(e){
43039 "tab" : function(e){
43042 if(this.fireEvent("specialkey", this, e)){
43043 this.onViewClick(false);
43051 doRelay : function(foo, bar, hname){
43052 if(hname == 'down' || this.scope.isExpanded()){
43053 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
43061 this.currencyEl().on("click", this.onTriggerClick, this, { preventDefault : true });
43065 initNumberEvent : function(e)
43067 this.inputEl().on("keydown" , this.fireKey, this);
43068 this.inputEl().on("focus", this.onFocus, this);
43069 this.inputEl().on("blur", this.onBlur, this);
43071 this.inputEl().relayEvent('keyup', this);
43073 if(this.indicator){
43074 this.indicator.addClass('invisible');
43077 this.originalValue = this.getValue();
43079 if(this.validationEvent == 'keyup'){
43080 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
43081 this.inputEl().on('keyup', this.filterValidation, this);
43083 else if(this.validationEvent !== false){
43084 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
43087 if(this.selectOnFocus){
43088 this.on("focus", this.preFocus, this);
43091 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
43092 this.inputEl().on("keypress", this.filterKeys, this);
43094 this.inputEl().relayEvent('keypress', this);
43097 var allowed = "0123456789";
43099 if(this.allowDecimals){
43100 allowed += this.decimalSeparator;
43103 if(this.allowNegative){
43107 if(this.thousandsDelimiter) {
43111 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
43113 var keyPress = function(e){
43115 var k = e.getKey();
43117 var c = e.getCharCode();
43120 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
43121 allowed.indexOf(String.fromCharCode(c)) === -1
43127 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
43131 if(allowed.indexOf(String.fromCharCode(c)) === -1){
43136 this.inputEl().on("keypress", keyPress, this);
43140 onTriggerClick : function(e)
43147 this.loadNext = false;
43149 if(this.isExpanded()){
43154 this.hasFocus = true;
43156 if(this.triggerAction == 'all') {
43157 this.doQuery(this.allQuery, true);
43161 this.doQuery(this.getRawValue());
43164 getCurrency : function()
43166 var v = this.currencyEl().getValue();
43171 restrictHeight : function()
43173 this.list.alignTo(this.currencyEl(), this.listAlign);
43174 this.list.alignTo(this.currencyEl(), this.listAlign);
43177 onViewClick : function(view, doFocus, el, e)
43179 var index = this.view.getSelectedIndexes()[0];
43181 var r = this.store.getAt(index);
43184 this.onSelect(r, index);
43188 onSelect : function(record, index){
43190 if(this.fireEvent('beforeselect', this, record, index) !== false){
43192 this.setFromCurrencyData(index > -1 ? record.data : false);
43196 this.fireEvent('select', this, record, index);
43200 setFromCurrencyData : function(o)
43204 this.lastCurrency = o;
43206 if (this.currencyField) {
43207 currency = !o || typeof(o[this.currencyField]) == 'undefined' ? '' : o[this.currencyField];
43209 Roo.log('no currencyField value set for '+ (this.name ? this.name : this.id));
43212 this.lastSelectionText = currency;
43214 //setting default currency
43215 if(o[this.currencyField] * 1 == 0 && this.defaultCurrency) {
43216 this.setCurrency(this.defaultCurrency);
43220 this.setCurrency(currency);
43223 setFromData : function(o)
43227 c[this.currencyField] = !o || typeof(o[this.currencyName]) == 'undefined' ? '' : o[this.currencyName];
43229 this.setFromCurrencyData(c);
43234 value = !o || typeof(o[this.name]) == 'undefined' ? '' : o[this.name];
43236 Roo.log('no value set for '+ (this.name ? this.name : this.id));
43239 this.setValue(value);
43243 setCurrency : function(v)
43245 this.currencyValue = v;
43248 this.currencyEl().dom.value = (v === null || v === undefined ? '' : v);
43253 setValue : function(v)
43255 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
43261 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
43263 this.inputEl().dom.value = (v == '') ? '' :
43264 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
43266 if(!this.allowZero && v === '0') {
43267 this.hiddenEl().dom.value = '';
43268 this.inputEl().dom.value = '';
43275 getRawValue : function()
43277 var v = this.inputEl().getValue();
43282 getValue : function()
43284 return this.fixPrecision(this.parseValue(this.getRawValue()));
43287 parseValue : function(value)
43289 if(this.thousandsDelimiter) {
43291 r = new RegExp(",", "g");
43292 value = value.replace(r, "");
43295 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
43296 return isNaN(value) ? '' : value;
43300 fixPrecision : function(value)
43302 if(this.thousandsDelimiter) {
43304 r = new RegExp(",", "g");
43305 value = value.replace(r, "");
43308 var nan = isNaN(value);
43310 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
43311 return nan ? '' : value;
43313 return parseFloat(value).toFixed(this.decimalPrecision);
43316 decimalPrecisionFcn : function(v)
43318 return Math.floor(v);
43321 validateValue : function(value)
43323 if(!Roo.bootstrap.MoneyField.superclass.validateValue.call(this, value)){
43327 var num = this.parseValue(value);
43330 this.markInvalid(String.format(this.nanText, value));
43334 if(num < this.minValue){
43335 this.markInvalid(String.format(this.minText, this.minValue));
43339 if(num > this.maxValue){
43340 this.markInvalid(String.format(this.maxText, this.maxValue));
43347 validate : function()
43349 if(this.disabled || this.allowBlank){
43354 var currency = this.getCurrency();
43356 if(this.validateValue(this.getRawValue()) && currency.length){
43361 this.markInvalid();
43365 getName: function()
43370 beforeBlur : function()
43376 var v = this.parseValue(this.getRawValue());
43383 onBlur : function()
43387 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
43388 //this.el.removeClass(this.focusClass);
43391 this.hasFocus = false;
43393 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
43397 var v = this.getValue();
43399 if(String(v) !== String(this.startValue)){
43400 this.fireEvent('change', this, v, this.startValue);
43403 this.fireEvent("blur", this);
43406 inputEl : function()
43408 return this.el.select('.roo-money-amount-input', true).first();
43411 currencyEl : function()
43413 return this.el.select('.roo-money-currency-input', true).first();
43416 hiddenEl : function()
43418 return this.el.select('input.hidden-number-input',true).first();
43422 * @class Roo.bootstrap.BezierSignature
43423 * @extends Roo.bootstrap.Component
43424 * Bootstrap BezierSignature class
43425 * This script refer to:
43426 * Title: Signature Pad
43428 * Availability: https://github.com/szimek/signature_pad
43431 * Create a new BezierSignature
43432 * @param {Object} config The config object
43435 Roo.bootstrap.BezierSignature = function(config){
43436 Roo.bootstrap.BezierSignature.superclass.constructor.call(this, config);
43442 Roo.extend(Roo.bootstrap.BezierSignature, Roo.bootstrap.Component,
43449 mouse_btn_down: true,
43452 * @cfg {int} canvas height
43454 canvas_height: '200px',
43457 * @cfg {float|function} Radius of a single dot.
43462 * @cfg {float} Minimum width of a line. Defaults to 0.5.
43467 * @cfg {float} Maximum width of a line. Defaults to 2.5.
43472 * @cfg {integer} Draw the next point at most once per every x milliseconds. Set it to 0 to turn off throttling. Defaults to 16.
43477 * @cfg {integer} Add the next point only if the previous one is farther than x pixels. Defaults to 5.
43482 * @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.
43484 bg_color: 'rgba(0, 0, 0, 0)',
43487 * @cfg {string} Color used to draw the lines. Can be any color format accepted by context.fillStyle. Defaults to "black".
43489 dot_color: 'black',
43492 * @cfg {float} Weight used to modify new velocity based on the previous velocity. Defaults to 0.7.
43494 velocity_filter_weight: 0.7,
43497 * @cfg {function} Callback when stroke begin.
43502 * @cfg {function} Callback when stroke end.
43506 getAutoCreate : function()
43508 var cls = 'roo-signature column';
43511 cls += ' ' + this.cls;
43521 for(var i = 0; i < col_sizes.length; i++) {
43522 if(this[col_sizes[i]]) {
43523 cls += " col-"+col_sizes[i]+"-"+this[col_sizes[i]];
43533 cls: 'roo-signature-body',
43537 cls: 'roo-signature-body-canvas',
43538 height: this.canvas_height,
43539 width: this.canvas_width
43546 style: 'display: none'
43554 initEvents: function()
43556 Roo.bootstrap.BezierSignature.superclass.initEvents.call(this);
43558 var canvas = this.canvasEl();
43560 // mouse && touch event swapping...
43561 canvas.dom.style.touchAction = 'none';
43562 canvas.dom.style.msTouchAction = 'none';
43564 this.mouse_btn_down = false;
43565 canvas.on('mousedown', this._handleMouseDown, this);
43566 canvas.on('mousemove', this._handleMouseMove, this);
43567 Roo.select('html').first().on('mouseup', this._handleMouseUp, this);
43569 if (window.PointerEvent) {
43570 canvas.on('pointerdown', this._handleMouseDown, this);
43571 canvas.on('pointermove', this._handleMouseMove, this);
43572 Roo.select('html').first().on('pointerup', this._handleMouseUp, this);
43575 if ('ontouchstart' in window) {
43576 canvas.on('touchstart', this._handleTouchStart, this);
43577 canvas.on('touchmove', this._handleTouchMove, this);
43578 canvas.on('touchend', this._handleTouchEnd, this);
43581 Roo.EventManager.onWindowResize(this.resize, this, true);
43583 // file input event
43584 this.fileEl().on('change', this.uploadImage, this);
43591 resize: function(){
43593 var canvas = this.canvasEl().dom;
43594 var ctx = this.canvasElCtx();
43595 var img_data = false;
43597 if(canvas.width > 0) {
43598 var img_data = ctx.getImageData(0, 0, canvas.width, canvas.height);
43600 // setting canvas width will clean img data
43603 var style = window.getComputedStyle ?
43604 getComputedStyle(this.el.dom, null) : this.el.dom.currentStyle;
43606 var padding_left = parseInt(style.paddingLeft) || 0;
43607 var padding_right = parseInt(style.paddingRight) || 0;
43609 canvas.width = this.el.dom.clientWidth - padding_left - padding_right;
43612 ctx.putImageData(img_data, 0, 0);
43616 _handleMouseDown: function(e)
43618 if (e.browserEvent.which === 1) {
43619 this.mouse_btn_down = true;
43620 this.strokeBegin(e);
43624 _handleMouseMove: function (e)
43626 if (this.mouse_btn_down) {
43627 this.strokeMoveUpdate(e);
43631 _handleMouseUp: function (e)
43633 if (e.browserEvent.which === 1 && this.mouse_btn_down) {
43634 this.mouse_btn_down = false;
43639 _handleTouchStart: function (e) {
43641 e.preventDefault();
43642 if (e.browserEvent.targetTouches.length === 1) {
43643 // var touch = e.browserEvent.changedTouches[0];
43644 // this.strokeBegin(touch);
43646 this.strokeBegin(e); // assume e catching the correct xy...
43650 _handleTouchMove: function (e) {
43651 e.preventDefault();
43652 // var touch = event.targetTouches[0];
43653 // _this._strokeMoveUpdate(touch);
43654 this.strokeMoveUpdate(e);
43657 _handleTouchEnd: function (e) {
43658 var wasCanvasTouched = e.target === this.canvasEl().dom;
43659 if (wasCanvasTouched) {
43660 e.preventDefault();
43661 // var touch = event.changedTouches[0];
43662 // _this._strokeEnd(touch);
43667 reset: function () {
43668 this._lastPoints = [];
43669 this._lastVelocity = 0;
43670 this._lastWidth = (this.min_width + this.max_width) / 2;
43671 this.canvasElCtx().fillStyle = this.dot_color;
43674 strokeMoveUpdate: function(e)
43676 this.strokeUpdate(e);
43678 if (this.throttle) {
43679 this.throttleStroke(this.strokeUpdate, this.throttle);
43682 this.strokeUpdate(e);
43686 strokeBegin: function(e)
43688 var newPointGroup = {
43689 color: this.dot_color,
43693 if (typeof this.onBegin === 'function') {
43697 this.curve_data.push(newPointGroup);
43699 this.strokeUpdate(e);
43702 strokeUpdate: function(e)
43704 var rect = this.canvasEl().dom.getBoundingClientRect();
43705 var point = new this.Point(e.xy[0] - rect.left, e.xy[1] - rect.top, new Date().getTime());
43706 var lastPointGroup = this.curve_data[this.curve_data.length - 1];
43707 var lastPoints = lastPointGroup.points;
43708 var lastPoint = lastPoints.length > 0 && lastPoints[lastPoints.length - 1];
43709 var isLastPointTooClose = lastPoint
43710 ? point.distanceTo(lastPoint) <= this.min_distance
43712 var color = lastPointGroup.color;
43713 if (!lastPoint || !(lastPoint && isLastPointTooClose)) {
43714 var curve = this.addPoint(point);
43716 this.drawDot({color: color, point: point});
43719 this.drawCurve({color: color, curve: curve});
43729 strokeEnd: function(e)
43731 this.strokeUpdate(e);
43732 if (typeof this.onEnd === 'function') {
43737 addPoint: function (point) {
43738 var _lastPoints = this._lastPoints;
43739 _lastPoints.push(point);
43740 if (_lastPoints.length > 2) {
43741 if (_lastPoints.length === 3) {
43742 _lastPoints.unshift(_lastPoints[0]);
43744 var widths = this.calculateCurveWidths(_lastPoints[1], _lastPoints[2]);
43745 var curve = this.Bezier.fromPoints(_lastPoints, widths, this);
43746 _lastPoints.shift();
43752 calculateCurveWidths: function (startPoint, endPoint) {
43753 var velocity = this.velocity_filter_weight * endPoint.velocityFrom(startPoint) +
43754 (1 - this.velocity_filter_weight) * this._lastVelocity;
43756 var newWidth = Math.max(this.max_width / (velocity + 1), this.min_width);
43759 start: this._lastWidth
43762 this._lastVelocity = velocity;
43763 this._lastWidth = newWidth;
43767 drawDot: function (_a) {
43768 var color = _a.color, point = _a.point;
43769 var ctx = this.canvasElCtx();
43770 var width = typeof this.dot_size === 'function' ? this.dot_size() : this.dot_size;
43772 this.drawCurveSegment(point.x, point.y, width);
43774 ctx.fillStyle = color;
43778 drawCurve: function (_a) {
43779 var color = _a.color, curve = _a.curve;
43780 var ctx = this.canvasElCtx();
43781 var widthDelta = curve.endWidth - curve.startWidth;
43782 var drawSteps = Math.floor(curve.length()) * 2;
43784 ctx.fillStyle = color;
43785 for (var i = 0; i < drawSteps; i += 1) {
43786 var t = i / drawSteps;
43792 var x = uuu * curve.startPoint.x;
43793 x += 3 * uu * t * curve.control1.x;
43794 x += 3 * u * tt * curve.control2.x;
43795 x += ttt * curve.endPoint.x;
43796 var y = uuu * curve.startPoint.y;
43797 y += 3 * uu * t * curve.control1.y;
43798 y += 3 * u * tt * curve.control2.y;
43799 y += ttt * curve.endPoint.y;
43800 var width = curve.startWidth + ttt * widthDelta;
43801 this.drawCurveSegment(x, y, width);
43807 drawCurveSegment: function (x, y, width) {
43808 var ctx = this.canvasElCtx();
43810 ctx.arc(x, y, width, 0, 2 * Math.PI, false);
43811 this.is_empty = false;
43816 var ctx = this.canvasElCtx();
43817 var canvas = this.canvasEl().dom;
43818 ctx.fillStyle = this.bg_color;
43819 ctx.clearRect(0, 0, canvas.width, canvas.height);
43820 ctx.fillRect(0, 0, canvas.width, canvas.height);
43821 this.curve_data = [];
43823 this.is_empty = true;
43828 return this.el.select('input',true).first();
43831 canvasEl: function()
43833 return this.el.select('canvas',true).first();
43836 canvasElCtx: function()
43838 return this.el.select('canvas',true).first().dom.getContext('2d');
43841 getImage: function(type)
43843 if(this.is_empty) {
43848 return this.canvasEl().dom.toDataURL('image/'+type, 1);
43851 drawFromImage: function(img_src)
43853 var img = new Image();
43855 img.onload = function(){
43856 this.canvasElCtx().drawImage(img, 0, 0);
43861 this.is_empty = false;
43864 selectImage: function()
43866 this.fileEl().dom.click();
43869 uploadImage: function(e)
43871 var reader = new FileReader();
43873 reader.onload = function(e){
43874 var img = new Image();
43875 img.onload = function(){
43877 this.canvasElCtx().drawImage(img, 0, 0);
43879 img.src = e.target.result;
43882 reader.readAsDataURL(e.target.files[0]);
43885 // Bezier Point Constructor
43886 Point: (function () {
43887 function Point(x, y, time) {
43890 this.time = time || Date.now();
43892 Point.prototype.distanceTo = function (start) {
43893 return Math.sqrt(Math.pow(this.x - start.x, 2) + Math.pow(this.y - start.y, 2));
43895 Point.prototype.equals = function (other) {
43896 return this.x === other.x && this.y === other.y && this.time === other.time;
43898 Point.prototype.velocityFrom = function (start) {
43899 return this.time !== start.time
43900 ? this.distanceTo(start) / (this.time - start.time)
43907 // Bezier Constructor
43908 Bezier: (function () {
43909 function Bezier(startPoint, control2, control1, endPoint, startWidth, endWidth) {
43910 this.startPoint = startPoint;
43911 this.control2 = control2;
43912 this.control1 = control1;
43913 this.endPoint = endPoint;
43914 this.startWidth = startWidth;
43915 this.endWidth = endWidth;
43917 Bezier.fromPoints = function (points, widths, scope) {
43918 var c2 = this.calculateControlPoints(points[0], points[1], points[2], scope).c2;
43919 var c3 = this.calculateControlPoints(points[1], points[2], points[3], scope).c1;
43920 return new Bezier(points[1], c2, c3, points[2], widths.start, widths.end);
43922 Bezier.calculateControlPoints = function (s1, s2, s3, scope) {
43923 var dx1 = s1.x - s2.x;
43924 var dy1 = s1.y - s2.y;
43925 var dx2 = s2.x - s3.x;
43926 var dy2 = s2.y - s3.y;
43927 var m1 = { x: (s1.x + s2.x) / 2.0, y: (s1.y + s2.y) / 2.0 };
43928 var m2 = { x: (s2.x + s3.x) / 2.0, y: (s2.y + s3.y) / 2.0 };
43929 var l1 = Math.sqrt(dx1 * dx1 + dy1 * dy1);
43930 var l2 = Math.sqrt(dx2 * dx2 + dy2 * dy2);
43931 var dxm = m1.x - m2.x;
43932 var dym = m1.y - m2.y;
43933 var k = l2 / (l1 + l2);
43934 var cm = { x: m2.x + dxm * k, y: m2.y + dym * k };
43935 var tx = s2.x - cm.x;
43936 var ty = s2.y - cm.y;
43938 c1: new scope.Point(m1.x + tx, m1.y + ty),
43939 c2: new scope.Point(m2.x + tx, m2.y + ty)
43942 Bezier.prototype.length = function () {
43947 for (var i = 0; i <= steps; i += 1) {
43949 var cx = this.point(t, this.startPoint.x, this.control1.x, this.control2.x, this.endPoint.x);
43950 var cy = this.point(t, this.startPoint.y, this.control1.y, this.control2.y, this.endPoint.y);
43952 var xdiff = cx - px;
43953 var ydiff = cy - py;
43954 length += Math.sqrt(xdiff * xdiff + ydiff * ydiff);
43961 Bezier.prototype.point = function (t, start, c1, c2, end) {
43962 return (start * (1.0 - t) * (1.0 - t) * (1.0 - t))
43963 + (3.0 * c1 * (1.0 - t) * (1.0 - t) * t)
43964 + (3.0 * c2 * (1.0 - t) * t * t)
43965 + (end * t * t * t);
43970 throttleStroke: function(fn, wait) {
43971 if (wait === void 0) { wait = 250; }
43973 var timeout = null;
43977 var later = function () {
43978 previous = Date.now();
43980 result = fn.apply(storedContext, storedArgs);
43982 storedContext = null;
43986 return function wrapper() {
43988 for (var _i = 0; _i < arguments.length; _i++) {
43989 args[_i] = arguments[_i];
43991 var now = Date.now();
43992 var remaining = wait - (now - previous);
43993 storedContext = this;
43995 if (remaining <= 0 || remaining > wait) {
43997 clearTimeout(timeout);
44001 result = fn.apply(storedContext, storedArgs);
44003 storedContext = null;
44007 else if (!timeout) {
44008 timeout = window.setTimeout(later, remaining);