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['display' + (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();
8592 this.getGridEl().select('tfoot tr, tfoot td',true).setWidth(cw);
8596 tbd.setWidth(ctr.getWidth());
8597 // if the body has a max height - and then scrolls - we should perhaps set up the height here
8598 // this needs fixing for various usage - currently only hydra job advers I think..
8600 // ctr.getHeight() - ((thd ? thd.getHeight() : 0) + (tfd ? tfd.getHeight() : 0))
8602 var barsize = (tbd.dom.offsetWidth - tbd.dom.clientWidth);
8605 cw = Math.max(cw, this.totalWidth);
8606 this.getGridEl().select('tbody tr',true).setWidth(cw);
8608 // resize 'expandable coloumn?
8610 return; // we doe not have a view in this design..
8613 onBodyScroll: function()
8615 //Roo.log("body scrolled');" + this.mainBody.dom.scrollLeft);
8617 this.mainHead.setStyle({
8618 'position' : 'relative',
8619 'left': (-1* this.mainBody.dom.scrollLeft) + 'px'
8625 var scrollHeight = this.mainBody.dom.scrollHeight;
8627 var scrollTop = Math.ceil(this.mainBody.getScroll().top);
8629 var height = this.mainBody.getHeight();
8631 if(scrollHeight - height == scrollTop) {
8633 var total = this.ds.getTotalCount();
8635 if(this.footer.cursor + this.footer.pageSize < total){
8637 this.footer.ds.load({
8639 start : this.footer.cursor + this.footer.pageSize,
8640 limit : this.footer.pageSize
8650 onHeaderChange : function()
8652 var header = this.renderHeader();
8653 var table = this.el.select('table', true).first();
8655 this.mainHead.remove();
8656 this.mainHead = table.createChild(header, this.mainBody, false);
8659 onHiddenChange : function(colModel, colIndex, hidden)
8661 var thSelector = '#' + this.id + ' .x-hcol-' + colIndex;
8662 var tdSelector = '#' + this.id + ' .x-col-' + colIndex;
8664 this.CSS.updateRule(thSelector, "display", "");
8665 this.CSS.updateRule(tdSelector, "display", "");
8668 this.CSS.updateRule(thSelector, "display", "none");
8669 this.CSS.updateRule(tdSelector, "display", "none");
8672 this.onHeaderChange();
8676 setColumnWidth: function(col_index, width)
8678 // width = "md-2 xs-2..."
8679 if(!this.colModel.config[col_index]) {
8683 var w = width.split(" ");
8685 var rows = this.el.dom.getElementsByClassName("x-col-"+col_index);
8687 var h_row = this.el.dom.getElementsByClassName("x-hcol-"+col_index);
8690 for(var j = 0; j < w.length; j++) {
8696 var size_cls = w[j].split("-");
8698 if(!Number.isInteger(size_cls[1] * 1)) {
8702 if(!this.colModel.config[col_index][size_cls[0]]) {
8706 if(!h_row[0].classList.contains("col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]])) {
8710 h_row[0].classList.replace(
8711 "col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]],
8712 "col-"+size_cls[0]+"-"+size_cls[1]
8715 for(var i = 0; i < rows.length; i++) {
8717 var size_cls = w[j].split("-");
8719 if(!Number.isInteger(size_cls[1] * 1)) {
8723 if(!this.colModel.config[col_index][size_cls[0]]) {
8727 if(!rows[i].classList.contains("col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]])) {
8731 rows[i].classList.replace(
8732 "col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]],
8733 "col-"+size_cls[0]+"-"+size_cls[1]
8737 this.colModel.config[col_index][size_cls[0]] = size_cls[1];
8752 * @class Roo.bootstrap.TableCell
8753 * @extends Roo.bootstrap.Component
8754 * Bootstrap TableCell class
8755 * @cfg {String} html cell contain text
8756 * @cfg {String} cls cell class
8757 * @cfg {String} tag cell tag (td|th) default td
8758 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
8759 * @cfg {String} align Aligns the content in a cell
8760 * @cfg {String} axis Categorizes cells
8761 * @cfg {String} bgcolor Specifies the background color of a cell
8762 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
8763 * @cfg {Number} colspan Specifies the number of columns a cell should span
8764 * @cfg {String} headers Specifies one or more header cells a cell is related to
8765 * @cfg {Number} height Sets the height of a cell
8766 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
8767 * @cfg {Number} rowspan Sets the number of rows a cell should span
8768 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
8769 * @cfg {String} valign Vertical aligns the content in a cell
8770 * @cfg {Number} width Specifies the width of a cell
8773 * Create a new TableCell
8774 * @param {Object} config The config object
8777 Roo.bootstrap.TableCell = function(config){
8778 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
8781 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
8801 getAutoCreate : function(){
8802 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
8822 cfg.align=this.align
8828 cfg.bgcolor=this.bgcolor
8831 cfg.charoff=this.charoff
8834 cfg.colspan=this.colspan
8837 cfg.headers=this.headers
8840 cfg.height=this.height
8843 cfg.nowrap=this.nowrap
8846 cfg.rowspan=this.rowspan
8849 cfg.scope=this.scope
8852 cfg.valign=this.valign
8855 cfg.width=this.width
8874 * @class Roo.bootstrap.TableRow
8875 * @extends Roo.bootstrap.Component
8876 * Bootstrap TableRow class
8877 * @cfg {String} cls row class
8878 * @cfg {String} align Aligns the content in a table row
8879 * @cfg {String} bgcolor Specifies a background color for a table row
8880 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
8881 * @cfg {String} valign Vertical aligns the content in a table row
8884 * Create a new TableRow
8885 * @param {Object} config The config object
8888 Roo.bootstrap.TableRow = function(config){
8889 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
8892 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
8900 getAutoCreate : function(){
8901 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
8911 cfg.align = this.align;
8914 cfg.bgcolor = this.bgcolor;
8917 cfg.charoff = this.charoff;
8920 cfg.valign = this.valign;
8938 * @class Roo.bootstrap.TableBody
8939 * @extends Roo.bootstrap.Component
8940 * Bootstrap TableBody class
8941 * @cfg {String} cls element class
8942 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
8943 * @cfg {String} align Aligns the content inside the element
8944 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
8945 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
8948 * Create a new TableBody
8949 * @param {Object} config The config object
8952 Roo.bootstrap.TableBody = function(config){
8953 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
8956 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
8964 getAutoCreate : function(){
8965 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
8979 cfg.align = this.align;
8982 cfg.charoff = this.charoff;
8985 cfg.valign = this.valign;
8992 // initEvents : function()
8999 // this.store = Roo.factory(this.store, Roo.data);
9000 // this.store.on('load', this.onLoad, this);
9002 // this.store.load();
9006 // onLoad: function ()
9008 // this.fireEvent('load', this);
9018 * Ext JS Library 1.1.1
9019 * Copyright(c) 2006-2007, Ext JS, LLC.
9021 * Originally Released Under LGPL - original licence link has changed is not relivant.
9024 * <script type="text/javascript">
9027 // as we use this in bootstrap.
9028 Roo.namespace('Roo.form');
9030 * @class Roo.form.Action
9031 * Internal Class used to handle form actions
9033 * @param {Roo.form.BasicForm} el The form element or its id
9034 * @param {Object} config Configuration options
9039 // define the action interface
9040 Roo.form.Action = function(form, options){
9042 this.options = options || {};
9045 * Client Validation Failed
9048 Roo.form.Action.CLIENT_INVALID = 'client';
9050 * Server Validation Failed
9053 Roo.form.Action.SERVER_INVALID = 'server';
9055 * Connect to Server Failed
9058 Roo.form.Action.CONNECT_FAILURE = 'connect';
9060 * Reading Data from Server Failed
9063 Roo.form.Action.LOAD_FAILURE = 'load';
9065 Roo.form.Action.prototype = {
9067 failureType : undefined,
9068 response : undefined,
9072 run : function(options){
9077 success : function(response){
9082 handleResponse : function(response){
9086 // default connection failure
9087 failure : function(response){
9089 this.response = response;
9090 this.failureType = Roo.form.Action.CONNECT_FAILURE;
9091 this.form.afterAction(this, false);
9094 processResponse : function(response){
9095 this.response = response;
9096 if(!response.responseText){
9099 this.result = this.handleResponse(response);
9103 // utility functions used internally
9104 getUrl : function(appendParams){
9105 var url = this.options.url || this.form.url || this.form.el.dom.action;
9107 var p = this.getParams();
9109 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
9115 getMethod : function(){
9116 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
9119 getParams : function(){
9120 var bp = this.form.baseParams;
9121 var p = this.options.params;
9123 if(typeof p == "object"){
9124 p = Roo.urlEncode(Roo.applyIf(p, bp));
9125 }else if(typeof p == 'string' && bp){
9126 p += '&' + Roo.urlEncode(bp);
9129 p = Roo.urlEncode(bp);
9134 createCallback : function(){
9136 success: this.success,
9137 failure: this.failure,
9139 timeout: (this.form.timeout*1000),
9140 upload: this.form.fileUpload ? this.success : undefined
9145 Roo.form.Action.Submit = function(form, options){
9146 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
9149 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
9152 haveProgress : false,
9153 uploadComplete : false,
9155 // uploadProgress indicator.
9156 uploadProgress : function()
9158 if (!this.form.progressUrl) {
9162 if (!this.haveProgress) {
9163 Roo.MessageBox.progress("Uploading", "Uploading");
9165 if (this.uploadComplete) {
9166 Roo.MessageBox.hide();
9170 this.haveProgress = true;
9172 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
9174 var c = new Roo.data.Connection();
9176 url : this.form.progressUrl,
9181 success : function(req){
9182 //console.log(data);
9186 rdata = Roo.decode(req.responseText)
9188 Roo.log("Invalid data from server..");
9192 if (!rdata || !rdata.success) {
9194 Roo.MessageBox.alert(Roo.encode(rdata));
9197 var data = rdata.data;
9199 if (this.uploadComplete) {
9200 Roo.MessageBox.hide();
9205 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
9206 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
9209 this.uploadProgress.defer(2000,this);
9212 failure: function(data) {
9213 Roo.log('progress url failed ');
9224 // run get Values on the form, so it syncs any secondary forms.
9225 this.form.getValues();
9227 var o = this.options;
9228 var method = this.getMethod();
9229 var isPost = method == 'POST';
9230 if(o.clientValidation === false || this.form.isValid()){
9232 if (this.form.progressUrl) {
9233 this.form.findField('UPLOAD_IDENTIFIER').setValue(
9234 (new Date() * 1) + '' + Math.random());
9239 Roo.Ajax.request(Roo.apply(this.createCallback(), {
9240 form:this.form.el.dom,
9241 url:this.getUrl(!isPost),
9243 params:isPost ? this.getParams() : null,
9244 isUpload: this.form.fileUpload,
9245 formData : this.form.formData
9248 this.uploadProgress();
9250 }else if (o.clientValidation !== false){ // client validation failed
9251 this.failureType = Roo.form.Action.CLIENT_INVALID;
9252 this.form.afterAction(this, false);
9256 success : function(response)
9258 this.uploadComplete= true;
9259 if (this.haveProgress) {
9260 Roo.MessageBox.hide();
9264 var result = this.processResponse(response);
9265 if(result === true || result.success){
9266 this.form.afterAction(this, true);
9270 this.form.markInvalid(result.errors);
9271 this.failureType = Roo.form.Action.SERVER_INVALID;
9273 this.form.afterAction(this, false);
9275 failure : function(response)
9277 this.uploadComplete= true;
9278 if (this.haveProgress) {
9279 Roo.MessageBox.hide();
9282 this.response = response;
9283 this.failureType = Roo.form.Action.CONNECT_FAILURE;
9284 this.form.afterAction(this, false);
9287 handleResponse : function(response){
9288 if(this.form.errorReader){
9289 var rs = this.form.errorReader.read(response);
9292 for(var i = 0, len = rs.records.length; i < len; i++) {
9293 var r = rs.records[i];
9297 if(errors.length < 1){
9301 success : rs.success,
9307 ret = Roo.decode(response.responseText);
9311 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
9321 Roo.form.Action.Load = function(form, options){
9322 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
9323 this.reader = this.form.reader;
9326 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
9331 Roo.Ajax.request(Roo.apply(
9332 this.createCallback(), {
9333 method:this.getMethod(),
9334 url:this.getUrl(false),
9335 params:this.getParams()
9339 success : function(response){
9341 var result = this.processResponse(response);
9342 if(result === true || !result.success || !result.data){
9343 this.failureType = Roo.form.Action.LOAD_FAILURE;
9344 this.form.afterAction(this, false);
9347 this.form.clearInvalid();
9348 this.form.setValues(result.data);
9349 this.form.afterAction(this, true);
9352 handleResponse : function(response){
9353 if(this.form.reader){
9354 var rs = this.form.reader.read(response);
9355 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
9357 success : rs.success,
9361 return Roo.decode(response.responseText);
9365 Roo.form.Action.ACTION_TYPES = {
9366 'load' : Roo.form.Action.Load,
9367 'submit' : Roo.form.Action.Submit
9376 * @class Roo.bootstrap.Form
9377 * @extends Roo.bootstrap.Component
9378 * Bootstrap Form class
9379 * @cfg {String} method GET | POST (default POST)
9380 * @cfg {String} labelAlign top | left (default top)
9381 * @cfg {String} align left | right - for navbars
9382 * @cfg {Boolean} loadMask load mask when submit (default true)
9387 * @param {Object} config The config object
9391 Roo.bootstrap.Form = function(config){
9393 Roo.bootstrap.Form.superclass.constructor.call(this, config);
9395 Roo.bootstrap.Form.popover.apply();
9399 * @event clientvalidation
9400 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
9401 * @param {Form} this
9402 * @param {Boolean} valid true if the form has passed client-side validation
9404 clientvalidation: true,
9406 * @event beforeaction
9407 * Fires before any action is performed. Return false to cancel the action.
9408 * @param {Form} this
9409 * @param {Action} action The action to be performed
9413 * @event actionfailed
9414 * Fires when an action fails.
9415 * @param {Form} this
9416 * @param {Action} action The action that failed
9418 actionfailed : true,
9420 * @event actioncomplete
9421 * Fires when an action is completed.
9422 * @param {Form} this
9423 * @param {Action} action The action that completed
9425 actioncomplete : true
9429 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
9432 * @cfg {String} method
9433 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
9438 * The URL to use for form actions if one isn't supplied in the action options.
9441 * @cfg {Boolean} fileUpload
9442 * Set to true if this form is a file upload.
9446 * @cfg {Object} baseParams
9447 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
9451 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
9455 * @cfg {Sting} align (left|right) for navbar forms
9460 activeAction : null,
9463 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
9464 * element by passing it or its id or mask the form itself by passing in true.
9467 waitMsgTarget : false,
9472 * @cfg {Boolean} errorMask (true|false) default false
9477 * @cfg {Number} maskOffset Default 100
9482 * @cfg {Boolean} maskBody
9486 getAutoCreate : function(){
9490 method : this.method || 'POST',
9491 id : this.id || Roo.id(),
9494 if (this.parent().xtype.match(/^Nav/)) {
9495 cfg.cls = 'navbar-form form-inline navbar-' + this.align;
9499 if (this.labelAlign == 'left' ) {
9500 cfg.cls += ' form-horizontal';
9506 initEvents : function()
9508 this.el.on('submit', this.onSubmit, this);
9509 // this was added as random key presses on the form where triggering form submit.
9510 this.el.on('keypress', function(e) {
9511 if (e.getCharCode() != 13) {
9514 // we might need to allow it for textareas.. and some other items.
9515 // check e.getTarget().
9517 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
9521 Roo.log("keypress blocked");
9529 onSubmit : function(e){
9534 * Returns true if client-side validation on the form is successful.
9537 isValid : function(){
9538 var items = this.getItems();
9542 items.each(function(f){
9548 Roo.log('invalid field: ' + f.name);
9552 if(!target && f.el.isVisible(true)){
9558 if(this.errorMask && !valid){
9559 Roo.bootstrap.Form.popover.mask(this, target);
9566 * Returns true if any fields in this form have changed since their original load.
9569 isDirty : function(){
9571 var items = this.getItems();
9572 items.each(function(f){
9582 * Performs a predefined action (submit or load) or custom actions you define on this form.
9583 * @param {String} actionName The name of the action type
9584 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
9585 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
9586 * accept other config options):
9588 Property Type Description
9589 ---------------- --------------- ----------------------------------------------------------------------------------
9590 url String The url for the action (defaults to the form's url)
9591 method String The form method to use (defaults to the form's method, or POST if not defined)
9592 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
9593 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
9594 validate the form on the client (defaults to false)
9596 * @return {BasicForm} this
9598 doAction : function(action, options){
9599 if(typeof action == 'string'){
9600 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
9602 if(this.fireEvent('beforeaction', this, action) !== false){
9603 this.beforeAction(action);
9604 action.run.defer(100, action);
9610 beforeAction : function(action){
9611 var o = action.options;
9616 Roo.get(document.body).mask(o.waitMsg || "Sending", 'x-mask-loading')
9618 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
9621 // not really supported yet.. ??
9623 //if(this.waitMsgTarget === true){
9624 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
9625 //}else if(this.waitMsgTarget){
9626 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
9627 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
9629 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
9635 afterAction : function(action, success){
9636 this.activeAction = null;
9637 var o = action.options;
9642 Roo.get(document.body).unmask();
9648 //if(this.waitMsgTarget === true){
9649 // this.el.unmask();
9650 //}else if(this.waitMsgTarget){
9651 // this.waitMsgTarget.unmask();
9653 // Roo.MessageBox.updateProgress(1);
9654 // Roo.MessageBox.hide();
9661 Roo.callback(o.success, o.scope, [this, action]);
9662 this.fireEvent('actioncomplete', this, action);
9666 // failure condition..
9667 // we have a scenario where updates need confirming.
9668 // eg. if a locking scenario exists..
9669 // we look for { errors : { needs_confirm : true }} in the response.
9671 (typeof(action.result) != 'undefined') &&
9672 (typeof(action.result.errors) != 'undefined') &&
9673 (typeof(action.result.errors.needs_confirm) != 'undefined')
9676 Roo.log("not supported yet");
9679 Roo.MessageBox.confirm(
9680 "Change requires confirmation",
9681 action.result.errorMsg,
9686 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
9696 Roo.callback(o.failure, o.scope, [this, action]);
9697 // show an error message if no failed handler is set..
9698 if (!this.hasListener('actionfailed')) {
9699 Roo.log("need to add dialog support");
9701 Roo.MessageBox.alert("Error",
9702 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
9703 action.result.errorMsg :
9704 "Saving Failed, please check your entries or try again"
9709 this.fireEvent('actionfailed', this, action);
9714 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
9715 * @param {String} id The value to search for
9718 findField : function(id){
9719 var items = this.getItems();
9720 var field = items.get(id);
9722 items.each(function(f){
9723 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
9730 return field || null;
9733 * Mark fields in this form invalid in bulk.
9734 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
9735 * @return {BasicForm} this
9737 markInvalid : function(errors){
9738 if(errors instanceof Array){
9739 for(var i = 0, len = errors.length; i < len; i++){
9740 var fieldError = errors[i];
9741 var f = this.findField(fieldError.id);
9743 f.markInvalid(fieldError.msg);
9749 if(typeof errors[id] != 'function' && (field = this.findField(id))){
9750 field.markInvalid(errors[id]);
9754 //Roo.each(this.childForms || [], function (f) {
9755 // f.markInvalid(errors);
9762 * Set values for fields in this form in bulk.
9763 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
9764 * @return {BasicForm} this
9766 setValues : function(values){
9767 if(values instanceof Array){ // array of objects
9768 for(var i = 0, len = values.length; i < len; i++){
9770 var f = this.findField(v.id);
9772 f.setValue(v.value);
9773 if(this.trackResetOnLoad){
9774 f.originalValue = f.getValue();
9778 }else{ // object hash
9781 if(typeof values[id] != 'function' && (field = this.findField(id))){
9783 if (field.setFromData &&
9785 field.displayField &&
9786 // combos' with local stores can
9787 // be queried via setValue()
9788 // to set their value..
9789 (field.store && !field.store.isLocal)
9793 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
9794 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
9795 field.setFromData(sd);
9797 } else if(field.setFromData && (field.store && !field.store.isLocal)) {
9799 field.setFromData(values);
9802 field.setValue(values[id]);
9806 if(this.trackResetOnLoad){
9807 field.originalValue = field.getValue();
9813 //Roo.each(this.childForms || [], function (f) {
9814 // f.setValues(values);
9821 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
9822 * they are returned as an array.
9823 * @param {Boolean} asString
9826 getValues : function(asString){
9827 //if (this.childForms) {
9828 // copy values from the child forms
9829 // Roo.each(this.childForms, function (f) {
9830 // this.setValues(f.getValues());
9836 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
9837 if(asString === true){
9840 return Roo.urlDecode(fs);
9844 * Returns the fields in this form as an object with key/value pairs.
9845 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
9848 getFieldValues : function(with_hidden)
9850 var items = this.getItems();
9852 items.each(function(f){
9858 var v = f.getValue();
9860 if (f.inputType =='radio') {
9861 if (typeof(ret[f.getName()]) == 'undefined') {
9862 ret[f.getName()] = ''; // empty..
9865 if (!f.el.dom.checked) {
9873 if(f.xtype == 'MoneyField'){
9874 ret[f.currencyName] = f.getCurrency();
9877 // not sure if this supported any more..
9878 if ((typeof(v) == 'object') && f.getRawValue) {
9879 v = f.getRawValue() ; // dates..
9881 // combo boxes where name != hiddenName...
9882 if (f.name !== false && f.name != '' && f.name != f.getName()) {
9883 ret[f.name] = f.getRawValue();
9885 ret[f.getName()] = v;
9892 * Clears all invalid messages in this form.
9893 * @return {BasicForm} this
9895 clearInvalid : function(){
9896 var items = this.getItems();
9898 items.each(function(f){
9907 * @return {BasicForm} this
9910 var items = this.getItems();
9911 items.each(function(f){
9915 Roo.each(this.childForms || [], function (f) {
9923 getItems : function()
9925 var r=new Roo.util.MixedCollection(false, function(o){
9926 return o.id || (o.id = Roo.id());
9928 var iter = function(el) {
9935 Roo.each(el.items,function(e) {
9944 hideFields : function(items)
9946 Roo.each(items, function(i){
9948 var f = this.findField(i);
9959 showFields : function(items)
9961 Roo.each(items, function(i){
9963 var f = this.findField(i);
9976 Roo.apply(Roo.bootstrap.Form, {
10003 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
10004 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
10005 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
10006 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
10009 this.maskEl.top.enableDisplayMode("block");
10010 this.maskEl.left.enableDisplayMode("block");
10011 this.maskEl.bottom.enableDisplayMode("block");
10012 this.maskEl.right.enableDisplayMode("block");
10014 this.toolTip = new Roo.bootstrap.Tooltip({
10015 cls : 'roo-form-error-popover',
10017 'left' : ['r-l', [-2,0], 'right'],
10018 'right' : ['l-r', [2,0], 'left'],
10019 'bottom' : ['tl-bl', [0,2], 'top'],
10020 'top' : [ 'bl-tl', [0,-2], 'bottom']
10024 this.toolTip.render(Roo.get(document.body));
10026 this.toolTip.el.enableDisplayMode("block");
10028 Roo.get(document.body).on('click', function(){
10032 Roo.get(document.body).on('touchstart', function(){
10036 this.isApplied = true
10039 mask : function(form, target)
10043 this.target = target;
10045 if(!this.form.errorMask || !target.el){
10049 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.modal', 100, true) || Roo.get(document.body);
10051 Roo.log(scrollable);
10053 var ot = this.target.el.calcOffsetsTo(scrollable);
10055 var scrollTo = ot[1] - this.form.maskOffset;
10057 scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
10059 scrollable.scrollTo('top', scrollTo);
10061 var box = this.target.el.getBox();
10063 var zIndex = Roo.bootstrap.Modal.zIndex++;
10066 this.maskEl.top.setStyle('position', 'absolute');
10067 this.maskEl.top.setStyle('z-index', zIndex);
10068 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
10069 this.maskEl.top.setLeft(0);
10070 this.maskEl.top.setTop(0);
10071 this.maskEl.top.show();
10073 this.maskEl.left.setStyle('position', 'absolute');
10074 this.maskEl.left.setStyle('z-index', zIndex);
10075 this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
10076 this.maskEl.left.setLeft(0);
10077 this.maskEl.left.setTop(box.y - this.padding);
10078 this.maskEl.left.show();
10080 this.maskEl.bottom.setStyle('position', 'absolute');
10081 this.maskEl.bottom.setStyle('z-index', zIndex);
10082 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
10083 this.maskEl.bottom.setLeft(0);
10084 this.maskEl.bottom.setTop(box.bottom + this.padding);
10085 this.maskEl.bottom.show();
10087 this.maskEl.right.setStyle('position', 'absolute');
10088 this.maskEl.right.setStyle('z-index', zIndex);
10089 this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
10090 this.maskEl.right.setLeft(box.right + this.padding);
10091 this.maskEl.right.setTop(box.y - this.padding);
10092 this.maskEl.right.show();
10094 this.toolTip.bindEl = this.target.el;
10096 this.toolTip.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
10098 var tip = this.target.blankText;
10100 if(this.target.getValue() !== '' ) {
10102 if (this.target.invalidText.length) {
10103 tip = this.target.invalidText;
10104 } else if (this.target.regexText.length){
10105 tip = this.target.regexText;
10109 this.toolTip.show(tip);
10111 this.intervalID = window.setInterval(function() {
10112 Roo.bootstrap.Form.popover.unmask();
10115 window.onwheel = function(){ return false;};
10117 (function(){ this.isMasked = true; }).defer(500, this);
10121 unmask : function()
10123 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
10127 this.maskEl.top.setStyle('position', 'absolute');
10128 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
10129 this.maskEl.top.hide();
10131 this.maskEl.left.setStyle('position', 'absolute');
10132 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
10133 this.maskEl.left.hide();
10135 this.maskEl.bottom.setStyle('position', 'absolute');
10136 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
10137 this.maskEl.bottom.hide();
10139 this.maskEl.right.setStyle('position', 'absolute');
10140 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
10141 this.maskEl.right.hide();
10143 this.toolTip.hide();
10145 this.toolTip.el.hide();
10147 window.onwheel = function(){ return true;};
10149 if(this.intervalID){
10150 window.clearInterval(this.intervalID);
10151 this.intervalID = false;
10154 this.isMasked = false;
10164 * Ext JS Library 1.1.1
10165 * Copyright(c) 2006-2007, Ext JS, LLC.
10167 * Originally Released Under LGPL - original licence link has changed is not relivant.
10170 * <script type="text/javascript">
10173 * @class Roo.form.VTypes
10174 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
10177 Roo.form.VTypes = function(){
10178 // closure these in so they are only created once.
10179 var alpha = /^[a-zA-Z_]+$/;
10180 var alphanum = /^[a-zA-Z0-9_]+$/;
10181 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
10182 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
10184 // All these messages and functions are configurable
10187 * The function used to validate email addresses
10188 * @param {String} value The email address
10190 'email' : function(v){
10191 return email.test(v);
10194 * The error text to display when the email validation function returns false
10197 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
10199 * The keystroke filter mask to be applied on email input
10202 'emailMask' : /[a-z0-9_\.\-@]/i,
10205 * The function used to validate URLs
10206 * @param {String} value The URL
10208 'url' : function(v){
10209 return url.test(v);
10212 * The error text to display when the url validation function returns false
10215 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
10218 * The function used to validate alpha values
10219 * @param {String} value The value
10221 'alpha' : function(v){
10222 return alpha.test(v);
10225 * The error text to display when the alpha validation function returns false
10228 'alphaText' : 'This field should only contain letters and _',
10230 * The keystroke filter mask to be applied on alpha input
10233 'alphaMask' : /[a-z_]/i,
10236 * The function used to validate alphanumeric values
10237 * @param {String} value The value
10239 'alphanum' : function(v){
10240 return alphanum.test(v);
10243 * The error text to display when the alphanumeric validation function returns false
10246 'alphanumText' : 'This field should only contain letters, numbers and _',
10248 * The keystroke filter mask to be applied on alphanumeric input
10251 'alphanumMask' : /[a-z0-9_]/i
10261 * @class Roo.bootstrap.Input
10262 * @extends Roo.bootstrap.Component
10263 * Bootstrap Input class
10264 * @cfg {Boolean} disabled is it disabled
10265 * @cfg {String} (button|checkbox|email|file|hidden|image|number|password|radio|range|reset|search|submit|text) inputType
10266 * @cfg {String} name name of the input
10267 * @cfg {string} fieldLabel - the label associated
10268 * @cfg {string} placeholder - placeholder to put in text.
10269 * @cfg {string} before - input group add on before
10270 * @cfg {string} after - input group add on after
10271 * @cfg {string} size - (lg|sm) or leave empty..
10272 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
10273 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
10274 * @cfg {Number} md colspan out of 12 for computer-sized screens
10275 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
10276 * @cfg {string} value default value of the input
10277 * @cfg {Number} labelWidth set the width of label
10278 * @cfg {Number} labellg set the width of label (1-12)
10279 * @cfg {Number} labelmd set the width of label (1-12)
10280 * @cfg {Number} labelsm set the width of label (1-12)
10281 * @cfg {Number} labelxs set the width of label (1-12)
10282 * @cfg {String} labelAlign (top|left)
10283 * @cfg {Boolean} readOnly Specifies that the field should be read-only
10284 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
10285 * @cfg {String} indicatorpos (left|right) default left
10286 * @cfg {String} capture (user|camera) use for file input only. (default empty)
10287 * @cfg {String} accept (image|video|audio) use for file input only. (default empty)
10288 * @cfg {Boolean} preventMark Do not show tick or cross if error/success
10290 * @cfg {String} align (left|center|right) Default left
10291 * @cfg {Boolean} forceFeedback (true|false) Default false
10294 * Create a new Input
10295 * @param {Object} config The config object
10298 Roo.bootstrap.Input = function(config){
10300 Roo.bootstrap.Input.superclass.constructor.call(this, config);
10305 * Fires when this field receives input focus.
10306 * @param {Roo.form.Field} this
10311 * Fires when this field loses input focus.
10312 * @param {Roo.form.Field} this
10316 * @event specialkey
10317 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
10318 * {@link Roo.EventObject#getKey} to determine which key was pressed.
10319 * @param {Roo.form.Field} this
10320 * @param {Roo.EventObject} e The event object
10325 * Fires just before the field blurs if the field value has changed.
10326 * @param {Roo.form.Field} this
10327 * @param {Mixed} newValue The new value
10328 * @param {Mixed} oldValue The original value
10333 * Fires after the field has been marked as invalid.
10334 * @param {Roo.form.Field} this
10335 * @param {String} msg The validation message
10340 * Fires after the field has been validated with no errors.
10341 * @param {Roo.form.Field} this
10346 * Fires after the key up
10347 * @param {Roo.form.Field} this
10348 * @param {Roo.EventObject} e The event Object
10354 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
10356 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
10357 automatic validation (defaults to "keyup").
10359 validationEvent : "keyup",
10361 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
10363 validateOnBlur : true,
10365 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
10367 validationDelay : 250,
10369 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
10371 focusClass : "x-form-focus", // not needed???
10375 * @cfg {String} invalidClass DEPRICATED - code uses BS4 - is-valid / is-invalid
10377 invalidClass : "has-warning",
10380 * @cfg {String} validClass DEPRICATED - code uses BS4 - is-valid / is-invalid
10382 validClass : "has-success",
10385 * @cfg {Boolean} hasFeedback (true|false) default true
10387 hasFeedback : true,
10390 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
10392 invalidFeedbackClass : "glyphicon-warning-sign",
10395 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
10397 validFeedbackClass : "glyphicon-ok",
10400 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
10402 selectOnFocus : false,
10405 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
10409 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
10414 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
10416 disableKeyFilter : false,
10419 * @cfg {Boolean} disabled True to disable the field (defaults to false).
10423 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
10427 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
10429 blankText : "Please complete this mandatory field",
10432 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
10436 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
10438 maxLength : Number.MAX_VALUE,
10440 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
10442 minLengthText : "The minimum length for this field is {0}",
10444 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
10446 maxLengthText : "The maximum length for this field is {0}",
10450 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
10451 * If available, this function will be called only after the basic validators all return true, and will be passed the
10452 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
10456 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
10457 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
10458 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
10462 * @cfg {String} regexText -- Depricated - use Invalid Text
10467 * @cfg {String} invalidText The error text to display if {@link #validator} test fails during validation (defaults to "")
10473 autocomplete: false,
10477 inputType : 'text',
10480 placeholder: false,
10485 preventMark: false,
10486 isFormField : true,
10489 labelAlign : false,
10492 formatedValue : false,
10493 forceFeedback : false,
10495 indicatorpos : 'left',
10505 parentLabelAlign : function()
10508 while (parent.parent()) {
10509 parent = parent.parent();
10510 if (typeof(parent.labelAlign) !='undefined') {
10511 return parent.labelAlign;
10518 getAutoCreate : function()
10520 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
10526 if(this.inputType != 'hidden'){
10527 cfg.cls = 'form-group' //input-group
10533 type : this.inputType,
10534 value : this.value,
10535 cls : 'form-control',
10536 placeholder : this.placeholder || '',
10537 autocomplete : this.autocomplete || 'new-password'
10539 if (this.inputType == 'file') {
10540 input.style = 'overflow:hidden'; // why not in CSS?
10543 if(this.capture.length){
10544 input.capture = this.capture;
10547 if(this.accept.length){
10548 input.accept = this.accept + "/*";
10552 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
10555 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
10556 input.maxLength = this.maxLength;
10559 if (this.disabled) {
10560 input.disabled=true;
10563 if (this.readOnly) {
10564 input.readonly=true;
10568 input.name = this.name;
10572 input.cls += ' input-' + this.size;
10576 ['xs','sm','md','lg'].map(function(size){
10577 if (settings[size]) {
10578 cfg.cls += ' col-' + size + '-' + settings[size];
10582 var inputblock = input;
10586 cls: 'glyphicon form-control-feedback'
10589 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10592 cls : 'has-feedback',
10600 if (this.before || this.after) {
10603 cls : 'input-group',
10607 if (this.before && typeof(this.before) == 'string') {
10609 inputblock.cn.push({
10611 cls : 'roo-input-before input-group-addon input-group-prepend input-group-text',
10615 if (this.before && typeof(this.before) == 'object') {
10616 this.before = Roo.factory(this.before);
10618 inputblock.cn.push({
10620 cls : 'roo-input-before input-group-prepend input-group-' +
10621 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
10625 inputblock.cn.push(input);
10627 if (this.after && typeof(this.after) == 'string') {
10628 inputblock.cn.push({
10630 cls : 'roo-input-after input-group-append input-group-text input-group-addon',
10634 if (this.after && typeof(this.after) == 'object') {
10635 this.after = Roo.factory(this.after);
10637 inputblock.cn.push({
10639 cls : 'roo-input-after input-group-append input-group-' +
10640 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
10644 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10645 inputblock.cls += ' has-feedback';
10646 inputblock.cn.push(feedback);
10651 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
10652 tooltip : 'This field is required'
10654 if (this.allowBlank ) {
10655 indicator.style = this.allowBlank ? ' display:none' : '';
10657 if (align ==='left' && this.fieldLabel.length) {
10659 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
10666 cls : 'control-label col-form-label',
10667 html : this.fieldLabel
10678 var labelCfg = cfg.cn[1];
10679 var contentCfg = cfg.cn[2];
10681 if(this.indicatorpos == 'right'){
10686 cls : 'control-label col-form-label',
10690 html : this.fieldLabel
10704 labelCfg = cfg.cn[0];
10705 contentCfg = cfg.cn[1];
10709 if(this.labelWidth > 12){
10710 labelCfg.style = "width: " + this.labelWidth + 'px';
10713 if(this.labelWidth < 13 && this.labelmd == 0){
10714 this.labelmd = this.labelWidth;
10717 if(this.labellg > 0){
10718 labelCfg.cls += ' col-lg-' + this.labellg;
10719 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
10722 if(this.labelmd > 0){
10723 labelCfg.cls += ' col-md-' + this.labelmd;
10724 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
10727 if(this.labelsm > 0){
10728 labelCfg.cls += ' col-sm-' + this.labelsm;
10729 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
10732 if(this.labelxs > 0){
10733 labelCfg.cls += ' col-xs-' + this.labelxs;
10734 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
10738 } else if ( this.fieldLabel.length) {
10745 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10746 tooltip : 'This field is required',
10747 style : this.allowBlank ? ' display:none' : ''
10751 //cls : 'input-group-addon',
10752 html : this.fieldLabel
10760 if(this.indicatorpos == 'right'){
10765 //cls : 'input-group-addon',
10766 html : this.fieldLabel
10771 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10772 tooltip : 'This field is required',
10773 style : this.allowBlank ? ' display:none' : ''
10793 if (this.parentType === 'Navbar' && this.parent().bar) {
10794 cfg.cls += ' navbar-form';
10797 if (this.parentType === 'NavGroup' && !(Roo.bootstrap.version == 4 && this.parent().form)) {
10798 // on BS4 we do this only if not form
10799 cfg.cls += ' navbar-form';
10807 * return the real input element.
10809 inputEl: function ()
10811 return this.el.select('input.form-control',true).first();
10814 tooltipEl : function()
10816 return this.inputEl();
10819 indicatorEl : function()
10821 if (Roo.bootstrap.version == 4) {
10822 return false; // not enabled in v4 yet.
10825 var indicator = this.el.select('i.roo-required-indicator',true).first();
10835 setDisabled : function(v)
10837 var i = this.inputEl().dom;
10839 i.removeAttribute('disabled');
10843 i.setAttribute('disabled','true');
10845 initEvents : function()
10848 this.inputEl().on("keydown" , this.fireKey, this);
10849 this.inputEl().on("focus", this.onFocus, this);
10850 this.inputEl().on("blur", this.onBlur, this);
10852 this.inputEl().relayEvent('keyup', this);
10854 this.indicator = this.indicatorEl();
10856 if(this.indicator){
10857 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible'); // changed from invisible??? -
10860 // reference to original value for reset
10861 this.originalValue = this.getValue();
10862 //Roo.form.TextField.superclass.initEvents.call(this);
10863 if(this.validationEvent == 'keyup'){
10864 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
10865 this.inputEl().on('keyup', this.filterValidation, this);
10867 else if(this.validationEvent !== false){
10868 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
10871 if(this.selectOnFocus){
10872 this.on("focus", this.preFocus, this);
10875 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
10876 this.inputEl().on("keypress", this.filterKeys, this);
10878 this.inputEl().relayEvent('keypress', this);
10881 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
10882 this.el.on("click", this.autoSize, this);
10885 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
10886 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
10889 if (typeof(this.before) == 'object') {
10890 this.before.render(this.el.select('.roo-input-before',true).first());
10892 if (typeof(this.after) == 'object') {
10893 this.after.render(this.el.select('.roo-input-after',true).first());
10896 this.inputEl().on('change', this.onChange, this);
10899 filterValidation : function(e){
10900 if(!e.isNavKeyPress()){
10901 this.validationTask.delay(this.validationDelay);
10905 * Validates the field value
10906 * @return {Boolean} True if the value is valid, else false
10908 validate : function(){
10909 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
10910 if(this.disabled || this.validateValue(this.getRawValue())){
10915 this.markInvalid();
10921 * Validates a value according to the field's validation rules and marks the field as invalid
10922 * if the validation fails
10923 * @param {Mixed} value The value to validate
10924 * @return {Boolean} True if the value is valid, else false
10926 validateValue : function(value)
10928 if(this.getVisibilityEl().hasClass('hidden')){
10932 if(value.length < 1) { // if it's blank
10933 if(this.allowBlank){
10939 if(value.length < this.minLength){
10942 if(value.length > this.maxLength){
10946 var vt = Roo.form.VTypes;
10947 if(!vt[this.vtype](value, this)){
10951 if(typeof this.validator == "function"){
10952 var msg = this.validator(value);
10956 if (typeof(msg) == 'string') {
10957 this.invalidText = msg;
10961 if(this.regex && !this.regex.test(value)){
10969 fireKey : function(e){
10970 //Roo.log('field ' + e.getKey());
10971 if(e.isNavKeyPress()){
10972 this.fireEvent("specialkey", this, e);
10975 focus : function (selectText){
10977 this.inputEl().focus();
10978 if(selectText === true){
10979 this.inputEl().dom.select();
10985 onFocus : function(){
10986 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
10987 // this.el.addClass(this.focusClass);
10989 if(!this.hasFocus){
10990 this.hasFocus = true;
10991 this.startValue = this.getValue();
10992 this.fireEvent("focus", this);
10996 beforeBlur : Roo.emptyFn,
11000 onBlur : function(){
11002 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
11003 //this.el.removeClass(this.focusClass);
11005 this.hasFocus = false;
11006 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
11009 var v = this.getValue();
11010 if(String(v) !== String(this.startValue)){
11011 this.fireEvent('change', this, v, this.startValue);
11013 this.fireEvent("blur", this);
11016 onChange : function(e)
11018 var v = this.getValue();
11019 if(String(v) !== String(this.startValue)){
11020 this.fireEvent('change', this, v, this.startValue);
11026 * Resets the current field value to the originally loaded value and clears any validation messages
11028 reset : function(){
11029 this.setValue(this.originalValue);
11033 * Returns the name of the field
11034 * @return {Mixed} name The name field
11036 getName: function(){
11040 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
11041 * @return {Mixed} value The field value
11043 getValue : function(){
11045 var v = this.inputEl().getValue();
11050 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
11051 * @return {Mixed} value The field value
11053 getRawValue : function(){
11054 var v = this.inputEl().getValue();
11060 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
11061 * @param {Mixed} value The value to set
11063 setRawValue : function(v){
11064 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
11067 selectText : function(start, end){
11068 var v = this.getRawValue();
11070 start = start === undefined ? 0 : start;
11071 end = end === undefined ? v.length : end;
11072 var d = this.inputEl().dom;
11073 if(d.setSelectionRange){
11074 d.setSelectionRange(start, end);
11075 }else if(d.createTextRange){
11076 var range = d.createTextRange();
11077 range.moveStart("character", start);
11078 range.moveEnd("character", v.length-end);
11085 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
11086 * @param {Mixed} value The value to set
11088 setValue : function(v){
11091 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
11097 processValue : function(value){
11098 if(this.stripCharsRe){
11099 var newValue = value.replace(this.stripCharsRe, '');
11100 if(newValue !== value){
11101 this.setRawValue(newValue);
11108 preFocus : function(){
11110 if(this.selectOnFocus){
11111 this.inputEl().dom.select();
11114 filterKeys : function(e){
11115 var k = e.getKey();
11116 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
11119 var c = e.getCharCode(), cc = String.fromCharCode(c);
11120 if(Roo.isIE && (e.isSpecialKey() || !cc)){
11123 if(!this.maskRe.test(cc)){
11128 * Clear any invalid styles/messages for this field
11130 clearInvalid : function(){
11132 if(!this.el || this.preventMark){ // not rendered
11137 this.el.removeClass([this.invalidClass, 'is-invalid']);
11139 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
11141 var feedback = this.el.select('.form-control-feedback', true).first();
11144 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
11149 if(this.indicator){
11150 this.indicator.removeClass('visible');
11151 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
11154 this.fireEvent('valid', this);
11158 * Mark this field as valid
11160 markValid : function()
11162 if(!this.el || this.preventMark){ // not rendered...
11166 this.el.removeClass([this.invalidClass, this.validClass]);
11167 this.inputEl().removeClass(['is-valid', 'is-invalid']);
11169 var feedback = this.el.select('.form-control-feedback', true).first();
11172 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
11175 if(this.indicator){
11176 this.indicator.removeClass('visible');
11177 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
11185 if(this.allowBlank && !this.getRawValue().length){
11188 if (Roo.bootstrap.version == 3) {
11189 this.el.addClass(this.validClass);
11191 this.inputEl().addClass('is-valid');
11194 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
11196 var feedback = this.el.select('.form-control-feedback', true).first();
11199 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
11200 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
11205 this.fireEvent('valid', this);
11209 * Mark this field as invalid
11210 * @param {String} msg The validation message
11212 markInvalid : function(msg)
11214 if(!this.el || this.preventMark){ // not rendered
11218 this.el.removeClass([this.invalidClass, this.validClass]);
11219 this.inputEl().removeClass(['is-valid', 'is-invalid']);
11221 var feedback = this.el.select('.form-control-feedback', true).first();
11224 this.el.select('.form-control-feedback', true).first().removeClass(
11225 [this.invalidFeedbackClass, this.validFeedbackClass]);
11232 if(this.allowBlank && !this.getRawValue().length){
11236 if(this.indicator){
11237 this.indicator.removeClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
11238 this.indicator.addClass('visible');
11240 if (Roo.bootstrap.version == 3) {
11241 this.el.addClass(this.invalidClass);
11243 this.inputEl().addClass('is-invalid');
11248 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
11250 var feedback = this.el.select('.form-control-feedback', true).first();
11253 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
11255 if(this.getValue().length || this.forceFeedback){
11256 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
11263 this.fireEvent('invalid', this, msg);
11266 SafariOnKeyDown : function(event)
11268 // this is a workaround for a password hang bug on chrome/ webkit.
11269 if (this.inputEl().dom.type != 'password') {
11273 var isSelectAll = false;
11275 if(this.inputEl().dom.selectionEnd > 0){
11276 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
11278 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
11279 event.preventDefault();
11284 if(isSelectAll && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
11286 event.preventDefault();
11287 // this is very hacky as keydown always get's upper case.
11289 var cc = String.fromCharCode(event.getCharCode());
11290 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
11294 adjustWidth : function(tag, w){
11295 tag = tag.toLowerCase();
11296 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
11297 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
11298 if(tag == 'input'){
11301 if(tag == 'textarea'){
11304 }else if(Roo.isOpera){
11305 if(tag == 'input'){
11308 if(tag == 'textarea'){
11316 setFieldLabel : function(v)
11318 if(!this.rendered){
11322 if(this.indicatorEl()){
11323 var ar = this.el.select('label > span',true);
11325 if (ar.elements.length) {
11326 this.el.select('label > span',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
11327 this.fieldLabel = v;
11331 var br = this.el.select('label',true);
11333 if(br.elements.length) {
11334 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
11335 this.fieldLabel = v;
11339 Roo.log('Cannot Found any of label > span || label in input');
11343 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
11344 this.fieldLabel = v;
11359 * @class Roo.bootstrap.TextArea
11360 * @extends Roo.bootstrap.Input
11361 * Bootstrap TextArea class
11362 * @cfg {Number} cols Specifies the visible width of a text area
11363 * @cfg {Number} rows Specifies the visible number of lines in a text area
11364 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
11365 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
11366 * @cfg {string} html text
11369 * Create a new TextArea
11370 * @param {Object} config The config object
11373 Roo.bootstrap.TextArea = function(config){
11374 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
11378 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
11388 getAutoCreate : function(){
11390 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
11396 if(this.inputType != 'hidden'){
11397 cfg.cls = 'form-group' //input-group
11405 value : this.value || '',
11406 html: this.html || '',
11407 cls : 'form-control',
11408 placeholder : this.placeholder || ''
11412 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
11413 input.maxLength = this.maxLength;
11417 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
11421 input.cols = this.cols;
11424 if (this.readOnly) {
11425 input.readonly = true;
11429 input.name = this.name;
11433 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
11437 ['xs','sm','md','lg'].map(function(size){
11438 if (settings[size]) {
11439 cfg.cls += ' col-' + size + '-' + settings[size];
11443 var inputblock = input;
11445 if(this.hasFeedback && !this.allowBlank){
11449 cls: 'glyphicon form-control-feedback'
11453 cls : 'has-feedback',
11462 if (this.before || this.after) {
11465 cls : 'input-group',
11469 inputblock.cn.push({
11471 cls : 'input-group-addon',
11476 inputblock.cn.push(input);
11478 if(this.hasFeedback && !this.allowBlank){
11479 inputblock.cls += ' has-feedback';
11480 inputblock.cn.push(feedback);
11484 inputblock.cn.push({
11486 cls : 'input-group-addon',
11493 if (align ==='left' && this.fieldLabel.length) {
11498 cls : 'control-label',
11499 html : this.fieldLabel
11510 if(this.labelWidth > 12){
11511 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
11514 if(this.labelWidth < 13 && this.labelmd == 0){
11515 this.labelmd = this.labelWidth;
11518 if(this.labellg > 0){
11519 cfg.cn[0].cls += ' col-lg-' + this.labellg;
11520 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
11523 if(this.labelmd > 0){
11524 cfg.cn[0].cls += ' col-md-' + this.labelmd;
11525 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
11528 if(this.labelsm > 0){
11529 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
11530 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
11533 if(this.labelxs > 0){
11534 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
11535 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
11538 } else if ( this.fieldLabel.length) {
11543 //cls : 'input-group-addon',
11544 html : this.fieldLabel
11562 if (this.disabled) {
11563 input.disabled=true;
11570 * return the real textarea element.
11572 inputEl: function ()
11574 return this.el.select('textarea.form-control',true).first();
11578 * Clear any invalid styles/messages for this field
11580 clearInvalid : function()
11583 if(!this.el || this.preventMark){ // not rendered
11587 var label = this.el.select('label', true).first();
11588 var icon = this.el.select('i.fa-star', true).first();
11593 this.el.removeClass( this.validClass);
11594 this.inputEl().removeClass('is-invalid');
11596 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
11598 var feedback = this.el.select('.form-control-feedback', true).first();
11601 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
11606 this.fireEvent('valid', this);
11610 * Mark this field as valid
11612 markValid : function()
11614 if(!this.el || this.preventMark){ // not rendered
11618 this.el.removeClass([this.invalidClass, this.validClass]);
11619 this.inputEl().removeClass(['is-valid', 'is-invalid']);
11621 var feedback = this.el.select('.form-control-feedback', true).first();
11624 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
11627 if(this.disabled || this.allowBlank){
11631 var label = this.el.select('label', true).first();
11632 var icon = this.el.select('i.fa-star', true).first();
11637 if (Roo.bootstrap.version == 3) {
11638 this.el.addClass(this.validClass);
11640 this.inputEl().addClass('is-valid');
11644 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
11646 var feedback = this.el.select('.form-control-feedback', true).first();
11649 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
11650 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
11655 this.fireEvent('valid', this);
11659 * Mark this field as invalid
11660 * @param {String} msg The validation message
11662 markInvalid : function(msg)
11664 if(!this.el || this.preventMark){ // not rendered
11668 this.el.removeClass([this.invalidClass, this.validClass]);
11669 this.inputEl().removeClass(['is-valid', 'is-invalid']);
11671 var feedback = this.el.select('.form-control-feedback', true).first();
11674 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
11677 if(this.disabled || this.allowBlank){
11681 var label = this.el.select('label', true).first();
11682 var icon = this.el.select('i.fa-star', true).first();
11684 if(!this.getValue().length && label && !icon){
11685 this.el.createChild({
11687 cls : 'text-danger fa fa-lg fa-star',
11688 tooltip : 'This field is required',
11689 style : 'margin-right:5px;'
11693 if (Roo.bootstrap.version == 3) {
11694 this.el.addClass(this.invalidClass);
11696 this.inputEl().addClass('is-invalid');
11699 // fixme ... this may be depricated need to test..
11700 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
11702 var feedback = this.el.select('.form-control-feedback', true).first();
11705 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
11707 if(this.getValue().length || this.forceFeedback){
11708 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
11715 this.fireEvent('invalid', this, msg);
11723 * trigger field - base class for combo..
11728 * @class Roo.bootstrap.TriggerField
11729 * @extends Roo.bootstrap.Input
11730 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
11731 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
11732 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
11733 * for which you can provide a custom implementation. For example:
11735 var trigger = new Roo.bootstrap.TriggerField();
11736 trigger.onTriggerClick = myTriggerFn;
11737 trigger.applyTo('my-field');
11740 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
11741 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
11742 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
11743 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
11744 * @cfg {String} caret (search|calendar) BS3 only - carat fa name
11747 * Create a new TriggerField.
11748 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
11749 * to the base TextField)
11751 Roo.bootstrap.TriggerField = function(config){
11752 this.mimicing = false;
11753 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
11756 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
11758 * @cfg {String} triggerClass A CSS class to apply to the trigger
11761 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
11766 * @cfg {Boolean} removable (true|false) special filter default false
11770 /** @cfg {Boolean} grow @hide */
11771 /** @cfg {Number} growMin @hide */
11772 /** @cfg {Number} growMax @hide */
11778 autoSize: Roo.emptyFn,
11782 deferHeight : true,
11785 actionMode : 'wrap',
11790 getAutoCreate : function(){
11792 var align = this.labelAlign || this.parentLabelAlign();
11797 cls: 'form-group' //input-group
11804 type : this.inputType,
11805 cls : 'form-control',
11806 autocomplete: 'new-password',
11807 placeholder : this.placeholder || ''
11811 input.name = this.name;
11814 input.cls += ' input-' + this.size;
11817 if (this.disabled) {
11818 input.disabled=true;
11821 var inputblock = input;
11823 if(this.hasFeedback && !this.allowBlank){
11827 cls: 'glyphicon form-control-feedback'
11830 if(this.removable && !this.editable ){
11832 cls : 'has-feedback',
11838 cls : 'roo-combo-removable-btn close'
11845 cls : 'has-feedback',
11854 if(this.removable && !this.editable ){
11856 cls : 'roo-removable',
11862 cls : 'roo-combo-removable-btn close'
11869 if (this.before || this.after) {
11872 cls : 'input-group',
11876 inputblock.cn.push({
11878 cls : 'input-group-addon input-group-prepend input-group-text',
11883 inputblock.cn.push(input);
11885 if(this.hasFeedback && !this.allowBlank){
11886 inputblock.cls += ' has-feedback';
11887 inputblock.cn.push(feedback);
11891 inputblock.cn.push({
11893 cls : 'input-group-addon input-group-append input-group-text',
11902 var ibwrap = inputblock;
11907 cls: 'roo-select2-choices',
11911 cls: 'roo-select2-search-field',
11923 cls: 'roo-select2-container input-group',
11928 cls: 'form-hidden-field'
11934 if(!this.multiple && this.showToggleBtn){
11940 if (this.caret != false) {
11943 cls: 'fa fa-' + this.caret
11950 cls : 'input-group-addon input-group-append input-group-text btn dropdown-toggle',
11952 Roo.bootstrap.version == 3 ? caret : '',
11955 cls: 'combobox-clear',
11969 combobox.cls += ' roo-select2-container-multi';
11973 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
11974 tooltip : 'This field is required'
11976 if (Roo.bootstrap.version == 4) {
11979 style : 'display:none'
11984 if (align ==='left' && this.fieldLabel.length) {
11986 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
11993 cls : 'control-label',
11994 html : this.fieldLabel
12006 var labelCfg = cfg.cn[1];
12007 var contentCfg = cfg.cn[2];
12009 if(this.indicatorpos == 'right'){
12014 cls : 'control-label',
12018 html : this.fieldLabel
12032 labelCfg = cfg.cn[0];
12033 contentCfg = cfg.cn[1];
12036 if(this.labelWidth > 12){
12037 labelCfg.style = "width: " + this.labelWidth + 'px';
12040 if(this.labelWidth < 13 && this.labelmd == 0){
12041 this.labelmd = this.labelWidth;
12044 if(this.labellg > 0){
12045 labelCfg.cls += ' col-lg-' + this.labellg;
12046 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
12049 if(this.labelmd > 0){
12050 labelCfg.cls += ' col-md-' + this.labelmd;
12051 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
12054 if(this.labelsm > 0){
12055 labelCfg.cls += ' col-sm-' + this.labelsm;
12056 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
12059 if(this.labelxs > 0){
12060 labelCfg.cls += ' col-xs-' + this.labelxs;
12061 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
12064 } else if ( this.fieldLabel.length) {
12065 // Roo.log(" label");
12070 //cls : 'input-group-addon',
12071 html : this.fieldLabel
12079 if(this.indicatorpos == 'right'){
12087 html : this.fieldLabel
12101 // Roo.log(" no label && no align");
12108 ['xs','sm','md','lg'].map(function(size){
12109 if (settings[size]) {
12110 cfg.cls += ' col-' + size + '-' + settings[size];
12121 onResize : function(w, h){
12122 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
12123 // if(typeof w == 'number'){
12124 // var x = w - this.trigger.getWidth();
12125 // this.inputEl().setWidth(this.adjustWidth('input', x));
12126 // this.trigger.setStyle('left', x+'px');
12131 adjustSize : Roo.BoxComponent.prototype.adjustSize,
12134 getResizeEl : function(){
12135 return this.inputEl();
12139 getPositionEl : function(){
12140 return this.inputEl();
12144 alignErrorIcon : function(){
12145 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
12149 initEvents : function(){
12153 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
12154 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
12155 if(!this.multiple && this.showToggleBtn){
12156 this.trigger = this.el.select('span.dropdown-toggle',true).first();
12157 if(this.hideTrigger){
12158 this.trigger.setDisplayed(false);
12160 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
12164 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
12167 if(this.removable && !this.editable && !this.tickable){
12168 var close = this.closeTriggerEl();
12171 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
12172 close.on('click', this.removeBtnClick, this, close);
12176 //this.trigger.addClassOnOver('x-form-trigger-over');
12177 //this.trigger.addClassOnClick('x-form-trigger-click');
12180 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
12184 closeTriggerEl : function()
12186 var close = this.el.select('.roo-combo-removable-btn', true).first();
12187 return close ? close : false;
12190 removeBtnClick : function(e, h, el)
12192 e.preventDefault();
12194 if(this.fireEvent("remove", this) !== false){
12196 this.fireEvent("afterremove", this)
12200 createList : function()
12202 this.list = Roo.get(document.body).createChild({
12203 tag: Roo.bootstrap.version == 4 ? 'div' : 'ul',
12204 cls: 'typeahead typeahead-long dropdown-menu',
12205 style: 'display:none'
12208 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
12213 initTrigger : function(){
12218 onDestroy : function(){
12220 this.trigger.removeAllListeners();
12221 // this.trigger.remove();
12224 // this.wrap.remove();
12226 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
12230 onFocus : function(){
12231 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
12233 if(!this.mimicing){
12234 this.wrap.addClass('x-trigger-wrap-focus');
12235 this.mimicing = true;
12236 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
12237 if(this.monitorTab){
12238 this.el.on("keydown", this.checkTab, this);
12245 checkTab : function(e){
12246 if(e.getKey() == e.TAB){
12247 this.triggerBlur();
12252 onBlur : function(){
12257 mimicBlur : function(e, t){
12259 if(!this.wrap.contains(t) && this.validateBlur()){
12260 this.triggerBlur();
12266 triggerBlur : function(){
12267 this.mimicing = false;
12268 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
12269 if(this.monitorTab){
12270 this.el.un("keydown", this.checkTab, this);
12272 //this.wrap.removeClass('x-trigger-wrap-focus');
12273 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
12277 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
12278 validateBlur : function(e, t){
12283 onDisable : function(){
12284 this.inputEl().dom.disabled = true;
12285 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
12287 // this.wrap.addClass('x-item-disabled');
12292 onEnable : function(){
12293 this.inputEl().dom.disabled = false;
12294 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
12296 // this.el.removeClass('x-item-disabled');
12301 onShow : function(){
12302 var ae = this.getActionEl();
12305 ae.dom.style.display = '';
12306 ae.dom.style.visibility = 'visible';
12312 onHide : function(){
12313 var ae = this.getActionEl();
12314 ae.dom.style.display = 'none';
12318 * The function that should handle the trigger's click event. This method does nothing by default until overridden
12319 * by an implementing function.
12321 * @param {EventObject} e
12323 onTriggerClick : Roo.emptyFn
12331 * @class Roo.bootstrap.CardUploader
12332 * @extends Roo.bootstrap.Button
12333 * Bootstrap Card Uploader class - it's a button which when you add files to it, adds cards below with preview and the name...
12334 * @cfg {Number} errorTimeout default 3000
12335 * @cfg {Array} images an array of ?? Img objects ??? when loading existing files..
12336 * @cfg {Array} html The button text.
12340 * Create a new CardUploader
12341 * @param {Object} config The config object
12344 Roo.bootstrap.CardUploader = function(config){
12348 Roo.bootstrap.CardUploader.superclass.constructor.call(this, config);
12351 this.fileCollection = new Roo.util.MixedCollection(false,function(r) {
12358 Roo.extend(Roo.bootstrap.CardUploader, Roo.bootstrap.Input, {
12361 errorTimeout : 3000,
12365 fileCollection : false,
12368 getAutoCreate : function()
12372 cls :'form-group' ,
12377 //cls : 'input-group-addon',
12378 html : this.fieldLabel
12385 value : this.value,
12386 cls : 'd-none form-control'
12391 multiple : 'multiple',
12393 cls : 'd-none roo-card-upload-selector'
12397 cls : 'roo-card-uploader-button-container w-100 mb-2'
12400 cls : 'card-columns roo-card-uploader-container'
12410 getChildContainer : function() /// what children are added to.
12412 return this.containerEl;
12415 getButtonContainer : function() /// what children are added to.
12417 return this.el.select(".roo-card-uploader-button-container").first();
12420 initEvents : function()
12423 Roo.bootstrap.Input.prototype.initEvents.call(this);
12427 xns: Roo.bootstrap,
12430 container_method : 'getButtonContainer' ,
12431 html : this.html, // fix changable?
12434 'click' : function(btn, e) {
12443 this.urlAPI = (window.createObjectURL && window) ||
12444 (window.URL && URL.revokeObjectURL && URL) ||
12445 (window.webkitURL && webkitURL);
12450 this.selectorEl = this.el.select('.roo-card-upload-selector', true).first();
12452 this.selectorEl.on('change', this.onFileSelected, this);
12455 this.images.forEach(function(img) {
12458 this.images = false;
12460 this.containerEl = this.el.select('.roo-card-uploader-container', true).first();
12466 onClick : function(e)
12468 e.preventDefault();
12470 this.selectorEl.dom.click();
12474 onFileSelected : function(e)
12476 e.preventDefault();
12478 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
12482 Roo.each(this.selectorEl.dom.files, function(file){
12483 this.addFile(file);
12492 addFile : function(file)
12495 if(typeof(file) === 'string'){
12496 throw "Add file by name?"; // should not happen
12500 if(!file || !this.urlAPI){
12510 var url = _this.urlAPI.createObjectURL( file);
12513 id : Roo.bootstrap.CardUploader.ID--,
12514 is_uploaded : false,
12517 mimetype : file.type,
12524 addCard : function (data)
12526 // hidden input element?
12527 // if the file is not an image...
12528 //then we need to use something other that and header_image
12533 xns : Roo.bootstrap,
12534 xtype : 'CardFooter',
12537 xns : Roo.bootstrap,
12543 xns : Roo.bootstrap,
12545 html : String.format("<small>{0}</small>", data.title),
12546 cls : 'col-11 text-left',
12551 click : function() {
12552 this.downloadCard(data.id)
12558 xns : Roo.bootstrap,
12566 click : function() {
12567 t.removeCard(data.id)
12579 var cn = this.addxtype(
12582 xns : Roo.bootstrap,
12585 header : !data.mimetype.match(/image/) && !data.preview ? "Document": false,
12586 header_image : data.mimetype.match(/image/) ? data.src : data.preview,
12587 header_image_fit_square: true, // fixme - we probably need to use the 'Img' element to do stuff like this.
12592 initEvents : function() {
12593 Roo.bootstrap.Card.prototype.initEvents.call(this);
12594 this.imgEl = this.el.select('.card-img-top').first();
12596 this.imgEl.on('click', function() { t.previewCard( data.id); }, this);
12597 this.imgEl.set({ 'pointer' : 'cursor' });
12606 // dont' really need ot update items.
12607 // this.items.push(cn);
12608 this.fileCollection.add(cn);
12609 this.updateInput();
12612 removeCard : function(id)
12615 var card = this.fileCollection.get(id);
12616 card.data.is_deleted = 1;
12617 card.data.src = ''; /// delete the source - so it reduces size of not uploaded images etc.
12618 this.fileCollection.remove(card);
12619 //this.items = this.items.filter(function(e) { return e != card });
12620 // dont' really need ot update items.
12621 card.el.dom.parentNode.removeChild(card.el.dom);
12626 this.fileCollection.each(function(card) {
12627 card.el.dom.parentNode.removeChild(card.el.dom);
12629 this.fileCollection.clear();
12630 this.updateInput();
12633 updateInput : function()
12636 this.fileCollection.each(function(e) {
12640 this.inputEl().dom.value = JSON.stringify(data);
12647 Roo.bootstrap.CardUploader.ID = -1;/*
12649 * Ext JS Library 1.1.1
12650 * Copyright(c) 2006-2007, Ext JS, LLC.
12652 * Originally Released Under LGPL - original licence link has changed is not relivant.
12655 * <script type="text/javascript">
12660 * @class Roo.data.SortTypes
12662 * Defines the default sorting (casting?) comparison functions used when sorting data.
12664 Roo.data.SortTypes = {
12666 * Default sort that does nothing
12667 * @param {Mixed} s The value being converted
12668 * @return {Mixed} The comparison value
12670 none : function(s){
12675 * The regular expression used to strip tags
12679 stripTagsRE : /<\/?[^>]+>/gi,
12682 * Strips all HTML tags to sort on text only
12683 * @param {Mixed} s The value being converted
12684 * @return {String} The comparison value
12686 asText : function(s){
12687 return String(s).replace(this.stripTagsRE, "");
12691 * Strips all HTML tags to sort on text only - Case insensitive
12692 * @param {Mixed} s The value being converted
12693 * @return {String} The comparison value
12695 asUCText : function(s){
12696 return String(s).toUpperCase().replace(this.stripTagsRE, "");
12700 * Case insensitive string
12701 * @param {Mixed} s The value being converted
12702 * @return {String} The comparison value
12704 asUCString : function(s) {
12705 return String(s).toUpperCase();
12710 * @param {Mixed} s The value being converted
12711 * @return {Number} The comparison value
12713 asDate : function(s) {
12717 if(s instanceof Date){
12718 return s.getTime();
12720 return Date.parse(String(s));
12725 * @param {Mixed} s The value being converted
12726 * @return {Float} The comparison value
12728 asFloat : function(s) {
12729 var val = parseFloat(String(s).replace(/,/g, ""));
12738 * @param {Mixed} s The value being converted
12739 * @return {Number} The comparison value
12741 asInt : function(s) {
12742 var val = parseInt(String(s).replace(/,/g, ""));
12750 * Ext JS Library 1.1.1
12751 * Copyright(c) 2006-2007, Ext JS, LLC.
12753 * Originally Released Under LGPL - original licence link has changed is not relivant.
12756 * <script type="text/javascript">
12760 * @class Roo.data.Record
12761 * Instances of this class encapsulate both record <em>definition</em> information, and record
12762 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
12763 * to access Records cached in an {@link Roo.data.Store} object.<br>
12765 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
12766 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
12769 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
12771 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
12772 * {@link #create}. The parameters are the same.
12773 * @param {Array} data An associative Array of data values keyed by the field name.
12774 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
12775 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
12776 * not specified an integer id is generated.
12778 Roo.data.Record = function(data, id){
12779 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
12784 * Generate a constructor for a specific record layout.
12785 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
12786 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
12787 * Each field definition object may contain the following properties: <ul>
12788 * <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,
12789 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
12790 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
12791 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
12792 * is being used, then this is a string containing the javascript expression to reference the data relative to
12793 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
12794 * to the data item relative to the record element. If the mapping expression is the same as the field name,
12795 * this may be omitted.</p></li>
12796 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
12797 * <ul><li>auto (Default, implies no conversion)</li>
12802 * <li>date</li></ul></p></li>
12803 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
12804 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
12805 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
12806 * by the Reader into an object that will be stored in the Record. It is passed the
12807 * following parameters:<ul>
12808 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
12810 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
12812 * <br>usage:<br><pre><code>
12813 var TopicRecord = Roo.data.Record.create(
12814 {name: 'title', mapping: 'topic_title'},
12815 {name: 'author', mapping: 'username'},
12816 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
12817 {name: 'lastPost', mapping: 'post_time', type: 'date'},
12818 {name: 'lastPoster', mapping: 'user2'},
12819 {name: 'excerpt', mapping: 'post_text'}
12822 var myNewRecord = new TopicRecord({
12823 title: 'Do my job please',
12826 lastPost: new Date(),
12827 lastPoster: 'Animal',
12828 excerpt: 'No way dude!'
12830 myStore.add(myNewRecord);
12835 Roo.data.Record.create = function(o){
12836 var f = function(){
12837 f.superclass.constructor.apply(this, arguments);
12839 Roo.extend(f, Roo.data.Record);
12840 var p = f.prototype;
12841 p.fields = new Roo.util.MixedCollection(false, function(field){
12844 for(var i = 0, len = o.length; i < len; i++){
12845 p.fields.add(new Roo.data.Field(o[i]));
12847 f.getField = function(name){
12848 return p.fields.get(name);
12853 Roo.data.Record.AUTO_ID = 1000;
12854 Roo.data.Record.EDIT = 'edit';
12855 Roo.data.Record.REJECT = 'reject';
12856 Roo.data.Record.COMMIT = 'commit';
12858 Roo.data.Record.prototype = {
12860 * Readonly flag - true if this record has been modified.
12869 join : function(store){
12870 this.store = store;
12874 * Set the named field to the specified value.
12875 * @param {String} name The name of the field to set.
12876 * @param {Object} value The value to set the field to.
12878 set : function(name, value){
12879 if(this.data[name] == value){
12883 if(!this.modified){
12884 this.modified = {};
12886 if(typeof this.modified[name] == 'undefined'){
12887 this.modified[name] = this.data[name];
12889 this.data[name] = value;
12890 if(!this.editing && this.store){
12891 this.store.afterEdit(this);
12896 * Get the value of the named field.
12897 * @param {String} name The name of the field to get the value of.
12898 * @return {Object} The value of the field.
12900 get : function(name){
12901 return this.data[name];
12905 beginEdit : function(){
12906 this.editing = true;
12907 this.modified = {};
12911 cancelEdit : function(){
12912 this.editing = false;
12913 delete this.modified;
12917 endEdit : function(){
12918 this.editing = false;
12919 if(this.dirty && this.store){
12920 this.store.afterEdit(this);
12925 * Usually called by the {@link Roo.data.Store} which owns the Record.
12926 * Rejects all changes made to the Record since either creation, or the last commit operation.
12927 * Modified fields are reverted to their original values.
12929 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
12930 * of reject operations.
12932 reject : function(){
12933 var m = this.modified;
12935 if(typeof m[n] != "function"){
12936 this.data[n] = m[n];
12939 this.dirty = false;
12940 delete this.modified;
12941 this.editing = false;
12943 this.store.afterReject(this);
12948 * Usually called by the {@link Roo.data.Store} which owns the Record.
12949 * Commits all changes made to the Record since either creation, or the last commit operation.
12951 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
12952 * of commit operations.
12954 commit : function(){
12955 this.dirty = false;
12956 delete this.modified;
12957 this.editing = false;
12959 this.store.afterCommit(this);
12964 hasError : function(){
12965 return this.error != null;
12969 clearError : function(){
12974 * Creates a copy of this record.
12975 * @param {String} id (optional) A new record id if you don't want to use this record's id
12978 copy : function(newId) {
12979 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
12983 * Ext JS Library 1.1.1
12984 * Copyright(c) 2006-2007, Ext JS, LLC.
12986 * Originally Released Under LGPL - original licence link has changed is not relivant.
12989 * <script type="text/javascript">
12995 * @class Roo.data.Store
12996 * @extends Roo.util.Observable
12997 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
12998 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
13000 * 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
13001 * has no knowledge of the format of the data returned by the Proxy.<br>
13003 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
13004 * instances from the data object. These records are cached and made available through accessor functions.
13006 * Creates a new Store.
13007 * @param {Object} config A config object containing the objects needed for the Store to access data,
13008 * and read the data into Records.
13010 Roo.data.Store = function(config){
13011 this.data = new Roo.util.MixedCollection(false);
13012 this.data.getKey = function(o){
13015 this.baseParams = {};
13017 this.paramNames = {
13022 "multisort" : "_multisort"
13025 if(config && config.data){
13026 this.inlineData = config.data;
13027 delete config.data;
13030 Roo.apply(this, config);
13032 if(this.reader){ // reader passed
13033 this.reader = Roo.factory(this.reader, Roo.data);
13034 this.reader.xmodule = this.xmodule || false;
13035 if(!this.recordType){
13036 this.recordType = this.reader.recordType;
13038 if(this.reader.onMetaChange){
13039 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
13043 if(this.recordType){
13044 this.fields = this.recordType.prototype.fields;
13046 this.modified = [];
13050 * @event datachanged
13051 * Fires when the data cache has changed, and a widget which is using this Store
13052 * as a Record cache should refresh its view.
13053 * @param {Store} this
13055 datachanged : true,
13057 * @event metachange
13058 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
13059 * @param {Store} this
13060 * @param {Object} meta The JSON metadata
13065 * Fires when Records have been added to the Store
13066 * @param {Store} this
13067 * @param {Roo.data.Record[]} records The array of Records added
13068 * @param {Number} index The index at which the record(s) were added
13073 * Fires when a Record has been removed from the Store
13074 * @param {Store} this
13075 * @param {Roo.data.Record} record The Record that was removed
13076 * @param {Number} index The index at which the record was removed
13081 * Fires when a Record has been updated
13082 * @param {Store} this
13083 * @param {Roo.data.Record} record The Record that was updated
13084 * @param {String} operation The update operation being performed. Value may be one of:
13086 Roo.data.Record.EDIT
13087 Roo.data.Record.REJECT
13088 Roo.data.Record.COMMIT
13094 * Fires when the data cache has been cleared.
13095 * @param {Store} this
13099 * @event beforeload
13100 * Fires before a request is made for a new data object. If the beforeload handler returns false
13101 * the load action will be canceled.
13102 * @param {Store} this
13103 * @param {Object} options The loading options that were specified (see {@link #load} for details)
13107 * @event beforeloadadd
13108 * Fires after a new set of Records has been loaded.
13109 * @param {Store} this
13110 * @param {Roo.data.Record[]} records The Records that were loaded
13111 * @param {Object} options The loading options that were specified (see {@link #load} for details)
13113 beforeloadadd : true,
13116 * Fires after a new set of Records has been loaded, before they are added to the store.
13117 * @param {Store} this
13118 * @param {Roo.data.Record[]} records The Records that were loaded
13119 * @param {Object} options The loading options that were specified (see {@link #load} for details)
13120 * @params {Object} return from reader
13124 * @event loadexception
13125 * Fires if an exception occurs in the Proxy during loading.
13126 * Called with the signature of the Proxy's "loadexception" event.
13127 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
13130 * @param {Object} return from JsonData.reader() - success, totalRecords, records
13131 * @param {Object} load options
13132 * @param {Object} jsonData from your request (normally this contains the Exception)
13134 loadexception : true
13138 this.proxy = Roo.factory(this.proxy, Roo.data);
13139 this.proxy.xmodule = this.xmodule || false;
13140 this.relayEvents(this.proxy, ["loadexception"]);
13142 this.sortToggle = {};
13143 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
13145 Roo.data.Store.superclass.constructor.call(this);
13147 if(this.inlineData){
13148 this.loadData(this.inlineData);
13149 delete this.inlineData;
13153 Roo.extend(Roo.data.Store, Roo.util.Observable, {
13155 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
13156 * without a remote query - used by combo/forms at present.
13160 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
13163 * @cfg {Array} data Inline data to be loaded when the store is initialized.
13166 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
13167 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
13170 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
13171 * on any HTTP request
13174 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
13177 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
13181 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
13182 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
13184 remoteSort : false,
13187 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
13188 * loaded or when a record is removed. (defaults to false).
13190 pruneModifiedRecords : false,
13193 lastOptions : null,
13196 * Add Records to the Store and fires the add event.
13197 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
13199 add : function(records){
13200 records = [].concat(records);
13201 for(var i = 0, len = records.length; i < len; i++){
13202 records[i].join(this);
13204 var index = this.data.length;
13205 this.data.addAll(records);
13206 this.fireEvent("add", this, records, index);
13210 * Remove a Record from the Store and fires the remove event.
13211 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
13213 remove : function(record){
13214 var index = this.data.indexOf(record);
13215 this.data.removeAt(index);
13217 if(this.pruneModifiedRecords){
13218 this.modified.remove(record);
13220 this.fireEvent("remove", this, record, index);
13224 * Remove all Records from the Store and fires the clear event.
13226 removeAll : function(){
13228 if(this.pruneModifiedRecords){
13229 this.modified = [];
13231 this.fireEvent("clear", this);
13235 * Inserts Records to the Store at the given index and fires the add event.
13236 * @param {Number} index The start index at which to insert the passed Records.
13237 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
13239 insert : function(index, records){
13240 records = [].concat(records);
13241 for(var i = 0, len = records.length; i < len; i++){
13242 this.data.insert(index, records[i]);
13243 records[i].join(this);
13245 this.fireEvent("add", this, records, index);
13249 * Get the index within the cache of the passed Record.
13250 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
13251 * @return {Number} The index of the passed Record. Returns -1 if not found.
13253 indexOf : function(record){
13254 return this.data.indexOf(record);
13258 * Get the index within the cache of the Record with the passed id.
13259 * @param {String} id The id of the Record to find.
13260 * @return {Number} The index of the Record. Returns -1 if not found.
13262 indexOfId : function(id){
13263 return this.data.indexOfKey(id);
13267 * Get the Record with the specified id.
13268 * @param {String} id The id of the Record to find.
13269 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
13271 getById : function(id){
13272 return this.data.key(id);
13276 * Get the Record at the specified index.
13277 * @param {Number} index The index of the Record to find.
13278 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
13280 getAt : function(index){
13281 return this.data.itemAt(index);
13285 * Returns a range of Records between specified indices.
13286 * @param {Number} startIndex (optional) The starting index (defaults to 0)
13287 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
13288 * @return {Roo.data.Record[]} An array of Records
13290 getRange : function(start, end){
13291 return this.data.getRange(start, end);
13295 storeOptions : function(o){
13296 o = Roo.apply({}, o);
13299 this.lastOptions = o;
13303 * Loads the Record cache from the configured Proxy using the configured Reader.
13305 * If using remote paging, then the first load call must specify the <em>start</em>
13306 * and <em>limit</em> properties in the options.params property to establish the initial
13307 * position within the dataset, and the number of Records to cache on each read from the Proxy.
13309 * <strong>It is important to note that for remote data sources, loading is asynchronous,
13310 * and this call will return before the new data has been loaded. Perform any post-processing
13311 * in a callback function, or in a "load" event handler.</strong>
13313 * @param {Object} options An object containing properties which control loading options:<ul>
13314 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
13315 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
13316 * passed the following arguments:<ul>
13317 * <li>r : Roo.data.Record[]</li>
13318 * <li>options: Options object from the load call</li>
13319 * <li>success: Boolean success indicator</li></ul></li>
13320 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
13321 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
13324 load : function(options){
13325 options = options || {};
13326 if(this.fireEvent("beforeload", this, options) !== false){
13327 this.storeOptions(options);
13328 var p = Roo.apply(options.params || {}, this.baseParams);
13329 // if meta was not loaded from remote source.. try requesting it.
13330 if (!this.reader.metaFromRemote) {
13331 p._requestMeta = 1;
13333 if(this.sortInfo && this.remoteSort){
13334 var pn = this.paramNames;
13335 p[pn["sort"]] = this.sortInfo.field;
13336 p[pn["dir"]] = this.sortInfo.direction;
13338 if (this.multiSort) {
13339 var pn = this.paramNames;
13340 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
13343 this.proxy.load(p, this.reader, this.loadRecords, this, options);
13348 * Reloads the Record cache from the configured Proxy using the configured Reader and
13349 * the options from the last load operation performed.
13350 * @param {Object} options (optional) An object containing properties which may override the options
13351 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
13352 * the most recently used options are reused).
13354 reload : function(options){
13355 this.load(Roo.applyIf(options||{}, this.lastOptions));
13359 // Called as a callback by the Reader during a load operation.
13360 loadRecords : function(o, options, success){
13361 if(!o || success === false){
13362 if(success !== false){
13363 this.fireEvent("load", this, [], options, o);
13365 if(options.callback){
13366 options.callback.call(options.scope || this, [], options, false);
13370 // if data returned failure - throw an exception.
13371 if (o.success === false) {
13372 // show a message if no listener is registered.
13373 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
13374 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
13376 // loadmask wil be hooked into this..
13377 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
13380 var r = o.records, t = o.totalRecords || r.length;
13382 this.fireEvent("beforeloadadd", this, r, options, o);
13384 if(!options || options.add !== true){
13385 if(this.pruneModifiedRecords){
13386 this.modified = [];
13388 for(var i = 0, len = r.length; i < len; i++){
13392 this.data = this.snapshot;
13393 delete this.snapshot;
13396 this.data.addAll(r);
13397 this.totalLength = t;
13399 this.fireEvent("datachanged", this);
13401 this.totalLength = Math.max(t, this.data.length+r.length);
13405 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
13407 var e = new Roo.data.Record({});
13409 e.set(this.parent.displayField, this.parent.emptyTitle);
13410 e.set(this.parent.valueField, '');
13415 this.fireEvent("load", this, r, options, o);
13416 if(options.callback){
13417 options.callback.call(options.scope || this, r, options, true);
13423 * Loads data from a passed data block. A Reader which understands the format of the data
13424 * must have been configured in the constructor.
13425 * @param {Object} data The data block from which to read the Records. The format of the data expected
13426 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
13427 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
13429 loadData : function(o, append){
13430 var r = this.reader.readRecords(o);
13431 this.loadRecords(r, {add: append}, true);
13435 * using 'cn' the nested child reader read the child array into it's child stores.
13436 * @param {Object} rec The record with a 'children array
13438 loadDataFromChildren : function(rec)
13440 this.loadData(this.reader.toLoadData(rec));
13445 * Gets the number of cached records.
13447 * <em>If using paging, this may not be the total size of the dataset. If the data object
13448 * used by the Reader contains the dataset size, then the getTotalCount() function returns
13449 * the data set size</em>
13451 getCount : function(){
13452 return this.data.length || 0;
13456 * Gets the total number of records in the dataset as returned by the server.
13458 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
13459 * the dataset size</em>
13461 getTotalCount : function(){
13462 return this.totalLength || 0;
13466 * Returns the sort state of the Store as an object with two properties:
13468 field {String} The name of the field by which the Records are sorted
13469 direction {String} The sort order, "ASC" or "DESC"
13472 getSortState : function(){
13473 return this.sortInfo;
13477 applySort : function(){
13478 if(this.sortInfo && !this.remoteSort){
13479 var s = this.sortInfo, f = s.field;
13480 var st = this.fields.get(f).sortType;
13481 var fn = function(r1, r2){
13482 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
13483 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
13485 this.data.sort(s.direction, fn);
13486 if(this.snapshot && this.snapshot != this.data){
13487 this.snapshot.sort(s.direction, fn);
13493 * Sets the default sort column and order to be used by the next load operation.
13494 * @param {String} fieldName The name of the field to sort by.
13495 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
13497 setDefaultSort : function(field, dir){
13498 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
13502 * Sort the Records.
13503 * If remote sorting is used, the sort is performed on the server, and the cache is
13504 * reloaded. If local sorting is used, the cache is sorted internally.
13505 * @param {String} fieldName The name of the field to sort by.
13506 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
13508 sort : function(fieldName, dir){
13509 var f = this.fields.get(fieldName);
13511 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
13513 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
13514 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
13519 this.sortToggle[f.name] = dir;
13520 this.sortInfo = {field: f.name, direction: dir};
13521 if(!this.remoteSort){
13523 this.fireEvent("datachanged", this);
13525 this.load(this.lastOptions);
13530 * Calls the specified function for each of the Records in the cache.
13531 * @param {Function} fn The function to call. The Record is passed as the first parameter.
13532 * Returning <em>false</em> aborts and exits the iteration.
13533 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
13535 each : function(fn, scope){
13536 this.data.each(fn, scope);
13540 * Gets all records modified since the last commit. Modified records are persisted across load operations
13541 * (e.g., during paging).
13542 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
13544 getModifiedRecords : function(){
13545 return this.modified;
13549 createFilterFn : function(property, value, anyMatch){
13550 if(!value.exec){ // not a regex
13551 value = String(value);
13552 if(value.length == 0){
13555 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
13557 return function(r){
13558 return value.test(r.data[property]);
13563 * Sums the value of <i>property</i> for each record between start and end and returns the result.
13564 * @param {String} property A field on your records
13565 * @param {Number} start The record index to start at (defaults to 0)
13566 * @param {Number} end The last record index to include (defaults to length - 1)
13567 * @return {Number} The sum
13569 sum : function(property, start, end){
13570 var rs = this.data.items, v = 0;
13571 start = start || 0;
13572 end = (end || end === 0) ? end : rs.length-1;
13574 for(var i = start; i <= end; i++){
13575 v += (rs[i].data[property] || 0);
13581 * Filter the records by a specified property.
13582 * @param {String} field A field on your records
13583 * @param {String/RegExp} value Either a string that the field
13584 * should start with or a RegExp to test against the field
13585 * @param {Boolean} anyMatch True to match any part not just the beginning
13587 filter : function(property, value, anyMatch){
13588 var fn = this.createFilterFn(property, value, anyMatch);
13589 return fn ? this.filterBy(fn) : this.clearFilter();
13593 * Filter by a function. The specified function will be called with each
13594 * record in this data source. If the function returns true the record is included,
13595 * otherwise it is filtered.
13596 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
13597 * @param {Object} scope (optional) The scope of the function (defaults to this)
13599 filterBy : function(fn, scope){
13600 this.snapshot = this.snapshot || this.data;
13601 this.data = this.queryBy(fn, scope||this);
13602 this.fireEvent("datachanged", this);
13606 * Query the records by a specified property.
13607 * @param {String} field A field on your records
13608 * @param {String/RegExp} value Either a string that the field
13609 * should start with or a RegExp to test against the field
13610 * @param {Boolean} anyMatch True to match any part not just the beginning
13611 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
13613 query : function(property, value, anyMatch){
13614 var fn = this.createFilterFn(property, value, anyMatch);
13615 return fn ? this.queryBy(fn) : this.data.clone();
13619 * Query by a function. The specified function will be called with each
13620 * record in this data source. If the function returns true the record is included
13622 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
13623 * @param {Object} scope (optional) The scope of the function (defaults to this)
13624 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
13626 queryBy : function(fn, scope){
13627 var data = this.snapshot || this.data;
13628 return data.filterBy(fn, scope||this);
13632 * Collects unique values for a particular dataIndex from this store.
13633 * @param {String} dataIndex The property to collect
13634 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
13635 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
13636 * @return {Array} An array of the unique values
13638 collect : function(dataIndex, allowNull, bypassFilter){
13639 var d = (bypassFilter === true && this.snapshot) ?
13640 this.snapshot.items : this.data.items;
13641 var v, sv, r = [], l = {};
13642 for(var i = 0, len = d.length; i < len; i++){
13643 v = d[i].data[dataIndex];
13645 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
13654 * Revert to a view of the Record cache with no filtering applied.
13655 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
13657 clearFilter : function(suppressEvent){
13658 if(this.snapshot && this.snapshot != this.data){
13659 this.data = this.snapshot;
13660 delete this.snapshot;
13661 if(suppressEvent !== true){
13662 this.fireEvent("datachanged", this);
13668 afterEdit : function(record){
13669 if(this.modified.indexOf(record) == -1){
13670 this.modified.push(record);
13672 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
13676 afterReject : function(record){
13677 this.modified.remove(record);
13678 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
13682 afterCommit : function(record){
13683 this.modified.remove(record);
13684 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
13688 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
13689 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
13691 commitChanges : function(){
13692 var m = this.modified.slice(0);
13693 this.modified = [];
13694 for(var i = 0, len = m.length; i < len; i++){
13700 * Cancel outstanding changes on all changed records.
13702 rejectChanges : function(){
13703 var m = this.modified.slice(0);
13704 this.modified = [];
13705 for(var i = 0, len = m.length; i < len; i++){
13710 onMetaChange : function(meta, rtype, o){
13711 this.recordType = rtype;
13712 this.fields = rtype.prototype.fields;
13713 delete this.snapshot;
13714 this.sortInfo = meta.sortInfo || this.sortInfo;
13715 this.modified = [];
13716 this.fireEvent('metachange', this, this.reader.meta);
13719 moveIndex : function(data, type)
13721 var index = this.indexOf(data);
13723 var newIndex = index + type;
13727 this.insert(newIndex, data);
13732 * Ext JS Library 1.1.1
13733 * Copyright(c) 2006-2007, Ext JS, LLC.
13735 * Originally Released Under LGPL - original licence link has changed is not relivant.
13738 * <script type="text/javascript">
13742 * @class Roo.data.SimpleStore
13743 * @extends Roo.data.Store
13744 * Small helper class to make creating Stores from Array data easier.
13745 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
13746 * @cfg {Array} fields An array of field definition objects, or field name strings.
13747 * @cfg {Object} an existing reader (eg. copied from another store)
13748 * @cfg {Array} data The multi-dimensional array of data
13750 * @param {Object} config
13752 Roo.data.SimpleStore = function(config)
13754 Roo.data.SimpleStore.superclass.constructor.call(this, {
13756 reader: typeof(config.reader) != 'undefined' ? config.reader : new Roo.data.ArrayReader({
13759 Roo.data.Record.create(config.fields)
13761 proxy : new Roo.data.MemoryProxy(config.data)
13765 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
13767 * Ext JS Library 1.1.1
13768 * Copyright(c) 2006-2007, Ext JS, LLC.
13770 * Originally Released Under LGPL - original licence link has changed is not relivant.
13773 * <script type="text/javascript">
13778 * @extends Roo.data.Store
13779 * @class Roo.data.JsonStore
13780 * Small helper class to make creating Stores for JSON data easier. <br/>
13782 var store = new Roo.data.JsonStore({
13783 url: 'get-images.php',
13785 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
13788 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
13789 * JsonReader and HttpProxy (unless inline data is provided).</b>
13790 * @cfg {Array} fields An array of field definition objects, or field name strings.
13792 * @param {Object} config
13794 Roo.data.JsonStore = function(c){
13795 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
13796 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
13797 reader: new Roo.data.JsonReader(c, c.fields)
13800 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
13802 * Ext JS Library 1.1.1
13803 * Copyright(c) 2006-2007, Ext JS, LLC.
13805 * Originally Released Under LGPL - original licence link has changed is not relivant.
13808 * <script type="text/javascript">
13812 Roo.data.Field = function(config){
13813 if(typeof config == "string"){
13814 config = {name: config};
13816 Roo.apply(this, config);
13819 this.type = "auto";
13822 var st = Roo.data.SortTypes;
13823 // named sortTypes are supported, here we look them up
13824 if(typeof this.sortType == "string"){
13825 this.sortType = st[this.sortType];
13828 // set default sortType for strings and dates
13829 if(!this.sortType){
13832 this.sortType = st.asUCString;
13835 this.sortType = st.asDate;
13838 this.sortType = st.none;
13843 var stripRe = /[\$,%]/g;
13845 // prebuilt conversion function for this field, instead of
13846 // switching every time we're reading a value
13848 var cv, dateFormat = this.dateFormat;
13853 cv = function(v){ return v; };
13856 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
13860 return v !== undefined && v !== null && v !== '' ?
13861 parseInt(String(v).replace(stripRe, ""), 10) : '';
13866 return v !== undefined && v !== null && v !== '' ?
13867 parseFloat(String(v).replace(stripRe, ""), 10) : '';
13872 cv = function(v){ return v === true || v === "true" || v == 1; };
13879 if(v instanceof Date){
13883 if(dateFormat == "timestamp"){
13884 return new Date(v*1000);
13886 return Date.parseDate(v, dateFormat);
13888 var parsed = Date.parse(v);
13889 return parsed ? new Date(parsed) : null;
13898 Roo.data.Field.prototype = {
13906 * Ext JS Library 1.1.1
13907 * Copyright(c) 2006-2007, Ext JS, LLC.
13909 * Originally Released Under LGPL - original licence link has changed is not relivant.
13912 * <script type="text/javascript">
13915 // Base class for reading structured data from a data source. This class is intended to be
13916 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
13919 * @class Roo.data.DataReader
13920 * Base class for reading structured data from a data source. This class is intended to be
13921 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
13924 Roo.data.DataReader = function(meta, recordType){
13928 this.recordType = recordType instanceof Array ?
13929 Roo.data.Record.create(recordType) : recordType;
13932 Roo.data.DataReader.prototype = {
13935 readerType : 'Data',
13937 * Create an empty record
13938 * @param {Object} data (optional) - overlay some values
13939 * @return {Roo.data.Record} record created.
13941 newRow : function(d) {
13943 this.recordType.prototype.fields.each(function(c) {
13945 case 'int' : da[c.name] = 0; break;
13946 case 'date' : da[c.name] = new Date(); break;
13947 case 'float' : da[c.name] = 0.0; break;
13948 case 'boolean' : da[c.name] = false; break;
13949 default : da[c.name] = ""; break;
13953 return new this.recordType(Roo.apply(da, d));
13959 * Ext JS Library 1.1.1
13960 * Copyright(c) 2006-2007, Ext JS, LLC.
13962 * Originally Released Under LGPL - original licence link has changed is not relivant.
13965 * <script type="text/javascript">
13969 * @class Roo.data.DataProxy
13970 * @extends Roo.data.Observable
13971 * This class is an abstract base class for implementations which provide retrieval of
13972 * unformatted data objects.<br>
13974 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
13975 * (of the appropriate type which knows how to parse the data object) to provide a block of
13976 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
13978 * Custom implementations must implement the load method as described in
13979 * {@link Roo.data.HttpProxy#load}.
13981 Roo.data.DataProxy = function(){
13984 * @event beforeload
13985 * Fires before a network request is made to retrieve a data object.
13986 * @param {Object} This DataProxy object.
13987 * @param {Object} params The params parameter to the load function.
13992 * Fires before the load method's callback is called.
13993 * @param {Object} This DataProxy object.
13994 * @param {Object} o The data object.
13995 * @param {Object} arg The callback argument object passed to the load function.
13999 * @event loadexception
14000 * Fires if an Exception occurs during data retrieval.
14001 * @param {Object} This DataProxy object.
14002 * @param {Object} o The data object.
14003 * @param {Object} arg The callback argument object passed to the load function.
14004 * @param {Object} e The Exception.
14006 loadexception : true
14008 Roo.data.DataProxy.superclass.constructor.call(this);
14011 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
14014 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
14018 * Ext JS Library 1.1.1
14019 * Copyright(c) 2006-2007, Ext JS, LLC.
14021 * Originally Released Under LGPL - original licence link has changed is not relivant.
14024 * <script type="text/javascript">
14027 * @class Roo.data.MemoryProxy
14028 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
14029 * to the Reader when its load method is called.
14031 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
14033 Roo.data.MemoryProxy = function(data){
14037 Roo.data.MemoryProxy.superclass.constructor.call(this);
14041 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
14044 * Load data from the requested source (in this case an in-memory
14045 * data object passed to the constructor), read the data object into
14046 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
14047 * process that block using the passed callback.
14048 * @param {Object} params This parameter is not used by the MemoryProxy class.
14049 * @param {Roo.data.DataReader} reader The Reader object which converts the data
14050 * object into a block of Roo.data.Records.
14051 * @param {Function} callback The function into which to pass the block of Roo.data.records.
14052 * The function must be passed <ul>
14053 * <li>The Record block object</li>
14054 * <li>The "arg" argument from the load function</li>
14055 * <li>A boolean success indicator</li>
14057 * @param {Object} scope The scope in which to call the callback
14058 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
14060 load : function(params, reader, callback, scope, arg){
14061 params = params || {};
14064 result = reader.readRecords(params.data ? params.data :this.data);
14066 this.fireEvent("loadexception", this, arg, null, e);
14067 callback.call(scope, null, arg, false);
14070 callback.call(scope, result, arg, true);
14074 update : function(params, records){
14079 * Ext JS Library 1.1.1
14080 * Copyright(c) 2006-2007, Ext JS, LLC.
14082 * Originally Released Under LGPL - original licence link has changed is not relivant.
14085 * <script type="text/javascript">
14088 * @class Roo.data.HttpProxy
14089 * @extends Roo.data.DataProxy
14090 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
14091 * configured to reference a certain URL.<br><br>
14093 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
14094 * from which the running page was served.<br><br>
14096 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
14098 * Be aware that to enable the browser to parse an XML document, the server must set
14099 * the Content-Type header in the HTTP response to "text/xml".
14101 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
14102 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
14103 * will be used to make the request.
14105 Roo.data.HttpProxy = function(conn){
14106 Roo.data.HttpProxy.superclass.constructor.call(this);
14107 // is conn a conn config or a real conn?
14109 this.useAjax = !conn || !conn.events;
14113 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
14114 // thse are take from connection...
14117 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
14120 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
14121 * extra parameters to each request made by this object. (defaults to undefined)
14124 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
14125 * to each request made by this object. (defaults to undefined)
14128 * @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)
14131 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
14134 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
14140 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
14144 * Return the {@link Roo.data.Connection} object being used by this Proxy.
14145 * @return {Connection} The Connection object. This object may be used to subscribe to events on
14146 * a finer-grained basis than the DataProxy events.
14148 getConnection : function(){
14149 return this.useAjax ? Roo.Ajax : this.conn;
14153 * Load data from the configured {@link Roo.data.Connection}, read the data object into
14154 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
14155 * process that block using the passed callback.
14156 * @param {Object} params An object containing properties which are to be used as HTTP parameters
14157 * for the request to the remote server.
14158 * @param {Roo.data.DataReader} reader The Reader object which converts the data
14159 * object into a block of Roo.data.Records.
14160 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
14161 * The function must be passed <ul>
14162 * <li>The Record block object</li>
14163 * <li>The "arg" argument from the load function</li>
14164 * <li>A boolean success indicator</li>
14166 * @param {Object} scope The scope in which to call the callback
14167 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
14169 load : function(params, reader, callback, scope, arg){
14170 if(this.fireEvent("beforeload", this, params) !== false){
14172 params : params || {},
14174 callback : callback,
14179 callback : this.loadResponse,
14183 Roo.applyIf(o, this.conn);
14184 if(this.activeRequest){
14185 Roo.Ajax.abort(this.activeRequest);
14187 this.activeRequest = Roo.Ajax.request(o);
14189 this.conn.request(o);
14192 callback.call(scope||this, null, arg, false);
14197 loadResponse : function(o, success, response){
14198 delete this.activeRequest;
14200 this.fireEvent("loadexception", this, o, response);
14201 o.request.callback.call(o.request.scope, null, o.request.arg, false);
14206 result = o.reader.read(response);
14208 this.fireEvent("loadexception", this, o, response, e);
14209 o.request.callback.call(o.request.scope, null, o.request.arg, false);
14213 this.fireEvent("load", this, o, o.request.arg);
14214 o.request.callback.call(o.request.scope, result, o.request.arg, true);
14218 update : function(dataSet){
14223 updateResponse : function(dataSet){
14228 * Ext JS Library 1.1.1
14229 * Copyright(c) 2006-2007, Ext JS, LLC.
14231 * Originally Released Under LGPL - original licence link has changed is not relivant.
14234 * <script type="text/javascript">
14238 * @class Roo.data.ScriptTagProxy
14239 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
14240 * other than the originating domain of the running page.<br><br>
14242 * <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
14243 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
14245 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
14246 * source code that is used as the source inside a <script> tag.<br><br>
14248 * In order for the browser to process the returned data, the server must wrap the data object
14249 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
14250 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
14251 * depending on whether the callback name was passed:
14254 boolean scriptTag = false;
14255 String cb = request.getParameter("callback");
14258 response.setContentType("text/javascript");
14260 response.setContentType("application/x-json");
14262 Writer out = response.getWriter();
14264 out.write(cb + "(");
14266 out.print(dataBlock.toJsonString());
14273 * @param {Object} config A configuration object.
14275 Roo.data.ScriptTagProxy = function(config){
14276 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
14277 Roo.apply(this, config);
14278 this.head = document.getElementsByTagName("head")[0];
14281 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
14283 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
14285 * @cfg {String} url The URL from which to request the data object.
14288 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
14292 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
14293 * the server the name of the callback function set up by the load call to process the returned data object.
14294 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
14295 * javascript output which calls this named function passing the data object as its only parameter.
14297 callbackParam : "callback",
14299 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
14300 * name to the request.
14305 * Load data from the configured URL, read the data object into
14306 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
14307 * process that block using the passed callback.
14308 * @param {Object} params An object containing properties which are to be used as HTTP parameters
14309 * for the request to the remote server.
14310 * @param {Roo.data.DataReader} reader The Reader object which converts the data
14311 * object into a block of Roo.data.Records.
14312 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
14313 * The function must be passed <ul>
14314 * <li>The Record block object</li>
14315 * <li>The "arg" argument from the load function</li>
14316 * <li>A boolean success indicator</li>
14318 * @param {Object} scope The scope in which to call the callback
14319 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
14321 load : function(params, reader, callback, scope, arg){
14322 if(this.fireEvent("beforeload", this, params) !== false){
14324 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
14326 var url = this.url;
14327 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
14329 url += "&_dc=" + (new Date().getTime());
14331 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
14334 cb : "stcCallback"+transId,
14335 scriptId : "stcScript"+transId,
14339 callback : callback,
14345 window[trans.cb] = function(o){
14346 conn.handleResponse(o, trans);
14349 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
14351 if(this.autoAbort !== false){
14355 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
14357 var script = document.createElement("script");
14358 script.setAttribute("src", url);
14359 script.setAttribute("type", "text/javascript");
14360 script.setAttribute("id", trans.scriptId);
14361 this.head.appendChild(script);
14363 this.trans = trans;
14365 callback.call(scope||this, null, arg, false);
14370 isLoading : function(){
14371 return this.trans ? true : false;
14375 * Abort the current server request.
14377 abort : function(){
14378 if(this.isLoading()){
14379 this.destroyTrans(this.trans);
14384 destroyTrans : function(trans, isLoaded){
14385 this.head.removeChild(document.getElementById(trans.scriptId));
14386 clearTimeout(trans.timeoutId);
14388 window[trans.cb] = undefined;
14390 delete window[trans.cb];
14393 // if hasn't been loaded, wait for load to remove it to prevent script error
14394 window[trans.cb] = function(){
14395 window[trans.cb] = undefined;
14397 delete window[trans.cb];
14404 handleResponse : function(o, trans){
14405 this.trans = false;
14406 this.destroyTrans(trans, true);
14409 result = trans.reader.readRecords(o);
14411 this.fireEvent("loadexception", this, o, trans.arg, e);
14412 trans.callback.call(trans.scope||window, null, trans.arg, false);
14415 this.fireEvent("load", this, o, trans.arg);
14416 trans.callback.call(trans.scope||window, result, trans.arg, true);
14420 handleFailure : function(trans){
14421 this.trans = false;
14422 this.destroyTrans(trans, false);
14423 this.fireEvent("loadexception", this, null, trans.arg);
14424 trans.callback.call(trans.scope||window, null, trans.arg, false);
14428 * Ext JS Library 1.1.1
14429 * Copyright(c) 2006-2007, Ext JS, LLC.
14431 * Originally Released Under LGPL - original licence link has changed is not relivant.
14434 * <script type="text/javascript">
14438 * @class Roo.data.JsonReader
14439 * @extends Roo.data.DataReader
14440 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
14441 * based on mappings in a provided Roo.data.Record constructor.
14443 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
14444 * in the reply previously.
14449 var RecordDef = Roo.data.Record.create([
14450 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
14451 {name: 'occupation'} // This field will use "occupation" as the mapping.
14453 var myReader = new Roo.data.JsonReader({
14454 totalProperty: "results", // The property which contains the total dataset size (optional)
14455 root: "rows", // The property which contains an Array of row objects
14456 id: "id" // The property within each row object that provides an ID for the record (optional)
14460 * This would consume a JSON file like this:
14462 { 'results': 2, 'rows': [
14463 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
14464 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
14467 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
14468 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
14469 * paged from the remote server.
14470 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
14471 * @cfg {String} root name of the property which contains the Array of row objects.
14472 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
14473 * @cfg {Array} fields Array of field definition objects
14475 * Create a new JsonReader
14476 * @param {Object} meta Metadata configuration options
14477 * @param {Object} recordType Either an Array of field definition objects,
14478 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
14480 Roo.data.JsonReader = function(meta, recordType){
14483 // set some defaults:
14484 Roo.applyIf(meta, {
14485 totalProperty: 'total',
14486 successProperty : 'success',
14491 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
14493 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
14495 readerType : 'Json',
14498 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
14499 * Used by Store query builder to append _requestMeta to params.
14502 metaFromRemote : false,
14504 * This method is only used by a DataProxy which has retrieved data from a remote server.
14505 * @param {Object} response The XHR object which contains the JSON data in its responseText.
14506 * @return {Object} data A data block which is used by an Roo.data.Store object as
14507 * a cache of Roo.data.Records.
14509 read : function(response){
14510 var json = response.responseText;
14512 var o = /* eval:var:o */ eval("("+json+")");
14514 throw {message: "JsonReader.read: Json object not found"};
14520 this.metaFromRemote = true;
14521 this.meta = o.metaData;
14522 this.recordType = Roo.data.Record.create(o.metaData.fields);
14523 this.onMetaChange(this.meta, this.recordType, o);
14525 return this.readRecords(o);
14528 // private function a store will implement
14529 onMetaChange : function(meta, recordType, o){
14536 simpleAccess: function(obj, subsc) {
14543 getJsonAccessor: function(){
14545 return function(expr) {
14547 return(re.test(expr))
14548 ? new Function("obj", "return obj." + expr)
14553 return Roo.emptyFn;
14558 * Create a data block containing Roo.data.Records from an XML document.
14559 * @param {Object} o An object which contains an Array of row objects in the property specified
14560 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
14561 * which contains the total size of the dataset.
14562 * @return {Object} data A data block which is used by an Roo.data.Store object as
14563 * a cache of Roo.data.Records.
14565 readRecords : function(o){
14567 * After any data loads, the raw JSON data is available for further custom processing.
14571 var s = this.meta, Record = this.recordType,
14572 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
14574 // Generate extraction functions for the totalProperty, the root, the id, and for each field
14576 if(s.totalProperty) {
14577 this.getTotal = this.getJsonAccessor(s.totalProperty);
14579 if(s.successProperty) {
14580 this.getSuccess = this.getJsonAccessor(s.successProperty);
14582 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
14584 var g = this.getJsonAccessor(s.id);
14585 this.getId = function(rec) {
14587 return (r === undefined || r === "") ? null : r;
14590 this.getId = function(){return null;};
14593 for(var jj = 0; jj < fl; jj++){
14595 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
14596 this.ef[jj] = this.getJsonAccessor(map);
14600 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
14601 if(s.totalProperty){
14602 var vt = parseInt(this.getTotal(o), 10);
14607 if(s.successProperty){
14608 var vs = this.getSuccess(o);
14609 if(vs === false || vs === 'false'){
14614 for(var i = 0; i < c; i++){
14617 var id = this.getId(n);
14618 for(var j = 0; j < fl; j++){
14620 var v = this.ef[j](n);
14622 Roo.log('missing convert for ' + f.name);
14626 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
14628 var record = new Record(values, id);
14630 records[i] = record;
14636 totalRecords : totalRecords
14639 // used when loading children.. @see loadDataFromChildren
14640 toLoadData: function(rec)
14642 // expect rec just to be an array.. eg [a,b,c, [...] << cn ]
14643 var data = typeof(rec.data.cn) == 'undefined' ? [] : rec.data.cn;
14644 return { data : data, total : data.length };
14649 * Ext JS Library 1.1.1
14650 * Copyright(c) 2006-2007, Ext JS, LLC.
14652 * Originally Released Under LGPL - original licence link has changed is not relivant.
14655 * <script type="text/javascript">
14659 * @class Roo.data.ArrayReader
14660 * @extends Roo.data.DataReader
14661 * Data reader class to create an Array of Roo.data.Record objects from an Array.
14662 * Each element of that Array represents a row of data fields. The
14663 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
14664 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
14668 var RecordDef = Roo.data.Record.create([
14669 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
14670 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
14672 var myReader = new Roo.data.ArrayReader({
14673 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
14677 * This would consume an Array like this:
14679 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
14683 * Create a new JsonReader
14684 * @param {Object} meta Metadata configuration options.
14685 * @param {Object|Array} recordType Either an Array of field definition objects
14687 * @cfg {Array} fields Array of field definition objects
14688 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
14689 * as specified to {@link Roo.data.Record#create},
14690 * or an {@link Roo.data.Record} object
14693 * created using {@link Roo.data.Record#create}.
14695 Roo.data.ArrayReader = function(meta, recordType)
14697 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType||meta.fields);
14700 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
14703 * Create a data block containing Roo.data.Records from an XML document.
14704 * @param {Object} o An Array of row objects which represents the dataset.
14705 * @return {Object} A data block which is used by an {@link Roo.data.Store} object as
14706 * a cache of Roo.data.Records.
14708 readRecords : function(o)
14710 var sid = this.meta ? this.meta.id : null;
14711 var recordType = this.recordType, fields = recordType.prototype.fields;
14714 for(var i = 0; i < root.length; i++){
14717 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
14718 for(var j = 0, jlen = fields.length; j < jlen; j++){
14719 var f = fields.items[j];
14720 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
14721 var v = n[k] !== undefined ? n[k] : f.defaultValue;
14723 values[f.name] = v;
14725 var record = new recordType(values, id);
14727 records[records.length] = record;
14731 totalRecords : records.length
14734 // used when loading children.. @see loadDataFromChildren
14735 toLoadData: function(rec)
14737 // expect rec just to be an array.. eg [a,b,c, [...] << cn ]
14738 return typeof(rec.data.cn) == 'undefined' ? [] : rec.data.cn;
14749 * @class Roo.bootstrap.ComboBox
14750 * @extends Roo.bootstrap.TriggerField
14751 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
14752 * @cfg {Boolean} append (true|false) default false
14753 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
14754 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
14755 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
14756 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
14757 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
14758 * @cfg {Boolean} animate default true
14759 * @cfg {Boolean} emptyResultText only for touch device
14760 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
14761 * @cfg {String} emptyTitle default ''
14762 * @cfg {Number} width fixed with? experimental
14764 * Create a new ComboBox.
14765 * @param {Object} config Configuration options
14767 Roo.bootstrap.ComboBox = function(config){
14768 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
14772 * Fires when the dropdown list is expanded
14773 * @param {Roo.bootstrap.ComboBox} combo This combo box
14778 * Fires when the dropdown list is collapsed
14779 * @param {Roo.bootstrap.ComboBox} combo This combo box
14783 * @event beforeselect
14784 * Fires before a list item is selected. Return false to cancel the selection.
14785 * @param {Roo.bootstrap.ComboBox} combo This combo box
14786 * @param {Roo.data.Record} record The data record returned from the underlying store
14787 * @param {Number} index The index of the selected item in the dropdown list
14789 'beforeselect' : true,
14792 * Fires when a list item is selected
14793 * @param {Roo.bootstrap.ComboBox} combo This combo box
14794 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
14795 * @param {Number} index The index of the selected item in the dropdown list
14799 * @event beforequery
14800 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
14801 * The event object passed has these properties:
14802 * @param {Roo.bootstrap.ComboBox} combo This combo box
14803 * @param {String} query The query
14804 * @param {Boolean} forceAll true to force "all" query
14805 * @param {Boolean} cancel true to cancel the query
14806 * @param {Object} e The query event object
14808 'beforequery': true,
14811 * Fires when the 'add' icon is pressed (add a listener to enable add button)
14812 * @param {Roo.bootstrap.ComboBox} combo This combo box
14817 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
14818 * @param {Roo.bootstrap.ComboBox} combo This combo box
14819 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
14824 * Fires when the remove value from the combobox array
14825 * @param {Roo.bootstrap.ComboBox} combo This combo box
14829 * @event afterremove
14830 * Fires when the remove value from the combobox array
14831 * @param {Roo.bootstrap.ComboBox} combo This combo box
14833 'afterremove' : true,
14835 * @event specialfilter
14836 * Fires when specialfilter
14837 * @param {Roo.bootstrap.ComboBox} combo This combo box
14839 'specialfilter' : true,
14842 * Fires when tick the element
14843 * @param {Roo.bootstrap.ComboBox} combo This combo box
14847 * @event touchviewdisplay
14848 * Fires when touch view require special display (default is using displayField)
14849 * @param {Roo.bootstrap.ComboBox} combo This combo box
14850 * @param {Object} cfg set html .
14852 'touchviewdisplay' : true
14857 this.tickItems = [];
14859 this.selectedIndex = -1;
14860 if(this.mode == 'local'){
14861 if(config.queryDelay === undefined){
14862 this.queryDelay = 10;
14864 if(config.minChars === undefined){
14870 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
14873 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
14874 * rendering into an Roo.Editor, defaults to false)
14877 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
14878 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
14881 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
14884 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
14885 * the dropdown list (defaults to undefined, with no header element)
14889 * @cfg {String/Roo.Template} tpl The template to use to render the output default is '<a class="dropdown-item" href="#">{' + this.displayField + '}</a>'
14893 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
14895 listWidth: undefined,
14897 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
14898 * mode = 'remote' or 'text' if mode = 'local')
14900 displayField: undefined,
14903 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
14904 * mode = 'remote' or 'value' if mode = 'local').
14905 * Note: use of a valueField requires the user make a selection
14906 * in order for a value to be mapped.
14908 valueField: undefined,
14910 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
14915 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
14916 * field's data value (defaults to the underlying DOM element's name)
14918 hiddenName: undefined,
14920 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
14924 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
14926 selectedClass: 'active',
14929 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
14933 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
14934 * anchor positions (defaults to 'tl-bl')
14936 listAlign: 'tl-bl?',
14938 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
14942 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
14943 * query specified by the allQuery config option (defaults to 'query')
14945 triggerAction: 'query',
14947 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
14948 * (defaults to 4, does not apply if editable = false)
14952 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
14953 * delay (typeAheadDelay) if it matches a known value (defaults to false)
14957 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
14958 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
14962 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
14963 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
14967 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
14968 * when editable = true (defaults to false)
14970 selectOnFocus:false,
14972 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
14974 queryParam: 'query',
14976 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
14977 * when mode = 'remote' (defaults to 'Loading...')
14979 loadingText: 'Loading...',
14981 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
14985 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
14989 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
14990 * traditional select (defaults to true)
14994 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
14998 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
15002 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
15003 * listWidth has a higher value)
15007 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
15008 * allow the user to set arbitrary text into the field (defaults to false)
15010 forceSelection:false,
15012 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
15013 * if typeAhead = true (defaults to 250)
15015 typeAheadDelay : 250,
15017 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
15018 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
15020 valueNotFoundText : undefined,
15022 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
15024 blockFocus : false,
15027 * @cfg {Boolean} disableClear Disable showing of clear button.
15029 disableClear : false,
15031 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
15033 alwaysQuery : false,
15036 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
15041 * @cfg {String} invalidClass DEPRICATED - uses BS4 is-valid now
15043 invalidClass : "has-warning",
15046 * @cfg {String} validClass DEPRICATED - uses BS4 is-valid now
15048 validClass : "has-success",
15051 * @cfg {Boolean} specialFilter (true|false) special filter default false
15053 specialFilter : false,
15056 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
15058 mobileTouchView : true,
15061 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
15063 useNativeIOS : false,
15066 * @cfg {Boolean} mobile_restrict_height (true|false) restrict height for touch view
15068 mobile_restrict_height : false,
15070 ios_options : false,
15082 btnPosition : 'right',
15083 triggerList : true,
15084 showToggleBtn : true,
15086 emptyResultText: 'Empty',
15087 triggerText : 'Select',
15091 // element that contains real text value.. (when hidden is used..)
15093 getAutoCreate : function()
15098 * Render classic select for iso
15101 if(Roo.isIOS && this.useNativeIOS){
15102 cfg = this.getAutoCreateNativeIOS();
15110 if(Roo.isTouch && this.mobileTouchView){
15111 cfg = this.getAutoCreateTouchView();
15118 if(!this.tickable){
15119 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
15124 * ComboBox with tickable selections
15127 var align = this.labelAlign || this.parentLabelAlign();
15130 cls : 'form-group roo-combobox-tickable' //input-group
15133 var btn_text_select = '';
15134 var btn_text_done = '';
15135 var btn_text_cancel = '';
15137 if (this.btn_text_show) {
15138 btn_text_select = 'Select';
15139 btn_text_done = 'Done';
15140 btn_text_cancel = 'Cancel';
15145 cls : 'tickable-buttons',
15150 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
15151 //html : this.triggerText
15152 html: btn_text_select
15158 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
15160 html: btn_text_done
15166 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
15168 html: btn_text_cancel
15174 buttons.cn.unshift({
15176 cls: 'roo-select2-search-field-input'
15182 Roo.each(buttons.cn, function(c){
15184 c.cls += ' btn-' + _this.size;
15187 if (_this.disabled) {
15194 style : 'display: contents',
15199 cls: 'form-hidden-field'
15203 cls: 'roo-select2-choices',
15207 cls: 'roo-select2-search-field',
15218 cls: 'roo-select2-container input-group roo-select2-container-multi',
15224 // cls: 'typeahead typeahead-long dropdown-menu',
15225 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
15230 if(this.hasFeedback && !this.allowBlank){
15234 cls: 'glyphicon form-control-feedback'
15237 combobox.cn.push(feedback);
15244 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
15245 tooltip : 'This field is required'
15247 if (Roo.bootstrap.version == 4) {
15250 style : 'display:none'
15253 if (align ==='left' && this.fieldLabel.length) {
15255 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
15262 cls : 'control-label col-form-label',
15263 html : this.fieldLabel
15275 var labelCfg = cfg.cn[1];
15276 var contentCfg = cfg.cn[2];
15279 if(this.indicatorpos == 'right'){
15285 cls : 'control-label col-form-label',
15289 html : this.fieldLabel
15305 labelCfg = cfg.cn[0];
15306 contentCfg = cfg.cn[1];
15310 if(this.labelWidth > 12){
15311 labelCfg.style = "width: " + this.labelWidth + 'px';
15313 if(this.width * 1 > 0){
15314 contentCfg.style = "width: " + this.width + 'px';
15316 if(this.labelWidth < 13 && this.labelmd == 0){
15317 this.labelmd = this.labelWidth;
15320 if(this.labellg > 0){
15321 labelCfg.cls += ' col-lg-' + this.labellg;
15322 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
15325 if(this.labelmd > 0){
15326 labelCfg.cls += ' col-md-' + this.labelmd;
15327 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
15330 if(this.labelsm > 0){
15331 labelCfg.cls += ' col-sm-' + this.labelsm;
15332 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
15335 if(this.labelxs > 0){
15336 labelCfg.cls += ' col-xs-' + this.labelxs;
15337 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
15341 } else if ( this.fieldLabel.length) {
15342 // Roo.log(" label");
15347 //cls : 'input-group-addon',
15348 html : this.fieldLabel
15353 if(this.indicatorpos == 'right'){
15357 //cls : 'input-group-addon',
15358 html : this.fieldLabel
15368 // Roo.log(" no label && no align");
15375 ['xs','sm','md','lg'].map(function(size){
15376 if (settings[size]) {
15377 cfg.cls += ' col-' + size + '-' + settings[size];
15385 _initEventsCalled : false,
15388 initEvents: function()
15390 if (this._initEventsCalled) { // as we call render... prevent looping...
15393 this._initEventsCalled = true;
15396 throw "can not find store for combo";
15399 this.indicator = this.indicatorEl();
15401 this.store = Roo.factory(this.store, Roo.data);
15402 this.store.parent = this;
15404 // if we are building from html. then this element is so complex, that we can not really
15405 // use the rendered HTML.
15406 // so we have to trash and replace the previous code.
15407 if (Roo.XComponent.build_from_html) {
15408 // remove this element....
15409 var e = this.el.dom, k=0;
15410 while (e ) { e = e.previousSibling; ++k;}
15415 this.rendered = false;
15417 this.render(this.parent().getChildContainer(true), k);
15420 if(Roo.isIOS && this.useNativeIOS){
15421 this.initIOSView();
15429 if(Roo.isTouch && this.mobileTouchView){
15430 this.initTouchView();
15435 this.initTickableEvents();
15439 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
15441 if(this.hiddenName){
15443 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
15445 this.hiddenField.dom.value =
15446 this.hiddenValue !== undefined ? this.hiddenValue :
15447 this.value !== undefined ? this.value : '';
15449 // prevent input submission
15450 this.el.dom.removeAttribute('name');
15451 this.hiddenField.dom.setAttribute('name', this.hiddenName);
15456 // this.el.dom.setAttribute('autocomplete', 'off');
15459 var cls = 'x-combo-list';
15461 //this.list = new Roo.Layer({
15462 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
15468 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
15469 _this.list.setWidth(lw);
15472 this.list.on('mouseover', this.onViewOver, this);
15473 this.list.on('mousemove', this.onViewMove, this);
15474 this.list.on('scroll', this.onViewScroll, this);
15477 this.list.swallowEvent('mousewheel');
15478 this.assetHeight = 0;
15481 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
15482 this.assetHeight += this.header.getHeight();
15485 this.innerList = this.list.createChild({cls:cls+'-inner'});
15486 this.innerList.on('mouseover', this.onViewOver, this);
15487 this.innerList.on('mousemove', this.onViewMove, this);
15488 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
15490 if(this.allowBlank && !this.pageSize && !this.disableClear){
15491 this.footer = this.list.createChild({cls:cls+'-ft'});
15492 this.pageTb = new Roo.Toolbar(this.footer);
15496 this.footer = this.list.createChild({cls:cls+'-ft'});
15497 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
15498 {pageSize: this.pageSize});
15502 if (this.pageTb && this.allowBlank && !this.disableClear) {
15504 this.pageTb.add(new Roo.Toolbar.Fill(), {
15505 cls: 'x-btn-icon x-btn-clear',
15507 handler: function()
15510 _this.clearValue();
15511 _this.onSelect(false, -1);
15516 this.assetHeight += this.footer.getHeight();
15521 this.tpl = Roo.bootstrap.version == 4 ?
15522 '<a class="dropdown-item" href="#">{' + this.displayField + '}</a>' : // 4 does not need <li> and it get's really confisued.
15523 '<li><a class="dropdown-item" href="#">{' + this.displayField + '}</a></li>';
15526 this.view = new Roo.View(this.list, this.tpl, {
15527 singleSelect:true, store: this.store, selectedClass: this.selectedClass
15529 //this.view.wrapEl.setDisplayed(false);
15530 this.view.on('click', this.onViewClick, this);
15533 this.store.on('beforeload', this.onBeforeLoad, this);
15534 this.store.on('load', this.onLoad, this);
15535 this.store.on('loadexception', this.onLoadException, this);
15537 if(this.resizable){
15538 this.resizer = new Roo.Resizable(this.list, {
15539 pinned:true, handles:'se'
15541 this.resizer.on('resize', function(r, w, h){
15542 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
15543 this.listWidth = w;
15544 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
15545 this.restrictHeight();
15547 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
15550 if(!this.editable){
15551 this.editable = true;
15552 this.setEditable(false);
15557 if (typeof(this.events.add.listeners) != 'undefined') {
15559 this.addicon = this.wrap.createChild(
15560 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
15562 this.addicon.on('click', function(e) {
15563 this.fireEvent('add', this);
15566 if (typeof(this.events.edit.listeners) != 'undefined') {
15568 this.editicon = this.wrap.createChild(
15569 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
15570 if (this.addicon) {
15571 this.editicon.setStyle('margin-left', '40px');
15573 this.editicon.on('click', function(e) {
15575 // we fire even if inothing is selected..
15576 this.fireEvent('edit', this, this.lastData );
15582 this.keyNav = new Roo.KeyNav(this.inputEl(), {
15583 "up" : function(e){
15584 this.inKeyMode = true;
15588 "down" : function(e){
15589 if(!this.isExpanded()){
15590 this.onTriggerClick();
15592 this.inKeyMode = true;
15597 "enter" : function(e){
15598 // this.onViewClick();
15602 if(this.fireEvent("specialkey", this, e)){
15603 this.onViewClick(false);
15609 "esc" : function(e){
15613 "tab" : function(e){
15616 if(this.fireEvent("specialkey", this, e)){
15617 this.onViewClick(false);
15625 doRelay : function(foo, bar, hname){
15626 if(hname == 'down' || this.scope.isExpanded()){
15627 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
15636 this.queryDelay = Math.max(this.queryDelay || 10,
15637 this.mode == 'local' ? 10 : 250);
15640 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
15642 if(this.typeAhead){
15643 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
15645 if(this.editable !== false){
15646 this.inputEl().on("keyup", this.onKeyUp, this);
15648 if(this.forceSelection){
15649 this.inputEl().on('blur', this.doForce, this);
15653 this.choices = this.el.select('ul.roo-select2-choices', true).first();
15654 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
15658 initTickableEvents: function()
15662 if(this.hiddenName){
15664 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
15666 this.hiddenField.dom.value =
15667 this.hiddenValue !== undefined ? this.hiddenValue :
15668 this.value !== undefined ? this.value : '';
15670 // prevent input submission
15671 this.el.dom.removeAttribute('name');
15672 this.hiddenField.dom.setAttribute('name', this.hiddenName);
15677 // this.list = this.el.select('ul.dropdown-menu',true).first();
15679 this.choices = this.el.select('ul.roo-select2-choices', true).first();
15680 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
15681 if(this.triggerList){
15682 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
15685 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
15686 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
15688 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
15689 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
15691 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
15692 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
15694 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
15695 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
15696 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
15699 this.cancelBtn.hide();
15704 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
15705 _this.list.setWidth(lw);
15708 this.list.on('mouseover', this.onViewOver, this);
15709 this.list.on('mousemove', this.onViewMove, this);
15711 this.list.on('scroll', this.onViewScroll, this);
15714 this.tpl = '<li class="roo-select2-result"><div class="checkbox"><input id="{roo-id}"' +
15715 'type="checkbox" {roo-data-checked}><label for="{roo-id}"><b>{' + this.displayField + '}</b></label></div></li>';
15718 this.view = new Roo.View(this.list, this.tpl, {
15723 selectedClass: this.selectedClass
15726 //this.view.wrapEl.setDisplayed(false);
15727 this.view.on('click', this.onViewClick, this);
15731 this.store.on('beforeload', this.onBeforeLoad, this);
15732 this.store.on('load', this.onLoad, this);
15733 this.store.on('loadexception', this.onLoadException, this);
15736 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
15737 "up" : function(e){
15738 this.inKeyMode = true;
15742 "down" : function(e){
15743 this.inKeyMode = true;
15747 "enter" : function(e){
15748 if(this.fireEvent("specialkey", this, e)){
15749 this.onViewClick(false);
15755 "esc" : function(e){
15756 this.onTickableFooterButtonClick(e, false, false);
15759 "tab" : function(e){
15760 this.fireEvent("specialkey", this, e);
15762 this.onTickableFooterButtonClick(e, false, false);
15769 doRelay : function(e, fn, key){
15770 if(this.scope.isExpanded()){
15771 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
15780 this.queryDelay = Math.max(this.queryDelay || 10,
15781 this.mode == 'local' ? 10 : 250);
15784 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
15786 if(this.typeAhead){
15787 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
15790 if(this.editable !== false){
15791 this.tickableInputEl().on("keyup", this.onKeyUp, this);
15794 this.indicator = this.indicatorEl();
15796 if(this.indicator){
15797 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
15798 this.indicator.hide();
15803 onDestroy : function(){
15805 this.view.setStore(null);
15806 this.view.el.removeAllListeners();
15807 this.view.el.remove();
15808 this.view.purgeListeners();
15811 this.list.dom.innerHTML = '';
15815 this.store.un('beforeload', this.onBeforeLoad, this);
15816 this.store.un('load', this.onLoad, this);
15817 this.store.un('loadexception', this.onLoadException, this);
15819 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
15823 fireKey : function(e){
15824 if(e.isNavKeyPress() && !this.list.isVisible()){
15825 this.fireEvent("specialkey", this, e);
15830 onResize: function(w, h)
15834 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
15836 // if(typeof w != 'number'){
15837 // // we do not handle it!?!?
15840 // var tw = this.trigger.getWidth();
15841 // // tw += this.addicon ? this.addicon.getWidth() : 0;
15842 // // tw += this.editicon ? this.editicon.getWidth() : 0;
15844 // this.inputEl().setWidth( this.adjustWidth('input', x));
15846 // //this.trigger.setStyle('left', x+'px');
15848 // if(this.list && this.listWidth === undefined){
15849 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
15850 // this.list.setWidth(lw);
15851 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
15859 * Allow or prevent the user from directly editing the field text. If false is passed,
15860 * the user will only be able to select from the items defined in the dropdown list. This method
15861 * is the runtime equivalent of setting the 'editable' config option at config time.
15862 * @param {Boolean} value True to allow the user to directly edit the field text
15864 setEditable : function(value){
15865 if(value == this.editable){
15868 this.editable = value;
15870 this.inputEl().dom.setAttribute('readOnly', true);
15871 this.inputEl().on('mousedown', this.onTriggerClick, this);
15872 this.inputEl().addClass('x-combo-noedit');
15874 this.inputEl().dom.setAttribute('readOnly', false);
15875 this.inputEl().un('mousedown', this.onTriggerClick, this);
15876 this.inputEl().removeClass('x-combo-noedit');
15882 onBeforeLoad : function(combo,opts){
15883 if(!this.hasFocus){
15887 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
15889 this.restrictHeight();
15890 this.selectedIndex = -1;
15894 onLoad : function(){
15896 this.hasQuery = false;
15898 if(!this.hasFocus){
15902 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
15903 this.loading.hide();
15906 if(this.store.getCount() > 0){
15909 this.restrictHeight();
15910 if(this.lastQuery == this.allQuery){
15911 if(this.editable && !this.tickable){
15912 this.inputEl().dom.select();
15916 !this.selectByValue(this.value, true) &&
15919 !this.store.lastOptions ||
15920 typeof(this.store.lastOptions.add) == 'undefined' ||
15921 this.store.lastOptions.add != true
15924 this.select(0, true);
15927 if(this.autoFocus){
15930 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
15931 this.taTask.delay(this.typeAheadDelay);
15935 this.onEmptyResults();
15941 onLoadException : function()
15943 this.hasQuery = false;
15945 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
15946 this.loading.hide();
15949 if(this.tickable && this.editable){
15954 // only causes errors at present
15955 //Roo.log(this.store.reader.jsonData);
15956 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
15958 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
15964 onTypeAhead : function(){
15965 if(this.store.getCount() > 0){
15966 var r = this.store.getAt(0);
15967 var newValue = r.data[this.displayField];
15968 var len = newValue.length;
15969 var selStart = this.getRawValue().length;
15971 if(selStart != len){
15972 this.setRawValue(newValue);
15973 this.selectText(selStart, newValue.length);
15979 onSelect : function(record, index){
15981 if(this.fireEvent('beforeselect', this, record, index) !== false){
15983 this.setFromData(index > -1 ? record.data : false);
15986 this.fireEvent('select', this, record, index);
15991 * Returns the currently selected field value or empty string if no value is set.
15992 * @return {String} value The selected value
15994 getValue : function()
15996 if(Roo.isIOS && this.useNativeIOS){
15997 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
16001 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
16004 if(this.valueField){
16005 return typeof this.value != 'undefined' ? this.value : '';
16007 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
16011 getRawValue : function()
16013 if(Roo.isIOS && this.useNativeIOS){
16014 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
16017 var v = this.inputEl().getValue();
16023 * Clears any text/value currently set in the field
16025 clearValue : function(){
16027 if(this.hiddenField){
16028 this.hiddenField.dom.value = '';
16031 this.setRawValue('');
16032 this.lastSelectionText = '';
16033 this.lastData = false;
16035 var close = this.closeTriggerEl();
16046 * Sets the specified value into the field. If the value finds a match, the corresponding record text
16047 * will be displayed in the field. If the value does not match the data value of an existing item,
16048 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
16049 * Otherwise the field will be blank (although the value will still be set).
16050 * @param {String} value The value to match
16052 setValue : function(v)
16054 if(Roo.isIOS && this.useNativeIOS){
16055 this.setIOSValue(v);
16065 if(this.valueField){
16066 var r = this.findRecord(this.valueField, v);
16068 text = r.data[this.displayField];
16069 }else if(this.valueNotFoundText !== undefined){
16070 text = this.valueNotFoundText;
16073 this.lastSelectionText = text;
16074 if(this.hiddenField){
16075 this.hiddenField.dom.value = v;
16077 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
16080 var close = this.closeTriggerEl();
16083 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
16089 * @property {Object} the last set data for the element
16094 * Sets the value of the field based on a object which is related to the record format for the store.
16095 * @param {Object} value the value to set as. or false on reset?
16097 setFromData : function(o){
16104 var dv = ''; // display value
16105 var vv = ''; // value value..
16107 if (this.displayField) {
16108 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
16110 // this is an error condition!!!
16111 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
16114 if(this.valueField){
16115 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
16118 var close = this.closeTriggerEl();
16121 if(dv.length || vv * 1 > 0){
16123 this.blockFocus=true;
16129 if(this.hiddenField){
16130 this.hiddenField.dom.value = vv;
16132 this.lastSelectionText = dv;
16133 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
16137 // no hidden field.. - we store the value in 'value', but still display
16138 // display field!!!!
16139 this.lastSelectionText = dv;
16140 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
16147 reset : function(){
16148 // overridden so that last data is reset..
16155 this.setValue(this.originalValue);
16156 //this.clearInvalid();
16157 this.lastData = false;
16159 this.view.clearSelections();
16165 findRecord : function(prop, value){
16167 if(this.store.getCount() > 0){
16168 this.store.each(function(r){
16169 if(r.data[prop] == value){
16179 getName: function()
16181 // returns hidden if it's set..
16182 if (!this.rendered) {return ''};
16183 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
16187 onViewMove : function(e, t){
16188 this.inKeyMode = false;
16192 onViewOver : function(e, t){
16193 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
16196 var item = this.view.findItemFromChild(t);
16199 var index = this.view.indexOf(item);
16200 this.select(index, false);
16205 onViewClick : function(view, doFocus, el, e)
16207 var index = this.view.getSelectedIndexes()[0];
16209 var r = this.store.getAt(index);
16213 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
16220 Roo.each(this.tickItems, function(v,k){
16222 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
16224 _this.tickItems.splice(k, 1);
16226 if(typeof(e) == 'undefined' && view == false){
16227 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
16239 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
16240 this.tickItems.push(r.data);
16243 if(typeof(e) == 'undefined' && view == false){
16244 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
16251 this.onSelect(r, index);
16253 if(doFocus !== false && !this.blockFocus){
16254 this.inputEl().focus();
16259 restrictHeight : function(){
16260 //this.innerList.dom.style.height = '';
16261 //var inner = this.innerList.dom;
16262 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
16263 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
16264 //this.list.beginUpdate();
16265 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
16266 this.list.alignTo(this.inputEl(), this.listAlign);
16267 this.list.alignTo(this.inputEl(), this.listAlign);
16268 //this.list.endUpdate();
16272 onEmptyResults : function(){
16274 if(this.tickable && this.editable){
16275 this.hasFocus = false;
16276 this.restrictHeight();
16284 * Returns true if the dropdown list is expanded, else false.
16286 isExpanded : function(){
16287 return this.list.isVisible();
16291 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
16292 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
16293 * @param {String} value The data value of the item to select
16294 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
16295 * selected item if it is not currently in view (defaults to true)
16296 * @return {Boolean} True if the value matched an item in the list, else false
16298 selectByValue : function(v, scrollIntoView){
16299 if(v !== undefined && v !== null){
16300 var r = this.findRecord(this.valueField || this.displayField, v);
16302 this.select(this.store.indexOf(r), scrollIntoView);
16310 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
16311 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
16312 * @param {Number} index The zero-based index of the list item to select
16313 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
16314 * selected item if it is not currently in view (defaults to true)
16316 select : function(index, scrollIntoView){
16317 this.selectedIndex = index;
16318 this.view.select(index);
16319 if(scrollIntoView !== false){
16320 var el = this.view.getNode(index);
16322 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
16325 this.list.scrollChildIntoView(el, false);
16331 selectNext : function(){
16332 var ct = this.store.getCount();
16334 if(this.selectedIndex == -1){
16336 }else if(this.selectedIndex < ct-1){
16337 this.select(this.selectedIndex+1);
16343 selectPrev : function(){
16344 var ct = this.store.getCount();
16346 if(this.selectedIndex == -1){
16348 }else if(this.selectedIndex != 0){
16349 this.select(this.selectedIndex-1);
16355 onKeyUp : function(e){
16356 if(this.editable !== false && !e.isSpecialKey()){
16357 this.lastKey = e.getKey();
16358 this.dqTask.delay(this.queryDelay);
16363 validateBlur : function(){
16364 return !this.list || !this.list.isVisible();
16368 initQuery : function(){
16370 var v = this.getRawValue();
16372 if(this.tickable && this.editable){
16373 v = this.tickableInputEl().getValue();
16380 doForce : function(){
16381 if(this.inputEl().dom.value.length > 0){
16382 this.inputEl().dom.value =
16383 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
16389 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
16390 * query allowing the query action to be canceled if needed.
16391 * @param {String} query The SQL query to execute
16392 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
16393 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
16394 * saved in the current store (defaults to false)
16396 doQuery : function(q, forceAll){
16398 if(q === undefined || q === null){
16403 forceAll: forceAll,
16407 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
16412 forceAll = qe.forceAll;
16413 if(forceAll === true || (q.length >= this.minChars)){
16415 this.hasQuery = true;
16417 if(this.lastQuery != q || this.alwaysQuery){
16418 this.lastQuery = q;
16419 if(this.mode == 'local'){
16420 this.selectedIndex = -1;
16422 this.store.clearFilter();
16425 if(this.specialFilter){
16426 this.fireEvent('specialfilter', this);
16431 this.store.filter(this.displayField, q);
16434 this.store.fireEvent("datachanged", this.store);
16441 this.store.baseParams[this.queryParam] = q;
16443 var options = {params : this.getParams(q)};
16446 options.add = true;
16447 options.params.start = this.page * this.pageSize;
16450 this.store.load(options);
16453 * this code will make the page width larger, at the beginning, the list not align correctly,
16454 * we should expand the list on onLoad
16455 * so command out it
16460 this.selectedIndex = -1;
16465 this.loadNext = false;
16469 getParams : function(q){
16471 //p[this.queryParam] = q;
16475 p.limit = this.pageSize;
16481 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
16483 collapse : function(){
16484 if(!this.isExpanded()){
16490 this.hasFocus = false;
16494 this.cancelBtn.hide();
16495 this.trigger.show();
16498 this.tickableInputEl().dom.value = '';
16499 this.tickableInputEl().blur();
16504 Roo.get(document).un('mousedown', this.collapseIf, this);
16505 Roo.get(document).un('mousewheel', this.collapseIf, this);
16506 if (!this.editable) {
16507 Roo.get(document).un('keydown', this.listKeyPress, this);
16509 this.fireEvent('collapse', this);
16515 collapseIf : function(e){
16516 var in_combo = e.within(this.el);
16517 var in_list = e.within(this.list);
16518 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
16520 if (in_combo || in_list || is_list) {
16521 //e.stopPropagation();
16526 this.onTickableFooterButtonClick(e, false, false);
16534 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
16536 expand : function(){
16538 if(this.isExpanded() || !this.hasFocus){
16542 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
16543 this.list.setWidth(lw);
16549 this.restrictHeight();
16553 this.tickItems = Roo.apply([], this.item);
16556 this.cancelBtn.show();
16557 this.trigger.hide();
16560 this.tickableInputEl().focus();
16565 Roo.get(document).on('mousedown', this.collapseIf, this);
16566 Roo.get(document).on('mousewheel', this.collapseIf, this);
16567 if (!this.editable) {
16568 Roo.get(document).on('keydown', this.listKeyPress, this);
16571 this.fireEvent('expand', this);
16575 // Implements the default empty TriggerField.onTriggerClick function
16576 onTriggerClick : function(e)
16578 Roo.log('trigger click');
16580 if(this.disabled || !this.triggerList){
16585 this.loadNext = false;
16587 if(this.isExpanded()){
16589 if (!this.blockFocus) {
16590 this.inputEl().focus();
16594 this.hasFocus = true;
16595 if(this.triggerAction == 'all') {
16596 this.doQuery(this.allQuery, true);
16598 this.doQuery(this.getRawValue());
16600 if (!this.blockFocus) {
16601 this.inputEl().focus();
16606 onTickableTriggerClick : function(e)
16613 this.loadNext = false;
16614 this.hasFocus = true;
16616 if(this.triggerAction == 'all') {
16617 this.doQuery(this.allQuery, true);
16619 this.doQuery(this.getRawValue());
16623 onSearchFieldClick : function(e)
16625 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
16626 this.onTickableFooterButtonClick(e, false, false);
16630 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
16635 this.loadNext = false;
16636 this.hasFocus = true;
16638 if(this.triggerAction == 'all') {
16639 this.doQuery(this.allQuery, true);
16641 this.doQuery(this.getRawValue());
16645 listKeyPress : function(e)
16647 //Roo.log('listkeypress');
16648 // scroll to first matching element based on key pres..
16649 if (e.isSpecialKey()) {
16652 var k = String.fromCharCode(e.getKey()).toUpperCase();
16655 var csel = this.view.getSelectedNodes();
16656 var cselitem = false;
16658 var ix = this.view.indexOf(csel[0]);
16659 cselitem = this.store.getAt(ix);
16660 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
16666 this.store.each(function(v) {
16668 // start at existing selection.
16669 if (cselitem.id == v.id) {
16675 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
16676 match = this.store.indexOf(v);
16682 if (match === false) {
16683 return true; // no more action?
16686 this.view.select(match);
16687 var sn = Roo.get(this.view.getSelectedNodes()[0]);
16688 sn.scrollIntoView(sn.dom.parentNode, false);
16691 onViewScroll : function(e, t){
16693 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){
16697 this.hasQuery = true;
16699 this.loading = this.list.select('.loading', true).first();
16701 if(this.loading === null){
16702 this.list.createChild({
16704 cls: 'loading roo-select2-more-results roo-select2-active',
16705 html: 'Loading more results...'
16708 this.loading = this.list.select('.loading', true).first();
16710 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
16712 this.loading.hide();
16715 this.loading.show();
16720 this.loadNext = true;
16722 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
16727 addItem : function(o)
16729 var dv = ''; // display value
16731 if (this.displayField) {
16732 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
16734 // this is an error condition!!!
16735 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
16742 var choice = this.choices.createChild({
16744 cls: 'roo-select2-search-choice',
16753 cls: 'roo-select2-search-choice-close fa fa-times',
16758 }, this.searchField);
16760 var close = choice.select('a.roo-select2-search-choice-close', true).first();
16762 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
16770 this.inputEl().dom.value = '';
16775 onRemoveItem : function(e, _self, o)
16777 e.preventDefault();
16779 this.lastItem = Roo.apply([], this.item);
16781 var index = this.item.indexOf(o.data) * 1;
16784 Roo.log('not this item?!');
16788 this.item.splice(index, 1);
16793 this.fireEvent('remove', this, e);
16799 syncValue : function()
16801 if(!this.item.length){
16808 Roo.each(this.item, function(i){
16809 if(_this.valueField){
16810 value.push(i[_this.valueField]);
16817 this.value = value.join(',');
16819 if(this.hiddenField){
16820 this.hiddenField.dom.value = this.value;
16823 this.store.fireEvent("datachanged", this.store);
16828 clearItem : function()
16830 if(!this.multiple){
16836 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
16844 if(this.tickable && !Roo.isTouch){
16845 this.view.refresh();
16849 inputEl: function ()
16851 if(Roo.isIOS && this.useNativeIOS){
16852 return this.el.select('select.roo-ios-select', true).first();
16855 if(Roo.isTouch && this.mobileTouchView){
16856 return this.el.select('input.form-control',true).first();
16860 return this.searchField;
16863 return this.el.select('input.form-control',true).first();
16866 onTickableFooterButtonClick : function(e, btn, el)
16868 e.preventDefault();
16870 this.lastItem = Roo.apply([], this.item);
16872 if(btn && btn.name == 'cancel'){
16873 this.tickItems = Roo.apply([], this.item);
16882 Roo.each(this.tickItems, function(o){
16890 validate : function()
16892 if(this.getVisibilityEl().hasClass('hidden')){
16896 var v = this.getRawValue();
16899 v = this.getValue();
16902 if(this.disabled || this.allowBlank || v.length){
16907 this.markInvalid();
16911 tickableInputEl : function()
16913 if(!this.tickable || !this.editable){
16914 return this.inputEl();
16917 return this.inputEl().select('.roo-select2-search-field-input', true).first();
16921 getAutoCreateTouchView : function()
16926 cls: 'form-group' //input-group
16932 type : this.inputType,
16933 cls : 'form-control x-combo-noedit',
16934 autocomplete: 'new-password',
16935 placeholder : this.placeholder || '',
16940 input.name = this.name;
16944 input.cls += ' input-' + this.size;
16947 if (this.disabled) {
16948 input.disabled = true;
16952 cls : 'roo-combobox-wrap',
16959 inputblock.cls += ' input-group';
16961 inputblock.cn.unshift({
16963 cls : 'input-group-addon input-group-prepend input-group-text',
16968 if(this.removable && !this.multiple){
16969 inputblock.cls += ' roo-removable';
16971 inputblock.cn.push({
16974 cls : 'roo-combo-removable-btn close'
16978 if(this.hasFeedback && !this.allowBlank){
16980 inputblock.cls += ' has-feedback';
16982 inputblock.cn.push({
16984 cls: 'glyphicon form-control-feedback'
16991 inputblock.cls += (this.before) ? '' : ' input-group';
16993 inputblock.cn.push({
16995 cls : 'input-group-addon input-group-append input-group-text',
17001 var ibwrap = inputblock;
17006 cls: 'roo-select2-choices',
17010 cls: 'roo-select2-search-field',
17023 cls: 'roo-select2-container input-group roo-touchview-combobox ',
17028 cls: 'form-hidden-field'
17034 if(!this.multiple && this.showToggleBtn){
17040 if (this.caret != false) {
17043 cls: 'fa fa-' + this.caret
17050 cls : 'input-group-addon input-group-append input-group-text btn dropdown-toggle',
17052 Roo.bootstrap.version == 3 ? caret : '',
17055 cls: 'combobox-clear',
17069 combobox.cls += ' roo-select2-container-multi';
17072 var align = this.labelAlign || this.parentLabelAlign();
17074 if (align ==='left' && this.fieldLabel.length) {
17079 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
17080 tooltip : 'This field is required'
17084 cls : 'control-label col-form-label',
17085 html : this.fieldLabel
17089 cls : 'roo-combobox-wrap ',
17096 var labelCfg = cfg.cn[1];
17097 var contentCfg = cfg.cn[2];
17100 if(this.indicatorpos == 'right'){
17105 cls : 'control-label col-form-label',
17109 html : this.fieldLabel
17113 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
17114 tooltip : 'This field is required'
17119 cls : "roo-combobox-wrap ",
17127 labelCfg = cfg.cn[0];
17128 contentCfg = cfg.cn[1];
17133 if(this.labelWidth > 12){
17134 labelCfg.style = "width: " + this.labelWidth + 'px';
17137 if(this.labelWidth < 13 && this.labelmd == 0){
17138 this.labelmd = this.labelWidth;
17141 if(this.labellg > 0){
17142 labelCfg.cls += ' col-lg-' + this.labellg;
17143 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
17146 if(this.labelmd > 0){
17147 labelCfg.cls += ' col-md-' + this.labelmd;
17148 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
17151 if(this.labelsm > 0){
17152 labelCfg.cls += ' col-sm-' + this.labelsm;
17153 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
17156 if(this.labelxs > 0){
17157 labelCfg.cls += ' col-xs-' + this.labelxs;
17158 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
17162 } else if ( this.fieldLabel.length) {
17166 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
17167 tooltip : 'This field is required'
17171 cls : 'control-label',
17172 html : this.fieldLabel
17183 if(this.indicatorpos == 'right'){
17187 cls : 'control-label',
17188 html : this.fieldLabel,
17192 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
17193 tooltip : 'This field is required'
17210 var settings = this;
17212 ['xs','sm','md','lg'].map(function(size){
17213 if (settings[size]) {
17214 cfg.cls += ' col-' + size + '-' + settings[size];
17221 initTouchView : function()
17223 this.renderTouchView();
17225 this.touchViewEl.on('scroll', function(){
17226 this.el.dom.scrollTop = 0;
17229 this.originalValue = this.getValue();
17231 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
17233 this.inputEl().on("click", this.showTouchView, this);
17234 if (this.triggerEl) {
17235 this.triggerEl.on("click", this.showTouchView, this);
17239 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
17240 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
17242 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
17244 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
17245 this.store.on('load', this.onTouchViewLoad, this);
17246 this.store.on('loadexception', this.onTouchViewLoadException, this);
17248 if(this.hiddenName){
17250 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
17252 this.hiddenField.dom.value =
17253 this.hiddenValue !== undefined ? this.hiddenValue :
17254 this.value !== undefined ? this.value : '';
17256 this.el.dom.removeAttribute('name');
17257 this.hiddenField.dom.setAttribute('name', this.hiddenName);
17261 this.choices = this.el.select('ul.roo-select2-choices', true).first();
17262 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
17265 if(this.removable && !this.multiple){
17266 var close = this.closeTriggerEl();
17268 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
17269 close.on('click', this.removeBtnClick, this, close);
17273 * fix the bug in Safari iOS8
17275 this.inputEl().on("focus", function(e){
17276 document.activeElement.blur();
17279 this._touchViewMask = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
17286 renderTouchView : function()
17288 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
17289 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
17291 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
17292 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
17294 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
17295 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
17296 this.touchViewBodyEl.setStyle('overflow', 'auto');
17298 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
17299 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
17301 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
17302 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
17306 showTouchView : function()
17312 this.touchViewHeaderEl.hide();
17314 if(this.modalTitle.length){
17315 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
17316 this.touchViewHeaderEl.show();
17319 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
17320 this.touchViewEl.show();
17322 this.touchViewEl.select('.modal-dialog', true).first().setStyle({ margin : '0px', width : '100%'});
17324 //this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
17325 // Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
17327 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
17329 if(this.modalTitle.length){
17330 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
17333 this.touchViewBodyEl.setHeight(bodyHeight);
17337 (function(){ _this.touchViewEl.addClass(['in','show']); }).defer(50);
17339 this.touchViewEl.addClass(['in','show']);
17342 if(this._touchViewMask){
17343 Roo.get(document.body).addClass("x-body-masked");
17344 this._touchViewMask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
17345 this._touchViewMask.setStyle('z-index', 10000);
17346 this._touchViewMask.addClass('show');
17349 this.doTouchViewQuery();
17353 hideTouchView : function()
17355 this.touchViewEl.removeClass(['in','show']);
17359 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
17361 this.touchViewEl.setStyle('display', 'none');
17364 if(this._touchViewMask){
17365 this._touchViewMask.removeClass('show');
17366 Roo.get(document.body).removeClass("x-body-masked");
17370 setTouchViewValue : function()
17377 Roo.each(this.tickItems, function(o){
17382 this.hideTouchView();
17385 doTouchViewQuery : function()
17394 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
17398 if(!this.alwaysQuery || this.mode == 'local'){
17399 this.onTouchViewLoad();
17406 onTouchViewBeforeLoad : function(combo,opts)
17412 onTouchViewLoad : function()
17414 if(this.store.getCount() < 1){
17415 this.onTouchViewEmptyResults();
17419 this.clearTouchView();
17421 var rawValue = this.getRawValue();
17423 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
17425 this.tickItems = [];
17427 this.store.data.each(function(d, rowIndex){
17428 var row = this.touchViewListGroup.createChild(template);
17430 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
17431 row.addClass(d.data.cls);
17434 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
17437 html : d.data[this.displayField]
17440 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
17441 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
17444 row.removeClass('selected');
17445 if(!this.multiple && this.valueField &&
17446 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
17449 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
17450 row.addClass('selected');
17453 if(this.multiple && this.valueField &&
17454 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
17458 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
17459 this.tickItems.push(d.data);
17462 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
17466 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
17468 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
17470 if(this.modalTitle.length){
17471 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
17474 var listHeight = this.touchViewListGroup.getHeight() + this.touchViewBodyEl.getPadding('tb') * 2;
17476 if(this.mobile_restrict_height && listHeight < bodyHeight){
17477 this.touchViewBodyEl.setHeight(listHeight);
17482 if(firstChecked && listHeight > bodyHeight){
17483 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
17488 onTouchViewLoadException : function()
17490 this.hideTouchView();
17493 onTouchViewEmptyResults : function()
17495 this.clearTouchView();
17497 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
17499 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
17503 clearTouchView : function()
17505 this.touchViewListGroup.dom.innerHTML = '';
17508 onTouchViewClick : function(e, el, o)
17510 e.preventDefault();
17513 var rowIndex = o.rowIndex;
17515 var r = this.store.getAt(rowIndex);
17517 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
17519 if(!this.multiple){
17520 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
17521 c.dom.removeAttribute('checked');
17524 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
17526 this.setFromData(r.data);
17528 var close = this.closeTriggerEl();
17534 this.hideTouchView();
17536 this.fireEvent('select', this, r, rowIndex);
17541 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
17542 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
17543 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
17547 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
17548 this.addItem(r.data);
17549 this.tickItems.push(r.data);
17553 getAutoCreateNativeIOS : function()
17556 cls: 'form-group' //input-group,
17561 cls : 'roo-ios-select'
17565 combobox.name = this.name;
17568 if (this.disabled) {
17569 combobox.disabled = true;
17572 var settings = this;
17574 ['xs','sm','md','lg'].map(function(size){
17575 if (settings[size]) {
17576 cfg.cls += ' col-' + size + '-' + settings[size];
17586 initIOSView : function()
17588 this.store.on('load', this.onIOSViewLoad, this);
17593 onIOSViewLoad : function()
17595 if(this.store.getCount() < 1){
17599 this.clearIOSView();
17601 if(this.allowBlank) {
17603 var default_text = '-- SELECT --';
17605 if(this.placeholder.length){
17606 default_text = this.placeholder;
17609 if(this.emptyTitle.length){
17610 default_text += ' - ' + this.emptyTitle + ' -';
17613 var opt = this.inputEl().createChild({
17616 html : default_text
17620 o[this.valueField] = 0;
17621 o[this.displayField] = default_text;
17623 this.ios_options.push({
17630 this.store.data.each(function(d, rowIndex){
17634 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
17635 html = d.data[this.displayField];
17640 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
17641 value = d.data[this.valueField];
17650 if(this.value == d.data[this.valueField]){
17651 option['selected'] = true;
17654 var opt = this.inputEl().createChild(option);
17656 this.ios_options.push({
17663 this.inputEl().on('change', function(){
17664 this.fireEvent('select', this);
17669 clearIOSView: function()
17671 this.inputEl().dom.innerHTML = '';
17673 this.ios_options = [];
17676 setIOSValue: function(v)
17680 if(!this.ios_options){
17684 Roo.each(this.ios_options, function(opts){
17686 opts.el.dom.removeAttribute('selected');
17688 if(opts.data[this.valueField] != v){
17692 opts.el.dom.setAttribute('selected', true);
17698 * @cfg {Boolean} grow
17702 * @cfg {Number} growMin
17706 * @cfg {Number} growMax
17715 Roo.apply(Roo.bootstrap.ComboBox, {
17719 cls: 'modal-header',
17741 cls: 'list-group-item',
17745 cls: 'roo-combobox-list-group-item-value'
17749 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
17763 listItemCheckbox : {
17765 cls: 'list-group-item',
17769 cls: 'roo-combobox-list-group-item-value'
17773 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
17789 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
17794 cls: 'modal-footer',
17802 cls: 'col-xs-6 text-left',
17805 cls: 'btn btn-danger roo-touch-view-cancel',
17811 cls: 'col-xs-6 text-right',
17814 cls: 'btn btn-success roo-touch-view-ok',
17825 Roo.apply(Roo.bootstrap.ComboBox, {
17827 touchViewTemplate : {
17829 cls: 'modal fade roo-combobox-touch-view',
17833 cls: 'modal-dialog',
17834 style : 'position:fixed', // we have to fix position....
17838 cls: 'modal-content',
17840 Roo.bootstrap.ComboBox.header,
17841 Roo.bootstrap.ComboBox.body,
17842 Roo.bootstrap.ComboBox.footer
17851 * Ext JS Library 1.1.1
17852 * Copyright(c) 2006-2007, Ext JS, LLC.
17854 * Originally Released Under LGPL - original licence link has changed is not relivant.
17857 * <script type="text/javascript">
17862 * @extends Roo.util.Observable
17863 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
17864 * This class also supports single and multi selection modes. <br>
17865 * Create a data model bound view:
17867 var store = new Roo.data.Store(...);
17869 var view = new Roo.View({
17871 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
17873 singleSelect: true,
17874 selectedClass: "ydataview-selected",
17878 // listen for node click?
17879 view.on("click", function(vw, index, node, e){
17880 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
17884 dataModel.load("foobar.xml");
17886 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
17888 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
17889 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
17891 * Note: old style constructor is still suported (container, template, config)
17894 * Create a new View
17895 * @param {Object} config The config object
17898 Roo.View = function(config, depreciated_tpl, depreciated_config){
17900 this.parent = false;
17902 if (typeof(depreciated_tpl) == 'undefined') {
17903 // new way.. - universal constructor.
17904 Roo.apply(this, config);
17905 this.el = Roo.get(this.el);
17908 this.el = Roo.get(config);
17909 this.tpl = depreciated_tpl;
17910 Roo.apply(this, depreciated_config);
17912 this.wrapEl = this.el.wrap().wrap();
17913 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
17916 if(typeof(this.tpl) == "string"){
17917 this.tpl = new Roo.Template(this.tpl);
17919 // support xtype ctors..
17920 this.tpl = new Roo.factory(this.tpl, Roo);
17924 this.tpl.compile();
17929 * @event beforeclick
17930 * Fires before a click is processed. Returns false to cancel the default action.
17931 * @param {Roo.View} this
17932 * @param {Number} index The index of the target node
17933 * @param {HTMLElement} node The target node
17934 * @param {Roo.EventObject} e The raw event object
17936 "beforeclick" : true,
17939 * Fires when a template node is clicked.
17940 * @param {Roo.View} this
17941 * @param {Number} index The index of the target node
17942 * @param {HTMLElement} node The target node
17943 * @param {Roo.EventObject} e The raw event object
17948 * Fires when a template node is double clicked.
17949 * @param {Roo.View} this
17950 * @param {Number} index The index of the target node
17951 * @param {HTMLElement} node The target node
17952 * @param {Roo.EventObject} e The raw event object
17956 * @event contextmenu
17957 * Fires when a template node is right clicked.
17958 * @param {Roo.View} this
17959 * @param {Number} index The index of the target node
17960 * @param {HTMLElement} node The target node
17961 * @param {Roo.EventObject} e The raw event object
17963 "contextmenu" : true,
17965 * @event selectionchange
17966 * Fires when the selected nodes change.
17967 * @param {Roo.View} this
17968 * @param {Array} selections Array of the selected nodes
17970 "selectionchange" : true,
17973 * @event beforeselect
17974 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
17975 * @param {Roo.View} this
17976 * @param {HTMLElement} node The node to be selected
17977 * @param {Array} selections Array of currently selected nodes
17979 "beforeselect" : true,
17981 * @event preparedata
17982 * Fires on every row to render, to allow you to change the data.
17983 * @param {Roo.View} this
17984 * @param {Object} data to be rendered (change this)
17986 "preparedata" : true
17994 "click": this.onClick,
17995 "dblclick": this.onDblClick,
17996 "contextmenu": this.onContextMenu,
18000 this.selections = [];
18002 this.cmp = new Roo.CompositeElementLite([]);
18004 this.store = Roo.factory(this.store, Roo.data);
18005 this.setStore(this.store, true);
18008 if ( this.footer && this.footer.xtype) {
18010 var fctr = this.wrapEl.appendChild(document.createElement("div"));
18012 this.footer.dataSource = this.store;
18013 this.footer.container = fctr;
18014 this.footer = Roo.factory(this.footer, Roo);
18015 fctr.insertFirst(this.el);
18017 // this is a bit insane - as the paging toolbar seems to detach the el..
18018 // dom.parentNode.parentNode.parentNode
18019 // they get detached?
18023 Roo.View.superclass.constructor.call(this);
18028 Roo.extend(Roo.View, Roo.util.Observable, {
18031 * @cfg {Roo.data.Store} store Data store to load data from.
18036 * @cfg {String|Roo.Element} el The container element.
18041 * @cfg {String|Roo.Template} tpl The template used by this View
18045 * @cfg {String} dataName the named area of the template to use as the data area
18046 * Works with domtemplates roo-name="name"
18050 * @cfg {String} selectedClass The css class to add to selected nodes
18052 selectedClass : "x-view-selected",
18054 * @cfg {String} emptyText The empty text to show when nothing is loaded.
18059 * @cfg {String} text to display on mask (default Loading)
18063 * @cfg {Boolean} multiSelect Allow multiple selection
18065 multiSelect : false,
18067 * @cfg {Boolean} singleSelect Allow single selection
18069 singleSelect: false,
18072 * @cfg {Boolean} toggleSelect - selecting
18074 toggleSelect : false,
18077 * @cfg {Boolean} tickable - selecting
18082 * Returns the element this view is bound to.
18083 * @return {Roo.Element}
18085 getEl : function(){
18086 return this.wrapEl;
18092 * Refreshes the view. - called by datachanged on the store. - do not call directly.
18094 refresh : function(){
18095 //Roo.log('refresh');
18098 // if we are using something like 'domtemplate', then
18099 // the what gets used is:
18100 // t.applySubtemplate(NAME, data, wrapping data..)
18101 // the outer template then get' applied with
18102 // the store 'extra data'
18103 // and the body get's added to the
18104 // roo-name="data" node?
18105 // <span class='roo-tpl-{name}'></span> ?????
18109 this.clearSelections();
18110 this.el.update("");
18112 var records = this.store.getRange();
18113 if(records.length < 1) {
18115 // is this valid?? = should it render a template??
18117 this.el.update(this.emptyText);
18121 if (this.dataName) {
18122 this.el.update(t.apply(this.store.meta)); //????
18123 el = this.el.child('.roo-tpl-' + this.dataName);
18126 for(var i = 0, len = records.length; i < len; i++){
18127 var data = this.prepareData(records[i].data, i, records[i]);
18128 this.fireEvent("preparedata", this, data, i, records[i]);
18130 var d = Roo.apply({}, data);
18133 Roo.apply(d, {'roo-id' : Roo.id()});
18137 Roo.each(this.parent.item, function(item){
18138 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
18141 Roo.apply(d, {'roo-data-checked' : 'checked'});
18145 html[html.length] = Roo.util.Format.trim(
18147 t.applySubtemplate(this.dataName, d, this.store.meta) :
18154 el.update(html.join(""));
18155 this.nodes = el.dom.childNodes;
18156 this.updateIndexes(0);
18161 * Function to override to reformat the data that is sent to
18162 * the template for each node.
18163 * DEPRICATED - use the preparedata event handler.
18164 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
18165 * a JSON object for an UpdateManager bound view).
18167 prepareData : function(data, index, record)
18169 this.fireEvent("preparedata", this, data, index, record);
18173 onUpdate : function(ds, record){
18174 // Roo.log('on update');
18175 this.clearSelections();
18176 var index = this.store.indexOf(record);
18177 var n = this.nodes[index];
18178 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
18179 n.parentNode.removeChild(n);
18180 this.updateIndexes(index, index);
18186 onAdd : function(ds, records, index)
18188 //Roo.log(['on Add', ds, records, index] );
18189 this.clearSelections();
18190 if(this.nodes.length == 0){
18194 var n = this.nodes[index];
18195 for(var i = 0, len = records.length; i < len; i++){
18196 var d = this.prepareData(records[i].data, i, records[i]);
18198 this.tpl.insertBefore(n, d);
18201 this.tpl.append(this.el, d);
18204 this.updateIndexes(index);
18207 onRemove : function(ds, record, index){
18208 // Roo.log('onRemove');
18209 this.clearSelections();
18210 var el = this.dataName ?
18211 this.el.child('.roo-tpl-' + this.dataName) :
18214 el.dom.removeChild(this.nodes[index]);
18215 this.updateIndexes(index);
18219 * Refresh an individual node.
18220 * @param {Number} index
18222 refreshNode : function(index){
18223 this.onUpdate(this.store, this.store.getAt(index));
18226 updateIndexes : function(startIndex, endIndex){
18227 var ns = this.nodes;
18228 startIndex = startIndex || 0;
18229 endIndex = endIndex || ns.length - 1;
18230 for(var i = startIndex; i <= endIndex; i++){
18231 ns[i].nodeIndex = i;
18236 * Changes the data store this view uses and refresh the view.
18237 * @param {Store} store
18239 setStore : function(store, initial){
18240 if(!initial && this.store){
18241 this.store.un("datachanged", this.refresh);
18242 this.store.un("add", this.onAdd);
18243 this.store.un("remove", this.onRemove);
18244 this.store.un("update", this.onUpdate);
18245 this.store.un("clear", this.refresh);
18246 this.store.un("beforeload", this.onBeforeLoad);
18247 this.store.un("load", this.onLoad);
18248 this.store.un("loadexception", this.onLoad);
18252 store.on("datachanged", this.refresh, this);
18253 store.on("add", this.onAdd, this);
18254 store.on("remove", this.onRemove, this);
18255 store.on("update", this.onUpdate, this);
18256 store.on("clear", this.refresh, this);
18257 store.on("beforeload", this.onBeforeLoad, this);
18258 store.on("load", this.onLoad, this);
18259 store.on("loadexception", this.onLoad, this);
18267 * onbeforeLoad - masks the loading area.
18270 onBeforeLoad : function(store,opts)
18272 //Roo.log('onBeforeLoad');
18274 this.el.update("");
18276 this.el.mask(this.mask ? this.mask : "Loading" );
18278 onLoad : function ()
18285 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
18286 * @param {HTMLElement} node
18287 * @return {HTMLElement} The template node
18289 findItemFromChild : function(node){
18290 var el = this.dataName ?
18291 this.el.child('.roo-tpl-' + this.dataName,true) :
18294 if(!node || node.parentNode == el){
18297 var p = node.parentNode;
18298 while(p && p != el){
18299 if(p.parentNode == el){
18308 onClick : function(e){
18309 var item = this.findItemFromChild(e.getTarget());
18311 var index = this.indexOf(item);
18312 if(this.onItemClick(item, index, e) !== false){
18313 this.fireEvent("click", this, index, item, e);
18316 this.clearSelections();
18321 onContextMenu : function(e){
18322 var item = this.findItemFromChild(e.getTarget());
18324 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
18329 onDblClick : function(e){
18330 var item = this.findItemFromChild(e.getTarget());
18332 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
18336 onItemClick : function(item, index, e)
18338 if(this.fireEvent("beforeclick", this, index, item, e) === false){
18341 if (this.toggleSelect) {
18342 var m = this.isSelected(item) ? 'unselect' : 'select';
18345 _t[m](item, true, false);
18348 if(this.multiSelect || this.singleSelect){
18349 if(this.multiSelect && e.shiftKey && this.lastSelection){
18350 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
18352 this.select(item, this.multiSelect && e.ctrlKey);
18353 this.lastSelection = item;
18356 if(!this.tickable){
18357 e.preventDefault();
18365 * Get the number of selected nodes.
18368 getSelectionCount : function(){
18369 return this.selections.length;
18373 * Get the currently selected nodes.
18374 * @return {Array} An array of HTMLElements
18376 getSelectedNodes : function(){
18377 return this.selections;
18381 * Get the indexes of the selected nodes.
18384 getSelectedIndexes : function(){
18385 var indexes = [], s = this.selections;
18386 for(var i = 0, len = s.length; i < len; i++){
18387 indexes.push(s[i].nodeIndex);
18393 * Clear all selections
18394 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
18396 clearSelections : function(suppressEvent){
18397 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
18398 this.cmp.elements = this.selections;
18399 this.cmp.removeClass(this.selectedClass);
18400 this.selections = [];
18401 if(!suppressEvent){
18402 this.fireEvent("selectionchange", this, this.selections);
18408 * Returns true if the passed node is selected
18409 * @param {HTMLElement/Number} node The node or node index
18410 * @return {Boolean}
18412 isSelected : function(node){
18413 var s = this.selections;
18417 node = this.getNode(node);
18418 return s.indexOf(node) !== -1;
18423 * @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
18424 * @param {Boolean} keepExisting (optional) true to keep existing selections
18425 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
18427 select : function(nodeInfo, keepExisting, suppressEvent){
18428 if(nodeInfo instanceof Array){
18430 this.clearSelections(true);
18432 for(var i = 0, len = nodeInfo.length; i < len; i++){
18433 this.select(nodeInfo[i], true, true);
18437 var node = this.getNode(nodeInfo);
18438 if(!node || this.isSelected(node)){
18439 return; // already selected.
18442 this.clearSelections(true);
18445 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
18446 Roo.fly(node).addClass(this.selectedClass);
18447 this.selections.push(node);
18448 if(!suppressEvent){
18449 this.fireEvent("selectionchange", this, this.selections);
18457 * @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
18458 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
18459 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
18461 unselect : function(nodeInfo, keepExisting, suppressEvent)
18463 if(nodeInfo instanceof Array){
18464 Roo.each(this.selections, function(s) {
18465 this.unselect(s, nodeInfo);
18469 var node = this.getNode(nodeInfo);
18470 if(!node || !this.isSelected(node)){
18471 //Roo.log("not selected");
18472 return; // not selected.
18476 Roo.each(this.selections, function(s) {
18478 Roo.fly(node).removeClass(this.selectedClass);
18485 this.selections= ns;
18486 this.fireEvent("selectionchange", this, this.selections);
18490 * Gets a template node.
18491 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
18492 * @return {HTMLElement} The node or null if it wasn't found
18494 getNode : function(nodeInfo){
18495 if(typeof nodeInfo == "string"){
18496 return document.getElementById(nodeInfo);
18497 }else if(typeof nodeInfo == "number"){
18498 return this.nodes[nodeInfo];
18504 * Gets a range template nodes.
18505 * @param {Number} startIndex
18506 * @param {Number} endIndex
18507 * @return {Array} An array of nodes
18509 getNodes : function(start, end){
18510 var ns = this.nodes;
18511 start = start || 0;
18512 end = typeof end == "undefined" ? ns.length - 1 : end;
18515 for(var i = start; i <= end; i++){
18519 for(var i = start; i >= end; i--){
18527 * Finds the index of the passed node
18528 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
18529 * @return {Number} The index of the node or -1
18531 indexOf : function(node){
18532 node = this.getNode(node);
18533 if(typeof node.nodeIndex == "number"){
18534 return node.nodeIndex;
18536 var ns = this.nodes;
18537 for(var i = 0, len = ns.length; i < len; i++){
18548 * based on jquery fullcalendar
18552 Roo.bootstrap = Roo.bootstrap || {};
18554 * @class Roo.bootstrap.Calendar
18555 * @extends Roo.bootstrap.Component
18556 * Bootstrap Calendar class
18557 * @cfg {Boolean} loadMask (true|false) default false
18558 * @cfg {Object} header generate the user specific header of the calendar, default false
18561 * Create a new Container
18562 * @param {Object} config The config object
18567 Roo.bootstrap.Calendar = function(config){
18568 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
18572 * Fires when a date is selected
18573 * @param {DatePicker} this
18574 * @param {Date} date The selected date
18578 * @event monthchange
18579 * Fires when the displayed month changes
18580 * @param {DatePicker} this
18581 * @param {Date} date The selected month
18583 'monthchange': true,
18585 * @event evententer
18586 * Fires when mouse over an event
18587 * @param {Calendar} this
18588 * @param {event} Event
18590 'evententer': true,
18592 * @event eventleave
18593 * Fires when the mouse leaves an
18594 * @param {Calendar} this
18597 'eventleave': true,
18599 * @event eventclick
18600 * Fires when the mouse click an
18601 * @param {Calendar} this
18610 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
18613 * @cfg {Number} startDay
18614 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
18622 getAutoCreate : function(){
18625 var fc_button = function(name, corner, style, content ) {
18626 return Roo.apply({},{
18628 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
18630 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
18633 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
18644 style : 'width:100%',
18651 cls : 'fc-header-left',
18653 fc_button('prev', 'left', 'arrow', '‹' ),
18654 fc_button('next', 'right', 'arrow', '›' ),
18655 { tag: 'span', cls: 'fc-header-space' },
18656 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
18664 cls : 'fc-header-center',
18668 cls: 'fc-header-title',
18671 html : 'month / year'
18679 cls : 'fc-header-right',
18681 /* fc_button('month', 'left', '', 'month' ),
18682 fc_button('week', '', '', 'week' ),
18683 fc_button('day', 'right', '', 'day' )
18695 header = this.header;
18698 var cal_heads = function() {
18700 // fixme - handle this.
18702 for (var i =0; i < Date.dayNames.length; i++) {
18703 var d = Date.dayNames[i];
18706 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
18707 html : d.substring(0,3)
18711 ret[0].cls += ' fc-first';
18712 ret[6].cls += ' fc-last';
18715 var cal_cell = function(n) {
18718 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
18723 cls: 'fc-day-number',
18727 cls: 'fc-day-content',
18731 style: 'position: relative;' // height: 17px;
18743 var cal_rows = function() {
18746 for (var r = 0; r < 6; r++) {
18753 for (var i =0; i < Date.dayNames.length; i++) {
18754 var d = Date.dayNames[i];
18755 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
18758 row.cn[0].cls+=' fc-first';
18759 row.cn[0].cn[0].style = 'min-height:90px';
18760 row.cn[6].cls+=' fc-last';
18764 ret[0].cls += ' fc-first';
18765 ret[4].cls += ' fc-prev-last';
18766 ret[5].cls += ' fc-last';
18773 cls: 'fc-border-separate',
18774 style : 'width:100%',
18782 cls : 'fc-first fc-last',
18800 cls : 'fc-content',
18801 style : "position: relative;",
18804 cls : 'fc-view fc-view-month fc-grid',
18805 style : 'position: relative',
18806 unselectable : 'on',
18809 cls : 'fc-event-container',
18810 style : 'position:absolute;z-index:8;top:0;left:0;'
18828 initEvents : function()
18831 throw "can not find store for calendar";
18837 style: "text-align:center",
18841 style: "background-color:white;width:50%;margin:250 auto",
18845 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
18856 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
18858 var size = this.el.select('.fc-content', true).first().getSize();
18859 this.maskEl.setSize(size.width, size.height);
18860 this.maskEl.enableDisplayMode("block");
18861 if(!this.loadMask){
18862 this.maskEl.hide();
18865 this.store = Roo.factory(this.store, Roo.data);
18866 this.store.on('load', this.onLoad, this);
18867 this.store.on('beforeload', this.onBeforeLoad, this);
18871 this.cells = this.el.select('.fc-day',true);
18872 //Roo.log(this.cells);
18873 this.textNodes = this.el.query('.fc-day-number');
18874 this.cells.addClassOnOver('fc-state-hover');
18876 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
18877 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
18878 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
18879 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
18881 this.on('monthchange', this.onMonthChange, this);
18883 this.update(new Date().clearTime());
18886 resize : function() {
18887 var sz = this.el.getSize();
18889 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
18890 this.el.select('.fc-day-content div',true).setHeight(34);
18895 showPrevMonth : function(e){
18896 this.update(this.activeDate.add("mo", -1));
18898 showToday : function(e){
18899 this.update(new Date().clearTime());
18902 showNextMonth : function(e){
18903 this.update(this.activeDate.add("mo", 1));
18907 showPrevYear : function(){
18908 this.update(this.activeDate.add("y", -1));
18912 showNextYear : function(){
18913 this.update(this.activeDate.add("y", 1));
18918 update : function(date)
18920 var vd = this.activeDate;
18921 this.activeDate = date;
18922 // if(vd && this.el){
18923 // var t = date.getTime();
18924 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
18925 // Roo.log('using add remove');
18927 // this.fireEvent('monthchange', this, date);
18929 // this.cells.removeClass("fc-state-highlight");
18930 // this.cells.each(function(c){
18931 // if(c.dateValue == t){
18932 // c.addClass("fc-state-highlight");
18933 // setTimeout(function(){
18934 // try{c.dom.firstChild.focus();}catch(e){}
18944 var days = date.getDaysInMonth();
18946 var firstOfMonth = date.getFirstDateOfMonth();
18947 var startingPos = firstOfMonth.getDay()-this.startDay;
18949 if(startingPos < this.startDay){
18953 var pm = date.add(Date.MONTH, -1);
18954 var prevStart = pm.getDaysInMonth()-startingPos;
18956 this.cells = this.el.select('.fc-day',true);
18957 this.textNodes = this.el.query('.fc-day-number');
18958 this.cells.addClassOnOver('fc-state-hover');
18960 var cells = this.cells.elements;
18961 var textEls = this.textNodes;
18963 Roo.each(cells, function(cell){
18964 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
18967 days += startingPos;
18969 // convert everything to numbers so it's fast
18970 var day = 86400000;
18971 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
18974 //Roo.log(prevStart);
18976 var today = new Date().clearTime().getTime();
18977 var sel = date.clearTime().getTime();
18978 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
18979 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
18980 var ddMatch = this.disabledDatesRE;
18981 var ddText = this.disabledDatesText;
18982 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
18983 var ddaysText = this.disabledDaysText;
18984 var format = this.format;
18986 var setCellClass = function(cal, cell){
18990 //Roo.log('set Cell Class');
18992 var t = d.getTime();
18996 cell.dateValue = t;
18998 cell.className += " fc-today";
18999 cell.className += " fc-state-highlight";
19000 cell.title = cal.todayText;
19003 // disable highlight in other month..
19004 //cell.className += " fc-state-highlight";
19009 cell.className = " fc-state-disabled";
19010 cell.title = cal.minText;
19014 cell.className = " fc-state-disabled";
19015 cell.title = cal.maxText;
19019 if(ddays.indexOf(d.getDay()) != -1){
19020 cell.title = ddaysText;
19021 cell.className = " fc-state-disabled";
19024 if(ddMatch && format){
19025 var fvalue = d.dateFormat(format);
19026 if(ddMatch.test(fvalue)){
19027 cell.title = ddText.replace("%0", fvalue);
19028 cell.className = " fc-state-disabled";
19032 if (!cell.initialClassName) {
19033 cell.initialClassName = cell.dom.className;
19036 cell.dom.className = cell.initialClassName + ' ' + cell.className;
19041 for(; i < startingPos; i++) {
19042 textEls[i].innerHTML = (++prevStart);
19043 d.setDate(d.getDate()+1);
19045 cells[i].className = "fc-past fc-other-month";
19046 setCellClass(this, cells[i]);
19051 for(; i < days; i++){
19052 intDay = i - startingPos + 1;
19053 textEls[i].innerHTML = (intDay);
19054 d.setDate(d.getDate()+1);
19056 cells[i].className = ''; // "x-date-active";
19057 setCellClass(this, cells[i]);
19061 for(; i < 42; i++) {
19062 textEls[i].innerHTML = (++extraDays);
19063 d.setDate(d.getDate()+1);
19065 cells[i].className = "fc-future fc-other-month";
19066 setCellClass(this, cells[i]);
19069 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
19071 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
19073 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
19074 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
19076 if(totalRows != 6){
19077 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
19078 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
19081 this.fireEvent('monthchange', this, date);
19085 if(!this.internalRender){
19086 var main = this.el.dom.firstChild;
19087 var w = main.offsetWidth;
19088 this.el.setWidth(w + this.el.getBorderWidth("lr"));
19089 Roo.fly(main).setWidth(w);
19090 this.internalRender = true;
19091 // opera does not respect the auto grow header center column
19092 // then, after it gets a width opera refuses to recalculate
19093 // without a second pass
19094 if(Roo.isOpera && !this.secondPass){
19095 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
19096 this.secondPass = true;
19097 this.update.defer(10, this, [date]);
19104 findCell : function(dt) {
19105 dt = dt.clearTime().getTime();
19107 this.cells.each(function(c){
19108 //Roo.log("check " +c.dateValue + '?=' + dt);
19109 if(c.dateValue == dt){
19119 findCells : function(ev) {
19120 var s = ev.start.clone().clearTime().getTime();
19122 var e= ev.end.clone().clearTime().getTime();
19125 this.cells.each(function(c){
19126 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
19128 if(c.dateValue > e){
19131 if(c.dateValue < s){
19140 // findBestRow: function(cells)
19144 // for (var i =0 ; i < cells.length;i++) {
19145 // ret = Math.max(cells[i].rows || 0,ret);
19152 addItem : function(ev)
19154 // look for vertical location slot in
19155 var cells = this.findCells(ev);
19157 // ev.row = this.findBestRow(cells);
19159 // work out the location.
19163 for(var i =0; i < cells.length; i++) {
19165 cells[i].row = cells[0].row;
19168 cells[i].row = cells[i].row + 1;
19178 if (crow.start.getY() == cells[i].getY()) {
19180 crow.end = cells[i];
19197 cells[0].events.push(ev);
19199 this.calevents.push(ev);
19202 clearEvents: function() {
19204 if(!this.calevents){
19208 Roo.each(this.cells.elements, function(c){
19214 Roo.each(this.calevents, function(e) {
19215 Roo.each(e.els, function(el) {
19216 el.un('mouseenter' ,this.onEventEnter, this);
19217 el.un('mouseleave' ,this.onEventLeave, this);
19222 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
19228 renderEvents: function()
19232 this.cells.each(function(c) {
19241 if(c.row != c.events.length){
19242 r = 4 - (4 - (c.row - c.events.length));
19245 c.events = ev.slice(0, r);
19246 c.more = ev.slice(r);
19248 if(c.more.length && c.more.length == 1){
19249 c.events.push(c.more.pop());
19252 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
19256 this.cells.each(function(c) {
19258 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
19261 for (var e = 0; e < c.events.length; e++){
19262 var ev = c.events[e];
19263 var rows = ev.rows;
19265 for(var i = 0; i < rows.length; i++) {
19267 // how many rows should it span..
19270 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
19271 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
19273 unselectable : "on",
19276 cls: 'fc-event-inner',
19280 // cls: 'fc-event-time',
19281 // html : cells.length > 1 ? '' : ev.time
19285 cls: 'fc-event-title',
19286 html : String.format('{0}', ev.title)
19293 cls: 'ui-resizable-handle ui-resizable-e',
19294 html : '  '
19301 cfg.cls += ' fc-event-start';
19303 if ((i+1) == rows.length) {
19304 cfg.cls += ' fc-event-end';
19307 var ctr = _this.el.select('.fc-event-container',true).first();
19308 var cg = ctr.createChild(cfg);
19310 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
19311 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
19313 var r = (c.more.length) ? 1 : 0;
19314 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
19315 cg.setWidth(ebox.right - sbox.x -2);
19317 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
19318 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
19319 cg.on('click', _this.onEventClick, _this, ev);
19330 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
19331 style : 'position: absolute',
19332 unselectable : "on",
19335 cls: 'fc-event-inner',
19339 cls: 'fc-event-title',
19347 cls: 'ui-resizable-handle ui-resizable-e',
19348 html : '  '
19354 var ctr = _this.el.select('.fc-event-container',true).first();
19355 var cg = ctr.createChild(cfg);
19357 var sbox = c.select('.fc-day-content',true).first().getBox();
19358 var ebox = c.select('.fc-day-content',true).first().getBox();
19360 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
19361 cg.setWidth(ebox.right - sbox.x -2);
19363 cg.on('click', _this.onMoreEventClick, _this, c.more);
19373 onEventEnter: function (e, el,event,d) {
19374 this.fireEvent('evententer', this, el, event);
19377 onEventLeave: function (e, el,event,d) {
19378 this.fireEvent('eventleave', this, el, event);
19381 onEventClick: function (e, el,event,d) {
19382 this.fireEvent('eventclick', this, el, event);
19385 onMonthChange: function () {
19389 onMoreEventClick: function(e, el, more)
19393 this.calpopover.placement = 'right';
19394 this.calpopover.setTitle('More');
19396 this.calpopover.setContent('');
19398 var ctr = this.calpopover.el.select('.popover-content', true).first();
19400 Roo.each(more, function(m){
19402 cls : 'fc-event-hori fc-event-draggable',
19405 var cg = ctr.createChild(cfg);
19407 cg.on('click', _this.onEventClick, _this, m);
19410 this.calpopover.show(el);
19415 onLoad: function ()
19417 this.calevents = [];
19420 if(this.store.getCount() > 0){
19421 this.store.data.each(function(d){
19424 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
19425 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
19426 time : d.data.start_time,
19427 title : d.data.title,
19428 description : d.data.description,
19429 venue : d.data.venue
19434 this.renderEvents();
19436 if(this.calevents.length && this.loadMask){
19437 this.maskEl.hide();
19441 onBeforeLoad: function()
19443 this.clearEvents();
19445 this.maskEl.show();
19459 * @class Roo.bootstrap.Popover
19460 * @extends Roo.bootstrap.Component
19461 * Bootstrap Popover class
19462 * @cfg {String} html contents of the popover (or false to use children..)
19463 * @cfg {String} title of popover (or false to hide)
19464 * @cfg {String} placement how it is placed
19465 * @cfg {String} trigger click || hover (or false to trigger manually)
19466 * @cfg {String} over what (parent or false to trigger manually.)
19467 * @cfg {Number} delay - delay before showing
19470 * Create a new Popover
19471 * @param {Object} config The config object
19474 Roo.bootstrap.Popover = function(config){
19475 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
19481 * After the popover show
19483 * @param {Roo.bootstrap.Popover} this
19488 * After the popover hide
19490 * @param {Roo.bootstrap.Popover} this
19496 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
19498 title: 'Fill in a title',
19501 placement : 'right',
19502 trigger : 'hover', // hover
19508 can_build_overlaid : false,
19510 getChildContainer : function()
19512 return this.el.select('.popover-content',true).first();
19515 getAutoCreate : function(){
19518 cls : 'popover roo-dynamic',
19519 style: 'display:block',
19525 cls : 'popover-inner',
19529 cls: 'popover-title popover-header',
19533 cls : 'popover-content popover-body',
19544 setTitle: function(str)
19547 this.el.select('.popover-title',true).first().dom.innerHTML = str;
19549 setContent: function(str)
19552 this.el.select('.popover-content',true).first().dom.innerHTML = str;
19554 // as it get's added to the bottom of the page.
19555 onRender : function(ct, position)
19557 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
19559 var cfg = Roo.apply({}, this.getAutoCreate());
19563 cfg.cls += ' ' + this.cls;
19566 cfg.style = this.style;
19568 //Roo.log("adding to ");
19569 this.el = Roo.get(document.body).createChild(cfg, position);
19570 // Roo.log(this.el);
19575 initEvents : function()
19577 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
19578 this.el.enableDisplayMode('block');
19580 if (this.over === false) {
19583 if (this.triggers === false) {
19586 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
19587 var triggers = this.trigger ? this.trigger.split(' ') : [];
19588 Roo.each(triggers, function(trigger) {
19590 if (trigger == 'click') {
19591 on_el.on('click', this.toggle, this);
19592 } else if (trigger != 'manual') {
19593 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
19594 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
19596 on_el.on(eventIn ,this.enter, this);
19597 on_el.on(eventOut, this.leave, this);
19608 toggle : function () {
19609 this.hoverState == 'in' ? this.leave() : this.enter();
19612 enter : function () {
19614 clearTimeout(this.timeout);
19616 this.hoverState = 'in';
19618 if (!this.delay || !this.delay.show) {
19623 this.timeout = setTimeout(function () {
19624 if (_t.hoverState == 'in') {
19627 }, this.delay.show)
19630 leave : function() {
19631 clearTimeout(this.timeout);
19633 this.hoverState = 'out';
19635 if (!this.delay || !this.delay.hide) {
19640 this.timeout = setTimeout(function () {
19641 if (_t.hoverState == 'out') {
19644 }, this.delay.hide)
19647 show : function (on_el)
19650 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
19654 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
19655 if (this.html !== false) {
19656 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
19658 this.el.removeClass([
19659 'fade','top','bottom', 'left', 'right','in',
19660 'bs-popover-top','bs-popover-bottom', 'bs-popover-left', 'bs-popover-right'
19662 if (!this.title.length) {
19663 this.el.select('.popover-title',true).hide();
19666 var placement = typeof this.placement == 'function' ?
19667 this.placement.call(this, this.el, on_el) :
19670 var autoToken = /\s?auto?\s?/i;
19671 var autoPlace = autoToken.test(placement);
19673 placement = placement.replace(autoToken, '') || 'top';
19677 //this.el.setXY([0,0]);
19679 this.el.dom.style.display='block';
19680 this.el.addClass(placement);
19682 //this.el.appendTo(on_el);
19684 var p = this.getPosition();
19685 var box = this.el.getBox();
19690 var align = Roo.bootstrap.Popover.alignment[placement];
19693 this.el.alignTo(on_el, align[0],align[1]);
19694 //var arrow = this.el.select('.arrow',true).first();
19695 //arrow.set(align[2],
19697 this.el.addClass('in');
19700 if (this.el.hasClass('fade')) {
19704 this.hoverState = 'in';
19706 this.fireEvent('show', this);
19711 this.el.setXY([0,0]);
19712 this.el.removeClass('in');
19714 this.hoverState = null;
19716 this.fireEvent('hide', this);
19721 Roo.bootstrap.Popover.alignment = {
19722 'left' : ['r-l', [-10,0], 'right bs-popover-right'],
19723 'right' : ['l-r', [10,0], 'left bs-popover-left'],
19724 'bottom' : ['t-b', [0,10], 'top bs-popover-top'],
19725 'top' : [ 'b-t', [0,-10], 'bottom bs-popover-bottom']
19736 * @class Roo.bootstrap.Progress
19737 * @extends Roo.bootstrap.Component
19738 * Bootstrap Progress class
19739 * @cfg {Boolean} striped striped of the progress bar
19740 * @cfg {Boolean} active animated of the progress bar
19744 * Create a new Progress
19745 * @param {Object} config The config object
19748 Roo.bootstrap.Progress = function(config){
19749 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
19752 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
19757 getAutoCreate : function(){
19765 cfg.cls += ' progress-striped';
19769 cfg.cls += ' active';
19788 * @class Roo.bootstrap.ProgressBar
19789 * @extends Roo.bootstrap.Component
19790 * Bootstrap ProgressBar class
19791 * @cfg {Number} aria_valuenow aria-value now
19792 * @cfg {Number} aria_valuemin aria-value min
19793 * @cfg {Number} aria_valuemax aria-value max
19794 * @cfg {String} label label for the progress bar
19795 * @cfg {String} panel (success | info | warning | danger )
19796 * @cfg {String} role role of the progress bar
19797 * @cfg {String} sr_only text
19801 * Create a new ProgressBar
19802 * @param {Object} config The config object
19805 Roo.bootstrap.ProgressBar = function(config){
19806 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
19809 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
19813 aria_valuemax : 100,
19819 getAutoCreate : function()
19824 cls: 'progress-bar',
19825 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
19837 cfg.role = this.role;
19840 if(this.aria_valuenow){
19841 cfg['aria-valuenow'] = this.aria_valuenow;
19844 if(this.aria_valuemin){
19845 cfg['aria-valuemin'] = this.aria_valuemin;
19848 if(this.aria_valuemax){
19849 cfg['aria-valuemax'] = this.aria_valuemax;
19852 if(this.label && !this.sr_only){
19853 cfg.html = this.label;
19857 cfg.cls += ' progress-bar-' + this.panel;
19863 update : function(aria_valuenow)
19865 this.aria_valuenow = aria_valuenow;
19867 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
19882 * @class Roo.bootstrap.TabGroup
19883 * @extends Roo.bootstrap.Column
19884 * Bootstrap Column class
19885 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
19886 * @cfg {Boolean} carousel true to make the group behave like a carousel
19887 * @cfg {Boolean} bullets show bullets for the panels
19888 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
19889 * @cfg {Number} timer auto slide timer .. default 0 millisecond
19890 * @cfg {Boolean} showarrow (true|false) show arrow default true
19893 * Create a new TabGroup
19894 * @param {Object} config The config object
19897 Roo.bootstrap.TabGroup = function(config){
19898 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
19900 this.navId = Roo.id();
19903 Roo.bootstrap.TabGroup.register(this);
19907 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
19910 transition : false,
19915 slideOnTouch : false,
19918 getAutoCreate : function()
19920 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
19922 cfg.cls += ' tab-content';
19924 if (this.carousel) {
19925 cfg.cls += ' carousel slide';
19928 cls : 'carousel-inner',
19932 if(this.bullets && !Roo.isTouch){
19935 cls : 'carousel-bullets',
19939 if(this.bullets_cls){
19940 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
19947 cfg.cn[0].cn.push(bullets);
19950 if(this.showarrow){
19951 cfg.cn[0].cn.push({
19953 class : 'carousel-arrow',
19957 class : 'carousel-prev',
19961 class : 'fa fa-chevron-left'
19967 class : 'carousel-next',
19971 class : 'fa fa-chevron-right'
19984 initEvents: function()
19986 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
19987 // this.el.on("touchstart", this.onTouchStart, this);
19990 if(this.autoslide){
19993 this.slideFn = window.setInterval(function() {
19994 _this.showPanelNext();
19998 if(this.showarrow){
19999 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
20000 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
20006 // onTouchStart : function(e, el, o)
20008 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
20012 // this.showPanelNext();
20016 getChildContainer : function()
20018 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
20022 * register a Navigation item
20023 * @param {Roo.bootstrap.NavItem} the navitem to add
20025 register : function(item)
20027 this.tabs.push( item);
20028 item.navId = this.navId; // not really needed..
20033 getActivePanel : function()
20036 Roo.each(this.tabs, function(t) {
20046 getPanelByName : function(n)
20049 Roo.each(this.tabs, function(t) {
20050 if (t.tabId == n) {
20058 indexOfPanel : function(p)
20061 Roo.each(this.tabs, function(t,i) {
20062 if (t.tabId == p.tabId) {
20071 * show a specific panel
20072 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
20073 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
20075 showPanel : function (pan)
20077 if(this.transition || typeof(pan) == 'undefined'){
20078 Roo.log("waiting for the transitionend");
20082 if (typeof(pan) == 'number') {
20083 pan = this.tabs[pan];
20086 if (typeof(pan) == 'string') {
20087 pan = this.getPanelByName(pan);
20090 var cur = this.getActivePanel();
20093 Roo.log('pan or acitve pan is undefined');
20097 if (pan.tabId == this.getActivePanel().tabId) {
20101 if (false === cur.fireEvent('beforedeactivate')) {
20105 if(this.bullets > 0 && !Roo.isTouch){
20106 this.setActiveBullet(this.indexOfPanel(pan));
20109 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
20111 //class="carousel-item carousel-item-next carousel-item-left"
20113 this.transition = true;
20114 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
20115 var lr = dir == 'next' ? 'left' : 'right';
20116 pan.el.addClass(dir); // or prev
20117 pan.el.addClass('carousel-item-' + dir); // or prev
20118 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
20119 cur.el.addClass(lr); // or right
20120 pan.el.addClass(lr);
20121 cur.el.addClass('carousel-item-' +lr); // or right
20122 pan.el.addClass('carousel-item-' +lr);
20126 cur.el.on('transitionend', function() {
20127 Roo.log("trans end?");
20129 pan.el.removeClass([lr,dir, 'carousel-item-' + lr, 'carousel-item-' + dir]);
20130 pan.setActive(true);
20132 cur.el.removeClass([lr, 'carousel-item-' + lr]);
20133 cur.setActive(false);
20135 _this.transition = false;
20137 }, this, { single: true } );
20142 cur.setActive(false);
20143 pan.setActive(true);
20148 showPanelNext : function()
20150 var i = this.indexOfPanel(this.getActivePanel());
20152 if (i >= this.tabs.length - 1 && !this.autoslide) {
20156 if (i >= this.tabs.length - 1 && this.autoslide) {
20160 this.showPanel(this.tabs[i+1]);
20163 showPanelPrev : function()
20165 var i = this.indexOfPanel(this.getActivePanel());
20167 if (i < 1 && !this.autoslide) {
20171 if (i < 1 && this.autoslide) {
20172 i = this.tabs.length;
20175 this.showPanel(this.tabs[i-1]);
20179 addBullet: function()
20181 if(!this.bullets || Roo.isTouch){
20184 var ctr = this.el.select('.carousel-bullets',true).first();
20185 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
20186 var bullet = ctr.createChild({
20187 cls : 'bullet bullet-' + i
20188 },ctr.dom.lastChild);
20193 bullet.on('click', (function(e, el, o, ii, t){
20195 e.preventDefault();
20197 this.showPanel(ii);
20199 if(this.autoslide && this.slideFn){
20200 clearInterval(this.slideFn);
20201 this.slideFn = window.setInterval(function() {
20202 _this.showPanelNext();
20206 }).createDelegate(this, [i, bullet], true));
20211 setActiveBullet : function(i)
20217 Roo.each(this.el.select('.bullet', true).elements, function(el){
20218 el.removeClass('selected');
20221 var bullet = this.el.select('.bullet-' + i, true).first();
20227 bullet.addClass('selected');
20238 Roo.apply(Roo.bootstrap.TabGroup, {
20242 * register a Navigation Group
20243 * @param {Roo.bootstrap.NavGroup} the navgroup to add
20245 register : function(navgrp)
20247 this.groups[navgrp.navId] = navgrp;
20251 * fetch a Navigation Group based on the navigation ID
20252 * if one does not exist , it will get created.
20253 * @param {string} the navgroup to add
20254 * @returns {Roo.bootstrap.NavGroup} the navgroup
20256 get: function(navId) {
20257 if (typeof(this.groups[navId]) == 'undefined') {
20258 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
20260 return this.groups[navId] ;
20275 * @class Roo.bootstrap.TabPanel
20276 * @extends Roo.bootstrap.Component
20277 * Bootstrap TabPanel class
20278 * @cfg {Boolean} active panel active
20279 * @cfg {String} html panel content
20280 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
20281 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
20282 * @cfg {String} href click to link..
20283 * @cfg {Boolean} touchSlide if swiping slides tab to next panel (default off)
20287 * Create a new TabPanel
20288 * @param {Object} config The config object
20291 Roo.bootstrap.TabPanel = function(config){
20292 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
20296 * Fires when the active status changes
20297 * @param {Roo.bootstrap.TabPanel} this
20298 * @param {Boolean} state the new state
20303 * @event beforedeactivate
20304 * Fires before a tab is de-activated - can be used to do validation on a form.
20305 * @param {Roo.bootstrap.TabPanel} this
20306 * @return {Boolean} false if there is an error
20309 'beforedeactivate': true
20312 this.tabId = this.tabId || Roo.id();
20316 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
20323 touchSlide : false,
20324 getAutoCreate : function(){
20329 // item is needed for carousel - not sure if it has any effect otherwise
20330 cls: 'carousel-item tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
20331 html: this.html || ''
20335 cfg.cls += ' active';
20339 cfg.tabId = this.tabId;
20347 initEvents: function()
20349 var p = this.parent();
20351 this.navId = this.navId || p.navId;
20353 if (typeof(this.navId) != 'undefined') {
20354 // not really needed.. but just in case.. parent should be a NavGroup.
20355 var tg = Roo.bootstrap.TabGroup.get(this.navId);
20359 var i = tg.tabs.length - 1;
20361 if(this.active && tg.bullets > 0 && i < tg.bullets){
20362 tg.setActiveBullet(i);
20366 this.el.on('click', this.onClick, this);
20368 if(Roo.isTouch && this.touchSlide){
20369 this.el.on("touchstart", this.onTouchStart, this);
20370 this.el.on("touchmove", this.onTouchMove, this);
20371 this.el.on("touchend", this.onTouchEnd, this);
20376 onRender : function(ct, position)
20378 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
20381 setActive : function(state)
20383 Roo.log("panel - set active " + this.tabId + "=" + state);
20385 this.active = state;
20387 this.el.removeClass('active');
20389 } else if (!this.el.hasClass('active')) {
20390 this.el.addClass('active');
20393 this.fireEvent('changed', this, state);
20396 onClick : function(e)
20398 e.preventDefault();
20400 if(!this.href.length){
20404 window.location.href = this.href;
20413 onTouchStart : function(e)
20415 this.swiping = false;
20417 this.startX = e.browserEvent.touches[0].clientX;
20418 this.startY = e.browserEvent.touches[0].clientY;
20421 onTouchMove : function(e)
20423 this.swiping = true;
20425 this.endX = e.browserEvent.touches[0].clientX;
20426 this.endY = e.browserEvent.touches[0].clientY;
20429 onTouchEnd : function(e)
20436 var tabGroup = this.parent();
20438 if(this.endX > this.startX){ // swiping right
20439 tabGroup.showPanelPrev();
20443 if(this.startX > this.endX){ // swiping left
20444 tabGroup.showPanelNext();
20463 * @class Roo.bootstrap.DateField
20464 * @extends Roo.bootstrap.Input
20465 * Bootstrap DateField class
20466 * @cfg {Number} weekStart default 0
20467 * @cfg {String} viewMode default empty, (months|years)
20468 * @cfg {String} minViewMode default empty, (months|years)
20469 * @cfg {Number} startDate default -Infinity
20470 * @cfg {Number} endDate default Infinity
20471 * @cfg {Boolean} todayHighlight default false
20472 * @cfg {Boolean} todayBtn default false
20473 * @cfg {Boolean} calendarWeeks default false
20474 * @cfg {Object} daysOfWeekDisabled default empty
20475 * @cfg {Boolean} singleMode default false (true | false)
20477 * @cfg {Boolean} keyboardNavigation default true
20478 * @cfg {String} language default en
20481 * Create a new DateField
20482 * @param {Object} config The config object
20485 Roo.bootstrap.DateField = function(config){
20486 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
20490 * Fires when this field show.
20491 * @param {Roo.bootstrap.DateField} this
20492 * @param {Mixed} date The date value
20497 * Fires when this field hide.
20498 * @param {Roo.bootstrap.DateField} this
20499 * @param {Mixed} date The date value
20504 * Fires when select a date.
20505 * @param {Roo.bootstrap.DateField} this
20506 * @param {Mixed} date The date value
20510 * @event beforeselect
20511 * Fires when before select a date.
20512 * @param {Roo.bootstrap.DateField} this
20513 * @param {Mixed} date The date value
20515 beforeselect : true
20519 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
20522 * @cfg {String} format
20523 * The default date format string which can be overriden for localization support. The format must be
20524 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
20528 * @cfg {String} altFormats
20529 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
20530 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
20532 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
20540 todayHighlight : false,
20546 keyboardNavigation: true,
20548 calendarWeeks: false,
20550 startDate: -Infinity,
20554 daysOfWeekDisabled: [],
20558 singleMode : false,
20560 UTCDate: function()
20562 return new Date(Date.UTC.apply(Date, arguments));
20565 UTCToday: function()
20567 var today = new Date();
20568 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
20571 getDate: function() {
20572 var d = this.getUTCDate();
20573 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
20576 getUTCDate: function() {
20580 setDate: function(d) {
20581 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
20584 setUTCDate: function(d) {
20586 this.setValue(this.formatDate(this.date));
20589 onRender: function(ct, position)
20592 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
20594 this.language = this.language || 'en';
20595 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
20596 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
20598 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
20599 this.format = this.format || 'm/d/y';
20600 this.isInline = false;
20601 this.isInput = true;
20602 this.component = this.el.select('.add-on', true).first() || false;
20603 this.component = (this.component && this.component.length === 0) ? false : this.component;
20604 this.hasInput = this.component && this.inputEl().length;
20606 if (typeof(this.minViewMode === 'string')) {
20607 switch (this.minViewMode) {
20609 this.minViewMode = 1;
20612 this.minViewMode = 2;
20615 this.minViewMode = 0;
20620 if (typeof(this.viewMode === 'string')) {
20621 switch (this.viewMode) {
20634 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
20636 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
20638 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
20640 this.picker().on('mousedown', this.onMousedown, this);
20641 this.picker().on('click', this.onClick, this);
20643 this.picker().addClass('datepicker-dropdown');
20645 this.startViewMode = this.viewMode;
20647 if(this.singleMode){
20648 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
20649 v.setVisibilityMode(Roo.Element.DISPLAY);
20653 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
20654 v.setStyle('width', '189px');
20658 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
20659 if(!this.calendarWeeks){
20664 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
20665 v.attr('colspan', function(i, val){
20666 return parseInt(val) + 1;
20671 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
20673 this.setStartDate(this.startDate);
20674 this.setEndDate(this.endDate);
20676 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
20683 if(this.isInline) {
20688 picker : function()
20690 return this.pickerEl;
20691 // return this.el.select('.datepicker', true).first();
20694 fillDow: function()
20696 var dowCnt = this.weekStart;
20705 if(this.calendarWeeks){
20713 while (dowCnt < this.weekStart + 7) {
20717 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
20721 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
20724 fillMonths: function()
20727 var months = this.picker().select('>.datepicker-months td', true).first();
20729 months.dom.innerHTML = '';
20735 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
20738 months.createChild(month);
20745 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;
20747 if (this.date < this.startDate) {
20748 this.viewDate = new Date(this.startDate);
20749 } else if (this.date > this.endDate) {
20750 this.viewDate = new Date(this.endDate);
20752 this.viewDate = new Date(this.date);
20760 var d = new Date(this.viewDate),
20761 year = d.getUTCFullYear(),
20762 month = d.getUTCMonth(),
20763 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
20764 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
20765 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
20766 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
20767 currentDate = this.date && this.date.valueOf(),
20768 today = this.UTCToday();
20770 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
20772 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
20774 // this.picker.select('>tfoot th.today').
20775 // .text(dates[this.language].today)
20776 // .toggle(this.todayBtn !== false);
20778 this.updateNavArrows();
20781 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
20783 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
20785 prevMonth.setUTCDate(day);
20787 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
20789 var nextMonth = new Date(prevMonth);
20791 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
20793 nextMonth = nextMonth.valueOf();
20795 var fillMonths = false;
20797 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
20799 while(prevMonth.valueOf() <= nextMonth) {
20802 if (prevMonth.getUTCDay() === this.weekStart) {
20804 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
20812 if(this.calendarWeeks){
20813 // ISO 8601: First week contains first thursday.
20814 // ISO also states week starts on Monday, but we can be more abstract here.
20816 // Start of current week: based on weekstart/current date
20817 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
20818 // Thursday of this week
20819 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
20820 // First Thursday of year, year from thursday
20821 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
20822 // Calendar week: ms between thursdays, div ms per day, div 7 days
20823 calWeek = (th - yth) / 864e5 / 7 + 1;
20825 fillMonths.cn.push({
20833 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
20835 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
20838 if (this.todayHighlight &&
20839 prevMonth.getUTCFullYear() == today.getFullYear() &&
20840 prevMonth.getUTCMonth() == today.getMonth() &&
20841 prevMonth.getUTCDate() == today.getDate()) {
20842 clsName += ' today';
20845 if (currentDate && prevMonth.valueOf() === currentDate) {
20846 clsName += ' active';
20849 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
20850 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
20851 clsName += ' disabled';
20854 fillMonths.cn.push({
20856 cls: 'day ' + clsName,
20857 html: prevMonth.getDate()
20860 prevMonth.setDate(prevMonth.getDate()+1);
20863 var currentYear = this.date && this.date.getUTCFullYear();
20864 var currentMonth = this.date && this.date.getUTCMonth();
20866 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
20868 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
20869 v.removeClass('active');
20871 if(currentYear === year && k === currentMonth){
20872 v.addClass('active');
20875 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
20876 v.addClass('disabled');
20882 year = parseInt(year/10, 10) * 10;
20884 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
20886 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
20889 for (var i = -1; i < 11; i++) {
20890 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
20892 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
20900 showMode: function(dir)
20903 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
20906 Roo.each(this.picker().select('>div',true).elements, function(v){
20907 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
20910 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
20915 if(this.isInline) {
20919 this.picker().removeClass(['bottom', 'top']);
20921 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
20923 * place to the top of element!
20927 this.picker().addClass('top');
20928 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
20933 this.picker().addClass('bottom');
20935 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
20938 parseDate : function(value)
20940 if(!value || value instanceof Date){
20943 var v = Date.parseDate(value, this.format);
20944 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
20945 v = Date.parseDate(value, 'Y-m-d');
20947 if(!v && this.altFormats){
20948 if(!this.altFormatsArray){
20949 this.altFormatsArray = this.altFormats.split("|");
20951 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
20952 v = Date.parseDate(value, this.altFormatsArray[i]);
20958 formatDate : function(date, fmt)
20960 return (!date || !(date instanceof Date)) ?
20961 date : date.dateFormat(fmt || this.format);
20964 onFocus : function()
20966 Roo.bootstrap.DateField.superclass.onFocus.call(this);
20970 onBlur : function()
20972 Roo.bootstrap.DateField.superclass.onBlur.call(this);
20974 var d = this.inputEl().getValue();
20981 showPopup : function()
20983 this.picker().show();
20987 this.fireEvent('showpopup', this, this.date);
20990 hidePopup : function()
20992 if(this.isInline) {
20995 this.picker().hide();
20996 this.viewMode = this.startViewMode;
20999 this.fireEvent('hidepopup', this, this.date);
21003 onMousedown: function(e)
21005 e.stopPropagation();
21006 e.preventDefault();
21011 Roo.bootstrap.DateField.superclass.keyup.call(this);
21015 setValue: function(v)
21017 if(this.fireEvent('beforeselect', this, v) !== false){
21018 var d = new Date(this.parseDate(v) ).clearTime();
21020 if(isNaN(d.getTime())){
21021 this.date = this.viewDate = '';
21022 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
21026 v = this.formatDate(d);
21028 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
21030 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
21034 this.fireEvent('select', this, this.date);
21038 getValue: function()
21040 return this.formatDate(this.date);
21043 fireKey: function(e)
21045 if (!this.picker().isVisible()){
21046 if (e.keyCode == 27) { // allow escape to hide and re-show picker
21052 var dateChanged = false,
21054 newDate, newViewDate;
21059 e.preventDefault();
21063 if (!this.keyboardNavigation) {
21066 dir = e.keyCode == 37 ? -1 : 1;
21069 newDate = this.moveYear(this.date, dir);
21070 newViewDate = this.moveYear(this.viewDate, dir);
21071 } else if (e.shiftKey){
21072 newDate = this.moveMonth(this.date, dir);
21073 newViewDate = this.moveMonth(this.viewDate, dir);
21075 newDate = new Date(this.date);
21076 newDate.setUTCDate(this.date.getUTCDate() + dir);
21077 newViewDate = new Date(this.viewDate);
21078 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
21080 if (this.dateWithinRange(newDate)){
21081 this.date = newDate;
21082 this.viewDate = newViewDate;
21083 this.setValue(this.formatDate(this.date));
21085 e.preventDefault();
21086 dateChanged = true;
21091 if (!this.keyboardNavigation) {
21094 dir = e.keyCode == 38 ? -1 : 1;
21096 newDate = this.moveYear(this.date, dir);
21097 newViewDate = this.moveYear(this.viewDate, dir);
21098 } else if (e.shiftKey){
21099 newDate = this.moveMonth(this.date, dir);
21100 newViewDate = this.moveMonth(this.viewDate, dir);
21102 newDate = new Date(this.date);
21103 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
21104 newViewDate = new Date(this.viewDate);
21105 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
21107 if (this.dateWithinRange(newDate)){
21108 this.date = newDate;
21109 this.viewDate = newViewDate;
21110 this.setValue(this.formatDate(this.date));
21112 e.preventDefault();
21113 dateChanged = true;
21117 this.setValue(this.formatDate(this.date));
21119 e.preventDefault();
21122 this.setValue(this.formatDate(this.date));
21136 onClick: function(e)
21138 e.stopPropagation();
21139 e.preventDefault();
21141 var target = e.getTarget();
21143 if(target.nodeName.toLowerCase() === 'i'){
21144 target = Roo.get(target).dom.parentNode;
21147 var nodeName = target.nodeName;
21148 var className = target.className;
21149 var html = target.innerHTML;
21150 //Roo.log(nodeName);
21152 switch(nodeName.toLowerCase()) {
21154 switch(className) {
21160 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
21161 switch(this.viewMode){
21163 this.viewDate = this.moveMonth(this.viewDate, dir);
21167 this.viewDate = this.moveYear(this.viewDate, dir);
21173 var date = new Date();
21174 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
21176 this.setValue(this.formatDate(this.date));
21183 if (className.indexOf('disabled') < 0) {
21184 this.viewDate.setUTCDate(1);
21185 if (className.indexOf('month') > -1) {
21186 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
21188 var year = parseInt(html, 10) || 0;
21189 this.viewDate.setUTCFullYear(year);
21193 if(this.singleMode){
21194 this.setValue(this.formatDate(this.viewDate));
21205 //Roo.log(className);
21206 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
21207 var day = parseInt(html, 10) || 1;
21208 var year = this.viewDate.getUTCFullYear(),
21209 month = this.viewDate.getUTCMonth();
21211 if (className.indexOf('old') > -1) {
21218 } else if (className.indexOf('new') > -1) {
21226 //Roo.log([year,month,day]);
21227 this.date = this.UTCDate(year, month, day,0,0,0,0);
21228 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
21230 //Roo.log(this.formatDate(this.date));
21231 this.setValue(this.formatDate(this.date));
21238 setStartDate: function(startDate)
21240 this.startDate = startDate || -Infinity;
21241 if (this.startDate !== -Infinity) {
21242 this.startDate = this.parseDate(this.startDate);
21245 this.updateNavArrows();
21248 setEndDate: function(endDate)
21250 this.endDate = endDate || Infinity;
21251 if (this.endDate !== Infinity) {
21252 this.endDate = this.parseDate(this.endDate);
21255 this.updateNavArrows();
21258 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
21260 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
21261 if (typeof(this.daysOfWeekDisabled) !== 'object') {
21262 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
21264 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
21265 return parseInt(d, 10);
21268 this.updateNavArrows();
21271 updateNavArrows: function()
21273 if(this.singleMode){
21277 var d = new Date(this.viewDate),
21278 year = d.getUTCFullYear(),
21279 month = d.getUTCMonth();
21281 Roo.each(this.picker().select('.prev', true).elements, function(v){
21283 switch (this.viewMode) {
21286 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
21292 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
21299 Roo.each(this.picker().select('.next', true).elements, function(v){
21301 switch (this.viewMode) {
21304 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
21310 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
21318 moveMonth: function(date, dir)
21323 var new_date = new Date(date.valueOf()),
21324 day = new_date.getUTCDate(),
21325 month = new_date.getUTCMonth(),
21326 mag = Math.abs(dir),
21328 dir = dir > 0 ? 1 : -1;
21331 // If going back one month, make sure month is not current month
21332 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
21334 return new_date.getUTCMonth() == month;
21336 // If going forward one month, make sure month is as expected
21337 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
21339 return new_date.getUTCMonth() != new_month;
21341 new_month = month + dir;
21342 new_date.setUTCMonth(new_month);
21343 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
21344 if (new_month < 0 || new_month > 11) {
21345 new_month = (new_month + 12) % 12;
21348 // For magnitudes >1, move one month at a time...
21349 for (var i=0; i<mag; i++) {
21350 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
21351 new_date = this.moveMonth(new_date, dir);
21353 // ...then reset the day, keeping it in the new month
21354 new_month = new_date.getUTCMonth();
21355 new_date.setUTCDate(day);
21357 return new_month != new_date.getUTCMonth();
21360 // Common date-resetting loop -- if date is beyond end of month, make it
21363 new_date.setUTCDate(--day);
21364 new_date.setUTCMonth(new_month);
21369 moveYear: function(date, dir)
21371 return this.moveMonth(date, dir*12);
21374 dateWithinRange: function(date)
21376 return date >= this.startDate && date <= this.endDate;
21382 this.picker().remove();
21385 validateValue : function(value)
21387 if(this.getVisibilityEl().hasClass('hidden')){
21391 if(value.length < 1) {
21392 if(this.allowBlank){
21398 if(value.length < this.minLength){
21401 if(value.length > this.maxLength){
21405 var vt = Roo.form.VTypes;
21406 if(!vt[this.vtype](value, this)){
21410 if(typeof this.validator == "function"){
21411 var msg = this.validator(value);
21417 if(this.regex && !this.regex.test(value)){
21421 if(typeof(this.parseDate(value)) == 'undefined'){
21425 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
21429 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
21439 this.date = this.viewDate = '';
21441 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
21446 Roo.apply(Roo.bootstrap.DateField, {
21457 html: '<i class="fa fa-arrow-left"/>'
21467 html: '<i class="fa fa-arrow-right"/>'
21509 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
21510 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
21511 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
21512 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
21513 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
21526 navFnc: 'FullYear',
21531 navFnc: 'FullYear',
21536 Roo.apply(Roo.bootstrap.DateField, {
21540 cls: 'datepicker dropdown-menu roo-dynamic',
21544 cls: 'datepicker-days',
21548 cls: 'table-condensed',
21550 Roo.bootstrap.DateField.head,
21554 Roo.bootstrap.DateField.footer
21561 cls: 'datepicker-months',
21565 cls: 'table-condensed',
21567 Roo.bootstrap.DateField.head,
21568 Roo.bootstrap.DateField.content,
21569 Roo.bootstrap.DateField.footer
21576 cls: 'datepicker-years',
21580 cls: 'table-condensed',
21582 Roo.bootstrap.DateField.head,
21583 Roo.bootstrap.DateField.content,
21584 Roo.bootstrap.DateField.footer
21603 * @class Roo.bootstrap.TimeField
21604 * @extends Roo.bootstrap.Input
21605 * Bootstrap DateField class
21609 * Create a new TimeField
21610 * @param {Object} config The config object
21613 Roo.bootstrap.TimeField = function(config){
21614 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
21618 * Fires when this field show.
21619 * @param {Roo.bootstrap.DateField} thisthis
21620 * @param {Mixed} date The date value
21625 * Fires when this field hide.
21626 * @param {Roo.bootstrap.DateField} this
21627 * @param {Mixed} date The date value
21632 * Fires when select a date.
21633 * @param {Roo.bootstrap.DateField} this
21634 * @param {Mixed} date The date value
21640 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
21643 * @cfg {String} format
21644 * The default time format string which can be overriden for localization support. The format must be
21645 * valid according to {@link Date#parseDate} (defaults to 'H:i').
21649 onRender: function(ct, position)
21652 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
21654 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
21656 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
21658 this.pop = this.picker().select('>.datepicker-time',true).first();
21659 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
21661 this.picker().on('mousedown', this.onMousedown, this);
21662 this.picker().on('click', this.onClick, this);
21664 this.picker().addClass('datepicker-dropdown');
21669 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
21670 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
21671 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
21672 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
21673 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
21674 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
21678 fireKey: function(e){
21679 if (!this.picker().isVisible()){
21680 if (e.keyCode == 27) { // allow escape to hide and re-show picker
21686 e.preventDefault();
21694 this.onTogglePeriod();
21697 this.onIncrementMinutes();
21700 this.onDecrementMinutes();
21709 onClick: function(e) {
21710 e.stopPropagation();
21711 e.preventDefault();
21714 picker : function()
21716 return this.el.select('.datepicker', true).first();
21719 fillTime: function()
21721 var time = this.pop.select('tbody', true).first();
21723 time.dom.innerHTML = '';
21738 cls: 'hours-up glyphicon glyphicon-chevron-up'
21758 cls: 'minutes-up glyphicon glyphicon-chevron-up'
21779 cls: 'timepicker-hour',
21794 cls: 'timepicker-minute',
21809 cls: 'btn btn-primary period',
21831 cls: 'hours-down glyphicon glyphicon-chevron-down'
21851 cls: 'minutes-down glyphicon glyphicon-chevron-down'
21869 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
21876 var hours = this.time.getHours();
21877 var minutes = this.time.getMinutes();
21890 hours = hours - 12;
21894 hours = '0' + hours;
21898 minutes = '0' + minutes;
21901 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
21902 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
21903 this.pop.select('button', true).first().dom.innerHTML = period;
21909 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
21911 var cls = ['bottom'];
21913 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
21920 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
21925 this.picker().addClass(cls.join('-'));
21929 Roo.each(cls, function(c){
21931 _this.picker().setTop(_this.inputEl().getHeight());
21935 _this.picker().setTop(0 - _this.picker().getHeight());
21940 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
21944 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
21951 onFocus : function()
21953 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
21957 onBlur : function()
21959 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
21965 this.picker().show();
21970 this.fireEvent('show', this, this.date);
21975 this.picker().hide();
21978 this.fireEvent('hide', this, this.date);
21981 setTime : function()
21984 this.setValue(this.time.format(this.format));
21986 this.fireEvent('select', this, this.date);
21991 onMousedown: function(e){
21992 e.stopPropagation();
21993 e.preventDefault();
21996 onIncrementHours: function()
21998 Roo.log('onIncrementHours');
21999 this.time = this.time.add(Date.HOUR, 1);
22004 onDecrementHours: function()
22006 Roo.log('onDecrementHours');
22007 this.time = this.time.add(Date.HOUR, -1);
22011 onIncrementMinutes: function()
22013 Roo.log('onIncrementMinutes');
22014 this.time = this.time.add(Date.MINUTE, 1);
22018 onDecrementMinutes: function()
22020 Roo.log('onDecrementMinutes');
22021 this.time = this.time.add(Date.MINUTE, -1);
22025 onTogglePeriod: function()
22027 Roo.log('onTogglePeriod');
22028 this.time = this.time.add(Date.HOUR, 12);
22035 Roo.apply(Roo.bootstrap.TimeField, {
22065 cls: 'btn btn-info ok',
22077 Roo.apply(Roo.bootstrap.TimeField, {
22081 cls: 'datepicker dropdown-menu',
22085 cls: 'datepicker-time',
22089 cls: 'table-condensed',
22091 Roo.bootstrap.TimeField.content,
22092 Roo.bootstrap.TimeField.footer
22111 * @class Roo.bootstrap.MonthField
22112 * @extends Roo.bootstrap.Input
22113 * Bootstrap MonthField class
22115 * @cfg {String} language default en
22118 * Create a new MonthField
22119 * @param {Object} config The config object
22122 Roo.bootstrap.MonthField = function(config){
22123 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
22128 * Fires when this field show.
22129 * @param {Roo.bootstrap.MonthField} this
22130 * @param {Mixed} date The date value
22135 * Fires when this field hide.
22136 * @param {Roo.bootstrap.MonthField} this
22137 * @param {Mixed} date The date value
22142 * Fires when select a date.
22143 * @param {Roo.bootstrap.MonthField} this
22144 * @param {String} oldvalue The old value
22145 * @param {String} newvalue The new value
22151 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
22153 onRender: function(ct, position)
22156 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
22158 this.language = this.language || 'en';
22159 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
22160 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
22162 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
22163 this.isInline = false;
22164 this.isInput = true;
22165 this.component = this.el.select('.add-on', true).first() || false;
22166 this.component = (this.component && this.component.length === 0) ? false : this.component;
22167 this.hasInput = this.component && this.inputEL().length;
22169 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
22171 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
22173 this.picker().on('mousedown', this.onMousedown, this);
22174 this.picker().on('click', this.onClick, this);
22176 this.picker().addClass('datepicker-dropdown');
22178 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
22179 v.setStyle('width', '189px');
22186 if(this.isInline) {
22192 setValue: function(v, suppressEvent)
22194 var o = this.getValue();
22196 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
22200 if(suppressEvent !== true){
22201 this.fireEvent('select', this, o, v);
22206 getValue: function()
22211 onClick: function(e)
22213 e.stopPropagation();
22214 e.preventDefault();
22216 var target = e.getTarget();
22218 if(target.nodeName.toLowerCase() === 'i'){
22219 target = Roo.get(target).dom.parentNode;
22222 var nodeName = target.nodeName;
22223 var className = target.className;
22224 var html = target.innerHTML;
22226 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
22230 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
22232 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
22238 picker : function()
22240 return this.pickerEl;
22243 fillMonths: function()
22246 var months = this.picker().select('>.datepicker-months td', true).first();
22248 months.dom.innerHTML = '';
22254 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
22257 months.createChild(month);
22266 if(typeof(this.vIndex) == 'undefined' && this.value.length){
22267 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
22270 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
22271 e.removeClass('active');
22273 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
22274 e.addClass('active');
22281 if(this.isInline) {
22285 this.picker().removeClass(['bottom', 'top']);
22287 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
22289 * place to the top of element!
22293 this.picker().addClass('top');
22294 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
22299 this.picker().addClass('bottom');
22301 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
22304 onFocus : function()
22306 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
22310 onBlur : function()
22312 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
22314 var d = this.inputEl().getValue();
22323 this.picker().show();
22324 this.picker().select('>.datepicker-months', true).first().show();
22328 this.fireEvent('show', this, this.date);
22333 if(this.isInline) {
22336 this.picker().hide();
22337 this.fireEvent('hide', this, this.date);
22341 onMousedown: function(e)
22343 e.stopPropagation();
22344 e.preventDefault();
22349 Roo.bootstrap.MonthField.superclass.keyup.call(this);
22353 fireKey: function(e)
22355 if (!this.picker().isVisible()){
22356 if (e.keyCode == 27) {// allow escape to hide and re-show picker
22367 e.preventDefault();
22371 dir = e.keyCode == 37 ? -1 : 1;
22373 this.vIndex = this.vIndex + dir;
22375 if(this.vIndex < 0){
22379 if(this.vIndex > 11){
22383 if(isNaN(this.vIndex)){
22387 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
22393 dir = e.keyCode == 38 ? -1 : 1;
22395 this.vIndex = this.vIndex + dir * 4;
22397 if(this.vIndex < 0){
22401 if(this.vIndex > 11){
22405 if(isNaN(this.vIndex)){
22409 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
22414 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
22415 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
22419 e.preventDefault();
22422 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
22423 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
22439 this.picker().remove();
22444 Roo.apply(Roo.bootstrap.MonthField, {
22463 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
22464 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
22469 Roo.apply(Roo.bootstrap.MonthField, {
22473 cls: 'datepicker dropdown-menu roo-dynamic',
22477 cls: 'datepicker-months',
22481 cls: 'table-condensed',
22483 Roo.bootstrap.DateField.content
22503 * @class Roo.bootstrap.CheckBox
22504 * @extends Roo.bootstrap.Input
22505 * Bootstrap CheckBox class
22507 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
22508 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
22509 * @cfg {String} boxLabel The text that appears beside the checkbox
22510 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
22511 * @cfg {Boolean} checked initnal the element
22512 * @cfg {Boolean} inline inline the element (default false)
22513 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
22514 * @cfg {String} tooltip label tooltip
22517 * Create a new CheckBox
22518 * @param {Object} config The config object
22521 Roo.bootstrap.CheckBox = function(config){
22522 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
22527 * Fires when the element is checked or unchecked.
22528 * @param {Roo.bootstrap.CheckBox} this This input
22529 * @param {Boolean} checked The new checked value
22534 * Fires when the element is click.
22535 * @param {Roo.bootstrap.CheckBox} this This input
22542 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
22544 inputType: 'checkbox',
22553 // checkbox success does not make any sense really..
22558 getAutoCreate : function()
22560 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
22566 cfg.cls = 'form-group form-check ' + this.inputType; //input-group
22569 cfg.cls += ' ' + this.inputType + '-inline form-check-inline';
22575 type : this.inputType,
22576 value : this.inputValue,
22577 cls : 'roo-' + this.inputType, //'form-box',
22578 placeholder : this.placeholder || ''
22582 if(this.inputType != 'radio'){
22586 cls : 'roo-hidden-value',
22587 value : this.checked ? this.inputValue : this.valueOff
22592 if (this.weight) { // Validity check?
22593 cfg.cls += " " + this.inputType + "-" + this.weight;
22596 if (this.disabled) {
22597 input.disabled=true;
22601 input.checked = this.checked;
22606 input.name = this.name;
22608 if(this.inputType != 'radio'){
22609 hidden.name = this.name;
22610 input.name = '_hidden_' + this.name;
22615 input.cls += ' input-' + this.size;
22620 ['xs','sm','md','lg'].map(function(size){
22621 if (settings[size]) {
22622 cfg.cls += ' col-' + size + '-' + settings[size];
22626 var inputblock = input;
22628 if (this.before || this.after) {
22631 cls : 'input-group',
22636 inputblock.cn.push({
22638 cls : 'input-group-addon',
22643 inputblock.cn.push(input);
22645 if(this.inputType != 'radio'){
22646 inputblock.cn.push(hidden);
22650 inputblock.cn.push({
22652 cls : 'input-group-addon',
22658 var boxLabelCfg = false;
22664 //'for': id, // box label is handled by onclick - so no for...
22666 html: this.boxLabel
22669 boxLabelCfg.tooltip = this.tooltip;
22675 if (align ==='left' && this.fieldLabel.length) {
22676 // Roo.log("left and has label");
22681 cls : 'control-label',
22682 html : this.fieldLabel
22693 cfg.cn[1].cn.push(boxLabelCfg);
22696 if(this.labelWidth > 12){
22697 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
22700 if(this.labelWidth < 13 && this.labelmd == 0){
22701 this.labelmd = this.labelWidth;
22704 if(this.labellg > 0){
22705 cfg.cn[0].cls += ' col-lg-' + this.labellg;
22706 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
22709 if(this.labelmd > 0){
22710 cfg.cn[0].cls += ' col-md-' + this.labelmd;
22711 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
22714 if(this.labelsm > 0){
22715 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
22716 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
22719 if(this.labelxs > 0){
22720 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
22721 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
22724 } else if ( this.fieldLabel.length) {
22725 // Roo.log(" label");
22729 tag: this.boxLabel ? 'span' : 'label',
22731 cls: 'control-label box-input-label',
22732 //cls : 'input-group-addon',
22733 html : this.fieldLabel
22740 cfg.cn.push(boxLabelCfg);
22745 // Roo.log(" no label && no align");
22746 cfg.cn = [ inputblock ] ;
22748 cfg.cn.push(boxLabelCfg);
22756 if(this.inputType != 'radio'){
22757 cfg.cn.push(hidden);
22765 * return the real input element.
22767 inputEl: function ()
22769 return this.el.select('input.roo-' + this.inputType,true).first();
22771 hiddenEl: function ()
22773 return this.el.select('input.roo-hidden-value',true).first();
22776 labelEl: function()
22778 return this.el.select('label.control-label',true).first();
22780 /* depricated... */
22784 return this.labelEl();
22787 boxLabelEl: function()
22789 return this.el.select('label.box-label',true).first();
22792 initEvents : function()
22794 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
22796 this.inputEl().on('click', this.onClick, this);
22798 if (this.boxLabel) {
22799 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
22802 this.startValue = this.getValue();
22805 Roo.bootstrap.CheckBox.register(this);
22809 onClick : function(e)
22811 if(this.fireEvent('click', this, e) !== false){
22812 this.setChecked(!this.checked);
22817 setChecked : function(state,suppressEvent)
22819 this.startValue = this.getValue();
22821 if(this.inputType == 'radio'){
22823 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
22824 e.dom.checked = false;
22827 this.inputEl().dom.checked = true;
22829 this.inputEl().dom.value = this.inputValue;
22831 if(suppressEvent !== true){
22832 this.fireEvent('check', this, true);
22840 this.checked = state;
22842 this.inputEl().dom.checked = state;
22845 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
22847 if(suppressEvent !== true){
22848 this.fireEvent('check', this, state);
22854 getValue : function()
22856 if(this.inputType == 'radio'){
22857 return this.getGroupValue();
22860 return this.hiddenEl().dom.value;
22864 getGroupValue : function()
22866 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
22870 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
22873 setValue : function(v,suppressEvent)
22875 if(this.inputType == 'radio'){
22876 this.setGroupValue(v, suppressEvent);
22880 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
22885 setGroupValue : function(v, suppressEvent)
22887 this.startValue = this.getValue();
22889 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
22890 e.dom.checked = false;
22892 if(e.dom.value == v){
22893 e.dom.checked = true;
22897 if(suppressEvent !== true){
22898 this.fireEvent('check', this, true);
22906 validate : function()
22908 if(this.getVisibilityEl().hasClass('hidden')){
22914 (this.inputType == 'radio' && this.validateRadio()) ||
22915 (this.inputType == 'checkbox' && this.validateCheckbox())
22921 this.markInvalid();
22925 validateRadio : function()
22927 if(this.getVisibilityEl().hasClass('hidden')){
22931 if(this.allowBlank){
22937 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
22938 if(!e.dom.checked){
22950 validateCheckbox : function()
22953 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
22954 //return (this.getValue() == this.inputValue) ? true : false;
22957 var group = Roo.bootstrap.CheckBox.get(this.groupId);
22965 for(var i in group){
22966 if(group[i].el.isVisible(true)){
22974 for(var i in group){
22979 r = (group[i].getValue() == group[i].inputValue) ? true : false;
22986 * Mark this field as valid
22988 markValid : function()
22992 this.fireEvent('valid', this);
22994 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
22997 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
23004 if(this.inputType == 'radio'){
23005 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
23006 var fg = e.findParent('.form-group', false, true);
23007 if (Roo.bootstrap.version == 3) {
23008 fg.removeClass([_this.invalidClass, _this.validClass]);
23009 fg.addClass(_this.validClass);
23011 fg.removeClass(['is-valid', 'is-invalid']);
23012 fg.addClass('is-valid');
23020 var fg = this.el.findParent('.form-group', false, true);
23021 if (Roo.bootstrap.version == 3) {
23022 fg.removeClass([this.invalidClass, this.validClass]);
23023 fg.addClass(this.validClass);
23025 fg.removeClass(['is-valid', 'is-invalid']);
23026 fg.addClass('is-valid');
23031 var group = Roo.bootstrap.CheckBox.get(this.groupId);
23037 for(var i in group){
23038 var fg = group[i].el.findParent('.form-group', false, true);
23039 if (Roo.bootstrap.version == 3) {
23040 fg.removeClass([this.invalidClass, this.validClass]);
23041 fg.addClass(this.validClass);
23043 fg.removeClass(['is-valid', 'is-invalid']);
23044 fg.addClass('is-valid');
23050 * Mark this field as invalid
23051 * @param {String} msg The validation message
23053 markInvalid : function(msg)
23055 if(this.allowBlank){
23061 this.fireEvent('invalid', this, msg);
23063 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
23066 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
23070 label.markInvalid();
23073 if(this.inputType == 'radio'){
23075 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
23076 var fg = e.findParent('.form-group', false, true);
23077 if (Roo.bootstrap.version == 3) {
23078 fg.removeClass([_this.invalidClass, _this.validClass]);
23079 fg.addClass(_this.invalidClass);
23081 fg.removeClass(['is-invalid', 'is-valid']);
23082 fg.addClass('is-invalid');
23090 var fg = this.el.findParent('.form-group', false, true);
23091 if (Roo.bootstrap.version == 3) {
23092 fg.removeClass([_this.invalidClass, _this.validClass]);
23093 fg.addClass(_this.invalidClass);
23095 fg.removeClass(['is-invalid', 'is-valid']);
23096 fg.addClass('is-invalid');
23101 var group = Roo.bootstrap.CheckBox.get(this.groupId);
23107 for(var i in group){
23108 var fg = group[i].el.findParent('.form-group', false, true);
23109 if (Roo.bootstrap.version == 3) {
23110 fg.removeClass([_this.invalidClass, _this.validClass]);
23111 fg.addClass(_this.invalidClass);
23113 fg.removeClass(['is-invalid', 'is-valid']);
23114 fg.addClass('is-invalid');
23120 clearInvalid : function()
23122 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
23124 // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
23126 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
23128 if (label && label.iconEl) {
23129 label.iconEl.removeClass([ label.validClass, label.invalidClass ]);
23130 label.iconEl.removeClass(['is-invalid', 'is-valid']);
23134 disable : function()
23136 if(this.inputType != 'radio'){
23137 Roo.bootstrap.CheckBox.superclass.disable.call(this);
23144 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
23145 _this.getActionEl().addClass(this.disabledClass);
23146 e.dom.disabled = true;
23150 this.disabled = true;
23151 this.fireEvent("disable", this);
23155 enable : function()
23157 if(this.inputType != 'radio'){
23158 Roo.bootstrap.CheckBox.superclass.enable.call(this);
23165 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
23166 _this.getActionEl().removeClass(this.disabledClass);
23167 e.dom.disabled = false;
23171 this.disabled = false;
23172 this.fireEvent("enable", this);
23176 setBoxLabel : function(v)
23181 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
23187 Roo.apply(Roo.bootstrap.CheckBox, {
23192 * register a CheckBox Group
23193 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
23195 register : function(checkbox)
23197 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
23198 this.groups[checkbox.groupId] = {};
23201 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
23205 this.groups[checkbox.groupId][checkbox.name] = checkbox;
23209 * fetch a CheckBox Group based on the group ID
23210 * @param {string} the group ID
23211 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
23213 get: function(groupId) {
23214 if (typeof(this.groups[groupId]) == 'undefined') {
23218 return this.groups[groupId] ;
23231 * @class Roo.bootstrap.Radio
23232 * @extends Roo.bootstrap.Component
23233 * Bootstrap Radio class
23234 * @cfg {String} boxLabel - the label associated
23235 * @cfg {String} value - the value of radio
23238 * Create a new Radio
23239 * @param {Object} config The config object
23241 Roo.bootstrap.Radio = function(config){
23242 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
23246 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
23252 getAutoCreate : function()
23256 cls : 'form-group radio',
23261 html : this.boxLabel
23269 initEvents : function()
23271 this.parent().register(this);
23273 this.el.on('click', this.onClick, this);
23277 onClick : function(e)
23279 if(this.parent().fireEvent('click', this.parent(), this, e) !== false){
23280 this.setChecked(true);
23284 setChecked : function(state, suppressEvent)
23286 this.parent().setValue(this.value, suppressEvent);
23290 setBoxLabel : function(v)
23295 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
23310 * @class Roo.bootstrap.SecurePass
23311 * @extends Roo.bootstrap.Input
23312 * Bootstrap SecurePass class
23316 * Create a new SecurePass
23317 * @param {Object} config The config object
23320 Roo.bootstrap.SecurePass = function (config) {
23321 // these go here, so the translation tool can replace them..
23323 PwdEmpty: "Please type a password, and then retype it to confirm.",
23324 PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
23325 PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
23326 PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
23327 IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
23328 FNInPwd: "Your password can't contain your first name. Please type a different password.",
23329 LNInPwd: "Your password can't contain your last name. Please type a different password.",
23330 TooWeak: "Your password is Too Weak."
23332 this.meterLabel = "Password strength:";
23333 this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
23334 this.meterClass = [
23335 "roo-password-meter-tooweak",
23336 "roo-password-meter-weak",
23337 "roo-password-meter-medium",
23338 "roo-password-meter-strong",
23339 "roo-password-meter-grey"
23344 Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
23347 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
23349 * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
23351 * PwdEmpty: "Please type a password, and then retype it to confirm.",
23352 * PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
23353 * PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
23354 * PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
23355 * IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
23356 * FNInPwd: "Your password can't contain your first name. Please type a different password.",
23357 * LNInPwd: "Your password can't contain your last name. Please type a different password."
23367 * @cfg {String/Object} Label for the strength meter (defaults to
23368 * 'Password strength:')
23373 * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
23374 * ['Weak', 'Medium', 'Strong'])
23377 pwdStrengths: false,
23390 initEvents: function ()
23392 Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
23394 if (this.el.is('input[type=password]') && Roo.isSafari) {
23395 this.el.on('keydown', this.SafariOnKeyDown, this);
23398 this.el.on('keyup', this.checkStrength, this, {buffer: 50});
23401 onRender: function (ct, position)
23403 Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
23404 this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
23405 this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
23407 this.trigger.createChild({
23412 cls: 'roo-password-meter-grey col-xs-12',
23415 //width: this.meterWidth + 'px'
23419 cls: 'roo-password-meter-text'
23425 if (this.hideTrigger) {
23426 this.trigger.setDisplayed(false);
23428 this.setSize(this.width || '', this.height || '');
23431 onDestroy: function ()
23433 if (this.trigger) {
23434 this.trigger.removeAllListeners();
23435 this.trigger.remove();
23438 this.wrap.remove();
23440 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
23443 checkStrength: function ()
23445 var pwd = this.inputEl().getValue();
23446 if (pwd == this._lastPwd) {
23451 if (this.ClientSideStrongPassword(pwd)) {
23453 } else if (this.ClientSideMediumPassword(pwd)) {
23455 } else if (this.ClientSideWeakPassword(pwd)) {
23461 Roo.log('strength1: ' + strength);
23463 //var pm = this.trigger.child('div/div/div').dom;
23464 var pm = this.trigger.child('div/div');
23465 pm.removeClass(this.meterClass);
23466 pm.addClass(this.meterClass[strength]);
23469 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
23471 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
23473 this._lastPwd = pwd;
23477 Roo.bootstrap.SecurePass.superclass.reset.call(this);
23479 this._lastPwd = '';
23481 var pm = this.trigger.child('div/div');
23482 pm.removeClass(this.meterClass);
23483 pm.addClass('roo-password-meter-grey');
23486 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
23489 this.inputEl().dom.type='password';
23492 validateValue: function (value)
23494 if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
23497 if (value.length == 0) {
23498 if (this.allowBlank) {
23499 this.clearInvalid();
23503 this.markInvalid(this.errors.PwdEmpty);
23504 this.errorMsg = this.errors.PwdEmpty;
23512 if (!value.match(/[\x21-\x7e]+/)) {
23513 this.markInvalid(this.errors.PwdBadChar);
23514 this.errorMsg = this.errors.PwdBadChar;
23517 if (value.length < 6) {
23518 this.markInvalid(this.errors.PwdShort);
23519 this.errorMsg = this.errors.PwdShort;
23522 if (value.length > 16) {
23523 this.markInvalid(this.errors.PwdLong);
23524 this.errorMsg = this.errors.PwdLong;
23528 if (this.ClientSideStrongPassword(value)) {
23530 } else if (this.ClientSideMediumPassword(value)) {
23532 } else if (this.ClientSideWeakPassword(value)) {
23539 if (strength < 2) {
23540 //this.markInvalid(this.errors.TooWeak);
23541 this.errorMsg = this.errors.TooWeak;
23546 console.log('strength2: ' + strength);
23548 //var pm = this.trigger.child('div/div/div').dom;
23550 var pm = this.trigger.child('div/div');
23551 pm.removeClass(this.meterClass);
23552 pm.addClass(this.meterClass[strength]);
23554 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
23556 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
23558 this.errorMsg = '';
23562 CharacterSetChecks: function (type)
23565 this.fResult = false;
23568 isctype: function (character, type)
23571 case this.kCapitalLetter:
23572 if (character >= 'A' && character <= 'Z') {
23577 case this.kSmallLetter:
23578 if (character >= 'a' && character <= 'z') {
23584 if (character >= '0' && character <= '9') {
23589 case this.kPunctuation:
23590 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
23601 IsLongEnough: function (pwd, size)
23603 return !(pwd == null || isNaN(size) || pwd.length < size);
23606 SpansEnoughCharacterSets: function (word, nb)
23608 if (!this.IsLongEnough(word, nb))
23613 var characterSetChecks = new Array(
23614 new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
23615 new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
23618 for (var index = 0; index < word.length; ++index) {
23619 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
23620 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
23621 characterSetChecks[nCharSet].fResult = true;
23628 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
23629 if (characterSetChecks[nCharSet].fResult) {
23634 if (nCharSets < nb) {
23640 ClientSideStrongPassword: function (pwd)
23642 return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
23645 ClientSideMediumPassword: function (pwd)
23647 return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
23650 ClientSideWeakPassword: function (pwd)
23652 return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
23655 })//<script type="text/javascript">
23658 * Based Ext JS Library 1.1.1
23659 * Copyright(c) 2006-2007, Ext JS, LLC.
23665 * @class Roo.HtmlEditorCore
23666 * @extends Roo.Component
23667 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
23669 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
23672 Roo.HtmlEditorCore = function(config){
23675 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
23680 * @event initialize
23681 * Fires when the editor is fully initialized (including the iframe)
23682 * @param {Roo.HtmlEditorCore} this
23687 * Fires when the editor is first receives the focus. Any insertion must wait
23688 * until after this event.
23689 * @param {Roo.HtmlEditorCore} this
23693 * @event beforesync
23694 * Fires before the textarea is updated with content from the editor iframe. Return false
23695 * to cancel the sync.
23696 * @param {Roo.HtmlEditorCore} this
23697 * @param {String} html
23701 * @event beforepush
23702 * Fires before the iframe editor is updated with content from the textarea. Return false
23703 * to cancel the push.
23704 * @param {Roo.HtmlEditorCore} this
23705 * @param {String} html
23710 * Fires when the textarea is updated with content from the editor iframe.
23711 * @param {Roo.HtmlEditorCore} this
23712 * @param {String} html
23717 * Fires when the iframe editor is updated with content from the textarea.
23718 * @param {Roo.HtmlEditorCore} this
23719 * @param {String} html
23724 * @event editorevent
23725 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
23726 * @param {Roo.HtmlEditorCore} this
23732 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
23734 // defaults : white / black...
23735 this.applyBlacklists();
23742 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
23746 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
23752 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
23757 * @cfg {Number} height (in pixels)
23761 * @cfg {Number} width (in pixels)
23766 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
23769 stylesheets: false,
23774 // private properties
23775 validationEvent : false,
23777 initialized : false,
23779 sourceEditMode : false,
23780 onFocus : Roo.emptyFn,
23782 hideMode:'offsets',
23786 // blacklist + whitelisted elements..
23793 * Protected method that will not generally be called directly. It
23794 * is called when the editor initializes the iframe with HTML contents. Override this method if you
23795 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
23797 getDocMarkup : function(){
23801 // inherit styels from page...??
23802 if (this.stylesheets === false) {
23804 Roo.get(document.head).select('style').each(function(node) {
23805 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
23808 Roo.get(document.head).select('link').each(function(node) {
23809 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
23812 } else if (!this.stylesheets.length) {
23814 st = '<style type="text/css">' +
23815 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
23818 for (var i in this.stylesheets) {
23819 st += '<link rel="stylesheet" href="' + this.stylesheets[i] +'" type="text/css">';
23824 st += '<style type="text/css">' +
23825 'IMG { cursor: pointer } ' +
23828 var cls = 'roo-htmleditor-body';
23830 if(this.bodyCls.length){
23831 cls += ' ' + this.bodyCls;
23834 return '<html><head>' + st +
23835 //<style type="text/css">' +
23836 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
23838 ' </head><body contenteditable="true" data-enable-grammerly="true" class="' + cls + '"></body></html>';
23842 onRender : function(ct, position)
23845 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
23846 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
23849 this.el.dom.style.border = '0 none';
23850 this.el.dom.setAttribute('tabIndex', -1);
23851 this.el.addClass('x-hidden hide');
23855 if(Roo.isIE){ // fix IE 1px bogus margin
23856 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
23860 this.frameId = Roo.id();
23864 var iframe = this.owner.wrap.createChild({
23866 cls: 'form-control', // bootstrap..
23868 name: this.frameId,
23869 frameBorder : 'no',
23870 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
23875 this.iframe = iframe.dom;
23877 this.assignDocWin();
23879 this.doc.designMode = 'on';
23882 this.doc.write(this.getDocMarkup());
23886 var task = { // must defer to wait for browser to be ready
23888 //console.log("run task?" + this.doc.readyState);
23889 this.assignDocWin();
23890 if(this.doc.body || this.doc.readyState == 'complete'){
23892 this.doc.designMode="on";
23896 Roo.TaskMgr.stop(task);
23897 this.initEditor.defer(10, this);
23904 Roo.TaskMgr.start(task);
23909 onResize : function(w, h)
23911 Roo.log('resize: ' +w + ',' + h );
23912 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
23916 if(typeof w == 'number'){
23918 this.iframe.style.width = w + 'px';
23920 if(typeof h == 'number'){
23922 this.iframe.style.height = h + 'px';
23924 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
23931 * Toggles the editor between standard and source edit mode.
23932 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
23934 toggleSourceEdit : function(sourceEditMode){
23936 this.sourceEditMode = sourceEditMode === true;
23938 if(this.sourceEditMode){
23940 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
23943 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
23944 //this.iframe.className = '';
23947 //this.setSize(this.owner.wrap.getSize());
23948 //this.fireEvent('editmodechange', this, this.sourceEditMode);
23955 * Protected method that will not generally be called directly. If you need/want
23956 * custom HTML cleanup, this is the method you should override.
23957 * @param {String} html The HTML to be cleaned
23958 * return {String} The cleaned HTML
23960 cleanHtml : function(html){
23961 html = String(html);
23962 if(html.length > 5){
23963 if(Roo.isSafari){ // strip safari nonsense
23964 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
23967 if(html == ' '){
23974 * HTML Editor -> Textarea
23975 * Protected method that will not generally be called directly. Syncs the contents
23976 * of the editor iframe with the textarea.
23978 syncValue : function(){
23979 if(this.initialized){
23980 var bd = (this.doc.body || this.doc.documentElement);
23981 //this.cleanUpPaste(); -- this is done else where and causes havoc..
23982 var html = bd.innerHTML;
23984 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
23985 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
23987 html = '<div style="'+m[0]+'">' + html + '</div>';
23990 html = this.cleanHtml(html);
23991 // fix up the special chars.. normaly like back quotes in word...
23992 // however we do not want to do this with chinese..
23993 html = html.replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]|[\u0080-\uFFFF]/g, function(match) {
23995 var cc = match.charCodeAt();
23997 // Get the character value, handling surrogate pairs
23998 if (match.length == 2) {
23999 // It's a surrogate pair, calculate the Unicode code point
24000 var high = match.charCodeAt(0) - 0xD800;
24001 var low = match.charCodeAt(1) - 0xDC00;
24002 cc = (high * 0x400) + low + 0x10000;
24004 (cc >= 0x4E00 && cc < 0xA000 ) ||
24005 (cc >= 0x3400 && cc < 0x4E00 ) ||
24006 (cc >= 0xf900 && cc < 0xfb00 )
24011 // No, use a numeric entity. Here we brazenly (and possibly mistakenly)
24012 return "&#" + cc + ";";
24019 if(this.owner.fireEvent('beforesync', this, html) !== false){
24020 this.el.dom.value = html;
24021 this.owner.fireEvent('sync', this, html);
24027 * Protected method that will not generally be called directly. Pushes the value of the textarea
24028 * into the iframe editor.
24030 pushValue : function(){
24031 if(this.initialized){
24032 var v = this.el.dom.value.trim();
24034 // if(v.length < 1){
24038 if(this.owner.fireEvent('beforepush', this, v) !== false){
24039 var d = (this.doc.body || this.doc.documentElement);
24041 this.cleanUpPaste();
24042 this.el.dom.value = d.innerHTML;
24043 this.owner.fireEvent('push', this, v);
24049 deferFocus : function(){
24050 this.focus.defer(10, this);
24054 focus : function(){
24055 if(this.win && !this.sourceEditMode){
24062 assignDocWin: function()
24064 var iframe = this.iframe;
24067 this.doc = iframe.contentWindow.document;
24068 this.win = iframe.contentWindow;
24070 // if (!Roo.get(this.frameId)) {
24073 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
24074 // this.win = Roo.get(this.frameId).dom.contentWindow;
24076 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
24080 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
24081 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
24086 initEditor : function(){
24087 //console.log("INIT EDITOR");
24088 this.assignDocWin();
24092 this.doc.designMode="on";
24094 this.doc.write(this.getDocMarkup());
24097 var dbody = (this.doc.body || this.doc.documentElement);
24098 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
24099 // this copies styles from the containing element into thsi one..
24100 // not sure why we need all of this..
24101 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
24103 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
24104 //ss['background-attachment'] = 'fixed'; // w3c
24105 dbody.bgProperties = 'fixed'; // ie
24106 //Roo.DomHelper.applyStyles(dbody, ss);
24107 Roo.EventManager.on(this.doc, {
24108 //'mousedown': this.onEditorEvent,
24109 'mouseup': this.onEditorEvent,
24110 'dblclick': this.onEditorEvent,
24111 'click': this.onEditorEvent,
24112 'keyup': this.onEditorEvent,
24117 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
24119 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
24120 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
24122 this.initialized = true;
24124 this.owner.fireEvent('initialize', this);
24129 onDestroy : function(){
24135 //for (var i =0; i < this.toolbars.length;i++) {
24136 // // fixme - ask toolbars for heights?
24137 // this.toolbars[i].onDestroy();
24140 //this.wrap.dom.innerHTML = '';
24141 //this.wrap.remove();
24146 onFirstFocus : function(){
24148 this.assignDocWin();
24151 this.activated = true;
24154 if(Roo.isGecko){ // prevent silly gecko errors
24156 var s = this.win.getSelection();
24157 if(!s.focusNode || s.focusNode.nodeType != 3){
24158 var r = s.getRangeAt(0);
24159 r.selectNodeContents((this.doc.body || this.doc.documentElement));
24164 this.execCmd('useCSS', true);
24165 this.execCmd('styleWithCSS', false);
24168 this.owner.fireEvent('activate', this);
24172 adjustFont: function(btn){
24173 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
24174 //if(Roo.isSafari){ // safari
24177 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
24178 if(Roo.isSafari){ // safari
24179 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
24180 v = (v < 10) ? 10 : v;
24181 v = (v > 48) ? 48 : v;
24182 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
24187 v = Math.max(1, v+adjust);
24189 this.execCmd('FontSize', v );
24192 onEditorEvent : function(e)
24194 this.owner.fireEvent('editorevent', this, e);
24195 // this.updateToolbar();
24196 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
24199 insertTag : function(tg)
24201 // could be a bit smarter... -> wrap the current selected tRoo..
24202 if (tg.toLowerCase() == 'span' ||
24203 tg.toLowerCase() == 'code' ||
24204 tg.toLowerCase() == 'sup' ||
24205 tg.toLowerCase() == 'sub'
24208 range = this.createRange(this.getSelection());
24209 var wrappingNode = this.doc.createElement(tg.toLowerCase());
24210 wrappingNode.appendChild(range.extractContents());
24211 range.insertNode(wrappingNode);
24218 this.execCmd("formatblock", tg);
24222 insertText : function(txt)
24226 var range = this.createRange();
24227 range.deleteContents();
24228 //alert(Sender.getAttribute('label'));
24230 range.insertNode(this.doc.createTextNode(txt));
24236 * Executes a Midas editor command on the editor document and performs necessary focus and
24237 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
24238 * @param {String} cmd The Midas command
24239 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
24241 relayCmd : function(cmd, value){
24243 this.execCmd(cmd, value);
24244 this.owner.fireEvent('editorevent', this);
24245 //this.updateToolbar();
24246 this.owner.deferFocus();
24250 * Executes a Midas editor command directly on the editor document.
24251 * For visual commands, you should use {@link #relayCmd} instead.
24252 * <b>This should only be called after the editor is initialized.</b>
24253 * @param {String} cmd The Midas command
24254 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
24256 execCmd : function(cmd, value){
24257 this.doc.execCommand(cmd, false, value === undefined ? null : value);
24264 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
24266 * @param {String} text | dom node..
24268 insertAtCursor : function(text)
24271 if(!this.activated){
24277 var r = this.doc.selection.createRange();
24288 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
24292 // from jquery ui (MIT licenced)
24294 var win = this.win;
24296 if (win.getSelection && win.getSelection().getRangeAt) {
24297 range = win.getSelection().getRangeAt(0);
24298 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
24299 range.insertNode(node);
24300 } else if (win.document.selection && win.document.selection.createRange) {
24301 // no firefox support
24302 var txt = typeof(text) == 'string' ? text : text.outerHTML;
24303 win.document.selection.createRange().pasteHTML(txt);
24305 // no firefox support
24306 var txt = typeof(text) == 'string' ? text : text.outerHTML;
24307 this.execCmd('InsertHTML', txt);
24316 mozKeyPress : function(e){
24318 var c = e.getCharCode(), cmd;
24321 c = String.fromCharCode(c).toLowerCase();
24335 this.cleanUpPaste.defer(100, this);
24343 e.preventDefault();
24351 fixKeys : function(){ // load time branching for fastest keydown performance
24353 return function(e){
24354 var k = e.getKey(), r;
24357 r = this.doc.selection.createRange();
24360 r.pasteHTML('    ');
24367 r = this.doc.selection.createRange();
24369 var target = r.parentElement();
24370 if(!target || target.tagName.toLowerCase() != 'li'){
24372 r.pasteHTML('<br />');
24378 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
24379 this.cleanUpPaste.defer(100, this);
24385 }else if(Roo.isOpera){
24386 return function(e){
24387 var k = e.getKey();
24391 this.execCmd('InsertHTML','    ');
24394 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
24395 this.cleanUpPaste.defer(100, this);
24400 }else if(Roo.isSafari){
24401 return function(e){
24402 var k = e.getKey();
24406 this.execCmd('InsertText','\t');
24410 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
24411 this.cleanUpPaste.defer(100, this);
24419 getAllAncestors: function()
24421 var p = this.getSelectedNode();
24424 a.push(p); // push blank onto stack..
24425 p = this.getParentElement();
24429 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
24433 a.push(this.doc.body);
24437 lastSelNode : false,
24440 getSelection : function()
24442 this.assignDocWin();
24443 return Roo.isIE ? this.doc.selection : this.win.getSelection();
24446 getSelectedNode: function()
24448 // this may only work on Gecko!!!
24450 // should we cache this!!!!
24455 var range = this.createRange(this.getSelection()).cloneRange();
24458 var parent = range.parentElement();
24460 var testRange = range.duplicate();
24461 testRange.moveToElementText(parent);
24462 if (testRange.inRange(range)) {
24465 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
24468 parent = parent.parentElement;
24473 // is ancestor a text element.
24474 var ac = range.commonAncestorContainer;
24475 if (ac.nodeType == 3) {
24476 ac = ac.parentNode;
24479 var ar = ac.childNodes;
24482 var other_nodes = [];
24483 var has_other_nodes = false;
24484 for (var i=0;i<ar.length;i++) {
24485 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
24488 // fullly contained node.
24490 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
24495 // probably selected..
24496 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
24497 other_nodes.push(ar[i]);
24501 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
24506 has_other_nodes = true;
24508 if (!nodes.length && other_nodes.length) {
24509 nodes= other_nodes;
24511 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
24517 createRange: function(sel)
24519 // this has strange effects when using with
24520 // top toolbar - not sure if it's a great idea.
24521 //this.editor.contentWindow.focus();
24522 if (typeof sel != "undefined") {
24524 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
24526 return this.doc.createRange();
24529 return this.doc.createRange();
24532 getParentElement: function()
24535 this.assignDocWin();
24536 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
24538 var range = this.createRange(sel);
24541 var p = range.commonAncestorContainer;
24542 while (p.nodeType == 3) { // text node
24553 * Range intersection.. the hard stuff...
24557 * [ -- selected range --- ]
24561 * if end is before start or hits it. fail.
24562 * if start is after end or hits it fail.
24564 * if either hits (but other is outside. - then it's not
24570 // @see http://www.thismuchiknow.co.uk/?p=64.
24571 rangeIntersectsNode : function(range, node)
24573 var nodeRange = node.ownerDocument.createRange();
24575 nodeRange.selectNode(node);
24577 nodeRange.selectNodeContents(node);
24580 var rangeStartRange = range.cloneRange();
24581 rangeStartRange.collapse(true);
24583 var rangeEndRange = range.cloneRange();
24584 rangeEndRange.collapse(false);
24586 var nodeStartRange = nodeRange.cloneRange();
24587 nodeStartRange.collapse(true);
24589 var nodeEndRange = nodeRange.cloneRange();
24590 nodeEndRange.collapse(false);
24592 return rangeStartRange.compareBoundaryPoints(
24593 Range.START_TO_START, nodeEndRange) == -1 &&
24594 rangeEndRange.compareBoundaryPoints(
24595 Range.START_TO_START, nodeStartRange) == 1;
24599 rangeCompareNode : function(range, node)
24601 var nodeRange = node.ownerDocument.createRange();
24603 nodeRange.selectNode(node);
24605 nodeRange.selectNodeContents(node);
24609 range.collapse(true);
24611 nodeRange.collapse(true);
24613 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
24614 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
24616 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
24618 var nodeIsBefore = ss == 1;
24619 var nodeIsAfter = ee == -1;
24621 if (nodeIsBefore && nodeIsAfter) {
24624 if (!nodeIsBefore && nodeIsAfter) {
24625 return 1; //right trailed.
24628 if (nodeIsBefore && !nodeIsAfter) {
24629 return 2; // left trailed.
24635 // private? - in a new class?
24636 cleanUpPaste : function()
24638 // cleans up the whole document..
24639 Roo.log('cleanuppaste');
24641 this.cleanUpChildren(this.doc.body);
24642 var clean = this.cleanWordChars(this.doc.body.innerHTML);
24643 if (clean != this.doc.body.innerHTML) {
24644 this.doc.body.innerHTML = clean;
24649 cleanWordChars : function(input) {// change the chars to hex code
24650 var he = Roo.HtmlEditorCore;
24652 var output = input;
24653 Roo.each(he.swapCodes, function(sw) {
24654 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
24656 output = output.replace(swapper, sw[1]);
24663 cleanUpChildren : function (n)
24665 if (!n.childNodes.length) {
24668 for (var i = n.childNodes.length-1; i > -1 ; i--) {
24669 this.cleanUpChild(n.childNodes[i]);
24676 cleanUpChild : function (node)
24679 //console.log(node);
24680 if (node.nodeName == "#text") {
24681 // clean up silly Windows -- stuff?
24684 if (node.nodeName == "#comment") {
24685 node.parentNode.removeChild(node);
24686 // clean up silly Windows -- stuff?
24689 var lcname = node.tagName.toLowerCase();
24690 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
24691 // whitelist of tags..
24693 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
24695 node.parentNode.removeChild(node);
24700 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
24702 // spans with no attributes - just remove them..
24703 if ((!node.attributes || !node.attributes.length) && lcname == 'span') {
24704 remove_keep_children = true;
24707 // remove <a name=....> as rendering on yahoo mailer is borked with this.
24708 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
24710 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
24711 // remove_keep_children = true;
24714 if (remove_keep_children) {
24715 this.cleanUpChildren(node);
24716 // inserts everything just before this node...
24717 while (node.childNodes.length) {
24718 var cn = node.childNodes[0];
24719 node.removeChild(cn);
24720 node.parentNode.insertBefore(cn, node);
24722 node.parentNode.removeChild(node);
24726 if (!node.attributes || !node.attributes.length) {
24731 this.cleanUpChildren(node);
24735 function cleanAttr(n,v)
24738 if (v.match(/^\./) || v.match(/^\//)) {
24741 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/) || v.match(/^ftp:/)) {
24744 if (v.match(/^#/)) {
24747 if (v.match(/^\{/)) { // allow template editing.
24750 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
24751 node.removeAttribute(n);
24755 var cwhite = this.cwhite;
24756 var cblack = this.cblack;
24758 function cleanStyle(n,v)
24760 if (v.match(/expression/)) { //XSS?? should we even bother..
24761 node.removeAttribute(n);
24765 var parts = v.split(/;/);
24768 Roo.each(parts, function(p) {
24769 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
24773 var l = p.split(':').shift().replace(/\s+/g,'');
24774 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
24776 if ( cwhite.length && cblack.indexOf(l) > -1) {
24777 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
24778 //node.removeAttribute(n);
24782 // only allow 'c whitelisted system attributes'
24783 if ( cwhite.length && cwhite.indexOf(l) < 0) {
24784 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
24785 //node.removeAttribute(n);
24795 if (clean.length) {
24796 node.setAttribute(n, clean.join(';'));
24798 node.removeAttribute(n);
24804 for (var i = node.attributes.length-1; i > -1 ; i--) {
24805 var a = node.attributes[i];
24808 if (a.name.toLowerCase().substr(0,2)=='on') {
24809 node.removeAttribute(a.name);
24812 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
24813 node.removeAttribute(a.name);
24816 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
24817 cleanAttr(a.name,a.value); // fixme..
24820 if (a.name == 'style') {
24821 cleanStyle(a.name,a.value);
24824 /// clean up MS crap..
24825 // tecnically this should be a list of valid class'es..
24828 if (a.name == 'class') {
24829 if (a.value.match(/^Mso/)) {
24830 node.removeAttribute('class');
24833 if (a.value.match(/^body$/)) {
24834 node.removeAttribute('class');
24845 this.cleanUpChildren(node);
24851 * Clean up MS wordisms...
24853 cleanWord : function(node)
24856 this.cleanWord(this.doc.body);
24861 node.nodeName == 'SPAN' &&
24862 !node.hasAttributes() &&
24863 node.childNodes.length == 1 &&
24864 node.firstChild.nodeName == "#text"
24866 var textNode = node.firstChild;
24867 node.removeChild(textNode);
24868 if (node.getAttribute('lang') != 'zh-CN') { // do not space pad on chinese characters..
24869 node.parentNode.insertBefore(node.ownerDocument.createTextNode(" "), node);
24871 node.parentNode.insertBefore(textNode, node);
24872 if (node.getAttribute('lang') != 'zh-CN') { // do not space pad on chinese characters..
24873 node.parentNode.insertBefore(node.ownerDocument.createTextNode(" ") , node);
24875 node.parentNode.removeChild(node);
24878 if (node.nodeName == "#text") {
24879 // clean up silly Windows -- stuff?
24882 if (node.nodeName == "#comment") {
24883 node.parentNode.removeChild(node);
24884 // clean up silly Windows -- stuff?
24888 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
24889 node.parentNode.removeChild(node);
24892 //Roo.log(node.tagName);
24893 // remove - but keep children..
24894 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|v:|font)/)) {
24895 //Roo.log('-- removed');
24896 while (node.childNodes.length) {
24897 var cn = node.childNodes[0];
24898 node.removeChild(cn);
24899 node.parentNode.insertBefore(cn, node);
24900 // move node to parent - and clean it..
24901 this.cleanWord(cn);
24903 node.parentNode.removeChild(node);
24904 /// no need to iterate chidlren = it's got none..
24905 //this.iterateChildren(node, this.cleanWord);
24909 if (node.className.length) {
24911 var cn = node.className.split(/\W+/);
24913 Roo.each(cn, function(cls) {
24914 if (cls.match(/Mso[a-zA-Z]+/)) {
24919 node.className = cna.length ? cna.join(' ') : '';
24921 node.removeAttribute("class");
24925 if (node.hasAttribute("lang")) {
24926 node.removeAttribute("lang");
24929 if (node.hasAttribute("style")) {
24931 var styles = node.getAttribute("style").split(";");
24933 Roo.each(styles, function(s) {
24934 if (!s.match(/:/)) {
24937 var kv = s.split(":");
24938 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
24941 // what ever is left... we allow.
24944 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
24945 if (!nstyle.length) {
24946 node.removeAttribute('style');
24949 this.iterateChildren(node, this.cleanWord);
24955 * iterateChildren of a Node, calling fn each time, using this as the scole..
24956 * @param {DomNode} node node to iterate children of.
24957 * @param {Function} fn method of this class to call on each item.
24959 iterateChildren : function(node, fn)
24961 if (!node.childNodes.length) {
24964 for (var i = node.childNodes.length-1; i > -1 ; i--) {
24965 fn.call(this, node.childNodes[i])
24971 * cleanTableWidths.
24973 * Quite often pasting from word etc.. results in tables with column and widths.
24974 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
24977 cleanTableWidths : function(node)
24982 this.cleanTableWidths(this.doc.body);
24987 if (node.nodeName == "#text" || node.nodeName == "#comment") {
24990 Roo.log(node.tagName);
24991 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
24992 this.iterateChildren(node, this.cleanTableWidths);
24995 if (node.hasAttribute('width')) {
24996 node.removeAttribute('width');
25000 if (node.hasAttribute("style")) {
25003 var styles = node.getAttribute("style").split(";");
25005 Roo.each(styles, function(s) {
25006 if (!s.match(/:/)) {
25009 var kv = s.split(":");
25010 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
25013 // what ever is left... we allow.
25016 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
25017 if (!nstyle.length) {
25018 node.removeAttribute('style');
25022 this.iterateChildren(node, this.cleanTableWidths);
25030 domToHTML : function(currentElement, depth, nopadtext) {
25032 depth = depth || 0;
25033 nopadtext = nopadtext || false;
25035 if (!currentElement) {
25036 return this.domToHTML(this.doc.body);
25039 //Roo.log(currentElement);
25041 var allText = false;
25042 var nodeName = currentElement.nodeName;
25043 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
25045 if (nodeName == '#text') {
25047 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
25052 if (nodeName != 'BODY') {
25055 // Prints the node tagName, such as <A>, <IMG>, etc
25058 for(i = 0; i < currentElement.attributes.length;i++) {
25060 var aname = currentElement.attributes.item(i).name;
25061 if (!currentElement.attributes.item(i).value.length) {
25064 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
25067 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
25076 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
25079 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
25084 // Traverse the tree
25086 var currentElementChild = currentElement.childNodes.item(i);
25087 var allText = true;
25088 var innerHTML = '';
25090 while (currentElementChild) {
25091 // Formatting code (indent the tree so it looks nice on the screen)
25092 var nopad = nopadtext;
25093 if (lastnode == 'SPAN') {
25097 if (currentElementChild.nodeName == '#text') {
25098 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
25099 toadd = nopadtext ? toadd : toadd.trim();
25100 if (!nopad && toadd.length > 80) {
25101 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
25103 innerHTML += toadd;
25106 currentElementChild = currentElement.childNodes.item(i);
25112 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
25114 // Recursively traverse the tree structure of the child node
25115 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
25116 lastnode = currentElementChild.nodeName;
25118 currentElementChild=currentElement.childNodes.item(i);
25124 // The remaining code is mostly for formatting the tree
25125 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
25130 ret+= "</"+tagName+">";
25136 applyBlacklists : function()
25138 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
25139 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
25143 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
25144 if (b.indexOf(tag) > -1) {
25147 this.white.push(tag);
25151 Roo.each(w, function(tag) {
25152 if (b.indexOf(tag) > -1) {
25155 if (this.white.indexOf(tag) > -1) {
25158 this.white.push(tag);
25163 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
25164 if (w.indexOf(tag) > -1) {
25167 this.black.push(tag);
25171 Roo.each(b, function(tag) {
25172 if (w.indexOf(tag) > -1) {
25175 if (this.black.indexOf(tag) > -1) {
25178 this.black.push(tag);
25183 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
25184 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
25188 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
25189 if (b.indexOf(tag) > -1) {
25192 this.cwhite.push(tag);
25196 Roo.each(w, function(tag) {
25197 if (b.indexOf(tag) > -1) {
25200 if (this.cwhite.indexOf(tag) > -1) {
25203 this.cwhite.push(tag);
25208 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
25209 if (w.indexOf(tag) > -1) {
25212 this.cblack.push(tag);
25216 Roo.each(b, function(tag) {
25217 if (w.indexOf(tag) > -1) {
25220 if (this.cblack.indexOf(tag) > -1) {
25223 this.cblack.push(tag);
25228 setStylesheets : function(stylesheets)
25230 if(typeof(stylesheets) == 'string'){
25231 Roo.get(this.iframe.contentDocument.head).createChild({
25233 rel : 'stylesheet',
25242 Roo.each(stylesheets, function(s) {
25247 Roo.get(_this.iframe.contentDocument.head).createChild({
25249 rel : 'stylesheet',
25258 removeStylesheets : function()
25262 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
25267 setStyle : function(style)
25269 Roo.get(this.iframe.contentDocument.head).createChild({
25278 // hide stuff that is not compatible
25292 * @event specialkey
25296 * @cfg {String} fieldClass @hide
25299 * @cfg {String} focusClass @hide
25302 * @cfg {String} autoCreate @hide
25305 * @cfg {String} inputType @hide
25308 * @cfg {String} invalidClass @hide
25311 * @cfg {String} invalidText @hide
25314 * @cfg {String} msgFx @hide
25317 * @cfg {String} validateOnBlur @hide
25321 Roo.HtmlEditorCore.white = [
25322 'area', 'br', 'img', 'input', 'hr', 'wbr',
25324 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
25325 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
25326 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
25327 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
25328 'table', 'ul', 'xmp',
25330 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
25333 'dir', 'menu', 'ol', 'ul', 'dl',
25339 Roo.HtmlEditorCore.black = [
25340 // 'embed', 'object', // enable - backend responsiblity to clean thiese
25342 'base', 'basefont', 'bgsound', 'blink', 'body',
25343 'frame', 'frameset', 'head', 'html', 'ilayer',
25344 'iframe', 'layer', 'link', 'meta', 'object',
25345 'script', 'style' ,'title', 'xml' // clean later..
25347 Roo.HtmlEditorCore.clean = [
25348 'script', 'style', 'title', 'xml'
25350 Roo.HtmlEditorCore.remove = [
25355 Roo.HtmlEditorCore.ablack = [
25359 Roo.HtmlEditorCore.aclean = [
25360 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
25364 Roo.HtmlEditorCore.pwhite= [
25365 'http', 'https', 'mailto'
25368 // white listed style attributes.
25369 Roo.HtmlEditorCore.cwhite= [
25370 // 'text-align', /// default is to allow most things..
25376 // black listed style attributes.
25377 Roo.HtmlEditorCore.cblack= [
25378 // 'font-size' -- this can be set by the project
25382 Roo.HtmlEditorCore.swapCodes =[
25401 * @class Roo.bootstrap.HtmlEditor
25402 * @extends Roo.bootstrap.TextArea
25403 * Bootstrap HtmlEditor class
25406 * Create a new HtmlEditor
25407 * @param {Object} config The config object
25410 Roo.bootstrap.HtmlEditor = function(config){
25411 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
25412 if (!this.toolbars) {
25413 this.toolbars = [];
25416 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
25419 * @event initialize
25420 * Fires when the editor is fully initialized (including the iframe)
25421 * @param {HtmlEditor} this
25426 * Fires when the editor is first receives the focus. Any insertion must wait
25427 * until after this event.
25428 * @param {HtmlEditor} this
25432 * @event beforesync
25433 * Fires before the textarea is updated with content from the editor iframe. Return false
25434 * to cancel the sync.
25435 * @param {HtmlEditor} this
25436 * @param {String} html
25440 * @event beforepush
25441 * Fires before the iframe editor is updated with content from the textarea. Return false
25442 * to cancel the push.
25443 * @param {HtmlEditor} this
25444 * @param {String} html
25449 * Fires when the textarea is updated with content from the editor iframe.
25450 * @param {HtmlEditor} this
25451 * @param {String} html
25456 * Fires when the iframe editor is updated with content from the textarea.
25457 * @param {HtmlEditor} this
25458 * @param {String} html
25462 * @event editmodechange
25463 * Fires when the editor switches edit modes
25464 * @param {HtmlEditor} this
25465 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
25467 editmodechange: true,
25469 * @event editorevent
25470 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
25471 * @param {HtmlEditor} this
25475 * @event firstfocus
25476 * Fires when on first focus - needed by toolbars..
25477 * @param {HtmlEditor} this
25482 * Auto save the htmlEditor value as a file into Events
25483 * @param {HtmlEditor} this
25487 * @event savedpreview
25488 * preview the saved version of htmlEditor
25489 * @param {HtmlEditor} this
25496 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
25500 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
25505 * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
25510 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
25515 * @cfg {Number} height (in pixels)
25519 * @cfg {Number} width (in pixels)
25524 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
25527 stylesheets: false,
25532 // private properties
25533 validationEvent : false,
25535 initialized : false,
25538 onFocus : Roo.emptyFn,
25540 hideMode:'offsets',
25542 tbContainer : false,
25546 toolbarContainer :function() {
25547 return this.wrap.select('.x-html-editor-tb',true).first();
25551 * Protected method that will not generally be called directly. It
25552 * is called when the editor creates its toolbar. Override this method if you need to
25553 * add custom toolbar buttons.
25554 * @param {HtmlEditor} editor
25556 createToolbar : function(){
25557 Roo.log('renewing');
25558 Roo.log("create toolbars");
25560 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
25561 this.toolbars[0].render(this.toolbarContainer());
25565 // if (!editor.toolbars || !editor.toolbars.length) {
25566 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
25569 // for (var i =0 ; i < editor.toolbars.length;i++) {
25570 // editor.toolbars[i] = Roo.factory(
25571 // typeof(editor.toolbars[i]) == 'string' ?
25572 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
25573 // Roo.bootstrap.HtmlEditor);
25574 // editor.toolbars[i].init(editor);
25580 onRender : function(ct, position)
25582 // Roo.log("Call onRender: " + this.xtype);
25584 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
25586 this.wrap = this.inputEl().wrap({
25587 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
25590 this.editorcore.onRender(ct, position);
25592 if (this.resizable) {
25593 this.resizeEl = new Roo.Resizable(this.wrap, {
25597 minHeight : this.height,
25598 height: this.height,
25599 handles : this.resizable,
25602 resize : function(r, w, h) {
25603 _t.onResize(w,h); // -something
25609 this.createToolbar(this);
25612 if(!this.width && this.resizable){
25613 this.setSize(this.wrap.getSize());
25615 if (this.resizeEl) {
25616 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
25617 // should trigger onReize..
25623 onResize : function(w, h)
25625 Roo.log('resize: ' +w + ',' + h );
25626 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
25630 if(this.inputEl() ){
25631 if(typeof w == 'number'){
25632 var aw = w - this.wrap.getFrameWidth('lr');
25633 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
25636 if(typeof h == 'number'){
25637 var tbh = -11; // fixme it needs to tool bar size!
25638 for (var i =0; i < this.toolbars.length;i++) {
25639 // fixme - ask toolbars for heights?
25640 tbh += this.toolbars[i].el.getHeight();
25641 //if (this.toolbars[i].footer) {
25642 // tbh += this.toolbars[i].footer.el.getHeight();
25650 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
25651 ah -= 5; // knock a few pixes off for look..
25652 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
25656 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
25657 this.editorcore.onResize(ew,eh);
25662 * Toggles the editor between standard and source edit mode.
25663 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
25665 toggleSourceEdit : function(sourceEditMode)
25667 this.editorcore.toggleSourceEdit(sourceEditMode);
25669 if(this.editorcore.sourceEditMode){
25670 Roo.log('editor - showing textarea');
25673 // Roo.log(this.syncValue());
25675 this.inputEl().removeClass(['hide', 'x-hidden']);
25676 this.inputEl().dom.removeAttribute('tabIndex');
25677 this.inputEl().focus();
25679 Roo.log('editor - hiding textarea');
25681 // Roo.log(this.pushValue());
25684 this.inputEl().addClass(['hide', 'x-hidden']);
25685 this.inputEl().dom.setAttribute('tabIndex', -1);
25686 //this.deferFocus();
25689 if(this.resizable){
25690 this.setSize(this.wrap.getSize());
25693 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
25696 // private (for BoxComponent)
25697 adjustSize : Roo.BoxComponent.prototype.adjustSize,
25699 // private (for BoxComponent)
25700 getResizeEl : function(){
25704 // private (for BoxComponent)
25705 getPositionEl : function(){
25710 initEvents : function(){
25711 this.originalValue = this.getValue();
25715 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
25718 // markInvalid : Roo.emptyFn,
25720 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
25723 // clearInvalid : Roo.emptyFn,
25725 setValue : function(v){
25726 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
25727 this.editorcore.pushValue();
25732 deferFocus : function(){
25733 this.focus.defer(10, this);
25737 focus : function(){
25738 this.editorcore.focus();
25744 onDestroy : function(){
25750 for (var i =0; i < this.toolbars.length;i++) {
25751 // fixme - ask toolbars for heights?
25752 this.toolbars[i].onDestroy();
25755 this.wrap.dom.innerHTML = '';
25756 this.wrap.remove();
25761 onFirstFocus : function(){
25762 //Roo.log("onFirstFocus");
25763 this.editorcore.onFirstFocus();
25764 for (var i =0; i < this.toolbars.length;i++) {
25765 this.toolbars[i].onFirstFocus();
25771 syncValue : function()
25773 this.editorcore.syncValue();
25776 pushValue : function()
25778 this.editorcore.pushValue();
25782 // hide stuff that is not compatible
25796 * @event specialkey
25800 * @cfg {String} fieldClass @hide
25803 * @cfg {String} focusClass @hide
25806 * @cfg {String} autoCreate @hide
25809 * @cfg {String} inputType @hide
25813 * @cfg {String} invalidText @hide
25816 * @cfg {String} msgFx @hide
25819 * @cfg {String} validateOnBlur @hide
25828 Roo.namespace('Roo.bootstrap.htmleditor');
25830 * @class Roo.bootstrap.HtmlEditorToolbar1
25836 new Roo.bootstrap.HtmlEditor({
25839 new Roo.bootstrap.HtmlEditorToolbar1({
25840 disable : { fonts: 1 , format: 1, ..., ... , ...],
25846 * @cfg {Object} disable List of elements to disable..
25847 * @cfg {Array} btns List of additional buttons.
25851 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
25854 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
25857 Roo.apply(this, config);
25859 // default disabled, based on 'good practice'..
25860 this.disable = this.disable || {};
25861 Roo.applyIf(this.disable, {
25864 specialElements : true
25866 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
25868 this.editor = config.editor;
25869 this.editorcore = config.editor.editorcore;
25871 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
25873 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
25874 // dont call parent... till later.
25876 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
25881 editorcore : false,
25886 "h1","h2","h3","h4","h5","h6",
25888 "abbr", "acronym", "address", "cite", "samp", "var",
25892 onRender : function(ct, position)
25894 // Roo.log("Call onRender: " + this.xtype);
25896 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
25898 this.el.dom.style.marginBottom = '0';
25900 var editorcore = this.editorcore;
25901 var editor= this.editor;
25904 var btn = function(id,cmd , toggle, handler, html){
25906 var event = toggle ? 'toggle' : 'click';
25911 xns: Roo.bootstrap,
25915 enableToggle:toggle !== false,
25917 pressed : toggle ? false : null,
25920 a.listeners[toggle ? 'toggle' : 'click'] = function() {
25921 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
25927 // var cb_box = function...
25932 xns: Roo.bootstrap,
25937 xns: Roo.bootstrap,
25941 Roo.each(this.formats, function(f) {
25942 style.menu.items.push({
25944 xns: Roo.bootstrap,
25945 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
25950 editorcore.insertTag(this.tagname);
25957 children.push(style);
25959 btn('bold',false,true);
25960 btn('italic',false,true);
25961 btn('align-left', 'justifyleft',true);
25962 btn('align-center', 'justifycenter',true);
25963 btn('align-right' , 'justifyright',true);
25964 btn('link', false, false, function(btn) {
25965 //Roo.log("create link?");
25966 var url = prompt(this.createLinkText, this.defaultLinkValue);
25967 if(url && url != 'http:/'+'/'){
25968 this.editorcore.relayCmd('createlink', url);
25971 btn('list','insertunorderedlist',true);
25972 btn('pencil', false,true, function(btn){
25974 this.toggleSourceEdit(btn.pressed);
25977 if (this.editor.btns.length > 0) {
25978 for (var i = 0; i<this.editor.btns.length; i++) {
25979 children.push(this.editor.btns[i]);
25987 xns: Roo.bootstrap,
25992 xns: Roo.bootstrap,
25997 cog.menu.items.push({
25999 xns: Roo.bootstrap,
26000 html : Clean styles,
26005 editorcore.insertTag(this.tagname);
26014 this.xtype = 'NavSimplebar';
26016 for(var i=0;i< children.length;i++) {
26018 this.buttons.add(this.addxtypeChild(children[i]));
26022 editor.on('editorevent', this.updateToolbar, this);
26024 onBtnClick : function(id)
26026 this.editorcore.relayCmd(id);
26027 this.editorcore.focus();
26031 * Protected method that will not generally be called directly. It triggers
26032 * a toolbar update by reading the markup state of the current selection in the editor.
26034 updateToolbar: function(){
26036 if(!this.editorcore.activated){
26037 this.editor.onFirstFocus(); // is this neeed?
26041 var btns = this.buttons;
26042 var doc = this.editorcore.doc;
26043 btns.get('bold').setActive(doc.queryCommandState('bold'));
26044 btns.get('italic').setActive(doc.queryCommandState('italic'));
26045 //btns.get('underline').setActive(doc.queryCommandState('underline'));
26047 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
26048 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
26049 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
26051 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
26052 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
26055 var ans = this.editorcore.getAllAncestors();
26056 if (this.formatCombo) {
26059 var store = this.formatCombo.store;
26060 this.formatCombo.setValue("");
26061 for (var i =0; i < ans.length;i++) {
26062 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
26064 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
26072 // hides menus... - so this cant be on a menu...
26073 Roo.bootstrap.MenuMgr.hideAll();
26075 Roo.bootstrap.MenuMgr.hideAll();
26076 //this.editorsyncValue();
26078 onFirstFocus: function() {
26079 this.buttons.each(function(item){
26083 toggleSourceEdit : function(sourceEditMode){
26086 if(sourceEditMode){
26087 Roo.log("disabling buttons");
26088 this.buttons.each( function(item){
26089 if(item.cmd != 'pencil'){
26095 Roo.log("enabling buttons");
26096 if(this.editorcore.initialized){
26097 this.buttons.each( function(item){
26103 Roo.log("calling toggole on editor");
26104 // tell the editor that it's been pressed..
26105 this.editor.toggleSourceEdit(sourceEditMode);
26119 * @class Roo.bootstrap.Markdown
26120 * @extends Roo.bootstrap.TextArea
26121 * Bootstrap Showdown editable area
26122 * @cfg {string} content
26125 * Create a new Showdown
26128 Roo.bootstrap.Markdown = function(config){
26129 Roo.bootstrap.Markdown.superclass.constructor.call(this, config);
26133 Roo.extend(Roo.bootstrap.Markdown, Roo.bootstrap.TextArea, {
26137 initEvents : function()
26140 Roo.bootstrap.TextArea.prototype.initEvents.call(this);
26141 this.markdownEl = this.el.createChild({
26142 cls : 'roo-markdown-area'
26144 this.inputEl().addClass('d-none');
26145 if (this.getValue() == '') {
26146 this.markdownEl.dom.innerHTML = String.format('<span class="roo-placeholder">{0}</span>', this.placeholder || '');
26149 this.markdownEl.dom.innerHTML = Roo.Markdown.toHtml(Roo.util.Format.htmlEncode(this.getValue()));
26151 this.markdownEl.on('click', this.toggleTextEdit, this);
26152 this.on('blur', this.toggleTextEdit, this);
26153 this.on('specialkey', this.resizeTextArea, this);
26156 toggleTextEdit : function()
26158 var sh = this.markdownEl.getHeight();
26159 this.inputEl().addClass('d-none');
26160 this.markdownEl.addClass('d-none');
26161 if (!this.editing) {
26163 this.inputEl().setHeight(Math.min(500, Math.max(sh,(this.getValue().split("\n").length+1) * 30)));
26164 this.inputEl().removeClass('d-none');
26165 this.inputEl().focus();
26166 this.editing = true;
26169 // show showdown...
26170 this.updateMarkdown();
26171 this.markdownEl.removeClass('d-none');
26172 this.editing = false;
26175 updateMarkdown : function()
26177 if (this.getValue() == '') {
26178 this.markdownEl.dom.innerHTML = String.format('<span class="roo-placeholder">{0}</span>', this.placeholder || '');
26182 this.markdownEl.dom.innerHTML = Roo.Markdown.toHtml(Roo.util.Format.htmlEncode(this.getValue()));
26185 resizeTextArea: function () {
26188 Roo.log([sh, this.getValue().split("\n").length * 30]);
26189 this.inputEl().setHeight(Math.min(500, Math.max(sh, (this.getValue().split("\n").length +1) * 30)));
26191 setValue : function(val)
26193 Roo.bootstrap.TextArea.prototype.setValue.call(this,val);
26194 if (!this.editing) {
26195 this.updateMarkdown();
26201 if (!this.editing) {
26202 this.toggleTextEdit();
26210 * @class Roo.bootstrap.Table.AbstractSelectionModel
26211 * @extends Roo.util.Observable
26212 * Abstract base class for grid SelectionModels. It provides the interface that should be
26213 * implemented by descendant classes. This class should not be directly instantiated.
26216 Roo.bootstrap.Table.AbstractSelectionModel = function(){
26217 this.locked = false;
26218 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
26222 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
26223 /** @ignore Called by the grid automatically. Do not call directly. */
26224 init : function(grid){
26230 * Locks the selections.
26233 this.locked = true;
26237 * Unlocks the selections.
26239 unlock : function(){
26240 this.locked = false;
26244 * Returns true if the selections are locked.
26245 * @return {Boolean}
26247 isLocked : function(){
26248 return this.locked;
26252 initEvents : function ()
26258 * @extends Roo.bootstrap.Table.AbstractSelectionModel
26259 * @class Roo.bootstrap.Table.RowSelectionModel
26260 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
26261 * It supports multiple selections and keyboard selection/navigation.
26263 * @param {Object} config
26266 Roo.bootstrap.Table.RowSelectionModel = function(config){
26267 Roo.apply(this, config);
26268 this.selections = new Roo.util.MixedCollection(false, function(o){
26273 this.lastActive = false;
26277 * @event selectionchange
26278 * Fires when the selection changes
26279 * @param {SelectionModel} this
26281 "selectionchange" : true,
26283 * @event afterselectionchange
26284 * Fires after the selection changes (eg. by key press or clicking)
26285 * @param {SelectionModel} this
26287 "afterselectionchange" : true,
26289 * @event beforerowselect
26290 * Fires when a row is selected being selected, return false to cancel.
26291 * @param {SelectionModel} this
26292 * @param {Number} rowIndex The selected index
26293 * @param {Boolean} keepExisting False if other selections will be cleared
26295 "beforerowselect" : true,
26298 * Fires when a row is selected.
26299 * @param {SelectionModel} this
26300 * @param {Number} rowIndex The selected index
26301 * @param {Roo.data.Record} r The record
26303 "rowselect" : true,
26305 * @event rowdeselect
26306 * Fires when a row is deselected.
26307 * @param {SelectionModel} this
26308 * @param {Number} rowIndex The selected index
26310 "rowdeselect" : true
26312 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
26313 this.locked = false;
26316 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
26318 * @cfg {Boolean} singleSelect
26319 * True to allow selection of only one row at a time (defaults to false)
26321 singleSelect : false,
26324 initEvents : function()
26327 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
26328 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
26329 //}else{ // allow click to work like normal
26330 // this.grid.on("rowclick", this.handleDragableRowClick, this);
26332 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
26333 this.grid.on("rowclick", this.handleMouseDown, this);
26335 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
26336 "up" : function(e){
26338 this.selectPrevious(e.shiftKey);
26339 }else if(this.last !== false && this.lastActive !== false){
26340 var last = this.last;
26341 this.selectRange(this.last, this.lastActive-1);
26342 this.grid.getView().focusRow(this.lastActive);
26343 if(last !== false){
26347 this.selectFirstRow();
26349 this.fireEvent("afterselectionchange", this);
26351 "down" : function(e){
26353 this.selectNext(e.shiftKey);
26354 }else if(this.last !== false && this.lastActive !== false){
26355 var last = this.last;
26356 this.selectRange(this.last, this.lastActive+1);
26357 this.grid.getView().focusRow(this.lastActive);
26358 if(last !== false){
26362 this.selectFirstRow();
26364 this.fireEvent("afterselectionchange", this);
26368 this.grid.store.on('load', function(){
26369 this.selections.clear();
26372 var view = this.grid.view;
26373 view.on("refresh", this.onRefresh, this);
26374 view.on("rowupdated", this.onRowUpdated, this);
26375 view.on("rowremoved", this.onRemove, this);
26380 onRefresh : function()
26382 var ds = this.grid.store, i, v = this.grid.view;
26383 var s = this.selections;
26384 s.each(function(r){
26385 if((i = ds.indexOfId(r.id)) != -1){
26394 onRemove : function(v, index, r){
26395 this.selections.remove(r);
26399 onRowUpdated : function(v, index, r){
26400 if(this.isSelected(r)){
26401 v.onRowSelect(index);
26407 * @param {Array} records The records to select
26408 * @param {Boolean} keepExisting (optional) True to keep existing selections
26410 selectRecords : function(records, keepExisting)
26413 this.clearSelections();
26415 var ds = this.grid.store;
26416 for(var i = 0, len = records.length; i < len; i++){
26417 this.selectRow(ds.indexOf(records[i]), true);
26422 * Gets the number of selected rows.
26425 getCount : function(){
26426 return this.selections.length;
26430 * Selects the first row in the grid.
26432 selectFirstRow : function(){
26437 * Select the last row.
26438 * @param {Boolean} keepExisting (optional) True to keep existing selections
26440 selectLastRow : function(keepExisting){
26441 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
26442 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
26446 * Selects the row immediately following the last selected row.
26447 * @param {Boolean} keepExisting (optional) True to keep existing selections
26449 selectNext : function(keepExisting)
26451 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
26452 this.selectRow(this.last+1, keepExisting);
26453 this.grid.getView().focusRow(this.last);
26458 * Selects the row that precedes the last selected row.
26459 * @param {Boolean} keepExisting (optional) True to keep existing selections
26461 selectPrevious : function(keepExisting){
26463 this.selectRow(this.last-1, keepExisting);
26464 this.grid.getView().focusRow(this.last);
26469 * Returns the selected records
26470 * @return {Array} Array of selected records
26472 getSelections : function(){
26473 return [].concat(this.selections.items);
26477 * Returns the first selected record.
26480 getSelected : function(){
26481 return this.selections.itemAt(0);
26486 * Clears all selections.
26488 clearSelections : function(fast)
26494 var ds = this.grid.store;
26495 var s = this.selections;
26496 s.each(function(r){
26497 this.deselectRow(ds.indexOfId(r.id));
26501 this.selections.clear();
26508 * Selects all rows.
26510 selectAll : function(){
26514 this.selections.clear();
26515 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
26516 this.selectRow(i, true);
26521 * Returns True if there is a selection.
26522 * @return {Boolean}
26524 hasSelection : function(){
26525 return this.selections.length > 0;
26529 * Returns True if the specified row is selected.
26530 * @param {Number/Record} record The record or index of the record to check
26531 * @return {Boolean}
26533 isSelected : function(index){
26534 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
26535 return (r && this.selections.key(r.id) ? true : false);
26539 * Returns True if the specified record id is selected.
26540 * @param {String} id The id of record to check
26541 * @return {Boolean}
26543 isIdSelected : function(id){
26544 return (this.selections.key(id) ? true : false);
26549 handleMouseDBClick : function(e, t){
26553 handleMouseDown : function(e, t)
26555 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
26556 if(this.isLocked() || rowIndex < 0 ){
26559 if(e.shiftKey && this.last !== false){
26560 var last = this.last;
26561 this.selectRange(last, rowIndex, e.ctrlKey);
26562 this.last = last; // reset the last
26566 var isSelected = this.isSelected(rowIndex);
26567 //Roo.log("select row:" + rowIndex);
26569 this.deselectRow(rowIndex);
26571 this.selectRow(rowIndex, true);
26575 if(e.button !== 0 && isSelected){
26576 alert('rowIndex 2: ' + rowIndex);
26577 view.focusRow(rowIndex);
26578 }else if(e.ctrlKey && isSelected){
26579 this.deselectRow(rowIndex);
26580 }else if(!isSelected){
26581 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
26582 view.focusRow(rowIndex);
26586 this.fireEvent("afterselectionchange", this);
26589 handleDragableRowClick : function(grid, rowIndex, e)
26591 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
26592 this.selectRow(rowIndex, false);
26593 grid.view.focusRow(rowIndex);
26594 this.fireEvent("afterselectionchange", this);
26599 * Selects multiple rows.
26600 * @param {Array} rows Array of the indexes of the row to select
26601 * @param {Boolean} keepExisting (optional) True to keep existing selections
26603 selectRows : function(rows, keepExisting){
26605 this.clearSelections();
26607 for(var i = 0, len = rows.length; i < len; i++){
26608 this.selectRow(rows[i], true);
26613 * Selects a range of rows. All rows in between startRow and endRow are also selected.
26614 * @param {Number} startRow The index of the first row in the range
26615 * @param {Number} endRow The index of the last row in the range
26616 * @param {Boolean} keepExisting (optional) True to retain existing selections
26618 selectRange : function(startRow, endRow, keepExisting){
26623 this.clearSelections();
26625 if(startRow <= endRow){
26626 for(var i = startRow; i <= endRow; i++){
26627 this.selectRow(i, true);
26630 for(var i = startRow; i >= endRow; i--){
26631 this.selectRow(i, true);
26637 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
26638 * @param {Number} startRow The index of the first row in the range
26639 * @param {Number} endRow The index of the last row in the range
26641 deselectRange : function(startRow, endRow, preventViewNotify){
26645 for(var i = startRow; i <= endRow; i++){
26646 this.deselectRow(i, preventViewNotify);
26652 * @param {Number} row The index of the row to select
26653 * @param {Boolean} keepExisting (optional) True to keep existing selections
26655 selectRow : function(index, keepExisting, preventViewNotify)
26657 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
26660 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
26661 if(!keepExisting || this.singleSelect){
26662 this.clearSelections();
26665 var r = this.grid.store.getAt(index);
26666 //console.log('selectRow - record id :' + r.id);
26668 this.selections.add(r);
26669 this.last = this.lastActive = index;
26670 if(!preventViewNotify){
26671 var proxy = new Roo.Element(
26672 this.grid.getRowDom(index)
26674 proxy.addClass('bg-info info');
26676 this.fireEvent("rowselect", this, index, r);
26677 this.fireEvent("selectionchange", this);
26683 * @param {Number} row The index of the row to deselect
26685 deselectRow : function(index, preventViewNotify)
26690 if(this.last == index){
26693 if(this.lastActive == index){
26694 this.lastActive = false;
26697 var r = this.grid.store.getAt(index);
26702 this.selections.remove(r);
26703 //.console.log('deselectRow - record id :' + r.id);
26704 if(!preventViewNotify){
26706 var proxy = new Roo.Element(
26707 this.grid.getRowDom(index)
26709 proxy.removeClass('bg-info info');
26711 this.fireEvent("rowdeselect", this, index);
26712 this.fireEvent("selectionchange", this);
26716 restoreLast : function(){
26718 this.last = this._last;
26723 acceptsNav : function(row, col, cm){
26724 return !cm.isHidden(col) && cm.isCellEditable(col, row);
26728 onEditorKey : function(field, e){
26729 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
26734 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
26736 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
26738 }else if(k == e.ENTER && !e.ctrlKey){
26742 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
26744 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
26746 }else if(k == e.ESC){
26750 g.startEditing(newCell[0], newCell[1]);
26756 * Ext JS Library 1.1.1
26757 * Copyright(c) 2006-2007, Ext JS, LLC.
26759 * Originally Released Under LGPL - original licence link has changed is not relivant.
26762 * <script type="text/javascript">
26766 * @class Roo.bootstrap.PagingToolbar
26767 * @extends Roo.bootstrap.NavSimplebar
26768 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
26770 * Create a new PagingToolbar
26771 * @param {Object} config The config object
26772 * @param {Roo.data.Store} store
26774 Roo.bootstrap.PagingToolbar = function(config)
26776 // old args format still supported... - xtype is prefered..
26777 // created from xtype...
26779 this.ds = config.dataSource;
26781 if (config.store && !this.ds) {
26782 this.store= Roo.factory(config.store, Roo.data);
26783 this.ds = this.store;
26784 this.ds.xmodule = this.xmodule || false;
26787 this.toolbarItems = [];
26788 if (config.items) {
26789 this.toolbarItems = config.items;
26792 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
26797 this.bind(this.ds);
26800 if (Roo.bootstrap.version == 4) {
26801 this.navgroup = new Roo.bootstrap.ButtonGroup({ cls: 'pagination' });
26803 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
26808 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
26810 * @cfg {Roo.data.Store} dataSource
26811 * The underlying data store providing the paged data
26814 * @cfg {String/HTMLElement/Element} container
26815 * container The id or element that will contain the toolbar
26818 * @cfg {Boolean} displayInfo
26819 * True to display the displayMsg (defaults to false)
26822 * @cfg {Number} pageSize
26823 * The number of records to display per page (defaults to 20)
26827 * @cfg {String} displayMsg
26828 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
26830 displayMsg : 'Displaying {0} - {1} of {2}',
26832 * @cfg {String} emptyMsg
26833 * The message to display when no records are found (defaults to "No data to display")
26835 emptyMsg : 'No data to display',
26837 * Customizable piece of the default paging text (defaults to "Page")
26840 beforePageText : "Page",
26842 * Customizable piece of the default paging text (defaults to "of %0")
26845 afterPageText : "of {0}",
26847 * Customizable piece of the default paging text (defaults to "First Page")
26850 firstText : "First Page",
26852 * Customizable piece of the default paging text (defaults to "Previous Page")
26855 prevText : "Previous Page",
26857 * Customizable piece of the default paging text (defaults to "Next Page")
26860 nextText : "Next Page",
26862 * Customizable piece of the default paging text (defaults to "Last Page")
26865 lastText : "Last Page",
26867 * Customizable piece of the default paging text (defaults to "Refresh")
26870 refreshText : "Refresh",
26874 onRender : function(ct, position)
26876 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
26877 this.navgroup.parentId = this.id;
26878 this.navgroup.onRender(this.el, null);
26879 // add the buttons to the navgroup
26881 if(this.displayInfo){
26882 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
26883 this.displayEl = this.el.select('.x-paging-info', true).first();
26884 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
26885 // this.displayEl = navel.el.select('span',true).first();
26891 Roo.each(_this.buttons, function(e){ // this might need to use render????
26892 Roo.factory(e).render(_this.el);
26896 Roo.each(_this.toolbarItems, function(e) {
26897 _this.navgroup.addItem(e);
26901 this.first = this.navgroup.addItem({
26902 tooltip: this.firstText,
26903 cls: "prev btn-outline-secondary",
26904 html : ' <i class="fa fa-step-backward"></i>',
26906 preventDefault: true,
26907 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
26910 this.prev = this.navgroup.addItem({
26911 tooltip: this.prevText,
26912 cls: "prev btn-outline-secondary",
26913 html : ' <i class="fa fa-backward"></i>',
26915 preventDefault: true,
26916 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
26918 //this.addSeparator();
26921 var field = this.navgroup.addItem( {
26923 cls : 'x-paging-position btn-outline-secondary',
26925 html : this.beforePageText +
26926 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
26927 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
26930 this.field = field.el.select('input', true).first();
26931 this.field.on("keydown", this.onPagingKeydown, this);
26932 this.field.on("focus", function(){this.dom.select();});
26935 this.afterTextEl = field.el.select('.x-paging-after',true).first();
26936 //this.field.setHeight(18);
26937 //this.addSeparator();
26938 this.next = this.navgroup.addItem({
26939 tooltip: this.nextText,
26940 cls: "next btn-outline-secondary",
26941 html : ' <i class="fa fa-forward"></i>',
26943 preventDefault: true,
26944 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
26946 this.last = this.navgroup.addItem({
26947 tooltip: this.lastText,
26948 html : ' <i class="fa fa-step-forward"></i>',
26949 cls: "next btn-outline-secondary",
26951 preventDefault: true,
26952 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
26954 //this.addSeparator();
26955 this.loading = this.navgroup.addItem({
26956 tooltip: this.refreshText,
26957 cls: "btn-outline-secondary",
26958 html : ' <i class="fa fa-refresh"></i>',
26959 preventDefault: true,
26960 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
26966 updateInfo : function(){
26967 if(this.displayEl){
26968 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
26969 var msg = count == 0 ?
26973 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
26975 this.displayEl.update(msg);
26980 onLoad : function(ds, r, o)
26982 this.cursor = o.params.start ? o.params.start : 0;
26984 var d = this.getPageData(),
26989 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
26990 this.field.dom.value = ap;
26991 this.first.setDisabled(ap == 1);
26992 this.prev.setDisabled(ap == 1);
26993 this.next.setDisabled(ap == ps);
26994 this.last.setDisabled(ap == ps);
26995 this.loading.enable();
27000 getPageData : function(){
27001 var total = this.ds.getTotalCount();
27004 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
27005 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
27010 onLoadError : function(){
27011 this.loading.enable();
27015 onPagingKeydown : function(e){
27016 var k = e.getKey();
27017 var d = this.getPageData();
27019 var v = this.field.dom.value, pageNum;
27020 if(!v || isNaN(pageNum = parseInt(v, 10))){
27021 this.field.dom.value = d.activePage;
27024 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
27025 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
27028 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))
27030 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
27031 this.field.dom.value = pageNum;
27032 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
27035 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
27037 var v = this.field.dom.value, pageNum;
27038 var increment = (e.shiftKey) ? 10 : 1;
27039 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
27042 if(!v || isNaN(pageNum = parseInt(v, 10))) {
27043 this.field.dom.value = d.activePage;
27046 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
27048 this.field.dom.value = parseInt(v, 10) + increment;
27049 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
27050 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
27057 beforeLoad : function(){
27059 this.loading.disable();
27064 onClick : function(which){
27073 ds.load({params:{start: 0, limit: this.pageSize}});
27076 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
27079 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
27082 var total = ds.getTotalCount();
27083 var extra = total % this.pageSize;
27084 var lastStart = extra ? (total - extra) : total-this.pageSize;
27085 ds.load({params:{start: lastStart, limit: this.pageSize}});
27088 ds.load({params:{start: this.cursor, limit: this.pageSize}});
27094 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
27095 * @param {Roo.data.Store} store The data store to unbind
27097 unbind : function(ds){
27098 ds.un("beforeload", this.beforeLoad, this);
27099 ds.un("load", this.onLoad, this);
27100 ds.un("loadexception", this.onLoadError, this);
27101 ds.un("remove", this.updateInfo, this);
27102 ds.un("add", this.updateInfo, this);
27103 this.ds = undefined;
27107 * Binds the paging toolbar to the specified {@link Roo.data.Store}
27108 * @param {Roo.data.Store} store The data store to bind
27110 bind : function(ds){
27111 ds.on("beforeload", this.beforeLoad, this);
27112 ds.on("load", this.onLoad, this);
27113 ds.on("loadexception", this.onLoadError, this);
27114 ds.on("remove", this.updateInfo, this);
27115 ds.on("add", this.updateInfo, this);
27126 * @class Roo.bootstrap.MessageBar
27127 * @extends Roo.bootstrap.Component
27128 * Bootstrap MessageBar class
27129 * @cfg {String} html contents of the MessageBar
27130 * @cfg {String} weight (info | success | warning | danger) default info
27131 * @cfg {String} beforeClass insert the bar before the given class
27132 * @cfg {Boolean} closable (true | false) default false
27133 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
27136 * Create a new Element
27137 * @param {Object} config The config object
27140 Roo.bootstrap.MessageBar = function(config){
27141 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
27144 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
27150 beforeClass: 'bootstrap-sticky-wrap',
27152 getAutoCreate : function(){
27156 cls: 'alert alert-dismissable alert-' + this.weight,
27161 html: this.html || ''
27167 cfg.cls += ' alert-messages-fixed';
27181 onRender : function(ct, position)
27183 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
27186 var cfg = Roo.apply({}, this.getAutoCreate());
27190 cfg.cls += ' ' + this.cls;
27193 cfg.style = this.style;
27195 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
27197 this.el.setVisibilityMode(Roo.Element.DISPLAY);
27200 this.el.select('>button.close').on('click', this.hide, this);
27206 if (!this.rendered) {
27212 this.fireEvent('show', this);
27218 if (!this.rendered) {
27224 this.fireEvent('hide', this);
27227 update : function()
27229 // var e = this.el.dom.firstChild;
27231 // if(this.closable){
27232 // e = e.nextSibling;
27235 // e.data = this.html || '';
27237 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
27253 * @class Roo.bootstrap.Graph
27254 * @extends Roo.bootstrap.Component
27255 * Bootstrap Graph class
27259 @cfg {String} graphtype bar | vbar | pie
27260 @cfg {number} g_x coodinator | centre x (pie)
27261 @cfg {number} g_y coodinator | centre y (pie)
27262 @cfg {number} g_r radius (pie)
27263 @cfg {number} g_height height of the chart (respected by all elements in the set)
27264 @cfg {number} g_width width of the chart (respected by all elements in the set)
27265 @cfg {Object} title The title of the chart
27268 -opts (object) options for the chart
27270 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
27271 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
27273 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.
27274 o stacked (boolean) whether or not to tread values as in a stacked bar chart
27276 o stretch (boolean)
27278 -opts (object) options for the pie
27281 o startAngle (number)
27282 o endAngle (number)
27286 * Create a new Input
27287 * @param {Object} config The config object
27290 Roo.bootstrap.Graph = function(config){
27291 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
27297 * The img click event for the img.
27298 * @param {Roo.EventObject} e
27304 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
27315 //g_colors: this.colors,
27322 getAutoCreate : function(){
27333 onRender : function(ct,position){
27336 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
27338 if (typeof(Raphael) == 'undefined') {
27339 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
27343 this.raphael = Raphael(this.el.dom);
27345 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
27346 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
27347 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
27348 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
27350 r.text(160, 10, "Single Series Chart").attr(txtattr);
27351 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
27352 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
27353 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
27355 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
27356 r.barchart(330, 10, 300, 220, data1);
27357 r.barchart(10, 250, 300, 220, data2, {stacked: true});
27358 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
27361 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
27362 // r.barchart(30, 30, 560, 250, xdata, {
27363 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
27364 // axis : "0 0 1 1",
27365 // axisxlabels : xdata
27366 // //yvalues : cols,
27369 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
27371 // this.load(null,xdata,{
27372 // axis : "0 0 1 1",
27373 // axisxlabels : xdata
27378 load : function(graphtype,xdata,opts)
27380 this.raphael.clear();
27382 graphtype = this.graphtype;
27387 var r = this.raphael,
27388 fin = function () {
27389 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
27391 fout = function () {
27392 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
27394 pfin = function() {
27395 this.sector.stop();
27396 this.sector.scale(1.1, 1.1, this.cx, this.cy);
27399 this.label[0].stop();
27400 this.label[0].attr({ r: 7.5 });
27401 this.label[1].attr({ "font-weight": 800 });
27404 pfout = function() {
27405 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
27408 this.label[0].animate({ r: 5 }, 500, "bounce");
27409 this.label[1].attr({ "font-weight": 400 });
27415 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
27418 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
27421 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
27422 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
27424 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
27431 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
27436 setTitle: function(o)
27441 initEvents: function() {
27444 this.el.on('click', this.onClick, this);
27448 onClick : function(e)
27450 Roo.log('img onclick');
27451 this.fireEvent('click', this, e);
27463 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
27466 * @class Roo.bootstrap.dash.NumberBox
27467 * @extends Roo.bootstrap.Component
27468 * Bootstrap NumberBox class
27469 * @cfg {String} headline Box headline
27470 * @cfg {String} content Box content
27471 * @cfg {String} icon Box icon
27472 * @cfg {String} footer Footer text
27473 * @cfg {String} fhref Footer href
27476 * Create a new NumberBox
27477 * @param {Object} config The config object
27481 Roo.bootstrap.dash.NumberBox = function(config){
27482 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
27486 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
27495 getAutoCreate : function(){
27499 cls : 'small-box ',
27507 cls : 'roo-headline',
27508 html : this.headline
27512 cls : 'roo-content',
27513 html : this.content
27527 cls : 'ion ' + this.icon
27536 cls : 'small-box-footer',
27537 href : this.fhref || '#',
27541 cfg.cn.push(footer);
27548 onRender : function(ct,position){
27549 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
27556 setHeadline: function (value)
27558 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
27561 setFooter: function (value, href)
27563 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
27566 this.el.select('a.small-box-footer',true).first().attr('href', href);
27571 setContent: function (value)
27573 this.el.select('.roo-content',true).first().dom.innerHTML = value;
27576 initEvents: function()
27590 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
27593 * @class Roo.bootstrap.dash.TabBox
27594 * @extends Roo.bootstrap.Component
27595 * Bootstrap TabBox class
27596 * @cfg {String} title Title of the TabBox
27597 * @cfg {String} icon Icon of the TabBox
27598 * @cfg {Boolean} showtabs (true|false) show the tabs default true
27599 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
27602 * Create a new TabBox
27603 * @param {Object} config The config object
27607 Roo.bootstrap.dash.TabBox = function(config){
27608 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
27613 * When a pane is added
27614 * @param {Roo.bootstrap.dash.TabPane} pane
27618 * @event activatepane
27619 * When a pane is activated
27620 * @param {Roo.bootstrap.dash.TabPane} pane
27622 "activatepane" : true
27630 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
27635 tabScrollable : false,
27637 getChildContainer : function()
27639 return this.el.select('.tab-content', true).first();
27642 getAutoCreate : function(){
27646 cls: 'pull-left header',
27654 cls: 'fa ' + this.icon
27660 cls: 'nav nav-tabs pull-right',
27666 if(this.tabScrollable){
27673 cls: 'nav nav-tabs pull-right',
27684 cls: 'nav-tabs-custom',
27689 cls: 'tab-content no-padding',
27697 initEvents : function()
27699 //Roo.log('add add pane handler');
27700 this.on('addpane', this.onAddPane, this);
27703 * Updates the box title
27704 * @param {String} html to set the title to.
27706 setTitle : function(value)
27708 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
27710 onAddPane : function(pane)
27712 this.panes.push(pane);
27713 //Roo.log('addpane');
27715 // tabs are rendere left to right..
27716 if(!this.showtabs){
27720 var ctr = this.el.select('.nav-tabs', true).first();
27723 var existing = ctr.select('.nav-tab',true);
27724 var qty = existing.getCount();;
27727 var tab = ctr.createChild({
27729 cls : 'nav-tab' + (qty ? '' : ' active'),
27737 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
27740 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
27742 pane.el.addClass('active');
27747 onTabClick : function(ev,un,ob,pane)
27749 //Roo.log('tab - prev default');
27750 ev.preventDefault();
27753 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
27754 pane.tab.addClass('active');
27755 //Roo.log(pane.title);
27756 this.getChildContainer().select('.tab-pane',true).removeClass('active');
27757 // technically we should have a deactivate event.. but maybe add later.
27758 // and it should not de-activate the selected tab...
27759 this.fireEvent('activatepane', pane);
27760 pane.el.addClass('active');
27761 pane.fireEvent('activate');
27766 getActivePane : function()
27769 Roo.each(this.panes, function(p) {
27770 if(p.el.hasClass('active')){
27791 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
27793 * @class Roo.bootstrap.TabPane
27794 * @extends Roo.bootstrap.Component
27795 * Bootstrap TabPane class
27796 * @cfg {Boolean} active (false | true) Default false
27797 * @cfg {String} title title of panel
27801 * Create a new TabPane
27802 * @param {Object} config The config object
27805 Roo.bootstrap.dash.TabPane = function(config){
27806 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
27812 * When a pane is activated
27813 * @param {Roo.bootstrap.dash.TabPane} pane
27820 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
27825 // the tabBox that this is attached to.
27828 getAutoCreate : function()
27836 cfg.cls += ' active';
27841 initEvents : function()
27843 //Roo.log('trigger add pane handler');
27844 this.parent().fireEvent('addpane', this)
27848 * Updates the tab title
27849 * @param {String} html to set the title to.
27851 setTitle: function(str)
27857 this.tab.select('a', true).first().dom.innerHTML = str;
27874 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
27877 * @class Roo.bootstrap.menu.Menu
27878 * @extends Roo.bootstrap.Component
27879 * Bootstrap Menu class - container for Menu
27880 * @cfg {String} html Text of the menu
27881 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
27882 * @cfg {String} icon Font awesome icon
27883 * @cfg {String} pos Menu align to (top | bottom) default bottom
27887 * Create a new Menu
27888 * @param {Object} config The config object
27892 Roo.bootstrap.menu.Menu = function(config){
27893 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
27897 * @event beforeshow
27898 * Fires before this menu is displayed
27899 * @param {Roo.bootstrap.menu.Menu} this
27903 * @event beforehide
27904 * Fires before this menu is hidden
27905 * @param {Roo.bootstrap.menu.Menu} this
27910 * Fires after this menu is displayed
27911 * @param {Roo.bootstrap.menu.Menu} this
27916 * Fires after this menu is hidden
27917 * @param {Roo.bootstrap.menu.Menu} this
27922 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
27923 * @param {Roo.bootstrap.menu.Menu} this
27924 * @param {Roo.EventObject} e
27931 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
27935 weight : 'default',
27940 getChildContainer : function() {
27941 if(this.isSubMenu){
27945 return this.el.select('ul.dropdown-menu', true).first();
27948 getAutoCreate : function()
27953 cls : 'roo-menu-text',
27961 cls : 'fa ' + this.icon
27972 cls : 'dropdown-button btn btn-' + this.weight,
27977 cls : 'dropdown-toggle btn btn-' + this.weight,
27987 cls : 'dropdown-menu'
27993 if(this.pos == 'top'){
27994 cfg.cls += ' dropup';
27997 if(this.isSubMenu){
28000 cls : 'dropdown-menu'
28007 onRender : function(ct, position)
28009 this.isSubMenu = ct.hasClass('dropdown-submenu');
28011 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
28014 initEvents : function()
28016 if(this.isSubMenu){
28020 this.hidden = true;
28022 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
28023 this.triggerEl.on('click', this.onTriggerPress, this);
28025 this.buttonEl = this.el.select('button.dropdown-button', true).first();
28026 this.buttonEl.on('click', this.onClick, this);
28032 if(this.isSubMenu){
28036 return this.el.select('ul.dropdown-menu', true).first();
28039 onClick : function(e)
28041 this.fireEvent("click", this, e);
28044 onTriggerPress : function(e)
28046 if (this.isVisible()) {
28053 isVisible : function(){
28054 return !this.hidden;
28059 this.fireEvent("beforeshow", this);
28061 this.hidden = false;
28062 this.el.addClass('open');
28064 Roo.get(document).on("mouseup", this.onMouseUp, this);
28066 this.fireEvent("show", this);
28073 this.fireEvent("beforehide", this);
28075 this.hidden = true;
28076 this.el.removeClass('open');
28078 Roo.get(document).un("mouseup", this.onMouseUp);
28080 this.fireEvent("hide", this);
28083 onMouseUp : function()
28097 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
28100 * @class Roo.bootstrap.menu.Item
28101 * @extends Roo.bootstrap.Component
28102 * Bootstrap MenuItem class
28103 * @cfg {Boolean} submenu (true | false) default false
28104 * @cfg {String} html text of the item
28105 * @cfg {String} href the link
28106 * @cfg {Boolean} disable (true | false) default false
28107 * @cfg {Boolean} preventDefault (true | false) default true
28108 * @cfg {String} icon Font awesome icon
28109 * @cfg {String} pos Submenu align to (left | right) default right
28113 * Create a new Item
28114 * @param {Object} config The config object
28118 Roo.bootstrap.menu.Item = function(config){
28119 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
28123 * Fires when the mouse is hovering over this menu
28124 * @param {Roo.bootstrap.menu.Item} this
28125 * @param {Roo.EventObject} e
28130 * Fires when the mouse exits this menu
28131 * @param {Roo.bootstrap.menu.Item} this
28132 * @param {Roo.EventObject} e
28138 * The raw click event for the entire grid.
28139 * @param {Roo.EventObject} e
28145 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
28150 preventDefault: true,
28155 getAutoCreate : function()
28160 cls : 'roo-menu-item-text',
28168 cls : 'fa ' + this.icon
28177 href : this.href || '#',
28184 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
28188 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
28190 if(this.pos == 'left'){
28191 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
28198 initEvents : function()
28200 this.el.on('mouseover', this.onMouseOver, this);
28201 this.el.on('mouseout', this.onMouseOut, this);
28203 this.el.select('a', true).first().on('click', this.onClick, this);
28207 onClick : function(e)
28209 if(this.preventDefault){
28210 e.preventDefault();
28213 this.fireEvent("click", this, e);
28216 onMouseOver : function(e)
28218 if(this.submenu && this.pos == 'left'){
28219 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
28222 this.fireEvent("mouseover", this, e);
28225 onMouseOut : function(e)
28227 this.fireEvent("mouseout", this, e);
28239 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
28242 * @class Roo.bootstrap.menu.Separator
28243 * @extends Roo.bootstrap.Component
28244 * Bootstrap Separator class
28247 * Create a new Separator
28248 * @param {Object} config The config object
28252 Roo.bootstrap.menu.Separator = function(config){
28253 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
28256 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
28258 getAutoCreate : function(){
28279 * @class Roo.bootstrap.Tooltip
28280 * Bootstrap Tooltip class
28281 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
28282 * to determine which dom element triggers the tooltip.
28284 * It needs to add support for additional attributes like tooltip-position
28287 * Create a new Toolti
28288 * @param {Object} config The config object
28291 Roo.bootstrap.Tooltip = function(config){
28292 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
28294 this.alignment = Roo.bootstrap.Tooltip.alignment;
28296 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
28297 this.alignment = config.alignment;
28302 Roo.apply(Roo.bootstrap.Tooltip, {
28304 * @function init initialize tooltip monitoring.
28308 currentTip : false,
28309 currentRegion : false,
28315 Roo.get(document).on('mouseover', this.enter ,this);
28316 Roo.get(document).on('mouseout', this.leave, this);
28319 this.currentTip = new Roo.bootstrap.Tooltip();
28322 enter : function(ev)
28324 var dom = ev.getTarget();
28326 //Roo.log(['enter',dom]);
28327 var el = Roo.fly(dom);
28328 if (this.currentEl) {
28330 //Roo.log(this.currentEl);
28331 //Roo.log(this.currentEl.contains(dom));
28332 if (this.currentEl == el) {
28335 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
28341 if (this.currentTip.el) {
28342 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
28346 if(!el || el.dom == document){
28352 // you can not look for children, as if el is the body.. then everythign is the child..
28353 if (!el.attr('tooltip')) { //
28354 if (!el.select("[tooltip]").elements.length) {
28357 // is the mouse over this child...?
28358 bindEl = el.select("[tooltip]").first();
28359 var xy = ev.getXY();
28360 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
28361 //Roo.log("not in region.");
28364 //Roo.log("child element over..");
28367 this.currentEl = bindEl;
28368 this.currentTip.bind(bindEl);
28369 this.currentRegion = Roo.lib.Region.getRegion(dom);
28370 this.currentTip.enter();
28373 leave : function(ev)
28375 var dom = ev.getTarget();
28376 //Roo.log(['leave',dom]);
28377 if (!this.currentEl) {
28382 if (dom != this.currentEl.dom) {
28385 var xy = ev.getXY();
28386 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
28389 // only activate leave if mouse cursor is outside... bounding box..
28394 if (this.currentTip) {
28395 this.currentTip.leave();
28397 //Roo.log('clear currentEl');
28398 this.currentEl = false;
28403 'left' : ['r-l', [-2,0], 'right'],
28404 'right' : ['l-r', [2,0], 'left'],
28405 'bottom' : ['t-b', [0,2], 'top'],
28406 'top' : [ 'b-t', [0,-2], 'bottom']
28412 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
28417 delay : null, // can be { show : 300 , hide: 500}
28421 hoverState : null, //???
28423 placement : 'bottom',
28427 getAutoCreate : function(){
28434 cls : 'tooltip-arrow arrow'
28437 cls : 'tooltip-inner'
28444 bind : function(el)
28449 initEvents : function()
28451 this.arrowEl = this.el.select('.arrow', true).first();
28452 this.innerEl = this.el.select('.tooltip-inner', true).first();
28455 enter : function () {
28457 if (this.timeout != null) {
28458 clearTimeout(this.timeout);
28461 this.hoverState = 'in';
28462 //Roo.log("enter - show");
28463 if (!this.delay || !this.delay.show) {
28468 this.timeout = setTimeout(function () {
28469 if (_t.hoverState == 'in') {
28472 }, this.delay.show);
28476 clearTimeout(this.timeout);
28478 this.hoverState = 'out';
28479 if (!this.delay || !this.delay.hide) {
28485 this.timeout = setTimeout(function () {
28486 //Roo.log("leave - timeout");
28488 if (_t.hoverState == 'out') {
28490 Roo.bootstrap.Tooltip.currentEl = false;
28495 show : function (msg)
28498 this.render(document.body);
28501 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
28503 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
28505 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
28507 this.el.removeClass(['fade','top','bottom', 'left', 'right','in',
28508 'bs-tooltip-top','bs-tooltip-bottom', 'bs-tooltip-left', 'bs-tooltip-right']);
28510 var placement = typeof this.placement == 'function' ?
28511 this.placement.call(this, this.el, on_el) :
28514 var autoToken = /\s?auto?\s?/i;
28515 var autoPlace = autoToken.test(placement);
28517 placement = placement.replace(autoToken, '') || 'top';
28521 //this.el.setXY([0,0]);
28523 //this.el.dom.style.display='block';
28525 //this.el.appendTo(on_el);
28527 var p = this.getPosition();
28528 var box = this.el.getBox();
28534 var align = this.alignment[placement];
28536 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
28538 if(placement == 'top' || placement == 'bottom'){
28540 placement = 'right';
28543 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
28544 placement = 'left';
28547 var scroll = Roo.select('body', true).first().getScroll();
28549 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
28553 align = this.alignment[placement];
28555 this.arrowEl.setLeft((this.innerEl.getWidth()/2) - 5);
28559 this.el.alignTo(this.bindEl, align[0],align[1]);
28560 //var arrow = this.el.select('.arrow',true).first();
28561 //arrow.set(align[2],
28563 this.el.addClass(placement);
28564 this.el.addClass("bs-tooltip-"+ placement);
28566 this.el.addClass('in fade show');
28568 this.hoverState = null;
28570 if (this.el.hasClass('fade')) {
28585 //this.el.setXY([0,0]);
28586 this.el.removeClass(['show', 'in']);
28602 * @class Roo.bootstrap.LocationPicker
28603 * @extends Roo.bootstrap.Component
28604 * Bootstrap LocationPicker class
28605 * @cfg {Number} latitude Position when init default 0
28606 * @cfg {Number} longitude Position when init default 0
28607 * @cfg {Number} zoom default 15
28608 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
28609 * @cfg {Boolean} mapTypeControl default false
28610 * @cfg {Boolean} disableDoubleClickZoom default false
28611 * @cfg {Boolean} scrollwheel default true
28612 * @cfg {Boolean} streetViewControl default false
28613 * @cfg {Number} radius default 0
28614 * @cfg {String} locationName
28615 * @cfg {Boolean} draggable default true
28616 * @cfg {Boolean} enableAutocomplete default false
28617 * @cfg {Boolean} enableReverseGeocode default true
28618 * @cfg {String} markerTitle
28621 * Create a new LocationPicker
28622 * @param {Object} config The config object
28626 Roo.bootstrap.LocationPicker = function(config){
28628 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
28633 * Fires when the picker initialized.
28634 * @param {Roo.bootstrap.LocationPicker} this
28635 * @param {Google Location} location
28639 * @event positionchanged
28640 * Fires when the picker position changed.
28641 * @param {Roo.bootstrap.LocationPicker} this
28642 * @param {Google Location} location
28644 positionchanged : true,
28647 * Fires when the map resize.
28648 * @param {Roo.bootstrap.LocationPicker} this
28653 * Fires when the map show.
28654 * @param {Roo.bootstrap.LocationPicker} this
28659 * Fires when the map hide.
28660 * @param {Roo.bootstrap.LocationPicker} this
28665 * Fires when click the map.
28666 * @param {Roo.bootstrap.LocationPicker} this
28667 * @param {Map event} e
28671 * @event mapRightClick
28672 * Fires when right click the map.
28673 * @param {Roo.bootstrap.LocationPicker} this
28674 * @param {Map event} e
28676 mapRightClick : true,
28678 * @event markerClick
28679 * Fires when click the marker.
28680 * @param {Roo.bootstrap.LocationPicker} this
28681 * @param {Map event} e
28683 markerClick : true,
28685 * @event markerRightClick
28686 * Fires when right click the marker.
28687 * @param {Roo.bootstrap.LocationPicker} this
28688 * @param {Map event} e
28690 markerRightClick : true,
28692 * @event OverlayViewDraw
28693 * Fires when OverlayView Draw
28694 * @param {Roo.bootstrap.LocationPicker} this
28696 OverlayViewDraw : true,
28698 * @event OverlayViewOnAdd
28699 * Fires when OverlayView Draw
28700 * @param {Roo.bootstrap.LocationPicker} this
28702 OverlayViewOnAdd : true,
28704 * @event OverlayViewOnRemove
28705 * Fires when OverlayView Draw
28706 * @param {Roo.bootstrap.LocationPicker} this
28708 OverlayViewOnRemove : true,
28710 * @event OverlayViewShow
28711 * Fires when OverlayView Draw
28712 * @param {Roo.bootstrap.LocationPicker} this
28713 * @param {Pixel} cpx
28715 OverlayViewShow : true,
28717 * @event OverlayViewHide
28718 * Fires when OverlayView Draw
28719 * @param {Roo.bootstrap.LocationPicker} this
28721 OverlayViewHide : true,
28723 * @event loadexception
28724 * Fires when load google lib failed.
28725 * @param {Roo.bootstrap.LocationPicker} this
28727 loadexception : true
28732 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
28734 gMapContext: false,
28740 mapTypeControl: false,
28741 disableDoubleClickZoom: false,
28743 streetViewControl: false,
28747 enableAutocomplete: false,
28748 enableReverseGeocode: true,
28751 getAutoCreate: function()
28756 cls: 'roo-location-picker'
28762 initEvents: function(ct, position)
28764 if(!this.el.getWidth() || this.isApplied()){
28768 this.el.setVisibilityMode(Roo.Element.DISPLAY);
28773 initial: function()
28775 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
28776 this.fireEvent('loadexception', this);
28780 if(!this.mapTypeId){
28781 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
28784 this.gMapContext = this.GMapContext();
28786 this.initOverlayView();
28788 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
28792 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
28793 _this.setPosition(_this.gMapContext.marker.position);
28796 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
28797 _this.fireEvent('mapClick', this, event);
28801 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
28802 _this.fireEvent('mapRightClick', this, event);
28806 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
28807 _this.fireEvent('markerClick', this, event);
28811 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
28812 _this.fireEvent('markerRightClick', this, event);
28816 this.setPosition(this.gMapContext.location);
28818 this.fireEvent('initial', this, this.gMapContext.location);
28821 initOverlayView: function()
28825 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
28829 _this.fireEvent('OverlayViewDraw', _this);
28834 _this.fireEvent('OverlayViewOnAdd', _this);
28837 onRemove: function()
28839 _this.fireEvent('OverlayViewOnRemove', _this);
28842 show: function(cpx)
28844 _this.fireEvent('OverlayViewShow', _this, cpx);
28849 _this.fireEvent('OverlayViewHide', _this);
28855 fromLatLngToContainerPixel: function(event)
28857 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
28860 isApplied: function()
28862 return this.getGmapContext() == false ? false : true;
28865 getGmapContext: function()
28867 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
28870 GMapContext: function()
28872 var position = new google.maps.LatLng(this.latitude, this.longitude);
28874 var _map = new google.maps.Map(this.el.dom, {
28877 mapTypeId: this.mapTypeId,
28878 mapTypeControl: this.mapTypeControl,
28879 disableDoubleClickZoom: this.disableDoubleClickZoom,
28880 scrollwheel: this.scrollwheel,
28881 streetViewControl: this.streetViewControl,
28882 locationName: this.locationName,
28883 draggable: this.draggable,
28884 enableAutocomplete: this.enableAutocomplete,
28885 enableReverseGeocode: this.enableReverseGeocode
28888 var _marker = new google.maps.Marker({
28889 position: position,
28891 title: this.markerTitle,
28892 draggable: this.draggable
28899 location: position,
28900 radius: this.radius,
28901 locationName: this.locationName,
28902 addressComponents: {
28903 formatted_address: null,
28904 addressLine1: null,
28905 addressLine2: null,
28907 streetNumber: null,
28911 stateOrProvince: null
28914 domContainer: this.el.dom,
28915 geodecoder: new google.maps.Geocoder()
28919 drawCircle: function(center, radius, options)
28921 if (this.gMapContext.circle != null) {
28922 this.gMapContext.circle.setMap(null);
28926 options = Roo.apply({}, options, {
28927 strokeColor: "#0000FF",
28928 strokeOpacity: .35,
28930 fillColor: "#0000FF",
28934 options.map = this.gMapContext.map;
28935 options.radius = radius;
28936 options.center = center;
28937 this.gMapContext.circle = new google.maps.Circle(options);
28938 return this.gMapContext.circle;
28944 setPosition: function(location)
28946 this.gMapContext.location = location;
28947 this.gMapContext.marker.setPosition(location);
28948 this.gMapContext.map.panTo(location);
28949 this.drawCircle(location, this.gMapContext.radius, {});
28953 if (this.gMapContext.settings.enableReverseGeocode) {
28954 this.gMapContext.geodecoder.geocode({
28955 latLng: this.gMapContext.location
28956 }, function(results, status) {
28958 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
28959 _this.gMapContext.locationName = results[0].formatted_address;
28960 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
28962 _this.fireEvent('positionchanged', this, location);
28969 this.fireEvent('positionchanged', this, location);
28974 google.maps.event.trigger(this.gMapContext.map, "resize");
28976 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
28978 this.fireEvent('resize', this);
28981 setPositionByLatLng: function(latitude, longitude)
28983 this.setPosition(new google.maps.LatLng(latitude, longitude));
28986 getCurrentPosition: function()
28989 latitude: this.gMapContext.location.lat(),
28990 longitude: this.gMapContext.location.lng()
28994 getAddressName: function()
28996 return this.gMapContext.locationName;
28999 getAddressComponents: function()
29001 return this.gMapContext.addressComponents;
29004 address_component_from_google_geocode: function(address_components)
29008 for (var i = 0; i < address_components.length; i++) {
29009 var component = address_components[i];
29010 if (component.types.indexOf("postal_code") >= 0) {
29011 result.postalCode = component.short_name;
29012 } else if (component.types.indexOf("street_number") >= 0) {
29013 result.streetNumber = component.short_name;
29014 } else if (component.types.indexOf("route") >= 0) {
29015 result.streetName = component.short_name;
29016 } else if (component.types.indexOf("neighborhood") >= 0) {
29017 result.city = component.short_name;
29018 } else if (component.types.indexOf("locality") >= 0) {
29019 result.city = component.short_name;
29020 } else if (component.types.indexOf("sublocality") >= 0) {
29021 result.district = component.short_name;
29022 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
29023 result.stateOrProvince = component.short_name;
29024 } else if (component.types.indexOf("country") >= 0) {
29025 result.country = component.short_name;
29029 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
29030 result.addressLine2 = "";
29034 setZoomLevel: function(zoom)
29036 this.gMapContext.map.setZoom(zoom);
29049 this.fireEvent('show', this);
29060 this.fireEvent('hide', this);
29065 Roo.apply(Roo.bootstrap.LocationPicker, {
29067 OverlayView : function(map, options)
29069 options = options || {};
29076 * @class Roo.bootstrap.Alert
29077 * @extends Roo.bootstrap.Component
29078 * Bootstrap Alert class - shows an alert area box
29080 * <div class="alert alert-danger" role="alert"><span class="fa fa-exclamation-triangle"></span><span class="sr-only">Error:</span>
29081 Enter a valid email address
29084 * @cfg {String} title The title of alert
29085 * @cfg {String} html The content of alert
29086 * @cfg {String} weight ( success | info | warning | danger )
29087 * @cfg {String} faicon font-awesomeicon
29090 * Create a new alert
29091 * @param {Object} config The config object
29095 Roo.bootstrap.Alert = function(config){
29096 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
29100 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
29107 getAutoCreate : function()
29116 cls : 'roo-alert-icon'
29121 cls : 'roo-alert-title',
29126 cls : 'roo-alert-text',
29133 cfg.cn[0].cls += ' fa ' + this.faicon;
29137 cfg.cls += ' alert-' + this.weight;
29143 initEvents: function()
29145 this.el.setVisibilityMode(Roo.Element.DISPLAY);
29148 setTitle : function(str)
29150 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
29153 setText : function(str)
29155 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
29158 setWeight : function(weight)
29161 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
29164 this.weight = weight;
29166 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
29169 setIcon : function(icon)
29172 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
29175 this.faicon = icon;
29177 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
29198 * @class Roo.bootstrap.UploadCropbox
29199 * @extends Roo.bootstrap.Component
29200 * Bootstrap UploadCropbox class
29201 * @cfg {String} emptyText show when image has been loaded
29202 * @cfg {String} rotateNotify show when image too small to rotate
29203 * @cfg {Number} errorTimeout default 3000
29204 * @cfg {Number} minWidth default 300
29205 * @cfg {Number} minHeight default 300
29206 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
29207 * @cfg {Boolean} isDocument (true|false) default false
29208 * @cfg {String} url action url
29209 * @cfg {String} paramName default 'imageUpload'
29210 * @cfg {String} method default POST
29211 * @cfg {Boolean} loadMask (true|false) default true
29212 * @cfg {Boolean} loadingText default 'Loading...'
29215 * Create a new UploadCropbox
29216 * @param {Object} config The config object
29219 Roo.bootstrap.UploadCropbox = function(config){
29220 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
29224 * @event beforeselectfile
29225 * Fire before select file
29226 * @param {Roo.bootstrap.UploadCropbox} this
29228 "beforeselectfile" : true,
29231 * Fire after initEvent
29232 * @param {Roo.bootstrap.UploadCropbox} this
29237 * Fire after initEvent
29238 * @param {Roo.bootstrap.UploadCropbox} this
29239 * @param {String} data
29244 * Fire when preparing the file data
29245 * @param {Roo.bootstrap.UploadCropbox} this
29246 * @param {Object} file
29251 * Fire when get exception
29252 * @param {Roo.bootstrap.UploadCropbox} this
29253 * @param {XMLHttpRequest} xhr
29255 "exception" : true,
29257 * @event beforeloadcanvas
29258 * Fire before load the canvas
29259 * @param {Roo.bootstrap.UploadCropbox} this
29260 * @param {String} src
29262 "beforeloadcanvas" : true,
29265 * Fire when trash image
29266 * @param {Roo.bootstrap.UploadCropbox} this
29271 * Fire when download the image
29272 * @param {Roo.bootstrap.UploadCropbox} this
29276 * @event footerbuttonclick
29277 * Fire when footerbuttonclick
29278 * @param {Roo.bootstrap.UploadCropbox} this
29279 * @param {String} type
29281 "footerbuttonclick" : true,
29285 * @param {Roo.bootstrap.UploadCropbox} this
29290 * Fire when rotate the image
29291 * @param {Roo.bootstrap.UploadCropbox} this
29292 * @param {String} pos
29297 * Fire when inspect the file
29298 * @param {Roo.bootstrap.UploadCropbox} this
29299 * @param {Object} file
29304 * Fire when xhr upload the file
29305 * @param {Roo.bootstrap.UploadCropbox} this
29306 * @param {Object} data
29311 * Fire when arrange the file data
29312 * @param {Roo.bootstrap.UploadCropbox} this
29313 * @param {Object} formData
29318 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
29321 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
29323 emptyText : 'Click to upload image',
29324 rotateNotify : 'Image is too small to rotate',
29325 errorTimeout : 3000,
29339 cropType : 'image/jpeg',
29341 canvasLoaded : false,
29342 isDocument : false,
29344 paramName : 'imageUpload',
29346 loadingText : 'Loading...',
29349 getAutoCreate : function()
29353 cls : 'roo-upload-cropbox',
29357 cls : 'roo-upload-cropbox-selector',
29362 cls : 'roo-upload-cropbox-body',
29363 style : 'cursor:pointer',
29367 cls : 'roo-upload-cropbox-preview'
29371 cls : 'roo-upload-cropbox-thumb'
29375 cls : 'roo-upload-cropbox-empty-notify',
29376 html : this.emptyText
29380 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
29381 html : this.rotateNotify
29387 cls : 'roo-upload-cropbox-footer',
29390 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
29400 onRender : function(ct, position)
29402 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
29404 if (this.buttons.length) {
29406 Roo.each(this.buttons, function(bb) {
29408 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
29410 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
29416 this.maskEl = this.el;
29420 initEvents : function()
29422 this.urlAPI = (window.createObjectURL && window) ||
29423 (window.URL && URL.revokeObjectURL && URL) ||
29424 (window.webkitURL && webkitURL);
29426 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
29427 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29429 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
29430 this.selectorEl.hide();
29432 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
29433 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29435 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
29436 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29437 this.thumbEl.hide();
29439 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
29440 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29442 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
29443 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29444 this.errorEl.hide();
29446 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
29447 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29448 this.footerEl.hide();
29450 this.setThumbBoxSize();
29456 this.fireEvent('initial', this);
29463 window.addEventListener("resize", function() { _this.resize(); } );
29465 this.bodyEl.on('click', this.beforeSelectFile, this);
29468 this.bodyEl.on('touchstart', this.onTouchStart, this);
29469 this.bodyEl.on('touchmove', this.onTouchMove, this);
29470 this.bodyEl.on('touchend', this.onTouchEnd, this);
29474 this.bodyEl.on('mousedown', this.onMouseDown, this);
29475 this.bodyEl.on('mousemove', this.onMouseMove, this);
29476 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
29477 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
29478 Roo.get(document).on('mouseup', this.onMouseUp, this);
29481 this.selectorEl.on('change', this.onFileSelected, this);
29487 this.baseScale = 1;
29489 this.baseRotate = 1;
29490 this.dragable = false;
29491 this.pinching = false;
29494 this.cropData = false;
29495 this.notifyEl.dom.innerHTML = this.emptyText;
29497 this.selectorEl.dom.value = '';
29501 resize : function()
29503 if(this.fireEvent('resize', this) != false){
29504 this.setThumbBoxPosition();
29505 this.setCanvasPosition();
29509 onFooterButtonClick : function(e, el, o, type)
29512 case 'rotate-left' :
29513 this.onRotateLeft(e);
29515 case 'rotate-right' :
29516 this.onRotateRight(e);
29519 this.beforeSelectFile(e);
29534 this.fireEvent('footerbuttonclick', this, type);
29537 beforeSelectFile : function(e)
29539 e.preventDefault();
29541 if(this.fireEvent('beforeselectfile', this) != false){
29542 this.selectorEl.dom.click();
29546 onFileSelected : function(e)
29548 e.preventDefault();
29550 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
29554 var file = this.selectorEl.dom.files[0];
29556 if(this.fireEvent('inspect', this, file) != false){
29557 this.prepare(file);
29562 trash : function(e)
29564 this.fireEvent('trash', this);
29567 download : function(e)
29569 this.fireEvent('download', this);
29572 loadCanvas : function(src)
29574 if(this.fireEvent('beforeloadcanvas', this, src) != false){
29578 this.imageEl = document.createElement('img');
29582 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
29584 this.imageEl.src = src;
29588 onLoadCanvas : function()
29590 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
29591 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
29593 this.bodyEl.un('click', this.beforeSelectFile, this);
29595 this.notifyEl.hide();
29596 this.thumbEl.show();
29597 this.footerEl.show();
29599 this.baseRotateLevel();
29601 if(this.isDocument){
29602 this.setThumbBoxSize();
29605 this.setThumbBoxPosition();
29607 this.baseScaleLevel();
29613 this.canvasLoaded = true;
29616 this.maskEl.unmask();
29621 setCanvasPosition : function()
29623 if(!this.canvasEl){
29627 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
29628 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
29630 this.previewEl.setLeft(pw);
29631 this.previewEl.setTop(ph);
29635 onMouseDown : function(e)
29639 this.dragable = true;
29640 this.pinching = false;
29642 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
29643 this.dragable = false;
29647 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
29648 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
29652 onMouseMove : function(e)
29656 if(!this.canvasLoaded){
29660 if (!this.dragable){
29664 var minX = Math.ceil(this.thumbEl.getLeft(true));
29665 var minY = Math.ceil(this.thumbEl.getTop(true));
29667 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
29668 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
29670 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
29671 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
29673 x = x - this.mouseX;
29674 y = y - this.mouseY;
29676 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
29677 var bgY = Math.ceil(y + this.previewEl.getTop(true));
29679 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
29680 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
29682 this.previewEl.setLeft(bgX);
29683 this.previewEl.setTop(bgY);
29685 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
29686 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
29689 onMouseUp : function(e)
29693 this.dragable = false;
29696 onMouseWheel : function(e)
29700 this.startScale = this.scale;
29702 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
29704 if(!this.zoomable()){
29705 this.scale = this.startScale;
29714 zoomable : function()
29716 var minScale = this.thumbEl.getWidth() / this.minWidth;
29718 if(this.minWidth < this.minHeight){
29719 minScale = this.thumbEl.getHeight() / this.minHeight;
29722 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
29723 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
29727 (this.rotate == 0 || this.rotate == 180) &&
29729 width > this.imageEl.OriginWidth ||
29730 height > this.imageEl.OriginHeight ||
29731 (width < this.minWidth && height < this.minHeight)
29739 (this.rotate == 90 || this.rotate == 270) &&
29741 width > this.imageEl.OriginWidth ||
29742 height > this.imageEl.OriginHeight ||
29743 (width < this.minHeight && height < this.minWidth)
29750 !this.isDocument &&
29751 (this.rotate == 0 || this.rotate == 180) &&
29753 width < this.minWidth ||
29754 width > this.imageEl.OriginWidth ||
29755 height < this.minHeight ||
29756 height > this.imageEl.OriginHeight
29763 !this.isDocument &&
29764 (this.rotate == 90 || this.rotate == 270) &&
29766 width < this.minHeight ||
29767 width > this.imageEl.OriginWidth ||
29768 height < this.minWidth ||
29769 height > this.imageEl.OriginHeight
29779 onRotateLeft : function(e)
29781 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
29783 var minScale = this.thumbEl.getWidth() / this.minWidth;
29785 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
29786 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
29788 this.startScale = this.scale;
29790 while (this.getScaleLevel() < minScale){
29792 this.scale = this.scale + 1;
29794 if(!this.zoomable()){
29799 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
29800 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
29805 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
29812 this.scale = this.startScale;
29814 this.onRotateFail();
29819 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
29821 if(this.isDocument){
29822 this.setThumbBoxSize();
29823 this.setThumbBoxPosition();
29824 this.setCanvasPosition();
29829 this.fireEvent('rotate', this, 'left');
29833 onRotateRight : function(e)
29835 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
29837 var minScale = this.thumbEl.getWidth() / this.minWidth;
29839 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
29840 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
29842 this.startScale = this.scale;
29844 while (this.getScaleLevel() < minScale){
29846 this.scale = this.scale + 1;
29848 if(!this.zoomable()){
29853 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
29854 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
29859 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
29866 this.scale = this.startScale;
29868 this.onRotateFail();
29873 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
29875 if(this.isDocument){
29876 this.setThumbBoxSize();
29877 this.setThumbBoxPosition();
29878 this.setCanvasPosition();
29883 this.fireEvent('rotate', this, 'right');
29886 onRotateFail : function()
29888 this.errorEl.show(true);
29892 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
29897 this.previewEl.dom.innerHTML = '';
29899 var canvasEl = document.createElement("canvas");
29901 var contextEl = canvasEl.getContext("2d");
29903 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
29904 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
29905 var center = this.imageEl.OriginWidth / 2;
29907 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
29908 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
29909 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
29910 center = this.imageEl.OriginHeight / 2;
29913 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
29915 contextEl.translate(center, center);
29916 contextEl.rotate(this.rotate * Math.PI / 180);
29918 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
29920 this.canvasEl = document.createElement("canvas");
29922 this.contextEl = this.canvasEl.getContext("2d");
29924 switch (this.rotate) {
29927 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
29928 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
29930 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
29935 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
29936 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
29938 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
29939 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);
29943 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
29948 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
29949 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
29951 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
29952 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);
29956 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);
29961 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
29962 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
29964 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
29965 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
29969 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);
29976 this.previewEl.appendChild(this.canvasEl);
29978 this.setCanvasPosition();
29983 if(!this.canvasLoaded){
29987 var imageCanvas = document.createElement("canvas");
29989 var imageContext = imageCanvas.getContext("2d");
29991 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
29992 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
29994 var center = imageCanvas.width / 2;
29996 imageContext.translate(center, center);
29998 imageContext.rotate(this.rotate * Math.PI / 180);
30000 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
30002 var canvas = document.createElement("canvas");
30004 var context = canvas.getContext("2d");
30006 canvas.width = this.minWidth;
30007 canvas.height = this.minHeight;
30009 switch (this.rotate) {
30012 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
30013 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
30015 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
30016 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
30018 var targetWidth = this.minWidth - 2 * x;
30019 var targetHeight = this.minHeight - 2 * y;
30023 if((x == 0 && y == 0) || (x == 0 && y > 0)){
30024 scale = targetWidth / width;
30027 if(x > 0 && y == 0){
30028 scale = targetHeight / height;
30031 if(x > 0 && y > 0){
30032 scale = targetWidth / width;
30034 if(width < height){
30035 scale = targetHeight / height;
30039 context.scale(scale, scale);
30041 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
30042 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
30044 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
30045 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
30047 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
30052 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
30053 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
30055 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
30056 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
30058 var targetWidth = this.minWidth - 2 * x;
30059 var targetHeight = this.minHeight - 2 * y;
30063 if((x == 0 && y == 0) || (x == 0 && y > 0)){
30064 scale = targetWidth / width;
30067 if(x > 0 && y == 0){
30068 scale = targetHeight / height;
30071 if(x > 0 && y > 0){
30072 scale = targetWidth / width;
30074 if(width < height){
30075 scale = targetHeight / height;
30079 context.scale(scale, scale);
30081 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
30082 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
30084 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
30085 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
30087 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
30089 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
30094 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
30095 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
30097 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
30098 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
30100 var targetWidth = this.minWidth - 2 * x;
30101 var targetHeight = this.minHeight - 2 * y;
30105 if((x == 0 && y == 0) || (x == 0 && y > 0)){
30106 scale = targetWidth / width;
30109 if(x > 0 && y == 0){
30110 scale = targetHeight / height;
30113 if(x > 0 && y > 0){
30114 scale = targetWidth / width;
30116 if(width < height){
30117 scale = targetHeight / height;
30121 context.scale(scale, scale);
30123 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
30124 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
30126 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
30127 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
30129 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
30130 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
30132 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
30137 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
30138 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
30140 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
30141 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
30143 var targetWidth = this.minWidth - 2 * x;
30144 var targetHeight = this.minHeight - 2 * y;
30148 if((x == 0 && y == 0) || (x == 0 && y > 0)){
30149 scale = targetWidth / width;
30152 if(x > 0 && y == 0){
30153 scale = targetHeight / height;
30156 if(x > 0 && y > 0){
30157 scale = targetWidth / width;
30159 if(width < height){
30160 scale = targetHeight / height;
30164 context.scale(scale, scale);
30166 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
30167 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
30169 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
30170 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
30172 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
30174 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
30181 this.cropData = canvas.toDataURL(this.cropType);
30183 if(this.fireEvent('crop', this, this.cropData) !== false){
30184 this.process(this.file, this.cropData);
30191 setThumbBoxSize : function()
30195 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
30196 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
30197 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
30199 this.minWidth = width;
30200 this.minHeight = height;
30202 if(this.rotate == 90 || this.rotate == 270){
30203 this.minWidth = height;
30204 this.minHeight = width;
30209 width = Math.ceil(this.minWidth * height / this.minHeight);
30211 if(this.minWidth > this.minHeight){
30213 height = Math.ceil(this.minHeight * width / this.minWidth);
30216 this.thumbEl.setStyle({
30217 width : width + 'px',
30218 height : height + 'px'
30225 setThumbBoxPosition : function()
30227 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
30228 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
30230 this.thumbEl.setLeft(x);
30231 this.thumbEl.setTop(y);
30235 baseRotateLevel : function()
30237 this.baseRotate = 1;
30240 typeof(this.exif) != 'undefined' &&
30241 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
30242 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
30244 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
30247 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
30251 baseScaleLevel : function()
30255 if(this.isDocument){
30257 if(this.baseRotate == 6 || this.baseRotate == 8){
30259 height = this.thumbEl.getHeight();
30260 this.baseScale = height / this.imageEl.OriginWidth;
30262 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
30263 width = this.thumbEl.getWidth();
30264 this.baseScale = width / this.imageEl.OriginHeight;
30270 height = this.thumbEl.getHeight();
30271 this.baseScale = height / this.imageEl.OriginHeight;
30273 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
30274 width = this.thumbEl.getWidth();
30275 this.baseScale = width / this.imageEl.OriginWidth;
30281 if(this.baseRotate == 6 || this.baseRotate == 8){
30283 width = this.thumbEl.getHeight();
30284 this.baseScale = width / this.imageEl.OriginHeight;
30286 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
30287 height = this.thumbEl.getWidth();
30288 this.baseScale = height / this.imageEl.OriginHeight;
30291 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
30292 height = this.thumbEl.getWidth();
30293 this.baseScale = height / this.imageEl.OriginHeight;
30295 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
30296 width = this.thumbEl.getHeight();
30297 this.baseScale = width / this.imageEl.OriginWidth;
30304 width = this.thumbEl.getWidth();
30305 this.baseScale = width / this.imageEl.OriginWidth;
30307 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
30308 height = this.thumbEl.getHeight();
30309 this.baseScale = height / this.imageEl.OriginHeight;
30312 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
30314 height = this.thumbEl.getHeight();
30315 this.baseScale = height / this.imageEl.OriginHeight;
30317 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
30318 width = this.thumbEl.getWidth();
30319 this.baseScale = width / this.imageEl.OriginWidth;
30327 getScaleLevel : function()
30329 return this.baseScale * Math.pow(1.1, this.scale);
30332 onTouchStart : function(e)
30334 if(!this.canvasLoaded){
30335 this.beforeSelectFile(e);
30339 var touches = e.browserEvent.touches;
30345 if(touches.length == 1){
30346 this.onMouseDown(e);
30350 if(touches.length != 2){
30356 for(var i = 0, finger; finger = touches[i]; i++){
30357 coords.push(finger.pageX, finger.pageY);
30360 var x = Math.pow(coords[0] - coords[2], 2);
30361 var y = Math.pow(coords[1] - coords[3], 2);
30363 this.startDistance = Math.sqrt(x + y);
30365 this.startScale = this.scale;
30367 this.pinching = true;
30368 this.dragable = false;
30372 onTouchMove : function(e)
30374 if(!this.pinching && !this.dragable){
30378 var touches = e.browserEvent.touches;
30385 this.onMouseMove(e);
30391 for(var i = 0, finger; finger = touches[i]; i++){
30392 coords.push(finger.pageX, finger.pageY);
30395 var x = Math.pow(coords[0] - coords[2], 2);
30396 var y = Math.pow(coords[1] - coords[3], 2);
30398 this.endDistance = Math.sqrt(x + y);
30400 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
30402 if(!this.zoomable()){
30403 this.scale = this.startScale;
30411 onTouchEnd : function(e)
30413 this.pinching = false;
30414 this.dragable = false;
30418 process : function(file, crop)
30421 this.maskEl.mask(this.loadingText);
30424 this.xhr = new XMLHttpRequest();
30426 file.xhr = this.xhr;
30428 this.xhr.open(this.method, this.url, true);
30431 "Accept": "application/json",
30432 "Cache-Control": "no-cache",
30433 "X-Requested-With": "XMLHttpRequest"
30436 for (var headerName in headers) {
30437 var headerValue = headers[headerName];
30439 this.xhr.setRequestHeader(headerName, headerValue);
30445 this.xhr.onload = function()
30447 _this.xhrOnLoad(_this.xhr);
30450 this.xhr.onerror = function()
30452 _this.xhrOnError(_this.xhr);
30455 var formData = new FormData();
30457 formData.append('returnHTML', 'NO');
30460 formData.append('crop', crop);
30463 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
30464 formData.append(this.paramName, file, file.name);
30467 if(typeof(file.filename) != 'undefined'){
30468 formData.append('filename', file.filename);
30471 if(typeof(file.mimetype) != 'undefined'){
30472 formData.append('mimetype', file.mimetype);
30475 if(this.fireEvent('arrange', this, formData) != false){
30476 this.xhr.send(formData);
30480 xhrOnLoad : function(xhr)
30483 this.maskEl.unmask();
30486 if (xhr.readyState !== 4) {
30487 this.fireEvent('exception', this, xhr);
30491 var response = Roo.decode(xhr.responseText);
30493 if(!response.success){
30494 this.fireEvent('exception', this, xhr);
30498 var response = Roo.decode(xhr.responseText);
30500 this.fireEvent('upload', this, response);
30504 xhrOnError : function()
30507 this.maskEl.unmask();
30510 Roo.log('xhr on error');
30512 var response = Roo.decode(xhr.responseText);
30518 prepare : function(file)
30521 this.maskEl.mask(this.loadingText);
30527 if(typeof(file) === 'string'){
30528 this.loadCanvas(file);
30532 if(!file || !this.urlAPI){
30537 this.cropType = file.type;
30541 if(this.fireEvent('prepare', this, this.file) != false){
30543 var reader = new FileReader();
30545 reader.onload = function (e) {
30546 if (e.target.error) {
30547 Roo.log(e.target.error);
30551 var buffer = e.target.result,
30552 dataView = new DataView(buffer),
30554 maxOffset = dataView.byteLength - 4,
30558 if (dataView.getUint16(0) === 0xffd8) {
30559 while (offset < maxOffset) {
30560 markerBytes = dataView.getUint16(offset);
30562 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
30563 markerLength = dataView.getUint16(offset + 2) + 2;
30564 if (offset + markerLength > dataView.byteLength) {
30565 Roo.log('Invalid meta data: Invalid segment size.');
30569 if(markerBytes == 0xffe1){
30570 _this.parseExifData(
30577 offset += markerLength;
30587 var url = _this.urlAPI.createObjectURL(_this.file);
30589 _this.loadCanvas(url);
30594 reader.readAsArrayBuffer(this.file);
30600 parseExifData : function(dataView, offset, length)
30602 var tiffOffset = offset + 10,
30606 if (dataView.getUint32(offset + 4) !== 0x45786966) {
30607 // No Exif data, might be XMP data instead
30611 // Check for the ASCII code for "Exif" (0x45786966):
30612 if (dataView.getUint32(offset + 4) !== 0x45786966) {
30613 // No Exif data, might be XMP data instead
30616 if (tiffOffset + 8 > dataView.byteLength) {
30617 Roo.log('Invalid Exif data: Invalid segment size.');
30620 // Check for the two null bytes:
30621 if (dataView.getUint16(offset + 8) !== 0x0000) {
30622 Roo.log('Invalid Exif data: Missing byte alignment offset.');
30625 // Check the byte alignment:
30626 switch (dataView.getUint16(tiffOffset)) {
30628 littleEndian = true;
30631 littleEndian = false;
30634 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
30637 // Check for the TIFF tag marker (0x002A):
30638 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
30639 Roo.log('Invalid Exif data: Missing TIFF marker.');
30642 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
30643 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
30645 this.parseExifTags(
30648 tiffOffset + dirOffset,
30653 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
30658 if (dirOffset + 6 > dataView.byteLength) {
30659 Roo.log('Invalid Exif data: Invalid directory offset.');
30662 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
30663 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
30664 if (dirEndOffset + 4 > dataView.byteLength) {
30665 Roo.log('Invalid Exif data: Invalid directory size.');
30668 for (i = 0; i < tagsNumber; i += 1) {
30672 dirOffset + 2 + 12 * i, // tag offset
30676 // Return the offset to the next directory:
30677 return dataView.getUint32(dirEndOffset, littleEndian);
30680 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
30682 var tag = dataView.getUint16(offset, littleEndian);
30684 this.exif[tag] = this.getExifValue(
30688 dataView.getUint16(offset + 2, littleEndian), // tag type
30689 dataView.getUint32(offset + 4, littleEndian), // tag length
30694 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
30696 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
30705 Roo.log('Invalid Exif data: Invalid tag type.');
30709 tagSize = tagType.size * length;
30710 // Determine if the value is contained in the dataOffset bytes,
30711 // or if the value at the dataOffset is a pointer to the actual data:
30712 dataOffset = tagSize > 4 ?
30713 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
30714 if (dataOffset + tagSize > dataView.byteLength) {
30715 Roo.log('Invalid Exif data: Invalid data offset.');
30718 if (length === 1) {
30719 return tagType.getValue(dataView, dataOffset, littleEndian);
30722 for (i = 0; i < length; i += 1) {
30723 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
30726 if (tagType.ascii) {
30728 // Concatenate the chars:
30729 for (i = 0; i < values.length; i += 1) {
30731 // Ignore the terminating NULL byte(s):
30732 if (c === '\u0000') {
30744 Roo.apply(Roo.bootstrap.UploadCropbox, {
30746 'Orientation': 0x0112
30750 1: 0, //'top-left',
30752 3: 180, //'bottom-right',
30753 // 4: 'bottom-left',
30755 6: 90, //'right-top',
30756 // 7: 'right-bottom',
30757 8: 270 //'left-bottom'
30761 // byte, 8-bit unsigned int:
30763 getValue: function (dataView, dataOffset) {
30764 return dataView.getUint8(dataOffset);
30768 // ascii, 8-bit byte:
30770 getValue: function (dataView, dataOffset) {
30771 return String.fromCharCode(dataView.getUint8(dataOffset));
30776 // short, 16 bit int:
30778 getValue: function (dataView, dataOffset, littleEndian) {
30779 return dataView.getUint16(dataOffset, littleEndian);
30783 // long, 32 bit int:
30785 getValue: function (dataView, dataOffset, littleEndian) {
30786 return dataView.getUint32(dataOffset, littleEndian);
30790 // rational = two long values, first is numerator, second is denominator:
30792 getValue: function (dataView, dataOffset, littleEndian) {
30793 return dataView.getUint32(dataOffset, littleEndian) /
30794 dataView.getUint32(dataOffset + 4, littleEndian);
30798 // slong, 32 bit signed int:
30800 getValue: function (dataView, dataOffset, littleEndian) {
30801 return dataView.getInt32(dataOffset, littleEndian);
30805 // srational, two slongs, first is numerator, second is denominator:
30807 getValue: function (dataView, dataOffset, littleEndian) {
30808 return dataView.getInt32(dataOffset, littleEndian) /
30809 dataView.getInt32(dataOffset + 4, littleEndian);
30819 cls : 'btn-group roo-upload-cropbox-rotate-left',
30820 action : 'rotate-left',
30824 cls : 'btn btn-default',
30825 html : '<i class="fa fa-undo"></i>'
30831 cls : 'btn-group roo-upload-cropbox-picture',
30832 action : 'picture',
30836 cls : 'btn btn-default',
30837 html : '<i class="fa fa-picture-o"></i>'
30843 cls : 'btn-group roo-upload-cropbox-rotate-right',
30844 action : 'rotate-right',
30848 cls : 'btn btn-default',
30849 html : '<i class="fa fa-repeat"></i>'
30857 cls : 'btn-group roo-upload-cropbox-rotate-left',
30858 action : 'rotate-left',
30862 cls : 'btn btn-default',
30863 html : '<i class="fa fa-undo"></i>'
30869 cls : 'btn-group roo-upload-cropbox-download',
30870 action : 'download',
30874 cls : 'btn btn-default',
30875 html : '<i class="fa fa-download"></i>'
30881 cls : 'btn-group roo-upload-cropbox-crop',
30886 cls : 'btn btn-default',
30887 html : '<i class="fa fa-crop"></i>'
30893 cls : 'btn-group roo-upload-cropbox-trash',
30898 cls : 'btn btn-default',
30899 html : '<i class="fa fa-trash"></i>'
30905 cls : 'btn-group roo-upload-cropbox-rotate-right',
30906 action : 'rotate-right',
30910 cls : 'btn btn-default',
30911 html : '<i class="fa fa-repeat"></i>'
30919 cls : 'btn-group roo-upload-cropbox-rotate-left',
30920 action : 'rotate-left',
30924 cls : 'btn btn-default',
30925 html : '<i class="fa fa-undo"></i>'
30931 cls : 'btn-group roo-upload-cropbox-rotate-right',
30932 action : 'rotate-right',
30936 cls : 'btn btn-default',
30937 html : '<i class="fa fa-repeat"></i>'
30950 * @class Roo.bootstrap.DocumentManager
30951 * @extends Roo.bootstrap.Component
30952 * Bootstrap DocumentManager class
30953 * @cfg {String} paramName default 'imageUpload'
30954 * @cfg {String} toolTipName default 'filename'
30955 * @cfg {String} method default POST
30956 * @cfg {String} url action url
30957 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
30958 * @cfg {Boolean} multiple multiple upload default true
30959 * @cfg {Number} thumbSize default 300
30960 * @cfg {String} fieldLabel
30961 * @cfg {Number} labelWidth default 4
30962 * @cfg {String} labelAlign (left|top) default left
30963 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
30964 * @cfg {Number} labellg set the width of label (1-12)
30965 * @cfg {Number} labelmd set the width of label (1-12)
30966 * @cfg {Number} labelsm set the width of label (1-12)
30967 * @cfg {Number} labelxs set the width of label (1-12)
30970 * Create a new DocumentManager
30971 * @param {Object} config The config object
30974 Roo.bootstrap.DocumentManager = function(config){
30975 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
30978 this.delegates = [];
30983 * Fire when initial the DocumentManager
30984 * @param {Roo.bootstrap.DocumentManager} this
30989 * inspect selected file
30990 * @param {Roo.bootstrap.DocumentManager} this
30991 * @param {File} file
30996 * Fire when xhr load exception
30997 * @param {Roo.bootstrap.DocumentManager} this
30998 * @param {XMLHttpRequest} xhr
31000 "exception" : true,
31002 * @event afterupload
31003 * Fire when xhr load exception
31004 * @param {Roo.bootstrap.DocumentManager} this
31005 * @param {XMLHttpRequest} xhr
31007 "afterupload" : true,
31010 * prepare the form data
31011 * @param {Roo.bootstrap.DocumentManager} this
31012 * @param {Object} formData
31017 * Fire when remove the file
31018 * @param {Roo.bootstrap.DocumentManager} this
31019 * @param {Object} file
31024 * Fire after refresh the file
31025 * @param {Roo.bootstrap.DocumentManager} this
31030 * Fire after click the image
31031 * @param {Roo.bootstrap.DocumentManager} this
31032 * @param {Object} file
31037 * Fire when upload a image and editable set to true
31038 * @param {Roo.bootstrap.DocumentManager} this
31039 * @param {Object} file
31043 * @event beforeselectfile
31044 * Fire before select file
31045 * @param {Roo.bootstrap.DocumentManager} this
31047 "beforeselectfile" : true,
31050 * Fire before process file
31051 * @param {Roo.bootstrap.DocumentManager} this
31052 * @param {Object} file
31056 * @event previewrendered
31057 * Fire when preview rendered
31058 * @param {Roo.bootstrap.DocumentManager} this
31059 * @param {Object} file
31061 "previewrendered" : true,
31064 "previewResize" : true
31069 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
31078 paramName : 'imageUpload',
31079 toolTipName : 'filename',
31082 labelAlign : 'left',
31092 getAutoCreate : function()
31094 var managerWidget = {
31096 cls : 'roo-document-manager',
31100 cls : 'roo-document-manager-selector',
31105 cls : 'roo-document-manager-uploader',
31109 cls : 'roo-document-manager-upload-btn',
31110 html : '<i class="fa fa-plus"></i>'
31121 cls : 'column col-md-12',
31126 if(this.fieldLabel.length){
31131 cls : 'column col-md-12',
31132 html : this.fieldLabel
31136 cls : 'column col-md-12',
31141 if(this.labelAlign == 'left'){
31146 html : this.fieldLabel
31155 if(this.labelWidth > 12){
31156 content[0].style = "width: " + this.labelWidth + 'px';
31159 if(this.labelWidth < 13 && this.labelmd == 0){
31160 this.labelmd = this.labelWidth;
31163 if(this.labellg > 0){
31164 content[0].cls += ' col-lg-' + this.labellg;
31165 content[1].cls += ' col-lg-' + (12 - this.labellg);
31168 if(this.labelmd > 0){
31169 content[0].cls += ' col-md-' + this.labelmd;
31170 content[1].cls += ' col-md-' + (12 - this.labelmd);
31173 if(this.labelsm > 0){
31174 content[0].cls += ' col-sm-' + this.labelsm;
31175 content[1].cls += ' col-sm-' + (12 - this.labelsm);
31178 if(this.labelxs > 0){
31179 content[0].cls += ' col-xs-' + this.labelxs;
31180 content[1].cls += ' col-xs-' + (12 - this.labelxs);
31188 cls : 'row clearfix',
31196 initEvents : function()
31198 this.managerEl = this.el.select('.roo-document-manager', true).first();
31199 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
31201 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
31202 this.selectorEl.hide();
31205 this.selectorEl.attr('multiple', 'multiple');
31208 this.selectorEl.on('change', this.onFileSelected, this);
31210 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
31211 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
31213 this.uploader.on('click', this.onUploaderClick, this);
31215 this.renderProgressDialog();
31219 window.addEventListener("resize", function() { _this.refresh(); } );
31221 this.fireEvent('initial', this);
31224 renderProgressDialog : function()
31228 this.progressDialog = new Roo.bootstrap.Modal({
31229 cls : 'roo-document-manager-progress-dialog',
31230 allow_close : false,
31241 btnclick : function() {
31242 _this.uploadCancel();
31248 this.progressDialog.render(Roo.get(document.body));
31250 this.progress = new Roo.bootstrap.Progress({
31251 cls : 'roo-document-manager-progress',
31256 this.progress.render(this.progressDialog.getChildContainer());
31258 this.progressBar = new Roo.bootstrap.ProgressBar({
31259 cls : 'roo-document-manager-progress-bar',
31262 aria_valuemax : 12,
31266 this.progressBar.render(this.progress.getChildContainer());
31269 onUploaderClick : function(e)
31271 e.preventDefault();
31273 if(this.fireEvent('beforeselectfile', this) != false){
31274 this.selectorEl.dom.click();
31279 onFileSelected : function(e)
31281 e.preventDefault();
31283 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
31287 Roo.each(this.selectorEl.dom.files, function(file){
31288 if(this.fireEvent('inspect', this, file) != false){
31289 this.files.push(file);
31299 this.selectorEl.dom.value = '';
31301 if(!this.files || !this.files.length){
31305 if(this.boxes > 0 && this.files.length > this.boxes){
31306 this.files = this.files.slice(0, this.boxes);
31309 this.uploader.show();
31311 if(this.boxes > 0 && this.files.length > this.boxes - 1){
31312 this.uploader.hide();
31321 Roo.each(this.files, function(file){
31323 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
31324 var f = this.renderPreview(file);
31329 if(file.type.indexOf('image') != -1){
31330 this.delegates.push(
31332 _this.process(file);
31333 }).createDelegate(this)
31341 _this.process(file);
31342 }).createDelegate(this)
31347 this.files = files;
31349 this.delegates = this.delegates.concat(docs);
31351 if(!this.delegates.length){
31356 this.progressBar.aria_valuemax = this.delegates.length;
31363 arrange : function()
31365 if(!this.delegates.length){
31366 this.progressDialog.hide();
31371 var delegate = this.delegates.shift();
31373 this.progressDialog.show();
31375 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
31377 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
31382 refresh : function()
31384 this.uploader.show();
31386 if(this.boxes > 0 && this.files.length > this.boxes - 1){
31387 this.uploader.hide();
31390 Roo.isTouch ? this.closable(false) : this.closable(true);
31392 this.fireEvent('refresh', this);
31395 onRemove : function(e, el, o)
31397 e.preventDefault();
31399 this.fireEvent('remove', this, o);
31403 remove : function(o)
31407 Roo.each(this.files, function(file){
31408 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
31417 this.files = files;
31424 Roo.each(this.files, function(file){
31429 file.target.remove();
31438 onClick : function(e, el, o)
31440 e.preventDefault();
31442 this.fireEvent('click', this, o);
31446 closable : function(closable)
31448 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
31450 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
31462 xhrOnLoad : function(xhr)
31464 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
31468 if (xhr.readyState !== 4) {
31470 this.fireEvent('exception', this, xhr);
31474 var response = Roo.decode(xhr.responseText);
31476 if(!response.success){
31478 this.fireEvent('exception', this, xhr);
31482 var file = this.renderPreview(response.data);
31484 this.files.push(file);
31488 this.fireEvent('afterupload', this, xhr);
31492 xhrOnError : function(xhr)
31494 Roo.log('xhr on error');
31496 var response = Roo.decode(xhr.responseText);
31503 process : function(file)
31505 if(this.fireEvent('process', this, file) !== false){
31506 if(this.editable && file.type.indexOf('image') != -1){
31507 this.fireEvent('edit', this, file);
31511 this.uploadStart(file, false);
31518 uploadStart : function(file, crop)
31520 this.xhr = new XMLHttpRequest();
31522 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
31527 file.xhr = this.xhr;
31529 this.managerEl.createChild({
31531 cls : 'roo-document-manager-loading',
31535 tooltip : file.name,
31536 cls : 'roo-document-manager-thumb',
31537 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
31543 this.xhr.open(this.method, this.url, true);
31546 "Accept": "application/json",
31547 "Cache-Control": "no-cache",
31548 "X-Requested-With": "XMLHttpRequest"
31551 for (var headerName in headers) {
31552 var headerValue = headers[headerName];
31554 this.xhr.setRequestHeader(headerName, headerValue);
31560 this.xhr.onload = function()
31562 _this.xhrOnLoad(_this.xhr);
31565 this.xhr.onerror = function()
31567 _this.xhrOnError(_this.xhr);
31570 var formData = new FormData();
31572 formData.append('returnHTML', 'NO');
31575 formData.append('crop', crop);
31578 formData.append(this.paramName, file, file.name);
31585 if(this.fireEvent('prepare', this, formData, options) != false){
31587 if(options.manually){
31591 this.xhr.send(formData);
31595 this.uploadCancel();
31598 uploadCancel : function()
31604 this.delegates = [];
31606 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
31613 renderPreview : function(file)
31615 if(typeof(file.target) != 'undefined' && file.target){
31619 var img_src = encodeURI(baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename);
31621 var previewEl = this.managerEl.createChild({
31623 cls : 'roo-document-manager-preview',
31627 tooltip : file[this.toolTipName],
31628 cls : 'roo-document-manager-thumb',
31629 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + img_src + '">'
31634 html : '<i class="fa fa-times-circle"></i>'
31639 var close = previewEl.select('button.close', true).first();
31641 close.on('click', this.onRemove, this, file);
31643 file.target = previewEl;
31645 var image = previewEl.select('img', true).first();
31649 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
31651 image.on('click', this.onClick, this, file);
31653 this.fireEvent('previewrendered', this, file);
31659 onPreviewLoad : function(file, image)
31661 if(typeof(file.target) == 'undefined' || !file.target){
31665 var width = image.dom.naturalWidth || image.dom.width;
31666 var height = image.dom.naturalHeight || image.dom.height;
31668 if(!this.previewResize) {
31672 if(width > height){
31673 file.target.addClass('wide');
31677 file.target.addClass('tall');
31682 uploadFromSource : function(file, crop)
31684 this.xhr = new XMLHttpRequest();
31686 this.managerEl.createChild({
31688 cls : 'roo-document-manager-loading',
31692 tooltip : file.name,
31693 cls : 'roo-document-manager-thumb',
31694 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
31700 this.xhr.open(this.method, this.url, true);
31703 "Accept": "application/json",
31704 "Cache-Control": "no-cache",
31705 "X-Requested-With": "XMLHttpRequest"
31708 for (var headerName in headers) {
31709 var headerValue = headers[headerName];
31711 this.xhr.setRequestHeader(headerName, headerValue);
31717 this.xhr.onload = function()
31719 _this.xhrOnLoad(_this.xhr);
31722 this.xhr.onerror = function()
31724 _this.xhrOnError(_this.xhr);
31727 var formData = new FormData();
31729 formData.append('returnHTML', 'NO');
31731 formData.append('crop', crop);
31733 if(typeof(file.filename) != 'undefined'){
31734 formData.append('filename', file.filename);
31737 if(typeof(file.mimetype) != 'undefined'){
31738 formData.append('mimetype', file.mimetype);
31743 if(this.fireEvent('prepare', this, formData) != false){
31744 this.xhr.send(formData);
31754 * @class Roo.bootstrap.DocumentViewer
31755 * @extends Roo.bootstrap.Component
31756 * Bootstrap DocumentViewer class
31757 * @cfg {Boolean} showDownload (true|false) show download button (default true)
31758 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
31761 * Create a new DocumentViewer
31762 * @param {Object} config The config object
31765 Roo.bootstrap.DocumentViewer = function(config){
31766 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
31771 * Fire after initEvent
31772 * @param {Roo.bootstrap.DocumentViewer} this
31778 * @param {Roo.bootstrap.DocumentViewer} this
31783 * Fire after download button
31784 * @param {Roo.bootstrap.DocumentViewer} this
31789 * Fire after trash button
31790 * @param {Roo.bootstrap.DocumentViewer} this
31797 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
31799 showDownload : true,
31803 getAutoCreate : function()
31807 cls : 'roo-document-viewer',
31811 cls : 'roo-document-viewer-body',
31815 cls : 'roo-document-viewer-thumb',
31819 cls : 'roo-document-viewer-image'
31827 cls : 'roo-document-viewer-footer',
31830 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
31834 cls : 'btn-group roo-document-viewer-download',
31838 cls : 'btn btn-default',
31839 html : '<i class="fa fa-download"></i>'
31845 cls : 'btn-group roo-document-viewer-trash',
31849 cls : 'btn btn-default',
31850 html : '<i class="fa fa-trash"></i>'
31863 initEvents : function()
31865 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
31866 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
31868 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
31869 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
31871 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
31872 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
31874 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
31875 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
31877 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
31878 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
31880 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
31881 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
31883 this.bodyEl.on('click', this.onClick, this);
31884 this.downloadBtn.on('click', this.onDownload, this);
31885 this.trashBtn.on('click', this.onTrash, this);
31887 this.downloadBtn.hide();
31888 this.trashBtn.hide();
31890 if(this.showDownload){
31891 this.downloadBtn.show();
31894 if(this.showTrash){
31895 this.trashBtn.show();
31898 if(!this.showDownload && !this.showTrash) {
31899 this.footerEl.hide();
31904 initial : function()
31906 this.fireEvent('initial', this);
31910 onClick : function(e)
31912 e.preventDefault();
31914 this.fireEvent('click', this);
31917 onDownload : function(e)
31919 e.preventDefault();
31921 this.fireEvent('download', this);
31924 onTrash : function(e)
31926 e.preventDefault();
31928 this.fireEvent('trash', this);
31940 * @class Roo.bootstrap.NavProgressBar
31941 * @extends Roo.bootstrap.Component
31942 * Bootstrap NavProgressBar class
31945 * Create a new nav progress bar
31946 * @param {Object} config The config object
31949 Roo.bootstrap.NavProgressBar = function(config){
31950 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
31952 this.bullets = this.bullets || [];
31954 // Roo.bootstrap.NavProgressBar.register(this);
31958 * Fires when the active item changes
31959 * @param {Roo.bootstrap.NavProgressBar} this
31960 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
31961 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
31968 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
31973 getAutoCreate : function()
31975 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
31979 cls : 'roo-navigation-bar-group',
31983 cls : 'roo-navigation-top-bar'
31987 cls : 'roo-navigation-bullets-bar',
31991 cls : 'roo-navigation-bar'
31998 cls : 'roo-navigation-bottom-bar'
32008 initEvents: function()
32013 onRender : function(ct, position)
32015 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
32017 if(this.bullets.length){
32018 Roo.each(this.bullets, function(b){
32027 addItem : function(cfg)
32029 var item = new Roo.bootstrap.NavProgressItem(cfg);
32031 item.parentId = this.id;
32032 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
32035 var top = new Roo.bootstrap.Element({
32037 cls : 'roo-navigation-bar-text'
32040 var bottom = new Roo.bootstrap.Element({
32042 cls : 'roo-navigation-bar-text'
32045 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
32046 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
32048 var topText = new Roo.bootstrap.Element({
32050 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
32053 var bottomText = new Roo.bootstrap.Element({
32055 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
32058 topText.onRender(top.el, null);
32059 bottomText.onRender(bottom.el, null);
32062 item.bottomEl = bottom;
32065 this.barItems.push(item);
32070 getActive : function()
32072 var active = false;
32074 Roo.each(this.barItems, function(v){
32076 if (!v.isActive()) {
32088 setActiveItem : function(item)
32092 Roo.each(this.barItems, function(v){
32093 if (v.rid == item.rid) {
32097 if (v.isActive()) {
32098 v.setActive(false);
32103 item.setActive(true);
32105 this.fireEvent('changed', this, item, prev);
32108 getBarItem: function(rid)
32112 Roo.each(this.barItems, function(e) {
32113 if (e.rid != rid) {
32124 indexOfItem : function(item)
32128 Roo.each(this.barItems, function(v, i){
32130 if (v.rid != item.rid) {
32141 setActiveNext : function()
32143 var i = this.indexOfItem(this.getActive());
32145 if (i > this.barItems.length) {
32149 this.setActiveItem(this.barItems[i+1]);
32152 setActivePrev : function()
32154 var i = this.indexOfItem(this.getActive());
32160 this.setActiveItem(this.barItems[i-1]);
32163 format : function()
32165 if(!this.barItems.length){
32169 var width = 100 / this.barItems.length;
32171 Roo.each(this.barItems, function(i){
32172 i.el.setStyle('width', width + '%');
32173 i.topEl.el.setStyle('width', width + '%');
32174 i.bottomEl.el.setStyle('width', width + '%');
32183 * Nav Progress Item
32188 * @class Roo.bootstrap.NavProgressItem
32189 * @extends Roo.bootstrap.Component
32190 * Bootstrap NavProgressItem class
32191 * @cfg {String} rid the reference id
32192 * @cfg {Boolean} active (true|false) Is item active default false
32193 * @cfg {Boolean} disabled (true|false) Is item active default false
32194 * @cfg {String} html
32195 * @cfg {String} position (top|bottom) text position default bottom
32196 * @cfg {String} icon show icon instead of number
32199 * Create a new NavProgressItem
32200 * @param {Object} config The config object
32202 Roo.bootstrap.NavProgressItem = function(config){
32203 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
32208 * The raw click event for the entire grid.
32209 * @param {Roo.bootstrap.NavProgressItem} this
32210 * @param {Roo.EventObject} e
32217 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
32223 position : 'bottom',
32226 getAutoCreate : function()
32228 var iconCls = 'roo-navigation-bar-item-icon';
32230 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
32234 cls: 'roo-navigation-bar-item',
32244 cfg.cls += ' active';
32247 cfg.cls += ' disabled';
32253 disable : function()
32255 this.setDisabled(true);
32258 enable : function()
32260 this.setDisabled(false);
32263 initEvents: function()
32265 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
32267 this.iconEl.on('click', this.onClick, this);
32270 onClick : function(e)
32272 e.preventDefault();
32278 if(this.fireEvent('click', this, e) === false){
32282 this.parent().setActiveItem(this);
32285 isActive: function ()
32287 return this.active;
32290 setActive : function(state)
32292 if(this.active == state){
32296 this.active = state;
32299 this.el.addClass('active');
32303 this.el.removeClass('active');
32308 setDisabled : function(state)
32310 if(this.disabled == state){
32314 this.disabled = state;
32317 this.el.addClass('disabled');
32321 this.el.removeClass('disabled');
32324 tooltipEl : function()
32326 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
32339 * @class Roo.bootstrap.FieldLabel
32340 * @extends Roo.bootstrap.Component
32341 * Bootstrap FieldLabel class
32342 * @cfg {String} html contents of the element
32343 * @cfg {String} tag tag of the element default label
32344 * @cfg {String} cls class of the element
32345 * @cfg {String} target label target
32346 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
32347 * @cfg {String} invalidClass DEPRICATED - BS4 uses is-invalid
32348 * @cfg {String} validClass DEPRICATED - BS4 uses is-valid
32349 * @cfg {String} iconTooltip default "This field is required"
32350 * @cfg {String} indicatorpos (left|right) default left
32353 * Create a new FieldLabel
32354 * @param {Object} config The config object
32357 Roo.bootstrap.FieldLabel = function(config){
32358 Roo.bootstrap.Element.superclass.constructor.call(this, config);
32363 * Fires after the field has been marked as invalid.
32364 * @param {Roo.form.FieldLabel} this
32365 * @param {String} msg The validation message
32370 * Fires after the field has been validated with no errors.
32371 * @param {Roo.form.FieldLabel} this
32377 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
32384 invalidClass : 'has-warning',
32385 validClass : 'has-success',
32386 iconTooltip : 'This field is required',
32387 indicatorpos : 'left',
32389 getAutoCreate : function(){
32392 if (!this.allowBlank) {
32398 cls : 'roo-bootstrap-field-label ' + this.cls,
32403 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star ' + cls,
32404 tooltip : this.iconTooltip
32413 if(this.indicatorpos == 'right'){
32416 cls : 'roo-bootstrap-field-label ' + this.cls,
32425 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star '+ cls,
32426 tooltip : this.iconTooltip
32435 initEvents: function()
32437 Roo.bootstrap.Element.superclass.initEvents.call(this);
32439 this.indicator = this.indicatorEl();
32441 if(this.indicator){
32442 this.indicator.removeClass('visible');
32443 this.indicator.addClass('invisible');
32446 Roo.bootstrap.FieldLabel.register(this);
32449 indicatorEl : function()
32451 var indicator = this.el.select('i.roo-required-indicator',true).first();
32462 * Mark this field as valid
32464 markValid : function()
32466 if(this.indicator){
32467 this.indicator.removeClass('visible');
32468 this.indicator.addClass('invisible');
32470 if (Roo.bootstrap.version == 3) {
32471 this.el.removeClass(this.invalidClass);
32472 this.el.addClass(this.validClass);
32474 this.el.removeClass('is-invalid');
32475 this.el.addClass('is-valid');
32479 this.fireEvent('valid', this);
32483 * Mark this field as invalid
32484 * @param {String} msg The validation message
32486 markInvalid : function(msg)
32488 if(this.indicator){
32489 this.indicator.removeClass('invisible');
32490 this.indicator.addClass('visible');
32492 if (Roo.bootstrap.version == 3) {
32493 this.el.removeClass(this.validClass);
32494 this.el.addClass(this.invalidClass);
32496 this.el.removeClass('is-valid');
32497 this.el.addClass('is-invalid');
32501 this.fireEvent('invalid', this, msg);
32507 Roo.apply(Roo.bootstrap.FieldLabel, {
32512 * register a FieldLabel Group
32513 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
32515 register : function(label)
32517 if(this.groups.hasOwnProperty(label.target)){
32521 this.groups[label.target] = label;
32525 * fetch a FieldLabel Group based on the target
32526 * @param {string} target
32527 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
32529 get: function(target) {
32530 if (typeof(this.groups[target]) == 'undefined') {
32534 return this.groups[target] ;
32543 * page DateSplitField.
32549 * @class Roo.bootstrap.DateSplitField
32550 * @extends Roo.bootstrap.Component
32551 * Bootstrap DateSplitField class
32552 * @cfg {string} fieldLabel - the label associated
32553 * @cfg {Number} labelWidth set the width of label (0-12)
32554 * @cfg {String} labelAlign (top|left)
32555 * @cfg {Boolean} dayAllowBlank (true|false) default false
32556 * @cfg {Boolean} monthAllowBlank (true|false) default false
32557 * @cfg {Boolean} yearAllowBlank (true|false) default false
32558 * @cfg {string} dayPlaceholder
32559 * @cfg {string} monthPlaceholder
32560 * @cfg {string} yearPlaceholder
32561 * @cfg {string} dayFormat default 'd'
32562 * @cfg {string} monthFormat default 'm'
32563 * @cfg {string} yearFormat default 'Y'
32564 * @cfg {Number} labellg set the width of label (1-12)
32565 * @cfg {Number} labelmd set the width of label (1-12)
32566 * @cfg {Number} labelsm set the width of label (1-12)
32567 * @cfg {Number} labelxs set the width of label (1-12)
32571 * Create a new DateSplitField
32572 * @param {Object} config The config object
32575 Roo.bootstrap.DateSplitField = function(config){
32576 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
32582 * getting the data of years
32583 * @param {Roo.bootstrap.DateSplitField} this
32584 * @param {Object} years
32589 * getting the data of days
32590 * @param {Roo.bootstrap.DateSplitField} this
32591 * @param {Object} days
32596 * Fires after the field has been marked as invalid.
32597 * @param {Roo.form.Field} this
32598 * @param {String} msg The validation message
32603 * Fires after the field has been validated with no errors.
32604 * @param {Roo.form.Field} this
32610 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
32613 labelAlign : 'top',
32615 dayAllowBlank : false,
32616 monthAllowBlank : false,
32617 yearAllowBlank : false,
32618 dayPlaceholder : '',
32619 monthPlaceholder : '',
32620 yearPlaceholder : '',
32624 isFormField : true,
32630 getAutoCreate : function()
32634 cls : 'row roo-date-split-field-group',
32639 cls : 'form-hidden-field roo-date-split-field-group-value',
32645 var labelCls = 'col-md-12';
32646 var contentCls = 'col-md-4';
32648 if(this.fieldLabel){
32652 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
32656 html : this.fieldLabel
32661 if(this.labelAlign == 'left'){
32663 if(this.labelWidth > 12){
32664 label.style = "width: " + this.labelWidth + 'px';
32667 if(this.labelWidth < 13 && this.labelmd == 0){
32668 this.labelmd = this.labelWidth;
32671 if(this.labellg > 0){
32672 labelCls = ' col-lg-' + this.labellg;
32673 contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
32676 if(this.labelmd > 0){
32677 labelCls = ' col-md-' + this.labelmd;
32678 contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
32681 if(this.labelsm > 0){
32682 labelCls = ' col-sm-' + this.labelsm;
32683 contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
32686 if(this.labelxs > 0){
32687 labelCls = ' col-xs-' + this.labelxs;
32688 contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
32692 label.cls += ' ' + labelCls;
32694 cfg.cn.push(label);
32697 Roo.each(['day', 'month', 'year'], function(t){
32700 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
32707 inputEl: function ()
32709 return this.el.select('.roo-date-split-field-group-value', true).first();
32712 onRender : function(ct, position)
32716 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
32718 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
32720 this.dayField = new Roo.bootstrap.ComboBox({
32721 allowBlank : this.dayAllowBlank,
32722 alwaysQuery : true,
32723 displayField : 'value',
32726 forceSelection : true,
32728 placeholder : this.dayPlaceholder,
32729 selectOnFocus : true,
32730 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
32731 triggerAction : 'all',
32733 valueField : 'value',
32734 store : new Roo.data.SimpleStore({
32735 data : (function() {
32737 _this.fireEvent('days', _this, days);
32740 fields : [ 'value' ]
32743 select : function (_self, record, index)
32745 _this.setValue(_this.getValue());
32750 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
32752 this.monthField = new Roo.bootstrap.MonthField({
32753 after : '<i class=\"fa fa-calendar\"></i>',
32754 allowBlank : this.monthAllowBlank,
32755 placeholder : this.monthPlaceholder,
32758 render : function (_self)
32760 this.el.select('span.input-group-addon', true).first().on('click', function(e){
32761 e.preventDefault();
32765 select : function (_self, oldvalue, newvalue)
32767 _this.setValue(_this.getValue());
32772 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
32774 this.yearField = new Roo.bootstrap.ComboBox({
32775 allowBlank : this.yearAllowBlank,
32776 alwaysQuery : true,
32777 displayField : 'value',
32780 forceSelection : true,
32782 placeholder : this.yearPlaceholder,
32783 selectOnFocus : true,
32784 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
32785 triggerAction : 'all',
32787 valueField : 'value',
32788 store : new Roo.data.SimpleStore({
32789 data : (function() {
32791 _this.fireEvent('years', _this, years);
32794 fields : [ 'value' ]
32797 select : function (_self, record, index)
32799 _this.setValue(_this.getValue());
32804 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
32807 setValue : function(v, format)
32809 this.inputEl.dom.value = v;
32811 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
32813 var d = Date.parseDate(v, f);
32820 this.setDay(d.format(this.dayFormat));
32821 this.setMonth(d.format(this.monthFormat));
32822 this.setYear(d.format(this.yearFormat));
32829 setDay : function(v)
32831 this.dayField.setValue(v);
32832 this.inputEl.dom.value = this.getValue();
32837 setMonth : function(v)
32839 this.monthField.setValue(v, true);
32840 this.inputEl.dom.value = this.getValue();
32845 setYear : function(v)
32847 this.yearField.setValue(v);
32848 this.inputEl.dom.value = this.getValue();
32853 getDay : function()
32855 return this.dayField.getValue();
32858 getMonth : function()
32860 return this.monthField.getValue();
32863 getYear : function()
32865 return this.yearField.getValue();
32868 getValue : function()
32870 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
32872 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
32882 this.inputEl.dom.value = '';
32887 validate : function()
32889 var d = this.dayField.validate();
32890 var m = this.monthField.validate();
32891 var y = this.yearField.validate();
32896 (!this.dayAllowBlank && !d) ||
32897 (!this.monthAllowBlank && !m) ||
32898 (!this.yearAllowBlank && !y)
32903 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
32912 this.markInvalid();
32917 markValid : function()
32920 var label = this.el.select('label', true).first();
32921 var icon = this.el.select('i.fa-star', true).first();
32927 this.fireEvent('valid', this);
32931 * Mark this field as invalid
32932 * @param {String} msg The validation message
32934 markInvalid : function(msg)
32937 var label = this.el.select('label', true).first();
32938 var icon = this.el.select('i.fa-star', true).first();
32940 if(label && !icon){
32941 this.el.select('.roo-date-split-field-label', true).createChild({
32943 cls : 'text-danger fa fa-lg fa-star',
32944 tooltip : 'This field is required',
32945 style : 'margin-right:5px;'
32949 this.fireEvent('invalid', this, msg);
32952 clearInvalid : function()
32954 var label = this.el.select('label', true).first();
32955 var icon = this.el.select('i.fa-star', true).first();
32961 this.fireEvent('valid', this);
32964 getName: function()
32974 * http://masonry.desandro.com
32976 * The idea is to render all the bricks based on vertical width...
32978 * The original code extends 'outlayer' - we might need to use that....
32984 * @class Roo.bootstrap.LayoutMasonry
32985 * @extends Roo.bootstrap.Component
32986 * Bootstrap Layout Masonry class
32989 * Create a new Element
32990 * @param {Object} config The config object
32993 Roo.bootstrap.LayoutMasonry = function(config){
32995 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
32999 Roo.bootstrap.LayoutMasonry.register(this);
33005 * Fire after layout the items
33006 * @param {Roo.bootstrap.LayoutMasonry} this
33007 * @param {Roo.EventObject} e
33014 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
33017 * @cfg {Boolean} isLayoutInstant = no animation?
33019 isLayoutInstant : false, // needed?
33022 * @cfg {Number} boxWidth width of the columns
33027 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
33032 * @cfg {Number} padWidth padding below box..
33037 * @cfg {Number} gutter gutter width..
33042 * @cfg {Number} maxCols maximum number of columns
33048 * @cfg {Boolean} isAutoInitial defalut true
33050 isAutoInitial : true,
33055 * @cfg {Boolean} isHorizontal defalut false
33057 isHorizontal : false,
33059 currentSize : null,
33065 bricks: null, //CompositeElement
33069 _isLayoutInited : false,
33071 // isAlternative : false, // only use for vertical layout...
33074 * @cfg {Number} alternativePadWidth padding below box..
33076 alternativePadWidth : 50,
33078 selectedBrick : [],
33080 getAutoCreate : function(){
33082 var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
33086 cls: 'blog-masonary-wrapper ' + this.cls,
33088 cls : 'mas-boxes masonary'
33095 getChildContainer: function( )
33097 if (this.boxesEl) {
33098 return this.boxesEl;
33101 this.boxesEl = this.el.select('.mas-boxes').first();
33103 return this.boxesEl;
33107 initEvents : function()
33111 if(this.isAutoInitial){
33112 Roo.log('hook children rendered');
33113 this.on('childrenrendered', function() {
33114 Roo.log('children rendered');
33120 initial : function()
33122 this.selectedBrick = [];
33124 this.currentSize = this.el.getBox(true);
33126 Roo.EventManager.onWindowResize(this.resize, this);
33128 if(!this.isAutoInitial){
33136 //this.layout.defer(500,this);
33140 resize : function()
33142 var cs = this.el.getBox(true);
33145 this.currentSize.width == cs.width &&
33146 this.currentSize.x == cs.x &&
33147 this.currentSize.height == cs.height &&
33148 this.currentSize.y == cs.y
33150 Roo.log("no change in with or X or Y");
33154 this.currentSize = cs;
33160 layout : function()
33162 this._resetLayout();
33164 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
33166 this.layoutItems( isInstant );
33168 this._isLayoutInited = true;
33170 this.fireEvent('layout', this);
33174 _resetLayout : function()
33176 if(this.isHorizontal){
33177 this.horizontalMeasureColumns();
33181 this.verticalMeasureColumns();
33185 verticalMeasureColumns : function()
33187 this.getContainerWidth();
33189 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
33190 // this.colWidth = Math.floor(this.containerWidth * 0.8);
33194 var boxWidth = this.boxWidth + this.padWidth;
33196 if(this.containerWidth < this.boxWidth){
33197 boxWidth = this.containerWidth
33200 var containerWidth = this.containerWidth;
33202 var cols = Math.floor(containerWidth / boxWidth);
33204 this.cols = Math.max( cols, 1 );
33206 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
33208 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
33210 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
33212 this.colWidth = boxWidth + avail - this.padWidth;
33214 this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
33215 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
33218 horizontalMeasureColumns : function()
33220 this.getContainerWidth();
33222 var boxWidth = this.boxWidth;
33224 if(this.containerWidth < boxWidth){
33225 boxWidth = this.containerWidth;
33228 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
33230 this.el.setHeight(boxWidth);
33234 getContainerWidth : function()
33236 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
33239 layoutItems : function( isInstant )
33241 Roo.log(this.bricks);
33243 var items = Roo.apply([], this.bricks);
33245 if(this.isHorizontal){
33246 this._horizontalLayoutItems( items , isInstant );
33250 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
33251 // this._verticalAlternativeLayoutItems( items , isInstant );
33255 this._verticalLayoutItems( items , isInstant );
33259 _verticalLayoutItems : function ( items , isInstant)
33261 if ( !items || !items.length ) {
33266 ['xs', 'xs', 'xs', 'tall'],
33267 ['xs', 'xs', 'tall'],
33268 ['xs', 'xs', 'sm'],
33269 ['xs', 'xs', 'xs'],
33275 ['sm', 'xs', 'xs'],
33279 ['tall', 'xs', 'xs', 'xs'],
33280 ['tall', 'xs', 'xs'],
33292 Roo.each(items, function(item, k){
33294 switch (item.size) {
33295 // these layouts take up a full box,
33306 boxes.push([item]);
33329 var filterPattern = function(box, length)
33337 var pattern = box.slice(0, length);
33341 Roo.each(pattern, function(i){
33342 format.push(i.size);
33345 Roo.each(standard, function(s){
33347 if(String(s) != String(format)){
33356 if(!match && length == 1){
33361 filterPattern(box, length - 1);
33365 queue.push(pattern);
33367 box = box.slice(length, box.length);
33369 filterPattern(box, 4);
33375 Roo.each(boxes, function(box, k){
33381 if(box.length == 1){
33386 filterPattern(box, 4);
33390 this._processVerticalLayoutQueue( queue, isInstant );
33394 // _verticalAlternativeLayoutItems : function( items , isInstant )
33396 // if ( !items || !items.length ) {
33400 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
33404 _horizontalLayoutItems : function ( items , isInstant)
33406 if ( !items || !items.length || items.length < 3) {
33412 var eItems = items.slice(0, 3);
33414 items = items.slice(3, items.length);
33417 ['xs', 'xs', 'xs', 'wide'],
33418 ['xs', 'xs', 'wide'],
33419 ['xs', 'xs', 'sm'],
33420 ['xs', 'xs', 'xs'],
33426 ['sm', 'xs', 'xs'],
33430 ['wide', 'xs', 'xs', 'xs'],
33431 ['wide', 'xs', 'xs'],
33444 Roo.each(items, function(item, k){
33446 switch (item.size) {
33457 boxes.push([item]);
33481 var filterPattern = function(box, length)
33489 var pattern = box.slice(0, length);
33493 Roo.each(pattern, function(i){
33494 format.push(i.size);
33497 Roo.each(standard, function(s){
33499 if(String(s) != String(format)){
33508 if(!match && length == 1){
33513 filterPattern(box, length - 1);
33517 queue.push(pattern);
33519 box = box.slice(length, box.length);
33521 filterPattern(box, 4);
33527 Roo.each(boxes, function(box, k){
33533 if(box.length == 1){
33538 filterPattern(box, 4);
33545 var pos = this.el.getBox(true);
33549 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
33551 var hit_end = false;
33553 Roo.each(queue, function(box){
33557 Roo.each(box, function(b){
33559 b.el.setVisibilityMode(Roo.Element.DISPLAY);
33569 Roo.each(box, function(b){
33571 b.el.setVisibilityMode(Roo.Element.DISPLAY);
33574 mx = Math.max(mx, b.x);
33578 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
33582 Roo.each(box, function(b){
33584 b.el.setVisibilityMode(Roo.Element.DISPLAY);
33598 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
33601 /** Sets position of item in DOM
33602 * @param {Element} item
33603 * @param {Number} x - horizontal position
33604 * @param {Number} y - vertical position
33605 * @param {Boolean} isInstant - disables transitions
33607 _processVerticalLayoutQueue : function( queue, isInstant )
33609 var pos = this.el.getBox(true);
33614 for (var i = 0; i < this.cols; i++){
33618 Roo.each(queue, function(box, k){
33620 var col = k % this.cols;
33622 Roo.each(box, function(b,kk){
33624 b.el.position('absolute');
33626 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
33627 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
33629 if(b.size == 'md-left' || b.size == 'md-right'){
33630 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
33631 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
33634 b.el.setWidth(width);
33635 b.el.setHeight(height);
33637 b.el.select('iframe',true).setSize(width,height);
33641 for (var i = 0; i < this.cols; i++){
33643 if(maxY[i] < maxY[col]){
33648 col = Math.min(col, i);
33652 x = pos.x + col * (this.colWidth + this.padWidth);
33656 var positions = [];
33658 switch (box.length){
33660 positions = this.getVerticalOneBoxColPositions(x, y, box);
33663 positions = this.getVerticalTwoBoxColPositions(x, y, box);
33666 positions = this.getVerticalThreeBoxColPositions(x, y, box);
33669 positions = this.getVerticalFourBoxColPositions(x, y, box);
33675 Roo.each(box, function(b,kk){
33677 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
33679 var sz = b.el.getSize();
33681 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
33689 for (var i = 0; i < this.cols; i++){
33690 mY = Math.max(mY, maxY[i]);
33693 this.el.setHeight(mY - pos.y);
33697 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
33699 // var pos = this.el.getBox(true);
33702 // var maxX = pos.right;
33704 // var maxHeight = 0;
33706 // Roo.each(items, function(item, k){
33710 // item.el.position('absolute');
33712 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
33714 // item.el.setWidth(width);
33716 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
33718 // item.el.setHeight(height);
33721 // item.el.setXY([x, y], isInstant ? false : true);
33723 // item.el.setXY([maxX - width, y], isInstant ? false : true);
33726 // y = y + height + this.alternativePadWidth;
33728 // maxHeight = maxHeight + height + this.alternativePadWidth;
33732 // this.el.setHeight(maxHeight);
33736 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
33738 var pos = this.el.getBox(true);
33743 var maxX = pos.right;
33745 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
33747 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
33749 Roo.each(queue, function(box, k){
33751 Roo.each(box, function(b, kk){
33753 b.el.position('absolute');
33755 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
33756 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
33758 if(b.size == 'md-left' || b.size == 'md-right'){
33759 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
33760 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
33763 b.el.setWidth(width);
33764 b.el.setHeight(height);
33772 var positions = [];
33774 switch (box.length){
33776 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
33779 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
33782 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
33785 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
33791 Roo.each(box, function(b,kk){
33793 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
33795 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
33803 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
33805 Roo.each(eItems, function(b,k){
33807 b.size = (k == 0) ? 'sm' : 'xs';
33808 b.x = (k == 0) ? 2 : 1;
33809 b.y = (k == 0) ? 2 : 1;
33811 b.el.position('absolute');
33813 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
33815 b.el.setWidth(width);
33817 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
33819 b.el.setHeight(height);
33823 var positions = [];
33826 x : maxX - this.unitWidth * 2 - this.gutter,
33831 x : maxX - this.unitWidth,
33832 y : minY + (this.unitWidth + this.gutter) * 2
33836 x : maxX - this.unitWidth * 3 - this.gutter * 2,
33840 Roo.each(eItems, function(b,k){
33842 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
33848 getVerticalOneBoxColPositions : function(x, y, box)
33852 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
33854 if(box[0].size == 'md-left'){
33858 if(box[0].size == 'md-right'){
33863 x : x + (this.unitWidth + this.gutter) * rand,
33870 getVerticalTwoBoxColPositions : function(x, y, box)
33874 if(box[0].size == 'xs'){
33878 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
33882 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
33896 x : x + (this.unitWidth + this.gutter) * 2,
33897 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
33904 getVerticalThreeBoxColPositions : function(x, y, box)
33908 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
33916 x : x + (this.unitWidth + this.gutter) * 1,
33921 x : x + (this.unitWidth + this.gutter) * 2,
33929 if(box[0].size == 'xs' && box[1].size == 'xs'){
33938 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
33942 x : x + (this.unitWidth + this.gutter) * 1,
33956 x : x + (this.unitWidth + this.gutter) * 2,
33961 x : x + (this.unitWidth + this.gutter) * 2,
33962 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
33969 getVerticalFourBoxColPositions : function(x, y, box)
33973 if(box[0].size == 'xs'){
33982 y : y + (this.unitHeight + this.gutter) * 1
33987 y : y + (this.unitHeight + this.gutter) * 2
33991 x : x + (this.unitWidth + this.gutter) * 1,
34005 x : x + (this.unitWidth + this.gutter) * 2,
34010 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
34011 y : y + (this.unitHeight + this.gutter) * 1
34015 x : x + (this.unitWidth + this.gutter) * 2,
34016 y : y + (this.unitWidth + this.gutter) * 2
34023 getHorizontalOneBoxColPositions : function(maxX, minY, box)
34027 if(box[0].size == 'md-left'){
34029 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
34036 if(box[0].size == 'md-right'){
34038 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
34039 y : minY + (this.unitWidth + this.gutter) * 1
34045 var rand = Math.floor(Math.random() * (4 - box[0].y));
34048 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
34049 y : minY + (this.unitWidth + this.gutter) * rand
34056 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
34060 if(box[0].size == 'xs'){
34063 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
34068 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
34069 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
34077 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
34082 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
34083 y : minY + (this.unitWidth + this.gutter) * 2
34090 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
34094 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
34097 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
34102 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
34103 y : minY + (this.unitWidth + this.gutter) * 1
34107 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
34108 y : minY + (this.unitWidth + this.gutter) * 2
34115 if(box[0].size == 'xs' && box[1].size == 'xs'){
34118 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
34123 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
34128 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
34129 y : minY + (this.unitWidth + this.gutter) * 1
34137 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
34142 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
34143 y : minY + (this.unitWidth + this.gutter) * 2
34147 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
34148 y : minY + (this.unitWidth + this.gutter) * 2
34155 getHorizontalFourBoxColPositions : function(maxX, minY, box)
34159 if(box[0].size == 'xs'){
34162 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
34167 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
34172 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),
34177 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
34178 y : minY + (this.unitWidth + this.gutter) * 1
34186 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
34191 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
34192 y : minY + (this.unitWidth + this.gutter) * 2
34196 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
34197 y : minY + (this.unitWidth + this.gutter) * 2
34201 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),
34202 y : minY + (this.unitWidth + this.gutter) * 2
34210 * remove a Masonry Brick
34211 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
34213 removeBrick : function(brick_id)
34219 for (var i = 0; i<this.bricks.length; i++) {
34220 if (this.bricks[i].id == brick_id) {
34221 this.bricks.splice(i,1);
34222 this.el.dom.removeChild(Roo.get(brick_id).dom);
34229 * adds a Masonry Brick
34230 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
34232 addBrick : function(cfg)
34234 var cn = new Roo.bootstrap.MasonryBrick(cfg);
34235 //this.register(cn);
34236 cn.parentId = this.id;
34237 cn.render(this.el);
34242 * register a Masonry Brick
34243 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
34246 register : function(brick)
34248 this.bricks.push(brick);
34249 brick.masonryId = this.id;
34253 * clear all the Masonry Brick
34255 clearAll : function()
34258 //this.getChildContainer().dom.innerHTML = "";
34259 this.el.dom.innerHTML = '';
34262 getSelected : function()
34264 if (!this.selectedBrick) {
34268 return this.selectedBrick;
34272 Roo.apply(Roo.bootstrap.LayoutMasonry, {
34276 * register a Masonry Layout
34277 * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
34280 register : function(layout)
34282 this.groups[layout.id] = layout;
34285 * fetch a Masonry Layout based on the masonry layout ID
34286 * @param {string} the masonry layout to add
34287 * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
34290 get: function(layout_id) {
34291 if (typeof(this.groups[layout_id]) == 'undefined') {
34294 return this.groups[layout_id] ;
34306 * http://masonry.desandro.com
34308 * The idea is to render all the bricks based on vertical width...
34310 * The original code extends 'outlayer' - we might need to use that....
34316 * @class Roo.bootstrap.LayoutMasonryAuto
34317 * @extends Roo.bootstrap.Component
34318 * Bootstrap Layout Masonry class
34321 * Create a new Element
34322 * @param {Object} config The config object
34325 Roo.bootstrap.LayoutMasonryAuto = function(config){
34326 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
34329 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
34332 * @cfg {Boolean} isFitWidth - resize the width..
34334 isFitWidth : false, // options..
34336 * @cfg {Boolean} isOriginLeft = left align?
34338 isOriginLeft : true,
34340 * @cfg {Boolean} isOriginTop = top align?
34342 isOriginTop : false,
34344 * @cfg {Boolean} isLayoutInstant = no animation?
34346 isLayoutInstant : false, // needed?
34348 * @cfg {Boolean} isResizingContainer = not sure if this is used..
34350 isResizingContainer : true,
34352 * @cfg {Number} columnWidth width of the columns
34358 * @cfg {Number} maxCols maximum number of columns
34363 * @cfg {Number} padHeight padding below box..
34369 * @cfg {Boolean} isAutoInitial defalut true
34372 isAutoInitial : true,
34378 initialColumnWidth : 0,
34379 currentSize : null,
34381 colYs : null, // array.
34388 bricks: null, //CompositeElement
34389 cols : 0, // array?
34390 // element : null, // wrapped now this.el
34391 _isLayoutInited : null,
34394 getAutoCreate : function(){
34398 cls: 'blog-masonary-wrapper ' + this.cls,
34400 cls : 'mas-boxes masonary'
34407 getChildContainer: function( )
34409 if (this.boxesEl) {
34410 return this.boxesEl;
34413 this.boxesEl = this.el.select('.mas-boxes').first();
34415 return this.boxesEl;
34419 initEvents : function()
34423 if(this.isAutoInitial){
34424 Roo.log('hook children rendered');
34425 this.on('childrenrendered', function() {
34426 Roo.log('children rendered');
34433 initial : function()
34435 this.reloadItems();
34437 this.currentSize = this.el.getBox(true);
34439 /// was window resize... - let's see if this works..
34440 Roo.EventManager.onWindowResize(this.resize, this);
34442 if(!this.isAutoInitial){
34447 this.layout.defer(500,this);
34450 reloadItems: function()
34452 this.bricks = this.el.select('.masonry-brick', true);
34454 this.bricks.each(function(b) {
34455 //Roo.log(b.getSize());
34456 if (!b.attr('originalwidth')) {
34457 b.attr('originalwidth', b.getSize().width);
34462 Roo.log(this.bricks.elements.length);
34465 resize : function()
34468 var cs = this.el.getBox(true);
34470 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
34471 Roo.log("no change in with or X");
34474 this.currentSize = cs;
34478 layout : function()
34481 this._resetLayout();
34482 //this._manageStamps();
34484 // don't animate first layout
34485 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
34486 this.layoutItems( isInstant );
34488 // flag for initalized
34489 this._isLayoutInited = true;
34492 layoutItems : function( isInstant )
34494 //var items = this._getItemsForLayout( this.items );
34495 // original code supports filtering layout items.. we just ignore it..
34497 this._layoutItems( this.bricks , isInstant );
34499 this._postLayout();
34501 _layoutItems : function ( items , isInstant)
34503 //this.fireEvent( 'layout', this, items );
34506 if ( !items || !items.elements.length ) {
34507 // no items, emit event with empty array
34512 items.each(function(item) {
34513 Roo.log("layout item");
34515 // get x/y object from method
34516 var position = this._getItemLayoutPosition( item );
34518 position.item = item;
34519 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
34520 queue.push( position );
34523 this._processLayoutQueue( queue );
34525 /** Sets position of item in DOM
34526 * @param {Element} item
34527 * @param {Number} x - horizontal position
34528 * @param {Number} y - vertical position
34529 * @param {Boolean} isInstant - disables transitions
34531 _processLayoutQueue : function( queue )
34533 for ( var i=0, len = queue.length; i < len; i++ ) {
34534 var obj = queue[i];
34535 obj.item.position('absolute');
34536 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
34542 * Any logic you want to do after each layout,
34543 * i.e. size the container
34545 _postLayout : function()
34547 this.resizeContainer();
34550 resizeContainer : function()
34552 if ( !this.isResizingContainer ) {
34555 var size = this._getContainerSize();
34557 this.el.setSize(size.width,size.height);
34558 this.boxesEl.setSize(size.width,size.height);
34564 _resetLayout : function()
34566 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
34567 this.colWidth = this.el.getWidth();
34568 //this.gutter = this.el.getWidth();
34570 this.measureColumns();
34576 this.colYs.push( 0 );
34582 measureColumns : function()
34584 this.getContainerWidth();
34585 // if columnWidth is 0, default to outerWidth of first item
34586 if ( !this.columnWidth ) {
34587 var firstItem = this.bricks.first();
34588 Roo.log(firstItem);
34589 this.columnWidth = this.containerWidth;
34590 if (firstItem && firstItem.attr('originalwidth') ) {
34591 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
34593 // columnWidth fall back to item of first element
34594 Roo.log("set column width?");
34595 this.initialColumnWidth = this.columnWidth ;
34597 // if first elem has no width, default to size of container
34602 if (this.initialColumnWidth) {
34603 this.columnWidth = this.initialColumnWidth;
34608 // column width is fixed at the top - however if container width get's smaller we should
34611 // this bit calcs how man columns..
34613 var columnWidth = this.columnWidth += this.gutter;
34615 // calculate columns
34616 var containerWidth = this.containerWidth + this.gutter;
34618 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
34619 // fix rounding errors, typically with gutters
34620 var excess = columnWidth - containerWidth % columnWidth;
34623 // if overshoot is less than a pixel, round up, otherwise floor it
34624 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
34625 cols = Math[ mathMethod ]( cols );
34626 this.cols = Math.max( cols, 1 );
34627 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
34629 // padding positioning..
34630 var totalColWidth = this.cols * this.columnWidth;
34631 var padavail = this.containerWidth - totalColWidth;
34632 // so for 2 columns - we need 3 'pads'
34634 var padNeeded = (1+this.cols) * this.padWidth;
34636 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
34638 this.columnWidth += padExtra
34639 //this.padWidth = Math.floor(padavail / ( this.cols));
34641 // adjust colum width so that padding is fixed??
34643 // we have 3 columns ... total = width * 3
34644 // we have X left over... that should be used by
34646 //if (this.expandC) {
34654 getContainerWidth : function()
34656 /* // container is parent if fit width
34657 var container = this.isFitWidth ? this.element.parentNode : this.element;
34658 // check that this.size and size are there
34659 // IE8 triggers resize on body size change, so they might not be
34661 var size = getSize( container ); //FIXME
34662 this.containerWidth = size && size.innerWidth; //FIXME
34665 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
34669 _getItemLayoutPosition : function( item ) // what is item?
34671 // we resize the item to our columnWidth..
34673 item.setWidth(this.columnWidth);
34674 item.autoBoxAdjust = false;
34676 var sz = item.getSize();
34678 // how many columns does this brick span
34679 var remainder = this.containerWidth % this.columnWidth;
34681 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
34682 // round if off by 1 pixel, otherwise use ceil
34683 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
34684 colSpan = Math.min( colSpan, this.cols );
34686 // normally this should be '1' as we dont' currently allow multi width columns..
34688 var colGroup = this._getColGroup( colSpan );
34689 // get the minimum Y value from the columns
34690 var minimumY = Math.min.apply( Math, colGroup );
34691 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
34693 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
34695 // position the brick
34697 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
34698 y: this.currentSize.y + minimumY + this.padHeight
34702 // apply setHeight to necessary columns
34703 var setHeight = minimumY + sz.height + this.padHeight;
34704 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
34706 var setSpan = this.cols + 1 - colGroup.length;
34707 for ( var i = 0; i < setSpan; i++ ) {
34708 this.colYs[ shortColIndex + i ] = setHeight ;
34715 * @param {Number} colSpan - number of columns the element spans
34716 * @returns {Array} colGroup
34718 _getColGroup : function( colSpan )
34720 if ( colSpan < 2 ) {
34721 // if brick spans only one column, use all the column Ys
34726 // how many different places could this brick fit horizontally
34727 var groupCount = this.cols + 1 - colSpan;
34728 // for each group potential horizontal position
34729 for ( var i = 0; i < groupCount; i++ ) {
34730 // make an array of colY values for that one group
34731 var groupColYs = this.colYs.slice( i, i + colSpan );
34732 // and get the max value of the array
34733 colGroup[i] = Math.max.apply( Math, groupColYs );
34738 _manageStamp : function( stamp )
34740 var stampSize = stamp.getSize();
34741 var offset = stamp.getBox();
34742 // get the columns that this stamp affects
34743 var firstX = this.isOriginLeft ? offset.x : offset.right;
34744 var lastX = firstX + stampSize.width;
34745 var firstCol = Math.floor( firstX / this.columnWidth );
34746 firstCol = Math.max( 0, firstCol );
34748 var lastCol = Math.floor( lastX / this.columnWidth );
34749 // lastCol should not go over if multiple of columnWidth #425
34750 lastCol -= lastX % this.columnWidth ? 0 : 1;
34751 lastCol = Math.min( this.cols - 1, lastCol );
34753 // set colYs to bottom of the stamp
34754 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
34757 for ( var i = firstCol; i <= lastCol; i++ ) {
34758 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
34763 _getContainerSize : function()
34765 this.maxY = Math.max.apply( Math, this.colYs );
34770 if ( this.isFitWidth ) {
34771 size.width = this._getContainerFitWidth();
34777 _getContainerFitWidth : function()
34779 var unusedCols = 0;
34780 // count unused columns
34783 if ( this.colYs[i] !== 0 ) {
34788 // fit container to columns that have been used
34789 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
34792 needsResizeLayout : function()
34794 var previousWidth = this.containerWidth;
34795 this.getContainerWidth();
34796 return previousWidth !== this.containerWidth;
34811 * @class Roo.bootstrap.MasonryBrick
34812 * @extends Roo.bootstrap.Component
34813 * Bootstrap MasonryBrick class
34816 * Create a new MasonryBrick
34817 * @param {Object} config The config object
34820 Roo.bootstrap.MasonryBrick = function(config){
34822 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
34824 Roo.bootstrap.MasonryBrick.register(this);
34830 * When a MasonryBrick is clcik
34831 * @param {Roo.bootstrap.MasonryBrick} this
34832 * @param {Roo.EventObject} e
34838 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
34841 * @cfg {String} title
34845 * @cfg {String} html
34849 * @cfg {String} bgimage
34853 * @cfg {String} videourl
34857 * @cfg {String} cls
34861 * @cfg {String} href
34865 * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
34870 * @cfg {String} placetitle (center|bottom)
34875 * @cfg {Boolean} isFitContainer defalut true
34877 isFitContainer : true,
34880 * @cfg {Boolean} preventDefault defalut false
34882 preventDefault : false,
34885 * @cfg {Boolean} inverse defalut false
34887 maskInverse : false,
34889 getAutoCreate : function()
34891 if(!this.isFitContainer){
34892 return this.getSplitAutoCreate();
34895 var cls = 'masonry-brick masonry-brick-full';
34897 if(this.href.length){
34898 cls += ' masonry-brick-link';
34901 if(this.bgimage.length){
34902 cls += ' masonry-brick-image';
34905 if(this.maskInverse){
34906 cls += ' mask-inverse';
34909 if(!this.html.length && !this.maskInverse && !this.videourl.length){
34910 cls += ' enable-mask';
34914 cls += ' masonry-' + this.size + '-brick';
34917 if(this.placetitle.length){
34919 switch (this.placetitle) {
34921 cls += ' masonry-center-title';
34924 cls += ' masonry-bottom-title';
34931 if(!this.html.length && !this.bgimage.length){
34932 cls += ' masonry-center-title';
34935 if(!this.html.length && this.bgimage.length){
34936 cls += ' masonry-bottom-title';
34941 cls += ' ' + this.cls;
34945 tag: (this.href.length) ? 'a' : 'div',
34950 cls: 'masonry-brick-mask'
34954 cls: 'masonry-brick-paragraph',
34960 if(this.href.length){
34961 cfg.href = this.href;
34964 var cn = cfg.cn[1].cn;
34966 if(this.title.length){
34969 cls: 'masonry-brick-title',
34974 if(this.html.length){
34977 cls: 'masonry-brick-text',
34982 if (!this.title.length && !this.html.length) {
34983 cfg.cn[1].cls += ' hide';
34986 if(this.bgimage.length){
34989 cls: 'masonry-brick-image-view',
34994 if(this.videourl.length){
34995 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
34996 // youtube support only?
34999 cls: 'masonry-brick-image-view',
35002 allowfullscreen : true
35010 getSplitAutoCreate : function()
35012 var cls = 'masonry-brick masonry-brick-split';
35014 if(this.href.length){
35015 cls += ' masonry-brick-link';
35018 if(this.bgimage.length){
35019 cls += ' masonry-brick-image';
35023 cls += ' masonry-' + this.size + '-brick';
35026 switch (this.placetitle) {
35028 cls += ' masonry-center-title';
35031 cls += ' masonry-bottom-title';
35034 if(!this.bgimage.length){
35035 cls += ' masonry-center-title';
35038 if(this.bgimage.length){
35039 cls += ' masonry-bottom-title';
35045 cls += ' ' + this.cls;
35049 tag: (this.href.length) ? 'a' : 'div',
35054 cls: 'masonry-brick-split-head',
35058 cls: 'masonry-brick-paragraph',
35065 cls: 'masonry-brick-split-body',
35071 if(this.href.length){
35072 cfg.href = this.href;
35075 if(this.title.length){
35076 cfg.cn[0].cn[0].cn.push({
35078 cls: 'masonry-brick-title',
35083 if(this.html.length){
35084 cfg.cn[1].cn.push({
35086 cls: 'masonry-brick-text',
35091 if(this.bgimage.length){
35092 cfg.cn[0].cn.push({
35094 cls: 'masonry-brick-image-view',
35099 if(this.videourl.length){
35100 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
35101 // youtube support only?
35102 cfg.cn[0].cn.cn.push({
35104 cls: 'masonry-brick-image-view',
35107 allowfullscreen : true
35114 initEvents: function()
35116 switch (this.size) {
35149 this.el.on('touchstart', this.onTouchStart, this);
35150 this.el.on('touchmove', this.onTouchMove, this);
35151 this.el.on('touchend', this.onTouchEnd, this);
35152 this.el.on('contextmenu', this.onContextMenu, this);
35154 this.el.on('mouseenter' ,this.enter, this);
35155 this.el.on('mouseleave', this.leave, this);
35156 this.el.on('click', this.onClick, this);
35159 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
35160 this.parent().bricks.push(this);
35165 onClick: function(e, el)
35167 var time = this.endTimer - this.startTimer;
35168 // Roo.log(e.preventDefault());
35171 e.preventDefault();
35176 if(!this.preventDefault){
35180 e.preventDefault();
35182 if (this.activeClass != '') {
35183 this.selectBrick();
35186 this.fireEvent('click', this, e);
35189 enter: function(e, el)
35191 e.preventDefault();
35193 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
35197 if(this.bgimage.length && this.html.length){
35198 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
35202 leave: function(e, el)
35204 e.preventDefault();
35206 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
35210 if(this.bgimage.length && this.html.length){
35211 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
35215 onTouchStart: function(e, el)
35217 // e.preventDefault();
35219 this.touchmoved = false;
35221 if(!this.isFitContainer){
35225 if(!this.bgimage.length || !this.html.length){
35229 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
35231 this.timer = new Date().getTime();
35235 onTouchMove: function(e, el)
35237 this.touchmoved = true;
35240 onContextMenu : function(e,el)
35242 e.preventDefault();
35243 e.stopPropagation();
35247 onTouchEnd: function(e, el)
35249 // e.preventDefault();
35251 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
35258 if(!this.bgimage.length || !this.html.length){
35260 if(this.href.length){
35261 window.location.href = this.href;
35267 if(!this.isFitContainer){
35271 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
35273 window.location.href = this.href;
35276 //selection on single brick only
35277 selectBrick : function() {
35279 if (!this.parentId) {
35283 var m = Roo.bootstrap.LayoutMasonry.get(this.parentId);
35284 var index = m.selectedBrick.indexOf(this.id);
35287 m.selectedBrick.splice(index,1);
35288 this.el.removeClass(this.activeClass);
35292 for(var i = 0; i < m.selectedBrick.length; i++) {
35293 var b = Roo.bootstrap.MasonryBrick.get(m.selectedBrick[i]);
35294 b.el.removeClass(b.activeClass);
35297 m.selectedBrick = [];
35299 m.selectedBrick.push(this.id);
35300 this.el.addClass(this.activeClass);
35304 isSelected : function(){
35305 return this.el.hasClass(this.activeClass);
35310 Roo.apply(Roo.bootstrap.MasonryBrick, {
35313 groups : new Roo.util.MixedCollection(false, function(o) { return o.el.id; }),
35315 * register a Masonry Brick
35316 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
35319 register : function(brick)
35321 //this.groups[brick.id] = brick;
35322 this.groups.add(brick.id, brick);
35325 * fetch a masonry brick based on the masonry brick ID
35326 * @param {string} the masonry brick to add
35327 * @returns {Roo.bootstrap.MasonryBrick} the masonry brick
35330 get: function(brick_id)
35332 // if (typeof(this.groups[brick_id]) == 'undefined') {
35335 // return this.groups[brick_id] ;
35337 if(this.groups.key(brick_id)) {
35338 return this.groups.key(brick_id);
35356 * @class Roo.bootstrap.Brick
35357 * @extends Roo.bootstrap.Component
35358 * Bootstrap Brick class
35361 * Create a new Brick
35362 * @param {Object} config The config object
35365 Roo.bootstrap.Brick = function(config){
35366 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
35372 * When a Brick is click
35373 * @param {Roo.bootstrap.Brick} this
35374 * @param {Roo.EventObject} e
35380 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
35383 * @cfg {String} title
35387 * @cfg {String} html
35391 * @cfg {String} bgimage
35395 * @cfg {String} cls
35399 * @cfg {String} href
35403 * @cfg {String} video
35407 * @cfg {Boolean} square
35411 getAutoCreate : function()
35413 var cls = 'roo-brick';
35415 if(this.href.length){
35416 cls += ' roo-brick-link';
35419 if(this.bgimage.length){
35420 cls += ' roo-brick-image';
35423 if(!this.html.length && !this.bgimage.length){
35424 cls += ' roo-brick-center-title';
35427 if(!this.html.length && this.bgimage.length){
35428 cls += ' roo-brick-bottom-title';
35432 cls += ' ' + this.cls;
35436 tag: (this.href.length) ? 'a' : 'div',
35441 cls: 'roo-brick-paragraph',
35447 if(this.href.length){
35448 cfg.href = this.href;
35451 var cn = cfg.cn[0].cn;
35453 if(this.title.length){
35456 cls: 'roo-brick-title',
35461 if(this.html.length){
35464 cls: 'roo-brick-text',
35471 if(this.bgimage.length){
35474 cls: 'roo-brick-image-view',
35482 initEvents: function()
35484 if(this.title.length || this.html.length){
35485 this.el.on('mouseenter' ,this.enter, this);
35486 this.el.on('mouseleave', this.leave, this);
35489 Roo.EventManager.onWindowResize(this.resize, this);
35491 if(this.bgimage.length){
35492 this.imageEl = this.el.select('.roo-brick-image-view', true).first();
35493 this.imageEl.on('load', this.onImageLoad, this);
35500 onImageLoad : function()
35505 resize : function()
35507 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
35509 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
35511 if(this.bgimage.length){
35512 var image = this.el.select('.roo-brick-image-view', true).first();
35514 image.setWidth(paragraph.getWidth());
35517 image.setHeight(paragraph.getWidth());
35520 this.el.setHeight(image.getHeight());
35521 paragraph.setHeight(image.getHeight());
35527 enter: function(e, el)
35529 e.preventDefault();
35531 if(this.bgimage.length){
35532 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
35533 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
35537 leave: function(e, el)
35539 e.preventDefault();
35541 if(this.bgimage.length){
35542 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
35543 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
35558 * @class Roo.bootstrap.NumberField
35559 * @extends Roo.bootstrap.Input
35560 * Bootstrap NumberField class
35566 * Create a new NumberField
35567 * @param {Object} config The config object
35570 Roo.bootstrap.NumberField = function(config){
35571 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
35574 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
35577 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
35579 allowDecimals : true,
35581 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
35583 decimalSeparator : ".",
35585 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
35587 decimalPrecision : 2,
35589 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
35591 allowNegative : true,
35594 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
35598 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
35600 minValue : Number.NEGATIVE_INFINITY,
35602 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
35604 maxValue : Number.MAX_VALUE,
35606 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
35608 minText : "The minimum value for this field is {0}",
35610 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
35612 maxText : "The maximum value for this field is {0}",
35614 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
35615 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
35617 nanText : "{0} is not a valid number",
35619 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
35621 thousandsDelimiter : false,
35623 * @cfg {String} valueAlign alignment of value
35625 valueAlign : "left",
35627 getAutoCreate : function()
35629 var hiddenInput = {
35633 cls: 'hidden-number-input'
35637 hiddenInput.name = this.name;
35642 var cfg = Roo.bootstrap.NumberField.superclass.getAutoCreate.call(this);
35644 this.name = hiddenInput.name;
35646 if(cfg.cn.length > 0) {
35647 cfg.cn.push(hiddenInput);
35654 initEvents : function()
35656 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
35658 var allowed = "0123456789";
35660 if(this.allowDecimals){
35661 allowed += this.decimalSeparator;
35664 if(this.allowNegative){
35668 if(this.thousandsDelimiter) {
35672 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
35674 var keyPress = function(e){
35676 var k = e.getKey();
35678 var c = e.getCharCode();
35681 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
35682 allowed.indexOf(String.fromCharCode(c)) === -1
35688 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
35692 if(allowed.indexOf(String.fromCharCode(c)) === -1){
35697 this.el.on("keypress", keyPress, this);
35700 validateValue : function(value)
35703 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
35707 var num = this.parseValue(value);
35710 this.markInvalid(String.format(this.nanText, value));
35714 if(num < this.minValue){
35715 this.markInvalid(String.format(this.minText, this.minValue));
35719 if(num > this.maxValue){
35720 this.markInvalid(String.format(this.maxText, this.maxValue));
35727 getValue : function()
35729 var v = this.hiddenEl().getValue();
35731 return this.fixPrecision(this.parseValue(v));
35734 parseValue : function(value)
35736 if(this.thousandsDelimiter) {
35738 r = new RegExp(",", "g");
35739 value = value.replace(r, "");
35742 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
35743 return isNaN(value) ? '' : value;
35746 fixPrecision : function(value)
35748 if(this.thousandsDelimiter) {
35750 r = new RegExp(",", "g");
35751 value = value.replace(r, "");
35754 var nan = isNaN(value);
35756 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
35757 return nan ? '' : value;
35759 return parseFloat(value).toFixed(this.decimalPrecision);
35762 setValue : function(v)
35764 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
35770 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
35772 this.inputEl().dom.value = (v == '') ? '' :
35773 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
35775 if(!this.allowZero && v === '0') {
35776 this.hiddenEl().dom.value = '';
35777 this.inputEl().dom.value = '';
35784 decimalPrecisionFcn : function(v)
35786 return Math.floor(v);
35789 beforeBlur : function()
35791 var v = this.parseValue(this.getRawValue());
35793 if(v || v === 0 || v === ''){
35798 hiddenEl : function()
35800 return this.el.select('input.hidden-number-input',true).first();
35812 * @class Roo.bootstrap.DocumentSlider
35813 * @extends Roo.bootstrap.Component
35814 * Bootstrap DocumentSlider class
35817 * Create a new DocumentViewer
35818 * @param {Object} config The config object
35821 Roo.bootstrap.DocumentSlider = function(config){
35822 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
35829 * Fire after initEvent
35830 * @param {Roo.bootstrap.DocumentSlider} this
35835 * Fire after update
35836 * @param {Roo.bootstrap.DocumentSlider} this
35842 * @param {Roo.bootstrap.DocumentSlider} this
35848 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
35854 getAutoCreate : function()
35858 cls : 'roo-document-slider',
35862 cls : 'roo-document-slider-header',
35866 cls : 'roo-document-slider-header-title'
35872 cls : 'roo-document-slider-body',
35876 cls : 'roo-document-slider-prev',
35880 cls : 'fa fa-chevron-left'
35886 cls : 'roo-document-slider-thumb',
35890 cls : 'roo-document-slider-image'
35896 cls : 'roo-document-slider-next',
35900 cls : 'fa fa-chevron-right'
35912 initEvents : function()
35914 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
35915 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
35917 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
35918 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
35920 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
35921 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
35923 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
35924 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
35926 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
35927 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
35929 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
35930 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
35932 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
35933 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
35935 this.thumbEl.on('click', this.onClick, this);
35937 this.prevIndicator.on('click', this.prev, this);
35939 this.nextIndicator.on('click', this.next, this);
35943 initial : function()
35945 if(this.files.length){
35946 this.indicator = 1;
35950 this.fireEvent('initial', this);
35953 update : function()
35955 this.imageEl.attr('src', this.files[this.indicator - 1]);
35957 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
35959 this.prevIndicator.show();
35961 if(this.indicator == 1){
35962 this.prevIndicator.hide();
35965 this.nextIndicator.show();
35967 if(this.indicator == this.files.length){
35968 this.nextIndicator.hide();
35971 this.thumbEl.scrollTo('top');
35973 this.fireEvent('update', this);
35976 onClick : function(e)
35978 e.preventDefault();
35980 this.fireEvent('click', this);
35985 e.preventDefault();
35987 this.indicator = Math.max(1, this.indicator - 1);
35994 e.preventDefault();
35996 this.indicator = Math.min(this.files.length, this.indicator + 1);
36010 * @class Roo.bootstrap.RadioSet
36011 * @extends Roo.bootstrap.Input
36012 * Bootstrap RadioSet class
36013 * @cfg {String} indicatorpos (left|right) default left
36014 * @cfg {Boolean} inline (true|false) inline the element (default true)
36015 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
36017 * Create a new RadioSet
36018 * @param {Object} config The config object
36021 Roo.bootstrap.RadioSet = function(config){
36023 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
36027 Roo.bootstrap.RadioSet.register(this);
36032 * Fires when the element is checked or unchecked.
36033 * @param {Roo.bootstrap.RadioSet} this This radio
36034 * @param {Roo.bootstrap.Radio} item The checked item
36039 * Fires when the element is click.
36040 * @param {Roo.bootstrap.RadioSet} this This radio set
36041 * @param {Roo.bootstrap.Radio} item The checked item
36042 * @param {Roo.EventObject} e The event object
36049 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
36057 indicatorpos : 'left',
36059 getAutoCreate : function()
36063 cls : 'roo-radio-set-label',
36067 html : this.fieldLabel
36071 if (Roo.bootstrap.version == 3) {
36074 if(this.indicatorpos == 'left'){
36077 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
36078 tooltip : 'This field is required'
36083 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
36084 tooltip : 'This field is required'
36090 cls : 'roo-radio-set-items'
36093 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
36095 if (align === 'left' && this.fieldLabel.length) {
36098 cls : "roo-radio-set-right",
36104 if(this.labelWidth > 12){
36105 label.style = "width: " + this.labelWidth + 'px';
36108 if(this.labelWidth < 13 && this.labelmd == 0){
36109 this.labelmd = this.labelWidth;
36112 if(this.labellg > 0){
36113 label.cls += ' col-lg-' + this.labellg;
36114 items.cls += ' col-lg-' + (12 - this.labellg);
36117 if(this.labelmd > 0){
36118 label.cls += ' col-md-' + this.labelmd;
36119 items.cls += ' col-md-' + (12 - this.labelmd);
36122 if(this.labelsm > 0){
36123 label.cls += ' col-sm-' + this.labelsm;
36124 items.cls += ' col-sm-' + (12 - this.labelsm);
36127 if(this.labelxs > 0){
36128 label.cls += ' col-xs-' + this.labelxs;
36129 items.cls += ' col-xs-' + (12 - this.labelxs);
36135 cls : 'roo-radio-set',
36139 cls : 'roo-radio-set-input',
36142 value : this.value ? this.value : ''
36149 if(this.weight.length){
36150 cfg.cls += ' roo-radio-' + this.weight;
36154 cfg.cls += ' roo-radio-set-inline';
36158 ['xs','sm','md','lg'].map(function(size){
36159 if (settings[size]) {
36160 cfg.cls += ' col-' + size + '-' + settings[size];
36168 initEvents : function()
36170 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
36171 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
36173 if(!this.fieldLabel.length){
36174 this.labelEl.hide();
36177 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
36178 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
36180 this.indicator = this.indicatorEl();
36182 if(this.indicator){
36183 this.indicator.addClass('invisible');
36186 this.originalValue = this.getValue();
36190 inputEl: function ()
36192 return this.el.select('.roo-radio-set-input', true).first();
36195 getChildContainer : function()
36197 return this.itemsEl;
36200 register : function(item)
36202 this.radioes.push(item);
36206 validate : function()
36208 if(this.getVisibilityEl().hasClass('hidden')){
36214 Roo.each(this.radioes, function(i){
36223 if(this.allowBlank) {
36227 if(this.disabled || valid){
36232 this.markInvalid();
36237 markValid : function()
36239 if(this.labelEl.isVisible(true) && this.indicatorEl()){
36240 this.indicatorEl().removeClass('visible');
36241 this.indicatorEl().addClass('invisible');
36245 if (Roo.bootstrap.version == 3) {
36246 this.el.removeClass([this.invalidClass, this.validClass]);
36247 this.el.addClass(this.validClass);
36249 this.el.removeClass(['is-invalid','is-valid']);
36250 this.el.addClass(['is-valid']);
36252 this.fireEvent('valid', this);
36255 markInvalid : function(msg)
36257 if(this.allowBlank || this.disabled){
36261 if(this.labelEl.isVisible(true) && this.indicatorEl()){
36262 this.indicatorEl().removeClass('invisible');
36263 this.indicatorEl().addClass('visible');
36265 if (Roo.bootstrap.version == 3) {
36266 this.el.removeClass([this.invalidClass, this.validClass]);
36267 this.el.addClass(this.invalidClass);
36269 this.el.removeClass(['is-invalid','is-valid']);
36270 this.el.addClass(['is-invalid']);
36273 this.fireEvent('invalid', this, msg);
36277 setValue : function(v, suppressEvent)
36279 if(this.value === v){
36286 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
36289 Roo.each(this.radioes, function(i){
36291 i.el.removeClass('checked');
36294 Roo.each(this.radioes, function(i){
36296 if(i.value === v || i.value.toString() === v.toString()){
36298 i.el.addClass('checked');
36300 if(suppressEvent !== true){
36301 this.fireEvent('check', this, i);
36312 clearInvalid : function(){
36314 if(!this.el || this.preventMark){
36318 this.el.removeClass([this.invalidClass]);
36320 this.fireEvent('valid', this);
36325 Roo.apply(Roo.bootstrap.RadioSet, {
36329 register : function(set)
36331 this.groups[set.name] = set;
36334 get: function(name)
36336 if (typeof(this.groups[name]) == 'undefined') {
36340 return this.groups[name] ;
36346 * Ext JS Library 1.1.1
36347 * Copyright(c) 2006-2007, Ext JS, LLC.
36349 * Originally Released Under LGPL - original licence link has changed is not relivant.
36352 * <script type="text/javascript">
36357 * @class Roo.bootstrap.SplitBar
36358 * @extends Roo.util.Observable
36359 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
36363 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
36364 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
36365 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
36366 split.minSize = 100;
36367 split.maxSize = 600;
36368 split.animate = true;
36369 split.on('moved', splitterMoved);
36372 * Create a new SplitBar
36373 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
36374 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
36375 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
36376 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
36377 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
36378 position of the SplitBar).
36380 Roo.bootstrap.SplitBar = function(cfg){
36385 // dragElement : elm
36386 // resizingElement: el,
36388 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
36389 // placement : Roo.bootstrap.SplitBar.LEFT ,
36390 // existingProxy ???
36393 this.el = Roo.get(cfg.dragElement, true);
36394 this.el.dom.unselectable = "on";
36396 this.resizingEl = Roo.get(cfg.resizingElement, true);
36400 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
36401 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
36404 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
36407 * The minimum size of the resizing element. (Defaults to 0)
36413 * The maximum size of the resizing element. (Defaults to 2000)
36416 this.maxSize = 2000;
36419 * Whether to animate the transition to the new size
36422 this.animate = false;
36425 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
36428 this.useShim = false;
36433 if(!cfg.existingProxy){
36435 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
36437 this.proxy = Roo.get(cfg.existingProxy).dom;
36440 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
36443 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
36446 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
36449 this.dragSpecs = {};
36452 * @private The adapter to use to positon and resize elements
36454 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
36455 this.adapter.init(this);
36457 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
36459 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
36460 this.el.addClass("roo-splitbar-h");
36463 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
36464 this.el.addClass("roo-splitbar-v");
36470 * Fires when the splitter is moved (alias for {@link #event-moved})
36471 * @param {Roo.bootstrap.SplitBar} this
36472 * @param {Number} newSize the new width or height
36477 * Fires when the splitter is moved
36478 * @param {Roo.bootstrap.SplitBar} this
36479 * @param {Number} newSize the new width or height
36483 * @event beforeresize
36484 * Fires before the splitter is dragged
36485 * @param {Roo.bootstrap.SplitBar} this
36487 "beforeresize" : true,
36489 "beforeapply" : true
36492 Roo.util.Observable.call(this);
36495 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
36496 onStartProxyDrag : function(x, y){
36497 this.fireEvent("beforeresize", this);
36499 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
36501 o.enableDisplayMode("block");
36502 // all splitbars share the same overlay
36503 Roo.bootstrap.SplitBar.prototype.overlay = o;
36505 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
36506 this.overlay.show();
36507 Roo.get(this.proxy).setDisplayed("block");
36508 var size = this.adapter.getElementSize(this);
36509 this.activeMinSize = this.getMinimumSize();;
36510 this.activeMaxSize = this.getMaximumSize();;
36511 var c1 = size - this.activeMinSize;
36512 var c2 = Math.max(this.activeMaxSize - size, 0);
36513 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
36514 this.dd.resetConstraints();
36515 this.dd.setXConstraint(
36516 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
36517 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
36519 this.dd.setYConstraint(0, 0);
36521 this.dd.resetConstraints();
36522 this.dd.setXConstraint(0, 0);
36523 this.dd.setYConstraint(
36524 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
36525 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
36528 this.dragSpecs.startSize = size;
36529 this.dragSpecs.startPoint = [x, y];
36530 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
36534 * @private Called after the drag operation by the DDProxy
36536 onEndProxyDrag : function(e){
36537 Roo.get(this.proxy).setDisplayed(false);
36538 var endPoint = Roo.lib.Event.getXY(e);
36540 this.overlay.hide();
36543 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
36544 newSize = this.dragSpecs.startSize +
36545 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
36546 endPoint[0] - this.dragSpecs.startPoint[0] :
36547 this.dragSpecs.startPoint[0] - endPoint[0]
36550 newSize = this.dragSpecs.startSize +
36551 (this.placement == Roo.bootstrap.SplitBar.TOP ?
36552 endPoint[1] - this.dragSpecs.startPoint[1] :
36553 this.dragSpecs.startPoint[1] - endPoint[1]
36556 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
36557 if(newSize != this.dragSpecs.startSize){
36558 if(this.fireEvent('beforeapply', this, newSize) !== false){
36559 this.adapter.setElementSize(this, newSize);
36560 this.fireEvent("moved", this, newSize);
36561 this.fireEvent("resize", this, newSize);
36567 * Get the adapter this SplitBar uses
36568 * @return The adapter object
36570 getAdapter : function(){
36571 return this.adapter;
36575 * Set the adapter this SplitBar uses
36576 * @param {Object} adapter A SplitBar adapter object
36578 setAdapter : function(adapter){
36579 this.adapter = adapter;
36580 this.adapter.init(this);
36584 * Gets the minimum size for the resizing element
36585 * @return {Number} The minimum size
36587 getMinimumSize : function(){
36588 return this.minSize;
36592 * Sets the minimum size for the resizing element
36593 * @param {Number} minSize The minimum size
36595 setMinimumSize : function(minSize){
36596 this.minSize = minSize;
36600 * Gets the maximum size for the resizing element
36601 * @return {Number} The maximum size
36603 getMaximumSize : function(){
36604 return this.maxSize;
36608 * Sets the maximum size for the resizing element
36609 * @param {Number} maxSize The maximum size
36611 setMaximumSize : function(maxSize){
36612 this.maxSize = maxSize;
36616 * Sets the initialize size for the resizing element
36617 * @param {Number} size The initial size
36619 setCurrentSize : function(size){
36620 var oldAnimate = this.animate;
36621 this.animate = false;
36622 this.adapter.setElementSize(this, size);
36623 this.animate = oldAnimate;
36627 * Destroy this splitbar.
36628 * @param {Boolean} removeEl True to remove the element
36630 destroy : function(removeEl){
36632 this.shim.remove();
36635 this.proxy.parentNode.removeChild(this.proxy);
36643 * @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.
36645 Roo.bootstrap.SplitBar.createProxy = function(dir){
36646 var proxy = new Roo.Element(document.createElement("div"));
36647 proxy.unselectable();
36648 var cls = 'roo-splitbar-proxy';
36649 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
36650 document.body.appendChild(proxy.dom);
36655 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
36656 * Default Adapter. It assumes the splitter and resizing element are not positioned
36657 * elements and only gets/sets the width of the element. Generally used for table based layouts.
36659 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
36662 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
36663 // do nothing for now
36664 init : function(s){
36668 * Called before drag operations to get the current size of the resizing element.
36669 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
36671 getElementSize : function(s){
36672 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
36673 return s.resizingEl.getWidth();
36675 return s.resizingEl.getHeight();
36680 * Called after drag operations to set the size of the resizing element.
36681 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
36682 * @param {Number} newSize The new size to set
36683 * @param {Function} onComplete A function to be invoked when resizing is complete
36685 setElementSize : function(s, newSize, onComplete){
36686 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
36688 s.resizingEl.setWidth(newSize);
36690 onComplete(s, newSize);
36693 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
36698 s.resizingEl.setHeight(newSize);
36700 onComplete(s, newSize);
36703 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
36710 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
36711 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
36712 * Adapter that moves the splitter element to align with the resized sizing element.
36713 * Used with an absolute positioned SplitBar.
36714 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
36715 * document.body, make sure you assign an id to the body element.
36717 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
36718 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
36719 this.container = Roo.get(container);
36722 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
36723 init : function(s){
36724 this.basic.init(s);
36727 getElementSize : function(s){
36728 return this.basic.getElementSize(s);
36731 setElementSize : function(s, newSize, onComplete){
36732 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
36735 moveSplitter : function(s){
36736 var yes = Roo.bootstrap.SplitBar;
36737 switch(s.placement){
36739 s.el.setX(s.resizingEl.getRight());
36742 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
36745 s.el.setY(s.resizingEl.getBottom());
36748 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
36755 * Orientation constant - Create a vertical SplitBar
36759 Roo.bootstrap.SplitBar.VERTICAL = 1;
36762 * Orientation constant - Create a horizontal SplitBar
36766 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
36769 * Placement constant - The resizing element is to the left of the splitter element
36773 Roo.bootstrap.SplitBar.LEFT = 1;
36776 * Placement constant - The resizing element is to the right of the splitter element
36780 Roo.bootstrap.SplitBar.RIGHT = 2;
36783 * Placement constant - The resizing element is positioned above the splitter element
36787 Roo.bootstrap.SplitBar.TOP = 3;
36790 * Placement constant - The resizing element is positioned under splitter element
36794 Roo.bootstrap.SplitBar.BOTTOM = 4;
36795 Roo.namespace("Roo.bootstrap.layout");/*
36797 * Ext JS Library 1.1.1
36798 * Copyright(c) 2006-2007, Ext JS, LLC.
36800 * Originally Released Under LGPL - original licence link has changed is not relivant.
36803 * <script type="text/javascript">
36807 * @class Roo.bootstrap.layout.Manager
36808 * @extends Roo.bootstrap.Component
36809 * Base class for layout managers.
36811 Roo.bootstrap.layout.Manager = function(config)
36813 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
36819 /** false to disable window resize monitoring @type Boolean */
36820 this.monitorWindowResize = true;
36825 * Fires when a layout is performed.
36826 * @param {Roo.LayoutManager} this
36830 * @event regionresized
36831 * Fires when the user resizes a region.
36832 * @param {Roo.LayoutRegion} region The resized region
36833 * @param {Number} newSize The new size (width for east/west, height for north/south)
36835 "regionresized" : true,
36837 * @event regioncollapsed
36838 * Fires when a region is collapsed.
36839 * @param {Roo.LayoutRegion} region The collapsed region
36841 "regioncollapsed" : true,
36843 * @event regionexpanded
36844 * Fires when a region is expanded.
36845 * @param {Roo.LayoutRegion} region The expanded region
36847 "regionexpanded" : true
36849 this.updating = false;
36852 this.el = Roo.get(config.el);
36858 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
36863 monitorWindowResize : true,
36869 onRender : function(ct, position)
36872 this.el = Roo.get(ct);
36875 //this.fireEvent('render',this);
36879 initEvents: function()
36883 // ie scrollbar fix
36884 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
36885 document.body.scroll = "no";
36886 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
36887 this.el.position('relative');
36889 this.id = this.el.id;
36890 this.el.addClass("roo-layout-container");
36891 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
36892 if(this.el.dom != document.body ) {
36893 this.el.on('resize', this.layout,this);
36894 this.el.on('show', this.layout,this);
36900 * Returns true if this layout is currently being updated
36901 * @return {Boolean}
36903 isUpdating : function(){
36904 return this.updating;
36908 * Suspend the LayoutManager from doing auto-layouts while
36909 * making multiple add or remove calls
36911 beginUpdate : function(){
36912 this.updating = true;
36916 * Restore auto-layouts and optionally disable the manager from performing a layout
36917 * @param {Boolean} noLayout true to disable a layout update
36919 endUpdate : function(noLayout){
36920 this.updating = false;
36926 layout: function(){
36930 onRegionResized : function(region, newSize){
36931 this.fireEvent("regionresized", region, newSize);
36935 onRegionCollapsed : function(region){
36936 this.fireEvent("regioncollapsed", region);
36939 onRegionExpanded : function(region){
36940 this.fireEvent("regionexpanded", region);
36944 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
36945 * performs box-model adjustments.
36946 * @return {Object} The size as an object {width: (the width), height: (the height)}
36948 getViewSize : function()
36951 if(this.el.dom != document.body){
36952 size = this.el.getSize();
36954 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
36956 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
36957 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
36962 * Returns the Element this layout is bound to.
36963 * @return {Roo.Element}
36965 getEl : function(){
36970 * Returns the specified region.
36971 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
36972 * @return {Roo.LayoutRegion}
36974 getRegion : function(target){
36975 return this.regions[target.toLowerCase()];
36978 onWindowResize : function(){
36979 if(this.monitorWindowResize){
36986 * Ext JS Library 1.1.1
36987 * Copyright(c) 2006-2007, Ext JS, LLC.
36989 * Originally Released Under LGPL - original licence link has changed is not relivant.
36992 * <script type="text/javascript">
36995 * @class Roo.bootstrap.layout.Border
36996 * @extends Roo.bootstrap.layout.Manager
36997 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
36998 * please see: examples/bootstrap/nested.html<br><br>
37000 <b>The container the layout is rendered into can be either the body element or any other element.
37001 If it is not the body element, the container needs to either be an absolute positioned element,
37002 or you will need to add "position:relative" to the css of the container. You will also need to specify
37003 the container size if it is not the body element.</b>
37006 * Create a new Border
37007 * @param {Object} config Configuration options
37009 Roo.bootstrap.layout.Border = function(config){
37010 config = config || {};
37011 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
37015 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
37016 if(config[region]){
37017 config[region].region = region;
37018 this.addRegion(config[region]);
37024 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
37026 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
37028 parent : false, // this might point to a 'nest' or a ???
37031 * Creates and adds a new region if it doesn't already exist.
37032 * @param {String} target The target region key (north, south, east, west or center).
37033 * @param {Object} config The regions config object
37034 * @return {BorderLayoutRegion} The new region
37036 addRegion : function(config)
37038 if(!this.regions[config.region]){
37039 var r = this.factory(config);
37040 this.bindRegion(r);
37042 return this.regions[config.region];
37046 bindRegion : function(r){
37047 this.regions[r.config.region] = r;
37049 r.on("visibilitychange", this.layout, this);
37050 r.on("paneladded", this.layout, this);
37051 r.on("panelremoved", this.layout, this);
37052 r.on("invalidated", this.layout, this);
37053 r.on("resized", this.onRegionResized, this);
37054 r.on("collapsed", this.onRegionCollapsed, this);
37055 r.on("expanded", this.onRegionExpanded, this);
37059 * Performs a layout update.
37061 layout : function()
37063 if(this.updating) {
37067 // render all the rebions if they have not been done alreayd?
37068 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
37069 if(this.regions[region] && !this.regions[region].bodyEl){
37070 this.regions[region].onRender(this.el)
37074 var size = this.getViewSize();
37075 var w = size.width;
37076 var h = size.height;
37081 //var x = 0, y = 0;
37083 var rs = this.regions;
37084 var north = rs["north"];
37085 var south = rs["south"];
37086 var west = rs["west"];
37087 var east = rs["east"];
37088 var center = rs["center"];
37089 //if(this.hideOnLayout){ // not supported anymore
37090 //c.el.setStyle("display", "none");
37092 if(north && north.isVisible()){
37093 var b = north.getBox();
37094 var m = north.getMargins();
37095 b.width = w - (m.left+m.right);
37098 centerY = b.height + b.y + m.bottom;
37099 centerH -= centerY;
37100 north.updateBox(this.safeBox(b));
37102 if(south && south.isVisible()){
37103 var b = south.getBox();
37104 var m = south.getMargins();
37105 b.width = w - (m.left+m.right);
37107 var totalHeight = (b.height + m.top + m.bottom);
37108 b.y = h - totalHeight + m.top;
37109 centerH -= totalHeight;
37110 south.updateBox(this.safeBox(b));
37112 if(west && west.isVisible()){
37113 var b = west.getBox();
37114 var m = west.getMargins();
37115 b.height = centerH - (m.top+m.bottom);
37117 b.y = centerY + m.top;
37118 var totalWidth = (b.width + m.left + m.right);
37119 centerX += totalWidth;
37120 centerW -= totalWidth;
37121 west.updateBox(this.safeBox(b));
37123 if(east && east.isVisible()){
37124 var b = east.getBox();
37125 var m = east.getMargins();
37126 b.height = centerH - (m.top+m.bottom);
37127 var totalWidth = (b.width + m.left + m.right);
37128 b.x = w - totalWidth + m.left;
37129 b.y = centerY + m.top;
37130 centerW -= totalWidth;
37131 east.updateBox(this.safeBox(b));
37134 var m = center.getMargins();
37136 x: centerX + m.left,
37137 y: centerY + m.top,
37138 width: centerW - (m.left+m.right),
37139 height: centerH - (m.top+m.bottom)
37141 //if(this.hideOnLayout){
37142 //center.el.setStyle("display", "block");
37144 center.updateBox(this.safeBox(centerBox));
37147 this.fireEvent("layout", this);
37151 safeBox : function(box){
37152 box.width = Math.max(0, box.width);
37153 box.height = Math.max(0, box.height);
37158 * Adds a ContentPanel (or subclass) to this layout.
37159 * @param {String} target The target region key (north, south, east, west or center).
37160 * @param {Roo.ContentPanel} panel The panel to add
37161 * @return {Roo.ContentPanel} The added panel
37163 add : function(target, panel){
37165 target = target.toLowerCase();
37166 return this.regions[target].add(panel);
37170 * Remove a ContentPanel (or subclass) to this layout.
37171 * @param {String} target The target region key (north, south, east, west or center).
37172 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
37173 * @return {Roo.ContentPanel} The removed panel
37175 remove : function(target, panel){
37176 target = target.toLowerCase();
37177 return this.regions[target].remove(panel);
37181 * Searches all regions for a panel with the specified id
37182 * @param {String} panelId
37183 * @return {Roo.ContentPanel} The panel or null if it wasn't found
37185 findPanel : function(panelId){
37186 var rs = this.regions;
37187 for(var target in rs){
37188 if(typeof rs[target] != "function"){
37189 var p = rs[target].getPanel(panelId);
37199 * Searches all regions for a panel with the specified id and activates (shows) it.
37200 * @param {String/ContentPanel} panelId The panels id or the panel itself
37201 * @return {Roo.ContentPanel} The shown panel or null
37203 showPanel : function(panelId) {
37204 var rs = this.regions;
37205 for(var target in rs){
37206 var r = rs[target];
37207 if(typeof r != "function"){
37208 if(r.hasPanel(panelId)){
37209 return r.showPanel(panelId);
37217 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
37218 * @param {Roo.state.Provider} provider (optional) An alternate state provider
37221 restoreState : function(provider){
37223 provider = Roo.state.Manager;
37225 var sm = new Roo.LayoutStateManager();
37226 sm.init(this, provider);
37232 * Adds a xtype elements to the layout.
37236 xtype : 'ContentPanel',
37243 xtype : 'NestedLayoutPanel',
37249 items : [ ... list of content panels or nested layout panels.. ]
37253 * @param {Object} cfg Xtype definition of item to add.
37255 addxtype : function(cfg)
37257 // basically accepts a pannel...
37258 // can accept a layout region..!?!?
37259 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
37262 // theory? children can only be panels??
37264 //if (!cfg.xtype.match(/Panel$/)) {
37269 if (typeof(cfg.region) == 'undefined') {
37270 Roo.log("Failed to add Panel, region was not set");
37274 var region = cfg.region;
37280 xitems = cfg.items;
37285 if ( region == 'center') {
37286 Roo.log("Center: " + cfg.title);
37292 case 'Content': // ContentPanel (el, cfg)
37293 case 'Scroll': // ContentPanel (el, cfg)
37295 cfg.autoCreate = cfg.autoCreate || true;
37296 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
37298 // var el = this.el.createChild();
37299 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
37302 this.add(region, ret);
37306 case 'TreePanel': // our new panel!
37307 cfg.el = this.el.createChild();
37308 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
37309 this.add(region, ret);
37314 // create a new Layout (which is a Border Layout...
37316 var clayout = cfg.layout;
37317 clayout.el = this.el.createChild();
37318 clayout.items = clayout.items || [];
37322 // replace this exitems with the clayout ones..
37323 xitems = clayout.items;
37325 // force background off if it's in center...
37326 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
37327 cfg.background = false;
37329 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
37332 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
37333 //console.log('adding nested layout panel ' + cfg.toSource());
37334 this.add(region, ret);
37335 nb = {}; /// find first...
37340 // needs grid and region
37342 //var el = this.getRegion(region).el.createChild();
37344 *var el = this.el.createChild();
37345 // create the grid first...
37346 cfg.grid.container = el;
37347 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
37350 if (region == 'center' && this.active ) {
37351 cfg.background = false;
37354 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
37356 this.add(region, ret);
37358 if (cfg.background) {
37359 // render grid on panel activation (if panel background)
37360 ret.on('activate', function(gp) {
37361 if (!gp.grid.rendered) {
37362 // gp.grid.render(el);
37366 // cfg.grid.render(el);
37372 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
37373 // it was the old xcomponent building that caused this before.
37374 // espeically if border is the top element in the tree.
37384 if (typeof(Roo[cfg.xtype]) != 'undefined') {
37386 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
37387 this.add(region, ret);
37391 throw "Can not add '" + cfg.xtype + "' to Border";
37397 this.beginUpdate();
37401 Roo.each(xitems, function(i) {
37402 region = nb && i.region ? i.region : false;
37404 var add = ret.addxtype(i);
37407 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
37408 if (!i.background) {
37409 abn[region] = nb[region] ;
37416 // make the last non-background panel active..
37417 //if (nb) { Roo.log(abn); }
37420 for(var r in abn) {
37421 region = this.getRegion(r);
37423 // tried using nb[r], but it does not work..
37425 region.showPanel(abn[r]);
37436 factory : function(cfg)
37439 var validRegions = Roo.bootstrap.layout.Border.regions;
37441 var target = cfg.region;
37444 var r = Roo.bootstrap.layout;
37448 return new r.North(cfg);
37450 return new r.South(cfg);
37452 return new r.East(cfg);
37454 return new r.West(cfg);
37456 return new r.Center(cfg);
37458 throw 'Layout region "'+target+'" not supported.';
37465 * Ext JS Library 1.1.1
37466 * Copyright(c) 2006-2007, Ext JS, LLC.
37468 * Originally Released Under LGPL - original licence link has changed is not relivant.
37471 * <script type="text/javascript">
37475 * @class Roo.bootstrap.layout.Basic
37476 * @extends Roo.util.Observable
37477 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
37478 * and does not have a titlebar, tabs or any other features. All it does is size and position
37479 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
37480 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
37481 * @cfg {string} region the region that it inhabits..
37482 * @cfg {bool} skipConfig skip config?
37486 Roo.bootstrap.layout.Basic = function(config){
37488 this.mgr = config.mgr;
37490 this.position = config.region;
37492 var skipConfig = config.skipConfig;
37496 * @scope Roo.BasicLayoutRegion
37500 * @event beforeremove
37501 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
37502 * @param {Roo.LayoutRegion} this
37503 * @param {Roo.ContentPanel} panel The panel
37504 * @param {Object} e The cancel event object
37506 "beforeremove" : true,
37508 * @event invalidated
37509 * Fires when the layout for this region is changed.
37510 * @param {Roo.LayoutRegion} this
37512 "invalidated" : true,
37514 * @event visibilitychange
37515 * Fires when this region is shown or hidden
37516 * @param {Roo.LayoutRegion} this
37517 * @param {Boolean} visibility true or false
37519 "visibilitychange" : true,
37521 * @event paneladded
37522 * Fires when a panel is added.
37523 * @param {Roo.LayoutRegion} this
37524 * @param {Roo.ContentPanel} panel The panel
37526 "paneladded" : true,
37528 * @event panelremoved
37529 * Fires when a panel is removed.
37530 * @param {Roo.LayoutRegion} this
37531 * @param {Roo.ContentPanel} panel The panel
37533 "panelremoved" : true,
37535 * @event beforecollapse
37536 * Fires when this region before collapse.
37537 * @param {Roo.LayoutRegion} this
37539 "beforecollapse" : true,
37542 * Fires when this region is collapsed.
37543 * @param {Roo.LayoutRegion} this
37545 "collapsed" : true,
37548 * Fires when this region is expanded.
37549 * @param {Roo.LayoutRegion} this
37554 * Fires when this region is slid into view.
37555 * @param {Roo.LayoutRegion} this
37557 "slideshow" : true,
37560 * Fires when this region slides out of view.
37561 * @param {Roo.LayoutRegion} this
37563 "slidehide" : true,
37565 * @event panelactivated
37566 * Fires when a panel is activated.
37567 * @param {Roo.LayoutRegion} this
37568 * @param {Roo.ContentPanel} panel The activated panel
37570 "panelactivated" : true,
37573 * Fires when the user resizes this region.
37574 * @param {Roo.LayoutRegion} this
37575 * @param {Number} newSize The new size (width for east/west, height for north/south)
37579 /** A collection of panels in this region. @type Roo.util.MixedCollection */
37580 this.panels = new Roo.util.MixedCollection();
37581 this.panels.getKey = this.getPanelId.createDelegate(this);
37583 this.activePanel = null;
37584 // ensure listeners are added...
37586 if (config.listeners || config.events) {
37587 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
37588 listeners : config.listeners || {},
37589 events : config.events || {}
37593 if(skipConfig !== true){
37594 this.applyConfig(config);
37598 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
37600 getPanelId : function(p){
37604 applyConfig : function(config){
37605 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
37606 this.config = config;
37611 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
37612 * the width, for horizontal (north, south) the height.
37613 * @param {Number} newSize The new width or height
37615 resizeTo : function(newSize){
37616 var el = this.el ? this.el :
37617 (this.activePanel ? this.activePanel.getEl() : null);
37619 switch(this.position){
37622 el.setWidth(newSize);
37623 this.fireEvent("resized", this, newSize);
37627 el.setHeight(newSize);
37628 this.fireEvent("resized", this, newSize);
37634 getBox : function(){
37635 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
37638 getMargins : function(){
37639 return this.margins;
37642 updateBox : function(box){
37644 var el = this.activePanel.getEl();
37645 el.dom.style.left = box.x + "px";
37646 el.dom.style.top = box.y + "px";
37647 this.activePanel.setSize(box.width, box.height);
37651 * Returns the container element for this region.
37652 * @return {Roo.Element}
37654 getEl : function(){
37655 return this.activePanel;
37659 * Returns true if this region is currently visible.
37660 * @return {Boolean}
37662 isVisible : function(){
37663 return this.activePanel ? true : false;
37666 setActivePanel : function(panel){
37667 panel = this.getPanel(panel);
37668 if(this.activePanel && this.activePanel != panel){
37669 this.activePanel.setActiveState(false);
37670 this.activePanel.getEl().setLeftTop(-10000,-10000);
37672 this.activePanel = panel;
37673 panel.setActiveState(true);
37675 panel.setSize(this.box.width, this.box.height);
37677 this.fireEvent("panelactivated", this, panel);
37678 this.fireEvent("invalidated");
37682 * Show the specified panel.
37683 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
37684 * @return {Roo.ContentPanel} The shown panel or null
37686 showPanel : function(panel){
37687 panel = this.getPanel(panel);
37689 this.setActivePanel(panel);
37695 * Get the active panel for this region.
37696 * @return {Roo.ContentPanel} The active panel or null
37698 getActivePanel : function(){
37699 return this.activePanel;
37703 * Add the passed ContentPanel(s)
37704 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
37705 * @return {Roo.ContentPanel} The panel added (if only one was added)
37707 add : function(panel){
37708 if(arguments.length > 1){
37709 for(var i = 0, len = arguments.length; i < len; i++) {
37710 this.add(arguments[i]);
37714 if(this.hasPanel(panel)){
37715 this.showPanel(panel);
37718 var el = panel.getEl();
37719 if(el.dom.parentNode != this.mgr.el.dom){
37720 this.mgr.el.dom.appendChild(el.dom);
37722 if(panel.setRegion){
37723 panel.setRegion(this);
37725 this.panels.add(panel);
37726 el.setStyle("position", "absolute");
37727 if(!panel.background){
37728 this.setActivePanel(panel);
37729 if(this.config.initialSize && this.panels.getCount()==1){
37730 this.resizeTo(this.config.initialSize);
37733 this.fireEvent("paneladded", this, panel);
37738 * Returns true if the panel is in this region.
37739 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
37740 * @return {Boolean}
37742 hasPanel : function(panel){
37743 if(typeof panel == "object"){ // must be panel obj
37744 panel = panel.getId();
37746 return this.getPanel(panel) ? true : false;
37750 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
37751 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
37752 * @param {Boolean} preservePanel Overrides the config preservePanel option
37753 * @return {Roo.ContentPanel} The panel that was removed
37755 remove : function(panel, preservePanel){
37756 panel = this.getPanel(panel);
37761 this.fireEvent("beforeremove", this, panel, e);
37762 if(e.cancel === true){
37765 var panelId = panel.getId();
37766 this.panels.removeKey(panelId);
37771 * Returns the panel specified or null if it's not in this region.
37772 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
37773 * @return {Roo.ContentPanel}
37775 getPanel : function(id){
37776 if(typeof id == "object"){ // must be panel obj
37779 return this.panels.get(id);
37783 * Returns this regions position (north/south/east/west/center).
37786 getPosition: function(){
37787 return this.position;
37791 * Ext JS Library 1.1.1
37792 * Copyright(c) 2006-2007, Ext JS, LLC.
37794 * Originally Released Under LGPL - original licence link has changed is not relivant.
37797 * <script type="text/javascript">
37801 * @class Roo.bootstrap.layout.Region
37802 * @extends Roo.bootstrap.layout.Basic
37803 * This class represents a region in a layout manager.
37805 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
37806 * @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})
37807 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
37808 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
37809 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
37810 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
37811 * @cfg {String} title The title for the region (overrides panel titles)
37812 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
37813 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
37814 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
37815 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
37816 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
37817 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
37818 * the space available, similar to FireFox 1.5 tabs (defaults to false)
37819 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
37820 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
37821 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
37823 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
37824 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
37825 * @cfg {Boolean} disableTabTips True to disable tab tooltips
37826 * @cfg {Number} width For East/West panels
37827 * @cfg {Number} height For North/South panels
37828 * @cfg {Boolean} split To show the splitter
37829 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
37831 * @cfg {string} cls Extra CSS classes to add to region
37833 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
37834 * @cfg {string} region the region that it inhabits..
37837 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
37838 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
37840 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
37841 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
37842 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
37844 Roo.bootstrap.layout.Region = function(config)
37846 this.applyConfig(config);
37848 var mgr = config.mgr;
37849 var pos = config.region;
37850 config.skipConfig = true;
37851 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
37854 this.onRender(mgr.el);
37857 this.visible = true;
37858 this.collapsed = false;
37859 this.unrendered_panels = [];
37862 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
37864 position: '', // set by wrapper (eg. north/south etc..)
37865 unrendered_panels : null, // unrendered panels.
37867 tabPosition : false,
37869 mgr: false, // points to 'Border'
37872 createBody : function(){
37873 /** This region's body element
37874 * @type Roo.Element */
37875 this.bodyEl = this.el.createChild({
37877 cls: "roo-layout-panel-body tab-content" // bootstrap added...
37881 onRender: function(ctr, pos)
37883 var dh = Roo.DomHelper;
37884 /** This region's container element
37885 * @type Roo.Element */
37886 this.el = dh.append(ctr.dom, {
37888 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
37890 /** This region's title element
37891 * @type Roo.Element */
37893 this.titleEl = dh.append(this.el.dom, {
37895 unselectable: "on",
37896 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
37898 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
37899 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
37903 this.titleEl.enableDisplayMode();
37904 /** This region's title text element
37905 * @type HTMLElement */
37906 this.titleTextEl = this.titleEl.dom.firstChild;
37907 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
37909 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
37910 this.closeBtn.enableDisplayMode();
37911 this.closeBtn.on("click", this.closeClicked, this);
37912 this.closeBtn.hide();
37914 this.createBody(this.config);
37915 if(this.config.hideWhenEmpty){
37917 this.on("paneladded", this.validateVisibility, this);
37918 this.on("panelremoved", this.validateVisibility, this);
37920 if(this.autoScroll){
37921 this.bodyEl.setStyle("overflow", "auto");
37923 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
37925 //if(c.titlebar !== false){
37926 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
37927 this.titleEl.hide();
37929 this.titleEl.show();
37930 if(this.config.title){
37931 this.titleTextEl.innerHTML = this.config.title;
37935 if(this.config.collapsed){
37936 this.collapse(true);
37938 if(this.config.hidden){
37942 if (this.unrendered_panels && this.unrendered_panels.length) {
37943 for (var i =0;i< this.unrendered_panels.length; i++) {
37944 this.add(this.unrendered_panels[i]);
37946 this.unrendered_panels = null;
37952 applyConfig : function(c)
37955 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
37956 var dh = Roo.DomHelper;
37957 if(c.titlebar !== false){
37958 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
37959 this.collapseBtn.on("click", this.collapse, this);
37960 this.collapseBtn.enableDisplayMode();
37962 if(c.showPin === true || this.showPin){
37963 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
37964 this.stickBtn.enableDisplayMode();
37965 this.stickBtn.on("click", this.expand, this);
37966 this.stickBtn.hide();
37971 /** This region's collapsed element
37972 * @type Roo.Element */
37975 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
37976 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
37979 if(c.floatable !== false){
37980 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
37981 this.collapsedEl.on("click", this.collapseClick, this);
37984 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
37985 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
37986 id: "message", unselectable: "on", style:{"float":"left"}});
37987 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
37989 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
37990 this.expandBtn.on("click", this.expand, this);
37994 if(this.collapseBtn){
37995 this.collapseBtn.setVisible(c.collapsible == true);
37998 this.cmargins = c.cmargins || this.cmargins ||
37999 (this.position == "west" || this.position == "east" ?
38000 {top: 0, left: 2, right:2, bottom: 0} :
38001 {top: 2, left: 0, right:0, bottom: 2});
38003 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
38006 this.tabPosition = [ 'top','bottom', 'west'].indexOf(c.tabPosition) > -1 ? c.tabPosition : "top";
38008 this.autoScroll = c.autoScroll || false;
38013 this.duration = c.duration || .30;
38014 this.slideDuration = c.slideDuration || .45;
38019 * Returns true if this region is currently visible.
38020 * @return {Boolean}
38022 isVisible : function(){
38023 return this.visible;
38027 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
38028 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
38030 //setCollapsedTitle : function(title){
38031 // title = title || " ";
38032 // if(this.collapsedTitleTextEl){
38033 // this.collapsedTitleTextEl.innerHTML = title;
38037 getBox : function(){
38039 // if(!this.collapsed){
38040 b = this.el.getBox(false, true);
38042 // b = this.collapsedEl.getBox(false, true);
38047 getMargins : function(){
38048 return this.margins;
38049 //return this.collapsed ? this.cmargins : this.margins;
38052 highlight : function(){
38053 this.el.addClass("x-layout-panel-dragover");
38056 unhighlight : function(){
38057 this.el.removeClass("x-layout-panel-dragover");
38060 updateBox : function(box)
38062 if (!this.bodyEl) {
38063 return; // not rendered yet..
38067 if(!this.collapsed){
38068 this.el.dom.style.left = box.x + "px";
38069 this.el.dom.style.top = box.y + "px";
38070 this.updateBody(box.width, box.height);
38072 this.collapsedEl.dom.style.left = box.x + "px";
38073 this.collapsedEl.dom.style.top = box.y + "px";
38074 this.collapsedEl.setSize(box.width, box.height);
38077 this.tabs.autoSizeTabs();
38081 updateBody : function(w, h)
38084 this.el.setWidth(w);
38085 w -= this.el.getBorderWidth("rl");
38086 if(this.config.adjustments){
38087 w += this.config.adjustments[0];
38090 if(h !== null && h > 0){
38091 this.el.setHeight(h);
38092 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
38093 h -= this.el.getBorderWidth("tb");
38094 if(this.config.adjustments){
38095 h += this.config.adjustments[1];
38097 this.bodyEl.setHeight(h);
38099 h = this.tabs.syncHeight(h);
38102 if(this.panelSize){
38103 w = w !== null ? w : this.panelSize.width;
38104 h = h !== null ? h : this.panelSize.height;
38106 if(this.activePanel){
38107 var el = this.activePanel.getEl();
38108 w = w !== null ? w : el.getWidth();
38109 h = h !== null ? h : el.getHeight();
38110 this.panelSize = {width: w, height: h};
38111 this.activePanel.setSize(w, h);
38113 if(Roo.isIE && this.tabs){
38114 this.tabs.el.repaint();
38119 * Returns the container element for this region.
38120 * @return {Roo.Element}
38122 getEl : function(){
38127 * Hides this region.
38130 //if(!this.collapsed){
38131 this.el.dom.style.left = "-2000px";
38134 // this.collapsedEl.dom.style.left = "-2000px";
38135 // this.collapsedEl.hide();
38137 this.visible = false;
38138 this.fireEvent("visibilitychange", this, false);
38142 * Shows this region if it was previously hidden.
38145 //if(!this.collapsed){
38148 // this.collapsedEl.show();
38150 this.visible = true;
38151 this.fireEvent("visibilitychange", this, true);
38154 closeClicked : function(){
38155 if(this.activePanel){
38156 this.remove(this.activePanel);
38160 collapseClick : function(e){
38162 e.stopPropagation();
38165 e.stopPropagation();
38171 * Collapses this region.
38172 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
38175 collapse : function(skipAnim, skipCheck = false){
38176 if(this.collapsed) {
38180 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
38182 this.collapsed = true;
38184 this.split.el.hide();
38186 if(this.config.animate && skipAnim !== true){
38187 this.fireEvent("invalidated", this);
38188 this.animateCollapse();
38190 this.el.setLocation(-20000,-20000);
38192 this.collapsedEl.show();
38193 this.fireEvent("collapsed", this);
38194 this.fireEvent("invalidated", this);
38200 animateCollapse : function(){
38205 * Expands this region if it was previously collapsed.
38206 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
38207 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
38210 expand : function(e, skipAnim){
38212 e.stopPropagation();
38214 if(!this.collapsed || this.el.hasActiveFx()) {
38218 this.afterSlideIn();
38221 this.collapsed = false;
38222 if(this.config.animate && skipAnim !== true){
38223 this.animateExpand();
38227 this.split.el.show();
38229 this.collapsedEl.setLocation(-2000,-2000);
38230 this.collapsedEl.hide();
38231 this.fireEvent("invalidated", this);
38232 this.fireEvent("expanded", this);
38236 animateExpand : function(){
38240 initTabs : function()
38242 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
38244 var ts = new Roo.bootstrap.panel.Tabs({
38245 el: this.bodyEl.dom,
38247 tabPosition: this.tabPosition ? this.tabPosition : 'top',
38248 disableTooltips: this.config.disableTabTips,
38249 toolbar : this.config.toolbar
38252 if(this.config.hideTabs){
38253 ts.stripWrap.setDisplayed(false);
38256 ts.resizeTabs = this.config.resizeTabs === true;
38257 ts.minTabWidth = this.config.minTabWidth || 40;
38258 ts.maxTabWidth = this.config.maxTabWidth || 250;
38259 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
38260 ts.monitorResize = false;
38261 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
38262 ts.bodyEl.addClass('roo-layout-tabs-body');
38263 this.panels.each(this.initPanelAsTab, this);
38266 initPanelAsTab : function(panel){
38267 var ti = this.tabs.addTab(
38271 this.config.closeOnTab && panel.isClosable(),
38274 if(panel.tabTip !== undefined){
38275 ti.setTooltip(panel.tabTip);
38277 ti.on("activate", function(){
38278 this.setActivePanel(panel);
38281 if(this.config.closeOnTab){
38282 ti.on("beforeclose", function(t, e){
38284 this.remove(panel);
38288 panel.tabItem = ti;
38293 updatePanelTitle : function(panel, title)
38295 if(this.activePanel == panel){
38296 this.updateTitle(title);
38299 var ti = this.tabs.getTab(panel.getEl().id);
38301 if(panel.tabTip !== undefined){
38302 ti.setTooltip(panel.tabTip);
38307 updateTitle : function(title){
38308 if(this.titleTextEl && !this.config.title){
38309 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
38313 setActivePanel : function(panel)
38315 panel = this.getPanel(panel);
38316 if(this.activePanel && this.activePanel != panel){
38317 if(this.activePanel.setActiveState(false) === false){
38321 this.activePanel = panel;
38322 panel.setActiveState(true);
38323 if(this.panelSize){
38324 panel.setSize(this.panelSize.width, this.panelSize.height);
38327 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
38329 this.updateTitle(panel.getTitle());
38331 this.fireEvent("invalidated", this);
38333 this.fireEvent("panelactivated", this, panel);
38337 * Shows the specified panel.
38338 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
38339 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
38341 showPanel : function(panel)
38343 panel = this.getPanel(panel);
38346 var tab = this.tabs.getTab(panel.getEl().id);
38347 if(tab.isHidden()){
38348 this.tabs.unhideTab(tab.id);
38352 this.setActivePanel(panel);
38359 * Get the active panel for this region.
38360 * @return {Roo.ContentPanel} The active panel or null
38362 getActivePanel : function(){
38363 return this.activePanel;
38366 validateVisibility : function(){
38367 if(this.panels.getCount() < 1){
38368 this.updateTitle(" ");
38369 this.closeBtn.hide();
38372 if(!this.isVisible()){
38379 * Adds the passed ContentPanel(s) to this region.
38380 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
38381 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
38383 add : function(panel)
38385 if(arguments.length > 1){
38386 for(var i = 0, len = arguments.length; i < len; i++) {
38387 this.add(arguments[i]);
38392 // if we have not been rendered yet, then we can not really do much of this..
38393 if (!this.bodyEl) {
38394 this.unrendered_panels.push(panel);
38401 if(this.hasPanel(panel)){
38402 this.showPanel(panel);
38405 panel.setRegion(this);
38406 this.panels.add(panel);
38407 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
38408 // sinle panel - no tab...?? would it not be better to render it with the tabs,
38409 // and hide them... ???
38410 this.bodyEl.dom.appendChild(panel.getEl().dom);
38411 if(panel.background !== true){
38412 this.setActivePanel(panel);
38414 this.fireEvent("paneladded", this, panel);
38421 this.initPanelAsTab(panel);
38425 if(panel.background !== true){
38426 this.tabs.activate(panel.getEl().id);
38428 this.fireEvent("paneladded", this, panel);
38433 * Hides the tab for the specified panel.
38434 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
38436 hidePanel : function(panel){
38437 if(this.tabs && (panel = this.getPanel(panel))){
38438 this.tabs.hideTab(panel.getEl().id);
38443 * Unhides the tab for a previously hidden panel.
38444 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
38446 unhidePanel : function(panel){
38447 if(this.tabs && (panel = this.getPanel(panel))){
38448 this.tabs.unhideTab(panel.getEl().id);
38452 clearPanels : function(){
38453 while(this.panels.getCount() > 0){
38454 this.remove(this.panels.first());
38459 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
38460 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
38461 * @param {Boolean} preservePanel Overrides the config preservePanel option
38462 * @return {Roo.ContentPanel} The panel that was removed
38464 remove : function(panel, preservePanel)
38466 panel = this.getPanel(panel);
38471 this.fireEvent("beforeremove", this, panel, e);
38472 if(e.cancel === true){
38475 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
38476 var panelId = panel.getId();
38477 this.panels.removeKey(panelId);
38479 document.body.appendChild(panel.getEl().dom);
38482 this.tabs.removeTab(panel.getEl().id);
38483 }else if (!preservePanel){
38484 this.bodyEl.dom.removeChild(panel.getEl().dom);
38486 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
38487 var p = this.panels.first();
38488 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
38489 tempEl.appendChild(p.getEl().dom);
38490 this.bodyEl.update("");
38491 this.bodyEl.dom.appendChild(p.getEl().dom);
38493 this.updateTitle(p.getTitle());
38495 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
38496 this.setActivePanel(p);
38498 panel.setRegion(null);
38499 if(this.activePanel == panel){
38500 this.activePanel = null;
38502 if(this.config.autoDestroy !== false && preservePanel !== true){
38503 try{panel.destroy();}catch(e){}
38505 this.fireEvent("panelremoved", this, panel);
38510 * Returns the TabPanel component used by this region
38511 * @return {Roo.TabPanel}
38513 getTabs : function(){
38517 createTool : function(parentEl, className){
38518 var btn = Roo.DomHelper.append(parentEl, {
38520 cls: "x-layout-tools-button",
38523 cls: "roo-layout-tools-button-inner " + className,
38527 btn.addClassOnOver("roo-layout-tools-button-over");
38532 * Ext JS Library 1.1.1
38533 * Copyright(c) 2006-2007, Ext JS, LLC.
38535 * Originally Released Under LGPL - original licence link has changed is not relivant.
38538 * <script type="text/javascript">
38544 * @class Roo.SplitLayoutRegion
38545 * @extends Roo.LayoutRegion
38546 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
38548 Roo.bootstrap.layout.Split = function(config){
38549 this.cursor = config.cursor;
38550 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
38553 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
38555 splitTip : "Drag to resize.",
38556 collapsibleSplitTip : "Drag to resize. Double click to hide.",
38557 useSplitTips : false,
38559 applyConfig : function(config){
38560 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
38563 onRender : function(ctr,pos) {
38565 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
38566 if(!this.config.split){
38571 var splitEl = Roo.DomHelper.append(ctr.dom, {
38573 id: this.el.id + "-split",
38574 cls: "roo-layout-split roo-layout-split-"+this.position,
38577 /** The SplitBar for this region
38578 * @type Roo.SplitBar */
38579 // does not exist yet...
38580 Roo.log([this.position, this.orientation]);
38582 this.split = new Roo.bootstrap.SplitBar({
38583 dragElement : splitEl,
38584 resizingElement: this.el,
38585 orientation : this.orientation
38588 this.split.on("moved", this.onSplitMove, this);
38589 this.split.useShim = this.config.useShim === true;
38590 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
38591 if(this.useSplitTips){
38592 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
38594 //if(config.collapsible){
38595 // this.split.el.on("dblclick", this.collapse, this);
38598 if(typeof this.config.minSize != "undefined"){
38599 this.split.minSize = this.config.minSize;
38601 if(typeof this.config.maxSize != "undefined"){
38602 this.split.maxSize = this.config.maxSize;
38604 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
38605 this.hideSplitter();
38610 getHMaxSize : function(){
38611 var cmax = this.config.maxSize || 10000;
38612 var center = this.mgr.getRegion("center");
38613 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
38616 getVMaxSize : function(){
38617 var cmax = this.config.maxSize || 10000;
38618 var center = this.mgr.getRegion("center");
38619 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
38622 onSplitMove : function(split, newSize){
38623 this.fireEvent("resized", this, newSize);
38627 * Returns the {@link Roo.SplitBar} for this region.
38628 * @return {Roo.SplitBar}
38630 getSplitBar : function(){
38635 this.hideSplitter();
38636 Roo.bootstrap.layout.Split.superclass.hide.call(this);
38639 hideSplitter : function(){
38641 this.split.el.setLocation(-2000,-2000);
38642 this.split.el.hide();
38648 this.split.el.show();
38650 Roo.bootstrap.layout.Split.superclass.show.call(this);
38653 beforeSlide: function(){
38654 if(Roo.isGecko){// firefox overflow auto bug workaround
38655 this.bodyEl.clip();
38657 this.tabs.bodyEl.clip();
38659 if(this.activePanel){
38660 this.activePanel.getEl().clip();
38662 if(this.activePanel.beforeSlide){
38663 this.activePanel.beforeSlide();
38669 afterSlide : function(){
38670 if(Roo.isGecko){// firefox overflow auto bug workaround
38671 this.bodyEl.unclip();
38673 this.tabs.bodyEl.unclip();
38675 if(this.activePanel){
38676 this.activePanel.getEl().unclip();
38677 if(this.activePanel.afterSlide){
38678 this.activePanel.afterSlide();
38684 initAutoHide : function(){
38685 if(this.autoHide !== false){
38686 if(!this.autoHideHd){
38687 var st = new Roo.util.DelayedTask(this.slideIn, this);
38688 this.autoHideHd = {
38689 "mouseout": function(e){
38690 if(!e.within(this.el, true)){
38694 "mouseover" : function(e){
38700 this.el.on(this.autoHideHd);
38704 clearAutoHide : function(){
38705 if(this.autoHide !== false){
38706 this.el.un("mouseout", this.autoHideHd.mouseout);
38707 this.el.un("mouseover", this.autoHideHd.mouseover);
38711 clearMonitor : function(){
38712 Roo.get(document).un("click", this.slideInIf, this);
38715 // these names are backwards but not changed for compat
38716 slideOut : function(){
38717 if(this.isSlid || this.el.hasActiveFx()){
38720 this.isSlid = true;
38721 if(this.collapseBtn){
38722 this.collapseBtn.hide();
38724 this.closeBtnState = this.closeBtn.getStyle('display');
38725 this.closeBtn.hide();
38727 this.stickBtn.show();
38730 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
38731 this.beforeSlide();
38732 this.el.setStyle("z-index", 10001);
38733 this.el.slideIn(this.getSlideAnchor(), {
38734 callback: function(){
38736 this.initAutoHide();
38737 Roo.get(document).on("click", this.slideInIf, this);
38738 this.fireEvent("slideshow", this);
38745 afterSlideIn : function(){
38746 this.clearAutoHide();
38747 this.isSlid = false;
38748 this.clearMonitor();
38749 this.el.setStyle("z-index", "");
38750 if(this.collapseBtn){
38751 this.collapseBtn.show();
38753 this.closeBtn.setStyle('display', this.closeBtnState);
38755 this.stickBtn.hide();
38757 this.fireEvent("slidehide", this);
38760 slideIn : function(cb){
38761 if(!this.isSlid || this.el.hasActiveFx()){
38765 this.isSlid = false;
38766 this.beforeSlide();
38767 this.el.slideOut(this.getSlideAnchor(), {
38768 callback: function(){
38769 this.el.setLeftTop(-10000, -10000);
38771 this.afterSlideIn();
38779 slideInIf : function(e){
38780 if(!e.within(this.el)){
38785 animateCollapse : function(){
38786 this.beforeSlide();
38787 this.el.setStyle("z-index", 20000);
38788 var anchor = this.getSlideAnchor();
38789 this.el.slideOut(anchor, {
38790 callback : function(){
38791 this.el.setStyle("z-index", "");
38792 this.collapsedEl.slideIn(anchor, {duration:.3});
38794 this.el.setLocation(-10000,-10000);
38796 this.fireEvent("collapsed", this);
38803 animateExpand : function(){
38804 this.beforeSlide();
38805 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
38806 this.el.setStyle("z-index", 20000);
38807 this.collapsedEl.hide({
38810 this.el.slideIn(this.getSlideAnchor(), {
38811 callback : function(){
38812 this.el.setStyle("z-index", "");
38815 this.split.el.show();
38817 this.fireEvent("invalidated", this);
38818 this.fireEvent("expanded", this);
38846 getAnchor : function(){
38847 return this.anchors[this.position];
38850 getCollapseAnchor : function(){
38851 return this.canchors[this.position];
38854 getSlideAnchor : function(){
38855 return this.sanchors[this.position];
38858 getAlignAdj : function(){
38859 var cm = this.cmargins;
38860 switch(this.position){
38876 getExpandAdj : function(){
38877 var c = this.collapsedEl, cm = this.cmargins;
38878 switch(this.position){
38880 return [-(cm.right+c.getWidth()+cm.left), 0];
38883 return [cm.right+c.getWidth()+cm.left, 0];
38886 return [0, -(cm.top+cm.bottom+c.getHeight())];
38889 return [0, cm.top+cm.bottom+c.getHeight()];
38895 * Ext JS Library 1.1.1
38896 * Copyright(c) 2006-2007, Ext JS, LLC.
38898 * Originally Released Under LGPL - original licence link has changed is not relivant.
38901 * <script type="text/javascript">
38904 * These classes are private internal classes
38906 Roo.bootstrap.layout.Center = function(config){
38907 config.region = "center";
38908 Roo.bootstrap.layout.Region.call(this, config);
38909 this.visible = true;
38910 this.minWidth = config.minWidth || 20;
38911 this.minHeight = config.minHeight || 20;
38914 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
38916 // center panel can't be hidden
38920 // center panel can't be hidden
38923 getMinWidth: function(){
38924 return this.minWidth;
38927 getMinHeight: function(){
38928 return this.minHeight;
38942 Roo.bootstrap.layout.North = function(config)
38944 config.region = 'north';
38945 config.cursor = 'n-resize';
38947 Roo.bootstrap.layout.Split.call(this, config);
38951 this.split.placement = Roo.bootstrap.SplitBar.TOP;
38952 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
38953 this.split.el.addClass("roo-layout-split-v");
38955 var size = config.initialSize || config.height;
38956 if(typeof size != "undefined"){
38957 this.el.setHeight(size);
38960 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
38962 orientation: Roo.bootstrap.SplitBar.VERTICAL,
38966 getBox : function(){
38967 if(this.collapsed){
38968 return this.collapsedEl.getBox();
38970 var box = this.el.getBox();
38972 box.height += this.split.el.getHeight();
38977 updateBox : function(box){
38978 if(this.split && !this.collapsed){
38979 box.height -= this.split.el.getHeight();
38980 this.split.el.setLeft(box.x);
38981 this.split.el.setTop(box.y+box.height);
38982 this.split.el.setWidth(box.width);
38984 if(this.collapsed){
38985 this.updateBody(box.width, null);
38987 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
38995 Roo.bootstrap.layout.South = function(config){
38996 config.region = 'south';
38997 config.cursor = 's-resize';
38998 Roo.bootstrap.layout.Split.call(this, config);
39000 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
39001 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
39002 this.split.el.addClass("roo-layout-split-v");
39004 var size = config.initialSize || config.height;
39005 if(typeof size != "undefined"){
39006 this.el.setHeight(size);
39010 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
39011 orientation: Roo.bootstrap.SplitBar.VERTICAL,
39012 getBox : function(){
39013 if(this.collapsed){
39014 return this.collapsedEl.getBox();
39016 var box = this.el.getBox();
39018 var sh = this.split.el.getHeight();
39025 updateBox : function(box){
39026 if(this.split && !this.collapsed){
39027 var sh = this.split.el.getHeight();
39030 this.split.el.setLeft(box.x);
39031 this.split.el.setTop(box.y-sh);
39032 this.split.el.setWidth(box.width);
39034 if(this.collapsed){
39035 this.updateBody(box.width, null);
39037 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
39041 Roo.bootstrap.layout.East = function(config){
39042 config.region = "east";
39043 config.cursor = "e-resize";
39044 Roo.bootstrap.layout.Split.call(this, config);
39046 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
39047 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
39048 this.split.el.addClass("roo-layout-split-h");
39050 var size = config.initialSize || config.width;
39051 if(typeof size != "undefined"){
39052 this.el.setWidth(size);
39055 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
39056 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
39057 getBox : function(){
39058 if(this.collapsed){
39059 return this.collapsedEl.getBox();
39061 var box = this.el.getBox();
39063 var sw = this.split.el.getWidth();
39070 updateBox : function(box){
39071 if(this.split && !this.collapsed){
39072 var sw = this.split.el.getWidth();
39074 this.split.el.setLeft(box.x);
39075 this.split.el.setTop(box.y);
39076 this.split.el.setHeight(box.height);
39079 if(this.collapsed){
39080 this.updateBody(null, box.height);
39082 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
39086 Roo.bootstrap.layout.West = function(config){
39087 config.region = "west";
39088 config.cursor = "w-resize";
39090 Roo.bootstrap.layout.Split.call(this, config);
39092 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
39093 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
39094 this.split.el.addClass("roo-layout-split-h");
39098 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
39099 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
39101 onRender: function(ctr, pos)
39103 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
39104 var size = this.config.initialSize || this.config.width;
39105 if(typeof size != "undefined"){
39106 this.el.setWidth(size);
39110 getBox : function(){
39111 if(this.collapsed){
39112 return this.collapsedEl.getBox();
39114 var box = this.el.getBox();
39116 box.width += this.split.el.getWidth();
39121 updateBox : function(box){
39122 if(this.split && !this.collapsed){
39123 var sw = this.split.el.getWidth();
39125 this.split.el.setLeft(box.x+box.width);
39126 this.split.el.setTop(box.y);
39127 this.split.el.setHeight(box.height);
39129 if(this.collapsed){
39130 this.updateBody(null, box.height);
39132 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
39134 });Roo.namespace("Roo.bootstrap.panel");/*
39136 * Ext JS Library 1.1.1
39137 * Copyright(c) 2006-2007, Ext JS, LLC.
39139 * Originally Released Under LGPL - original licence link has changed is not relivant.
39142 * <script type="text/javascript">
39145 * @class Roo.ContentPanel
39146 * @extends Roo.util.Observable
39147 * A basic ContentPanel element.
39148 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
39149 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
39150 * @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
39151 * @cfg {Boolean} closable True if the panel can be closed/removed
39152 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
39153 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
39154 * @cfg {Toolbar} toolbar A toolbar for this panel
39155 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
39156 * @cfg {String} title The title for this panel
39157 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
39158 * @cfg {String} url Calls {@link #setUrl} with this value
39159 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
39160 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
39161 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
39162 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
39163 * @cfg {Boolean} badges render the badges
39164 * @cfg {String} cls extra classes to use
39165 * @cfg {String} background (primary|secondary|success|info|warning|danger|light|dark)
39168 * Create a new ContentPanel.
39169 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
39170 * @param {String/Object} config A string to set only the title or a config object
39171 * @param {String} content (optional) Set the HTML content for this panel
39172 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
39174 Roo.bootstrap.panel.Content = function( config){
39176 this.tpl = config.tpl || false;
39178 var el = config.el;
39179 var content = config.content;
39181 if(config.autoCreate){ // xtype is available if this is called from factory
39184 this.el = Roo.get(el);
39185 if(!this.el && config && config.autoCreate){
39186 if(typeof config.autoCreate == "object"){
39187 if(!config.autoCreate.id){
39188 config.autoCreate.id = config.id||el;
39190 this.el = Roo.DomHelper.append(document.body,
39191 config.autoCreate, true);
39195 cls: (config.cls || '') +
39196 (config.background ? ' bg-' + config.background : '') +
39197 " roo-layout-inactive-content",
39201 elcfg.html = config.html;
39205 this.el = Roo.DomHelper.append(document.body, elcfg , true);
39208 this.closable = false;
39209 this.loaded = false;
39210 this.active = false;
39213 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
39215 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
39217 this.wrapEl = this.el; //this.el.wrap();
39219 if (config.toolbar.items) {
39220 ti = config.toolbar.items ;
39221 delete config.toolbar.items ;
39225 this.toolbar.render(this.wrapEl, 'before');
39226 for(var i =0;i < ti.length;i++) {
39227 // Roo.log(['add child', items[i]]);
39228 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
39230 this.toolbar.items = nitems;
39231 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
39232 delete config.toolbar;
39236 // xtype created footer. - not sure if will work as we normally have to render first..
39237 if (this.footer && !this.footer.el && this.footer.xtype) {
39238 if (!this.wrapEl) {
39239 this.wrapEl = this.el.wrap();
39242 this.footer.container = this.wrapEl.createChild();
39244 this.footer = Roo.factory(this.footer, Roo);
39249 if(typeof config == "string"){
39250 this.title = config;
39252 Roo.apply(this, config);
39256 this.resizeEl = Roo.get(this.resizeEl, true);
39258 this.resizeEl = this.el;
39260 // handle view.xtype
39268 * Fires when this panel is activated.
39269 * @param {Roo.ContentPanel} this
39273 * @event deactivate
39274 * Fires when this panel is activated.
39275 * @param {Roo.ContentPanel} this
39277 "deactivate" : true,
39281 * Fires when this panel is resized if fitToFrame is true.
39282 * @param {Roo.ContentPanel} this
39283 * @param {Number} width The width after any component adjustments
39284 * @param {Number} height The height after any component adjustments
39290 * Fires when this tab is created
39291 * @param {Roo.ContentPanel} this
39302 if(this.autoScroll){
39303 this.resizeEl.setStyle("overflow", "auto");
39305 // fix randome scrolling
39306 //this.el.on('scroll', function() {
39307 // Roo.log('fix random scolling');
39308 // this.scrollTo('top',0);
39311 content = content || this.content;
39313 this.setContent(content);
39315 if(config && config.url){
39316 this.setUrl(this.url, this.params, this.loadOnce);
39321 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
39323 if (this.view && typeof(this.view.xtype) != 'undefined') {
39324 this.view.el = this.el.appendChild(document.createElement("div"));
39325 this.view = Roo.factory(this.view);
39326 this.view.render && this.view.render(false, '');
39330 this.fireEvent('render', this);
39333 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
39340 setRegion : function(region){
39341 this.region = region;
39342 this.setActiveClass(region && !this.background);
39346 setActiveClass: function(state)
39349 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
39350 this.el.setStyle('position','relative');
39352 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
39353 this.el.setStyle('position', 'absolute');
39358 * Returns the toolbar for this Panel if one was configured.
39359 * @return {Roo.Toolbar}
39361 getToolbar : function(){
39362 return this.toolbar;
39365 setActiveState : function(active)
39367 this.active = active;
39368 this.setActiveClass(active);
39370 if(this.fireEvent("deactivate", this) === false){
39375 this.fireEvent("activate", this);
39379 * Updates this panel's element
39380 * @param {String} content The new content
39381 * @param {Boolean} loadScripts (optional) true to look for and process scripts
39383 setContent : function(content, loadScripts){
39384 this.el.update(content, loadScripts);
39387 ignoreResize : function(w, h){
39388 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
39391 this.lastSize = {width: w, height: h};
39396 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
39397 * @return {Roo.UpdateManager} The UpdateManager
39399 getUpdateManager : function(){
39400 return this.el.getUpdateManager();
39403 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
39404 * @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:
39407 url: "your-url.php",
39408 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
39409 callback: yourFunction,
39410 scope: yourObject, //(optional scope)
39413 text: "Loading...",
39418 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
39419 * 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.
39420 * @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}
39421 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
39422 * @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.
39423 * @return {Roo.ContentPanel} this
39426 var um = this.el.getUpdateManager();
39427 um.update.apply(um, arguments);
39433 * 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.
39434 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
39435 * @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)
39436 * @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)
39437 * @return {Roo.UpdateManager} The UpdateManager
39439 setUrl : function(url, params, loadOnce){
39440 if(this.refreshDelegate){
39441 this.removeListener("activate", this.refreshDelegate);
39443 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
39444 this.on("activate", this.refreshDelegate);
39445 return this.el.getUpdateManager();
39448 _handleRefresh : function(url, params, loadOnce){
39449 if(!loadOnce || !this.loaded){
39450 var updater = this.el.getUpdateManager();
39451 updater.update(url, params, this._setLoaded.createDelegate(this));
39455 _setLoaded : function(){
39456 this.loaded = true;
39460 * Returns this panel's id
39463 getId : function(){
39468 * Returns this panel's element - used by regiosn to add.
39469 * @return {Roo.Element}
39471 getEl : function(){
39472 return this.wrapEl || this.el;
39477 adjustForComponents : function(width, height)
39479 //Roo.log('adjustForComponents ');
39480 if(this.resizeEl != this.el){
39481 width -= this.el.getFrameWidth('lr');
39482 height -= this.el.getFrameWidth('tb');
39485 var te = this.toolbar.getEl();
39486 te.setWidth(width);
39487 height -= te.getHeight();
39490 var te = this.footer.getEl();
39491 te.setWidth(width);
39492 height -= te.getHeight();
39496 if(this.adjustments){
39497 width += this.adjustments[0];
39498 height += this.adjustments[1];
39500 return {"width": width, "height": height};
39503 setSize : function(width, height){
39504 if(this.fitToFrame && !this.ignoreResize(width, height)){
39505 if(this.fitContainer && this.resizeEl != this.el){
39506 this.el.setSize(width, height);
39508 var size = this.adjustForComponents(width, height);
39509 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
39510 this.fireEvent('resize', this, size.width, size.height);
39515 * Returns this panel's title
39518 getTitle : function(){
39520 if (typeof(this.title) != 'object') {
39525 for (var k in this.title) {
39526 if (!this.title.hasOwnProperty(k)) {
39530 if (k.indexOf('-') >= 0) {
39531 var s = k.split('-');
39532 for (var i = 0; i<s.length; i++) {
39533 t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
39536 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
39543 * Set this panel's title
39544 * @param {String} title
39546 setTitle : function(title){
39547 this.title = title;
39549 this.region.updatePanelTitle(this, title);
39554 * Returns true is this panel was configured to be closable
39555 * @return {Boolean}
39557 isClosable : function(){
39558 return this.closable;
39561 beforeSlide : function(){
39563 this.resizeEl.clip();
39566 afterSlide : function(){
39568 this.resizeEl.unclip();
39572 * Force a content refresh from the URL specified in the {@link #setUrl} method.
39573 * Will fail silently if the {@link #setUrl} method has not been called.
39574 * This does not activate the panel, just updates its content.
39576 refresh : function(){
39577 if(this.refreshDelegate){
39578 this.loaded = false;
39579 this.refreshDelegate();
39584 * Destroys this panel
39586 destroy : function(){
39587 this.el.removeAllListeners();
39588 var tempEl = document.createElement("span");
39589 tempEl.appendChild(this.el.dom);
39590 tempEl.innerHTML = "";
39596 * form - if the content panel contains a form - this is a reference to it.
39597 * @type {Roo.form.Form}
39601 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
39602 * This contains a reference to it.
39608 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
39618 * @param {Object} cfg Xtype definition of item to add.
39622 getChildContainer: function () {
39623 return this.getEl();
39628 var ret = new Roo.factory(cfg);
39633 if (cfg.xtype.match(/^Form$/)) {
39636 //if (this.footer) {
39637 // el = this.footer.container.insertSibling(false, 'before');
39639 el = this.el.createChild();
39642 this.form = new Roo.form.Form(cfg);
39645 if ( this.form.allItems.length) {
39646 this.form.render(el.dom);
39650 // should only have one of theses..
39651 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
39652 // views.. should not be just added - used named prop 'view''
39654 cfg.el = this.el.appendChild(document.createElement("div"));
39657 var ret = new Roo.factory(cfg);
39659 ret.render && ret.render(false, ''); // render blank..
39669 * @class Roo.bootstrap.panel.Grid
39670 * @extends Roo.bootstrap.panel.Content
39672 * Create a new GridPanel.
39673 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
39674 * @param {Object} config A the config object
39680 Roo.bootstrap.panel.Grid = function(config)
39684 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
39685 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
39687 config.el = this.wrapper;
39688 //this.el = this.wrapper;
39690 if (config.container) {
39691 // ctor'ed from a Border/panel.grid
39694 this.wrapper.setStyle("overflow", "hidden");
39695 this.wrapper.addClass('roo-grid-container');
39700 if(config.toolbar){
39701 var tool_el = this.wrapper.createChild();
39702 this.toolbar = Roo.factory(config.toolbar);
39704 if (config.toolbar.items) {
39705 ti = config.toolbar.items ;
39706 delete config.toolbar.items ;
39710 this.toolbar.render(tool_el);
39711 for(var i =0;i < ti.length;i++) {
39712 // Roo.log(['add child', items[i]]);
39713 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
39715 this.toolbar.items = nitems;
39717 delete config.toolbar;
39720 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
39721 config.grid.scrollBody = true;;
39722 config.grid.monitorWindowResize = false; // turn off autosizing
39723 config.grid.autoHeight = false;
39724 config.grid.autoWidth = false;
39726 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
39728 if (config.background) {
39729 // render grid on panel activation (if panel background)
39730 this.on('activate', function(gp) {
39731 if (!gp.grid.rendered) {
39732 gp.grid.render(this.wrapper);
39733 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
39738 this.grid.render(this.wrapper);
39739 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
39742 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
39743 // ??? needed ??? config.el = this.wrapper;
39748 // xtype created footer. - not sure if will work as we normally have to render first..
39749 if (this.footer && !this.footer.el && this.footer.xtype) {
39751 var ctr = this.grid.getView().getFooterPanel(true);
39752 this.footer.dataSource = this.grid.dataSource;
39753 this.footer = Roo.factory(this.footer, Roo);
39754 this.footer.render(ctr);
39764 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
39765 getId : function(){
39766 return this.grid.id;
39770 * Returns the grid for this panel
39771 * @return {Roo.bootstrap.Table}
39773 getGrid : function(){
39777 setSize : function(width, height){
39778 if(!this.ignoreResize(width, height)){
39779 var grid = this.grid;
39780 var size = this.adjustForComponents(width, height);
39781 // tfoot is not a footer?
39784 var gridel = grid.getGridEl();
39785 gridel.setSize(size.width, size.height);
39787 var tbd = grid.getGridEl().select('tbody', true).first();
39788 var thd = grid.getGridEl().select('thead',true).first();
39789 var tbf= grid.getGridEl().select('tfoot', true).first();
39792 size.height -= thd.getHeight();
39795 size.height -= thd.getHeight();
39798 tbd.setSize(size.width, size.height );
39799 // this is for the account management tab -seems to work there.
39800 var thd = grid.getGridEl().select('thead',true).first();
39802 // tbd.setSize(size.width, size.height - thd.getHeight());
39811 beforeSlide : function(){
39812 this.grid.getView().scroller.clip();
39815 afterSlide : function(){
39816 this.grid.getView().scroller.unclip();
39819 destroy : function(){
39820 this.grid.destroy();
39822 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
39827 * @class Roo.bootstrap.panel.Nest
39828 * @extends Roo.bootstrap.panel.Content
39830 * Create a new Panel, that can contain a layout.Border.
39833 * @param {Roo.BorderLayout} layout The layout for this panel
39834 * @param {String/Object} config A string to set only the title or a config object
39836 Roo.bootstrap.panel.Nest = function(config)
39838 // construct with only one argument..
39839 /* FIXME - implement nicer consturctors
39840 if (layout.layout) {
39842 layout = config.layout;
39843 delete config.layout;
39845 if (layout.xtype && !layout.getEl) {
39846 // then layout needs constructing..
39847 layout = Roo.factory(layout, Roo);
39851 config.el = config.layout.getEl();
39853 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
39855 config.layout.monitorWindowResize = false; // turn off autosizing
39856 this.layout = config.layout;
39857 this.layout.getEl().addClass("roo-layout-nested-layout");
39858 this.layout.parent = this;
39865 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
39867 setSize : function(width, height){
39868 if(!this.ignoreResize(width, height)){
39869 var size = this.adjustForComponents(width, height);
39870 var el = this.layout.getEl();
39871 if (size.height < 1) {
39872 el.setWidth(size.width);
39874 el.setSize(size.width, size.height);
39876 var touch = el.dom.offsetWidth;
39877 this.layout.layout();
39878 // ie requires a double layout on the first pass
39879 if(Roo.isIE && !this.initialized){
39880 this.initialized = true;
39881 this.layout.layout();
39886 // activate all subpanels if not currently active..
39888 setActiveState : function(active){
39889 this.active = active;
39890 this.setActiveClass(active);
39893 this.fireEvent("deactivate", this);
39897 this.fireEvent("activate", this);
39898 // not sure if this should happen before or after..
39899 if (!this.layout) {
39900 return; // should not happen..
39903 for (var r in this.layout.regions) {
39904 reg = this.layout.getRegion(r);
39905 if (reg.getActivePanel()) {
39906 //reg.showPanel(reg.getActivePanel()); // force it to activate..
39907 reg.setActivePanel(reg.getActivePanel());
39910 if (!reg.panels.length) {
39913 reg.showPanel(reg.getPanel(0));
39922 * Returns the nested BorderLayout for this panel
39923 * @return {Roo.BorderLayout}
39925 getLayout : function(){
39926 return this.layout;
39930 * Adds a xtype elements to the layout of the nested panel
39934 xtype : 'ContentPanel',
39941 xtype : 'NestedLayoutPanel',
39947 items : [ ... list of content panels or nested layout panels.. ]
39951 * @param {Object} cfg Xtype definition of item to add.
39953 addxtype : function(cfg) {
39954 return this.layout.addxtype(cfg);
39959 * Ext JS Library 1.1.1
39960 * Copyright(c) 2006-2007, Ext JS, LLC.
39962 * Originally Released Under LGPL - original licence link has changed is not relivant.
39965 * <script type="text/javascript">
39968 * @class Roo.TabPanel
39969 * @extends Roo.util.Observable
39970 * A lightweight tab container.
39974 // basic tabs 1, built from existing content
39975 var tabs = new Roo.TabPanel("tabs1");
39976 tabs.addTab("script", "View Script");
39977 tabs.addTab("markup", "View Markup");
39978 tabs.activate("script");
39980 // more advanced tabs, built from javascript
39981 var jtabs = new Roo.TabPanel("jtabs");
39982 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
39984 // set up the UpdateManager
39985 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
39986 var updater = tab2.getUpdateManager();
39987 updater.setDefaultUrl("ajax1.htm");
39988 tab2.on('activate', updater.refresh, updater, true);
39990 // Use setUrl for Ajax loading
39991 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
39992 tab3.setUrl("ajax2.htm", null, true);
39995 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
39998 jtabs.activate("jtabs-1");
40001 * Create a new TabPanel.
40002 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
40003 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
40005 Roo.bootstrap.panel.Tabs = function(config){
40007 * The container element for this TabPanel.
40008 * @type Roo.Element
40010 this.el = Roo.get(config.el);
40013 if(typeof config == "boolean"){
40014 this.tabPosition = config ? "bottom" : "top";
40016 Roo.apply(this, config);
40020 if(this.tabPosition == "bottom"){
40021 // if tabs are at the bottom = create the body first.
40022 this.bodyEl = Roo.get(this.createBody(this.el.dom));
40023 this.el.addClass("roo-tabs-bottom");
40025 // next create the tabs holders
40027 if (this.tabPosition == "west"){
40029 var reg = this.region; // fake it..
40031 if (!reg.mgr.parent) {
40034 reg = reg.mgr.parent.region;
40036 Roo.log("got nest?");
40038 if (reg.mgr.getRegion('west')) {
40039 var ctrdom = reg.mgr.getRegion('west').bodyEl.dom;
40040 this.stripWrap = Roo.get(this.createStrip(ctrdom ), true);
40041 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
40042 this.stripEl.setVisibilityMode(Roo.Element.DISPLAY);
40043 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
40051 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
40052 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
40053 this.stripEl.setVisibilityMode(Roo.Element.DISPLAY);
40054 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
40059 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
40062 // finally - if tabs are at the top, then create the body last..
40063 if(this.tabPosition != "bottom"){
40064 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
40065 * @type Roo.Element
40067 this.bodyEl = Roo.get(this.createBody(this.el.dom));
40068 this.el.addClass("roo-tabs-top");
40072 this.bodyEl.setStyle("position", "relative");
40074 this.active = null;
40075 this.activateDelegate = this.activate.createDelegate(this);
40080 * Fires when the active tab changes
40081 * @param {Roo.TabPanel} this
40082 * @param {Roo.TabPanelItem} activePanel The new active tab
40086 * @event beforetabchange
40087 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
40088 * @param {Roo.TabPanel} this
40089 * @param {Object} e Set cancel to true on this object to cancel the tab change
40090 * @param {Roo.TabPanelItem} tab The tab being changed to
40092 "beforetabchange" : true
40095 Roo.EventManager.onWindowResize(this.onResize, this);
40096 this.cpad = this.el.getPadding("lr");
40097 this.hiddenCount = 0;
40100 // toolbar on the tabbar support...
40101 if (this.toolbar) {
40102 alert("no toolbar support yet");
40103 this.toolbar = false;
40105 var tcfg = this.toolbar;
40106 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
40107 this.toolbar = new Roo.Toolbar(tcfg);
40108 if (Roo.isSafari) {
40109 var tbl = tcfg.container.child('table', true);
40110 tbl.setAttribute('width', '100%');
40118 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
40121 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
40123 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
40125 tabPosition : "top",
40127 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
40129 currentTabWidth : 0,
40131 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
40135 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
40139 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
40141 preferredTabWidth : 175,
40143 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
40145 resizeTabs : false,
40147 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
40149 monitorResize : true,
40151 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
40153 toolbar : false, // set by caller..
40155 region : false, /// set by caller
40157 disableTooltips : true, // not used yet...
40160 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
40161 * @param {String} id The id of the div to use <b>or create</b>
40162 * @param {String} text The text for the tab
40163 * @param {String} content (optional) Content to put in the TabPanelItem body
40164 * @param {Boolean} closable (optional) True to create a close icon on the tab
40165 * @return {Roo.TabPanelItem} The created TabPanelItem
40167 addTab : function(id, text, content, closable, tpl)
40169 var item = new Roo.bootstrap.panel.TabItem({
40173 closable : closable,
40176 this.addTabItem(item);
40178 item.setContent(content);
40184 * Returns the {@link Roo.TabPanelItem} with the specified id/index
40185 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
40186 * @return {Roo.TabPanelItem}
40188 getTab : function(id){
40189 return this.items[id];
40193 * Hides the {@link Roo.TabPanelItem} with the specified id/index
40194 * @param {String/Number} id The id or index of the TabPanelItem to hide.
40196 hideTab : function(id){
40197 var t = this.items[id];
40200 this.hiddenCount++;
40201 this.autoSizeTabs();
40206 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
40207 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
40209 unhideTab : function(id){
40210 var t = this.items[id];
40212 t.setHidden(false);
40213 this.hiddenCount--;
40214 this.autoSizeTabs();
40219 * Adds an existing {@link Roo.TabPanelItem}.
40220 * @param {Roo.TabPanelItem} item The TabPanelItem to add
40222 addTabItem : function(item)
40224 this.items[item.id] = item;
40225 this.items.push(item);
40226 this.autoSizeTabs();
40227 // if(this.resizeTabs){
40228 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
40229 // this.autoSizeTabs();
40231 // item.autoSize();
40236 * Removes a {@link Roo.TabPanelItem}.
40237 * @param {String/Number} id The id or index of the TabPanelItem to remove.
40239 removeTab : function(id){
40240 var items = this.items;
40241 var tab = items[id];
40242 if(!tab) { return; }
40243 var index = items.indexOf(tab);
40244 if(this.active == tab && items.length > 1){
40245 var newTab = this.getNextAvailable(index);
40250 this.stripEl.dom.removeChild(tab.pnode.dom);
40251 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
40252 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
40254 items.splice(index, 1);
40255 delete this.items[tab.id];
40256 tab.fireEvent("close", tab);
40257 tab.purgeListeners();
40258 this.autoSizeTabs();
40261 getNextAvailable : function(start){
40262 var items = this.items;
40264 // look for a next tab that will slide over to
40265 // replace the one being removed
40266 while(index < items.length){
40267 var item = items[++index];
40268 if(item && !item.isHidden()){
40272 // if one isn't found select the previous tab (on the left)
40275 var item = items[--index];
40276 if(item && !item.isHidden()){
40284 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
40285 * @param {String/Number} id The id or index of the TabPanelItem to disable.
40287 disableTab : function(id){
40288 var tab = this.items[id];
40289 if(tab && this.active != tab){
40295 * Enables a {@link Roo.TabPanelItem} that is disabled.
40296 * @param {String/Number} id The id or index of the TabPanelItem to enable.
40298 enableTab : function(id){
40299 var tab = this.items[id];
40304 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
40305 * @param {String/Number} id The id or index of the TabPanelItem to activate.
40306 * @return {Roo.TabPanelItem} The TabPanelItem.
40308 activate : function(id)
40310 //Roo.log('activite:' + id);
40312 var tab = this.items[id];
40316 if(tab == this.active || tab.disabled){
40320 this.fireEvent("beforetabchange", this, e, tab);
40321 if(e.cancel !== true && !tab.disabled){
40323 this.active.hide();
40325 this.active = this.items[id];
40326 this.active.show();
40327 this.fireEvent("tabchange", this, this.active);
40333 * Gets the active {@link Roo.TabPanelItem}.
40334 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
40336 getActiveTab : function(){
40337 return this.active;
40341 * Updates the tab body element to fit the height of the container element
40342 * for overflow scrolling
40343 * @param {Number} targetHeight (optional) Override the starting height from the elements height
40345 syncHeight : function(targetHeight){
40346 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
40347 var bm = this.bodyEl.getMargins();
40348 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
40349 this.bodyEl.setHeight(newHeight);
40353 onResize : function(){
40354 if(this.monitorResize){
40355 this.autoSizeTabs();
40360 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
40362 beginUpdate : function(){
40363 this.updating = true;
40367 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
40369 endUpdate : function(){
40370 this.updating = false;
40371 this.autoSizeTabs();
40375 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
40377 autoSizeTabs : function()
40379 var count = this.items.length;
40380 var vcount = count - this.hiddenCount;
40383 this.stripEl.hide();
40385 this.stripEl.show();
40388 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
40393 var w = Math.max(this.el.getWidth() - this.cpad, 10);
40394 var availWidth = Math.floor(w / vcount);
40395 var b = this.stripBody;
40396 if(b.getWidth() > w){
40397 var tabs = this.items;
40398 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
40399 if(availWidth < this.minTabWidth){
40400 /*if(!this.sleft){ // incomplete scrolling code
40401 this.createScrollButtons();
40404 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
40407 if(this.currentTabWidth < this.preferredTabWidth){
40408 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
40414 * Returns the number of tabs in this TabPanel.
40417 getCount : function(){
40418 return this.items.length;
40422 * Resizes all the tabs to the passed width
40423 * @param {Number} The new width
40425 setTabWidth : function(width){
40426 this.currentTabWidth = width;
40427 for(var i = 0, len = this.items.length; i < len; i++) {
40428 if(!this.items[i].isHidden()) {
40429 this.items[i].setWidth(width);
40435 * Destroys this TabPanel
40436 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
40438 destroy : function(removeEl){
40439 Roo.EventManager.removeResizeListener(this.onResize, this);
40440 for(var i = 0, len = this.items.length; i < len; i++){
40441 this.items[i].purgeListeners();
40443 if(removeEl === true){
40444 this.el.update("");
40449 createStrip : function(container)
40451 var strip = document.createElement("nav");
40452 strip.className = Roo.bootstrap.version == 4 ?
40453 "navbar-light bg-light" :
40454 "navbar navbar-default"; //"x-tabs-wrap";
40455 container.appendChild(strip);
40459 createStripList : function(strip)
40461 // div wrapper for retard IE
40462 // returns the "tr" element.
40463 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
40464 //'<div class="x-tabs-strip-wrap">'+
40465 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
40466 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
40467 return strip.firstChild; //.firstChild.firstChild.firstChild;
40469 createBody : function(container)
40471 var body = document.createElement("div");
40472 Roo.id(body, "tab-body");
40473 //Roo.fly(body).addClass("x-tabs-body");
40474 Roo.fly(body).addClass("tab-content");
40475 container.appendChild(body);
40478 createItemBody :function(bodyEl, id){
40479 var body = Roo.getDom(id);
40481 body = document.createElement("div");
40484 //Roo.fly(body).addClass("x-tabs-item-body");
40485 Roo.fly(body).addClass("tab-pane");
40486 bodyEl.insertBefore(body, bodyEl.firstChild);
40490 createStripElements : function(stripEl, text, closable, tpl)
40492 var td = document.createElement("li"); // was td..
40493 td.className = 'nav-item';
40495 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
40498 stripEl.appendChild(td);
40500 td.className = "x-tabs-closable";
40501 if(!this.closeTpl){
40502 this.closeTpl = new Roo.Template(
40503 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
40504 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
40505 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
40508 var el = this.closeTpl.overwrite(td, {"text": text});
40509 var close = el.getElementsByTagName("div")[0];
40510 var inner = el.getElementsByTagName("em")[0];
40511 return {"el": el, "close": close, "inner": inner};
40514 // not sure what this is..
40515 // if(!this.tabTpl){
40516 //this.tabTpl = new Roo.Template(
40517 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
40518 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
40520 // this.tabTpl = new Roo.Template(
40521 // '<a href="#">' +
40522 // '<span unselectable="on"' +
40523 // (this.disableTooltips ? '' : ' title="{text}"') +
40524 // ' >{text}</span></a>'
40530 var template = tpl || this.tabTpl || false;
40533 template = new Roo.Template(
40534 Roo.bootstrap.version == 4 ?
40536 '<a class="nav-link" href="#" unselectable="on"' +
40537 (this.disableTooltips ? '' : ' title="{text}"') +
40540 '<a class="nav-link" href="#">' +
40541 '<span unselectable="on"' +
40542 (this.disableTooltips ? '' : ' title="{text}"') +
40543 ' >{text}</span></a>'
40548 switch (typeof(template)) {
40552 template = new Roo.Template(template);
40558 var el = template.overwrite(td, {"text": text});
40560 var inner = el.getElementsByTagName("span")[0];
40562 return {"el": el, "inner": inner};
40570 * @class Roo.TabPanelItem
40571 * @extends Roo.util.Observable
40572 * Represents an individual item (tab plus body) in a TabPanel.
40573 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
40574 * @param {String} id The id of this TabPanelItem
40575 * @param {String} text The text for the tab of this TabPanelItem
40576 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
40578 Roo.bootstrap.panel.TabItem = function(config){
40580 * The {@link Roo.TabPanel} this TabPanelItem belongs to
40581 * @type Roo.TabPanel
40583 this.tabPanel = config.panel;
40585 * The id for this TabPanelItem
40588 this.id = config.id;
40590 this.disabled = false;
40592 this.text = config.text;
40594 this.loaded = false;
40595 this.closable = config.closable;
40598 * The body element for this TabPanelItem.
40599 * @type Roo.Element
40601 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
40602 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
40603 this.bodyEl.setStyle("display", "block");
40604 this.bodyEl.setStyle("zoom", "1");
40605 //this.hideAction();
40607 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
40609 this.el = Roo.get(els.el);
40610 this.inner = Roo.get(els.inner, true);
40611 this.textEl = Roo.bootstrap.version == 4 ?
40612 this.el : Roo.get(this.el.dom.firstChild, true);
40614 this.pnode = this.linode = Roo.get(els.el.parentNode, true);
40615 this.status_node = Roo.bootstrap.version == 4 ? this.el : this.linode;
40618 // this.el.on("mousedown", this.onTabMouseDown, this);
40619 this.el.on("click", this.onTabClick, this);
40621 if(config.closable){
40622 var c = Roo.get(els.close, true);
40623 c.dom.title = this.closeText;
40624 c.addClassOnOver("close-over");
40625 c.on("click", this.closeClick, this);
40631 * Fires when this tab becomes the active tab.
40632 * @param {Roo.TabPanel} tabPanel The parent TabPanel
40633 * @param {Roo.TabPanelItem} this
40637 * @event beforeclose
40638 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
40639 * @param {Roo.TabPanelItem} this
40640 * @param {Object} e Set cancel to true on this object to cancel the close.
40642 "beforeclose": true,
40645 * Fires when this tab is closed.
40646 * @param {Roo.TabPanelItem} this
40650 * @event deactivate
40651 * Fires when this tab is no longer the active tab.
40652 * @param {Roo.TabPanel} tabPanel The parent TabPanel
40653 * @param {Roo.TabPanelItem} this
40655 "deactivate" : true
40657 this.hidden = false;
40659 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
40662 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
40664 purgeListeners : function(){
40665 Roo.util.Observable.prototype.purgeListeners.call(this);
40666 this.el.removeAllListeners();
40669 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
40672 this.status_node.addClass("active");
40675 this.tabPanel.stripWrap.repaint();
40677 this.fireEvent("activate", this.tabPanel, this);
40681 * Returns true if this tab is the active tab.
40682 * @return {Boolean}
40684 isActive : function(){
40685 return this.tabPanel.getActiveTab() == this;
40689 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
40692 this.status_node.removeClass("active");
40694 this.fireEvent("deactivate", this.tabPanel, this);
40697 hideAction : function(){
40698 this.bodyEl.hide();
40699 this.bodyEl.setStyle("position", "absolute");
40700 this.bodyEl.setLeft("-20000px");
40701 this.bodyEl.setTop("-20000px");
40704 showAction : function(){
40705 this.bodyEl.setStyle("position", "relative");
40706 this.bodyEl.setTop("");
40707 this.bodyEl.setLeft("");
40708 this.bodyEl.show();
40712 * Set the tooltip for the tab.
40713 * @param {String} tooltip The tab's tooltip
40715 setTooltip : function(text){
40716 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
40717 this.textEl.dom.qtip = text;
40718 this.textEl.dom.removeAttribute('title');
40720 this.textEl.dom.title = text;
40724 onTabClick : function(e){
40725 e.preventDefault();
40726 this.tabPanel.activate(this.id);
40729 onTabMouseDown : function(e){
40730 e.preventDefault();
40731 this.tabPanel.activate(this.id);
40734 getWidth : function(){
40735 return this.inner.getWidth();
40738 setWidth : function(width){
40739 var iwidth = width - this.linode.getPadding("lr");
40740 this.inner.setWidth(iwidth);
40741 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
40742 this.linode.setWidth(width);
40746 * Show or hide the tab
40747 * @param {Boolean} hidden True to hide or false to show.
40749 setHidden : function(hidden){
40750 this.hidden = hidden;
40751 this.linode.setStyle("display", hidden ? "none" : "");
40755 * Returns true if this tab is "hidden"
40756 * @return {Boolean}
40758 isHidden : function(){
40759 return this.hidden;
40763 * Returns the text for this tab
40766 getText : function(){
40770 autoSize : function(){
40771 //this.el.beginMeasure();
40772 this.textEl.setWidth(1);
40774 * #2804 [new] Tabs in Roojs
40775 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
40777 //this.setWidth(this.textEl.dom.scrollWidth+this.linode.getPadding("lr")+this.inner.getPadding("lr") + 2);
40778 //this.el.endMeasure();
40782 * Sets the text for the tab (Note: this also sets the tooltip text)
40783 * @param {String} text The tab's text and tooltip
40785 setText : function(text){
40787 this.textEl.update(text);
40788 this.setTooltip(text);
40789 //if(!this.tabPanel.resizeTabs){
40790 // this.autoSize();
40794 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
40796 activate : function(){
40797 this.tabPanel.activate(this.id);
40801 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
40803 disable : function(){
40804 if(this.tabPanel.active != this){
40805 this.disabled = true;
40806 this.status_node.addClass("disabled");
40811 * Enables this TabPanelItem if it was previously disabled.
40813 enable : function(){
40814 this.disabled = false;
40815 this.status_node.removeClass("disabled");
40819 * Sets the content for this TabPanelItem.
40820 * @param {String} content The content
40821 * @param {Boolean} loadScripts true to look for and load scripts
40823 setContent : function(content, loadScripts){
40824 this.bodyEl.update(content, loadScripts);
40828 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
40829 * @return {Roo.UpdateManager} The UpdateManager
40831 getUpdateManager : function(){
40832 return this.bodyEl.getUpdateManager();
40836 * Set a URL to be used to load the content for this TabPanelItem.
40837 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
40838 * @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)
40839 * @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)
40840 * @return {Roo.UpdateManager} The UpdateManager
40842 setUrl : function(url, params, loadOnce){
40843 if(this.refreshDelegate){
40844 this.un('activate', this.refreshDelegate);
40846 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
40847 this.on("activate", this.refreshDelegate);
40848 return this.bodyEl.getUpdateManager();
40852 _handleRefresh : function(url, params, loadOnce){
40853 if(!loadOnce || !this.loaded){
40854 var updater = this.bodyEl.getUpdateManager();
40855 updater.update(url, params, this._setLoaded.createDelegate(this));
40860 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
40861 * Will fail silently if the setUrl method has not been called.
40862 * This does not activate the panel, just updates its content.
40864 refresh : function(){
40865 if(this.refreshDelegate){
40866 this.loaded = false;
40867 this.refreshDelegate();
40872 _setLoaded : function(){
40873 this.loaded = true;
40877 closeClick : function(e){
40880 this.fireEvent("beforeclose", this, o);
40881 if(o.cancel !== true){
40882 this.tabPanel.removeTab(this.id);
40886 * The text displayed in the tooltip for the close icon.
40889 closeText : "Close this tab"
40892 * This script refer to:
40893 * Title: International Telephone Input
40894 * Author: Jack O'Connor
40895 * Code version: v12.1.12
40896 * Availability: https://github.com/jackocnr/intl-tel-input.git
40899 Roo.bootstrap.PhoneInputData = function() {
40902 "Afghanistan (افغانستان)",
40907 "Albania (Shqipëri)",
40912 "Algeria (الجزائر)",
40937 "Antigua and Barbuda",
40947 "Armenia (Հայաստան)",
40963 "Austria (Österreich)",
40968 "Azerbaijan (Azərbaycan)",
40978 "Bahrain (البحرين)",
40983 "Bangladesh (বাংলাদেশ)",
40993 "Belarus (Беларусь)",
40998 "Belgium (België)",
41028 "Bosnia and Herzegovina (Босна и Херцеговина)",
41043 "British Indian Ocean Territory",
41048 "British Virgin Islands",
41058 "Bulgaria (България)",
41068 "Burundi (Uburundi)",
41073 "Cambodia (កម្ពុជា)",
41078 "Cameroon (Cameroun)",
41087 ["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"]
41090 "Cape Verde (Kabu Verdi)",
41095 "Caribbean Netherlands",
41106 "Central African Republic (République centrafricaine)",
41126 "Christmas Island",
41132 "Cocos (Keeling) Islands",
41143 "Comoros (جزر القمر)",
41148 "Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)",
41153 "Congo (Republic) (Congo-Brazzaville)",
41173 "Croatia (Hrvatska)",
41194 "Czech Republic (Česká republika)",
41199 "Denmark (Danmark)",
41214 "Dominican Republic (República Dominicana)",
41218 ["809", "829", "849"]
41236 "Equatorial Guinea (Guinea Ecuatorial)",
41256 "Falkland Islands (Islas Malvinas)",
41261 "Faroe Islands (Føroyar)",
41282 "French Guiana (Guyane française)",
41287 "French Polynesia (Polynésie française)",
41302 "Georgia (საქართველო)",
41307 "Germany (Deutschland)",
41327 "Greenland (Kalaallit Nunaat)",
41364 "Guinea-Bissau (Guiné Bissau)",
41389 "Hungary (Magyarország)",
41394 "Iceland (Ísland)",
41414 "Iraq (العراق)",
41430 "Israel (ישראל)",
41457 "Jordan (الأردن)",
41462 "Kazakhstan (Казахстан)",
41483 "Kuwait (الكويت)",
41488 "Kyrgyzstan (Кыргызстан)",
41498 "Latvia (Latvija)",
41503 "Lebanon (لبنان)",
41518 "Libya (ليبيا)",
41528 "Lithuania (Lietuva)",
41543 "Macedonia (FYROM) (Македонија)",
41548 "Madagascar (Madagasikara)",
41578 "Marshall Islands",
41588 "Mauritania (موريتانيا)",
41593 "Mauritius (Moris)",
41614 "Moldova (Republica Moldova)",
41624 "Mongolia (Монгол)",
41629 "Montenegro (Crna Gora)",
41639 "Morocco (المغرب)",
41645 "Mozambique (Moçambique)",
41650 "Myanmar (Burma) (မြန်မာ)",
41655 "Namibia (Namibië)",
41670 "Netherlands (Nederland)",
41675 "New Caledonia (Nouvelle-Calédonie)",
41710 "North Korea (조선 민주주의 인민 공화국)",
41715 "Northern Mariana Islands",
41731 "Pakistan (پاکستان)",
41741 "Palestine (فلسطين)",
41751 "Papua New Guinea",
41793 "Réunion (La Réunion)",
41799 "Romania (România)",
41815 "Saint Barthélemy",
41826 "Saint Kitts and Nevis",
41836 "Saint Martin (Saint-Martin (partie française))",
41842 "Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)",
41847 "Saint Vincent and the Grenadines",
41862 "São Tomé and Príncipe (São Tomé e Príncipe)",
41867 "Saudi Arabia (المملكة العربية السعودية)",
41872 "Senegal (Sénégal)",
41902 "Slovakia (Slovensko)",
41907 "Slovenia (Slovenija)",
41917 "Somalia (Soomaaliya)",
41927 "South Korea (대한민국)",
41932 "South Sudan (جنوب السودان)",
41942 "Sri Lanka (ශ්රී ලංකාව)",
41947 "Sudan (السودان)",
41957 "Svalbard and Jan Mayen",
41968 "Sweden (Sverige)",
41973 "Switzerland (Schweiz)",
41978 "Syria (سوريا)",
42023 "Trinidad and Tobago",
42028 "Tunisia (تونس)",
42033 "Turkey (Türkiye)",
42043 "Turks and Caicos Islands",
42053 "U.S. Virgin Islands",
42063 "Ukraine (Україна)",
42068 "United Arab Emirates (الإمارات العربية المتحدة)",
42090 "Uzbekistan (Oʻzbekiston)",
42100 "Vatican City (Città del Vaticano)",
42111 "Vietnam (Việt Nam)",
42116 "Wallis and Futuna (Wallis-et-Futuna)",
42121 "Western Sahara (الصحراء الغربية)",
42127 "Yemen (اليمن)",
42151 * This script refer to:
42152 * Title: International Telephone Input
42153 * Author: Jack O'Connor
42154 * Code version: v12.1.12
42155 * Availability: https://github.com/jackocnr/intl-tel-input.git
42159 * @class Roo.bootstrap.PhoneInput
42160 * @extends Roo.bootstrap.TriggerField
42161 * An input with International dial-code selection
42163 * @cfg {String} defaultDialCode default '+852'
42164 * @cfg {Array} preferedCountries default []
42167 * Create a new PhoneInput.
42168 * @param {Object} config Configuration options
42171 Roo.bootstrap.PhoneInput = function(config) {
42172 Roo.bootstrap.PhoneInput.superclass.constructor.call(this, config);
42175 Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
42177 listWidth: undefined,
42179 selectedClass: 'active',
42181 invalidClass : "has-warning",
42183 validClass: 'has-success',
42185 allowed: '0123456789',
42190 * @cfg {String} defaultDialCode The default dial code when initializing the input
42192 defaultDialCode: '+852',
42195 * @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
42197 preferedCountries: false,
42199 getAutoCreate : function()
42201 var data = Roo.bootstrap.PhoneInputData();
42202 var align = this.labelAlign || this.parentLabelAlign();
42205 this.allCountries = [];
42206 this.dialCodeMapping = [];
42208 for (var i = 0; i < data.length; i++) {
42210 this.allCountries[i] = {
42214 priority: c[3] || 0,
42215 areaCodes: c[4] || null
42217 this.dialCodeMapping[c[2]] = {
42220 priority: c[3] || 0,
42221 areaCodes: c[4] || null
42233 // type: 'number', -- do not use number - we get the flaky up/down arrows.
42234 maxlength: this.max_length,
42235 cls : 'form-control tel-input',
42236 autocomplete: 'new-password'
42239 var hiddenInput = {
42242 cls: 'hidden-tel-input'
42246 hiddenInput.name = this.name;
42249 if (this.disabled) {
42250 input.disabled = true;
42253 var flag_container = {
42270 cls: this.hasFeedback ? 'has-feedback' : '',
42276 cls: 'dial-code-holder',
42283 cls: 'roo-select2-container input-group',
42290 if (this.fieldLabel.length) {
42293 tooltip: 'This field is required'
42299 cls: 'control-label',
42305 html: this.fieldLabel
42308 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
42314 if(this.indicatorpos == 'right') {
42315 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
42322 if(align == 'left') {
42330 if(this.labelWidth > 12){
42331 label.style = "width: " + this.labelWidth + 'px';
42333 if(this.labelWidth < 13 && this.labelmd == 0){
42334 this.labelmd = this.labelWidth;
42336 if(this.labellg > 0){
42337 label.cls += ' col-lg-' + this.labellg;
42338 input.cls += ' col-lg-' + (12 - this.labellg);
42340 if(this.labelmd > 0){
42341 label.cls += ' col-md-' + this.labelmd;
42342 container.cls += ' col-md-' + (12 - this.labelmd);
42344 if(this.labelsm > 0){
42345 label.cls += ' col-sm-' + this.labelsm;
42346 container.cls += ' col-sm-' + (12 - this.labelsm);
42348 if(this.labelxs > 0){
42349 label.cls += ' col-xs-' + this.labelxs;
42350 container.cls += ' col-xs-' + (12 - this.labelxs);
42360 var settings = this;
42362 ['xs','sm','md','lg'].map(function(size){
42363 if (settings[size]) {
42364 cfg.cls += ' col-' + size + '-' + settings[size];
42368 this.store = new Roo.data.Store({
42369 proxy : new Roo.data.MemoryProxy({}),
42370 reader : new Roo.data.JsonReader({
42381 'name' : 'dialCode',
42385 'name' : 'priority',
42389 'name' : 'areaCodes',
42396 if(!this.preferedCountries) {
42397 this.preferedCountries = [
42404 var p = this.preferedCountries.reverse();
42407 for (var i = 0; i < p.length; i++) {
42408 for (var j = 0; j < this.allCountries.length; j++) {
42409 if(this.allCountries[j].iso2 == p[i]) {
42410 var t = this.allCountries[j];
42411 this.allCountries.splice(j,1);
42412 this.allCountries.unshift(t);
42418 this.store.proxy.data = {
42420 data: this.allCountries
42426 initEvents : function()
42429 Roo.bootstrap.PhoneInput.superclass.initEvents.call(this);
42431 this.indicator = this.indicatorEl();
42432 this.flag = this.flagEl();
42433 this.dialCodeHolder = this.dialCodeHolderEl();
42435 this.trigger = this.el.select('div.flag-box',true).first();
42436 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
42441 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
42442 _this.list.setWidth(lw);
42445 this.list.on('mouseover', this.onViewOver, this);
42446 this.list.on('mousemove', this.onViewMove, this);
42447 this.inputEl().on("keyup", this.onKeyUp, this);
42448 this.inputEl().on("keypress", this.onKeyPress, this);
42450 this.tpl = '<li><a href="#"><div class="flag {iso2}"></div>{name} <span class="dial-code">+{dialCode}</span></a></li>';
42452 this.view = new Roo.View(this.list, this.tpl, {
42453 singleSelect:true, store: this.store, selectedClass: this.selectedClass
42456 this.view.on('click', this.onViewClick, this);
42457 this.setValue(this.defaultDialCode);
42460 onTriggerClick : function(e)
42462 Roo.log('trigger click');
42467 if(this.isExpanded()){
42469 this.hasFocus = false;
42471 this.store.load({});
42472 this.hasFocus = true;
42477 isExpanded : function()
42479 return this.list.isVisible();
42482 collapse : function()
42484 if(!this.isExpanded()){
42488 Roo.get(document).un('mousedown', this.collapseIf, this);
42489 Roo.get(document).un('mousewheel', this.collapseIf, this);
42490 this.fireEvent('collapse', this);
42494 expand : function()
42498 if(this.isExpanded() || !this.hasFocus){
42502 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
42503 this.list.setWidth(lw);
42506 this.restrictHeight();
42508 Roo.get(document).on('mousedown', this.collapseIf, this);
42509 Roo.get(document).on('mousewheel', this.collapseIf, this);
42511 this.fireEvent('expand', this);
42514 restrictHeight : function()
42516 this.list.alignTo(this.inputEl(), this.listAlign);
42517 this.list.alignTo(this.inputEl(), this.listAlign);
42520 onViewOver : function(e, t)
42522 if(this.inKeyMode){
42525 var item = this.view.findItemFromChild(t);
42528 var index = this.view.indexOf(item);
42529 this.select(index, false);
42534 onViewClick : function(view, doFocus, el, e)
42536 var index = this.view.getSelectedIndexes()[0];
42538 var r = this.store.getAt(index);
42541 this.onSelect(r, index);
42543 if(doFocus !== false && !this.blockFocus){
42544 this.inputEl().focus();
42548 onViewMove : function(e, t)
42550 this.inKeyMode = false;
42553 select : function(index, scrollIntoView)
42555 this.selectedIndex = index;
42556 this.view.select(index);
42557 if(scrollIntoView !== false){
42558 var el = this.view.getNode(index);
42560 this.list.scrollChildIntoView(el, false);
42565 createList : function()
42567 this.list = Roo.get(document.body).createChild({
42569 cls: 'typeahead typeahead-long dropdown-menu tel-list',
42570 style: 'display:none'
42573 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
42576 collapseIf : function(e)
42578 var in_combo = e.within(this.el);
42579 var in_list = e.within(this.list);
42580 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
42582 if (in_combo || in_list || is_list) {
42588 onSelect : function(record, index)
42590 if(this.fireEvent('beforeselect', this, record, index) !== false){
42592 this.setFlagClass(record.data.iso2);
42593 this.setDialCode(record.data.dialCode);
42594 this.hasFocus = false;
42596 this.fireEvent('select', this, record, index);
42600 flagEl : function()
42602 var flag = this.el.select('div.flag',true).first();
42609 dialCodeHolderEl : function()
42611 var d = this.el.select('input.dial-code-holder',true).first();
42618 setDialCode : function(v)
42620 this.dialCodeHolder.dom.value = '+'+v;
42623 setFlagClass : function(n)
42625 this.flag.dom.className = 'flag '+n;
42628 getValue : function()
42630 var v = this.inputEl().getValue();
42631 if(this.dialCodeHolder) {
42632 v = this.dialCodeHolder.dom.value+this.inputEl().getValue();
42637 setValue : function(v)
42639 var d = this.getDialCode(v);
42641 //invalid dial code
42642 if(v.length == 0 || !d || d.length == 0) {
42644 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
42645 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
42651 this.setFlagClass(this.dialCodeMapping[d].iso2);
42652 this.setDialCode(d);
42653 this.inputEl().dom.value = v.replace('+'+d,'');
42654 this.hiddenEl().dom.value = this.getValue();
42659 getDialCode : function(v)
42663 if (v.length == 0) {
42664 return this.dialCodeHolder.dom.value;
42668 if (v.charAt(0) != "+") {
42671 var numericChars = "";
42672 for (var i = 1; i < v.length; i++) {
42673 var c = v.charAt(i);
42676 if (this.dialCodeMapping[numericChars]) {
42677 dialCode = v.substr(1, i);
42679 if (numericChars.length == 4) {
42689 this.setValue(this.defaultDialCode);
42693 hiddenEl : function()
42695 return this.el.select('input.hidden-tel-input',true).first();
42698 // after setting val
42699 onKeyUp : function(e){
42700 this.setValue(this.getValue());
42703 onKeyPress : function(e){
42704 if(this.allowed.indexOf(String.fromCharCode(e.getCharCode())) === -1){
42711 * @class Roo.bootstrap.MoneyField
42712 * @extends Roo.bootstrap.ComboBox
42713 * Bootstrap MoneyField class
42716 * Create a new MoneyField.
42717 * @param {Object} config Configuration options
42720 Roo.bootstrap.MoneyField = function(config) {
42722 Roo.bootstrap.MoneyField.superclass.constructor.call(this, config);
42726 Roo.extend(Roo.bootstrap.MoneyField, Roo.bootstrap.ComboBox, {
42729 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
42731 allowDecimals : true,
42733 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
42735 decimalSeparator : ".",
42737 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
42739 decimalPrecision : 0,
42741 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
42743 allowNegative : true,
42745 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
42749 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
42751 minValue : Number.NEGATIVE_INFINITY,
42753 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
42755 maxValue : Number.MAX_VALUE,
42757 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
42759 minText : "The minimum value for this field is {0}",
42761 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
42763 maxText : "The maximum value for this field is {0}",
42765 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
42766 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
42768 nanText : "{0} is not a valid number",
42770 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
42774 * @cfg {String} defaults currency of the MoneyField
42775 * value should be in lkey
42777 defaultCurrency : false,
42779 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
42781 thousandsDelimiter : false,
42783 * @cfg {Number} max_length Maximum input field length allowed (defaults to Number.MAX_VALUE)
42794 getAutoCreate : function()
42796 var align = this.labelAlign || this.parentLabelAlign();
42808 cls : 'form-control roo-money-amount-input',
42809 autocomplete: 'new-password'
42812 var hiddenInput = {
42816 cls: 'hidden-number-input'
42819 if(this.max_length) {
42820 input.maxlength = this.max_length;
42824 hiddenInput.name = this.name;
42827 if (this.disabled) {
42828 input.disabled = true;
42831 var clg = 12 - this.inputlg;
42832 var cmd = 12 - this.inputmd;
42833 var csm = 12 - this.inputsm;
42834 var cxs = 12 - this.inputxs;
42838 cls : 'row roo-money-field',
42842 cls : 'roo-money-currency column col-lg-' + clg + ' col-md-' + cmd + ' col-sm-' + csm + ' col-xs-' + cxs,
42846 cls: 'roo-select2-container input-group',
42850 cls : 'form-control roo-money-currency-input',
42851 autocomplete: 'new-password',
42853 name : this.currencyName
42857 cls : 'input-group-addon',
42871 cls : 'roo-money-amount column col-lg-' + this.inputlg + ' col-md-' + this.inputmd + ' col-sm-' + this.inputsm + ' col-xs-' + this.inputxs,
42875 cls: this.hasFeedback ? 'has-feedback' : '',
42886 if (this.fieldLabel.length) {
42889 tooltip: 'This field is required'
42895 cls: 'control-label',
42901 html: this.fieldLabel
42904 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
42910 if(this.indicatorpos == 'right') {
42911 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
42918 if(align == 'left') {
42926 if(this.labelWidth > 12){
42927 label.style = "width: " + this.labelWidth + 'px';
42929 if(this.labelWidth < 13 && this.labelmd == 0){
42930 this.labelmd = this.labelWidth;
42932 if(this.labellg > 0){
42933 label.cls += ' col-lg-' + this.labellg;
42934 input.cls += ' col-lg-' + (12 - this.labellg);
42936 if(this.labelmd > 0){
42937 label.cls += ' col-md-' + this.labelmd;
42938 container.cls += ' col-md-' + (12 - this.labelmd);
42940 if(this.labelsm > 0){
42941 label.cls += ' col-sm-' + this.labelsm;
42942 container.cls += ' col-sm-' + (12 - this.labelsm);
42944 if(this.labelxs > 0){
42945 label.cls += ' col-xs-' + this.labelxs;
42946 container.cls += ' col-xs-' + (12 - this.labelxs);
42957 var settings = this;
42959 ['xs','sm','md','lg'].map(function(size){
42960 if (settings[size]) {
42961 cfg.cls += ' col-' + size + '-' + settings[size];
42968 initEvents : function()
42970 this.indicator = this.indicatorEl();
42972 this.initCurrencyEvent();
42974 this.initNumberEvent();
42977 initCurrencyEvent : function()
42980 throw "can not find store for combo";
42983 this.store = Roo.factory(this.store, Roo.data);
42984 this.store.parent = this;
42988 this.triggerEl = this.el.select('.input-group-addon', true).first();
42990 this.triggerEl.on("click", this.onTriggerClick, this, { preventDefault : true });
42995 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
42996 _this.list.setWidth(lw);
42999 this.list.on('mouseover', this.onViewOver, this);
43000 this.list.on('mousemove', this.onViewMove, this);
43001 this.list.on('scroll', this.onViewScroll, this);
43004 this.tpl = '<li><a href="#">{' + this.currencyField + '}</a></li>';
43007 this.view = new Roo.View(this.list, this.tpl, {
43008 singleSelect:true, store: this.store, selectedClass: this.selectedClass
43011 this.view.on('click', this.onViewClick, this);
43013 this.store.on('beforeload', this.onBeforeLoad, this);
43014 this.store.on('load', this.onLoad, this);
43015 this.store.on('loadexception', this.onLoadException, this);
43017 this.keyNav = new Roo.KeyNav(this.currencyEl(), {
43018 "up" : function(e){
43019 this.inKeyMode = true;
43023 "down" : function(e){
43024 if(!this.isExpanded()){
43025 this.onTriggerClick();
43027 this.inKeyMode = true;
43032 "enter" : function(e){
43035 if(this.fireEvent("specialkey", this, e)){
43036 this.onViewClick(false);
43042 "esc" : function(e){
43046 "tab" : function(e){
43049 if(this.fireEvent("specialkey", this, e)){
43050 this.onViewClick(false);
43058 doRelay : function(foo, bar, hname){
43059 if(hname == 'down' || this.scope.isExpanded()){
43060 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
43068 this.currencyEl().on("click", this.onTriggerClick, this, { preventDefault : true });
43072 initNumberEvent : function(e)
43074 this.inputEl().on("keydown" , this.fireKey, this);
43075 this.inputEl().on("focus", this.onFocus, this);
43076 this.inputEl().on("blur", this.onBlur, this);
43078 this.inputEl().relayEvent('keyup', this);
43080 if(this.indicator){
43081 this.indicator.addClass('invisible');
43084 this.originalValue = this.getValue();
43086 if(this.validationEvent == 'keyup'){
43087 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
43088 this.inputEl().on('keyup', this.filterValidation, this);
43090 else if(this.validationEvent !== false){
43091 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
43094 if(this.selectOnFocus){
43095 this.on("focus", this.preFocus, this);
43098 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
43099 this.inputEl().on("keypress", this.filterKeys, this);
43101 this.inputEl().relayEvent('keypress', this);
43104 var allowed = "0123456789";
43106 if(this.allowDecimals){
43107 allowed += this.decimalSeparator;
43110 if(this.allowNegative){
43114 if(this.thousandsDelimiter) {
43118 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
43120 var keyPress = function(e){
43122 var k = e.getKey();
43124 var c = e.getCharCode();
43127 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
43128 allowed.indexOf(String.fromCharCode(c)) === -1
43134 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
43138 if(allowed.indexOf(String.fromCharCode(c)) === -1){
43143 this.inputEl().on("keypress", keyPress, this);
43147 onTriggerClick : function(e)
43154 this.loadNext = false;
43156 if(this.isExpanded()){
43161 this.hasFocus = true;
43163 if(this.triggerAction == 'all') {
43164 this.doQuery(this.allQuery, true);
43168 this.doQuery(this.getRawValue());
43171 getCurrency : function()
43173 var v = this.currencyEl().getValue();
43178 restrictHeight : function()
43180 this.list.alignTo(this.currencyEl(), this.listAlign);
43181 this.list.alignTo(this.currencyEl(), this.listAlign);
43184 onViewClick : function(view, doFocus, el, e)
43186 var index = this.view.getSelectedIndexes()[0];
43188 var r = this.store.getAt(index);
43191 this.onSelect(r, index);
43195 onSelect : function(record, index){
43197 if(this.fireEvent('beforeselect', this, record, index) !== false){
43199 this.setFromCurrencyData(index > -1 ? record.data : false);
43203 this.fireEvent('select', this, record, index);
43207 setFromCurrencyData : function(o)
43211 this.lastCurrency = o;
43213 if (this.currencyField) {
43214 currency = !o || typeof(o[this.currencyField]) == 'undefined' ? '' : o[this.currencyField];
43216 Roo.log('no currencyField value set for '+ (this.name ? this.name : this.id));
43219 this.lastSelectionText = currency;
43221 //setting default currency
43222 if(o[this.currencyField] * 1 == 0 && this.defaultCurrency) {
43223 this.setCurrency(this.defaultCurrency);
43227 this.setCurrency(currency);
43230 setFromData : function(o)
43234 c[this.currencyField] = !o || typeof(o[this.currencyName]) == 'undefined' ? '' : o[this.currencyName];
43236 this.setFromCurrencyData(c);
43241 value = !o || typeof(o[this.name]) == 'undefined' ? '' : o[this.name];
43243 Roo.log('no value set for '+ (this.name ? this.name : this.id));
43246 this.setValue(value);
43250 setCurrency : function(v)
43252 this.currencyValue = v;
43255 this.currencyEl().dom.value = (v === null || v === undefined ? '' : v);
43260 setValue : function(v)
43262 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
43268 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
43270 this.inputEl().dom.value = (v == '') ? '' :
43271 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
43273 if(!this.allowZero && v === '0') {
43274 this.hiddenEl().dom.value = '';
43275 this.inputEl().dom.value = '';
43282 getRawValue : function()
43284 var v = this.inputEl().getValue();
43289 getValue : function()
43291 return this.fixPrecision(this.parseValue(this.getRawValue()));
43294 parseValue : function(value)
43296 if(this.thousandsDelimiter) {
43298 r = new RegExp(",", "g");
43299 value = value.replace(r, "");
43302 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
43303 return isNaN(value) ? '' : value;
43307 fixPrecision : function(value)
43309 if(this.thousandsDelimiter) {
43311 r = new RegExp(",", "g");
43312 value = value.replace(r, "");
43315 var nan = isNaN(value);
43317 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
43318 return nan ? '' : value;
43320 return parseFloat(value).toFixed(this.decimalPrecision);
43323 decimalPrecisionFcn : function(v)
43325 return Math.floor(v);
43328 validateValue : function(value)
43330 if(!Roo.bootstrap.MoneyField.superclass.validateValue.call(this, value)){
43334 var num = this.parseValue(value);
43337 this.markInvalid(String.format(this.nanText, value));
43341 if(num < this.minValue){
43342 this.markInvalid(String.format(this.minText, this.minValue));
43346 if(num > this.maxValue){
43347 this.markInvalid(String.format(this.maxText, this.maxValue));
43354 validate : function()
43356 if(this.disabled || this.allowBlank){
43361 var currency = this.getCurrency();
43363 if(this.validateValue(this.getRawValue()) && currency.length){
43368 this.markInvalid();
43372 getName: function()
43377 beforeBlur : function()
43383 var v = this.parseValue(this.getRawValue());
43390 onBlur : function()
43394 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
43395 //this.el.removeClass(this.focusClass);
43398 this.hasFocus = false;
43400 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
43404 var v = this.getValue();
43406 if(String(v) !== String(this.startValue)){
43407 this.fireEvent('change', this, v, this.startValue);
43410 this.fireEvent("blur", this);
43413 inputEl : function()
43415 return this.el.select('.roo-money-amount-input', true).first();
43418 currencyEl : function()
43420 return this.el.select('.roo-money-currency-input', true).first();
43423 hiddenEl : function()
43425 return this.el.select('input.hidden-number-input',true).first();
43429 * @class Roo.bootstrap.BezierSignature
43430 * @extends Roo.bootstrap.Component
43431 * Bootstrap BezierSignature class
43432 * This script refer to:
43433 * Title: Signature Pad
43435 * Availability: https://github.com/szimek/signature_pad
43438 * Create a new BezierSignature
43439 * @param {Object} config The config object
43442 Roo.bootstrap.BezierSignature = function(config){
43443 Roo.bootstrap.BezierSignature.superclass.constructor.call(this, config);
43449 Roo.extend(Roo.bootstrap.BezierSignature, Roo.bootstrap.Component,
43456 mouse_btn_down: true,
43459 * @cfg {int} canvas height
43461 canvas_height: '200px',
43464 * @cfg {float|function} Radius of a single dot.
43469 * @cfg {float} Minimum width of a line. Defaults to 0.5.
43474 * @cfg {float} Maximum width of a line. Defaults to 2.5.
43479 * @cfg {integer} Draw the next point at most once per every x milliseconds. Set it to 0 to turn off throttling. Defaults to 16.
43484 * @cfg {integer} Add the next point only if the previous one is farther than x pixels. Defaults to 5.
43489 * @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.
43491 bg_color: 'rgba(0, 0, 0, 0)',
43494 * @cfg {string} Color used to draw the lines. Can be any color format accepted by context.fillStyle. Defaults to "black".
43496 dot_color: 'black',
43499 * @cfg {float} Weight used to modify new velocity based on the previous velocity. Defaults to 0.7.
43501 velocity_filter_weight: 0.7,
43504 * @cfg {function} Callback when stroke begin.
43509 * @cfg {function} Callback when stroke end.
43513 getAutoCreate : function()
43515 var cls = 'roo-signature column';
43518 cls += ' ' + this.cls;
43528 for(var i = 0; i < col_sizes.length; i++) {
43529 if(this[col_sizes[i]]) {
43530 cls += " col-"+col_sizes[i]+"-"+this[col_sizes[i]];
43540 cls: 'roo-signature-body',
43544 cls: 'roo-signature-body-canvas',
43545 height: this.canvas_height,
43546 width: this.canvas_width
43553 style: 'display: none'
43561 initEvents: function()
43563 Roo.bootstrap.BezierSignature.superclass.initEvents.call(this);
43565 var canvas = this.canvasEl();
43567 // mouse && touch event swapping...
43568 canvas.dom.style.touchAction = 'none';
43569 canvas.dom.style.msTouchAction = 'none';
43571 this.mouse_btn_down = false;
43572 canvas.on('mousedown', this._handleMouseDown, this);
43573 canvas.on('mousemove', this._handleMouseMove, this);
43574 Roo.select('html').first().on('mouseup', this._handleMouseUp, this);
43576 if (window.PointerEvent) {
43577 canvas.on('pointerdown', this._handleMouseDown, this);
43578 canvas.on('pointermove', this._handleMouseMove, this);
43579 Roo.select('html').first().on('pointerup', this._handleMouseUp, this);
43582 if ('ontouchstart' in window) {
43583 canvas.on('touchstart', this._handleTouchStart, this);
43584 canvas.on('touchmove', this._handleTouchMove, this);
43585 canvas.on('touchend', this._handleTouchEnd, this);
43588 Roo.EventManager.onWindowResize(this.resize, this, true);
43590 // file input event
43591 this.fileEl().on('change', this.uploadImage, this);
43598 resize: function(){
43600 var canvas = this.canvasEl().dom;
43601 var ctx = this.canvasElCtx();
43602 var img_data = false;
43604 if(canvas.width > 0) {
43605 var img_data = ctx.getImageData(0, 0, canvas.width, canvas.height);
43607 // setting canvas width will clean img data
43610 var style = window.getComputedStyle ?
43611 getComputedStyle(this.el.dom, null) : this.el.dom.currentStyle;
43613 var padding_left = parseInt(style.paddingLeft) || 0;
43614 var padding_right = parseInt(style.paddingRight) || 0;
43616 canvas.width = this.el.dom.clientWidth - padding_left - padding_right;
43619 ctx.putImageData(img_data, 0, 0);
43623 _handleMouseDown: function(e)
43625 if (e.browserEvent.which === 1) {
43626 this.mouse_btn_down = true;
43627 this.strokeBegin(e);
43631 _handleMouseMove: function (e)
43633 if (this.mouse_btn_down) {
43634 this.strokeMoveUpdate(e);
43638 _handleMouseUp: function (e)
43640 if (e.browserEvent.which === 1 && this.mouse_btn_down) {
43641 this.mouse_btn_down = false;
43646 _handleTouchStart: function (e) {
43648 e.preventDefault();
43649 if (e.browserEvent.targetTouches.length === 1) {
43650 // var touch = e.browserEvent.changedTouches[0];
43651 // this.strokeBegin(touch);
43653 this.strokeBegin(e); // assume e catching the correct xy...
43657 _handleTouchMove: function (e) {
43658 e.preventDefault();
43659 // var touch = event.targetTouches[0];
43660 // _this._strokeMoveUpdate(touch);
43661 this.strokeMoveUpdate(e);
43664 _handleTouchEnd: function (e) {
43665 var wasCanvasTouched = e.target === this.canvasEl().dom;
43666 if (wasCanvasTouched) {
43667 e.preventDefault();
43668 // var touch = event.changedTouches[0];
43669 // _this._strokeEnd(touch);
43674 reset: function () {
43675 this._lastPoints = [];
43676 this._lastVelocity = 0;
43677 this._lastWidth = (this.min_width + this.max_width) / 2;
43678 this.canvasElCtx().fillStyle = this.dot_color;
43681 strokeMoveUpdate: function(e)
43683 this.strokeUpdate(e);
43685 if (this.throttle) {
43686 this.throttleStroke(this.strokeUpdate, this.throttle);
43689 this.strokeUpdate(e);
43693 strokeBegin: function(e)
43695 var newPointGroup = {
43696 color: this.dot_color,
43700 if (typeof this.onBegin === 'function') {
43704 this.curve_data.push(newPointGroup);
43706 this.strokeUpdate(e);
43709 strokeUpdate: function(e)
43711 var rect = this.canvasEl().dom.getBoundingClientRect();
43712 var point = new this.Point(e.xy[0] - rect.left, e.xy[1] - rect.top, new Date().getTime());
43713 var lastPointGroup = this.curve_data[this.curve_data.length - 1];
43714 var lastPoints = lastPointGroup.points;
43715 var lastPoint = lastPoints.length > 0 && lastPoints[lastPoints.length - 1];
43716 var isLastPointTooClose = lastPoint
43717 ? point.distanceTo(lastPoint) <= this.min_distance
43719 var color = lastPointGroup.color;
43720 if (!lastPoint || !(lastPoint && isLastPointTooClose)) {
43721 var curve = this.addPoint(point);
43723 this.drawDot({color: color, point: point});
43726 this.drawCurve({color: color, curve: curve});
43736 strokeEnd: function(e)
43738 this.strokeUpdate(e);
43739 if (typeof this.onEnd === 'function') {
43744 addPoint: function (point) {
43745 var _lastPoints = this._lastPoints;
43746 _lastPoints.push(point);
43747 if (_lastPoints.length > 2) {
43748 if (_lastPoints.length === 3) {
43749 _lastPoints.unshift(_lastPoints[0]);
43751 var widths = this.calculateCurveWidths(_lastPoints[1], _lastPoints[2]);
43752 var curve = this.Bezier.fromPoints(_lastPoints, widths, this);
43753 _lastPoints.shift();
43759 calculateCurveWidths: function (startPoint, endPoint) {
43760 var velocity = this.velocity_filter_weight * endPoint.velocityFrom(startPoint) +
43761 (1 - this.velocity_filter_weight) * this._lastVelocity;
43763 var newWidth = Math.max(this.max_width / (velocity + 1), this.min_width);
43766 start: this._lastWidth
43769 this._lastVelocity = velocity;
43770 this._lastWidth = newWidth;
43774 drawDot: function (_a) {
43775 var color = _a.color, point = _a.point;
43776 var ctx = this.canvasElCtx();
43777 var width = typeof this.dot_size === 'function' ? this.dot_size() : this.dot_size;
43779 this.drawCurveSegment(point.x, point.y, width);
43781 ctx.fillStyle = color;
43785 drawCurve: function (_a) {
43786 var color = _a.color, curve = _a.curve;
43787 var ctx = this.canvasElCtx();
43788 var widthDelta = curve.endWidth - curve.startWidth;
43789 var drawSteps = Math.floor(curve.length()) * 2;
43791 ctx.fillStyle = color;
43792 for (var i = 0; i < drawSteps; i += 1) {
43793 var t = i / drawSteps;
43799 var x = uuu * curve.startPoint.x;
43800 x += 3 * uu * t * curve.control1.x;
43801 x += 3 * u * tt * curve.control2.x;
43802 x += ttt * curve.endPoint.x;
43803 var y = uuu * curve.startPoint.y;
43804 y += 3 * uu * t * curve.control1.y;
43805 y += 3 * u * tt * curve.control2.y;
43806 y += ttt * curve.endPoint.y;
43807 var width = curve.startWidth + ttt * widthDelta;
43808 this.drawCurveSegment(x, y, width);
43814 drawCurveSegment: function (x, y, width) {
43815 var ctx = this.canvasElCtx();
43817 ctx.arc(x, y, width, 0, 2 * Math.PI, false);
43818 this.is_empty = false;
43823 var ctx = this.canvasElCtx();
43824 var canvas = this.canvasEl().dom;
43825 ctx.fillStyle = this.bg_color;
43826 ctx.clearRect(0, 0, canvas.width, canvas.height);
43827 ctx.fillRect(0, 0, canvas.width, canvas.height);
43828 this.curve_data = [];
43830 this.is_empty = true;
43835 return this.el.select('input',true).first();
43838 canvasEl: function()
43840 return this.el.select('canvas',true).first();
43843 canvasElCtx: function()
43845 return this.el.select('canvas',true).first().dom.getContext('2d');
43848 getImage: function(type)
43850 if(this.is_empty) {
43855 return this.canvasEl().dom.toDataURL('image/'+type, 1);
43858 drawFromImage: function(img_src)
43860 var img = new Image();
43862 img.onload = function(){
43863 this.canvasElCtx().drawImage(img, 0, 0);
43868 this.is_empty = false;
43871 selectImage: function()
43873 this.fileEl().dom.click();
43876 uploadImage: function(e)
43878 var reader = new FileReader();
43880 reader.onload = function(e){
43881 var img = new Image();
43882 img.onload = function(){
43884 this.canvasElCtx().drawImage(img, 0, 0);
43886 img.src = e.target.result;
43889 reader.readAsDataURL(e.target.files[0]);
43892 // Bezier Point Constructor
43893 Point: (function () {
43894 function Point(x, y, time) {
43897 this.time = time || Date.now();
43899 Point.prototype.distanceTo = function (start) {
43900 return Math.sqrt(Math.pow(this.x - start.x, 2) + Math.pow(this.y - start.y, 2));
43902 Point.prototype.equals = function (other) {
43903 return this.x === other.x && this.y === other.y && this.time === other.time;
43905 Point.prototype.velocityFrom = function (start) {
43906 return this.time !== start.time
43907 ? this.distanceTo(start) / (this.time - start.time)
43914 // Bezier Constructor
43915 Bezier: (function () {
43916 function Bezier(startPoint, control2, control1, endPoint, startWidth, endWidth) {
43917 this.startPoint = startPoint;
43918 this.control2 = control2;
43919 this.control1 = control1;
43920 this.endPoint = endPoint;
43921 this.startWidth = startWidth;
43922 this.endWidth = endWidth;
43924 Bezier.fromPoints = function (points, widths, scope) {
43925 var c2 = this.calculateControlPoints(points[0], points[1], points[2], scope).c2;
43926 var c3 = this.calculateControlPoints(points[1], points[2], points[3], scope).c1;
43927 return new Bezier(points[1], c2, c3, points[2], widths.start, widths.end);
43929 Bezier.calculateControlPoints = function (s1, s2, s3, scope) {
43930 var dx1 = s1.x - s2.x;
43931 var dy1 = s1.y - s2.y;
43932 var dx2 = s2.x - s3.x;
43933 var dy2 = s2.y - s3.y;
43934 var m1 = { x: (s1.x + s2.x) / 2.0, y: (s1.y + s2.y) / 2.0 };
43935 var m2 = { x: (s2.x + s3.x) / 2.0, y: (s2.y + s3.y) / 2.0 };
43936 var l1 = Math.sqrt(dx1 * dx1 + dy1 * dy1);
43937 var l2 = Math.sqrt(dx2 * dx2 + dy2 * dy2);
43938 var dxm = m1.x - m2.x;
43939 var dym = m1.y - m2.y;
43940 var k = l2 / (l1 + l2);
43941 var cm = { x: m2.x + dxm * k, y: m2.y + dym * k };
43942 var tx = s2.x - cm.x;
43943 var ty = s2.y - cm.y;
43945 c1: new scope.Point(m1.x + tx, m1.y + ty),
43946 c2: new scope.Point(m2.x + tx, m2.y + ty)
43949 Bezier.prototype.length = function () {
43954 for (var i = 0; i <= steps; i += 1) {
43956 var cx = this.point(t, this.startPoint.x, this.control1.x, this.control2.x, this.endPoint.x);
43957 var cy = this.point(t, this.startPoint.y, this.control1.y, this.control2.y, this.endPoint.y);
43959 var xdiff = cx - px;
43960 var ydiff = cy - py;
43961 length += Math.sqrt(xdiff * xdiff + ydiff * ydiff);
43968 Bezier.prototype.point = function (t, start, c1, c2, end) {
43969 return (start * (1.0 - t) * (1.0 - t) * (1.0 - t))
43970 + (3.0 * c1 * (1.0 - t) * (1.0 - t) * t)
43971 + (3.0 * c2 * (1.0 - t) * t * t)
43972 + (end * t * t * t);
43977 throttleStroke: function(fn, wait) {
43978 if (wait === void 0) { wait = 250; }
43980 var timeout = null;
43984 var later = function () {
43985 previous = Date.now();
43987 result = fn.apply(storedContext, storedArgs);
43989 storedContext = null;
43993 return function wrapper() {
43995 for (var _i = 0; _i < arguments.length; _i++) {
43996 args[_i] = arguments[_i];
43998 var now = Date.now();
43999 var remaining = wait - (now - previous);
44000 storedContext = this;
44002 if (remaining <= 0 || remaining > wait) {
44004 clearTimeout(timeout);
44008 result = fn.apply(storedContext, storedArgs);
44010 storedContext = null;
44014 else if (!timeout) {
44015 timeout = window.setTimeout(later, remaining);