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;
2522 move_card.parent().removeCard(move_card);
2525 var dom = move_card.el.dom;
2526 dom.style.width = ''; // clear with - which is set by drag.
2528 if (next_to_card !== false && next_to_card !== true && next_to_card.el.dom.parentNode) {
2529 var cardel = next_to_card.el.dom;
2531 if (position == 'above' ) {
2532 cardel.parentNode.insertBefore(dom, cardel);
2533 } else if (cardel.nextSibling) {
2534 cardel.parentNode.insertBefore(dom,cardel.nextSibling);
2536 cardel.parentNode.append(dom);
2539 // card container???
2540 this.containerEl.dom.append(dom);
2543 //FIXME HANDLE card = true
2545 // add this to the correct place in items.
2547 // remove Card from items.
2550 if (this.items.length) {
2552 //Roo.log([info.items_n, info.position, this.items.length]);
2553 for (var i =0; i < this.items.length; i++) {
2554 if (i == to_items_n && position == 'above') {
2555 nitems.push(move_card);
2557 nitems.push(this.items[i]);
2558 if (i == to_items_n && position == 'below') {
2559 nitems.push(move_card);
2562 this.items = nitems;
2563 Roo.log(this.items);
2565 this.items.push(move_card);
2568 move_card.parentId = this.id;
2574 removeCard : function(c)
2576 this.items = this.items.filter(function(e) { return e != c });
2579 dom.parentNode.removeChild(dom);
2580 dom.style.width = ''; // clear with - which is set by drag.
2585 /** Decide whether to drop above or below a View node. */
2586 getDropPoint : function(e, n, dd)
2591 if (n == this.containerEl.dom) {
2594 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
2595 var c = t + (b - t) / 2;
2596 var y = Roo.lib.Event.getPageY(e);
2603 onToggleCollapse : function(e)
2605 if (this.collapsed) {
2606 this.el.select('.roo-collapse-toggle').removeClass('collapsed');
2607 this.collapsableEl.addClass('show');
2608 this.collapsed = false;
2611 this.el.select('.roo-collapse-toggle').addClass('collapsed');
2612 this.collapsableEl.removeClass('show');
2613 this.collapsed = true;
2618 onToggleRotate : function(e)
2620 this.collapsableEl.removeClass('show');
2621 this.footerEl.removeClass('d-none');
2622 this.el.removeClass('roo-card-rotated');
2623 this.el.removeClass('d-none');
2626 this.collapsableEl.addClass('show');
2627 this.rotated = false;
2628 this.fireEvent('rotate', this, this.rotated);
2631 this.el.addClass('roo-card-rotated');
2632 this.footerEl.addClass('d-none');
2633 this.el.select('.roo-collapsable').removeClass('show');
2635 this.rotated = true;
2636 this.fireEvent('rotate', this, this.rotated);
2640 dropPlaceHolder: function (action, info, data)
2642 if (this.dropEl === false) {
2643 this.dropEl = Roo.DomHelper.append(this.containerEl, {
2647 this.dropEl.removeClass(['d-none', 'd-block']);
2648 if (action == 'hide') {
2650 this.dropEl.addClass('d-none');
2653 // FIXME - info.card == true!!!
2654 this.dropEl.dom.parentNode.removeChild(this.dropEl.dom);
2656 if (info.card !== true) {
2657 var cardel = info.card.el.dom;
2659 if (info.position == 'above') {
2660 cardel.parentNode.insertBefore(this.dropEl.dom, cardel);
2661 } else if (cardel.nextSibling) {
2662 cardel.parentNode.insertBefore(this.dropEl.dom,cardel.nextSibling);
2664 cardel.parentNode.append(this.dropEl.dom);
2667 // card container???
2668 this.containerEl.dom.append(this.dropEl.dom);
2671 this.dropEl.addClass('d-block roo-card-dropzone');
2673 this.dropEl.setHeight( Roo.get(data.ddel).getHeight() );
2680 setHeaderText: function(html)
2682 this.headerContainerEl.dom.innerHTML = html;
2691 * Card header - holder for the card header elements.
2696 * @class Roo.bootstrap.CardHeader
2697 * @extends Roo.bootstrap.Element
2698 * Bootstrap CardHeader class
2700 * Create a new Card Header - that you can embed children into
2701 * @param {Object} config The config object
2704 Roo.bootstrap.CardHeader = function(config){
2705 Roo.bootstrap.CardHeader.superclass.constructor.call(this, config);
2708 Roo.extend(Roo.bootstrap.CardHeader, Roo.bootstrap.Element, {
2711 container_method : 'getCardHeader'
2724 * Card footer - holder for the card footer elements.
2729 * @class Roo.bootstrap.CardFooter
2730 * @extends Roo.bootstrap.Element
2731 * Bootstrap CardFooter class
2733 * Create a new Card Footer - that you can embed children into
2734 * @param {Object} config The config object
2737 Roo.bootstrap.CardFooter = function(config){
2738 Roo.bootstrap.CardFooter.superclass.constructor.call(this, config);
2741 Roo.extend(Roo.bootstrap.CardFooter, Roo.bootstrap.Element, {
2744 container_method : 'getCardFooter'
2757 * Card header - holder for the card header elements.
2762 * @class Roo.bootstrap.CardImageTop
2763 * @extends Roo.bootstrap.Element
2764 * Bootstrap CardImageTop class
2766 * Create a new Card Image Top container
2767 * @param {Object} config The config object
2770 Roo.bootstrap.CardImageTop = function(config){
2771 Roo.bootstrap.CardImageTop.superclass.constructor.call(this, config);
2774 Roo.extend(Roo.bootstrap.CardImageTop, Roo.bootstrap.Element, {
2777 container_method : 'getCardImageTop'
2795 * @class Roo.bootstrap.Img
2796 * @extends Roo.bootstrap.Component
2797 * Bootstrap Img class
2798 * @cfg {Boolean} imgResponsive false | true
2799 * @cfg {String} border rounded | circle | thumbnail
2800 * @cfg {String} src image source
2801 * @cfg {String} alt image alternative text
2802 * @cfg {String} href a tag href
2803 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
2804 * @cfg {String} xsUrl xs image source
2805 * @cfg {String} smUrl sm image source
2806 * @cfg {String} mdUrl md image source
2807 * @cfg {String} lgUrl lg image source
2810 * Create a new Input
2811 * @param {Object} config The config object
2814 Roo.bootstrap.Img = function(config){
2815 Roo.bootstrap.Img.superclass.constructor.call(this, config);
2821 * The img click event for the img.
2822 * @param {Roo.EventObject} e
2828 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
2830 imgResponsive: true,
2840 getAutoCreate : function()
2842 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
2843 return this.createSingleImg();
2848 cls: 'roo-image-responsive-group',
2853 Roo.each(['xs', 'sm', 'md', 'lg'], function(size){
2855 if(!_this[size + 'Url']){
2861 cls: (_this.imgResponsive) ? 'img-responsive' : '',
2862 html: _this.html || cfg.html,
2863 src: _this[size + 'Url']
2866 img.cls += ' roo-image-responsive-' + size;
2868 var s = ['xs', 'sm', 'md', 'lg'];
2870 s.splice(s.indexOf(size), 1);
2872 Roo.each(s, function(ss){
2873 img.cls += ' hidden-' + ss;
2876 if (['rounded','circle','thumbnail'].indexOf(_this.border)>-1) {
2877 cfg.cls += ' img-' + _this.border;
2881 cfg.alt = _this.alt;
2894 a.target = _this.target;
2898 cfg.cn.push((_this.href) ? a : img);
2905 createSingleImg : function()
2909 cls: (this.imgResponsive) ? 'img-responsive' : '',
2911 src : 'about:blank' // just incase src get's set to undefined?!?
2914 cfg.html = this.html || cfg.html;
2916 cfg.src = this.src || cfg.src;
2918 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
2919 cfg.cls += ' img-' + this.border;
2936 a.target = this.target;
2941 return (this.href) ? a : cfg;
2944 initEvents: function()
2947 this.el.on('click', this.onClick, this);
2952 onClick : function(e)
2954 Roo.log('img onclick');
2955 this.fireEvent('click', this, e);
2958 * Sets the url of the image - used to update it
2959 * @param {String} url the url of the image
2962 setSrc : function(url)
2966 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
2967 this.el.dom.src = url;
2971 this.el.select('img', true).first().dom.src = url;
2987 * @class Roo.bootstrap.Link
2988 * @extends Roo.bootstrap.Component
2989 * Bootstrap Link Class
2990 * @cfg {String} alt image alternative text
2991 * @cfg {String} href a tag href
2992 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
2993 * @cfg {String} html the content of the link.
2994 * @cfg {String} anchor name for the anchor link
2995 * @cfg {String} fa - favicon
2997 * @cfg {Boolean} preventDefault (true | false) default false
3001 * Create a new Input
3002 * @param {Object} config The config object
3005 Roo.bootstrap.Link = function(config){
3006 Roo.bootstrap.Link.superclass.constructor.call(this, config);
3012 * The img click event for the img.
3013 * @param {Roo.EventObject} e
3019 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
3023 preventDefault: false,
3029 getAutoCreate : function()
3031 var html = this.html || '';
3033 if (this.fa !== false) {
3034 html = '<i class="fa fa-' + this.fa + '"></i>';
3039 // anchor's do not require html/href...
3040 if (this.anchor === false) {
3042 cfg.href = this.href || '#';
3044 cfg.name = this.anchor;
3045 if (this.html !== false || this.fa !== false) {
3048 if (this.href !== false) {
3049 cfg.href = this.href;
3053 if(this.alt !== false){
3058 if(this.target !== false) {
3059 cfg.target = this.target;
3065 initEvents: function() {
3067 if(!this.href || this.preventDefault){
3068 this.el.on('click', this.onClick, this);
3072 onClick : function(e)
3074 if(this.preventDefault){
3077 //Roo.log('img onclick');
3078 this.fireEvent('click', this, e);
3091 * @class Roo.bootstrap.Header
3092 * @extends Roo.bootstrap.Component
3093 * Bootstrap Header class
3094 * @cfg {String} html content of header
3095 * @cfg {Number} level (1|2|3|4|5|6) default 1
3098 * Create a new Header
3099 * @param {Object} config The config object
3103 Roo.bootstrap.Header = function(config){
3104 Roo.bootstrap.Header.superclass.constructor.call(this, config);
3107 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
3115 getAutoCreate : function(){
3120 tag: 'h' + (1 *this.level),
3121 html: this.html || ''
3133 * Ext JS Library 1.1.1
3134 * Copyright(c) 2006-2007, Ext JS, LLC.
3136 * Originally Released Under LGPL - original licence link has changed is not relivant.
3139 * <script type="text/javascript">
3143 * @class Roo.bootstrap.MenuMgr
3144 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
3147 Roo.bootstrap.MenuMgr = function(){
3148 var menus, active, groups = {}, attached = false, lastShow = new Date();
3150 // private - called when first menu is created
3153 active = new Roo.util.MixedCollection();
3154 Roo.get(document).addKeyListener(27, function(){
3155 if(active.length > 0){
3163 if(active && active.length > 0){
3164 var c = active.clone();
3174 if(active.length < 1){
3175 Roo.get(document).un("mouseup", onMouseDown);
3183 var last = active.last();
3184 lastShow = new Date();
3187 Roo.get(document).on("mouseup", onMouseDown);
3192 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
3193 m.parentMenu.activeChild = m;
3194 }else if(last && last.isVisible()){
3195 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
3200 function onBeforeHide(m){
3202 m.activeChild.hide();
3204 if(m.autoHideTimer){
3205 clearTimeout(m.autoHideTimer);
3206 delete m.autoHideTimer;
3211 function onBeforeShow(m){
3212 var pm = m.parentMenu;
3213 if(!pm && !m.allowOtherMenus){
3215 }else if(pm && pm.activeChild && active != m){
3216 pm.activeChild.hide();
3220 // private this should really trigger on mouseup..
3221 function onMouseDown(e){
3222 Roo.log("on Mouse Up");
3224 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".dropdown-menu") && !e.getTarget('.user-menu')){
3225 Roo.log("MenuManager hideAll");
3234 function onBeforeCheck(mi, state){
3236 var g = groups[mi.group];
3237 for(var i = 0, l = g.length; i < l; i++){
3239 g[i].setChecked(false);
3248 * Hides all menus that are currently visible
3250 hideAll : function(){
3255 register : function(menu){
3259 menus[menu.id] = menu;
3260 menu.on("beforehide", onBeforeHide);
3261 menu.on("hide", onHide);
3262 menu.on("beforeshow", onBeforeShow);
3263 menu.on("show", onShow);
3265 if(g && menu.events["checkchange"]){
3269 groups[g].push(menu);
3270 menu.on("checkchange", onCheck);
3275 * Returns a {@link Roo.menu.Menu} object
3276 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
3277 * be used to generate and return a new Menu instance.
3279 get : function(menu){
3280 if(typeof menu == "string"){ // menu id
3282 }else if(menu.events){ // menu instance
3285 /*else if(typeof menu.length == 'number'){ // array of menu items?
3286 return new Roo.bootstrap.Menu({items:menu});
3287 }else{ // otherwise, must be a config
3288 return new Roo.bootstrap.Menu(menu);
3295 unregister : function(menu){
3296 delete menus[menu.id];
3297 menu.un("beforehide", onBeforeHide);
3298 menu.un("hide", onHide);
3299 menu.un("beforeshow", onBeforeShow);
3300 menu.un("show", onShow);
3302 if(g && menu.events["checkchange"]){
3303 groups[g].remove(menu);
3304 menu.un("checkchange", onCheck);
3309 registerCheckable : function(menuItem){
3310 var g = menuItem.group;
3315 groups[g].push(menuItem);
3316 menuItem.on("beforecheckchange", onBeforeCheck);
3321 unregisterCheckable : function(menuItem){
3322 var g = menuItem.group;
3324 groups[g].remove(menuItem);
3325 menuItem.un("beforecheckchange", onBeforeCheck);
3337 * @class Roo.bootstrap.Menu
3338 * @extends Roo.bootstrap.Component
3339 * Bootstrap Menu class - container for MenuItems
3340 * @cfg {String} type (dropdown|treeview|submenu) type of menu
3341 * @cfg {bool} hidden if the menu should be hidden when rendered.
3342 * @cfg {bool} stopEvent (true|false) Stop event after trigger press (default true)
3343 * @cfg {bool} isLink (true|false) the menu has link disable auto expand and collaspe (default false)
3347 * @param {Object} config The config object
3351 Roo.bootstrap.Menu = function(config){
3352 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
3353 if (this.registerMenu && this.type != 'treeview') {
3354 Roo.bootstrap.MenuMgr.register(this);
3361 * Fires before this menu is displayed (return false to block)
3362 * @param {Roo.menu.Menu} this
3367 * Fires before this menu is hidden (return false to block)
3368 * @param {Roo.menu.Menu} this
3373 * Fires after this menu is displayed
3374 * @param {Roo.menu.Menu} this
3379 * Fires after this menu is hidden
3380 * @param {Roo.menu.Menu} this
3385 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
3386 * @param {Roo.menu.Menu} this
3387 * @param {Roo.menu.Item} menuItem The menu item that was clicked
3388 * @param {Roo.EventObject} e
3393 * Fires when the mouse is hovering over this menu
3394 * @param {Roo.menu.Menu} this
3395 * @param {Roo.EventObject} e
3396 * @param {Roo.menu.Item} menuItem The menu item that was clicked
3401 * Fires when the mouse exits this menu
3402 * @param {Roo.menu.Menu} this
3403 * @param {Roo.EventObject} e
3404 * @param {Roo.menu.Item} menuItem The menu item that was clicked
3409 * Fires when a menu item contained in this menu is clicked
3410 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
3411 * @param {Roo.EventObject} e
3415 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
3418 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
3422 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
3425 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
3427 registerMenu : true,
3429 menuItems :false, // stores the menu items..
3439 getChildContainer : function() {
3443 getAutoCreate : function(){
3445 //if (['right'].indexOf(this.align)!==-1) {
3446 // cfg.cn[1].cls += ' pull-right'
3452 cls : 'dropdown-menu' ,
3453 style : 'z-index:1000'
3457 if (this.type === 'submenu') {
3458 cfg.cls = 'submenu active';
3460 if (this.type === 'treeview') {
3461 cfg.cls = 'treeview-menu';
3466 initEvents : function() {
3468 // Roo.log("ADD event");
3469 // Roo.log(this.triggerEl.dom);
3471 this.triggerEl.on('click', this.onTriggerClick, this);
3473 this.triggerEl.on(Roo.isTouch ? 'touchstart' : 'mouseup', this.onTriggerPress, this);
3476 if (this.triggerEl.hasClass('nav-item')) {
3477 // dropdown toggle on the 'a' in BS4?
3478 this.triggerEl.select('.nav-link',true).first().addClass('dropdown-toggle');
3480 this.triggerEl.addClass('dropdown-toggle');
3483 this.el.on('touchstart' , this.onTouch, this);
3485 this.el.on('click' , this.onClick, this);
3487 this.el.on("mouseover", this.onMouseOver, this);
3488 this.el.on("mouseout", this.onMouseOut, this);
3492 findTargetItem : function(e)
3494 var t = e.getTarget(".dropdown-menu-item", this.el, true);
3498 //Roo.log(t); Roo.log(t.id);
3500 //Roo.log(this.menuitems);
3501 return this.menuitems.get(t.id);
3503 //return this.items.get(t.menuItemId);
3509 onTouch : function(e)
3511 Roo.log("menu.onTouch");
3512 //e.stopEvent(); this make the user popdown broken
3516 onClick : function(e)
3518 Roo.log("menu.onClick");
3520 var t = this.findTargetItem(e);
3521 if(!t || t.isContainer){
3526 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
3527 if(t == this.activeItem && t.shouldDeactivate(e)){
3528 this.activeItem.deactivate();
3529 delete this.activeItem;
3533 this.setActiveItem(t, true);
3541 Roo.log('pass click event');
3545 this.fireEvent("click", this, t, e);
3549 if(!t.href.length || t.href == '#'){
3550 (function() { _this.hide(); }).defer(100);
3555 onMouseOver : function(e){
3556 var t = this.findTargetItem(e);
3559 // if(t.canActivate && !t.disabled){
3560 // this.setActiveItem(t, true);
3564 this.fireEvent("mouseover", this, e, t);
3566 isVisible : function(){
3567 return !this.hidden;
3569 onMouseOut : function(e){
3570 var t = this.findTargetItem(e);
3573 // if(t == this.activeItem && t.shouldDeactivate(e)){
3574 // this.activeItem.deactivate();
3575 // delete this.activeItem;
3578 this.fireEvent("mouseout", this, e, t);
3583 * Displays this menu relative to another element
3584 * @param {String/HTMLElement/Roo.Element} element The element to align to
3585 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
3586 * the element (defaults to this.defaultAlign)
3587 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
3589 show : function(el, pos, parentMenu)
3591 if (false === this.fireEvent("beforeshow", this)) {
3592 Roo.log("show canceled");
3595 this.parentMenu = parentMenu;
3600 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
3603 * Displays this menu at a specific xy position
3604 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
3605 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
3607 showAt : function(xy, parentMenu, /* private: */_e){
3608 this.parentMenu = parentMenu;
3613 this.fireEvent("beforeshow", this);
3614 //xy = this.el.adjustForConstraints(xy);
3618 this.hideMenuItems();
3619 this.hidden = false;
3620 this.triggerEl.addClass('open');
3621 this.el.addClass('show');
3623 // reassign x when hitting right
3624 if(this.el.getWidth() + xy[0] >= Roo.lib.Dom.getViewWidth()){
3625 xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
3628 // reassign y when hitting bottom
3629 if(this.el.getHeight() + xy[1] >= Roo.lib.Dom.getViewHeight()){
3630 xy[1] = xy[1] - this.el.getHeight() - this.triggerEl.getHeight();
3633 // but the list may align on trigger left or trigger top... should it be a properity?
3635 if(this.el.getStyle('top') != 'auto' && this.el.getStyle('top').slice(-1) != "%"){
3640 this.fireEvent("show", this);
3646 this.doFocus.defer(50, this);
3650 doFocus : function(){
3652 this.focusEl.focus();
3657 * Hides this menu and optionally all parent menus
3658 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
3660 hide : function(deep)
3662 if (false === this.fireEvent("beforehide", this)) {
3663 Roo.log("hide canceled");
3666 this.hideMenuItems();
3667 if(this.el && this.isVisible()){
3669 if(this.activeItem){
3670 this.activeItem.deactivate();
3671 this.activeItem = null;
3673 this.triggerEl.removeClass('open');;
3674 this.el.removeClass('show');
3676 this.fireEvent("hide", this);
3678 if(deep === true && this.parentMenu){
3679 this.parentMenu.hide(true);
3683 onTriggerClick : function(e)
3685 Roo.log('trigger click');
3687 var target = e.getTarget();
3689 Roo.log(target.nodeName.toLowerCase());
3691 if(target.nodeName.toLowerCase() === 'i'){
3697 onTriggerPress : function(e)
3699 Roo.log('trigger press');
3700 //Roo.log(e.getTarget());
3701 // Roo.log(this.triggerEl.dom);
3703 // trigger only occurs on normal menu's -- if it's a treeview or dropdown... do not hide/show..
3704 var pel = Roo.get(e.getTarget());
3705 if (pel.findParent('.dropdown-menu') || pel.findParent('.treeview-menu') ) {
3706 Roo.log('is treeview or dropdown?');
3710 if(e.getTarget().nodeName.toLowerCase() !== 'i' && this.isLink){
3714 if (this.isVisible()) {
3719 this.show(this.triggerEl, '?', false);
3722 if(this.stopEvent || e.getTarget().nodeName.toLowerCase() === 'i'){
3729 hideMenuItems : function()
3731 Roo.log("hide Menu Items");
3736 this.el.select('.open',true).each(function(aa) {
3738 aa.removeClass('open');
3742 addxtypeChild : function (tree, cntr) {
3743 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
3745 this.menuitems.add(comp);
3757 this.getEl().dom.innerHTML = '';
3758 this.menuitems.clear();
3772 * @class Roo.bootstrap.MenuItem
3773 * @extends Roo.bootstrap.Component
3774 * Bootstrap MenuItem class
3775 * @cfg {String} html the menu label
3776 * @cfg {String} href the link
3777 * @cfg {Boolean} preventDefault do not trigger A href on clicks (default false).
3778 * @cfg {Boolean} isContainer is it a container - just returns a drop down item..
3779 * @cfg {Boolean} active used on sidebars to highlight active itesm
3780 * @cfg {String} fa favicon to show on left of menu item.
3781 * @cfg {Roo.bootsrap.Menu} menu the child menu.
3785 * Create a new MenuItem
3786 * @param {Object} config The config object
3790 Roo.bootstrap.MenuItem = function(config){
3791 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
3796 * The raw click event for the entire grid.
3797 * @param {Roo.bootstrap.MenuItem} this
3798 * @param {Roo.EventObject} e
3804 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
3808 preventDefault: false,
3809 isContainer : false,
3813 getAutoCreate : function(){
3815 if(this.isContainer){
3818 cls: 'dropdown-menu-item '
3828 cls : 'dropdown-item',
3833 if (this.fa !== false) {
3836 cls : 'fa fa-' + this.fa
3845 cls: 'dropdown-menu-item',
3848 if (this.parent().type == 'treeview') {
3849 cfg.cls = 'treeview-menu';
3852 cfg.cls += ' active';
3857 anc.href = this.href || cfg.cn[0].href ;
3858 ctag.html = this.html || cfg.cn[0].html ;
3862 initEvents: function()
3864 if (this.parent().type == 'treeview') {
3865 this.el.select('a').on('click', this.onClick, this);
3869 this.menu.parentType = this.xtype;
3870 this.menu.triggerEl = this.el;
3871 this.menu = this.addxtype(Roo.apply({}, this.menu));
3875 onClick : function(e)
3877 Roo.log('item on click ');
3879 if(this.preventDefault){
3882 //this.parent().hideMenuItems();
3884 this.fireEvent('click', this, e);
3903 * @class Roo.bootstrap.MenuSeparator
3904 * @extends Roo.bootstrap.Component
3905 * Bootstrap MenuSeparator class
3908 * Create a new MenuItem
3909 * @param {Object} config The config object
3913 Roo.bootstrap.MenuSeparator = function(config){
3914 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
3917 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
3919 getAutoCreate : function(){
3938 * @class Roo.bootstrap.Modal
3939 * @extends Roo.bootstrap.Component
3940 * Bootstrap Modal class
3941 * @cfg {String} title Title of dialog
3942 * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
3943 * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method adn
3944 * @cfg {Boolean} specificTitle default false
3945 * @cfg {Array} buttons Array of buttons or standard button set..
3946 * @cfg {String} buttonPosition (left|right|center) default right (DEPRICATED) - use mr-auto on buttons to put them on the left
3947 * @cfg {Boolean} animate default true
3948 * @cfg {Boolean} allow_close default true
3949 * @cfg {Boolean} fitwindow default false
3950 * @cfg {Boolean} bodyOverflow should the body element have overflow auto added default false
3951 * @cfg {Number} width fixed width - usefull for chrome extension only really.
3952 * @cfg {Number} height fixed height - usefull for chrome extension only really.
3953 * @cfg {String} size (sm|lg|xl) default empty
3954 * @cfg {Number} max_width set the max width of modal
3955 * @cfg {Boolean} editableTitle can the title be edited
3960 * Create a new Modal Dialog
3961 * @param {Object} config The config object
3964 Roo.bootstrap.Modal = function(config){
3965 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
3970 * The raw btnclick event for the button
3971 * @param {Roo.EventObject} e
3976 * Fire when dialog resize
3977 * @param {Roo.bootstrap.Modal} this
3978 * @param {Roo.EventObject} e
3982 * @event titlechanged
3983 * Fire when the editable title has been changed
3984 * @param {Roo.bootstrap.Modal} this
3985 * @param {Roo.EventObject} value
3987 "titlechanged" : true
3990 this.buttons = this.buttons || [];
3993 this.tmpl = Roo.factory(this.tmpl);
3998 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
4000 title : 'test dialog',
4010 specificTitle: false,
4012 buttonPosition: 'right',
4034 editableTitle : false,
4036 onRender : function(ct, position)
4038 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
4041 var cfg = Roo.apply({}, this.getAutoCreate());
4044 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
4046 //if (!cfg.name.length) {
4050 cfg.cls += ' ' + this.cls;
4053 cfg.style = this.style;
4055 this.el = Roo.get(document.body).createChild(cfg, position);
4057 //var type = this.el.dom.type;
4060 if(this.tabIndex !== undefined){
4061 this.el.dom.setAttribute('tabIndex', this.tabIndex);
4064 this.dialogEl = this.el.select('.modal-dialog',true).first();
4065 this.bodyEl = this.el.select('.modal-body',true).first();
4066 this.closeEl = this.el.select('.modal-header .close', true).first();
4067 this.headerEl = this.el.select('.modal-header',true).first();
4068 this.titleEl = this.el.select('.modal-title',true).first();
4069 this.footerEl = this.el.select('.modal-footer',true).first();
4071 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
4073 //this.el.addClass("x-dlg-modal");
4075 if (this.buttons.length) {
4076 Roo.each(this.buttons, function(bb) {
4077 var b = Roo.apply({}, bb);
4078 b.xns = b.xns || Roo.bootstrap;
4079 b.xtype = b.xtype || 'Button';
4080 if (typeof(b.listeners) == 'undefined') {
4081 b.listeners = { click : this.onButtonClick.createDelegate(this) };
4084 var btn = Roo.factory(b);
4086 btn.render(this.getButtonContainer());
4090 // render the children.
4093 if(typeof(this.items) != 'undefined'){
4094 var items = this.items;
4097 for(var i =0;i < items.length;i++) {
4098 nitems.push(this.addxtype(Roo.apply({}, items[i])));
4102 this.items = nitems;
4104 // where are these used - they used to be body/close/footer
4108 //this.el.addClass([this.fieldClass, this.cls]);
4112 getAutoCreate : function()
4114 // we will default to modal-body-overflow - might need to remove or make optional later.
4116 cls : 'modal-body ' + (this.bodyOverflow ? 'overflow-auto' : ''),
4117 html : this.html || ''
4122 cls : 'modal-title',
4126 if(this.specificTitle){ // WTF is this?
4131 if (this.allow_close && Roo.bootstrap.version == 3) {
4141 if (this.editableTitle) {
4143 cls: 'form-control roo-editable-title d-none',
4149 if (this.allow_close && Roo.bootstrap.version == 4) {
4159 if(this.size.length){
4160 size = 'modal-' + this.size;
4163 var footer = Roo.bootstrap.version == 3 ?
4165 cls : 'modal-footer',
4169 cls: 'btn-' + this.buttonPosition
4174 { // BS4 uses mr-auto on left buttons....
4175 cls : 'modal-footer'
4186 cls: "modal-dialog " + size,
4189 cls : "modal-content",
4192 cls : 'modal-header',
4207 modal.cls += ' fade';
4213 getChildContainer : function() {
4218 getButtonContainer : function() {
4220 return Roo.bootstrap.version == 4 ?
4221 this.el.select('.modal-footer',true).first()
4222 : this.el.select('.modal-footer div',true).first();
4225 initEvents : function()
4227 if (this.allow_close) {
4228 this.closeEl.on('click', this.hide, this);
4230 Roo.EventManager.onWindowResize(this.resize, this, true);
4231 if (this.editableTitle) {
4232 this.headerEditEl = this.headerEl.select('.form-control',true).first();
4233 this.headerEl.on('click', function() { this.toggleHeaderInput(true) } , this);
4234 this.headerEditEl.on('keyup', function(e) {
4235 if([ e.RETURN , e.TAB , e.ESC ].indexOf(e.keyCode) > -1) {
4236 this.toggleHeaderInput(false)
4239 this.headerEditEl.on('blur', function(e) {
4240 this.toggleHeaderInput(false)
4249 this.maskEl.setSize(
4250 Roo.lib.Dom.getViewWidth(true),
4251 Roo.lib.Dom.getViewHeight(true)
4254 if (this.fitwindow) {
4256 this.dialogEl.setStyle( { 'max-width' : '100%' });
4258 this.width || Roo.lib.Dom.getViewportWidth(true) - 30,
4259 this.height || Roo.lib.Dom.getViewportHeight(true) // catering margin-top 30 margin-bottom 30
4264 if(this.max_width !== 0) {
4266 var w = Math.min(this.max_width, Roo.lib.Dom.getViewportWidth(true) - 30);
4269 this.setSize(w, this.height);
4273 if(this.max_height) {
4274 this.setSize(w,Math.min(
4276 Roo.lib.Dom.getViewportHeight(true) - 60
4282 if(!this.fit_content) {
4283 this.setSize(w, Roo.lib.Dom.getViewportHeight(true) - 60);
4287 this.setSize(w, Math.min(
4289 this.headerEl.getHeight() +
4290 this.footerEl.getHeight() +
4291 this.getChildHeight(this.bodyEl.dom.childNodes),
4292 Roo.lib.Dom.getViewportHeight(true) - 60)
4298 setSize : function(w,h)
4309 if (!this.rendered) {
4312 this.toggleHeaderInput(false);
4313 //this.el.setStyle('display', 'block');
4314 this.el.removeClass('hideing');
4315 this.el.dom.style.display='block';
4317 Roo.get(document.body).addClass('modal-open');
4319 if(this.animate){ // element has 'fade' - so stuff happens after .3s ?- not sure why the delay?
4322 this.el.addClass('show');
4323 this.el.addClass('in');
4326 this.el.addClass('show');
4327 this.el.addClass('in');
4330 // not sure how we can show data in here..
4332 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
4335 Roo.get(document.body).addClass("x-body-masked");
4337 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
4338 this.maskEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
4339 this.maskEl.dom.style.display = 'block';
4340 this.maskEl.addClass('show');
4345 this.fireEvent('show', this);
4347 // set zindex here - otherwise it appears to be ignored...
4348 this.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
4351 this.items.forEach( function(e) {
4352 e.layout ? e.layout() : false;
4360 if(this.fireEvent("beforehide", this) !== false){
4362 this.maskEl.removeClass('show');
4364 this.maskEl.dom.style.display = '';
4365 Roo.get(document.body).removeClass("x-body-masked");
4366 this.el.removeClass('in');
4367 this.el.select('.modal-dialog', true).first().setStyle('transform','');
4369 if(this.animate){ // why
4370 this.el.addClass('hideing');
4371 this.el.removeClass('show');
4373 if (!this.el.hasClass('hideing')) {
4374 return; // it's been shown again...
4377 this.el.dom.style.display='';
4379 Roo.get(document.body).removeClass('modal-open');
4380 this.el.removeClass('hideing');
4384 this.el.removeClass('show');
4385 this.el.dom.style.display='';
4386 Roo.get(document.body).removeClass('modal-open');
4389 this.fireEvent('hide', this);
4392 isVisible : function()
4395 return this.el.hasClass('show') && !this.el.hasClass('hideing');
4399 addButton : function(str, cb)
4403 var b = Roo.apply({}, { html : str } );
4404 b.xns = b.xns || Roo.bootstrap;
4405 b.xtype = b.xtype || 'Button';
4406 if (typeof(b.listeners) == 'undefined') {
4407 b.listeners = { click : cb.createDelegate(this) };
4410 var btn = Roo.factory(b);
4412 btn.render(this.getButtonContainer());
4418 setDefaultButton : function(btn)
4420 //this.el.select('.modal-footer').()
4423 resizeTo: function(w,h)
4425 this.dialogEl.setWidth(w);
4427 var diff = this.headerEl.getHeight() + this.footerEl.getHeight() + 60; // dialog margin-bottom: 30
4429 this.bodyEl.setHeight(h - diff);
4431 this.fireEvent('resize', this);
4434 setContentSize : function(w, h)
4438 onButtonClick: function(btn,e)
4441 this.fireEvent('btnclick', btn.name, e);
4444 * Set the title of the Dialog
4445 * @param {String} str new Title
4447 setTitle: function(str) {
4448 this.titleEl.dom.innerHTML = str;
4452 * Set the body of the Dialog
4453 * @param {String} str new Title
4455 setBody: function(str) {
4456 this.bodyEl.dom.innerHTML = str;
4459 * Set the body of the Dialog using the template
4460 * @param {Obj} data - apply this data to the template and replace the body contents.
4462 applyBody: function(obj)
4465 Roo.log("Error - using apply Body without a template");
4468 this.tmpl.overwrite(this.bodyEl, obj);
4471 getChildHeight : function(child_nodes)
4475 child_nodes.length == 0
4480 var child_height = 0;
4482 for(var i = 0; i < child_nodes.length; i++) {
4485 * for modal with tabs...
4486 if(child_nodes[i].classList.contains('roo-layout-panel')) {
4488 var layout_childs = child_nodes[i].childNodes;
4490 for(var j = 0; j < layout_childs.length; j++) {
4492 if(layout_childs[j].classList.contains('roo-layout-panel-body')) {
4494 var layout_body_childs = layout_childs[j].childNodes;
4496 for(var k = 0; k < layout_body_childs.length; k++) {
4498 if(layout_body_childs[k].classList.contains('navbar')) {
4499 child_height += layout_body_childs[k].offsetHeight;
4503 if(layout_body_childs[k].classList.contains('roo-layout-tabs-body')) {
4505 var layout_body_tab_childs = layout_body_childs[k].childNodes;
4507 for(var m = 0; m < layout_body_tab_childs.length; m++) {
4509 if(layout_body_tab_childs[m].classList.contains('roo-layout-active-content')) {
4510 child_height += this.getChildHeight(layout_body_tab_childs[m].childNodes);
4525 child_height += child_nodes[i].offsetHeight;
4526 // Roo.log(child_nodes[i].offsetHeight);
4529 return child_height;
4531 toggleHeaderInput : function(is_edit)
4533 if (!this.editableTitle) {
4534 return; // not editable.
4536 if (is_edit && this.is_header_editing) {
4537 return; // already editing..
4541 this.headerEditEl.dom.value = this.title;
4542 this.headerEditEl.removeClass('d-none');
4543 this.headerEditEl.dom.focus();
4544 this.titleEl.addClass('d-none');
4546 this.is_header_editing = true;
4549 // flip back to not editing.
4550 this.title = this.headerEditEl.dom.value;
4551 this.headerEditEl.addClass('d-none');
4552 this.titleEl.removeClass('d-none');
4553 this.titleEl.dom.innerHTML = String.format('{0}', this.title);
4554 this.is_header_editing = false;
4555 this.fireEvent('titlechanged', this, this.title);
4564 Roo.apply(Roo.bootstrap.Modal, {
4566 * Button config that displays a single OK button
4575 * Button config that displays Yes and No buttons
4591 * Button config that displays OK and Cancel buttons
4606 * Button config that displays Yes, No and Cancel buttons
4631 * messagebox - can be used as a replace
4635 * @class Roo.MessageBox
4636 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
4640 Roo.Msg.alert('Status', 'Changes saved successfully.');
4642 // Prompt for user data:
4643 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
4645 // process text value...
4649 // Show a dialog using config options:
4651 title:'Save Changes?',
4652 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
4653 buttons: Roo.Msg.YESNOCANCEL,
4660 Roo.bootstrap.MessageBox = function(){
4661 var dlg, opt, mask, waitTimer;
4662 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
4663 var buttons, activeTextEl, bwidth;
4667 var handleButton = function(button){
4669 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
4673 var handleHide = function(){
4675 dlg.el.removeClass(opt.cls);
4678 // Roo.TaskMgr.stop(waitTimer);
4679 // waitTimer = null;
4684 var updateButtons = function(b){
4687 buttons["ok"].hide();
4688 buttons["cancel"].hide();
4689 buttons["yes"].hide();
4690 buttons["no"].hide();
4691 dlg.footerEl.hide();
4695 dlg.footerEl.show();
4696 for(var k in buttons){
4697 if(typeof buttons[k] != "function"){
4700 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
4701 width += buttons[k].el.getWidth()+15;
4711 var handleEsc = function(d, k, e){
4712 if(opt && opt.closable !== false){
4722 * Returns a reference to the underlying {@link Roo.BasicDialog} element
4723 * @return {Roo.BasicDialog} The BasicDialog element
4725 getDialog : function(){
4727 dlg = new Roo.bootstrap.Modal( {
4730 //constraintoviewport:false,
4732 //collapsible : false,
4737 //buttonAlign:"center",
4738 closeClick : function(){
4739 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
4742 handleButton("cancel");
4747 dlg.on("hide", handleHide);
4749 //dlg.addKeyListener(27, handleEsc);
4751 this.buttons = buttons;
4752 var bt = this.buttonText;
4753 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
4754 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
4755 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
4756 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
4758 bodyEl = dlg.bodyEl.createChild({
4760 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
4761 '<textarea class="roo-mb-textarea"></textarea>' +
4762 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
4764 msgEl = bodyEl.dom.firstChild;
4765 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
4766 textboxEl.enableDisplayMode();
4767 textboxEl.addKeyListener([10,13], function(){
4768 if(dlg.isVisible() && opt && opt.buttons){
4771 }else if(opt.buttons.yes){
4772 handleButton("yes");
4776 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
4777 textareaEl.enableDisplayMode();
4778 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
4779 progressEl.enableDisplayMode();
4781 // This is supposed to be the progessElement.. but I think it's controlling the height of everything..
4782 var pf = progressEl.dom.firstChild;
4784 pp = Roo.get(pf.firstChild);
4785 pp.setHeight(pf.offsetHeight);
4793 * Updates the message box body text
4794 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
4795 * the XHTML-compliant non-breaking space character '&#160;')
4796 * @return {Roo.MessageBox} This message box
4798 updateText : function(text)
4800 if(!dlg.isVisible() && !opt.width){
4801 dlg.dialogEl.setStyle({ 'max-width' : this.maxWidth});
4802 // dlg.resizeTo(this.maxWidth, 100); // forcing the height breaks long alerts()
4804 msgEl.innerHTML = text || ' ';
4806 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
4807 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
4809 Math.min(opt.width || cw , this.maxWidth),
4810 Math.max(opt.minWidth || this.minWidth, bwidth)
4813 activeTextEl.setWidth(w);
4815 if(dlg.isVisible()){
4816 dlg.fixedcenter = false;
4818 // to big, make it scroll. = But as usual stupid IE does not support
4821 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
4822 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
4823 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
4825 bodyEl.dom.style.height = '';
4826 bodyEl.dom.style.overflowY = '';
4829 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
4831 bodyEl.dom.style.overflowX = '';
4834 dlg.setContentSize(w, bodyEl.getHeight());
4835 if(dlg.isVisible()){
4836 dlg.fixedcenter = true;
4842 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
4843 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
4844 * @param {Number} value Any number between 0 and 1 (e.g., .5)
4845 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
4846 * @return {Roo.MessageBox} This message box
4848 updateProgress : function(value, text){
4850 this.updateText(text);
4853 if (pp) { // weird bug on my firefox - for some reason this is not defined
4854 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
4855 pp.setHeight(Math.floor(progressEl.dom.firstChild.offsetHeight));
4861 * Returns true if the message box is currently displayed
4862 * @return {Boolean} True if the message box is visible, else false
4864 isVisible : function(){
4865 return dlg && dlg.isVisible();
4869 * Hides the message box if it is displayed
4872 if(this.isVisible()){
4878 * Displays a new message box, or reinitializes an existing message box, based on the config options
4879 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
4880 * The following config object properties are supported:
4882 Property Type Description
4883 ---------- --------------- ------------------------------------------------------------------------------------
4884 animEl String/Element An id or Element from which the message box should animate as it opens and
4885 closes (defaults to undefined)
4886 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
4887 cancel:'Bar'}), or false to not show any buttons (defaults to false)
4888 closable Boolean False to hide the top-right close button (defaults to true). Note that
4889 progress and wait dialogs will ignore this property and always hide the
4890 close button as they can only be closed programmatically.
4891 cls String A custom CSS class to apply to the message box element
4892 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
4893 displayed (defaults to 75)
4894 fn Function A callback function to execute after closing the dialog. The arguments to the
4895 function will be btn (the name of the button that was clicked, if applicable,
4896 e.g. "ok"), and text (the value of the active text field, if applicable).
4897 Progress and wait dialogs will ignore this option since they do not respond to
4898 user actions and can only be closed programmatically, so any required function
4899 should be called by the same code after it closes the dialog.
4900 icon String A CSS class that provides a background image to be used as an icon for
4901 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
4902 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
4903 minWidth Number The minimum width in pixels of the message box (defaults to 100)
4904 modal Boolean False to allow user interaction with the page while the message box is
4905 displayed (defaults to true)
4906 msg String A string that will replace the existing message box body text (defaults
4907 to the XHTML-compliant non-breaking space character ' ')
4908 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
4909 progress Boolean True to display a progress bar (defaults to false)
4910 progressText String The text to display inside the progress bar if progress = true (defaults to '')
4911 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
4912 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
4913 title String The title text
4914 value String The string value to set into the active textbox element if displayed
4915 wait Boolean True to display a progress bar (defaults to false)
4916 width Number The width of the dialog in pixels
4923 msg: 'Please enter your address:',
4925 buttons: Roo.MessageBox.OKCANCEL,
4928 animEl: 'addAddressBtn'
4931 * @param {Object} config Configuration options
4932 * @return {Roo.MessageBox} This message box
4934 show : function(options)
4937 // this causes nightmares if you show one dialog after another
4938 // especially on callbacks..
4940 if(this.isVisible()){
4943 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
4944 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
4945 Roo.log("New Dialog Message:" + options.msg )
4946 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
4947 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
4950 var d = this.getDialog();
4952 d.setTitle(opt.title || " ");
4953 d.closeEl.setDisplayed(opt.closable !== false);
4954 activeTextEl = textboxEl;
4955 opt.prompt = opt.prompt || (opt.multiline ? true : false);
4960 textareaEl.setHeight(typeof opt.multiline == "number" ?
4961 opt.multiline : this.defaultTextHeight);
4962 activeTextEl = textareaEl;
4971 progressEl.setDisplayed(opt.progress === true);
4973 d.animate = false; // do not animate progress, as it may not have finished animating before we close it..
4975 this.updateProgress(0);
4976 activeTextEl.dom.value = opt.value || "";
4978 dlg.setDefaultButton(activeTextEl);
4980 var bs = opt.buttons;
4984 }else if(bs && bs.yes){
4985 db = buttons["yes"];
4987 dlg.setDefaultButton(db);
4989 bwidth = updateButtons(opt.buttons);
4990 this.updateText(opt.msg);
4992 d.el.addClass(opt.cls);
4994 d.proxyDrag = opt.proxyDrag === true;
4995 d.modal = opt.modal !== false;
4996 d.mask = opt.modal !== false ? mask : false;
4998 // force it to the end of the z-index stack so it gets a cursor in FF
4999 document.body.appendChild(dlg.el.dom);
5000 d.animateTarget = null;
5001 d.show(options.animEl);
5007 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
5008 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
5009 * and closing the message box when the process is complete.
5010 * @param {String} title The title bar text
5011 * @param {String} msg The message box body text
5012 * @return {Roo.MessageBox} This message box
5014 progress : function(title, msg){
5021 minWidth: this.minProgressWidth,
5028 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
5029 * If a callback function is passed it will be called after the user clicks the button, and the
5030 * id of the button that was clicked will be passed as the only parameter to the callback
5031 * (could also be the top-right close button).
5032 * @param {String} title The title bar text
5033 * @param {String} msg The message box body text
5034 * @param {Function} fn (optional) The callback function invoked after the message box is closed
5035 * @param {Object} scope (optional) The scope of the callback function
5036 * @return {Roo.MessageBox} This message box
5038 alert : function(title, msg, fn, scope)
5053 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
5054 * interaction while waiting for a long-running process to complete that does not have defined intervals.
5055 * You are responsible for closing the message box when the process is complete.
5056 * @param {String} msg The message box body text
5057 * @param {String} title (optional) The title bar text
5058 * @return {Roo.MessageBox} This message box
5060 wait : function(msg, title){
5071 waitTimer = Roo.TaskMgr.start({
5073 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
5081 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
5082 * If a callback function is passed it will be called after the user clicks either button, and the id of the
5083 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
5084 * @param {String} title The title bar text
5085 * @param {String} msg The message box body text
5086 * @param {Function} fn (optional) The callback function invoked after the message box is closed
5087 * @param {Object} scope (optional) The scope of the callback function
5088 * @return {Roo.MessageBox} This message box
5090 confirm : function(title, msg, fn, scope){
5094 buttons: this.YESNO,
5103 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
5104 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
5105 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
5106 * (could also be the top-right close button) and the text that was entered will be passed as the two
5107 * parameters to the callback.
5108 * @param {String} title The title bar text
5109 * @param {String} msg The message box body text
5110 * @param {Function} fn (optional) The callback function invoked after the message box is closed
5111 * @param {Object} scope (optional) The scope of the callback function
5112 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
5113 * property, or the height in pixels to create the textbox (defaults to false / single-line)
5114 * @return {Roo.MessageBox} This message box
5116 prompt : function(title, msg, fn, scope, multiline){
5120 buttons: this.OKCANCEL,
5125 multiline: multiline,
5132 * Button config that displays a single OK button
5137 * Button config that displays Yes and No buttons
5140 YESNO : {yes:true, no:true},
5142 * Button config that displays OK and Cancel buttons
5145 OKCANCEL : {ok:true, cancel:true},
5147 * Button config that displays Yes, No and Cancel buttons
5150 YESNOCANCEL : {yes:true, no:true, cancel:true},
5153 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
5156 defaultTextHeight : 75,
5158 * The maximum width in pixels of the message box (defaults to 600)
5163 * The minimum width in pixels of the message box (defaults to 100)
5168 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
5169 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
5172 minProgressWidth : 250,
5174 * An object containing the default button text strings that can be overriden for localized language support.
5175 * Supported properties are: ok, cancel, yes and no.
5176 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
5189 * Shorthand for {@link Roo.MessageBox}
5191 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
5192 Roo.Msg = Roo.Msg || Roo.MessageBox;
5201 * @class Roo.bootstrap.Navbar
5202 * @extends Roo.bootstrap.Component
5203 * Bootstrap Navbar class
5206 * Create a new Navbar
5207 * @param {Object} config The config object
5211 Roo.bootstrap.Navbar = function(config){
5212 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
5216 * @event beforetoggle
5217 * Fire before toggle the menu
5218 * @param {Roo.EventObject} e
5220 "beforetoggle" : true
5224 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
5233 getAutoCreate : function(){
5236 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
5240 initEvents :function ()
5242 //Roo.log(this.el.select('.navbar-toggle',true));
5243 this.el.select('.navbar-toggle',true).on('click', this.onToggle , this);
5250 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
5252 var size = this.el.getSize();
5253 this.maskEl.setSize(size.width, size.height);
5254 this.maskEl.enableDisplayMode("block");
5263 getChildContainer : function()
5265 if (this.el && this.el.select('.collapse').getCount()) {
5266 return this.el.select('.collapse',true).first();
5281 onToggle : function()
5284 if(this.fireEvent('beforetoggle', this) === false){
5287 var ce = this.el.select('.navbar-collapse',true).first();
5289 if (!ce.hasClass('show')) {
5299 * Expand the navbar pulldown
5301 expand : function ()
5304 var ce = this.el.select('.navbar-collapse',true).first();
5305 if (ce.hasClass('collapsing')) {
5308 ce.dom.style.height = '';
5310 ce.addClass('in'); // old...
5311 ce.removeClass('collapse');
5312 ce.addClass('show');
5313 var h = ce.getHeight();
5315 ce.removeClass('show');
5316 // at this point we should be able to see it..
5317 ce.addClass('collapsing');
5319 ce.setHeight(0); // resize it ...
5320 ce.on('transitionend', function() {
5321 //Roo.log('done transition');
5322 ce.removeClass('collapsing');
5323 ce.addClass('show');
5324 ce.removeClass('collapse');
5326 ce.dom.style.height = '';
5327 }, this, { single: true} );
5329 ce.dom.scrollTop = 0;
5332 * Collapse the navbar pulldown
5334 collapse : function()
5336 var ce = this.el.select('.navbar-collapse',true).first();
5338 if (ce.hasClass('collapsing') || ce.hasClass('collapse') ) {
5339 // it's collapsed or collapsing..
5342 ce.removeClass('in'); // old...
5343 ce.setHeight(ce.getHeight());
5344 ce.removeClass('show');
5345 ce.addClass('collapsing');
5347 ce.on('transitionend', function() {
5348 ce.dom.style.height = '';
5349 ce.removeClass('collapsing');
5350 ce.addClass('collapse');
5351 }, this, { single: true} );
5371 * @class Roo.bootstrap.NavSimplebar
5372 * @extends Roo.bootstrap.Navbar
5373 * Bootstrap Sidebar class
5375 * @cfg {Boolean} inverse is inverted color
5377 * @cfg {String} type (nav | pills | tabs)
5378 * @cfg {Boolean} arrangement stacked | justified
5379 * @cfg {String} align (left | right) alignment
5381 * @cfg {Boolean} main (true|false) main nav bar? default false
5382 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
5384 * @cfg {String} tag (header|footer|nav|div) default is nav
5386 * @cfg {String} weight (light|primary|secondary|success|danger|warning|info|dark|white) default is light.
5390 * Create a new Sidebar
5391 * @param {Object} config The config object
5395 Roo.bootstrap.NavSimplebar = function(config){
5396 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
5399 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
5415 getAutoCreate : function(){
5419 tag : this.tag || 'div',
5420 cls : 'navbar roo-navbar-simple' //navbar-expand-lg ??
5422 if (['light','white'].indexOf(this.weight) > -1) {
5423 cfg.cls += ['light','white'].indexOf(this.weight) > -1 ? ' navbar-light' : ' navbar-dark';
5425 cfg.cls += ' bg-' + this.weight;
5428 cfg.cls += ' navbar-inverse';
5432 // i'm not actually sure these are really used - normally we add a navGroup to a navbar
5434 if (Roo.bootstrap.version == 4 && this.xtype == 'NavSimplebar') {
5443 cls: 'nav nav-' + this.xtype,
5449 this.type = this.type || 'nav';
5450 if (['tabs','pills'].indexOf(this.type) != -1) {
5451 cfg.cn[0].cls += ' nav-' + this.type
5455 if (this.type!=='nav') {
5456 Roo.log('nav type must be nav/tabs/pills')
5458 cfg.cn[0].cls += ' navbar-nav'
5464 if (['stacked','justified'].indexOf(this.arrangement) != -1) {
5465 cfg.cn[0].cls += ' nav-' + this.arrangement;
5469 if (this.align === 'right') {
5470 cfg.cn[0].cls += ' navbar-right';
5495 * navbar-expand-md fixed-top
5499 * @class Roo.bootstrap.NavHeaderbar
5500 * @extends Roo.bootstrap.NavSimplebar
5501 * Bootstrap Sidebar class
5503 * @cfg {String} brand what is brand
5504 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
5505 * @cfg {String} brand_href href of the brand
5506 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
5507 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
5508 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
5509 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
5512 * Create a new Sidebar
5513 * @param {Object} config The config object
5517 Roo.bootstrap.NavHeaderbar = function(config){
5518 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
5522 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
5529 desktopCenter : false,
5532 getAutoCreate : function(){
5535 tag: this.nav || 'nav',
5536 cls: 'navbar navbar-expand-md',
5542 if (this.desktopCenter) {
5543 cn.push({cls : 'container', cn : []});
5551 cls: 'navbar-toggle navbar-toggler',
5552 'data-toggle': 'collapse',
5557 html: 'Toggle navigation'
5561 cls: 'icon-bar navbar-toggler-icon'
5574 cn.push( Roo.bootstrap.version == 4 ? btn : {
5576 cls: 'navbar-header',
5585 cls: Roo.bootstrap.version == 4 ? 'nav flex-row roo-navbar-collapse collapse navbar-collapse' : 'collapse navbar-collapse roo-navbar-collapse',
5589 cfg.cls += this.inverse ? ' navbar-inverse navbar-dark bg-dark' : ' navbar-default';
5591 if (['light','white'].indexOf(this.weight) > -1) {
5592 cfg.cls += ['light','white'].indexOf(this.weight) > -1 ? ' navbar-light' : ' navbar-dark';
5594 cfg.cls += ' bg-' + this.weight;
5597 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
5598 cfg.cls += ' navbar-' + this.position + ' ' + this.position ;
5600 // tag can override this..
5602 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
5605 if (this.brand !== '') {
5606 var cp = Roo.bootstrap.version == 4 ? cn : cn[0].cn;
5607 cp.unshift({ // changed from push ?? BS4 needs it at the start? - does this break or exsiting?
5609 href: this.brand_href ? this.brand_href : '#',
5610 cls: 'navbar-brand',
5618 cfg.cls += ' main-nav';
5626 getHeaderChildContainer : function()
5628 if (this.srButton && this.el.select('.navbar-header').getCount()) {
5629 return this.el.select('.navbar-header',true).first();
5632 return this.getChildContainer();
5635 getChildContainer : function()
5638 return this.el.select('.roo-navbar-collapse',true).first();
5643 initEvents : function()
5645 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
5647 if (this.autohide) {
5652 Roo.get(document).on('scroll',function(e) {
5653 var ns = Roo.get(document).getScroll().top;
5654 var os = prevScroll;
5658 ft.removeClass('slideDown');
5659 ft.addClass('slideUp');
5662 ft.removeClass('slideUp');
5663 ft.addClass('slideDown');
5684 * @class Roo.bootstrap.NavSidebar
5685 * @extends Roo.bootstrap.Navbar
5686 * Bootstrap Sidebar class
5689 * Create a new Sidebar
5690 * @param {Object} config The config object
5694 Roo.bootstrap.NavSidebar = function(config){
5695 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
5698 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
5700 sidebar : true, // used by Navbar Item and NavbarGroup at present...
5702 getAutoCreate : function(){
5707 cls: 'sidebar sidebar-nav'
5729 * @class Roo.bootstrap.NavGroup
5730 * @extends Roo.bootstrap.Component
5731 * Bootstrap NavGroup class
5732 * @cfg {String} align (left|right)
5733 * @cfg {Boolean} inverse
5734 * @cfg {String} type (nav|pills|tab) default nav
5735 * @cfg {String} navId - reference Id for navbar.
5736 * @cfg {Boolean} pilltype default true (turn to off to disable active toggle)
5739 * Create a new nav group
5740 * @param {Object} config The config object
5743 Roo.bootstrap.NavGroup = function(config){
5744 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
5747 Roo.bootstrap.NavGroup.register(this);
5751 * Fires when the active item changes
5752 * @param {Roo.bootstrap.NavGroup} this
5753 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
5754 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
5761 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
5773 getAutoCreate : function()
5775 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
5781 if (Roo.bootstrap.version == 4) {
5782 if (['tabs','pills'].indexOf(this.type) != -1) {
5783 cfg.cls += ' nav-' + this.type;
5785 // trying to remove so header bar can right align top?
5786 if (this.parent() && this.parent().xtype != 'NavHeaderbar') {
5787 // do not use on header bar...
5788 cfg.cls += ' navbar-nav';
5793 if (['tabs','pills'].indexOf(this.type) != -1) {
5794 cfg.cls += ' nav-' + this.type
5796 if (this.type !== 'nav') {
5797 Roo.log('nav type must be nav/tabs/pills')
5799 cfg.cls += ' navbar-nav'
5803 if (this.parent() && this.parent().sidebar) {
5806 cls: 'dashboard-menu sidebar-menu'
5812 if (this.form === true) {
5815 cls: 'navbar-form form-inline'
5817 //nav navbar-right ml-md-auto
5818 if (this.align === 'right') {
5819 cfg.cls += ' navbar-right ml-md-auto';
5821 cfg.cls += ' navbar-left';
5825 if (this.align === 'right') {
5826 cfg.cls += ' navbar-right ml-md-auto';
5828 cfg.cls += ' mr-auto';
5832 cfg.cls += ' navbar-inverse';
5840 * sets the active Navigation item
5841 * @param {Roo.bootstrap.NavItem} the new current navitem
5843 setActiveItem : function(item)
5846 Roo.each(this.navItems, function(v){
5851 v.setActive(false, true);
5858 item.setActive(true, true);
5859 this.fireEvent('changed', this, item, prev);
5864 * gets the active Navigation item
5865 * @return {Roo.bootstrap.NavItem} the current navitem
5867 getActive : function()
5871 Roo.each(this.navItems, function(v){
5882 indexOfNav : function()
5886 Roo.each(this.navItems, function(v,i){
5897 * adds a Navigation item
5898 * @param {Roo.bootstrap.NavItem} the navitem to add
5900 addItem : function(cfg)
5902 if (this.form && Roo.bootstrap.version == 4) {
5905 var cn = new Roo.bootstrap.NavItem(cfg);
5907 cn.parentId = this.id;
5908 cn.onRender(this.el, null);
5912 * register a Navigation item
5913 * @param {Roo.bootstrap.NavItem} the navitem to add
5915 register : function(item)
5917 this.navItems.push( item);
5918 item.navId = this.navId;
5923 * clear all the Navigation item
5926 clearAll : function()
5929 this.el.dom.innerHTML = '';
5932 getNavItem: function(tabId)
5935 Roo.each(this.navItems, function(e) {
5936 if (e.tabId == tabId) {
5946 setActiveNext : function()
5948 var i = this.indexOfNav(this.getActive());
5949 if (i > this.navItems.length) {
5952 this.setActiveItem(this.navItems[i+1]);
5954 setActivePrev : function()
5956 var i = this.indexOfNav(this.getActive());
5960 this.setActiveItem(this.navItems[i-1]);
5962 clearWasActive : function(except) {
5963 Roo.each(this.navItems, function(e) {
5964 if (e.tabId != except.tabId && e.was_active) {
5965 e.was_active = false;
5972 getWasActive : function ()
5975 Roo.each(this.navItems, function(e) {
5990 Roo.apply(Roo.bootstrap.NavGroup, {
5994 * register a Navigation Group
5995 * @param {Roo.bootstrap.NavGroup} the navgroup to add
5997 register : function(navgrp)
5999 this.groups[navgrp.navId] = navgrp;
6003 * fetch a Navigation Group based on the navigation ID
6004 * @param {string} the navgroup to add
6005 * @returns {Roo.bootstrap.NavGroup} the navgroup
6007 get: function(navId) {
6008 if (typeof(this.groups[navId]) == 'undefined') {
6010 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
6012 return this.groups[navId] ;
6027 * @class Roo.bootstrap.NavItem
6028 * @extends Roo.bootstrap.Component
6029 * Bootstrap Navbar.NavItem class
6030 * @cfg {String} href link to
6031 * @cfg {String} button_weight (default|primary|secondary|success|info|warning|danger|link|light|dark) default none
6032 * @cfg {Boolean} button_outline show and outlined button
6033 * @cfg {String} html content of button
6034 * @cfg {String} badge text inside badge
6035 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
6036 * @cfg {String} glyphicon DEPRICATED - use fa
6037 * @cfg {String} icon DEPRICATED - use fa
6038 * @cfg {String} fa - Fontawsome icon name (can add stuff to it like fa-2x)
6039 * @cfg {Boolean} active Is item active
6040 * @cfg {Boolean} disabled Is item disabled
6041 * @cfg {String} linkcls Link Class
6042 * @cfg {Boolean} preventDefault (true | false) default false
6043 * @cfg {String} tabId the tab that this item activates.
6044 * @cfg {String} tagtype (a|span) render as a href or span?
6045 * @cfg {Boolean} animateRef (true|false) link to element default false
6048 * Create a new Navbar Item
6049 * @param {Object} config The config object
6051 Roo.bootstrap.NavItem = function(config){
6052 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
6057 * The raw click event for the entire grid.
6058 * @param {Roo.EventObject} e
6063 * Fires when the active item active state changes
6064 * @param {Roo.bootstrap.NavItem} this
6065 * @param {boolean} state the new state
6071 * Fires when scroll to element
6072 * @param {Roo.bootstrap.NavItem} this
6073 * @param {Object} options
6074 * @param {Roo.EventObject} e
6082 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
6091 preventDefault : false,
6099 button_outline : false,
6103 getAutoCreate : function(){
6110 cfg.cls = typeof(cfg.cls) == 'undefined' ? '' : cfg.cls;
6113 cfg.cls += ' active' ;
6115 if (this.disabled) {
6116 cfg.cls += ' disabled';
6120 if (this.button_weight.length) {
6121 cfg.tag = this.href ? 'a' : 'button';
6122 cfg.html = this.html || '';
6123 cfg.cls += ' btn btn' + (this.button_outline ? '-outline' : '') + '-' + this.button_weight;
6125 cfg.href = this.href;
6128 cfg.html = '<i class="fa fas fa-'+this.fa+'"></i> <span>' + this.html + '</span>';
6131 // menu .. should add dropdown-menu class - so no need for carat..
6133 if (this.badge !== '') {
6135 cfg.html += ' <span class="badge badge-secondary">' + this.badge + '</span>';
6140 if (this.href || this.html || this.glyphicon || this.icon || this.fa) {
6144 href : this.href || "#",
6145 html: this.html || ''
6148 if (this.tagtype == 'a') {
6149 cfg.cn[0].cls = 'nav-link' + (this.active ? ' active' : '') + ' ' + this.linkcls;
6153 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>';
6156 cfg.cn[0].html = '<i class="fa fas fa-'+this.fa+'"></i> <span>' + cfg.cn[0].html + '</span>';
6158 if(this.glyphicon) {
6159 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
6164 cfg.cn[0].html += " <span class='caret'></span>";
6168 if (this.badge !== '') {
6170 cfg.cn[0].html += ' <span class="badge badge-secondary">' + this.badge + '</span>';
6178 onRender : function(ct, position)
6180 // Roo.log("Call onRender: " + this.xtype);
6181 if (Roo.bootstrap.version == 4 && ct.dom.type != 'ul') {
6185 var ret = Roo.bootstrap.NavItem.superclass.onRender.call(this, ct, position);
6186 this.navLink = this.el.select('.nav-link',true).first();
6191 initEvents: function()
6193 if (typeof (this.menu) != 'undefined') {
6194 this.menu.parentType = this.xtype;
6195 this.menu.triggerEl = this.el;
6196 this.menu = this.addxtype(Roo.apply({}, this.menu));
6199 this.el.on('click', this.onClick, this);
6201 //if(this.tagtype == 'span'){
6202 // this.el.select('span',true).on('click', this.onClick, this);
6205 // at this point parent should be available..
6206 this.parent().register(this);
6209 onClick : function(e)
6211 if (e.getTarget('.dropdown-menu-item')) {
6212 // did you click on a menu itemm.... - then don't trigger onclick..
6217 this.preventDefault ||
6220 Roo.log("NavItem - prevent Default?");
6224 if (this.disabled) {
6228 var tg = Roo.bootstrap.TabGroup.get(this.navId);
6229 if (tg && tg.transition) {
6230 Roo.log("waiting for the transitionend");
6236 //Roo.log("fire event clicked");
6237 if(this.fireEvent('click', this, e) === false){
6241 if(this.tagtype == 'span'){
6245 //Roo.log(this.href);
6246 var ael = this.el.select('a',true).first();
6249 if(ael && this.animateRef && this.href.indexOf('#') > -1){
6250 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
6251 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
6252 return; // ignore... - it's a 'hash' to another page.
6254 Roo.log("NavItem - prevent Default?");
6256 this.scrollToElement(e);
6260 var p = this.parent();
6262 if (['tabs','pills'].indexOf(p.type)!==-1 && p.pilltype) {
6263 if (typeof(p.setActiveItem) !== 'undefined') {
6264 p.setActiveItem(this);
6268 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
6269 if (p.parentType == 'NavHeaderbar' && !this.menu) {
6270 // remove the collapsed menu expand...
6271 p.parent().el.select('.roo-navbar-collapse',true).removeClass('in');
6275 isActive: function () {
6278 setActive : function(state, fire, is_was_active)
6280 if (this.active && !state && this.navId) {
6281 this.was_active = true;
6282 var nv = Roo.bootstrap.NavGroup.get(this.navId);
6284 nv.clearWasActive(this);
6288 this.active = state;
6291 this.el.removeClass('active');
6292 this.navLink ? this.navLink.removeClass('active') : false;
6293 } else if (!this.el.hasClass('active')) {
6295 this.el.addClass('active');
6296 if (Roo.bootstrap.version == 4 && this.navLink ) {
6297 this.navLink.addClass('active');
6302 this.fireEvent('changed', this, state);
6305 // show a panel if it's registered and related..
6307 if (!this.navId || !this.tabId || !state || is_was_active) {
6311 var tg = Roo.bootstrap.TabGroup.get(this.navId);
6315 var pan = tg.getPanelByName(this.tabId);
6319 // if we can not flip to new panel - go back to old nav highlight..
6320 if (false == tg.showPanel(pan)) {
6321 var nv = Roo.bootstrap.NavGroup.get(this.navId);
6323 var onav = nv.getWasActive();
6325 onav.setActive(true, false, true);
6334 // this should not be here...
6335 setDisabled : function(state)
6337 this.disabled = state;
6339 this.el.removeClass('disabled');
6340 } else if (!this.el.hasClass('disabled')) {
6341 this.el.addClass('disabled');
6347 * Fetch the element to display the tooltip on.
6348 * @return {Roo.Element} defaults to this.el
6350 tooltipEl : function()
6352 return this.el; //this.tagtype == 'a' ? this.el : this.el.select('' + this.tagtype + '', true).first();
6355 scrollToElement : function(e)
6357 var c = document.body;
6360 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
6362 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
6363 c = document.documentElement;
6366 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
6372 var o = target.calcOffsetsTo(c);
6379 this.fireEvent('scrollto', this, options, e);
6381 Roo.get(c).scrollTo('top', options.value, true);
6394 * <span> icon </span>
6395 * <span> text </span>
6396 * <span>badge </span>
6400 * @class Roo.bootstrap.NavSidebarItem
6401 * @extends Roo.bootstrap.NavItem
6402 * Bootstrap Navbar.NavSidebarItem class
6403 * {String} badgeWeight (default|primary|success|info|warning|danger)the extra classes for the badge
6404 * {Boolean} open is the menu open
6405 * {Boolean} buttonView use button as the tigger el rather that a (default false)
6406 * {String} buttonWeight (default|primary|success|info|warning|danger)the extra classes for the button
6407 * {String} buttonSize (sm|md|lg)the extra classes for the button
6408 * {Boolean} showArrow show arrow next to the text (default true)
6410 * Create a new Navbar Button
6411 * @param {Object} config The config object
6413 Roo.bootstrap.NavSidebarItem = function(config){
6414 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
6419 * The raw click event for the entire grid.
6420 * @param {Roo.EventObject} e
6425 * Fires when the active item active state changes
6426 * @param {Roo.bootstrap.NavSidebarItem} this
6427 * @param {boolean} state the new state
6435 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
6437 badgeWeight : 'default',
6443 buttonWeight : 'default',
6449 getAutoCreate : function(){
6454 href : this.href || '#',
6460 if(this.buttonView){
6463 href : this.href || '#',
6464 cls: 'btn btn-' + this.buttonWeight + ' btn-' + this.buttonSize + 'roo-button-dropdown-toggle',
6477 cfg.cls += ' active';
6480 if (this.disabled) {
6481 cfg.cls += ' disabled';
6484 cfg.cls += ' open x-open';
6487 if (this.glyphicon || this.icon) {
6488 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
6489 a.cn.push({ tag : 'i', cls : c }) ;
6492 if(!this.buttonView){
6495 html : this.html || ''
6502 if (this.badge !== '') {
6503 a.cn.push({ tag: 'span', cls : 'badge pull-right badge-' + this.badgeWeight, html: this.badge });
6509 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
6512 a.cls += ' dropdown-toggle treeview' ;
6518 initEvents : function()
6520 if (typeof (this.menu) != 'undefined') {
6521 this.menu.parentType = this.xtype;
6522 this.menu.triggerEl = this.el;
6523 this.menu = this.addxtype(Roo.apply({}, this.menu));
6526 this.el.on('click', this.onClick, this);
6528 if(this.badge !== ''){
6529 this.badgeEl = this.el.select('.badge', true).first().setVisibilityMode(Roo.Element.DISPLAY);
6534 onClick : function(e)
6541 if(this.preventDefault){
6545 this.fireEvent('click', this, e);
6548 disable : function()
6550 this.setDisabled(true);
6555 this.setDisabled(false);
6558 setDisabled : function(state)
6560 if(this.disabled == state){
6564 this.disabled = state;
6567 this.el.addClass('disabled');
6571 this.el.removeClass('disabled');
6576 setActive : function(state)
6578 if(this.active == state){
6582 this.active = state;
6585 this.el.addClass('active');
6589 this.el.removeClass('active');
6594 isActive: function ()
6599 setBadge : function(str)
6605 this.badgeEl.dom.innerHTML = str;
6620 Roo.namespace('Roo.bootstrap.breadcrumb');
6624 * @class Roo.bootstrap.breadcrumb.Nav
6625 * @extends Roo.bootstrap.Component
6626 * Bootstrap Breadcrumb Nav Class
6628 * @children Roo.bootstrap.breadcrumb.Item
6631 * Create a new breadcrumb.Nav
6632 * @param {Object} config The config object
6636 Roo.bootstrap.breadcrumb.Nav = function(config){
6637 Roo.bootstrap.breadcrumb.Nav.superclass.constructor.call(this, config);
6642 Roo.extend(Roo.bootstrap.breadcrumb.Nav, Roo.bootstrap.Component, {
6644 getAutoCreate : function()
6661 initEvents: function()
6663 this.olEl = this.el.select('ol',true).first();
6665 getChildContainer : function()
6681 * @class Roo.bootstrap.breadcrumb.Nav
6682 * @extends Roo.bootstrap.Component
6683 * Bootstrap Breadcrumb Nav Class
6685 * @children Roo.bootstrap.breadcrumb.Component
6686 * @cfg {String} html the content of the link.
6687 * @cfg {String} href where it links to if '#' is used the link will be handled by onClick.
6688 * @cfg {Boolean} active is it active
6692 * Create a new breadcrumb.Nav
6693 * @param {Object} config The config object
6696 Roo.bootstrap.breadcrumb.Item = function(config){
6697 Roo.bootstrap.breadcrumb.Item.superclass.constructor.call(this, config);
6702 * The img click event for the img.
6703 * @param {Roo.EventObject} e
6710 Roo.extend(Roo.bootstrap.breadcrumb.Item, Roo.bootstrap.Component, {
6715 getAutoCreate : function()
6720 cls : 'breadcrumb-item' + (this.active ? ' active' : '')
6722 if (this.href !== false) {
6729 cfg.html = this.html;
6735 initEvents: function()
6738 this.el.select('a', true).first().on('click',this.onClick, this)
6742 onClick : function(e)
6745 this.fireEvent('click',this, e);
6758 * @class Roo.bootstrap.Row
6759 * @extends Roo.bootstrap.Component
6760 * Bootstrap Row class (contains columns...)
6764 * @param {Object} config The config object
6767 Roo.bootstrap.Row = function(config){
6768 Roo.bootstrap.Row.superclass.constructor.call(this, config);
6771 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
6773 getAutoCreate : function(){
6792 * @class Roo.bootstrap.Pagination
6793 * @extends Roo.bootstrap.Component
6794 * Bootstrap Pagination class
6795 * @cfg {String} size xs | sm | md | lg
6796 * @cfg {Boolean} inverse false | true
6799 * Create a new Pagination
6800 * @param {Object} config The config object
6803 Roo.bootstrap.Pagination = function(config){
6804 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
6807 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
6813 getAutoCreate : function(){
6819 cfg.cls += ' inverse';
6825 cfg.cls += " " + this.cls;
6843 * @class Roo.bootstrap.PaginationItem
6844 * @extends Roo.bootstrap.Component
6845 * Bootstrap PaginationItem class
6846 * @cfg {String} html text
6847 * @cfg {String} href the link
6848 * @cfg {Boolean} preventDefault (true | false) default true
6849 * @cfg {Boolean} active (true | false) default false
6850 * @cfg {Boolean} disabled default false
6854 * Create a new PaginationItem
6855 * @param {Object} config The config object
6859 Roo.bootstrap.PaginationItem = function(config){
6860 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
6865 * The raw click event for the entire grid.
6866 * @param {Roo.EventObject} e
6872 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
6876 preventDefault: true,
6881 getAutoCreate : function(){
6887 href : this.href ? this.href : '#',
6888 html : this.html ? this.html : ''
6898 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
6902 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
6908 initEvents: function() {
6910 this.el.on('click', this.onClick, this);
6913 onClick : function(e)
6915 Roo.log('PaginationItem on click ');
6916 if(this.preventDefault){
6924 this.fireEvent('click', this, e);
6940 * @class Roo.bootstrap.Slider
6941 * @extends Roo.bootstrap.Component
6942 * Bootstrap Slider class
6945 * Create a new Slider
6946 * @param {Object} config The config object
6949 Roo.bootstrap.Slider = function(config){
6950 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
6953 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
6955 getAutoCreate : function(){
6959 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
6963 cls: 'ui-slider-handle ui-state-default ui-corner-all'
6975 * Ext JS Library 1.1.1
6976 * Copyright(c) 2006-2007, Ext JS, LLC.
6978 * Originally Released Under LGPL - original licence link has changed is not relivant.
6981 * <script type="text/javascript">
6986 * @class Roo.grid.ColumnModel
6987 * @extends Roo.util.Observable
6988 * This is the default implementation of a ColumnModel used by the Grid. It defines
6989 * the columns in the grid.
6992 var colModel = new Roo.grid.ColumnModel([
6993 {header: "Ticker", width: 60, sortable: true, locked: true},
6994 {header: "Company Name", width: 150, sortable: true},
6995 {header: "Market Cap.", width: 100, sortable: true},
6996 {header: "$ Sales", width: 100, sortable: true, renderer: money},
6997 {header: "Employees", width: 100, sortable: true, resizable: false}
7002 * The config options listed for this class are options which may appear in each
7003 * individual column definition.
7004 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
7006 * @param {Object} config An Array of column config objects. See this class's
7007 * config objects for details.
7009 Roo.grid.ColumnModel = function(config){
7011 * The config passed into the constructor
7013 this.config = config;
7016 // if no id, create one
7017 // if the column does not have a dataIndex mapping,
7018 // map it to the order it is in the config
7019 for(var i = 0, len = config.length; i < len; i++){
7021 if(typeof c.dataIndex == "undefined"){
7024 if(typeof c.renderer == "string"){
7025 c.renderer = Roo.util.Format[c.renderer];
7027 if(typeof c.id == "undefined"){
7030 if(c.editor && c.editor.xtype){
7031 c.editor = Roo.factory(c.editor, Roo.grid);
7033 if(c.editor && c.editor.isFormField){
7034 c.editor = new Roo.grid.GridEditor(c.editor);
7036 this.lookup[c.id] = c;
7040 * The width of columns which have no width specified (defaults to 100)
7043 this.defaultWidth = 100;
7046 * Default sortable of columns which have no sortable specified (defaults to false)
7049 this.defaultSortable = false;
7053 * @event widthchange
7054 * Fires when the width of a column changes.
7055 * @param {ColumnModel} this
7056 * @param {Number} columnIndex The column index
7057 * @param {Number} newWidth The new width
7059 "widthchange": true,
7061 * @event headerchange
7062 * Fires when the text of a header changes.
7063 * @param {ColumnModel} this
7064 * @param {Number} columnIndex The column index
7065 * @param {Number} newText The new header text
7067 "headerchange": true,
7069 * @event hiddenchange
7070 * Fires when a column is hidden or "unhidden".
7071 * @param {ColumnModel} this
7072 * @param {Number} columnIndex The column index
7073 * @param {Boolean} hidden true if hidden, false otherwise
7075 "hiddenchange": true,
7077 * @event columnmoved
7078 * Fires when a column is moved.
7079 * @param {ColumnModel} this
7080 * @param {Number} oldIndex
7081 * @param {Number} newIndex
7083 "columnmoved" : true,
7085 * @event columlockchange
7086 * Fires when a column's locked state is changed
7087 * @param {ColumnModel} this
7088 * @param {Number} colIndex
7089 * @param {Boolean} locked true if locked
7091 "columnlockchange" : true
7093 Roo.grid.ColumnModel.superclass.constructor.call(this);
7095 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
7097 * @cfg {String} header The header text to display in the Grid view.
7100 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
7101 * {@link Roo.data.Record} definition from which to draw the column's value. If not
7102 * specified, the column's index is used as an index into the Record's data Array.
7105 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
7106 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
7109 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
7110 * Defaults to the value of the {@link #defaultSortable} property.
7111 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
7114 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
7117 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
7120 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
7123 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
7126 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
7127 * given the cell's data value. See {@link #setRenderer}. If not specified, the
7128 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
7129 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
7132 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
7135 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
7138 * @cfg {String} valign (Optional) Set the CSS vertical-align property of the column (eg. middle, top, bottom etc). Defaults to undefined.
7141 * @cfg {String} cursor (Optional)
7144 * @cfg {String} tooltip (Optional)
7147 * @cfg {Number} xs (Optional)
7150 * @cfg {Number} sm (Optional)
7153 * @cfg {Number} md (Optional)
7156 * @cfg {Number} lg (Optional)
7159 * Returns the id of the column at the specified index.
7160 * @param {Number} index The column index
7161 * @return {String} the id
7163 getColumnId : function(index){
7164 return this.config[index].id;
7168 * Returns the column for a specified id.
7169 * @param {String} id The column id
7170 * @return {Object} the column
7172 getColumnById : function(id){
7173 return this.lookup[id];
7178 * Returns the column for a specified dataIndex.
7179 * @param {String} dataIndex The column dataIndex
7180 * @return {Object|Boolean} the column or false if not found
7182 getColumnByDataIndex: function(dataIndex){
7183 var index = this.findColumnIndex(dataIndex);
7184 return index > -1 ? this.config[index] : false;
7188 * Returns the index for a specified column id.
7189 * @param {String} id The column id
7190 * @return {Number} the index, or -1 if not found
7192 getIndexById : function(id){
7193 for(var i = 0, len = this.config.length; i < len; i++){
7194 if(this.config[i].id == id){
7202 * Returns the index for a specified column dataIndex.
7203 * @param {String} dataIndex The column dataIndex
7204 * @return {Number} the index, or -1 if not found
7207 findColumnIndex : function(dataIndex){
7208 for(var i = 0, len = this.config.length; i < len; i++){
7209 if(this.config[i].dataIndex == dataIndex){
7217 moveColumn : function(oldIndex, newIndex){
7218 var c = this.config[oldIndex];
7219 this.config.splice(oldIndex, 1);
7220 this.config.splice(newIndex, 0, c);
7221 this.dataMap = null;
7222 this.fireEvent("columnmoved", this, oldIndex, newIndex);
7225 isLocked : function(colIndex){
7226 return this.config[colIndex].locked === true;
7229 setLocked : function(colIndex, value, suppressEvent){
7230 if(this.isLocked(colIndex) == value){
7233 this.config[colIndex].locked = value;
7235 this.fireEvent("columnlockchange", this, colIndex, value);
7239 getTotalLockedWidth : function(){
7241 for(var i = 0; i < this.config.length; i++){
7242 if(this.isLocked(i) && !this.isHidden(i)){
7243 this.totalWidth += this.getColumnWidth(i);
7249 getLockedCount : function(){
7250 for(var i = 0, len = this.config.length; i < len; i++){
7251 if(!this.isLocked(i)){
7256 return this.config.length;
7260 * Returns the number of columns.
7263 getColumnCount : function(visibleOnly){
7264 if(visibleOnly === true){
7266 for(var i = 0, len = this.config.length; i < len; i++){
7267 if(!this.isHidden(i)){
7273 return this.config.length;
7277 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
7278 * @param {Function} fn
7279 * @param {Object} scope (optional)
7280 * @return {Array} result
7282 getColumnsBy : function(fn, scope){
7284 for(var i = 0, len = this.config.length; i < len; i++){
7285 var c = this.config[i];
7286 if(fn.call(scope||this, c, i) === true){
7294 * Returns true if the specified column is sortable.
7295 * @param {Number} col The column index
7298 isSortable : function(col){
7299 if(typeof this.config[col].sortable == "undefined"){
7300 return this.defaultSortable;
7302 return this.config[col].sortable;
7306 * Returns the rendering (formatting) function defined for the column.
7307 * @param {Number} col The column index.
7308 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
7310 getRenderer : function(col){
7311 if(!this.config[col].renderer){
7312 return Roo.grid.ColumnModel.defaultRenderer;
7314 return this.config[col].renderer;
7318 * Sets the rendering (formatting) function for a column.
7319 * @param {Number} col The column index
7320 * @param {Function} fn The function to use to process the cell's raw data
7321 * to return HTML markup for the grid view. The render function is called with
7322 * the following parameters:<ul>
7323 * <li>Data value.</li>
7324 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
7325 * <li>css A CSS style string to apply to the table cell.</li>
7326 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
7327 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
7328 * <li>Row index</li>
7329 * <li>Column index</li>
7330 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
7332 setRenderer : function(col, fn){
7333 this.config[col].renderer = fn;
7337 * Returns the width for the specified column.
7338 * @param {Number} col The column index
7341 getColumnWidth : function(col){
7342 return this.config[col].width * 1 || this.defaultWidth;
7346 * Sets the width for a column.
7347 * @param {Number} col The column index
7348 * @param {Number} width The new width
7350 setColumnWidth : function(col, width, suppressEvent){
7351 this.config[col].width = width;
7352 this.totalWidth = null;
7354 this.fireEvent("widthchange", this, col, width);
7359 * Returns the total width of all columns.
7360 * @param {Boolean} includeHidden True to include hidden column widths
7363 getTotalWidth : function(includeHidden){
7364 if(!this.totalWidth){
7365 this.totalWidth = 0;
7366 for(var i = 0, len = this.config.length; i < len; i++){
7367 if(includeHidden || !this.isHidden(i)){
7368 this.totalWidth += this.getColumnWidth(i);
7372 return this.totalWidth;
7376 * Returns the header for the specified column.
7377 * @param {Number} col The column index
7380 getColumnHeader : function(col){
7381 return this.config[col].header;
7385 * Sets the header for a column.
7386 * @param {Number} col The column index
7387 * @param {String} header The new header
7389 setColumnHeader : function(col, header){
7390 this.config[col].header = header;
7391 this.fireEvent("headerchange", this, col, header);
7395 * Returns the tooltip for the specified column.
7396 * @param {Number} col The column index
7399 getColumnTooltip : function(col){
7400 return this.config[col].tooltip;
7403 * Sets the tooltip for a column.
7404 * @param {Number} col The column index
7405 * @param {String} tooltip The new tooltip
7407 setColumnTooltip : function(col, tooltip){
7408 this.config[col].tooltip = tooltip;
7412 * Returns the dataIndex for the specified column.
7413 * @param {Number} col The column index
7416 getDataIndex : function(col){
7417 return this.config[col].dataIndex;
7421 * Sets the dataIndex for a column.
7422 * @param {Number} col The column index
7423 * @param {Number} dataIndex The new dataIndex
7425 setDataIndex : function(col, dataIndex){
7426 this.config[col].dataIndex = dataIndex;
7432 * Returns true if the cell is editable.
7433 * @param {Number} colIndex The column index
7434 * @param {Number} rowIndex The row index - this is nto actually used..?
7437 isCellEditable : function(colIndex, rowIndex){
7438 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
7442 * Returns the editor defined for the cell/column.
7443 * return false or null to disable editing.
7444 * @param {Number} colIndex The column index
7445 * @param {Number} rowIndex The row index
7448 getCellEditor : function(colIndex, rowIndex){
7449 return this.config[colIndex].editor;
7453 * Sets if a column is editable.
7454 * @param {Number} col The column index
7455 * @param {Boolean} editable True if the column is editable
7457 setEditable : function(col, editable){
7458 this.config[col].editable = editable;
7463 * Returns true if the column is hidden.
7464 * @param {Number} colIndex The column index
7467 isHidden : function(colIndex){
7468 return this.config[colIndex].hidden;
7473 * Returns true if the column width cannot be changed
7475 isFixed : function(colIndex){
7476 return this.config[colIndex].fixed;
7480 * Returns true if the column can be resized
7483 isResizable : function(colIndex){
7484 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
7487 * Sets if a column is hidden.
7488 * @param {Number} colIndex The column index
7489 * @param {Boolean} hidden True if the column is hidden
7491 setHidden : function(colIndex, hidden){
7492 this.config[colIndex].hidden = hidden;
7493 this.totalWidth = null;
7494 this.fireEvent("hiddenchange", this, colIndex, hidden);
7498 * Sets the editor for a column.
7499 * @param {Number} col The column index
7500 * @param {Object} editor The editor object
7502 setEditor : function(col, editor){
7503 this.config[col].editor = editor;
7507 Roo.grid.ColumnModel.defaultRenderer = function(value)
7509 if(typeof value == "object") {
7512 if(typeof value == "string" && value.length < 1){
7516 return String.format("{0}", value);
7519 // Alias for backwards compatibility
7520 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
7523 * Ext JS Library 1.1.1
7524 * Copyright(c) 2006-2007, Ext JS, LLC.
7526 * Originally Released Under LGPL - original licence link has changed is not relivant.
7529 * <script type="text/javascript">
7533 * @class Roo.LoadMask
7534 * A simple utility class for generically masking elements while loading data. If the element being masked has
7535 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
7536 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
7537 * element's UpdateManager load indicator and will be destroyed after the initial load.
7539 * Create a new LoadMask
7540 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
7541 * @param {Object} config The config object
7543 Roo.LoadMask = function(el, config){
7544 this.el = Roo.get(el);
7545 Roo.apply(this, config);
7547 this.store.on('beforeload', this.onBeforeLoad, this);
7548 this.store.on('load', this.onLoad, this);
7549 this.store.on('loadexception', this.onLoadException, this);
7550 this.removeMask = false;
7552 var um = this.el.getUpdateManager();
7553 um.showLoadIndicator = false; // disable the default indicator
7554 um.on('beforeupdate', this.onBeforeLoad, this);
7555 um.on('update', this.onLoad, this);
7556 um.on('failure', this.onLoad, this);
7557 this.removeMask = true;
7561 Roo.LoadMask.prototype = {
7563 * @cfg {Boolean} removeMask
7564 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
7565 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
7569 * The text to display in a centered loading message box (defaults to 'Loading...')
7573 * @cfg {String} msgCls
7574 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
7576 msgCls : 'x-mask-loading',
7579 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
7585 * Disables the mask to prevent it from being displayed
7587 disable : function(){
7588 this.disabled = true;
7592 * Enables the mask so that it can be displayed
7594 enable : function(){
7595 this.disabled = false;
7598 onLoadException : function()
7602 if (typeof(arguments[3]) != 'undefined') {
7603 Roo.MessageBox.alert("Error loading",arguments[3]);
7607 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
7608 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
7615 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
7620 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
7624 onBeforeLoad : function(){
7626 (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
7631 destroy : function(){
7633 this.store.un('beforeload', this.onBeforeLoad, this);
7634 this.store.un('load', this.onLoad, this);
7635 this.store.un('loadexception', this.onLoadException, this);
7637 var um = this.el.getUpdateManager();
7638 um.un('beforeupdate', this.onBeforeLoad, this);
7639 um.un('update', this.onLoad, this);
7640 um.un('failure', this.onLoad, this);
7651 * @class Roo.bootstrap.Table
7652 * @extends Roo.bootstrap.Component
7653 * Bootstrap Table class
7654 * @cfg {String} cls table class
7655 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
7656 * @cfg {String} bgcolor Specifies the background color for a table
7657 * @cfg {Number} border Specifies whether the table cells should have borders or not
7658 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
7659 * @cfg {Number} cellspacing Specifies the space between cells
7660 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
7661 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
7662 * @cfg {String} sortable Specifies that the table should be sortable
7663 * @cfg {String} summary Specifies a summary of the content of a table
7664 * @cfg {Number} width Specifies the width of a table
7665 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
7667 * @cfg {boolean} striped Should the rows be alternative striped
7668 * @cfg {boolean} bordered Add borders to the table
7669 * @cfg {boolean} hover Add hover highlighting
7670 * @cfg {boolean} condensed Format condensed
7671 * @cfg {boolean} responsive Format condensed
7672 * @cfg {Boolean} loadMask (true|false) default false
7673 * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
7674 * @cfg {Boolean} headerShow (true|false) generate thead, default true
7675 * @cfg {Boolean} rowSelection (true|false) default false
7676 * @cfg {Boolean} cellSelection (true|false) default false
7677 * @cfg {Boolean} scrollBody (true|false) default false - body scrolled / fixed header
7678 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
7679 * @cfg {Boolean} lazyLoad auto load data while scrolling to the end (default false)
7680 * @cfg {Boolean} auto_hide_footer auto hide footer if only one page (default false)
7684 * Create a new Table
7685 * @param {Object} config The config object
7688 Roo.bootstrap.Table = function(config){
7689 Roo.bootstrap.Table.superclass.constructor.call(this, config);
7694 this.rowSelection = (typeof(config.rowSelection) != 'undefined') ? config.rowSelection : this.rowSelection;
7695 this.cellSelection = (typeof(config.cellSelection) != 'undefined') ? config.cellSelection : this.cellSelection;
7696 this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
7697 this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
7699 this.sm = this.sm || {xtype: 'RowSelectionModel'};
7701 this.sm.grid = this;
7702 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
7703 this.sm = this.selModel;
7704 this.sm.xmodule = this.xmodule || false;
7707 if (this.cm && typeof(this.cm.config) == 'undefined') {
7708 this.colModel = new Roo.grid.ColumnModel(this.cm);
7709 this.cm = this.colModel;
7710 this.cm.xmodule = this.xmodule || false;
7713 this.store= Roo.factory(this.store, Roo.data);
7714 this.ds = this.store;
7715 this.ds.xmodule = this.xmodule || false;
7718 if (this.footer && this.store) {
7719 this.footer.dataSource = this.ds;
7720 this.footer = Roo.factory(this.footer);
7727 * Fires when a cell is clicked
7728 * @param {Roo.bootstrap.Table} this
7729 * @param {Roo.Element} el
7730 * @param {Number} rowIndex
7731 * @param {Number} columnIndex
7732 * @param {Roo.EventObject} e
7736 * @event celldblclick
7737 * Fires when a cell is double clicked
7738 * @param {Roo.bootstrap.Table} this
7739 * @param {Roo.Element} el
7740 * @param {Number} rowIndex
7741 * @param {Number} columnIndex
7742 * @param {Roo.EventObject} e
7744 "celldblclick" : true,
7747 * Fires when a row is clicked
7748 * @param {Roo.bootstrap.Table} this
7749 * @param {Roo.Element} el
7750 * @param {Number} rowIndex
7751 * @param {Roo.EventObject} e
7755 * @event rowdblclick
7756 * Fires when a row is double clicked
7757 * @param {Roo.bootstrap.Table} this
7758 * @param {Roo.Element} el
7759 * @param {Number} rowIndex
7760 * @param {Roo.EventObject} e
7762 "rowdblclick" : true,
7765 * Fires when a mouseover occur
7766 * @param {Roo.bootstrap.Table} this
7767 * @param {Roo.Element} el
7768 * @param {Number} rowIndex
7769 * @param {Number} columnIndex
7770 * @param {Roo.EventObject} e
7775 * Fires when a mouseout occur
7776 * @param {Roo.bootstrap.Table} this
7777 * @param {Roo.Element} el
7778 * @param {Number} rowIndex
7779 * @param {Number} columnIndex
7780 * @param {Roo.EventObject} e
7785 * Fires when a row is rendered, so you can change add a style to it.
7786 * @param {Roo.bootstrap.Table} this
7787 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
7791 * @event rowsrendered
7792 * Fires when all the rows have been rendered
7793 * @param {Roo.bootstrap.Table} this
7795 'rowsrendered' : true,
7797 * @event contextmenu
7798 * The raw contextmenu event for the entire grid.
7799 * @param {Roo.EventObject} e
7801 "contextmenu" : true,
7803 * @event rowcontextmenu
7804 * Fires when a row is right clicked
7805 * @param {Roo.bootstrap.Table} this
7806 * @param {Number} rowIndex
7807 * @param {Roo.EventObject} e
7809 "rowcontextmenu" : true,
7811 * @event cellcontextmenu
7812 * Fires when a cell is right clicked
7813 * @param {Roo.bootstrap.Table} this
7814 * @param {Number} rowIndex
7815 * @param {Number} cellIndex
7816 * @param {Roo.EventObject} e
7818 "cellcontextmenu" : true,
7820 * @event headercontextmenu
7821 * Fires when a header is right clicked
7822 * @param {Roo.bootstrap.Table} this
7823 * @param {Number} columnIndex
7824 * @param {Roo.EventObject} e
7826 "headercontextmenu" : true
7830 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
7856 rowSelection : false,
7857 cellSelection : false,
7860 // Roo.Element - the tbody
7862 // Roo.Element - thead element
7865 container: false, // used by gridpanel...
7871 auto_hide_footer : false,
7873 getAutoCreate : function()
7875 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
7882 if (this.scrollBody) {
7883 cfg.cls += ' table-body-fixed';
7886 cfg.cls += ' table-striped';
7890 cfg.cls += ' table-hover';
7892 if (this.bordered) {
7893 cfg.cls += ' table-bordered';
7895 if (this.condensed) {
7896 cfg.cls += ' table-condensed';
7898 if (this.responsive) {
7899 cfg.cls += ' table-responsive';
7903 cfg.cls+= ' ' +this.cls;
7906 // this lot should be simplifed...
7919 ].forEach(function(k) {
7927 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
7930 if(this.store || this.cm){
7931 if(this.headerShow){
7932 cfg.cn.push(this.renderHeader());
7935 cfg.cn.push(this.renderBody());
7937 if(this.footerShow){
7938 cfg.cn.push(this.renderFooter());
7940 // where does this come from?
7941 //cfg.cls+= ' TableGrid';
7944 return { cn : [ cfg ] };
7947 initEvents : function()
7949 if(!this.store || !this.cm){
7952 if (this.selModel) {
7953 this.selModel.initEvents();
7957 //Roo.log('initEvents with ds!!!!');
7959 this.mainBody = this.el.select('tbody', true).first();
7960 this.mainHead = this.el.select('thead', true).first();
7961 this.mainFoot = this.el.select('tfoot', true).first();
7967 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
7968 e.on('click', _this.sort, _this);
7971 this.mainBody.on("click", this.onClick, this);
7972 this.mainBody.on("dblclick", this.onDblClick, this);
7974 // why is this done????? = it breaks dialogs??
7975 //this.parent().el.setStyle('position', 'relative');
7979 this.footer.parentId = this.id;
7980 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
7983 this.el.select('tfoot tr td').first().addClass('hide');
7988 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
7991 this.store.on('load', this.onLoad, this);
7992 this.store.on('beforeload', this.onBeforeLoad, this);
7993 this.store.on('update', this.onUpdate, this);
7994 this.store.on('add', this.onAdd, this);
7995 this.store.on("clear", this.clear, this);
7997 this.el.on("contextmenu", this.onContextMenu, this);
7999 this.mainBody.on('scroll', this.onBodyScroll, this);
8001 this.cm.on("headerchange", this.onHeaderChange, this);
8003 this.cm.on("hiddenchange", this.onHiddenChange, this, arguments);
8007 onContextMenu : function(e, t)
8009 this.processEvent("contextmenu", e);
8012 processEvent : function(name, e)
8014 if (name != 'touchstart' ) {
8015 this.fireEvent(name, e);
8018 var t = e.getTarget();
8020 var cell = Roo.get(t);
8026 if(cell.findParent('tfoot', false, true)){
8030 if(cell.findParent('thead', false, true)){
8032 if(e.getTarget().nodeName.toLowerCase() != 'th'){
8033 cell = Roo.get(t).findParent('th', false, true);
8035 Roo.log("failed to find th in thead?");
8036 Roo.log(e.getTarget());
8041 var cellIndex = cell.dom.cellIndex;
8043 var ename = name == 'touchstart' ? 'click' : name;
8044 this.fireEvent("header" + ename, this, cellIndex, e);
8049 if(e.getTarget().nodeName.toLowerCase() != 'td'){
8050 cell = Roo.get(t).findParent('td', false, true);
8052 Roo.log("failed to find th in tbody?");
8053 Roo.log(e.getTarget());
8058 var row = cell.findParent('tr', false, true);
8059 var cellIndex = cell.dom.cellIndex;
8060 var rowIndex = row.dom.rowIndex - 1;
8064 this.fireEvent("row" + name, this, rowIndex, e);
8068 this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
8074 onMouseover : function(e, el)
8076 var cell = Roo.get(el);
8082 if(e.getTarget().nodeName.toLowerCase() != 'td'){
8083 cell = cell.findParent('td', false, true);
8086 var row = cell.findParent('tr', false, true);
8087 var cellIndex = cell.dom.cellIndex;
8088 var rowIndex = row.dom.rowIndex - 1; // start from 0
8090 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
8094 onMouseout : function(e, el)
8096 var cell = Roo.get(el);
8102 if(e.getTarget().nodeName.toLowerCase() != 'td'){
8103 cell = cell.findParent('td', false, true);
8106 var row = cell.findParent('tr', false, true);
8107 var cellIndex = cell.dom.cellIndex;
8108 var rowIndex = row.dom.rowIndex - 1; // start from 0
8110 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
8114 onClick : function(e, el)
8116 var cell = Roo.get(el);
8118 if(!cell || (!this.cellSelection && !this.rowSelection)){
8122 if(e.getTarget().nodeName.toLowerCase() != 'td'){
8123 cell = cell.findParent('td', false, true);
8126 if(!cell || typeof(cell) == 'undefined'){
8130 var row = cell.findParent('tr', false, true);
8132 if(!row || typeof(row) == 'undefined'){
8136 var cellIndex = cell.dom.cellIndex;
8137 var rowIndex = this.getRowIndex(row);
8139 // why??? - should these not be based on SelectionModel?
8140 if(this.cellSelection){
8141 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
8144 if(this.rowSelection){
8145 this.fireEvent('rowclick', this, row, rowIndex, e);
8151 onDblClick : function(e,el)
8153 var cell = Roo.get(el);
8155 if(!cell || (!this.cellSelection && !this.rowSelection)){
8159 if(e.getTarget().nodeName.toLowerCase() != 'td'){
8160 cell = cell.findParent('td', false, true);
8163 if(!cell || typeof(cell) == 'undefined'){
8167 var row = cell.findParent('tr', false, true);
8169 if(!row || typeof(row) == 'undefined'){
8173 var cellIndex = cell.dom.cellIndex;
8174 var rowIndex = this.getRowIndex(row);
8176 if(this.cellSelection){
8177 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
8180 if(this.rowSelection){
8181 this.fireEvent('rowdblclick', this, row, rowIndex, e);
8185 sort : function(e,el)
8187 var col = Roo.get(el);
8189 if(!col.hasClass('sortable')){
8193 var sort = col.attr('sort');
8196 if(col.select('i', true).first().hasClass('glyphicon-arrow-up')){
8200 this.store.sortInfo = {field : sort, direction : dir};
8203 Roo.log("calling footer first");
8204 this.footer.onClick('first');
8207 this.store.load({ params : { start : 0 } });
8211 renderHeader : function()
8219 this.totalWidth = 0;
8221 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
8223 var config = cm.config[i];
8227 cls : 'x-hcol-' + i,
8229 html: cm.getColumnHeader(i)
8234 if(typeof(config.sortable) != 'undefined' && config.sortable){
8236 c.html = '<i class="glyphicon"></i>' + c.html;
8239 // could use BS4 hidden-..-down
8241 if(typeof(config.lgHeader) != 'undefined'){
8242 hh += '<span class="hidden-xs hidden-sm hidden-md ">' + config.lgHeader + '</span>';
8245 if(typeof(config.mdHeader) != 'undefined'){
8246 hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
8249 if(typeof(config.smHeader) != 'undefined'){
8250 hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
8253 if(typeof(config.xsHeader) != 'undefined'){
8254 hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
8261 if(typeof(config.tooltip) != 'undefined'){
8262 c.tooltip = config.tooltip;
8265 if(typeof(config.colspan) != 'undefined'){
8266 c.colspan = config.colspan;
8269 if(typeof(config.hidden) != 'undefined' && config.hidden){
8270 c.style += ' display:none;';
8273 if(typeof(config.dataIndex) != 'undefined'){
8274 c.sort = config.dataIndex;
8279 if(typeof(config.align) != 'undefined' && config.align.length){
8280 c.style += ' text-align:' + config.align + ';';
8283 if(typeof(config.width) != 'undefined'){
8284 c.style += ' width:' + config.width + 'px;';
8285 this.totalWidth += config.width;
8287 this.totalWidth += 100; // assume minimum of 100 per column?
8290 if(typeof(config.cls) != 'undefined'){
8291 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
8294 ['xs','sm','md','lg'].map(function(size){
8296 if(typeof(config[size]) == 'undefined'){
8300 if (!config[size]) { // 0 = hidden
8301 // BS 4 '0' is treated as hide that column and below.
8302 c.cls += ' hidden-' + size + ' hidden' + size + '-down';
8306 c.cls += ' col-' + size + '-' + config[size] + (
8307 size == 'xs' ? (' col-' + config[size] ) : '' // bs4 col-{num} replaces col-xs
8319 renderBody : function()
8329 colspan : this.cm.getColumnCount()
8339 renderFooter : function()
8349 colspan : this.cm.getColumnCount()
8363 // Roo.log('ds onload');
8368 var ds = this.store;
8370 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
8371 e.select('i', true).removeClass(['glyphicon-arrow-up', 'glyphicon-arrow-down']);
8372 if (_this.store.sortInfo) {
8374 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
8375 e.select('i', true).addClass(['glyphicon-arrow-up']);
8378 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
8379 e.select('i', true).addClass(['glyphicon-arrow-down']);
8384 var tbody = this.mainBody;
8386 if(ds.getCount() > 0){
8387 ds.data.each(function(d,rowIndex){
8388 var row = this.renderRow(cm, ds, rowIndex);
8390 tbody.createChild(row);
8394 if(row.cellObjects.length){
8395 Roo.each(row.cellObjects, function(r){
8396 _this.renderCellObject(r);
8403 var tfoot = this.el.select('tfoot', true).first();
8405 if(this.footerShow && this.auto_hide_footer && this.mainFoot){
8407 this.mainFoot.setVisibilityMode(Roo.Element.DISPLAY).hide();
8409 var total = this.ds.getTotalCount();
8411 if(this.footer.pageSize < total){
8412 this.mainFoot.show();
8416 Roo.each(this.el.select('tbody td', true).elements, function(e){
8417 e.on('mouseover', _this.onMouseover, _this);
8420 Roo.each(this.el.select('tbody td', true).elements, function(e){
8421 e.on('mouseout', _this.onMouseout, _this);
8423 this.fireEvent('rowsrendered', this);
8429 onUpdate : function(ds,record)
8431 this.refreshRow(record);
8435 onRemove : function(ds, record, index, isUpdate){
8436 if(isUpdate !== true){
8437 this.fireEvent("beforerowremoved", this, index, record);
8439 var bt = this.mainBody.dom;
8441 var rows = this.el.select('tbody > tr', true).elements;
8443 if(typeof(rows[index]) != 'undefined'){
8444 bt.removeChild(rows[index].dom);
8447 // if(bt.rows[index]){
8448 // bt.removeChild(bt.rows[index]);
8451 if(isUpdate !== true){
8452 //this.stripeRows(index);
8453 //this.syncRowHeights(index, index);
8455 this.fireEvent("rowremoved", this, index, record);
8459 onAdd : function(ds, records, rowIndex)
8461 //Roo.log('on Add called');
8462 // - note this does not handle multiple adding very well..
8463 var bt = this.mainBody.dom;
8464 for (var i =0 ; i < records.length;i++) {
8465 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
8466 //Roo.log(records[i]);
8467 //Roo.log(this.store.getAt(rowIndex+i));
8468 this.insertRow(this.store, rowIndex + i, false);
8475 refreshRow : function(record){
8476 var ds = this.store, index;
8477 if(typeof record == 'number'){
8479 record = ds.getAt(index);
8481 index = ds.indexOf(record);
8483 return; // should not happen - but seems to
8486 this.insertRow(ds, index, true);
8488 this.onRemove(ds, record, index+1, true);
8490 //this.syncRowHeights(index, index);
8492 this.fireEvent("rowupdated", this, index, record);
8495 insertRow : function(dm, rowIndex, isUpdate){
8498 this.fireEvent("beforerowsinserted", this, rowIndex);
8500 //var s = this.getScrollState();
8501 var row = this.renderRow(this.cm, this.store, rowIndex);
8502 // insert before rowIndex..
8503 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
8507 if(row.cellObjects.length){
8508 Roo.each(row.cellObjects, function(r){
8509 _this.renderCellObject(r);
8514 this.fireEvent("rowsinserted", this, rowIndex);
8515 //this.syncRowHeights(firstRow, lastRow);
8516 //this.stripeRows(firstRow);
8523 getRowDom : function(rowIndex)
8525 var rows = this.el.select('tbody > tr', true).elements;
8527 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
8530 // returns the object tree for a tr..
8533 renderRow : function(cm, ds, rowIndex)
8535 var d = ds.getAt(rowIndex);
8539 cls : 'x-row-' + rowIndex,
8543 var cellObjects = [];
8545 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
8546 var config = cm.config[i];
8548 var renderer = cm.getRenderer(i);
8552 if(typeof(renderer) !== 'undefined'){
8553 value = renderer(d.data[cm.getDataIndex(i)], false, d);
8555 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
8556 // and are rendered into the cells after the row is rendered - using the id for the element.
8558 if(typeof(value) === 'object'){
8568 rowIndex : rowIndex,
8573 this.fireEvent('rowclass', this, rowcfg);
8577 cls : rowcfg.rowClass + ' x-col-' + i,
8579 html: (typeof(value) === 'object') ? '' : value
8586 if(typeof(config.colspan) != 'undefined'){
8587 td.colspan = config.colspan;
8590 if(typeof(config.hidden) != 'undefined' && config.hidden){
8591 td.style += ' display:none;';
8594 if(typeof(config.align) != 'undefined' && config.align.length){
8595 td.style += ' text-align:' + config.align + ';';
8597 if(typeof(config.valign) != 'undefined' && config.valign.length){
8598 td.style += ' vertical-align:' + config.valign + ';';
8601 if(typeof(config.width) != 'undefined'){
8602 td.style += ' width:' + config.width + 'px;';
8605 if(typeof(config.cursor) != 'undefined'){
8606 td.style += ' cursor:' + config.cursor + ';';
8609 if(typeof(config.cls) != 'undefined'){
8610 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
8613 ['xs','sm','md','lg'].map(function(size){
8615 if(typeof(config[size]) == 'undefined'){
8621 if (!config[size]) { // 0 = hidden
8622 // BS 4 '0' is treated as hide that column and below.
8623 td.cls += ' hidden-' + size + ' hidden' + size + '-down';
8627 td.cls += ' col-' + size + '-' + config[size] + (
8628 size == 'xs' ? (' col-' + config[size] ) : '' // bs4 col-{num} replaces col-xs
8638 row.cellObjects = cellObjects;
8646 onBeforeLoad : function()
8655 this.el.select('tbody', true).first().dom.innerHTML = '';
8658 * Show or hide a row.
8659 * @param {Number} rowIndex to show or hide
8660 * @param {Boolean} state hide
8662 setRowVisibility : function(rowIndex, state)
8664 var bt = this.mainBody.dom;
8666 var rows = this.el.select('tbody > tr', true).elements;
8668 if(typeof(rows[rowIndex]) == 'undefined'){
8671 rows[rowIndex].dom.style.display = state ? '' : 'none';
8675 getSelectionModel : function(){
8677 this.selModel = new Roo.bootstrap.Table.RowSelectionModel({grid: this});
8679 return this.selModel;
8682 * Render the Roo.bootstrap object from renderder
8684 renderCellObject : function(r)
8688 r.cfg.parentId = (typeof(r.container) == 'string') ? r.container : r.container.id;
8690 var t = r.cfg.render(r.container);
8693 Roo.each(r.cfg.cn, function(c){
8695 container: t.getChildContainer(),
8698 _this.renderCellObject(child);
8703 getRowIndex : function(row)
8707 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
8718 * Returns the grid's underlying element = used by panel.Grid
8719 * @return {Element} The element
8721 getGridEl : function(){
8725 * Forces a resize - used by panel.Grid
8726 * @return {Element} The element
8728 autoSize : function()
8730 //var ctr = Roo.get(this.container.dom.parentElement);
8731 var ctr = Roo.get(this.el.dom);
8733 var thd = this.getGridEl().select('thead',true).first();
8734 var tbd = this.getGridEl().select('tbody', true).first();
8735 var tfd = this.getGridEl().select('tfoot', true).first();
8737 var cw = ctr.getWidth();
8738 this.getGridEl().select('tfoot tr, tfoot td',true).setWidth(cw);
8742 tbd.setWidth(ctr.getWidth());
8743 // if the body has a max height - and then scrolls - we should perhaps set up the height here
8744 // this needs fixing for various usage - currently only hydra job advers I think..
8746 // ctr.getHeight() - ((thd ? thd.getHeight() : 0) + (tfd ? tfd.getHeight() : 0))
8748 var barsize = (tbd.dom.offsetWidth - tbd.dom.clientWidth);
8751 cw = Math.max(cw, this.totalWidth);
8752 this.getGridEl().select('tbody tr',true).setWidth(cw);
8754 // resize 'expandable coloumn?
8756 return; // we doe not have a view in this design..
8759 onBodyScroll: function()
8761 //Roo.log("body scrolled');" + this.mainBody.dom.scrollLeft);
8763 this.mainHead.setStyle({
8764 'position' : 'relative',
8765 'left': (-1* this.mainBody.dom.scrollLeft) + 'px'
8771 var scrollHeight = this.mainBody.dom.scrollHeight;
8773 var scrollTop = Math.ceil(this.mainBody.getScroll().top);
8775 var height = this.mainBody.getHeight();
8777 if(scrollHeight - height == scrollTop) {
8779 var total = this.ds.getTotalCount();
8781 if(this.footer.cursor + this.footer.pageSize < total){
8783 this.footer.ds.load({
8785 start : this.footer.cursor + this.footer.pageSize,
8786 limit : this.footer.pageSize
8796 onHeaderChange : function()
8798 var header = this.renderHeader();
8799 var table = this.el.select('table', true).first();
8801 this.mainHead.remove();
8802 this.mainHead = table.createChild(header, this.mainBody, false);
8805 onHiddenChange : function(colModel, colIndex, hidden)
8807 var thSelector = '#' + this.id + ' .x-hcol-' + colIndex;
8808 var tdSelector = '#' + this.id + ' .x-col-' + colIndex;
8810 this.CSS.updateRule(thSelector, "display", "");
8811 this.CSS.updateRule(tdSelector, "display", "");
8814 this.CSS.updateRule(thSelector, "display", "none");
8815 this.CSS.updateRule(tdSelector, "display", "none");
8818 this.onHeaderChange();
8822 setColumnWidth: function(col_index, width)
8824 // width = "md-2 xs-2..."
8825 if(!this.colModel.config[col_index]) {
8829 var w = width.split(" ");
8831 var rows = this.el.dom.getElementsByClassName("x-col-"+col_index);
8833 var h_row = this.el.dom.getElementsByClassName("x-hcol-"+col_index);
8836 for(var j = 0; j < w.length; j++) {
8842 var size_cls = w[j].split("-");
8844 if(!Number.isInteger(size_cls[1] * 1)) {
8848 if(!this.colModel.config[col_index][size_cls[0]]) {
8852 if(!h_row[0].classList.contains("col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]])) {
8856 h_row[0].classList.replace(
8857 "col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]],
8858 "col-"+size_cls[0]+"-"+size_cls[1]
8861 for(var i = 0; i < rows.length; i++) {
8863 var size_cls = w[j].split("-");
8865 if(!Number.isInteger(size_cls[1] * 1)) {
8869 if(!this.colModel.config[col_index][size_cls[0]]) {
8873 if(!rows[i].classList.contains("col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]])) {
8877 rows[i].classList.replace(
8878 "col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]],
8879 "col-"+size_cls[0]+"-"+size_cls[1]
8883 this.colModel.config[col_index][size_cls[0]] = size_cls[1];
8898 * @class Roo.bootstrap.TableCell
8899 * @extends Roo.bootstrap.Component
8900 * Bootstrap TableCell class
8901 * @cfg {String} html cell contain text
8902 * @cfg {String} cls cell class
8903 * @cfg {String} tag cell tag (td|th) default td
8904 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
8905 * @cfg {String} align Aligns the content in a cell
8906 * @cfg {String} axis Categorizes cells
8907 * @cfg {String} bgcolor Specifies the background color of a cell
8908 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
8909 * @cfg {Number} colspan Specifies the number of columns a cell should span
8910 * @cfg {String} headers Specifies one or more header cells a cell is related to
8911 * @cfg {Number} height Sets the height of a cell
8912 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
8913 * @cfg {Number} rowspan Sets the number of rows a cell should span
8914 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
8915 * @cfg {String} valign Vertical aligns the content in a cell
8916 * @cfg {Number} width Specifies the width of a cell
8919 * Create a new TableCell
8920 * @param {Object} config The config object
8923 Roo.bootstrap.TableCell = function(config){
8924 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
8927 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
8947 getAutoCreate : function(){
8948 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
8968 cfg.align=this.align
8974 cfg.bgcolor=this.bgcolor
8977 cfg.charoff=this.charoff
8980 cfg.colspan=this.colspan
8983 cfg.headers=this.headers
8986 cfg.height=this.height
8989 cfg.nowrap=this.nowrap
8992 cfg.rowspan=this.rowspan
8995 cfg.scope=this.scope
8998 cfg.valign=this.valign
9001 cfg.width=this.width
9020 * @class Roo.bootstrap.TableRow
9021 * @extends Roo.bootstrap.Component
9022 * Bootstrap TableRow class
9023 * @cfg {String} cls row class
9024 * @cfg {String} align Aligns the content in a table row
9025 * @cfg {String} bgcolor Specifies a background color for a table row
9026 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
9027 * @cfg {String} valign Vertical aligns the content in a table row
9030 * Create a new TableRow
9031 * @param {Object} config The config object
9034 Roo.bootstrap.TableRow = function(config){
9035 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
9038 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
9046 getAutoCreate : function(){
9047 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
9057 cfg.align = this.align;
9060 cfg.bgcolor = this.bgcolor;
9063 cfg.charoff = this.charoff;
9066 cfg.valign = this.valign;
9084 * @class Roo.bootstrap.TableBody
9085 * @extends Roo.bootstrap.Component
9086 * Bootstrap TableBody class
9087 * @cfg {String} cls element class
9088 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
9089 * @cfg {String} align Aligns the content inside the element
9090 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
9091 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
9094 * Create a new TableBody
9095 * @param {Object} config The config object
9098 Roo.bootstrap.TableBody = function(config){
9099 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
9102 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
9110 getAutoCreate : function(){
9111 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
9125 cfg.align = this.align;
9128 cfg.charoff = this.charoff;
9131 cfg.valign = this.valign;
9138 // initEvents : function()
9145 // this.store = Roo.factory(this.store, Roo.data);
9146 // this.store.on('load', this.onLoad, this);
9148 // this.store.load();
9152 // onLoad: function ()
9154 // this.fireEvent('load', this);
9164 * Ext JS Library 1.1.1
9165 * Copyright(c) 2006-2007, Ext JS, LLC.
9167 * Originally Released Under LGPL - original licence link has changed is not relivant.
9170 * <script type="text/javascript">
9173 // as we use this in bootstrap.
9174 Roo.namespace('Roo.form');
9176 * @class Roo.form.Action
9177 * Internal Class used to handle form actions
9179 * @param {Roo.form.BasicForm} el The form element or its id
9180 * @param {Object} config Configuration options
9185 // define the action interface
9186 Roo.form.Action = function(form, options){
9188 this.options = options || {};
9191 * Client Validation Failed
9194 Roo.form.Action.CLIENT_INVALID = 'client';
9196 * Server Validation Failed
9199 Roo.form.Action.SERVER_INVALID = 'server';
9201 * Connect to Server Failed
9204 Roo.form.Action.CONNECT_FAILURE = 'connect';
9206 * Reading Data from Server Failed
9209 Roo.form.Action.LOAD_FAILURE = 'load';
9211 Roo.form.Action.prototype = {
9213 failureType : undefined,
9214 response : undefined,
9218 run : function(options){
9223 success : function(response){
9228 handleResponse : function(response){
9232 // default connection failure
9233 failure : function(response){
9235 this.response = response;
9236 this.failureType = Roo.form.Action.CONNECT_FAILURE;
9237 this.form.afterAction(this, false);
9240 processResponse : function(response){
9241 this.response = response;
9242 if(!response.responseText){
9245 this.result = this.handleResponse(response);
9249 // utility functions used internally
9250 getUrl : function(appendParams){
9251 var url = this.options.url || this.form.url || this.form.el.dom.action;
9253 var p = this.getParams();
9255 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
9261 getMethod : function(){
9262 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
9265 getParams : function(){
9266 var bp = this.form.baseParams;
9267 var p = this.options.params;
9269 if(typeof p == "object"){
9270 p = Roo.urlEncode(Roo.applyIf(p, bp));
9271 }else if(typeof p == 'string' && bp){
9272 p += '&' + Roo.urlEncode(bp);
9275 p = Roo.urlEncode(bp);
9280 createCallback : function(){
9282 success: this.success,
9283 failure: this.failure,
9285 timeout: (this.form.timeout*1000),
9286 upload: this.form.fileUpload ? this.success : undefined
9291 Roo.form.Action.Submit = function(form, options){
9292 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
9295 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
9298 haveProgress : false,
9299 uploadComplete : false,
9301 // uploadProgress indicator.
9302 uploadProgress : function()
9304 if (!this.form.progressUrl) {
9308 if (!this.haveProgress) {
9309 Roo.MessageBox.progress("Uploading", "Uploading");
9311 if (this.uploadComplete) {
9312 Roo.MessageBox.hide();
9316 this.haveProgress = true;
9318 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
9320 var c = new Roo.data.Connection();
9322 url : this.form.progressUrl,
9327 success : function(req){
9328 //console.log(data);
9332 rdata = Roo.decode(req.responseText)
9334 Roo.log("Invalid data from server..");
9338 if (!rdata || !rdata.success) {
9340 Roo.MessageBox.alert(Roo.encode(rdata));
9343 var data = rdata.data;
9345 if (this.uploadComplete) {
9346 Roo.MessageBox.hide();
9351 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
9352 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
9355 this.uploadProgress.defer(2000,this);
9358 failure: function(data) {
9359 Roo.log('progress url failed ');
9370 // run get Values on the form, so it syncs any secondary forms.
9371 this.form.getValues();
9373 var o = this.options;
9374 var method = this.getMethod();
9375 var isPost = method == 'POST';
9376 if(o.clientValidation === false || this.form.isValid()){
9378 if (this.form.progressUrl) {
9379 this.form.findField('UPLOAD_IDENTIFIER').setValue(
9380 (new Date() * 1) + '' + Math.random());
9385 Roo.Ajax.request(Roo.apply(this.createCallback(), {
9386 form:this.form.el.dom,
9387 url:this.getUrl(!isPost),
9389 params:isPost ? this.getParams() : null,
9390 isUpload: this.form.fileUpload,
9391 formData : this.form.formData
9394 this.uploadProgress();
9396 }else if (o.clientValidation !== false){ // client validation failed
9397 this.failureType = Roo.form.Action.CLIENT_INVALID;
9398 this.form.afterAction(this, false);
9402 success : function(response)
9404 this.uploadComplete= true;
9405 if (this.haveProgress) {
9406 Roo.MessageBox.hide();
9410 var result = this.processResponse(response);
9411 if(result === true || result.success){
9412 this.form.afterAction(this, true);
9416 this.form.markInvalid(result.errors);
9417 this.failureType = Roo.form.Action.SERVER_INVALID;
9419 this.form.afterAction(this, false);
9421 failure : function(response)
9423 this.uploadComplete= true;
9424 if (this.haveProgress) {
9425 Roo.MessageBox.hide();
9428 this.response = response;
9429 this.failureType = Roo.form.Action.CONNECT_FAILURE;
9430 this.form.afterAction(this, false);
9433 handleResponse : function(response){
9434 if(this.form.errorReader){
9435 var rs = this.form.errorReader.read(response);
9438 for(var i = 0, len = rs.records.length; i < len; i++) {
9439 var r = rs.records[i];
9443 if(errors.length < 1){
9447 success : rs.success,
9453 ret = Roo.decode(response.responseText);
9457 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
9467 Roo.form.Action.Load = function(form, options){
9468 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
9469 this.reader = this.form.reader;
9472 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
9477 Roo.Ajax.request(Roo.apply(
9478 this.createCallback(), {
9479 method:this.getMethod(),
9480 url:this.getUrl(false),
9481 params:this.getParams()
9485 success : function(response){
9487 var result = this.processResponse(response);
9488 if(result === true || !result.success || !result.data){
9489 this.failureType = Roo.form.Action.LOAD_FAILURE;
9490 this.form.afterAction(this, false);
9493 this.form.clearInvalid();
9494 this.form.setValues(result.data);
9495 this.form.afterAction(this, true);
9498 handleResponse : function(response){
9499 if(this.form.reader){
9500 var rs = this.form.reader.read(response);
9501 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
9503 success : rs.success,
9507 return Roo.decode(response.responseText);
9511 Roo.form.Action.ACTION_TYPES = {
9512 'load' : Roo.form.Action.Load,
9513 'submit' : Roo.form.Action.Submit
9522 * @class Roo.bootstrap.Form
9523 * @extends Roo.bootstrap.Component
9524 * Bootstrap Form class
9525 * @cfg {String} method GET | POST (default POST)
9526 * @cfg {String} labelAlign top | left (default top)
9527 * @cfg {String} align left | right - for navbars
9528 * @cfg {Boolean} loadMask load mask when submit (default true)
9533 * @param {Object} config The config object
9537 Roo.bootstrap.Form = function(config){
9539 Roo.bootstrap.Form.superclass.constructor.call(this, config);
9541 Roo.bootstrap.Form.popover.apply();
9545 * @event clientvalidation
9546 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
9547 * @param {Form} this
9548 * @param {Boolean} valid true if the form has passed client-side validation
9550 clientvalidation: true,
9552 * @event beforeaction
9553 * Fires before any action is performed. Return false to cancel the action.
9554 * @param {Form} this
9555 * @param {Action} action The action to be performed
9559 * @event actionfailed
9560 * Fires when an action fails.
9561 * @param {Form} this
9562 * @param {Action} action The action that failed
9564 actionfailed : true,
9566 * @event actioncomplete
9567 * Fires when an action is completed.
9568 * @param {Form} this
9569 * @param {Action} action The action that completed
9571 actioncomplete : true
9575 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
9578 * @cfg {String} method
9579 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
9584 * The URL to use for form actions if one isn't supplied in the action options.
9587 * @cfg {Boolean} fileUpload
9588 * Set to true if this form is a file upload.
9592 * @cfg {Object} baseParams
9593 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
9597 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
9601 * @cfg {Sting} align (left|right) for navbar forms
9606 activeAction : null,
9609 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
9610 * element by passing it or its id or mask the form itself by passing in true.
9613 waitMsgTarget : false,
9618 * @cfg {Boolean} errorMask (true|false) default false
9623 * @cfg {Number} maskOffset Default 100
9628 * @cfg {Boolean} maskBody
9632 getAutoCreate : function(){
9636 method : this.method || 'POST',
9637 id : this.id || Roo.id(),
9640 if (this.parent().xtype.match(/^Nav/)) {
9641 cfg.cls = 'navbar-form form-inline navbar-' + this.align;
9645 if (this.labelAlign == 'left' ) {
9646 cfg.cls += ' form-horizontal';
9652 initEvents : function()
9654 this.el.on('submit', this.onSubmit, this);
9655 // this was added as random key presses on the form where triggering form submit.
9656 this.el.on('keypress', function(e) {
9657 if (e.getCharCode() != 13) {
9660 // we might need to allow it for textareas.. and some other items.
9661 // check e.getTarget().
9663 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
9667 Roo.log("keypress blocked");
9675 onSubmit : function(e){
9680 * Returns true if client-side validation on the form is successful.
9683 isValid : function(){
9684 var items = this.getItems();
9688 items.each(function(f){
9694 Roo.log('invalid field: ' + f.name);
9698 if(!target && f.el.isVisible(true)){
9704 if(this.errorMask && !valid){
9705 Roo.bootstrap.Form.popover.mask(this, target);
9712 * Returns true if any fields in this form have changed since their original load.
9715 isDirty : function(){
9717 var items = this.getItems();
9718 items.each(function(f){
9728 * Performs a predefined action (submit or load) or custom actions you define on this form.
9729 * @param {String} actionName The name of the action type
9730 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
9731 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
9732 * accept other config options):
9734 Property Type Description
9735 ---------------- --------------- ----------------------------------------------------------------------------------
9736 url String The url for the action (defaults to the form's url)
9737 method String The form method to use (defaults to the form's method, or POST if not defined)
9738 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
9739 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
9740 validate the form on the client (defaults to false)
9742 * @return {BasicForm} this
9744 doAction : function(action, options){
9745 if(typeof action == 'string'){
9746 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
9748 if(this.fireEvent('beforeaction', this, action) !== false){
9749 this.beforeAction(action);
9750 action.run.defer(100, action);
9756 beforeAction : function(action){
9757 var o = action.options;
9762 Roo.get(document.body).mask(o.waitMsg || "Sending", 'x-mask-loading')
9764 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
9767 // not really supported yet.. ??
9769 //if(this.waitMsgTarget === true){
9770 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
9771 //}else if(this.waitMsgTarget){
9772 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
9773 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
9775 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
9781 afterAction : function(action, success){
9782 this.activeAction = null;
9783 var o = action.options;
9788 Roo.get(document.body).unmask();
9794 //if(this.waitMsgTarget === true){
9795 // this.el.unmask();
9796 //}else if(this.waitMsgTarget){
9797 // this.waitMsgTarget.unmask();
9799 // Roo.MessageBox.updateProgress(1);
9800 // Roo.MessageBox.hide();
9807 Roo.callback(o.success, o.scope, [this, action]);
9808 this.fireEvent('actioncomplete', this, action);
9812 // failure condition..
9813 // we have a scenario where updates need confirming.
9814 // eg. if a locking scenario exists..
9815 // we look for { errors : { needs_confirm : true }} in the response.
9817 (typeof(action.result) != 'undefined') &&
9818 (typeof(action.result.errors) != 'undefined') &&
9819 (typeof(action.result.errors.needs_confirm) != 'undefined')
9822 Roo.log("not supported yet");
9825 Roo.MessageBox.confirm(
9826 "Change requires confirmation",
9827 action.result.errorMsg,
9832 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
9842 Roo.callback(o.failure, o.scope, [this, action]);
9843 // show an error message if no failed handler is set..
9844 if (!this.hasListener('actionfailed')) {
9845 Roo.log("need to add dialog support");
9847 Roo.MessageBox.alert("Error",
9848 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
9849 action.result.errorMsg :
9850 "Saving Failed, please check your entries or try again"
9855 this.fireEvent('actionfailed', this, action);
9860 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
9861 * @param {String} id The value to search for
9864 findField : function(id){
9865 var items = this.getItems();
9866 var field = items.get(id);
9868 items.each(function(f){
9869 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
9876 return field || null;
9879 * Mark fields in this form invalid in bulk.
9880 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
9881 * @return {BasicForm} this
9883 markInvalid : function(errors){
9884 if(errors instanceof Array){
9885 for(var i = 0, len = errors.length; i < len; i++){
9886 var fieldError = errors[i];
9887 var f = this.findField(fieldError.id);
9889 f.markInvalid(fieldError.msg);
9895 if(typeof errors[id] != 'function' && (field = this.findField(id))){
9896 field.markInvalid(errors[id]);
9900 //Roo.each(this.childForms || [], function (f) {
9901 // f.markInvalid(errors);
9908 * Set values for fields in this form in bulk.
9909 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
9910 * @return {BasicForm} this
9912 setValues : function(values){
9913 if(values instanceof Array){ // array of objects
9914 for(var i = 0, len = values.length; i < len; i++){
9916 var f = this.findField(v.id);
9918 f.setValue(v.value);
9919 if(this.trackResetOnLoad){
9920 f.originalValue = f.getValue();
9924 }else{ // object hash
9927 if(typeof values[id] != 'function' && (field = this.findField(id))){
9929 if (field.setFromData &&
9931 field.displayField &&
9932 // combos' with local stores can
9933 // be queried via setValue()
9934 // to set their value..
9935 (field.store && !field.store.isLocal)
9939 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
9940 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
9941 field.setFromData(sd);
9943 } else if(field.setFromData && (field.store && !field.store.isLocal)) {
9945 field.setFromData(values);
9948 field.setValue(values[id]);
9952 if(this.trackResetOnLoad){
9953 field.originalValue = field.getValue();
9959 //Roo.each(this.childForms || [], function (f) {
9960 // f.setValues(values);
9967 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
9968 * they are returned as an array.
9969 * @param {Boolean} asString
9972 getValues : function(asString){
9973 //if (this.childForms) {
9974 // copy values from the child forms
9975 // Roo.each(this.childForms, function (f) {
9976 // this.setValues(f.getValues());
9982 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
9983 if(asString === true){
9986 return Roo.urlDecode(fs);
9990 * Returns the fields in this form as an object with key/value pairs.
9991 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
9994 getFieldValues : function(with_hidden)
9996 var items = this.getItems();
9998 items.each(function(f){
10000 if (!f.getName()) {
10004 var v = f.getValue();
10006 if (f.inputType =='radio') {
10007 if (typeof(ret[f.getName()]) == 'undefined') {
10008 ret[f.getName()] = ''; // empty..
10011 if (!f.el.dom.checked) {
10015 v = f.el.dom.value;
10019 if(f.xtype == 'MoneyField'){
10020 ret[f.currencyName] = f.getCurrency();
10023 // not sure if this supported any more..
10024 if ((typeof(v) == 'object') && f.getRawValue) {
10025 v = f.getRawValue() ; // dates..
10027 // combo boxes where name != hiddenName...
10028 if (f.name !== false && f.name != '' && f.name != f.getName()) {
10029 ret[f.name] = f.getRawValue();
10031 ret[f.getName()] = v;
10038 * Clears all invalid messages in this form.
10039 * @return {BasicForm} this
10041 clearInvalid : function(){
10042 var items = this.getItems();
10044 items.each(function(f){
10052 * Resets this form.
10053 * @return {BasicForm} this
10055 reset : function(){
10056 var items = this.getItems();
10057 items.each(function(f){
10061 Roo.each(this.childForms || [], function (f) {
10069 getItems : function()
10071 var r=new Roo.util.MixedCollection(false, function(o){
10072 return o.id || (o.id = Roo.id());
10074 var iter = function(el) {
10081 Roo.each(el.items,function(e) {
10090 hideFields : function(items)
10092 Roo.each(items, function(i){
10094 var f = this.findField(i);
10105 showFields : function(items)
10107 Roo.each(items, function(i){
10109 var f = this.findField(i);
10122 Roo.apply(Roo.bootstrap.Form, {
10138 intervalID : false,
10144 if(this.isApplied){
10149 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
10150 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
10151 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
10152 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
10155 this.maskEl.top.enableDisplayMode("block");
10156 this.maskEl.left.enableDisplayMode("block");
10157 this.maskEl.bottom.enableDisplayMode("block");
10158 this.maskEl.right.enableDisplayMode("block");
10160 this.toolTip = new Roo.bootstrap.Tooltip({
10161 cls : 'roo-form-error-popover',
10163 'left' : ['r-l', [-2,0], 'right'],
10164 'right' : ['l-r', [2,0], 'left'],
10165 'bottom' : ['tl-bl', [0,2], 'top'],
10166 'top' : [ 'bl-tl', [0,-2], 'bottom']
10170 this.toolTip.render(Roo.get(document.body));
10172 this.toolTip.el.enableDisplayMode("block");
10174 Roo.get(document.body).on('click', function(){
10178 Roo.get(document.body).on('touchstart', function(){
10182 this.isApplied = true
10185 mask : function(form, target)
10189 this.target = target;
10191 if(!this.form.errorMask || !target.el){
10195 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.modal', 100, true) || Roo.get(document.body);
10197 Roo.log(scrollable);
10199 var ot = this.target.el.calcOffsetsTo(scrollable);
10201 var scrollTo = ot[1] - this.form.maskOffset;
10203 scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
10205 scrollable.scrollTo('top', scrollTo);
10207 var box = this.target.el.getBox();
10209 var zIndex = Roo.bootstrap.Modal.zIndex++;
10212 this.maskEl.top.setStyle('position', 'absolute');
10213 this.maskEl.top.setStyle('z-index', zIndex);
10214 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
10215 this.maskEl.top.setLeft(0);
10216 this.maskEl.top.setTop(0);
10217 this.maskEl.top.show();
10219 this.maskEl.left.setStyle('position', 'absolute');
10220 this.maskEl.left.setStyle('z-index', zIndex);
10221 this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
10222 this.maskEl.left.setLeft(0);
10223 this.maskEl.left.setTop(box.y - this.padding);
10224 this.maskEl.left.show();
10226 this.maskEl.bottom.setStyle('position', 'absolute');
10227 this.maskEl.bottom.setStyle('z-index', zIndex);
10228 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
10229 this.maskEl.bottom.setLeft(0);
10230 this.maskEl.bottom.setTop(box.bottom + this.padding);
10231 this.maskEl.bottom.show();
10233 this.maskEl.right.setStyle('position', 'absolute');
10234 this.maskEl.right.setStyle('z-index', zIndex);
10235 this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
10236 this.maskEl.right.setLeft(box.right + this.padding);
10237 this.maskEl.right.setTop(box.y - this.padding);
10238 this.maskEl.right.show();
10240 this.toolTip.bindEl = this.target.el;
10242 this.toolTip.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
10244 var tip = this.target.blankText;
10246 if(this.target.getValue() !== '' ) {
10248 if (this.target.invalidText.length) {
10249 tip = this.target.invalidText;
10250 } else if (this.target.regexText.length){
10251 tip = this.target.regexText;
10255 this.toolTip.show(tip);
10257 this.intervalID = window.setInterval(function() {
10258 Roo.bootstrap.Form.popover.unmask();
10261 window.onwheel = function(){ return false;};
10263 (function(){ this.isMasked = true; }).defer(500, this);
10267 unmask : function()
10269 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
10273 this.maskEl.top.setStyle('position', 'absolute');
10274 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
10275 this.maskEl.top.hide();
10277 this.maskEl.left.setStyle('position', 'absolute');
10278 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
10279 this.maskEl.left.hide();
10281 this.maskEl.bottom.setStyle('position', 'absolute');
10282 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
10283 this.maskEl.bottom.hide();
10285 this.maskEl.right.setStyle('position', 'absolute');
10286 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
10287 this.maskEl.right.hide();
10289 this.toolTip.hide();
10291 this.toolTip.el.hide();
10293 window.onwheel = function(){ return true;};
10295 if(this.intervalID){
10296 window.clearInterval(this.intervalID);
10297 this.intervalID = false;
10300 this.isMasked = false;
10310 * Ext JS Library 1.1.1
10311 * Copyright(c) 2006-2007, Ext JS, LLC.
10313 * Originally Released Under LGPL - original licence link has changed is not relivant.
10316 * <script type="text/javascript">
10319 * @class Roo.form.VTypes
10320 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
10323 Roo.form.VTypes = function(){
10324 // closure these in so they are only created once.
10325 var alpha = /^[a-zA-Z_]+$/;
10326 var alphanum = /^[a-zA-Z0-9_]+$/;
10327 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
10328 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
10330 // All these messages and functions are configurable
10333 * The function used to validate email addresses
10334 * @param {String} value The email address
10336 'email' : function(v){
10337 return email.test(v);
10340 * The error text to display when the email validation function returns false
10343 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
10345 * The keystroke filter mask to be applied on email input
10348 'emailMask' : /[a-z0-9_\.\-@]/i,
10351 * The function used to validate URLs
10352 * @param {String} value The URL
10354 'url' : function(v){
10355 return url.test(v);
10358 * The error text to display when the url validation function returns false
10361 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
10364 * The function used to validate alpha values
10365 * @param {String} value The value
10367 'alpha' : function(v){
10368 return alpha.test(v);
10371 * The error text to display when the alpha validation function returns false
10374 'alphaText' : 'This field should only contain letters and _',
10376 * The keystroke filter mask to be applied on alpha input
10379 'alphaMask' : /[a-z_]/i,
10382 * The function used to validate alphanumeric values
10383 * @param {String} value The value
10385 'alphanum' : function(v){
10386 return alphanum.test(v);
10389 * The error text to display when the alphanumeric validation function returns false
10392 'alphanumText' : 'This field should only contain letters, numbers and _',
10394 * The keystroke filter mask to be applied on alphanumeric input
10397 'alphanumMask' : /[a-z0-9_]/i
10407 * @class Roo.bootstrap.Input
10408 * @extends Roo.bootstrap.Component
10409 * Bootstrap Input class
10410 * @cfg {Boolean} disabled is it disabled
10411 * @cfg {String} (button|checkbox|email|file|hidden|image|number|password|radio|range|reset|search|submit|text) inputType
10412 * @cfg {String} name name of the input
10413 * @cfg {string} fieldLabel - the label associated
10414 * @cfg {string} placeholder - placeholder to put in text.
10415 * @cfg {string} before - input group add on before
10416 * @cfg {string} after - input group add on after
10417 * @cfg {string} size - (lg|sm) or leave empty..
10418 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
10419 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
10420 * @cfg {Number} md colspan out of 12 for computer-sized screens
10421 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
10422 * @cfg {string} value default value of the input
10423 * @cfg {Number} labelWidth set the width of label
10424 * @cfg {Number} labellg set the width of label (1-12)
10425 * @cfg {Number} labelmd set the width of label (1-12)
10426 * @cfg {Number} labelsm set the width of label (1-12)
10427 * @cfg {Number} labelxs set the width of label (1-12)
10428 * @cfg {String} labelAlign (top|left)
10429 * @cfg {Boolean} readOnly Specifies that the field should be read-only
10430 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
10431 * @cfg {String} indicatorpos (left|right) default left
10432 * @cfg {String} capture (user|camera) use for file input only. (default empty)
10433 * @cfg {String} accept (image|video|audio) use for file input only. (default empty)
10434 * @cfg {Boolean} preventMark Do not show tick or cross if error/success
10436 * @cfg {String} align (left|center|right) Default left
10437 * @cfg {Boolean} forceFeedback (true|false) Default false
10440 * Create a new Input
10441 * @param {Object} config The config object
10444 Roo.bootstrap.Input = function(config){
10446 Roo.bootstrap.Input.superclass.constructor.call(this, config);
10451 * Fires when this field receives input focus.
10452 * @param {Roo.form.Field} this
10457 * Fires when this field loses input focus.
10458 * @param {Roo.form.Field} this
10462 * @event specialkey
10463 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
10464 * {@link Roo.EventObject#getKey} to determine which key was pressed.
10465 * @param {Roo.form.Field} this
10466 * @param {Roo.EventObject} e The event object
10471 * Fires just before the field blurs if the field value has changed.
10472 * @param {Roo.form.Field} this
10473 * @param {Mixed} newValue The new value
10474 * @param {Mixed} oldValue The original value
10479 * Fires after the field has been marked as invalid.
10480 * @param {Roo.form.Field} this
10481 * @param {String} msg The validation message
10486 * Fires after the field has been validated with no errors.
10487 * @param {Roo.form.Field} this
10492 * Fires after the key up
10493 * @param {Roo.form.Field} this
10494 * @param {Roo.EventObject} e The event Object
10500 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
10502 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
10503 automatic validation (defaults to "keyup").
10505 validationEvent : "keyup",
10507 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
10509 validateOnBlur : true,
10511 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
10513 validationDelay : 250,
10515 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
10517 focusClass : "x-form-focus", // not needed???
10521 * @cfg {String} invalidClass DEPRICATED - code uses BS4 - is-valid / is-invalid
10523 invalidClass : "has-warning",
10526 * @cfg {String} validClass DEPRICATED - code uses BS4 - is-valid / is-invalid
10528 validClass : "has-success",
10531 * @cfg {Boolean} hasFeedback (true|false) default true
10533 hasFeedback : true,
10536 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
10538 invalidFeedbackClass : "glyphicon-warning-sign",
10541 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
10543 validFeedbackClass : "glyphicon-ok",
10546 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
10548 selectOnFocus : false,
10551 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
10555 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
10560 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
10562 disableKeyFilter : false,
10565 * @cfg {Boolean} disabled True to disable the field (defaults to false).
10569 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
10573 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
10575 blankText : "Please complete this mandatory field",
10578 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
10582 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
10584 maxLength : Number.MAX_VALUE,
10586 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
10588 minLengthText : "The minimum length for this field is {0}",
10590 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
10592 maxLengthText : "The maximum length for this field is {0}",
10596 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
10597 * If available, this function will be called only after the basic validators all return true, and will be passed the
10598 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
10602 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
10603 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
10604 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
10608 * @cfg {String} regexText -- Depricated - use Invalid Text
10613 * @cfg {String} invalidText The error text to display if {@link #validator} test fails during validation (defaults to "")
10619 autocomplete: false,
10623 inputType : 'text',
10626 placeholder: false,
10631 preventMark: false,
10632 isFormField : true,
10635 labelAlign : false,
10638 formatedValue : false,
10639 forceFeedback : false,
10641 indicatorpos : 'left',
10651 parentLabelAlign : function()
10654 while (parent.parent()) {
10655 parent = parent.parent();
10656 if (typeof(parent.labelAlign) !='undefined') {
10657 return parent.labelAlign;
10664 getAutoCreate : function()
10666 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
10672 if(this.inputType != 'hidden'){
10673 cfg.cls = 'form-group' //input-group
10679 type : this.inputType,
10680 value : this.value,
10681 cls : 'form-control',
10682 placeholder : this.placeholder || '',
10683 autocomplete : this.autocomplete || 'new-password'
10685 if (this.inputType == 'file') {
10686 input.style = 'overflow:hidden'; // why not in CSS?
10689 if(this.capture.length){
10690 input.capture = this.capture;
10693 if(this.accept.length){
10694 input.accept = this.accept + "/*";
10698 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
10701 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
10702 input.maxLength = this.maxLength;
10705 if (this.disabled) {
10706 input.disabled=true;
10709 if (this.readOnly) {
10710 input.readonly=true;
10714 input.name = this.name;
10718 input.cls += ' input-' + this.size;
10722 ['xs','sm','md','lg'].map(function(size){
10723 if (settings[size]) {
10724 cfg.cls += ' col-' + size + '-' + settings[size];
10728 var inputblock = input;
10732 cls: 'glyphicon form-control-feedback'
10735 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10738 cls : 'has-feedback',
10746 if (this.before || this.after) {
10749 cls : 'input-group',
10753 if (this.before && typeof(this.before) == 'string') {
10755 inputblock.cn.push({
10757 cls : 'roo-input-before input-group-addon input-group-prepend input-group-text',
10761 if (this.before && typeof(this.before) == 'object') {
10762 this.before = Roo.factory(this.before);
10764 inputblock.cn.push({
10766 cls : 'roo-input-before input-group-prepend input-group-' +
10767 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
10771 inputblock.cn.push(input);
10773 if (this.after && typeof(this.after) == 'string') {
10774 inputblock.cn.push({
10776 cls : 'roo-input-after input-group-append input-group-text input-group-addon',
10780 if (this.after && typeof(this.after) == 'object') {
10781 this.after = Roo.factory(this.after);
10783 inputblock.cn.push({
10785 cls : 'roo-input-after input-group-append input-group-' +
10786 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
10790 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10791 inputblock.cls += ' has-feedback';
10792 inputblock.cn.push(feedback);
10797 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
10798 tooltip : 'This field is required'
10800 if (this.allowBlank ) {
10801 indicator.style = this.allowBlank ? ' display:none' : '';
10803 if (align ==='left' && this.fieldLabel.length) {
10805 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
10812 cls : 'control-label col-form-label',
10813 html : this.fieldLabel
10824 var labelCfg = cfg.cn[1];
10825 var contentCfg = cfg.cn[2];
10827 if(this.indicatorpos == 'right'){
10832 cls : 'control-label col-form-label',
10836 html : this.fieldLabel
10850 labelCfg = cfg.cn[0];
10851 contentCfg = cfg.cn[1];
10855 if(this.labelWidth > 12){
10856 labelCfg.style = "width: " + this.labelWidth + 'px';
10859 if(this.labelWidth < 13 && this.labelmd == 0){
10860 this.labelmd = this.labelWidth;
10863 if(this.labellg > 0){
10864 labelCfg.cls += ' col-lg-' + this.labellg;
10865 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
10868 if(this.labelmd > 0){
10869 labelCfg.cls += ' col-md-' + this.labelmd;
10870 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
10873 if(this.labelsm > 0){
10874 labelCfg.cls += ' col-sm-' + this.labelsm;
10875 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
10878 if(this.labelxs > 0){
10879 labelCfg.cls += ' col-xs-' + this.labelxs;
10880 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
10884 } else if ( this.fieldLabel.length) {
10891 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
10892 tooltip : 'This field is required',
10893 style : this.allowBlank ? ' display:none' : ''
10897 //cls : 'input-group-addon',
10898 html : this.fieldLabel
10906 if(this.indicatorpos == 'right'){
10911 //cls : 'input-group-addon',
10912 html : this.fieldLabel
10917 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
10918 tooltip : 'This field is required',
10919 style : this.allowBlank ? ' display:none' : ''
10939 if (this.parentType === 'Navbar' && this.parent().bar) {
10940 cfg.cls += ' navbar-form';
10943 if (this.parentType === 'NavGroup' && !(Roo.bootstrap.version == 4 && this.parent().form)) {
10944 // on BS4 we do this only if not form
10945 cfg.cls += ' navbar-form';
10953 * return the real input element.
10955 inputEl: function ()
10957 return this.el.select('input.form-control',true).first();
10960 tooltipEl : function()
10962 return this.inputEl();
10965 indicatorEl : function()
10967 if (Roo.bootstrap.version == 4) {
10968 return false; // not enabled in v4 yet.
10971 var indicator = this.el.select('i.roo-required-indicator',true).first();
10981 setDisabled : function(v)
10983 var i = this.inputEl().dom;
10985 i.removeAttribute('disabled');
10989 i.setAttribute('disabled','true');
10991 initEvents : function()
10994 this.inputEl().on("keydown" , this.fireKey, this);
10995 this.inputEl().on("focus", this.onFocus, this);
10996 this.inputEl().on("blur", this.onBlur, this);
10998 this.inputEl().relayEvent('keyup', this);
11000 this.indicator = this.indicatorEl();
11002 if(this.indicator){
11003 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible'); // changed from invisible??? -
11006 // reference to original value for reset
11007 this.originalValue = this.getValue();
11008 //Roo.form.TextField.superclass.initEvents.call(this);
11009 if(this.validationEvent == 'keyup'){
11010 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
11011 this.inputEl().on('keyup', this.filterValidation, this);
11013 else if(this.validationEvent !== false){
11014 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
11017 if(this.selectOnFocus){
11018 this.on("focus", this.preFocus, this);
11021 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
11022 this.inputEl().on("keypress", this.filterKeys, this);
11024 this.inputEl().relayEvent('keypress', this);
11027 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
11028 this.el.on("click", this.autoSize, this);
11031 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
11032 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
11035 if (typeof(this.before) == 'object') {
11036 this.before.render(this.el.select('.roo-input-before',true).first());
11038 if (typeof(this.after) == 'object') {
11039 this.after.render(this.el.select('.roo-input-after',true).first());
11042 this.inputEl().on('change', this.onChange, this);
11045 filterValidation : function(e){
11046 if(!e.isNavKeyPress()){
11047 this.validationTask.delay(this.validationDelay);
11051 * Validates the field value
11052 * @return {Boolean} True if the value is valid, else false
11054 validate : function(){
11055 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
11056 if(this.disabled || this.validateValue(this.getRawValue())){
11061 this.markInvalid();
11067 * Validates a value according to the field's validation rules and marks the field as invalid
11068 * if the validation fails
11069 * @param {Mixed} value The value to validate
11070 * @return {Boolean} True if the value is valid, else false
11072 validateValue : function(value)
11074 if(this.getVisibilityEl().hasClass('hidden')){
11078 if(value.length < 1) { // if it's blank
11079 if(this.allowBlank){
11085 if(value.length < this.minLength){
11088 if(value.length > this.maxLength){
11092 var vt = Roo.form.VTypes;
11093 if(!vt[this.vtype](value, this)){
11097 if(typeof this.validator == "function"){
11098 var msg = this.validator(value);
11102 if (typeof(msg) == 'string') {
11103 this.invalidText = msg;
11107 if(this.regex && !this.regex.test(value)){
11115 fireKey : function(e){
11116 //Roo.log('field ' + e.getKey());
11117 if(e.isNavKeyPress()){
11118 this.fireEvent("specialkey", this, e);
11121 focus : function (selectText){
11123 this.inputEl().focus();
11124 if(selectText === true){
11125 this.inputEl().dom.select();
11131 onFocus : function(){
11132 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
11133 // this.el.addClass(this.focusClass);
11135 if(!this.hasFocus){
11136 this.hasFocus = true;
11137 this.startValue = this.getValue();
11138 this.fireEvent("focus", this);
11142 beforeBlur : Roo.emptyFn,
11146 onBlur : function(){
11148 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
11149 //this.el.removeClass(this.focusClass);
11151 this.hasFocus = false;
11152 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
11155 var v = this.getValue();
11156 if(String(v) !== String(this.startValue)){
11157 this.fireEvent('change', this, v, this.startValue);
11159 this.fireEvent("blur", this);
11162 onChange : function(e)
11164 var v = this.getValue();
11165 if(String(v) !== String(this.startValue)){
11166 this.fireEvent('change', this, v, this.startValue);
11172 * Resets the current field value to the originally loaded value and clears any validation messages
11174 reset : function(){
11175 this.setValue(this.originalValue);
11179 * Returns the name of the field
11180 * @return {Mixed} name The name field
11182 getName: function(){
11186 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
11187 * @return {Mixed} value The field value
11189 getValue : function(){
11191 var v = this.inputEl().getValue();
11196 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
11197 * @return {Mixed} value The field value
11199 getRawValue : function(){
11200 var v = this.inputEl().getValue();
11206 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
11207 * @param {Mixed} value The value to set
11209 setRawValue : function(v){
11210 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
11213 selectText : function(start, end){
11214 var v = this.getRawValue();
11216 start = start === undefined ? 0 : start;
11217 end = end === undefined ? v.length : end;
11218 var d = this.inputEl().dom;
11219 if(d.setSelectionRange){
11220 d.setSelectionRange(start, end);
11221 }else if(d.createTextRange){
11222 var range = d.createTextRange();
11223 range.moveStart("character", start);
11224 range.moveEnd("character", v.length-end);
11231 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
11232 * @param {Mixed} value The value to set
11234 setValue : function(v){
11237 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
11243 processValue : function(value){
11244 if(this.stripCharsRe){
11245 var newValue = value.replace(this.stripCharsRe, '');
11246 if(newValue !== value){
11247 this.setRawValue(newValue);
11254 preFocus : function(){
11256 if(this.selectOnFocus){
11257 this.inputEl().dom.select();
11260 filterKeys : function(e){
11261 var k = e.getKey();
11262 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
11265 var c = e.getCharCode(), cc = String.fromCharCode(c);
11266 if(Roo.isIE && (e.isSpecialKey() || !cc)){
11269 if(!this.maskRe.test(cc)){
11274 * Clear any invalid styles/messages for this field
11276 clearInvalid : function(){
11278 if(!this.el || this.preventMark){ // not rendered
11283 this.el.removeClass([this.invalidClass, 'is-invalid']);
11285 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
11287 var feedback = this.el.select('.form-control-feedback', true).first();
11290 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
11295 if(this.indicator){
11296 this.indicator.removeClass('visible');
11297 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
11300 this.fireEvent('valid', this);
11304 * Mark this field as valid
11306 markValid : function()
11308 if(!this.el || this.preventMark){ // not rendered...
11312 this.el.removeClass([this.invalidClass, this.validClass]);
11313 this.inputEl().removeClass(['is-valid', 'is-invalid']);
11315 var feedback = this.el.select('.form-control-feedback', true).first();
11318 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
11321 if(this.indicator){
11322 this.indicator.removeClass('visible');
11323 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
11331 if(this.allowBlank && !this.getRawValue().length){
11334 if (Roo.bootstrap.version == 3) {
11335 this.el.addClass(this.validClass);
11337 this.inputEl().addClass('is-valid');
11340 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
11342 var feedback = this.el.select('.form-control-feedback', true).first();
11345 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
11346 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
11351 this.fireEvent('valid', this);
11355 * Mark this field as invalid
11356 * @param {String} msg The validation message
11358 markInvalid : function(msg)
11360 if(!this.el || this.preventMark){ // not rendered
11364 this.el.removeClass([this.invalidClass, this.validClass]);
11365 this.inputEl().removeClass(['is-valid', 'is-invalid']);
11367 var feedback = this.el.select('.form-control-feedback', true).first();
11370 this.el.select('.form-control-feedback', true).first().removeClass(
11371 [this.invalidFeedbackClass, this.validFeedbackClass]);
11378 if(this.allowBlank && !this.getRawValue().length){
11382 if(this.indicator){
11383 this.indicator.removeClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
11384 this.indicator.addClass('visible');
11386 if (Roo.bootstrap.version == 3) {
11387 this.el.addClass(this.invalidClass);
11389 this.inputEl().addClass('is-invalid');
11394 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
11396 var feedback = this.el.select('.form-control-feedback', true).first();
11399 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
11401 if(this.getValue().length || this.forceFeedback){
11402 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
11409 this.fireEvent('invalid', this, msg);
11412 SafariOnKeyDown : function(event)
11414 // this is a workaround for a password hang bug on chrome/ webkit.
11415 if (this.inputEl().dom.type != 'password') {
11419 var isSelectAll = false;
11421 if(this.inputEl().dom.selectionEnd > 0){
11422 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
11424 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
11425 event.preventDefault();
11430 if(isSelectAll && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
11432 event.preventDefault();
11433 // this is very hacky as keydown always get's upper case.
11435 var cc = String.fromCharCode(event.getCharCode());
11436 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
11440 adjustWidth : function(tag, w){
11441 tag = tag.toLowerCase();
11442 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
11443 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
11444 if(tag == 'input'){
11447 if(tag == 'textarea'){
11450 }else if(Roo.isOpera){
11451 if(tag == 'input'){
11454 if(tag == 'textarea'){
11462 setFieldLabel : function(v)
11464 if(!this.rendered){
11468 if(this.indicatorEl()){
11469 var ar = this.el.select('label > span',true);
11471 if (ar.elements.length) {
11472 this.el.select('label > span',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
11473 this.fieldLabel = v;
11477 var br = this.el.select('label',true);
11479 if(br.elements.length) {
11480 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
11481 this.fieldLabel = v;
11485 Roo.log('Cannot Found any of label > span || label in input');
11489 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
11490 this.fieldLabel = v;
11505 * @class Roo.bootstrap.TextArea
11506 * @extends Roo.bootstrap.Input
11507 * Bootstrap TextArea class
11508 * @cfg {Number} cols Specifies the visible width of a text area
11509 * @cfg {Number} rows Specifies the visible number of lines in a text area
11510 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
11511 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
11512 * @cfg {string} html text
11515 * Create a new TextArea
11516 * @param {Object} config The config object
11519 Roo.bootstrap.TextArea = function(config){
11520 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
11524 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
11534 getAutoCreate : function(){
11536 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
11542 if(this.inputType != 'hidden'){
11543 cfg.cls = 'form-group' //input-group
11551 value : this.value || '',
11552 html: this.html || '',
11553 cls : 'form-control',
11554 placeholder : this.placeholder || ''
11558 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
11559 input.maxLength = this.maxLength;
11563 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
11567 input.cols = this.cols;
11570 if (this.readOnly) {
11571 input.readonly = true;
11575 input.name = this.name;
11579 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
11583 ['xs','sm','md','lg'].map(function(size){
11584 if (settings[size]) {
11585 cfg.cls += ' col-' + size + '-' + settings[size];
11589 var inputblock = input;
11591 if(this.hasFeedback && !this.allowBlank){
11595 cls: 'glyphicon form-control-feedback'
11599 cls : 'has-feedback',
11608 if (this.before || this.after) {
11611 cls : 'input-group',
11615 inputblock.cn.push({
11617 cls : 'input-group-addon',
11622 inputblock.cn.push(input);
11624 if(this.hasFeedback && !this.allowBlank){
11625 inputblock.cls += ' has-feedback';
11626 inputblock.cn.push(feedback);
11630 inputblock.cn.push({
11632 cls : 'input-group-addon',
11639 if (align ==='left' && this.fieldLabel.length) {
11644 cls : 'control-label',
11645 html : this.fieldLabel
11656 if(this.labelWidth > 12){
11657 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
11660 if(this.labelWidth < 13 && this.labelmd == 0){
11661 this.labelmd = this.labelWidth;
11664 if(this.labellg > 0){
11665 cfg.cn[0].cls += ' col-lg-' + this.labellg;
11666 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
11669 if(this.labelmd > 0){
11670 cfg.cn[0].cls += ' col-md-' + this.labelmd;
11671 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
11674 if(this.labelsm > 0){
11675 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
11676 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
11679 if(this.labelxs > 0){
11680 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
11681 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
11684 } else if ( this.fieldLabel.length) {
11689 //cls : 'input-group-addon',
11690 html : this.fieldLabel
11708 if (this.disabled) {
11709 input.disabled=true;
11716 * return the real textarea element.
11718 inputEl: function ()
11720 return this.el.select('textarea.form-control',true).first();
11724 * Clear any invalid styles/messages for this field
11726 clearInvalid : function()
11729 if(!this.el || this.preventMark){ // not rendered
11733 var label = this.el.select('label', true).first();
11734 var icon = this.el.select('i.fa-star', true).first();
11739 this.el.removeClass( this.validClass);
11740 this.inputEl().removeClass('is-invalid');
11742 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
11744 var feedback = this.el.select('.form-control-feedback', true).first();
11747 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
11752 this.fireEvent('valid', this);
11756 * Mark this field as valid
11758 markValid : function()
11760 if(!this.el || this.preventMark){ // not rendered
11764 this.el.removeClass([this.invalidClass, this.validClass]);
11765 this.inputEl().removeClass(['is-valid', 'is-invalid']);
11767 var feedback = this.el.select('.form-control-feedback', true).first();
11770 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
11773 if(this.disabled || this.allowBlank){
11777 var label = this.el.select('label', true).first();
11778 var icon = this.el.select('i.fa-star', true).first();
11783 if (Roo.bootstrap.version == 3) {
11784 this.el.addClass(this.validClass);
11786 this.inputEl().addClass('is-valid');
11790 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
11792 var feedback = this.el.select('.form-control-feedback', true).first();
11795 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
11796 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
11801 this.fireEvent('valid', this);
11805 * Mark this field as invalid
11806 * @param {String} msg The validation message
11808 markInvalid : function(msg)
11810 if(!this.el || this.preventMark){ // not rendered
11814 this.el.removeClass([this.invalidClass, this.validClass]);
11815 this.inputEl().removeClass(['is-valid', 'is-invalid']);
11817 var feedback = this.el.select('.form-control-feedback', true).first();
11820 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
11823 if(this.disabled || this.allowBlank){
11827 var label = this.el.select('label', true).first();
11828 var icon = this.el.select('i.fa-star', true).first();
11830 if(!this.getValue().length && label && !icon){
11831 this.el.createChild({
11833 cls : 'text-danger fa fa-lg fa-star',
11834 tooltip : 'This field is required',
11835 style : 'margin-right:5px;'
11839 if (Roo.bootstrap.version == 3) {
11840 this.el.addClass(this.invalidClass);
11842 this.inputEl().addClass('is-invalid');
11845 // fixme ... this may be depricated need to test..
11846 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
11848 var feedback = this.el.select('.form-control-feedback', true).first();
11851 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
11853 if(this.getValue().length || this.forceFeedback){
11854 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
11861 this.fireEvent('invalid', this, msg);
11869 * trigger field - base class for combo..
11874 * @class Roo.bootstrap.TriggerField
11875 * @extends Roo.bootstrap.Input
11876 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
11877 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
11878 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
11879 * for which you can provide a custom implementation. For example:
11881 var trigger = new Roo.bootstrap.TriggerField();
11882 trigger.onTriggerClick = myTriggerFn;
11883 trigger.applyTo('my-field');
11886 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
11887 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
11888 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
11889 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
11890 * @cfg {String} caret (search|calendar) BS3 only - carat fa name
11893 * Create a new TriggerField.
11894 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
11895 * to the base TextField)
11897 Roo.bootstrap.TriggerField = function(config){
11898 this.mimicing = false;
11899 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
11902 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
11904 * @cfg {String} triggerClass A CSS class to apply to the trigger
11907 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
11912 * @cfg {Boolean} removable (true|false) special filter default false
11916 /** @cfg {Boolean} grow @hide */
11917 /** @cfg {Number} growMin @hide */
11918 /** @cfg {Number} growMax @hide */
11924 autoSize: Roo.emptyFn,
11928 deferHeight : true,
11931 actionMode : 'wrap',
11936 getAutoCreate : function(){
11938 var align = this.labelAlign || this.parentLabelAlign();
11943 cls: 'form-group' //input-group
11950 type : this.inputType,
11951 cls : 'form-control',
11952 autocomplete: 'new-password',
11953 placeholder : this.placeholder || ''
11957 input.name = this.name;
11960 input.cls += ' input-' + this.size;
11963 if (this.disabled) {
11964 input.disabled=true;
11967 var inputblock = input;
11969 if(this.hasFeedback && !this.allowBlank){
11973 cls: 'glyphicon form-control-feedback'
11976 if(this.removable && !this.editable ){
11978 cls : 'has-feedback',
11984 cls : 'roo-combo-removable-btn close'
11991 cls : 'has-feedback',
12000 if(this.removable && !this.editable ){
12002 cls : 'roo-removable',
12008 cls : 'roo-combo-removable-btn close'
12015 if (this.before || this.after) {
12018 cls : 'input-group',
12022 inputblock.cn.push({
12024 cls : 'input-group-addon input-group-prepend input-group-text',
12029 inputblock.cn.push(input);
12031 if(this.hasFeedback && !this.allowBlank){
12032 inputblock.cls += ' has-feedback';
12033 inputblock.cn.push(feedback);
12037 inputblock.cn.push({
12039 cls : 'input-group-addon input-group-append input-group-text',
12048 var ibwrap = inputblock;
12053 cls: 'roo-select2-choices',
12057 cls: 'roo-select2-search-field',
12069 cls: 'roo-select2-container input-group',
12074 cls: 'form-hidden-field'
12080 if(!this.multiple && this.showToggleBtn){
12086 if (this.caret != false) {
12089 cls: 'fa fa-' + this.caret
12096 cls : 'input-group-addon input-group-append input-group-text btn dropdown-toggle',
12098 Roo.bootstrap.version == 3 ? caret : '',
12101 cls: 'combobox-clear',
12115 combobox.cls += ' roo-select2-container-multi';
12119 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
12120 tooltip : 'This field is required'
12122 if (Roo.bootstrap.version == 4) {
12125 style : 'display:none'
12130 if (align ==='left' && this.fieldLabel.length) {
12132 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
12139 cls : 'control-label',
12140 html : this.fieldLabel
12152 var labelCfg = cfg.cn[1];
12153 var contentCfg = cfg.cn[2];
12155 if(this.indicatorpos == 'right'){
12160 cls : 'control-label',
12164 html : this.fieldLabel
12178 labelCfg = cfg.cn[0];
12179 contentCfg = cfg.cn[1];
12182 if(this.labelWidth > 12){
12183 labelCfg.style = "width: " + this.labelWidth + 'px';
12186 if(this.labelWidth < 13 && this.labelmd == 0){
12187 this.labelmd = this.labelWidth;
12190 if(this.labellg > 0){
12191 labelCfg.cls += ' col-lg-' + this.labellg;
12192 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
12195 if(this.labelmd > 0){
12196 labelCfg.cls += ' col-md-' + this.labelmd;
12197 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
12200 if(this.labelsm > 0){
12201 labelCfg.cls += ' col-sm-' + this.labelsm;
12202 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
12205 if(this.labelxs > 0){
12206 labelCfg.cls += ' col-xs-' + this.labelxs;
12207 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
12210 } else if ( this.fieldLabel.length) {
12211 // Roo.log(" label");
12216 //cls : 'input-group-addon',
12217 html : this.fieldLabel
12225 if(this.indicatorpos == 'right'){
12233 html : this.fieldLabel
12247 // Roo.log(" no label && no align");
12254 ['xs','sm','md','lg'].map(function(size){
12255 if (settings[size]) {
12256 cfg.cls += ' col-' + size + '-' + settings[size];
12267 onResize : function(w, h){
12268 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
12269 // if(typeof w == 'number'){
12270 // var x = w - this.trigger.getWidth();
12271 // this.inputEl().setWidth(this.adjustWidth('input', x));
12272 // this.trigger.setStyle('left', x+'px');
12277 adjustSize : Roo.BoxComponent.prototype.adjustSize,
12280 getResizeEl : function(){
12281 return this.inputEl();
12285 getPositionEl : function(){
12286 return this.inputEl();
12290 alignErrorIcon : function(){
12291 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
12295 initEvents : function(){
12299 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
12300 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
12301 if(!this.multiple && this.showToggleBtn){
12302 this.trigger = this.el.select('span.dropdown-toggle',true).first();
12303 if(this.hideTrigger){
12304 this.trigger.setDisplayed(false);
12306 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
12310 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
12313 if(this.removable && !this.editable && !this.tickable){
12314 var close = this.closeTriggerEl();
12317 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
12318 close.on('click', this.removeBtnClick, this, close);
12322 //this.trigger.addClassOnOver('x-form-trigger-over');
12323 //this.trigger.addClassOnClick('x-form-trigger-click');
12326 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
12330 closeTriggerEl : function()
12332 var close = this.el.select('.roo-combo-removable-btn', true).first();
12333 return close ? close : false;
12336 removeBtnClick : function(e, h, el)
12338 e.preventDefault();
12340 if(this.fireEvent("remove", this) !== false){
12342 this.fireEvent("afterremove", this)
12346 createList : function()
12348 this.list = Roo.get(document.body).createChild({
12349 tag: Roo.bootstrap.version == 4 ? 'div' : 'ul',
12350 cls: 'typeahead typeahead-long dropdown-menu shadow',
12351 style: 'display:none'
12354 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
12359 initTrigger : function(){
12364 onDestroy : function(){
12366 this.trigger.removeAllListeners();
12367 // this.trigger.remove();
12370 // this.wrap.remove();
12372 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
12376 onFocus : function(){
12377 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
12379 if(!this.mimicing){
12380 this.wrap.addClass('x-trigger-wrap-focus');
12381 this.mimicing = true;
12382 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
12383 if(this.monitorTab){
12384 this.el.on("keydown", this.checkTab, this);
12391 checkTab : function(e){
12392 if(e.getKey() == e.TAB){
12393 this.triggerBlur();
12398 onBlur : function(){
12403 mimicBlur : function(e, t){
12405 if(!this.wrap.contains(t) && this.validateBlur()){
12406 this.triggerBlur();
12412 triggerBlur : function(){
12413 this.mimicing = false;
12414 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
12415 if(this.monitorTab){
12416 this.el.un("keydown", this.checkTab, this);
12418 //this.wrap.removeClass('x-trigger-wrap-focus');
12419 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
12423 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
12424 validateBlur : function(e, t){
12429 onDisable : function(){
12430 this.inputEl().dom.disabled = true;
12431 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
12433 // this.wrap.addClass('x-item-disabled');
12438 onEnable : function(){
12439 this.inputEl().dom.disabled = false;
12440 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
12442 // this.el.removeClass('x-item-disabled');
12447 onShow : function(){
12448 var ae = this.getActionEl();
12451 ae.dom.style.display = '';
12452 ae.dom.style.visibility = 'visible';
12458 onHide : function(){
12459 var ae = this.getActionEl();
12460 ae.dom.style.display = 'none';
12464 * The function that should handle the trigger's click event. This method does nothing by default until overridden
12465 * by an implementing function.
12467 * @param {EventObject} e
12469 onTriggerClick : Roo.emptyFn
12477 * @class Roo.bootstrap.CardUploader
12478 * @extends Roo.bootstrap.Button
12479 * Bootstrap Card Uploader class - it's a button which when you add files to it, adds cards below with preview and the name...
12480 * @cfg {Number} errorTimeout default 3000
12481 * @cfg {Array} images an array of ?? Img objects ??? when loading existing files..
12482 * @cfg {Array} html The button text.
12486 * Create a new CardUploader
12487 * @param {Object} config The config object
12490 Roo.bootstrap.CardUploader = function(config){
12494 Roo.bootstrap.CardUploader.superclass.constructor.call(this, config);
12497 this.fileCollection = new Roo.util.MixedCollection(false,function(r) {
12504 Roo.extend(Roo.bootstrap.CardUploader, Roo.bootstrap.Input, {
12507 errorTimeout : 3000,
12511 fileCollection : false,
12514 getAutoCreate : function()
12518 cls :'form-group' ,
12523 //cls : 'input-group-addon',
12524 html : this.fieldLabel
12532 value : this.value,
12533 cls : 'd-none form-control'
12538 multiple : 'multiple',
12540 cls : 'd-none roo-card-upload-selector'
12544 cls : 'roo-card-uploader-button-container w-100 mb-2'
12547 cls : 'card-columns roo-card-uploader-container'
12557 getChildContainer : function() /// what children are added to.
12559 return this.containerEl;
12562 getButtonContainer : function() /// what children are added to.
12564 return this.el.select(".roo-card-uploader-button-container").first();
12567 initEvents : function()
12570 Roo.bootstrap.Input.prototype.initEvents.call(this);
12574 xns: Roo.bootstrap,
12577 container_method : 'getButtonContainer' ,
12578 html : this.html, // fix changable?
12581 'click' : function(btn, e) {
12590 this.urlAPI = (window.createObjectURL && window) ||
12591 (window.URL && URL.revokeObjectURL && URL) ||
12592 (window.webkitURL && webkitURL);
12597 this.selectorEl = this.el.select('.roo-card-upload-selector', true).first();
12599 this.selectorEl.on('change', this.onFileSelected, this);
12602 this.images.forEach(function(img) {
12605 this.images = false;
12607 this.containerEl = this.el.select('.roo-card-uploader-container', true).first();
12613 onClick : function(e)
12615 e.preventDefault();
12617 this.selectorEl.dom.click();
12621 onFileSelected : function(e)
12623 e.preventDefault();
12625 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
12629 Roo.each(this.selectorEl.dom.files, function(file){
12630 this.addFile(file);
12639 addFile : function(file)
12642 if(typeof(file) === 'string'){
12643 throw "Add file by name?"; // should not happen
12647 if(!file || !this.urlAPI){
12657 var url = _this.urlAPI.createObjectURL( file);
12660 id : Roo.bootstrap.CardUploader.ID--,
12661 is_uploaded : false,
12664 mimetype : file.type,
12671 addCard : function (data)
12673 // hidden input element?
12674 // if the file is not an image...
12675 //then we need to use something other that and header_image
12680 xns : Roo.bootstrap,
12681 xtype : 'CardFooter',
12684 xns : Roo.bootstrap,
12690 xns : Roo.bootstrap,
12692 html : String.format("<small>{0}</small>", data.title),
12693 cls : 'col-11 text-left',
12698 click : function() {
12699 this.downloadCard(data.id)
12705 xns : Roo.bootstrap,
12713 click : function() {
12714 t.removeCard(data.id)
12726 var cn = this.addxtype(
12729 xns : Roo.bootstrap,
12732 header : !data.mimetype.match(/image/) && !data.preview ? "Document": false,
12733 header_image : data.mimetype.match(/image/) ? data.src : data.preview,
12734 header_image_fit_square: true, // fixme - we probably need to use the 'Img' element to do stuff like this.
12739 initEvents : function() {
12740 Roo.bootstrap.Card.prototype.initEvents.call(this);
12741 this.imgEl = this.el.select('.card-img-top').first();
12743 this.imgEl.on('click', function() { t.previewCard( data.id); }, this);
12744 this.imgEl.set({ 'pointer' : 'cursor' });
12753 // dont' really need ot update items.
12754 // this.items.push(cn);
12755 this.fileCollection.add(cn);
12756 this.updateInput();
12759 removeCard : function(id)
12762 var card = this.fileCollection.get(id);
12763 card.data.is_deleted = 1;
12764 card.data.src = ''; /// delete the source - so it reduces size of not uploaded images etc.
12765 this.fileCollection.remove(card);
12766 //this.items = this.items.filter(function(e) { return e != card });
12767 // dont' really need ot update items.
12768 card.el.dom.parentNode.removeChild(card.el.dom);
12773 this.fileCollection.each(function(card) {
12774 card.el.dom.parentNode.removeChild(card.el.dom);
12776 this.fileCollection.clear();
12777 this.updateInput();
12780 updateInput : function()
12784 var dom = this.inputEl().dom;
12785 var fc = this.fileCollection;
12786 var next = function() {
12787 if (i >= fc.length) {
12788 dom.value = JSON.stringify(data);
12791 var reader = new FileReader();
12792 reader.onloadend = function(evt) {
12794 var ee = Roo.apply({}, fc[i]);
12795 ee.src = evt.target.result;
12799 reader.readAsDataURL(fc[i].src);
12811 Roo.bootstrap.CardUploader.ID = -1;/*
12813 * Ext JS Library 1.1.1
12814 * Copyright(c) 2006-2007, Ext JS, LLC.
12816 * Originally Released Under LGPL - original licence link has changed is not relivant.
12819 * <script type="text/javascript">
12824 * @class Roo.data.SortTypes
12826 * Defines the default sorting (casting?) comparison functions used when sorting data.
12828 Roo.data.SortTypes = {
12830 * Default sort that does nothing
12831 * @param {Mixed} s The value being converted
12832 * @return {Mixed} The comparison value
12834 none : function(s){
12839 * The regular expression used to strip tags
12843 stripTagsRE : /<\/?[^>]+>/gi,
12846 * Strips all HTML tags to sort on text only
12847 * @param {Mixed} s The value being converted
12848 * @return {String} The comparison value
12850 asText : function(s){
12851 return String(s).replace(this.stripTagsRE, "");
12855 * Strips all HTML tags to sort on text only - Case insensitive
12856 * @param {Mixed} s The value being converted
12857 * @return {String} The comparison value
12859 asUCText : function(s){
12860 return String(s).toUpperCase().replace(this.stripTagsRE, "");
12864 * Case insensitive string
12865 * @param {Mixed} s The value being converted
12866 * @return {String} The comparison value
12868 asUCString : function(s) {
12869 return String(s).toUpperCase();
12874 * @param {Mixed} s The value being converted
12875 * @return {Number} The comparison value
12877 asDate : function(s) {
12881 if(s instanceof Date){
12882 return s.getTime();
12884 return Date.parse(String(s));
12889 * @param {Mixed} s The value being converted
12890 * @return {Float} The comparison value
12892 asFloat : function(s) {
12893 var val = parseFloat(String(s).replace(/,/g, ""));
12902 * @param {Mixed} s The value being converted
12903 * @return {Number} The comparison value
12905 asInt : function(s) {
12906 var val = parseInt(String(s).replace(/,/g, ""));
12914 * Ext JS Library 1.1.1
12915 * Copyright(c) 2006-2007, Ext JS, LLC.
12917 * Originally Released Under LGPL - original licence link has changed is not relivant.
12920 * <script type="text/javascript">
12924 * @class Roo.data.Record
12925 * Instances of this class encapsulate both record <em>definition</em> information, and record
12926 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
12927 * to access Records cached in an {@link Roo.data.Store} object.<br>
12929 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
12930 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
12933 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
12935 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
12936 * {@link #create}. The parameters are the same.
12937 * @param {Array} data An associative Array of data values keyed by the field name.
12938 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
12939 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
12940 * not specified an integer id is generated.
12942 Roo.data.Record = function(data, id){
12943 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
12948 * Generate a constructor for a specific record layout.
12949 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
12950 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
12951 * Each field definition object may contain the following properties: <ul>
12952 * <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,
12953 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
12954 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
12955 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
12956 * is being used, then this is a string containing the javascript expression to reference the data relative to
12957 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
12958 * to the data item relative to the record element. If the mapping expression is the same as the field name,
12959 * this may be omitted.</p></li>
12960 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
12961 * <ul><li>auto (Default, implies no conversion)</li>
12966 * <li>date</li></ul></p></li>
12967 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
12968 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
12969 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
12970 * by the Reader into an object that will be stored in the Record. It is passed the
12971 * following parameters:<ul>
12972 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
12974 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
12976 * <br>usage:<br><pre><code>
12977 var TopicRecord = Roo.data.Record.create(
12978 {name: 'title', mapping: 'topic_title'},
12979 {name: 'author', mapping: 'username'},
12980 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
12981 {name: 'lastPost', mapping: 'post_time', type: 'date'},
12982 {name: 'lastPoster', mapping: 'user2'},
12983 {name: 'excerpt', mapping: 'post_text'}
12986 var myNewRecord = new TopicRecord({
12987 title: 'Do my job please',
12990 lastPost: new Date(),
12991 lastPoster: 'Animal',
12992 excerpt: 'No way dude!'
12994 myStore.add(myNewRecord);
12999 Roo.data.Record.create = function(o){
13000 var f = function(){
13001 f.superclass.constructor.apply(this, arguments);
13003 Roo.extend(f, Roo.data.Record);
13004 var p = f.prototype;
13005 p.fields = new Roo.util.MixedCollection(false, function(field){
13008 for(var i = 0, len = o.length; i < len; i++){
13009 p.fields.add(new Roo.data.Field(o[i]));
13011 f.getField = function(name){
13012 return p.fields.get(name);
13017 Roo.data.Record.AUTO_ID = 1000;
13018 Roo.data.Record.EDIT = 'edit';
13019 Roo.data.Record.REJECT = 'reject';
13020 Roo.data.Record.COMMIT = 'commit';
13022 Roo.data.Record.prototype = {
13024 * Readonly flag - true if this record has been modified.
13033 join : function(store){
13034 this.store = store;
13038 * Set the named field to the specified value.
13039 * @param {String} name The name of the field to set.
13040 * @param {Object} value The value to set the field to.
13042 set : function(name, value){
13043 if(this.data[name] == value){
13047 if(!this.modified){
13048 this.modified = {};
13050 if(typeof this.modified[name] == 'undefined'){
13051 this.modified[name] = this.data[name];
13053 this.data[name] = value;
13054 if(!this.editing && this.store){
13055 this.store.afterEdit(this);
13060 * Get the value of the named field.
13061 * @param {String} name The name of the field to get the value of.
13062 * @return {Object} The value of the field.
13064 get : function(name){
13065 return this.data[name];
13069 beginEdit : function(){
13070 this.editing = true;
13071 this.modified = {};
13075 cancelEdit : function(){
13076 this.editing = false;
13077 delete this.modified;
13081 endEdit : function(){
13082 this.editing = false;
13083 if(this.dirty && this.store){
13084 this.store.afterEdit(this);
13089 * Usually called by the {@link Roo.data.Store} which owns the Record.
13090 * Rejects all changes made to the Record since either creation, or the last commit operation.
13091 * Modified fields are reverted to their original values.
13093 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
13094 * of reject operations.
13096 reject : function(){
13097 var m = this.modified;
13099 if(typeof m[n] != "function"){
13100 this.data[n] = m[n];
13103 this.dirty = false;
13104 delete this.modified;
13105 this.editing = false;
13107 this.store.afterReject(this);
13112 * Usually called by the {@link Roo.data.Store} which owns the Record.
13113 * Commits all changes made to the Record since either creation, or the last commit operation.
13115 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
13116 * of commit operations.
13118 commit : function(){
13119 this.dirty = false;
13120 delete this.modified;
13121 this.editing = false;
13123 this.store.afterCommit(this);
13128 hasError : function(){
13129 return this.error != null;
13133 clearError : function(){
13138 * Creates a copy of this record.
13139 * @param {String} id (optional) A new record id if you don't want to use this record's id
13142 copy : function(newId) {
13143 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
13147 * Ext JS Library 1.1.1
13148 * Copyright(c) 2006-2007, Ext JS, LLC.
13150 * Originally Released Under LGPL - original licence link has changed is not relivant.
13153 * <script type="text/javascript">
13159 * @class Roo.data.Store
13160 * @extends Roo.util.Observable
13161 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
13162 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
13164 * 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
13165 * has no knowledge of the format of the data returned by the Proxy.<br>
13167 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
13168 * instances from the data object. These records are cached and made available through accessor functions.
13170 * Creates a new Store.
13171 * @param {Object} config A config object containing the objects needed for the Store to access data,
13172 * and read the data into Records.
13174 Roo.data.Store = function(config){
13175 this.data = new Roo.util.MixedCollection(false);
13176 this.data.getKey = function(o){
13179 this.baseParams = {};
13181 this.paramNames = {
13186 "multisort" : "_multisort"
13189 if(config && config.data){
13190 this.inlineData = config.data;
13191 delete config.data;
13194 Roo.apply(this, config);
13196 if(this.reader){ // reader passed
13197 this.reader = Roo.factory(this.reader, Roo.data);
13198 this.reader.xmodule = this.xmodule || false;
13199 if(!this.recordType){
13200 this.recordType = this.reader.recordType;
13202 if(this.reader.onMetaChange){
13203 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
13207 if(this.recordType){
13208 this.fields = this.recordType.prototype.fields;
13210 this.modified = [];
13214 * @event datachanged
13215 * Fires when the data cache has changed, and a widget which is using this Store
13216 * as a Record cache should refresh its view.
13217 * @param {Store} this
13219 datachanged : true,
13221 * @event metachange
13222 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
13223 * @param {Store} this
13224 * @param {Object} meta The JSON metadata
13229 * Fires when Records have been added to the Store
13230 * @param {Store} this
13231 * @param {Roo.data.Record[]} records The array of Records added
13232 * @param {Number} index The index at which the record(s) were added
13237 * Fires when a Record has been removed from the Store
13238 * @param {Store} this
13239 * @param {Roo.data.Record} record The Record that was removed
13240 * @param {Number} index The index at which the record was removed
13245 * Fires when a Record has been updated
13246 * @param {Store} this
13247 * @param {Roo.data.Record} record The Record that was updated
13248 * @param {String} operation The update operation being performed. Value may be one of:
13250 Roo.data.Record.EDIT
13251 Roo.data.Record.REJECT
13252 Roo.data.Record.COMMIT
13258 * Fires when the data cache has been cleared.
13259 * @param {Store} this
13263 * @event beforeload
13264 * Fires before a request is made for a new data object. If the beforeload handler returns false
13265 * the load action will be canceled.
13266 * @param {Store} this
13267 * @param {Object} options The loading options that were specified (see {@link #load} for details)
13271 * @event beforeloadadd
13272 * Fires after a new set of Records has been loaded.
13273 * @param {Store} this
13274 * @param {Roo.data.Record[]} records The Records that were loaded
13275 * @param {Object} options The loading options that were specified (see {@link #load} for details)
13277 beforeloadadd : true,
13280 * Fires after a new set of Records has been loaded, before they are added to the store.
13281 * @param {Store} this
13282 * @param {Roo.data.Record[]} records The Records that were loaded
13283 * @param {Object} options The loading options that were specified (see {@link #load} for details)
13284 * @params {Object} return from reader
13288 * @event loadexception
13289 * Fires if an exception occurs in the Proxy during loading.
13290 * Called with the signature of the Proxy's "loadexception" event.
13291 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
13294 * @param {Object} return from JsonData.reader() - success, totalRecords, records
13295 * @param {Object} load options
13296 * @param {Object} jsonData from your request (normally this contains the Exception)
13298 loadexception : true
13302 this.proxy = Roo.factory(this.proxy, Roo.data);
13303 this.proxy.xmodule = this.xmodule || false;
13304 this.relayEvents(this.proxy, ["loadexception"]);
13306 this.sortToggle = {};
13307 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
13309 Roo.data.Store.superclass.constructor.call(this);
13311 if(this.inlineData){
13312 this.loadData(this.inlineData);
13313 delete this.inlineData;
13317 Roo.extend(Roo.data.Store, Roo.util.Observable, {
13319 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
13320 * without a remote query - used by combo/forms at present.
13324 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
13327 * @cfg {Array} data Inline data to be loaded when the store is initialized.
13330 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
13331 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
13334 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
13335 * on any HTTP request
13338 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
13341 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
13345 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
13346 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
13348 remoteSort : false,
13351 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
13352 * loaded or when a record is removed. (defaults to false).
13354 pruneModifiedRecords : false,
13357 lastOptions : null,
13360 * Add Records to the Store and fires the add event.
13361 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
13363 add : function(records){
13364 records = [].concat(records);
13365 for(var i = 0, len = records.length; i < len; i++){
13366 records[i].join(this);
13368 var index = this.data.length;
13369 this.data.addAll(records);
13370 this.fireEvent("add", this, records, index);
13374 * Remove a Record from the Store and fires the remove event.
13375 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
13377 remove : function(record){
13378 var index = this.data.indexOf(record);
13379 this.data.removeAt(index);
13381 if(this.pruneModifiedRecords){
13382 this.modified.remove(record);
13384 this.fireEvent("remove", this, record, index);
13388 * Remove all Records from the Store and fires the clear event.
13390 removeAll : function(){
13392 if(this.pruneModifiedRecords){
13393 this.modified = [];
13395 this.fireEvent("clear", this);
13399 * Inserts Records to the Store at the given index and fires the add event.
13400 * @param {Number} index The start index at which to insert the passed Records.
13401 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
13403 insert : function(index, records){
13404 records = [].concat(records);
13405 for(var i = 0, len = records.length; i < len; i++){
13406 this.data.insert(index, records[i]);
13407 records[i].join(this);
13409 this.fireEvent("add", this, records, index);
13413 * Get the index within the cache of the passed Record.
13414 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
13415 * @return {Number} The index of the passed Record. Returns -1 if not found.
13417 indexOf : function(record){
13418 return this.data.indexOf(record);
13422 * Get the index within the cache of the Record with the passed id.
13423 * @param {String} id The id of the Record to find.
13424 * @return {Number} The index of the Record. Returns -1 if not found.
13426 indexOfId : function(id){
13427 return this.data.indexOfKey(id);
13431 * Get the Record with the specified id.
13432 * @param {String} id The id of the Record to find.
13433 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
13435 getById : function(id){
13436 return this.data.key(id);
13440 * Get the Record at the specified index.
13441 * @param {Number} index The index of the Record to find.
13442 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
13444 getAt : function(index){
13445 return this.data.itemAt(index);
13449 * Returns a range of Records between specified indices.
13450 * @param {Number} startIndex (optional) The starting index (defaults to 0)
13451 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
13452 * @return {Roo.data.Record[]} An array of Records
13454 getRange : function(start, end){
13455 return this.data.getRange(start, end);
13459 storeOptions : function(o){
13460 o = Roo.apply({}, o);
13463 this.lastOptions = o;
13467 * Loads the Record cache from the configured Proxy using the configured Reader.
13469 * If using remote paging, then the first load call must specify the <em>start</em>
13470 * and <em>limit</em> properties in the options.params property to establish the initial
13471 * position within the dataset, and the number of Records to cache on each read from the Proxy.
13473 * <strong>It is important to note that for remote data sources, loading is asynchronous,
13474 * and this call will return before the new data has been loaded. Perform any post-processing
13475 * in a callback function, or in a "load" event handler.</strong>
13477 * @param {Object} options An object containing properties which control loading options:<ul>
13478 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
13479 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
13480 * passed the following arguments:<ul>
13481 * <li>r : Roo.data.Record[]</li>
13482 * <li>options: Options object from the load call</li>
13483 * <li>success: Boolean success indicator</li></ul></li>
13484 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
13485 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
13488 load : function(options){
13489 options = options || {};
13490 if(this.fireEvent("beforeload", this, options) !== false){
13491 this.storeOptions(options);
13492 var p = Roo.apply(options.params || {}, this.baseParams);
13493 // if meta was not loaded from remote source.. try requesting it.
13494 if (!this.reader.metaFromRemote) {
13495 p._requestMeta = 1;
13497 if(this.sortInfo && this.remoteSort){
13498 var pn = this.paramNames;
13499 p[pn["sort"]] = this.sortInfo.field;
13500 p[pn["dir"]] = this.sortInfo.direction;
13502 if (this.multiSort) {
13503 var pn = this.paramNames;
13504 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
13507 this.proxy.load(p, this.reader, this.loadRecords, this, options);
13512 * Reloads the Record cache from the configured Proxy using the configured Reader and
13513 * the options from the last load operation performed.
13514 * @param {Object} options (optional) An object containing properties which may override the options
13515 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
13516 * the most recently used options are reused).
13518 reload : function(options){
13519 this.load(Roo.applyIf(options||{}, this.lastOptions));
13523 // Called as a callback by the Reader during a load operation.
13524 loadRecords : function(o, options, success){
13525 if(!o || success === false){
13526 if(success !== false){
13527 this.fireEvent("load", this, [], options, o);
13529 if(options.callback){
13530 options.callback.call(options.scope || this, [], options, false);
13534 // if data returned failure - throw an exception.
13535 if (o.success === false) {
13536 // show a message if no listener is registered.
13537 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
13538 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
13540 // loadmask wil be hooked into this..
13541 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
13544 var r = o.records, t = o.totalRecords || r.length;
13546 this.fireEvent("beforeloadadd", this, r, options, o);
13548 if(!options || options.add !== true){
13549 if(this.pruneModifiedRecords){
13550 this.modified = [];
13552 for(var i = 0, len = r.length; i < len; i++){
13556 this.data = this.snapshot;
13557 delete this.snapshot;
13560 this.data.addAll(r);
13561 this.totalLength = t;
13563 this.fireEvent("datachanged", this);
13565 this.totalLength = Math.max(t, this.data.length+r.length);
13569 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
13571 var e = new Roo.data.Record({});
13573 e.set(this.parent.displayField, this.parent.emptyTitle);
13574 e.set(this.parent.valueField, '');
13579 this.fireEvent("load", this, r, options, o);
13580 if(options.callback){
13581 options.callback.call(options.scope || this, r, options, true);
13587 * Loads data from a passed data block. A Reader which understands the format of the data
13588 * must have been configured in the constructor.
13589 * @param {Object} data The data block from which to read the Records. The format of the data expected
13590 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
13591 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
13593 loadData : function(o, append){
13594 var r = this.reader.readRecords(o);
13595 this.loadRecords(r, {add: append}, true);
13599 * using 'cn' the nested child reader read the child array into it's child stores.
13600 * @param {Object} rec The record with a 'children array
13602 loadDataFromChildren : function(rec)
13604 this.loadData(this.reader.toLoadData(rec));
13609 * Gets the number of cached records.
13611 * <em>If using paging, this may not be the total size of the dataset. If the data object
13612 * used by the Reader contains the dataset size, then the getTotalCount() function returns
13613 * the data set size</em>
13615 getCount : function(){
13616 return this.data.length || 0;
13620 * Gets the total number of records in the dataset as returned by the server.
13622 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
13623 * the dataset size</em>
13625 getTotalCount : function(){
13626 return this.totalLength || 0;
13630 * Returns the sort state of the Store as an object with two properties:
13632 field {String} The name of the field by which the Records are sorted
13633 direction {String} The sort order, "ASC" or "DESC"
13636 getSortState : function(){
13637 return this.sortInfo;
13641 applySort : function(){
13642 if(this.sortInfo && !this.remoteSort){
13643 var s = this.sortInfo, f = s.field;
13644 var st = this.fields.get(f).sortType;
13645 var fn = function(r1, r2){
13646 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
13647 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
13649 this.data.sort(s.direction, fn);
13650 if(this.snapshot && this.snapshot != this.data){
13651 this.snapshot.sort(s.direction, fn);
13657 * Sets the default sort column and order to be used by the next load operation.
13658 * @param {String} fieldName The name of the field to sort by.
13659 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
13661 setDefaultSort : function(field, dir){
13662 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
13666 * Sort the Records.
13667 * If remote sorting is used, the sort is performed on the server, and the cache is
13668 * reloaded. If local sorting is used, the cache is sorted internally.
13669 * @param {String} fieldName The name of the field to sort by.
13670 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
13672 sort : function(fieldName, dir){
13673 var f = this.fields.get(fieldName);
13675 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
13677 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
13678 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
13683 this.sortToggle[f.name] = dir;
13684 this.sortInfo = {field: f.name, direction: dir};
13685 if(!this.remoteSort){
13687 this.fireEvent("datachanged", this);
13689 this.load(this.lastOptions);
13694 * Calls the specified function for each of the Records in the cache.
13695 * @param {Function} fn The function to call. The Record is passed as the first parameter.
13696 * Returning <em>false</em> aborts and exits the iteration.
13697 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
13699 each : function(fn, scope){
13700 this.data.each(fn, scope);
13704 * Gets all records modified since the last commit. Modified records are persisted across load operations
13705 * (e.g., during paging).
13706 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
13708 getModifiedRecords : function(){
13709 return this.modified;
13713 createFilterFn : function(property, value, anyMatch){
13714 if(!value.exec){ // not a regex
13715 value = String(value);
13716 if(value.length == 0){
13719 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
13721 return function(r){
13722 return value.test(r.data[property]);
13727 * Sums the value of <i>property</i> for each record between start and end and returns the result.
13728 * @param {String} property A field on your records
13729 * @param {Number} start The record index to start at (defaults to 0)
13730 * @param {Number} end The last record index to include (defaults to length - 1)
13731 * @return {Number} The sum
13733 sum : function(property, start, end){
13734 var rs = this.data.items, v = 0;
13735 start = start || 0;
13736 end = (end || end === 0) ? end : rs.length-1;
13738 for(var i = start; i <= end; i++){
13739 v += (rs[i].data[property] || 0);
13745 * Filter the records by a specified property.
13746 * @param {String} field A field on your records
13747 * @param {String/RegExp} value Either a string that the field
13748 * should start with or a RegExp to test against the field
13749 * @param {Boolean} anyMatch True to match any part not just the beginning
13751 filter : function(property, value, anyMatch){
13752 var fn = this.createFilterFn(property, value, anyMatch);
13753 return fn ? this.filterBy(fn) : this.clearFilter();
13757 * Filter by a function. The specified function will be called with each
13758 * record in this data source. If the function returns true the record is included,
13759 * otherwise it is filtered.
13760 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
13761 * @param {Object} scope (optional) The scope of the function (defaults to this)
13763 filterBy : function(fn, scope){
13764 this.snapshot = this.snapshot || this.data;
13765 this.data = this.queryBy(fn, scope||this);
13766 this.fireEvent("datachanged", this);
13770 * Query the records by a specified property.
13771 * @param {String} field A field on your records
13772 * @param {String/RegExp} value Either a string that the field
13773 * should start with or a RegExp to test against the field
13774 * @param {Boolean} anyMatch True to match any part not just the beginning
13775 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
13777 query : function(property, value, anyMatch){
13778 var fn = this.createFilterFn(property, value, anyMatch);
13779 return fn ? this.queryBy(fn) : this.data.clone();
13783 * Query by a function. The specified function will be called with each
13784 * record in this data source. If the function returns true the record is included
13786 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
13787 * @param {Object} scope (optional) The scope of the function (defaults to this)
13788 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
13790 queryBy : function(fn, scope){
13791 var data = this.snapshot || this.data;
13792 return data.filterBy(fn, scope||this);
13796 * Collects unique values for a particular dataIndex from this store.
13797 * @param {String} dataIndex The property to collect
13798 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
13799 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
13800 * @return {Array} An array of the unique values
13802 collect : function(dataIndex, allowNull, bypassFilter){
13803 var d = (bypassFilter === true && this.snapshot) ?
13804 this.snapshot.items : this.data.items;
13805 var v, sv, r = [], l = {};
13806 for(var i = 0, len = d.length; i < len; i++){
13807 v = d[i].data[dataIndex];
13809 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
13818 * Revert to a view of the Record cache with no filtering applied.
13819 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
13821 clearFilter : function(suppressEvent){
13822 if(this.snapshot && this.snapshot != this.data){
13823 this.data = this.snapshot;
13824 delete this.snapshot;
13825 if(suppressEvent !== true){
13826 this.fireEvent("datachanged", this);
13832 afterEdit : function(record){
13833 if(this.modified.indexOf(record) == -1){
13834 this.modified.push(record);
13836 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
13840 afterReject : function(record){
13841 this.modified.remove(record);
13842 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
13846 afterCommit : function(record){
13847 this.modified.remove(record);
13848 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
13852 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
13853 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
13855 commitChanges : function(){
13856 var m = this.modified.slice(0);
13857 this.modified = [];
13858 for(var i = 0, len = m.length; i < len; i++){
13864 * Cancel outstanding changes on all changed records.
13866 rejectChanges : function(){
13867 var m = this.modified.slice(0);
13868 this.modified = [];
13869 for(var i = 0, len = m.length; i < len; i++){
13874 onMetaChange : function(meta, rtype, o){
13875 this.recordType = rtype;
13876 this.fields = rtype.prototype.fields;
13877 delete this.snapshot;
13878 this.sortInfo = meta.sortInfo || this.sortInfo;
13879 this.modified = [];
13880 this.fireEvent('metachange', this, this.reader.meta);
13883 moveIndex : function(data, type)
13885 var index = this.indexOf(data);
13887 var newIndex = index + type;
13891 this.insert(newIndex, data);
13896 * Ext JS Library 1.1.1
13897 * Copyright(c) 2006-2007, Ext JS, LLC.
13899 * Originally Released Under LGPL - original licence link has changed is not relivant.
13902 * <script type="text/javascript">
13906 * @class Roo.data.SimpleStore
13907 * @extends Roo.data.Store
13908 * Small helper class to make creating Stores from Array data easier.
13909 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
13910 * @cfg {Array} fields An array of field definition objects, or field name strings.
13911 * @cfg {Object} an existing reader (eg. copied from another store)
13912 * @cfg {Array} data The multi-dimensional array of data
13914 * @param {Object} config
13916 Roo.data.SimpleStore = function(config)
13918 Roo.data.SimpleStore.superclass.constructor.call(this, {
13920 reader: typeof(config.reader) != 'undefined' ? config.reader : new Roo.data.ArrayReader({
13923 Roo.data.Record.create(config.fields)
13925 proxy : new Roo.data.MemoryProxy(config.data)
13929 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
13931 * Ext JS Library 1.1.1
13932 * Copyright(c) 2006-2007, Ext JS, LLC.
13934 * Originally Released Under LGPL - original licence link has changed is not relivant.
13937 * <script type="text/javascript">
13942 * @extends Roo.data.Store
13943 * @class Roo.data.JsonStore
13944 * Small helper class to make creating Stores for JSON data easier. <br/>
13946 var store = new Roo.data.JsonStore({
13947 url: 'get-images.php',
13949 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
13952 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
13953 * JsonReader and HttpProxy (unless inline data is provided).</b>
13954 * @cfg {Array} fields An array of field definition objects, or field name strings.
13956 * @param {Object} config
13958 Roo.data.JsonStore = function(c){
13959 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
13960 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
13961 reader: new Roo.data.JsonReader(c, c.fields)
13964 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
13966 * Ext JS Library 1.1.1
13967 * Copyright(c) 2006-2007, Ext JS, LLC.
13969 * Originally Released Under LGPL - original licence link has changed is not relivant.
13972 * <script type="text/javascript">
13976 Roo.data.Field = function(config){
13977 if(typeof config == "string"){
13978 config = {name: config};
13980 Roo.apply(this, config);
13983 this.type = "auto";
13986 var st = Roo.data.SortTypes;
13987 // named sortTypes are supported, here we look them up
13988 if(typeof this.sortType == "string"){
13989 this.sortType = st[this.sortType];
13992 // set default sortType for strings and dates
13993 if(!this.sortType){
13996 this.sortType = st.asUCString;
13999 this.sortType = st.asDate;
14002 this.sortType = st.none;
14007 var stripRe = /[\$,%]/g;
14009 // prebuilt conversion function for this field, instead of
14010 // switching every time we're reading a value
14012 var cv, dateFormat = this.dateFormat;
14017 cv = function(v){ return v; };
14020 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
14024 return v !== undefined && v !== null && v !== '' ?
14025 parseInt(String(v).replace(stripRe, ""), 10) : '';
14030 return v !== undefined && v !== null && v !== '' ?
14031 parseFloat(String(v).replace(stripRe, ""), 10) : '';
14036 cv = function(v){ return v === true || v === "true" || v == 1; };
14043 if(v instanceof Date){
14047 if(dateFormat == "timestamp"){
14048 return new Date(v*1000);
14050 return Date.parseDate(v, dateFormat);
14052 var parsed = Date.parse(v);
14053 return parsed ? new Date(parsed) : null;
14062 Roo.data.Field.prototype = {
14070 * Ext JS Library 1.1.1
14071 * Copyright(c) 2006-2007, Ext JS, LLC.
14073 * Originally Released Under LGPL - original licence link has changed is not relivant.
14076 * <script type="text/javascript">
14079 // Base class for reading structured data from a data source. This class is intended to be
14080 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
14083 * @class Roo.data.DataReader
14084 * Base class for reading structured data from a data source. This class is intended to be
14085 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
14088 Roo.data.DataReader = function(meta, recordType){
14092 this.recordType = recordType instanceof Array ?
14093 Roo.data.Record.create(recordType) : recordType;
14096 Roo.data.DataReader.prototype = {
14099 readerType : 'Data',
14101 * Create an empty record
14102 * @param {Object} data (optional) - overlay some values
14103 * @return {Roo.data.Record} record created.
14105 newRow : function(d) {
14107 this.recordType.prototype.fields.each(function(c) {
14109 case 'int' : da[c.name] = 0; break;
14110 case 'date' : da[c.name] = new Date(); break;
14111 case 'float' : da[c.name] = 0.0; break;
14112 case 'boolean' : da[c.name] = false; break;
14113 default : da[c.name] = ""; break;
14117 return new this.recordType(Roo.apply(da, d));
14123 * Ext JS Library 1.1.1
14124 * Copyright(c) 2006-2007, Ext JS, LLC.
14126 * Originally Released Under LGPL - original licence link has changed is not relivant.
14129 * <script type="text/javascript">
14133 * @class Roo.data.DataProxy
14134 * @extends Roo.data.Observable
14135 * This class is an abstract base class for implementations which provide retrieval of
14136 * unformatted data objects.<br>
14138 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
14139 * (of the appropriate type which knows how to parse the data object) to provide a block of
14140 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
14142 * Custom implementations must implement the load method as described in
14143 * {@link Roo.data.HttpProxy#load}.
14145 Roo.data.DataProxy = function(){
14148 * @event beforeload
14149 * Fires before a network request is made to retrieve a data object.
14150 * @param {Object} This DataProxy object.
14151 * @param {Object} params The params parameter to the load function.
14156 * Fires before the load method's callback is called.
14157 * @param {Object} This DataProxy object.
14158 * @param {Object} o The data object.
14159 * @param {Object} arg The callback argument object passed to the load function.
14163 * @event loadexception
14164 * Fires if an Exception occurs during data retrieval.
14165 * @param {Object} This DataProxy object.
14166 * @param {Object} o The data object.
14167 * @param {Object} arg The callback argument object passed to the load function.
14168 * @param {Object} e The Exception.
14170 loadexception : true
14172 Roo.data.DataProxy.superclass.constructor.call(this);
14175 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
14178 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
14182 * Ext JS Library 1.1.1
14183 * Copyright(c) 2006-2007, Ext JS, LLC.
14185 * Originally Released Under LGPL - original licence link has changed is not relivant.
14188 * <script type="text/javascript">
14191 * @class Roo.data.MemoryProxy
14192 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
14193 * to the Reader when its load method is called.
14195 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
14197 Roo.data.MemoryProxy = function(data){
14201 Roo.data.MemoryProxy.superclass.constructor.call(this);
14205 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
14208 * Load data from the requested source (in this case an in-memory
14209 * data object passed to the constructor), read the data object into
14210 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
14211 * process that block using the passed callback.
14212 * @param {Object} params This parameter is not used by the MemoryProxy class.
14213 * @param {Roo.data.DataReader} reader The Reader object which converts the data
14214 * object into a block of Roo.data.Records.
14215 * @param {Function} callback The function into which to pass the block of Roo.data.records.
14216 * The function must be passed <ul>
14217 * <li>The Record block object</li>
14218 * <li>The "arg" argument from the load function</li>
14219 * <li>A boolean success indicator</li>
14221 * @param {Object} scope The scope in which to call the callback
14222 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
14224 load : function(params, reader, callback, scope, arg){
14225 params = params || {};
14228 result = reader.readRecords(params.data ? params.data :this.data);
14230 this.fireEvent("loadexception", this, arg, null, e);
14231 callback.call(scope, null, arg, false);
14234 callback.call(scope, result, arg, true);
14238 update : function(params, records){
14243 * Ext JS Library 1.1.1
14244 * Copyright(c) 2006-2007, Ext JS, LLC.
14246 * Originally Released Under LGPL - original licence link has changed is not relivant.
14249 * <script type="text/javascript">
14252 * @class Roo.data.HttpProxy
14253 * @extends Roo.data.DataProxy
14254 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
14255 * configured to reference a certain URL.<br><br>
14257 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
14258 * from which the running page was served.<br><br>
14260 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
14262 * Be aware that to enable the browser to parse an XML document, the server must set
14263 * the Content-Type header in the HTTP response to "text/xml".
14265 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
14266 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
14267 * will be used to make the request.
14269 Roo.data.HttpProxy = function(conn){
14270 Roo.data.HttpProxy.superclass.constructor.call(this);
14271 // is conn a conn config or a real conn?
14273 this.useAjax = !conn || !conn.events;
14277 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
14278 // thse are take from connection...
14281 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
14284 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
14285 * extra parameters to each request made by this object. (defaults to undefined)
14288 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
14289 * to each request made by this object. (defaults to undefined)
14292 * @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)
14295 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
14298 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
14304 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
14308 * Return the {@link Roo.data.Connection} object being used by this Proxy.
14309 * @return {Connection} The Connection object. This object may be used to subscribe to events on
14310 * a finer-grained basis than the DataProxy events.
14312 getConnection : function(){
14313 return this.useAjax ? Roo.Ajax : this.conn;
14317 * Load data from the configured {@link Roo.data.Connection}, read the data object into
14318 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
14319 * process that block using the passed callback.
14320 * @param {Object} params An object containing properties which are to be used as HTTP parameters
14321 * for the request to the remote server.
14322 * @param {Roo.data.DataReader} reader The Reader object which converts the data
14323 * object into a block of Roo.data.Records.
14324 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
14325 * The function must be passed <ul>
14326 * <li>The Record block object</li>
14327 * <li>The "arg" argument from the load function</li>
14328 * <li>A boolean success indicator</li>
14330 * @param {Object} scope The scope in which to call the callback
14331 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
14333 load : function(params, reader, callback, scope, arg){
14334 if(this.fireEvent("beforeload", this, params) !== false){
14336 params : params || {},
14338 callback : callback,
14343 callback : this.loadResponse,
14347 Roo.applyIf(o, this.conn);
14348 if(this.activeRequest){
14349 Roo.Ajax.abort(this.activeRequest);
14351 this.activeRequest = Roo.Ajax.request(o);
14353 this.conn.request(o);
14356 callback.call(scope||this, null, arg, false);
14361 loadResponse : function(o, success, response){
14362 delete this.activeRequest;
14364 this.fireEvent("loadexception", this, o, response);
14365 o.request.callback.call(o.request.scope, null, o.request.arg, false);
14370 result = o.reader.read(response);
14372 this.fireEvent("loadexception", this, o, response, e);
14373 o.request.callback.call(o.request.scope, null, o.request.arg, false);
14377 this.fireEvent("load", this, o, o.request.arg);
14378 o.request.callback.call(o.request.scope, result, o.request.arg, true);
14382 update : function(dataSet){
14387 updateResponse : function(dataSet){
14392 * Ext JS Library 1.1.1
14393 * Copyright(c) 2006-2007, Ext JS, LLC.
14395 * Originally Released Under LGPL - original licence link has changed is not relivant.
14398 * <script type="text/javascript">
14402 * @class Roo.data.ScriptTagProxy
14403 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
14404 * other than the originating domain of the running page.<br><br>
14406 * <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
14407 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
14409 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
14410 * source code that is used as the source inside a <script> tag.<br><br>
14412 * In order for the browser to process the returned data, the server must wrap the data object
14413 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
14414 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
14415 * depending on whether the callback name was passed:
14418 boolean scriptTag = false;
14419 String cb = request.getParameter("callback");
14422 response.setContentType("text/javascript");
14424 response.setContentType("application/x-json");
14426 Writer out = response.getWriter();
14428 out.write(cb + "(");
14430 out.print(dataBlock.toJsonString());
14437 * @param {Object} config A configuration object.
14439 Roo.data.ScriptTagProxy = function(config){
14440 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
14441 Roo.apply(this, config);
14442 this.head = document.getElementsByTagName("head")[0];
14445 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
14447 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
14449 * @cfg {String} url The URL from which to request the data object.
14452 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
14456 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
14457 * the server the name of the callback function set up by the load call to process the returned data object.
14458 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
14459 * javascript output which calls this named function passing the data object as its only parameter.
14461 callbackParam : "callback",
14463 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
14464 * name to the request.
14469 * Load data from the configured URL, read the data object into
14470 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
14471 * process that block using the passed callback.
14472 * @param {Object} params An object containing properties which are to be used as HTTP parameters
14473 * for the request to the remote server.
14474 * @param {Roo.data.DataReader} reader The Reader object which converts the data
14475 * object into a block of Roo.data.Records.
14476 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
14477 * The function must be passed <ul>
14478 * <li>The Record block object</li>
14479 * <li>The "arg" argument from the load function</li>
14480 * <li>A boolean success indicator</li>
14482 * @param {Object} scope The scope in which to call the callback
14483 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
14485 load : function(params, reader, callback, scope, arg){
14486 if(this.fireEvent("beforeload", this, params) !== false){
14488 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
14490 var url = this.url;
14491 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
14493 url += "&_dc=" + (new Date().getTime());
14495 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
14498 cb : "stcCallback"+transId,
14499 scriptId : "stcScript"+transId,
14503 callback : callback,
14509 window[trans.cb] = function(o){
14510 conn.handleResponse(o, trans);
14513 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
14515 if(this.autoAbort !== false){
14519 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
14521 var script = document.createElement("script");
14522 script.setAttribute("src", url);
14523 script.setAttribute("type", "text/javascript");
14524 script.setAttribute("id", trans.scriptId);
14525 this.head.appendChild(script);
14527 this.trans = trans;
14529 callback.call(scope||this, null, arg, false);
14534 isLoading : function(){
14535 return this.trans ? true : false;
14539 * Abort the current server request.
14541 abort : function(){
14542 if(this.isLoading()){
14543 this.destroyTrans(this.trans);
14548 destroyTrans : function(trans, isLoaded){
14549 this.head.removeChild(document.getElementById(trans.scriptId));
14550 clearTimeout(trans.timeoutId);
14552 window[trans.cb] = undefined;
14554 delete window[trans.cb];
14557 // if hasn't been loaded, wait for load to remove it to prevent script error
14558 window[trans.cb] = function(){
14559 window[trans.cb] = undefined;
14561 delete window[trans.cb];
14568 handleResponse : function(o, trans){
14569 this.trans = false;
14570 this.destroyTrans(trans, true);
14573 result = trans.reader.readRecords(o);
14575 this.fireEvent("loadexception", this, o, trans.arg, e);
14576 trans.callback.call(trans.scope||window, null, trans.arg, false);
14579 this.fireEvent("load", this, o, trans.arg);
14580 trans.callback.call(trans.scope||window, result, trans.arg, true);
14584 handleFailure : function(trans){
14585 this.trans = false;
14586 this.destroyTrans(trans, false);
14587 this.fireEvent("loadexception", this, null, trans.arg);
14588 trans.callback.call(trans.scope||window, null, trans.arg, false);
14592 * Ext JS Library 1.1.1
14593 * Copyright(c) 2006-2007, Ext JS, LLC.
14595 * Originally Released Under LGPL - original licence link has changed is not relivant.
14598 * <script type="text/javascript">
14602 * @class Roo.data.JsonReader
14603 * @extends Roo.data.DataReader
14604 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
14605 * based on mappings in a provided Roo.data.Record constructor.
14607 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
14608 * in the reply previously.
14613 var RecordDef = Roo.data.Record.create([
14614 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
14615 {name: 'occupation'} // This field will use "occupation" as the mapping.
14617 var myReader = new Roo.data.JsonReader({
14618 totalProperty: "results", // The property which contains the total dataset size (optional)
14619 root: "rows", // The property which contains an Array of row objects
14620 id: "id" // The property within each row object that provides an ID for the record (optional)
14624 * This would consume a JSON file like this:
14626 { 'results': 2, 'rows': [
14627 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
14628 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
14631 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
14632 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
14633 * paged from the remote server.
14634 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
14635 * @cfg {String} root name of the property which contains the Array of row objects.
14636 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
14637 * @cfg {Array} fields Array of field definition objects
14639 * Create a new JsonReader
14640 * @param {Object} meta Metadata configuration options
14641 * @param {Object} recordType Either an Array of field definition objects,
14642 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
14644 Roo.data.JsonReader = function(meta, recordType){
14647 // set some defaults:
14648 Roo.applyIf(meta, {
14649 totalProperty: 'total',
14650 successProperty : 'success',
14655 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
14657 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
14659 readerType : 'Json',
14662 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
14663 * Used by Store query builder to append _requestMeta to params.
14666 metaFromRemote : false,
14668 * This method is only used by a DataProxy which has retrieved data from a remote server.
14669 * @param {Object} response The XHR object which contains the JSON data in its responseText.
14670 * @return {Object} data A data block which is used by an Roo.data.Store object as
14671 * a cache of Roo.data.Records.
14673 read : function(response){
14674 var json = response.responseText;
14676 var o = /* eval:var:o */ eval("("+json+")");
14678 throw {message: "JsonReader.read: Json object not found"};
14684 this.metaFromRemote = true;
14685 this.meta = o.metaData;
14686 this.recordType = Roo.data.Record.create(o.metaData.fields);
14687 this.onMetaChange(this.meta, this.recordType, o);
14689 return this.readRecords(o);
14692 // private function a store will implement
14693 onMetaChange : function(meta, recordType, o){
14700 simpleAccess: function(obj, subsc) {
14707 getJsonAccessor: function(){
14709 return function(expr) {
14711 return(re.test(expr))
14712 ? new Function("obj", "return obj." + expr)
14717 return Roo.emptyFn;
14722 * Create a data block containing Roo.data.Records from an XML document.
14723 * @param {Object} o An object which contains an Array of row objects in the property specified
14724 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
14725 * which contains the total size of the dataset.
14726 * @return {Object} data A data block which is used by an Roo.data.Store object as
14727 * a cache of Roo.data.Records.
14729 readRecords : function(o){
14731 * After any data loads, the raw JSON data is available for further custom processing.
14735 var s = this.meta, Record = this.recordType,
14736 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
14738 // Generate extraction functions for the totalProperty, the root, the id, and for each field
14740 if(s.totalProperty) {
14741 this.getTotal = this.getJsonAccessor(s.totalProperty);
14743 if(s.successProperty) {
14744 this.getSuccess = this.getJsonAccessor(s.successProperty);
14746 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
14748 var g = this.getJsonAccessor(s.id);
14749 this.getId = function(rec) {
14751 return (r === undefined || r === "") ? null : r;
14754 this.getId = function(){return null;};
14757 for(var jj = 0; jj < fl; jj++){
14759 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
14760 this.ef[jj] = this.getJsonAccessor(map);
14764 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
14765 if(s.totalProperty){
14766 var vt = parseInt(this.getTotal(o), 10);
14771 if(s.successProperty){
14772 var vs = this.getSuccess(o);
14773 if(vs === false || vs === 'false'){
14778 for(var i = 0; i < c; i++){
14781 var id = this.getId(n);
14782 for(var j = 0; j < fl; j++){
14784 var v = this.ef[j](n);
14786 Roo.log('missing convert for ' + f.name);
14790 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
14792 var record = new Record(values, id);
14794 records[i] = record;
14800 totalRecords : totalRecords
14803 // used when loading children.. @see loadDataFromChildren
14804 toLoadData: function(rec)
14806 // expect rec just to be an array.. eg [a,b,c, [...] << cn ]
14807 var data = typeof(rec.data.cn) == 'undefined' ? [] : rec.data.cn;
14808 return { data : data, total : data.length };
14813 * Ext JS Library 1.1.1
14814 * Copyright(c) 2006-2007, Ext JS, LLC.
14816 * Originally Released Under LGPL - original licence link has changed is not relivant.
14819 * <script type="text/javascript">
14823 * @class Roo.data.ArrayReader
14824 * @extends Roo.data.DataReader
14825 * Data reader class to create an Array of Roo.data.Record objects from an Array.
14826 * Each element of that Array represents a row of data fields. The
14827 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
14828 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
14832 var RecordDef = Roo.data.Record.create([
14833 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
14834 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
14836 var myReader = new Roo.data.ArrayReader({
14837 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
14841 * This would consume an Array like this:
14843 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
14847 * Create a new JsonReader
14848 * @param {Object} meta Metadata configuration options.
14849 * @param {Object|Array} recordType Either an Array of field definition objects
14851 * @cfg {Array} fields Array of field definition objects
14852 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
14853 * as specified to {@link Roo.data.Record#create},
14854 * or an {@link Roo.data.Record} object
14857 * created using {@link Roo.data.Record#create}.
14859 Roo.data.ArrayReader = function(meta, recordType)
14861 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType||meta.fields);
14864 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
14867 * Create a data block containing Roo.data.Records from an XML document.
14868 * @param {Object} o An Array of row objects which represents the dataset.
14869 * @return {Object} A data block which is used by an {@link Roo.data.Store} object as
14870 * a cache of Roo.data.Records.
14872 readRecords : function(o)
14874 var sid = this.meta ? this.meta.id : null;
14875 var recordType = this.recordType, fields = recordType.prototype.fields;
14878 for(var i = 0; i < root.length; i++){
14881 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
14882 for(var j = 0, jlen = fields.length; j < jlen; j++){
14883 var f = fields.items[j];
14884 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
14885 var v = n[k] !== undefined ? n[k] : f.defaultValue;
14887 values[f.name] = v;
14889 var record = new recordType(values, id);
14891 records[records.length] = record;
14895 totalRecords : records.length
14898 // used when loading children.. @see loadDataFromChildren
14899 toLoadData: function(rec)
14901 // expect rec just to be an array.. eg [a,b,c, [...] << cn ]
14902 return typeof(rec.data.cn) == 'undefined' ? [] : rec.data.cn;
14913 * @class Roo.bootstrap.ComboBox
14914 * @extends Roo.bootstrap.TriggerField
14915 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
14916 * @cfg {Boolean} append (true|false) default false
14917 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
14918 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
14919 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
14920 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
14921 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
14922 * @cfg {Boolean} animate default true
14923 * @cfg {Boolean} emptyResultText only for touch device
14924 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
14925 * @cfg {String} emptyTitle default ''
14926 * @cfg {Number} width fixed with? experimental
14928 * Create a new ComboBox.
14929 * @param {Object} config Configuration options
14931 Roo.bootstrap.ComboBox = function(config){
14932 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
14936 * Fires when the dropdown list is expanded
14937 * @param {Roo.bootstrap.ComboBox} combo This combo box
14942 * Fires when the dropdown list is collapsed
14943 * @param {Roo.bootstrap.ComboBox} combo This combo box
14947 * @event beforeselect
14948 * Fires before a list item is selected. Return false to cancel the selection.
14949 * @param {Roo.bootstrap.ComboBox} combo This combo box
14950 * @param {Roo.data.Record} record The data record returned from the underlying store
14951 * @param {Number} index The index of the selected item in the dropdown list
14953 'beforeselect' : true,
14956 * Fires when a list item is selected
14957 * @param {Roo.bootstrap.ComboBox} combo This combo box
14958 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
14959 * @param {Number} index The index of the selected item in the dropdown list
14963 * @event beforequery
14964 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
14965 * The event object passed has these properties:
14966 * @param {Roo.bootstrap.ComboBox} combo This combo box
14967 * @param {String} query The query
14968 * @param {Boolean} forceAll true to force "all" query
14969 * @param {Boolean} cancel true to cancel the query
14970 * @param {Object} e The query event object
14972 'beforequery': true,
14975 * Fires when the 'add' icon is pressed (add a listener to enable add button)
14976 * @param {Roo.bootstrap.ComboBox} combo This combo box
14981 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
14982 * @param {Roo.bootstrap.ComboBox} combo This combo box
14983 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
14988 * Fires when the remove value from the combobox array
14989 * @param {Roo.bootstrap.ComboBox} combo This combo box
14993 * @event afterremove
14994 * Fires when the remove value from the combobox array
14995 * @param {Roo.bootstrap.ComboBox} combo This combo box
14997 'afterremove' : true,
14999 * @event specialfilter
15000 * Fires when specialfilter
15001 * @param {Roo.bootstrap.ComboBox} combo This combo box
15003 'specialfilter' : true,
15006 * Fires when tick the element
15007 * @param {Roo.bootstrap.ComboBox} combo This combo box
15011 * @event touchviewdisplay
15012 * Fires when touch view require special display (default is using displayField)
15013 * @param {Roo.bootstrap.ComboBox} combo This combo box
15014 * @param {Object} cfg set html .
15016 'touchviewdisplay' : true
15021 this.tickItems = [];
15023 this.selectedIndex = -1;
15024 if(this.mode == 'local'){
15025 if(config.queryDelay === undefined){
15026 this.queryDelay = 10;
15028 if(config.minChars === undefined){
15034 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
15037 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
15038 * rendering into an Roo.Editor, defaults to false)
15041 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
15042 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
15045 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
15048 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
15049 * the dropdown list (defaults to undefined, with no header element)
15053 * @cfg {String/Roo.Template} tpl The template to use to render the output default is '<a class="dropdown-item" href="#">{' + this.displayField + '}</a>'
15057 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
15059 listWidth: undefined,
15061 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
15062 * mode = 'remote' or 'text' if mode = 'local')
15064 displayField: undefined,
15067 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
15068 * mode = 'remote' or 'value' if mode = 'local').
15069 * Note: use of a valueField requires the user make a selection
15070 * in order for a value to be mapped.
15072 valueField: undefined,
15074 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
15079 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
15080 * field's data value (defaults to the underlying DOM element's name)
15082 hiddenName: undefined,
15084 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
15088 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
15090 selectedClass: 'active',
15093 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
15097 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
15098 * anchor positions (defaults to 'tl-bl')
15100 listAlign: 'tl-bl?',
15102 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
15106 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
15107 * query specified by the allQuery config option (defaults to 'query')
15109 triggerAction: 'query',
15111 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
15112 * (defaults to 4, does not apply if editable = false)
15116 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
15117 * delay (typeAheadDelay) if it matches a known value (defaults to false)
15121 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
15122 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
15126 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
15127 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
15131 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
15132 * when editable = true (defaults to false)
15134 selectOnFocus:false,
15136 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
15138 queryParam: 'query',
15140 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
15141 * when mode = 'remote' (defaults to 'Loading...')
15143 loadingText: 'Loading...',
15145 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
15149 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
15153 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
15154 * traditional select (defaults to true)
15158 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
15162 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
15166 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
15167 * listWidth has a higher value)
15171 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
15172 * allow the user to set arbitrary text into the field (defaults to false)
15174 forceSelection:false,
15176 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
15177 * if typeAhead = true (defaults to 250)
15179 typeAheadDelay : 250,
15181 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
15182 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
15184 valueNotFoundText : undefined,
15186 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
15188 blockFocus : false,
15191 * @cfg {Boolean} disableClear Disable showing of clear button.
15193 disableClear : false,
15195 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
15197 alwaysQuery : false,
15200 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
15205 * @cfg {String} invalidClass DEPRICATED - uses BS4 is-valid now
15207 invalidClass : "has-warning",
15210 * @cfg {String} validClass DEPRICATED - uses BS4 is-valid now
15212 validClass : "has-success",
15215 * @cfg {Boolean} specialFilter (true|false) special filter default false
15217 specialFilter : false,
15220 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
15222 mobileTouchView : true,
15225 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
15227 useNativeIOS : false,
15230 * @cfg {Boolean} mobile_restrict_height (true|false) restrict height for touch view
15232 mobile_restrict_height : false,
15234 ios_options : false,
15246 btnPosition : 'right',
15247 triggerList : true,
15248 showToggleBtn : true,
15250 emptyResultText: 'Empty',
15251 triggerText : 'Select',
15255 // element that contains real text value.. (when hidden is used..)
15257 getAutoCreate : function()
15262 * Render classic select for iso
15265 if(Roo.isIOS && this.useNativeIOS){
15266 cfg = this.getAutoCreateNativeIOS();
15274 if(Roo.isTouch && this.mobileTouchView){
15275 cfg = this.getAutoCreateTouchView();
15282 if(!this.tickable){
15283 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
15288 * ComboBox with tickable selections
15291 var align = this.labelAlign || this.parentLabelAlign();
15294 cls : 'form-group roo-combobox-tickable' //input-group
15297 var btn_text_select = '';
15298 var btn_text_done = '';
15299 var btn_text_cancel = '';
15301 if (this.btn_text_show) {
15302 btn_text_select = 'Select';
15303 btn_text_done = 'Done';
15304 btn_text_cancel = 'Cancel';
15309 cls : 'tickable-buttons',
15314 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
15315 //html : this.triggerText
15316 html: btn_text_select
15322 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
15324 html: btn_text_done
15330 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
15332 html: btn_text_cancel
15338 buttons.cn.unshift({
15340 cls: 'roo-select2-search-field-input'
15346 Roo.each(buttons.cn, function(c){
15348 c.cls += ' btn-' + _this.size;
15351 if (_this.disabled) {
15358 style : 'display: contents',
15363 cls: 'form-hidden-field'
15367 cls: 'roo-select2-choices',
15371 cls: 'roo-select2-search-field',
15382 cls: 'roo-select2-container input-group roo-select2-container-multi',
15388 // cls: 'typeahead typeahead-long dropdown-menu',
15389 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
15394 if(this.hasFeedback && !this.allowBlank){
15398 cls: 'glyphicon form-control-feedback'
15401 combobox.cn.push(feedback);
15408 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
15409 tooltip : 'This field is required'
15411 if (Roo.bootstrap.version == 4) {
15414 style : 'display:none'
15417 if (align ==='left' && this.fieldLabel.length) {
15419 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
15426 cls : 'control-label col-form-label',
15427 html : this.fieldLabel
15439 var labelCfg = cfg.cn[1];
15440 var contentCfg = cfg.cn[2];
15443 if(this.indicatorpos == 'right'){
15449 cls : 'control-label col-form-label',
15453 html : this.fieldLabel
15469 labelCfg = cfg.cn[0];
15470 contentCfg = cfg.cn[1];
15474 if(this.labelWidth > 12){
15475 labelCfg.style = "width: " + this.labelWidth + 'px';
15477 if(this.width * 1 > 0){
15478 contentCfg.style = "width: " + this.width + 'px';
15480 if(this.labelWidth < 13 && this.labelmd == 0){
15481 this.labelmd = this.labelWidth;
15484 if(this.labellg > 0){
15485 labelCfg.cls += ' col-lg-' + this.labellg;
15486 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
15489 if(this.labelmd > 0){
15490 labelCfg.cls += ' col-md-' + this.labelmd;
15491 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
15494 if(this.labelsm > 0){
15495 labelCfg.cls += ' col-sm-' + this.labelsm;
15496 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
15499 if(this.labelxs > 0){
15500 labelCfg.cls += ' col-xs-' + this.labelxs;
15501 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
15505 } else if ( this.fieldLabel.length) {
15506 // Roo.log(" label");
15511 //cls : 'input-group-addon',
15512 html : this.fieldLabel
15517 if(this.indicatorpos == 'right'){
15521 //cls : 'input-group-addon',
15522 html : this.fieldLabel
15532 // Roo.log(" no label && no align");
15539 ['xs','sm','md','lg'].map(function(size){
15540 if (settings[size]) {
15541 cfg.cls += ' col-' + size + '-' + settings[size];
15549 _initEventsCalled : false,
15552 initEvents: function()
15554 if (this._initEventsCalled) { // as we call render... prevent looping...
15557 this._initEventsCalled = true;
15560 throw "can not find store for combo";
15563 this.indicator = this.indicatorEl();
15565 this.store = Roo.factory(this.store, Roo.data);
15566 this.store.parent = this;
15568 // if we are building from html. then this element is so complex, that we can not really
15569 // use the rendered HTML.
15570 // so we have to trash and replace the previous code.
15571 if (Roo.XComponent.build_from_html) {
15572 // remove this element....
15573 var e = this.el.dom, k=0;
15574 while (e ) { e = e.previousSibling; ++k;}
15579 this.rendered = false;
15581 this.render(this.parent().getChildContainer(true), k);
15584 if(Roo.isIOS && this.useNativeIOS){
15585 this.initIOSView();
15593 if(Roo.isTouch && this.mobileTouchView){
15594 this.initTouchView();
15599 this.initTickableEvents();
15603 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
15605 if(this.hiddenName){
15607 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
15609 this.hiddenField.dom.value =
15610 this.hiddenValue !== undefined ? this.hiddenValue :
15611 this.value !== undefined ? this.value : '';
15613 // prevent input submission
15614 this.el.dom.removeAttribute('name');
15615 this.hiddenField.dom.setAttribute('name', this.hiddenName);
15620 // this.el.dom.setAttribute('autocomplete', 'off');
15623 var cls = 'x-combo-list';
15625 //this.list = new Roo.Layer({
15626 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
15632 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
15633 _this.list.setWidth(lw);
15636 this.list.on('mouseover', this.onViewOver, this);
15637 this.list.on('mousemove', this.onViewMove, this);
15638 this.list.on('scroll', this.onViewScroll, this);
15641 this.list.swallowEvent('mousewheel');
15642 this.assetHeight = 0;
15645 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
15646 this.assetHeight += this.header.getHeight();
15649 this.innerList = this.list.createChild({cls:cls+'-inner'});
15650 this.innerList.on('mouseover', this.onViewOver, this);
15651 this.innerList.on('mousemove', this.onViewMove, this);
15652 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
15654 if(this.allowBlank && !this.pageSize && !this.disableClear){
15655 this.footer = this.list.createChild({cls:cls+'-ft'});
15656 this.pageTb = new Roo.Toolbar(this.footer);
15660 this.footer = this.list.createChild({cls:cls+'-ft'});
15661 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
15662 {pageSize: this.pageSize});
15666 if (this.pageTb && this.allowBlank && !this.disableClear) {
15668 this.pageTb.add(new Roo.Toolbar.Fill(), {
15669 cls: 'x-btn-icon x-btn-clear',
15671 handler: function()
15674 _this.clearValue();
15675 _this.onSelect(false, -1);
15680 this.assetHeight += this.footer.getHeight();
15685 this.tpl = Roo.bootstrap.version == 4 ?
15686 '<a class="dropdown-item" href="#">{' + this.displayField + '}</a>' : // 4 does not need <li> and it get's really confisued.
15687 '<li><a class="dropdown-item" href="#">{' + this.displayField + '}</a></li>';
15690 this.view = new Roo.View(this.list, this.tpl, {
15691 singleSelect:true, store: this.store, selectedClass: this.selectedClass
15693 //this.view.wrapEl.setDisplayed(false);
15694 this.view.on('click', this.onViewClick, this);
15697 this.store.on('beforeload', this.onBeforeLoad, this);
15698 this.store.on('load', this.onLoad, this);
15699 this.store.on('loadexception', this.onLoadException, this);
15701 if(this.resizable){
15702 this.resizer = new Roo.Resizable(this.list, {
15703 pinned:true, handles:'se'
15705 this.resizer.on('resize', function(r, w, h){
15706 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
15707 this.listWidth = w;
15708 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
15709 this.restrictHeight();
15711 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
15714 if(!this.editable){
15715 this.editable = true;
15716 this.setEditable(false);
15721 if (typeof(this.events.add.listeners) != 'undefined') {
15723 this.addicon = this.wrap.createChild(
15724 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
15726 this.addicon.on('click', function(e) {
15727 this.fireEvent('add', this);
15730 if (typeof(this.events.edit.listeners) != 'undefined') {
15732 this.editicon = this.wrap.createChild(
15733 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
15734 if (this.addicon) {
15735 this.editicon.setStyle('margin-left', '40px');
15737 this.editicon.on('click', function(e) {
15739 // we fire even if inothing is selected..
15740 this.fireEvent('edit', this, this.lastData );
15746 this.keyNav = new Roo.KeyNav(this.inputEl(), {
15747 "up" : function(e){
15748 this.inKeyMode = true;
15752 "down" : function(e){
15753 if(!this.isExpanded()){
15754 this.onTriggerClick();
15756 this.inKeyMode = true;
15761 "enter" : function(e){
15762 // this.onViewClick();
15766 if(this.fireEvent("specialkey", this, e)){
15767 this.onViewClick(false);
15773 "esc" : function(e){
15777 "tab" : function(e){
15780 if(this.fireEvent("specialkey", this, e)){
15781 this.onViewClick(false);
15789 doRelay : function(foo, bar, hname){
15790 if(hname == 'down' || this.scope.isExpanded()){
15791 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
15800 this.queryDelay = Math.max(this.queryDelay || 10,
15801 this.mode == 'local' ? 10 : 250);
15804 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
15806 if(this.typeAhead){
15807 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
15809 if(this.editable !== false){
15810 this.inputEl().on("keyup", this.onKeyUp, this);
15812 if(this.forceSelection){
15813 this.inputEl().on('blur', this.doForce, this);
15817 this.choices = this.el.select('ul.roo-select2-choices', true).first();
15818 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
15822 initTickableEvents: function()
15826 if(this.hiddenName){
15828 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
15830 this.hiddenField.dom.value =
15831 this.hiddenValue !== undefined ? this.hiddenValue :
15832 this.value !== undefined ? this.value : '';
15834 // prevent input submission
15835 this.el.dom.removeAttribute('name');
15836 this.hiddenField.dom.setAttribute('name', this.hiddenName);
15841 // this.list = this.el.select('ul.dropdown-menu',true).first();
15843 this.choices = this.el.select('ul.roo-select2-choices', true).first();
15844 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
15845 if(this.triggerList){
15846 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
15849 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
15850 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
15852 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
15853 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
15855 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
15856 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
15858 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
15859 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
15860 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
15863 this.cancelBtn.hide();
15868 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
15869 _this.list.setWidth(lw);
15872 this.list.on('mouseover', this.onViewOver, this);
15873 this.list.on('mousemove', this.onViewMove, this);
15875 this.list.on('scroll', this.onViewScroll, this);
15878 this.tpl = '<li class="roo-select2-result"><div class="checkbox"><input id="{roo-id}"' +
15879 'type="checkbox" {roo-data-checked}><label for="{roo-id}"><b>{' + this.displayField + '}</b></label></div></li>';
15882 this.view = new Roo.View(this.list, this.tpl, {
15887 selectedClass: this.selectedClass
15890 //this.view.wrapEl.setDisplayed(false);
15891 this.view.on('click', this.onViewClick, this);
15895 this.store.on('beforeload', this.onBeforeLoad, this);
15896 this.store.on('load', this.onLoad, this);
15897 this.store.on('loadexception', this.onLoadException, this);
15900 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
15901 "up" : function(e){
15902 this.inKeyMode = true;
15906 "down" : function(e){
15907 this.inKeyMode = true;
15911 "enter" : function(e){
15912 if(this.fireEvent("specialkey", this, e)){
15913 this.onViewClick(false);
15919 "esc" : function(e){
15920 this.onTickableFooterButtonClick(e, false, false);
15923 "tab" : function(e){
15924 this.fireEvent("specialkey", this, e);
15926 this.onTickableFooterButtonClick(e, false, false);
15933 doRelay : function(e, fn, key){
15934 if(this.scope.isExpanded()){
15935 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
15944 this.queryDelay = Math.max(this.queryDelay || 10,
15945 this.mode == 'local' ? 10 : 250);
15948 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
15950 if(this.typeAhead){
15951 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
15954 if(this.editable !== false){
15955 this.tickableInputEl().on("keyup", this.onKeyUp, this);
15958 this.indicator = this.indicatorEl();
15960 if(this.indicator){
15961 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
15962 this.indicator.hide();
15967 onDestroy : function(){
15969 this.view.setStore(null);
15970 this.view.el.removeAllListeners();
15971 this.view.el.remove();
15972 this.view.purgeListeners();
15975 this.list.dom.innerHTML = '';
15979 this.store.un('beforeload', this.onBeforeLoad, this);
15980 this.store.un('load', this.onLoad, this);
15981 this.store.un('loadexception', this.onLoadException, this);
15983 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
15987 fireKey : function(e){
15988 if(e.isNavKeyPress() && !this.list.isVisible()){
15989 this.fireEvent("specialkey", this, e);
15994 onResize: function(w, h)
15998 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
16000 // if(typeof w != 'number'){
16001 // // we do not handle it!?!?
16004 // var tw = this.trigger.getWidth();
16005 // // tw += this.addicon ? this.addicon.getWidth() : 0;
16006 // // tw += this.editicon ? this.editicon.getWidth() : 0;
16008 // this.inputEl().setWidth( this.adjustWidth('input', x));
16010 // //this.trigger.setStyle('left', x+'px');
16012 // if(this.list && this.listWidth === undefined){
16013 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
16014 // this.list.setWidth(lw);
16015 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
16023 * Allow or prevent the user from directly editing the field text. If false is passed,
16024 * the user will only be able to select from the items defined in the dropdown list. This method
16025 * is the runtime equivalent of setting the 'editable' config option at config time.
16026 * @param {Boolean} value True to allow the user to directly edit the field text
16028 setEditable : function(value){
16029 if(value == this.editable){
16032 this.editable = value;
16034 this.inputEl().dom.setAttribute('readOnly', true);
16035 this.inputEl().on('mousedown', this.onTriggerClick, this);
16036 this.inputEl().addClass('x-combo-noedit');
16038 this.inputEl().dom.setAttribute('readOnly', false);
16039 this.inputEl().un('mousedown', this.onTriggerClick, this);
16040 this.inputEl().removeClass('x-combo-noedit');
16046 onBeforeLoad : function(combo,opts){
16047 if(!this.hasFocus){
16051 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
16053 this.restrictHeight();
16054 this.selectedIndex = -1;
16058 onLoad : function(){
16060 this.hasQuery = false;
16062 if(!this.hasFocus){
16066 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
16067 this.loading.hide();
16070 if(this.store.getCount() > 0){
16073 this.restrictHeight();
16074 if(this.lastQuery == this.allQuery){
16075 if(this.editable && !this.tickable){
16076 this.inputEl().dom.select();
16080 !this.selectByValue(this.value, true) &&
16083 !this.store.lastOptions ||
16084 typeof(this.store.lastOptions.add) == 'undefined' ||
16085 this.store.lastOptions.add != true
16088 this.select(0, true);
16091 if(this.autoFocus){
16094 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
16095 this.taTask.delay(this.typeAheadDelay);
16099 this.onEmptyResults();
16105 onLoadException : function()
16107 this.hasQuery = false;
16109 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
16110 this.loading.hide();
16113 if(this.tickable && this.editable){
16118 // only causes errors at present
16119 //Roo.log(this.store.reader.jsonData);
16120 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
16122 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
16128 onTypeAhead : function(){
16129 if(this.store.getCount() > 0){
16130 var r = this.store.getAt(0);
16131 var newValue = r.data[this.displayField];
16132 var len = newValue.length;
16133 var selStart = this.getRawValue().length;
16135 if(selStart != len){
16136 this.setRawValue(newValue);
16137 this.selectText(selStart, newValue.length);
16143 onSelect : function(record, index){
16145 if(this.fireEvent('beforeselect', this, record, index) !== false){
16147 this.setFromData(index > -1 ? record.data : false);
16150 this.fireEvent('select', this, record, index);
16155 * Returns the currently selected field value or empty string if no value is set.
16156 * @return {String} value The selected value
16158 getValue : function()
16160 if(Roo.isIOS && this.useNativeIOS){
16161 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
16165 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
16168 if(this.valueField){
16169 return typeof this.value != 'undefined' ? this.value : '';
16171 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
16175 getRawValue : function()
16177 if(Roo.isIOS && this.useNativeIOS){
16178 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
16181 var v = this.inputEl().getValue();
16187 * Clears any text/value currently set in the field
16189 clearValue : function(){
16191 if(this.hiddenField){
16192 this.hiddenField.dom.value = '';
16195 this.setRawValue('');
16196 this.lastSelectionText = '';
16197 this.lastData = false;
16199 var close = this.closeTriggerEl();
16210 * Sets the specified value into the field. If the value finds a match, the corresponding record text
16211 * will be displayed in the field. If the value does not match the data value of an existing item,
16212 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
16213 * Otherwise the field will be blank (although the value will still be set).
16214 * @param {String} value The value to match
16216 setValue : function(v)
16218 if(Roo.isIOS && this.useNativeIOS){
16219 this.setIOSValue(v);
16229 if(this.valueField){
16230 var r = this.findRecord(this.valueField, v);
16232 text = r.data[this.displayField];
16233 }else if(this.valueNotFoundText !== undefined){
16234 text = this.valueNotFoundText;
16237 this.lastSelectionText = text;
16238 if(this.hiddenField){
16239 this.hiddenField.dom.value = v;
16241 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
16244 var close = this.closeTriggerEl();
16247 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
16253 * @property {Object} the last set data for the element
16258 * Sets the value of the field based on a object which is related to the record format for the store.
16259 * @param {Object} value the value to set as. or false on reset?
16261 setFromData : function(o){
16268 var dv = ''; // display value
16269 var vv = ''; // value value..
16271 if (this.displayField) {
16272 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
16274 // this is an error condition!!!
16275 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
16278 if(this.valueField){
16279 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
16282 var close = this.closeTriggerEl();
16285 if(dv.length || vv * 1 > 0){
16287 this.blockFocus=true;
16293 if(this.hiddenField){
16294 this.hiddenField.dom.value = vv;
16296 this.lastSelectionText = dv;
16297 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
16301 // no hidden field.. - we store the value in 'value', but still display
16302 // display field!!!!
16303 this.lastSelectionText = dv;
16304 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
16311 reset : function(){
16312 // overridden so that last data is reset..
16319 this.setValue(this.originalValue);
16320 //this.clearInvalid();
16321 this.lastData = false;
16323 this.view.clearSelections();
16329 findRecord : function(prop, value){
16331 if(this.store.getCount() > 0){
16332 this.store.each(function(r){
16333 if(r.data[prop] == value){
16343 getName: function()
16345 // returns hidden if it's set..
16346 if (!this.rendered) {return ''};
16347 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
16351 onViewMove : function(e, t){
16352 this.inKeyMode = false;
16356 onViewOver : function(e, t){
16357 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
16360 var item = this.view.findItemFromChild(t);
16363 var index = this.view.indexOf(item);
16364 this.select(index, false);
16369 onViewClick : function(view, doFocus, el, e)
16371 var index = this.view.getSelectedIndexes()[0];
16373 var r = this.store.getAt(index);
16377 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
16384 Roo.each(this.tickItems, function(v,k){
16386 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
16388 _this.tickItems.splice(k, 1);
16390 if(typeof(e) == 'undefined' && view == false){
16391 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
16403 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
16404 this.tickItems.push(r.data);
16407 if(typeof(e) == 'undefined' && view == false){
16408 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
16415 this.onSelect(r, index);
16417 if(doFocus !== false && !this.blockFocus){
16418 this.inputEl().focus();
16423 restrictHeight : function(){
16424 //this.innerList.dom.style.height = '';
16425 //var inner = this.innerList.dom;
16426 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
16427 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
16428 //this.list.beginUpdate();
16429 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
16430 this.list.alignTo(this.inputEl(), this.listAlign);
16431 this.list.alignTo(this.inputEl(), this.listAlign);
16432 //this.list.endUpdate();
16436 onEmptyResults : function(){
16438 if(this.tickable && this.editable){
16439 this.hasFocus = false;
16440 this.restrictHeight();
16448 * Returns true if the dropdown list is expanded, else false.
16450 isExpanded : function(){
16451 return this.list.isVisible();
16455 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
16456 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
16457 * @param {String} value The data value of the item to select
16458 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
16459 * selected item if it is not currently in view (defaults to true)
16460 * @return {Boolean} True if the value matched an item in the list, else false
16462 selectByValue : function(v, scrollIntoView){
16463 if(v !== undefined && v !== null){
16464 var r = this.findRecord(this.valueField || this.displayField, v);
16466 this.select(this.store.indexOf(r), scrollIntoView);
16474 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
16475 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
16476 * @param {Number} index The zero-based index of the list item to select
16477 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
16478 * selected item if it is not currently in view (defaults to true)
16480 select : function(index, scrollIntoView){
16481 this.selectedIndex = index;
16482 this.view.select(index);
16483 if(scrollIntoView !== false){
16484 var el = this.view.getNode(index);
16486 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
16489 this.list.scrollChildIntoView(el, false);
16495 selectNext : function(){
16496 var ct = this.store.getCount();
16498 if(this.selectedIndex == -1){
16500 }else if(this.selectedIndex < ct-1){
16501 this.select(this.selectedIndex+1);
16507 selectPrev : function(){
16508 var ct = this.store.getCount();
16510 if(this.selectedIndex == -1){
16512 }else if(this.selectedIndex != 0){
16513 this.select(this.selectedIndex-1);
16519 onKeyUp : function(e){
16520 if(this.editable !== false && !e.isSpecialKey()){
16521 this.lastKey = e.getKey();
16522 this.dqTask.delay(this.queryDelay);
16527 validateBlur : function(){
16528 return !this.list || !this.list.isVisible();
16532 initQuery : function(){
16534 var v = this.getRawValue();
16536 if(this.tickable && this.editable){
16537 v = this.tickableInputEl().getValue();
16544 doForce : function(){
16545 if(this.inputEl().dom.value.length > 0){
16546 this.inputEl().dom.value =
16547 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
16553 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
16554 * query allowing the query action to be canceled if needed.
16555 * @param {String} query The SQL query to execute
16556 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
16557 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
16558 * saved in the current store (defaults to false)
16560 doQuery : function(q, forceAll){
16562 if(q === undefined || q === null){
16567 forceAll: forceAll,
16571 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
16576 forceAll = qe.forceAll;
16577 if(forceAll === true || (q.length >= this.minChars)){
16579 this.hasQuery = true;
16581 if(this.lastQuery != q || this.alwaysQuery){
16582 this.lastQuery = q;
16583 if(this.mode == 'local'){
16584 this.selectedIndex = -1;
16586 this.store.clearFilter();
16589 if(this.specialFilter){
16590 this.fireEvent('specialfilter', this);
16595 this.store.filter(this.displayField, q);
16598 this.store.fireEvent("datachanged", this.store);
16605 this.store.baseParams[this.queryParam] = q;
16607 var options = {params : this.getParams(q)};
16610 options.add = true;
16611 options.params.start = this.page * this.pageSize;
16614 this.store.load(options);
16617 * this code will make the page width larger, at the beginning, the list not align correctly,
16618 * we should expand the list on onLoad
16619 * so command out it
16624 this.selectedIndex = -1;
16629 this.loadNext = false;
16633 getParams : function(q){
16635 //p[this.queryParam] = q;
16639 p.limit = this.pageSize;
16645 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
16647 collapse : function(){
16648 if(!this.isExpanded()){
16654 this.hasFocus = false;
16658 this.cancelBtn.hide();
16659 this.trigger.show();
16662 this.tickableInputEl().dom.value = '';
16663 this.tickableInputEl().blur();
16668 Roo.get(document).un('mousedown', this.collapseIf, this);
16669 Roo.get(document).un('mousewheel', this.collapseIf, this);
16670 if (!this.editable) {
16671 Roo.get(document).un('keydown', this.listKeyPress, this);
16673 this.fireEvent('collapse', this);
16679 collapseIf : function(e){
16680 var in_combo = e.within(this.el);
16681 var in_list = e.within(this.list);
16682 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
16684 if (in_combo || in_list || is_list) {
16685 //e.stopPropagation();
16690 this.onTickableFooterButtonClick(e, false, false);
16698 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
16700 expand : function(){
16702 if(this.isExpanded() || !this.hasFocus){
16706 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
16707 this.list.setWidth(lw);
16713 this.restrictHeight();
16717 this.tickItems = Roo.apply([], this.item);
16720 this.cancelBtn.show();
16721 this.trigger.hide();
16724 this.tickableInputEl().focus();
16729 Roo.get(document).on('mousedown', this.collapseIf, this);
16730 Roo.get(document).on('mousewheel', this.collapseIf, this);
16731 if (!this.editable) {
16732 Roo.get(document).on('keydown', this.listKeyPress, this);
16735 this.fireEvent('expand', this);
16739 // Implements the default empty TriggerField.onTriggerClick function
16740 onTriggerClick : function(e)
16742 Roo.log('trigger click');
16744 if(this.disabled || !this.triggerList){
16749 this.loadNext = false;
16751 if(this.isExpanded()){
16753 if (!this.blockFocus) {
16754 this.inputEl().focus();
16758 this.hasFocus = true;
16759 if(this.triggerAction == 'all') {
16760 this.doQuery(this.allQuery, true);
16762 this.doQuery(this.getRawValue());
16764 if (!this.blockFocus) {
16765 this.inputEl().focus();
16770 onTickableTriggerClick : function(e)
16777 this.loadNext = false;
16778 this.hasFocus = true;
16780 if(this.triggerAction == 'all') {
16781 this.doQuery(this.allQuery, true);
16783 this.doQuery(this.getRawValue());
16787 onSearchFieldClick : function(e)
16789 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
16790 this.onTickableFooterButtonClick(e, false, false);
16794 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
16799 this.loadNext = false;
16800 this.hasFocus = true;
16802 if(this.triggerAction == 'all') {
16803 this.doQuery(this.allQuery, true);
16805 this.doQuery(this.getRawValue());
16809 listKeyPress : function(e)
16811 //Roo.log('listkeypress');
16812 // scroll to first matching element based on key pres..
16813 if (e.isSpecialKey()) {
16816 var k = String.fromCharCode(e.getKey()).toUpperCase();
16819 var csel = this.view.getSelectedNodes();
16820 var cselitem = false;
16822 var ix = this.view.indexOf(csel[0]);
16823 cselitem = this.store.getAt(ix);
16824 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
16830 this.store.each(function(v) {
16832 // start at existing selection.
16833 if (cselitem.id == v.id) {
16839 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
16840 match = this.store.indexOf(v);
16846 if (match === false) {
16847 return true; // no more action?
16850 this.view.select(match);
16851 var sn = Roo.get(this.view.getSelectedNodes()[0]);
16852 sn.scrollIntoView(sn.dom.parentNode, false);
16855 onViewScroll : function(e, t){
16857 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){
16861 this.hasQuery = true;
16863 this.loading = this.list.select('.loading', true).first();
16865 if(this.loading === null){
16866 this.list.createChild({
16868 cls: 'loading roo-select2-more-results roo-select2-active',
16869 html: 'Loading more results...'
16872 this.loading = this.list.select('.loading', true).first();
16874 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
16876 this.loading.hide();
16879 this.loading.show();
16884 this.loadNext = true;
16886 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
16891 addItem : function(o)
16893 var dv = ''; // display value
16895 if (this.displayField) {
16896 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
16898 // this is an error condition!!!
16899 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
16906 var choice = this.choices.createChild({
16908 cls: 'roo-select2-search-choice',
16917 cls: 'roo-select2-search-choice-close fa fa-times',
16922 }, this.searchField);
16924 var close = choice.select('a.roo-select2-search-choice-close', true).first();
16926 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
16934 this.inputEl().dom.value = '';
16939 onRemoveItem : function(e, _self, o)
16941 e.preventDefault();
16943 this.lastItem = Roo.apply([], this.item);
16945 var index = this.item.indexOf(o.data) * 1;
16948 Roo.log('not this item?!');
16952 this.item.splice(index, 1);
16957 this.fireEvent('remove', this, e);
16963 syncValue : function()
16965 if(!this.item.length){
16972 Roo.each(this.item, function(i){
16973 if(_this.valueField){
16974 value.push(i[_this.valueField]);
16981 this.value = value.join(',');
16983 if(this.hiddenField){
16984 this.hiddenField.dom.value = this.value;
16987 this.store.fireEvent("datachanged", this.store);
16992 clearItem : function()
16994 if(!this.multiple){
17000 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
17008 if(this.tickable && !Roo.isTouch){
17009 this.view.refresh();
17013 inputEl: function ()
17015 if(Roo.isIOS && this.useNativeIOS){
17016 return this.el.select('select.roo-ios-select', true).first();
17019 if(Roo.isTouch && this.mobileTouchView){
17020 return this.el.select('input.form-control',true).first();
17024 return this.searchField;
17027 return this.el.select('input.form-control',true).first();
17030 onTickableFooterButtonClick : function(e, btn, el)
17032 e.preventDefault();
17034 this.lastItem = Roo.apply([], this.item);
17036 if(btn && btn.name == 'cancel'){
17037 this.tickItems = Roo.apply([], this.item);
17046 Roo.each(this.tickItems, function(o){
17054 validate : function()
17056 if(this.getVisibilityEl().hasClass('hidden')){
17060 var v = this.getRawValue();
17063 v = this.getValue();
17066 if(this.disabled || this.allowBlank || v.length){
17071 this.markInvalid();
17075 tickableInputEl : function()
17077 if(!this.tickable || !this.editable){
17078 return this.inputEl();
17081 return this.inputEl().select('.roo-select2-search-field-input', true).first();
17085 getAutoCreateTouchView : function()
17090 cls: 'form-group' //input-group
17096 type : this.inputType,
17097 cls : 'form-control x-combo-noedit',
17098 autocomplete: 'new-password',
17099 placeholder : this.placeholder || '',
17104 input.name = this.name;
17108 input.cls += ' input-' + this.size;
17111 if (this.disabled) {
17112 input.disabled = true;
17116 cls : 'roo-combobox-wrap',
17123 inputblock.cls += ' input-group';
17125 inputblock.cn.unshift({
17127 cls : 'input-group-addon input-group-prepend input-group-text',
17132 if(this.removable && !this.multiple){
17133 inputblock.cls += ' roo-removable';
17135 inputblock.cn.push({
17138 cls : 'roo-combo-removable-btn close'
17142 if(this.hasFeedback && !this.allowBlank){
17144 inputblock.cls += ' has-feedback';
17146 inputblock.cn.push({
17148 cls: 'glyphicon form-control-feedback'
17155 inputblock.cls += (this.before) ? '' : ' input-group';
17157 inputblock.cn.push({
17159 cls : 'input-group-addon input-group-append input-group-text',
17165 var ibwrap = inputblock;
17170 cls: 'roo-select2-choices',
17174 cls: 'roo-select2-search-field',
17187 cls: 'roo-select2-container input-group roo-touchview-combobox ',
17192 cls: 'form-hidden-field'
17198 if(!this.multiple && this.showToggleBtn){
17204 if (this.caret != false) {
17207 cls: 'fa fa-' + this.caret
17214 cls : 'input-group-addon input-group-append input-group-text btn dropdown-toggle',
17216 Roo.bootstrap.version == 3 ? caret : '',
17219 cls: 'combobox-clear',
17233 combobox.cls += ' roo-select2-container-multi';
17236 var align = this.labelAlign || this.parentLabelAlign();
17238 if (align ==='left' && this.fieldLabel.length) {
17243 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
17244 tooltip : 'This field is required'
17248 cls : 'control-label col-form-label',
17249 html : this.fieldLabel
17253 cls : 'roo-combobox-wrap ',
17260 var labelCfg = cfg.cn[1];
17261 var contentCfg = cfg.cn[2];
17264 if(this.indicatorpos == 'right'){
17269 cls : 'control-label col-form-label',
17273 html : this.fieldLabel
17277 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
17278 tooltip : 'This field is required'
17283 cls : "roo-combobox-wrap ",
17291 labelCfg = cfg.cn[0];
17292 contentCfg = cfg.cn[1];
17297 if(this.labelWidth > 12){
17298 labelCfg.style = "width: " + this.labelWidth + 'px';
17301 if(this.labelWidth < 13 && this.labelmd == 0){
17302 this.labelmd = this.labelWidth;
17305 if(this.labellg > 0){
17306 labelCfg.cls += ' col-lg-' + this.labellg;
17307 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
17310 if(this.labelmd > 0){
17311 labelCfg.cls += ' col-md-' + this.labelmd;
17312 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
17315 if(this.labelsm > 0){
17316 labelCfg.cls += ' col-sm-' + this.labelsm;
17317 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
17320 if(this.labelxs > 0){
17321 labelCfg.cls += ' col-xs-' + this.labelxs;
17322 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
17326 } else if ( this.fieldLabel.length) {
17330 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
17331 tooltip : 'This field is required'
17335 cls : 'control-label',
17336 html : this.fieldLabel
17347 if(this.indicatorpos == 'right'){
17351 cls : 'control-label',
17352 html : this.fieldLabel,
17356 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
17357 tooltip : 'This field is required'
17374 var settings = this;
17376 ['xs','sm','md','lg'].map(function(size){
17377 if (settings[size]) {
17378 cfg.cls += ' col-' + size + '-' + settings[size];
17385 initTouchView : function()
17387 this.renderTouchView();
17389 this.touchViewEl.on('scroll', function(){
17390 this.el.dom.scrollTop = 0;
17393 this.originalValue = this.getValue();
17395 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
17397 this.inputEl().on("click", this.showTouchView, this);
17398 if (this.triggerEl) {
17399 this.triggerEl.on("click", this.showTouchView, this);
17403 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
17404 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
17406 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
17408 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
17409 this.store.on('load', this.onTouchViewLoad, this);
17410 this.store.on('loadexception', this.onTouchViewLoadException, this);
17412 if(this.hiddenName){
17414 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
17416 this.hiddenField.dom.value =
17417 this.hiddenValue !== undefined ? this.hiddenValue :
17418 this.value !== undefined ? this.value : '';
17420 this.el.dom.removeAttribute('name');
17421 this.hiddenField.dom.setAttribute('name', this.hiddenName);
17425 this.choices = this.el.select('ul.roo-select2-choices', true).first();
17426 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
17429 if(this.removable && !this.multiple){
17430 var close = this.closeTriggerEl();
17432 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
17433 close.on('click', this.removeBtnClick, this, close);
17437 * fix the bug in Safari iOS8
17439 this.inputEl().on("focus", function(e){
17440 document.activeElement.blur();
17443 this._touchViewMask = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
17450 renderTouchView : function()
17452 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
17453 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
17455 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
17456 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
17458 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
17459 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
17460 this.touchViewBodyEl.setStyle('overflow', 'auto');
17462 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
17463 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
17465 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
17466 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
17470 showTouchView : function()
17476 this.touchViewHeaderEl.hide();
17478 if(this.modalTitle.length){
17479 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
17480 this.touchViewHeaderEl.show();
17483 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
17484 this.touchViewEl.show();
17486 this.touchViewEl.select('.modal-dialog', true).first().setStyle({ margin : '0px', width : '100%'});
17488 //this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
17489 // Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
17491 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
17493 if(this.modalTitle.length){
17494 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
17497 this.touchViewBodyEl.setHeight(bodyHeight);
17501 (function(){ _this.touchViewEl.addClass(['in','show']); }).defer(50);
17503 this.touchViewEl.addClass(['in','show']);
17506 if(this._touchViewMask){
17507 Roo.get(document.body).addClass("x-body-masked");
17508 this._touchViewMask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
17509 this._touchViewMask.setStyle('z-index', 10000);
17510 this._touchViewMask.addClass('show');
17513 this.doTouchViewQuery();
17517 hideTouchView : function()
17519 this.touchViewEl.removeClass(['in','show']);
17523 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
17525 this.touchViewEl.setStyle('display', 'none');
17528 if(this._touchViewMask){
17529 this._touchViewMask.removeClass('show');
17530 Roo.get(document.body).removeClass("x-body-masked");
17534 setTouchViewValue : function()
17541 Roo.each(this.tickItems, function(o){
17546 this.hideTouchView();
17549 doTouchViewQuery : function()
17558 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
17562 if(!this.alwaysQuery || this.mode == 'local'){
17563 this.onTouchViewLoad();
17570 onTouchViewBeforeLoad : function(combo,opts)
17576 onTouchViewLoad : function()
17578 if(this.store.getCount() < 1){
17579 this.onTouchViewEmptyResults();
17583 this.clearTouchView();
17585 var rawValue = this.getRawValue();
17587 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
17589 this.tickItems = [];
17591 this.store.data.each(function(d, rowIndex){
17592 var row = this.touchViewListGroup.createChild(template);
17594 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
17595 row.addClass(d.data.cls);
17598 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
17601 html : d.data[this.displayField]
17604 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
17605 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
17608 row.removeClass('selected');
17609 if(!this.multiple && this.valueField &&
17610 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
17613 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
17614 row.addClass('selected');
17617 if(this.multiple && this.valueField &&
17618 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
17622 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
17623 this.tickItems.push(d.data);
17626 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
17630 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
17632 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
17634 if(this.modalTitle.length){
17635 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
17638 var listHeight = this.touchViewListGroup.getHeight() + this.touchViewBodyEl.getPadding('tb') * 2;
17640 if(this.mobile_restrict_height && listHeight < bodyHeight){
17641 this.touchViewBodyEl.setHeight(listHeight);
17646 if(firstChecked && listHeight > bodyHeight){
17647 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
17652 onTouchViewLoadException : function()
17654 this.hideTouchView();
17657 onTouchViewEmptyResults : function()
17659 this.clearTouchView();
17661 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
17663 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
17667 clearTouchView : function()
17669 this.touchViewListGroup.dom.innerHTML = '';
17672 onTouchViewClick : function(e, el, o)
17674 e.preventDefault();
17677 var rowIndex = o.rowIndex;
17679 var r = this.store.getAt(rowIndex);
17681 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
17683 if(!this.multiple){
17684 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
17685 c.dom.removeAttribute('checked');
17688 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
17690 this.setFromData(r.data);
17692 var close = this.closeTriggerEl();
17698 this.hideTouchView();
17700 this.fireEvent('select', this, r, rowIndex);
17705 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
17706 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
17707 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
17711 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
17712 this.addItem(r.data);
17713 this.tickItems.push(r.data);
17717 getAutoCreateNativeIOS : function()
17720 cls: 'form-group' //input-group,
17725 cls : 'roo-ios-select'
17729 combobox.name = this.name;
17732 if (this.disabled) {
17733 combobox.disabled = true;
17736 var settings = this;
17738 ['xs','sm','md','lg'].map(function(size){
17739 if (settings[size]) {
17740 cfg.cls += ' col-' + size + '-' + settings[size];
17750 initIOSView : function()
17752 this.store.on('load', this.onIOSViewLoad, this);
17757 onIOSViewLoad : function()
17759 if(this.store.getCount() < 1){
17763 this.clearIOSView();
17765 if(this.allowBlank) {
17767 var default_text = '-- SELECT --';
17769 if(this.placeholder.length){
17770 default_text = this.placeholder;
17773 if(this.emptyTitle.length){
17774 default_text += ' - ' + this.emptyTitle + ' -';
17777 var opt = this.inputEl().createChild({
17780 html : default_text
17784 o[this.valueField] = 0;
17785 o[this.displayField] = default_text;
17787 this.ios_options.push({
17794 this.store.data.each(function(d, rowIndex){
17798 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
17799 html = d.data[this.displayField];
17804 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
17805 value = d.data[this.valueField];
17814 if(this.value == d.data[this.valueField]){
17815 option['selected'] = true;
17818 var opt = this.inputEl().createChild(option);
17820 this.ios_options.push({
17827 this.inputEl().on('change', function(){
17828 this.fireEvent('select', this);
17833 clearIOSView: function()
17835 this.inputEl().dom.innerHTML = '';
17837 this.ios_options = [];
17840 setIOSValue: function(v)
17844 if(!this.ios_options){
17848 Roo.each(this.ios_options, function(opts){
17850 opts.el.dom.removeAttribute('selected');
17852 if(opts.data[this.valueField] != v){
17856 opts.el.dom.setAttribute('selected', true);
17862 * @cfg {Boolean} grow
17866 * @cfg {Number} growMin
17870 * @cfg {Number} growMax
17879 Roo.apply(Roo.bootstrap.ComboBox, {
17883 cls: 'modal-header',
17905 cls: 'list-group-item',
17909 cls: 'roo-combobox-list-group-item-value'
17913 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
17927 listItemCheckbox : {
17929 cls: 'list-group-item',
17933 cls: 'roo-combobox-list-group-item-value'
17937 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
17953 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
17958 cls: 'modal-footer',
17966 cls: 'col-xs-6 text-left',
17969 cls: 'btn btn-danger roo-touch-view-cancel',
17975 cls: 'col-xs-6 text-right',
17978 cls: 'btn btn-success roo-touch-view-ok',
17989 Roo.apply(Roo.bootstrap.ComboBox, {
17991 touchViewTemplate : {
17993 cls: 'modal fade roo-combobox-touch-view',
17997 cls: 'modal-dialog',
17998 style : 'position:fixed', // we have to fix position....
18002 cls: 'modal-content',
18004 Roo.bootstrap.ComboBox.header,
18005 Roo.bootstrap.ComboBox.body,
18006 Roo.bootstrap.ComboBox.footer
18015 * Ext JS Library 1.1.1
18016 * Copyright(c) 2006-2007, Ext JS, LLC.
18018 * Originally Released Under LGPL - original licence link has changed is not relivant.
18021 * <script type="text/javascript">
18026 * @extends Roo.util.Observable
18027 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
18028 * This class also supports single and multi selection modes. <br>
18029 * Create a data model bound view:
18031 var store = new Roo.data.Store(...);
18033 var view = new Roo.View({
18035 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
18037 singleSelect: true,
18038 selectedClass: "ydataview-selected",
18042 // listen for node click?
18043 view.on("click", function(vw, index, node, e){
18044 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
18048 dataModel.load("foobar.xml");
18050 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
18052 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
18053 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
18055 * Note: old style constructor is still suported (container, template, config)
18058 * Create a new View
18059 * @param {Object} config The config object
18062 Roo.View = function(config, depreciated_tpl, depreciated_config){
18064 this.parent = false;
18066 if (typeof(depreciated_tpl) == 'undefined') {
18067 // new way.. - universal constructor.
18068 Roo.apply(this, config);
18069 this.el = Roo.get(this.el);
18072 this.el = Roo.get(config);
18073 this.tpl = depreciated_tpl;
18074 Roo.apply(this, depreciated_config);
18076 this.wrapEl = this.el.wrap().wrap();
18077 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
18080 if(typeof(this.tpl) == "string"){
18081 this.tpl = new Roo.Template(this.tpl);
18083 // support xtype ctors..
18084 this.tpl = new Roo.factory(this.tpl, Roo);
18088 this.tpl.compile();
18093 * @event beforeclick
18094 * Fires before a click is processed. Returns false to cancel the default action.
18095 * @param {Roo.View} this
18096 * @param {Number} index The index of the target node
18097 * @param {HTMLElement} node The target node
18098 * @param {Roo.EventObject} e The raw event object
18100 "beforeclick" : true,
18103 * Fires when a template node is clicked.
18104 * @param {Roo.View} this
18105 * @param {Number} index The index of the target node
18106 * @param {HTMLElement} node The target node
18107 * @param {Roo.EventObject} e The raw event object
18112 * Fires when a template node is double clicked.
18113 * @param {Roo.View} this
18114 * @param {Number} index The index of the target node
18115 * @param {HTMLElement} node The target node
18116 * @param {Roo.EventObject} e The raw event object
18120 * @event contextmenu
18121 * Fires when a template node is right clicked.
18122 * @param {Roo.View} this
18123 * @param {Number} index The index of the target node
18124 * @param {HTMLElement} node The target node
18125 * @param {Roo.EventObject} e The raw event object
18127 "contextmenu" : true,
18129 * @event selectionchange
18130 * Fires when the selected nodes change.
18131 * @param {Roo.View} this
18132 * @param {Array} selections Array of the selected nodes
18134 "selectionchange" : true,
18137 * @event beforeselect
18138 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
18139 * @param {Roo.View} this
18140 * @param {HTMLElement} node The node to be selected
18141 * @param {Array} selections Array of currently selected nodes
18143 "beforeselect" : true,
18145 * @event preparedata
18146 * Fires on every row to render, to allow you to change the data.
18147 * @param {Roo.View} this
18148 * @param {Object} data to be rendered (change this)
18150 "preparedata" : true
18158 "click": this.onClick,
18159 "dblclick": this.onDblClick,
18160 "contextmenu": this.onContextMenu,
18164 this.selections = [];
18166 this.cmp = new Roo.CompositeElementLite([]);
18168 this.store = Roo.factory(this.store, Roo.data);
18169 this.setStore(this.store, true);
18172 if ( this.footer && this.footer.xtype) {
18174 var fctr = this.wrapEl.appendChild(document.createElement("div"));
18176 this.footer.dataSource = this.store;
18177 this.footer.container = fctr;
18178 this.footer = Roo.factory(this.footer, Roo);
18179 fctr.insertFirst(this.el);
18181 // this is a bit insane - as the paging toolbar seems to detach the el..
18182 // dom.parentNode.parentNode.parentNode
18183 // they get detached?
18187 Roo.View.superclass.constructor.call(this);
18192 Roo.extend(Roo.View, Roo.util.Observable, {
18195 * @cfg {Roo.data.Store} store Data store to load data from.
18200 * @cfg {String|Roo.Element} el The container element.
18205 * @cfg {String|Roo.Template} tpl The template used by this View
18209 * @cfg {String} dataName the named area of the template to use as the data area
18210 * Works with domtemplates roo-name="name"
18214 * @cfg {String} selectedClass The css class to add to selected nodes
18216 selectedClass : "x-view-selected",
18218 * @cfg {String} emptyText The empty text to show when nothing is loaded.
18223 * @cfg {String} text to display on mask (default Loading)
18227 * @cfg {Boolean} multiSelect Allow multiple selection
18229 multiSelect : false,
18231 * @cfg {Boolean} singleSelect Allow single selection
18233 singleSelect: false,
18236 * @cfg {Boolean} toggleSelect - selecting
18238 toggleSelect : false,
18241 * @cfg {Boolean} tickable - selecting
18246 * Returns the element this view is bound to.
18247 * @return {Roo.Element}
18249 getEl : function(){
18250 return this.wrapEl;
18256 * Refreshes the view. - called by datachanged on the store. - do not call directly.
18258 refresh : function(){
18259 //Roo.log('refresh');
18262 // if we are using something like 'domtemplate', then
18263 // the what gets used is:
18264 // t.applySubtemplate(NAME, data, wrapping data..)
18265 // the outer template then get' applied with
18266 // the store 'extra data'
18267 // and the body get's added to the
18268 // roo-name="data" node?
18269 // <span class='roo-tpl-{name}'></span> ?????
18273 this.clearSelections();
18274 this.el.update("");
18276 var records = this.store.getRange();
18277 if(records.length < 1) {
18279 // is this valid?? = should it render a template??
18281 this.el.update(this.emptyText);
18285 if (this.dataName) {
18286 this.el.update(t.apply(this.store.meta)); //????
18287 el = this.el.child('.roo-tpl-' + this.dataName);
18290 for(var i = 0, len = records.length; i < len; i++){
18291 var data = this.prepareData(records[i].data, i, records[i]);
18292 this.fireEvent("preparedata", this, data, i, records[i]);
18294 var d = Roo.apply({}, data);
18297 Roo.apply(d, {'roo-id' : Roo.id()});
18301 Roo.each(this.parent.item, function(item){
18302 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
18305 Roo.apply(d, {'roo-data-checked' : 'checked'});
18309 html[html.length] = Roo.util.Format.trim(
18311 t.applySubtemplate(this.dataName, d, this.store.meta) :
18318 el.update(html.join(""));
18319 this.nodes = el.dom.childNodes;
18320 this.updateIndexes(0);
18325 * Function to override to reformat the data that is sent to
18326 * the template for each node.
18327 * DEPRICATED - use the preparedata event handler.
18328 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
18329 * a JSON object for an UpdateManager bound view).
18331 prepareData : function(data, index, record)
18333 this.fireEvent("preparedata", this, data, index, record);
18337 onUpdate : function(ds, record){
18338 // Roo.log('on update');
18339 this.clearSelections();
18340 var index = this.store.indexOf(record);
18341 var n = this.nodes[index];
18342 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
18343 n.parentNode.removeChild(n);
18344 this.updateIndexes(index, index);
18350 onAdd : function(ds, records, index)
18352 //Roo.log(['on Add', ds, records, index] );
18353 this.clearSelections();
18354 if(this.nodes.length == 0){
18358 var n = this.nodes[index];
18359 for(var i = 0, len = records.length; i < len; i++){
18360 var d = this.prepareData(records[i].data, i, records[i]);
18362 this.tpl.insertBefore(n, d);
18365 this.tpl.append(this.el, d);
18368 this.updateIndexes(index);
18371 onRemove : function(ds, record, index){
18372 // Roo.log('onRemove');
18373 this.clearSelections();
18374 var el = this.dataName ?
18375 this.el.child('.roo-tpl-' + this.dataName) :
18378 el.dom.removeChild(this.nodes[index]);
18379 this.updateIndexes(index);
18383 * Refresh an individual node.
18384 * @param {Number} index
18386 refreshNode : function(index){
18387 this.onUpdate(this.store, this.store.getAt(index));
18390 updateIndexes : function(startIndex, endIndex){
18391 var ns = this.nodes;
18392 startIndex = startIndex || 0;
18393 endIndex = endIndex || ns.length - 1;
18394 for(var i = startIndex; i <= endIndex; i++){
18395 ns[i].nodeIndex = i;
18400 * Changes the data store this view uses and refresh the view.
18401 * @param {Store} store
18403 setStore : function(store, initial){
18404 if(!initial && this.store){
18405 this.store.un("datachanged", this.refresh);
18406 this.store.un("add", this.onAdd);
18407 this.store.un("remove", this.onRemove);
18408 this.store.un("update", this.onUpdate);
18409 this.store.un("clear", this.refresh);
18410 this.store.un("beforeload", this.onBeforeLoad);
18411 this.store.un("load", this.onLoad);
18412 this.store.un("loadexception", this.onLoad);
18416 store.on("datachanged", this.refresh, this);
18417 store.on("add", this.onAdd, this);
18418 store.on("remove", this.onRemove, this);
18419 store.on("update", this.onUpdate, this);
18420 store.on("clear", this.refresh, this);
18421 store.on("beforeload", this.onBeforeLoad, this);
18422 store.on("load", this.onLoad, this);
18423 store.on("loadexception", this.onLoad, this);
18431 * onbeforeLoad - masks the loading area.
18434 onBeforeLoad : function(store,opts)
18436 //Roo.log('onBeforeLoad');
18438 this.el.update("");
18440 this.el.mask(this.mask ? this.mask : "Loading" );
18442 onLoad : function ()
18449 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
18450 * @param {HTMLElement} node
18451 * @return {HTMLElement} The template node
18453 findItemFromChild : function(node){
18454 var el = this.dataName ?
18455 this.el.child('.roo-tpl-' + this.dataName,true) :
18458 if(!node || node.parentNode == el){
18461 var p = node.parentNode;
18462 while(p && p != el){
18463 if(p.parentNode == el){
18472 onClick : function(e){
18473 var item = this.findItemFromChild(e.getTarget());
18475 var index = this.indexOf(item);
18476 if(this.onItemClick(item, index, e) !== false){
18477 this.fireEvent("click", this, index, item, e);
18480 this.clearSelections();
18485 onContextMenu : function(e){
18486 var item = this.findItemFromChild(e.getTarget());
18488 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
18493 onDblClick : function(e){
18494 var item = this.findItemFromChild(e.getTarget());
18496 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
18500 onItemClick : function(item, index, e)
18502 if(this.fireEvent("beforeclick", this, index, item, e) === false){
18505 if (this.toggleSelect) {
18506 var m = this.isSelected(item) ? 'unselect' : 'select';
18509 _t[m](item, true, false);
18512 if(this.multiSelect || this.singleSelect){
18513 if(this.multiSelect && e.shiftKey && this.lastSelection){
18514 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
18516 this.select(item, this.multiSelect && e.ctrlKey);
18517 this.lastSelection = item;
18520 if(!this.tickable){
18521 e.preventDefault();
18529 * Get the number of selected nodes.
18532 getSelectionCount : function(){
18533 return this.selections.length;
18537 * Get the currently selected nodes.
18538 * @return {Array} An array of HTMLElements
18540 getSelectedNodes : function(){
18541 return this.selections;
18545 * Get the indexes of the selected nodes.
18548 getSelectedIndexes : function(){
18549 var indexes = [], s = this.selections;
18550 for(var i = 0, len = s.length; i < len; i++){
18551 indexes.push(s[i].nodeIndex);
18557 * Clear all selections
18558 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
18560 clearSelections : function(suppressEvent){
18561 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
18562 this.cmp.elements = this.selections;
18563 this.cmp.removeClass(this.selectedClass);
18564 this.selections = [];
18565 if(!suppressEvent){
18566 this.fireEvent("selectionchange", this, this.selections);
18572 * Returns true if the passed node is selected
18573 * @param {HTMLElement/Number} node The node or node index
18574 * @return {Boolean}
18576 isSelected : function(node){
18577 var s = this.selections;
18581 node = this.getNode(node);
18582 return s.indexOf(node) !== -1;
18587 * @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
18588 * @param {Boolean} keepExisting (optional) true to keep existing selections
18589 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
18591 select : function(nodeInfo, keepExisting, suppressEvent){
18592 if(nodeInfo instanceof Array){
18594 this.clearSelections(true);
18596 for(var i = 0, len = nodeInfo.length; i < len; i++){
18597 this.select(nodeInfo[i], true, true);
18601 var node = this.getNode(nodeInfo);
18602 if(!node || this.isSelected(node)){
18603 return; // already selected.
18606 this.clearSelections(true);
18609 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
18610 Roo.fly(node).addClass(this.selectedClass);
18611 this.selections.push(node);
18612 if(!suppressEvent){
18613 this.fireEvent("selectionchange", this, this.selections);
18621 * @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
18622 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
18623 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
18625 unselect : function(nodeInfo, keepExisting, suppressEvent)
18627 if(nodeInfo instanceof Array){
18628 Roo.each(this.selections, function(s) {
18629 this.unselect(s, nodeInfo);
18633 var node = this.getNode(nodeInfo);
18634 if(!node || !this.isSelected(node)){
18635 //Roo.log("not selected");
18636 return; // not selected.
18640 Roo.each(this.selections, function(s) {
18642 Roo.fly(node).removeClass(this.selectedClass);
18649 this.selections= ns;
18650 this.fireEvent("selectionchange", this, this.selections);
18654 * Gets a template node.
18655 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
18656 * @return {HTMLElement} The node or null if it wasn't found
18658 getNode : function(nodeInfo){
18659 if(typeof nodeInfo == "string"){
18660 return document.getElementById(nodeInfo);
18661 }else if(typeof nodeInfo == "number"){
18662 return this.nodes[nodeInfo];
18668 * Gets a range template nodes.
18669 * @param {Number} startIndex
18670 * @param {Number} endIndex
18671 * @return {Array} An array of nodes
18673 getNodes : function(start, end){
18674 var ns = this.nodes;
18675 start = start || 0;
18676 end = typeof end == "undefined" ? ns.length - 1 : end;
18679 for(var i = start; i <= end; i++){
18683 for(var i = start; i >= end; i--){
18691 * Finds the index of the passed node
18692 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
18693 * @return {Number} The index of the node or -1
18695 indexOf : function(node){
18696 node = this.getNode(node);
18697 if(typeof node.nodeIndex == "number"){
18698 return node.nodeIndex;
18700 var ns = this.nodes;
18701 for(var i = 0, len = ns.length; i < len; i++){
18712 * based on jquery fullcalendar
18716 Roo.bootstrap = Roo.bootstrap || {};
18718 * @class Roo.bootstrap.Calendar
18719 * @extends Roo.bootstrap.Component
18720 * Bootstrap Calendar class
18721 * @cfg {Boolean} loadMask (true|false) default false
18722 * @cfg {Object} header generate the user specific header of the calendar, default false
18725 * Create a new Container
18726 * @param {Object} config The config object
18731 Roo.bootstrap.Calendar = function(config){
18732 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
18736 * Fires when a date is selected
18737 * @param {DatePicker} this
18738 * @param {Date} date The selected date
18742 * @event monthchange
18743 * Fires when the displayed month changes
18744 * @param {DatePicker} this
18745 * @param {Date} date The selected month
18747 'monthchange': true,
18749 * @event evententer
18750 * Fires when mouse over an event
18751 * @param {Calendar} this
18752 * @param {event} Event
18754 'evententer': true,
18756 * @event eventleave
18757 * Fires when the mouse leaves an
18758 * @param {Calendar} this
18761 'eventleave': true,
18763 * @event eventclick
18764 * Fires when the mouse click an
18765 * @param {Calendar} this
18774 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
18777 * @cfg {Number} startDay
18778 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
18786 getAutoCreate : function(){
18789 var fc_button = function(name, corner, style, content ) {
18790 return Roo.apply({},{
18792 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
18794 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
18797 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
18808 style : 'width:100%',
18815 cls : 'fc-header-left',
18817 fc_button('prev', 'left', 'arrow', '‹' ),
18818 fc_button('next', 'right', 'arrow', '›' ),
18819 { tag: 'span', cls: 'fc-header-space' },
18820 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
18828 cls : 'fc-header-center',
18832 cls: 'fc-header-title',
18835 html : 'month / year'
18843 cls : 'fc-header-right',
18845 /* fc_button('month', 'left', '', 'month' ),
18846 fc_button('week', '', '', 'week' ),
18847 fc_button('day', 'right', '', 'day' )
18859 header = this.header;
18862 var cal_heads = function() {
18864 // fixme - handle this.
18866 for (var i =0; i < Date.dayNames.length; i++) {
18867 var d = Date.dayNames[i];
18870 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
18871 html : d.substring(0,3)
18875 ret[0].cls += ' fc-first';
18876 ret[6].cls += ' fc-last';
18879 var cal_cell = function(n) {
18882 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
18887 cls: 'fc-day-number',
18891 cls: 'fc-day-content',
18895 style: 'position: relative;' // height: 17px;
18907 var cal_rows = function() {
18910 for (var r = 0; r < 6; r++) {
18917 for (var i =0; i < Date.dayNames.length; i++) {
18918 var d = Date.dayNames[i];
18919 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
18922 row.cn[0].cls+=' fc-first';
18923 row.cn[0].cn[0].style = 'min-height:90px';
18924 row.cn[6].cls+=' fc-last';
18928 ret[0].cls += ' fc-first';
18929 ret[4].cls += ' fc-prev-last';
18930 ret[5].cls += ' fc-last';
18937 cls: 'fc-border-separate',
18938 style : 'width:100%',
18946 cls : 'fc-first fc-last',
18964 cls : 'fc-content',
18965 style : "position: relative;",
18968 cls : 'fc-view fc-view-month fc-grid',
18969 style : 'position: relative',
18970 unselectable : 'on',
18973 cls : 'fc-event-container',
18974 style : 'position:absolute;z-index:8;top:0;left:0;'
18992 initEvents : function()
18995 throw "can not find store for calendar";
19001 style: "text-align:center",
19005 style: "background-color:white;width:50%;margin:250 auto",
19009 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
19020 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
19022 var size = this.el.select('.fc-content', true).first().getSize();
19023 this.maskEl.setSize(size.width, size.height);
19024 this.maskEl.enableDisplayMode("block");
19025 if(!this.loadMask){
19026 this.maskEl.hide();
19029 this.store = Roo.factory(this.store, Roo.data);
19030 this.store.on('load', this.onLoad, this);
19031 this.store.on('beforeload', this.onBeforeLoad, this);
19035 this.cells = this.el.select('.fc-day',true);
19036 //Roo.log(this.cells);
19037 this.textNodes = this.el.query('.fc-day-number');
19038 this.cells.addClassOnOver('fc-state-hover');
19040 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
19041 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
19042 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
19043 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
19045 this.on('monthchange', this.onMonthChange, this);
19047 this.update(new Date().clearTime());
19050 resize : function() {
19051 var sz = this.el.getSize();
19053 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
19054 this.el.select('.fc-day-content div',true).setHeight(34);
19059 showPrevMonth : function(e){
19060 this.update(this.activeDate.add("mo", -1));
19062 showToday : function(e){
19063 this.update(new Date().clearTime());
19066 showNextMonth : function(e){
19067 this.update(this.activeDate.add("mo", 1));
19071 showPrevYear : function(){
19072 this.update(this.activeDate.add("y", -1));
19076 showNextYear : function(){
19077 this.update(this.activeDate.add("y", 1));
19082 update : function(date)
19084 var vd = this.activeDate;
19085 this.activeDate = date;
19086 // if(vd && this.el){
19087 // var t = date.getTime();
19088 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
19089 // Roo.log('using add remove');
19091 // this.fireEvent('monthchange', this, date);
19093 // this.cells.removeClass("fc-state-highlight");
19094 // this.cells.each(function(c){
19095 // if(c.dateValue == t){
19096 // c.addClass("fc-state-highlight");
19097 // setTimeout(function(){
19098 // try{c.dom.firstChild.focus();}catch(e){}
19108 var days = date.getDaysInMonth();
19110 var firstOfMonth = date.getFirstDateOfMonth();
19111 var startingPos = firstOfMonth.getDay()-this.startDay;
19113 if(startingPos < this.startDay){
19117 var pm = date.add(Date.MONTH, -1);
19118 var prevStart = pm.getDaysInMonth()-startingPos;
19120 this.cells = this.el.select('.fc-day',true);
19121 this.textNodes = this.el.query('.fc-day-number');
19122 this.cells.addClassOnOver('fc-state-hover');
19124 var cells = this.cells.elements;
19125 var textEls = this.textNodes;
19127 Roo.each(cells, function(cell){
19128 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
19131 days += startingPos;
19133 // convert everything to numbers so it's fast
19134 var day = 86400000;
19135 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
19138 //Roo.log(prevStart);
19140 var today = new Date().clearTime().getTime();
19141 var sel = date.clearTime().getTime();
19142 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
19143 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
19144 var ddMatch = this.disabledDatesRE;
19145 var ddText = this.disabledDatesText;
19146 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
19147 var ddaysText = this.disabledDaysText;
19148 var format = this.format;
19150 var setCellClass = function(cal, cell){
19154 //Roo.log('set Cell Class');
19156 var t = d.getTime();
19160 cell.dateValue = t;
19162 cell.className += " fc-today";
19163 cell.className += " fc-state-highlight";
19164 cell.title = cal.todayText;
19167 // disable highlight in other month..
19168 //cell.className += " fc-state-highlight";
19173 cell.className = " fc-state-disabled";
19174 cell.title = cal.minText;
19178 cell.className = " fc-state-disabled";
19179 cell.title = cal.maxText;
19183 if(ddays.indexOf(d.getDay()) != -1){
19184 cell.title = ddaysText;
19185 cell.className = " fc-state-disabled";
19188 if(ddMatch && format){
19189 var fvalue = d.dateFormat(format);
19190 if(ddMatch.test(fvalue)){
19191 cell.title = ddText.replace("%0", fvalue);
19192 cell.className = " fc-state-disabled";
19196 if (!cell.initialClassName) {
19197 cell.initialClassName = cell.dom.className;
19200 cell.dom.className = cell.initialClassName + ' ' + cell.className;
19205 for(; i < startingPos; i++) {
19206 textEls[i].innerHTML = (++prevStart);
19207 d.setDate(d.getDate()+1);
19209 cells[i].className = "fc-past fc-other-month";
19210 setCellClass(this, cells[i]);
19215 for(; i < days; i++){
19216 intDay = i - startingPos + 1;
19217 textEls[i].innerHTML = (intDay);
19218 d.setDate(d.getDate()+1);
19220 cells[i].className = ''; // "x-date-active";
19221 setCellClass(this, cells[i]);
19225 for(; i < 42; i++) {
19226 textEls[i].innerHTML = (++extraDays);
19227 d.setDate(d.getDate()+1);
19229 cells[i].className = "fc-future fc-other-month";
19230 setCellClass(this, cells[i]);
19233 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
19235 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
19237 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
19238 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
19240 if(totalRows != 6){
19241 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
19242 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
19245 this.fireEvent('monthchange', this, date);
19249 if(!this.internalRender){
19250 var main = this.el.dom.firstChild;
19251 var w = main.offsetWidth;
19252 this.el.setWidth(w + this.el.getBorderWidth("lr"));
19253 Roo.fly(main).setWidth(w);
19254 this.internalRender = true;
19255 // opera does not respect the auto grow header center column
19256 // then, after it gets a width opera refuses to recalculate
19257 // without a second pass
19258 if(Roo.isOpera && !this.secondPass){
19259 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
19260 this.secondPass = true;
19261 this.update.defer(10, this, [date]);
19268 findCell : function(dt) {
19269 dt = dt.clearTime().getTime();
19271 this.cells.each(function(c){
19272 //Roo.log("check " +c.dateValue + '?=' + dt);
19273 if(c.dateValue == dt){
19283 findCells : function(ev) {
19284 var s = ev.start.clone().clearTime().getTime();
19286 var e= ev.end.clone().clearTime().getTime();
19289 this.cells.each(function(c){
19290 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
19292 if(c.dateValue > e){
19295 if(c.dateValue < s){
19304 // findBestRow: function(cells)
19308 // for (var i =0 ; i < cells.length;i++) {
19309 // ret = Math.max(cells[i].rows || 0,ret);
19316 addItem : function(ev)
19318 // look for vertical location slot in
19319 var cells = this.findCells(ev);
19321 // ev.row = this.findBestRow(cells);
19323 // work out the location.
19327 for(var i =0; i < cells.length; i++) {
19329 cells[i].row = cells[0].row;
19332 cells[i].row = cells[i].row + 1;
19342 if (crow.start.getY() == cells[i].getY()) {
19344 crow.end = cells[i];
19361 cells[0].events.push(ev);
19363 this.calevents.push(ev);
19366 clearEvents: function() {
19368 if(!this.calevents){
19372 Roo.each(this.cells.elements, function(c){
19378 Roo.each(this.calevents, function(e) {
19379 Roo.each(e.els, function(el) {
19380 el.un('mouseenter' ,this.onEventEnter, this);
19381 el.un('mouseleave' ,this.onEventLeave, this);
19386 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
19392 renderEvents: function()
19396 this.cells.each(function(c) {
19405 if(c.row != c.events.length){
19406 r = 4 - (4 - (c.row - c.events.length));
19409 c.events = ev.slice(0, r);
19410 c.more = ev.slice(r);
19412 if(c.more.length && c.more.length == 1){
19413 c.events.push(c.more.pop());
19416 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
19420 this.cells.each(function(c) {
19422 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
19425 for (var e = 0; e < c.events.length; e++){
19426 var ev = c.events[e];
19427 var rows = ev.rows;
19429 for(var i = 0; i < rows.length; i++) {
19431 // how many rows should it span..
19434 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
19435 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
19437 unselectable : "on",
19440 cls: 'fc-event-inner',
19444 // cls: 'fc-event-time',
19445 // html : cells.length > 1 ? '' : ev.time
19449 cls: 'fc-event-title',
19450 html : String.format('{0}', ev.title)
19457 cls: 'ui-resizable-handle ui-resizable-e',
19458 html : '  '
19465 cfg.cls += ' fc-event-start';
19467 if ((i+1) == rows.length) {
19468 cfg.cls += ' fc-event-end';
19471 var ctr = _this.el.select('.fc-event-container',true).first();
19472 var cg = ctr.createChild(cfg);
19474 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
19475 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
19477 var r = (c.more.length) ? 1 : 0;
19478 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
19479 cg.setWidth(ebox.right - sbox.x -2);
19481 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
19482 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
19483 cg.on('click', _this.onEventClick, _this, ev);
19494 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
19495 style : 'position: absolute',
19496 unselectable : "on",
19499 cls: 'fc-event-inner',
19503 cls: 'fc-event-title',
19511 cls: 'ui-resizable-handle ui-resizable-e',
19512 html : '  '
19518 var ctr = _this.el.select('.fc-event-container',true).first();
19519 var cg = ctr.createChild(cfg);
19521 var sbox = c.select('.fc-day-content',true).first().getBox();
19522 var ebox = c.select('.fc-day-content',true).first().getBox();
19524 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
19525 cg.setWidth(ebox.right - sbox.x -2);
19527 cg.on('click', _this.onMoreEventClick, _this, c.more);
19537 onEventEnter: function (e, el,event,d) {
19538 this.fireEvent('evententer', this, el, event);
19541 onEventLeave: function (e, el,event,d) {
19542 this.fireEvent('eventleave', this, el, event);
19545 onEventClick: function (e, el,event,d) {
19546 this.fireEvent('eventclick', this, el, event);
19549 onMonthChange: function () {
19553 onMoreEventClick: function(e, el, more)
19557 this.calpopover.placement = 'right';
19558 this.calpopover.setTitle('More');
19560 this.calpopover.setContent('');
19562 var ctr = this.calpopover.el.select('.popover-content', true).first();
19564 Roo.each(more, function(m){
19566 cls : 'fc-event-hori fc-event-draggable',
19569 var cg = ctr.createChild(cfg);
19571 cg.on('click', _this.onEventClick, _this, m);
19574 this.calpopover.show(el);
19579 onLoad: function ()
19581 this.calevents = [];
19584 if(this.store.getCount() > 0){
19585 this.store.data.each(function(d){
19588 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
19589 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
19590 time : d.data.start_time,
19591 title : d.data.title,
19592 description : d.data.description,
19593 venue : d.data.venue
19598 this.renderEvents();
19600 if(this.calevents.length && this.loadMask){
19601 this.maskEl.hide();
19605 onBeforeLoad: function()
19607 this.clearEvents();
19609 this.maskEl.show();
19623 * @class Roo.bootstrap.Popover
19624 * @extends Roo.bootstrap.Component
19625 * Bootstrap Popover class
19626 * @cfg {String} html contents of the popover (or false to use children..)
19627 * @cfg {String} title of popover (or false to hide)
19628 * @cfg {String|function} (right|top|bottom|left|auto) placement how it is placed
19629 * @cfg {String} trigger click || hover (or false to trigger manually)
19630 * @cfg {Boolean} modal - popovers that are modal will mask the screen, and must be closed with another event.
19631 * @cfg {String|Boolean|Roo.Element} add click hander to trigger show over what element
19632 * - if false and it has a 'parent' then it will be automatically added to that element
19633 * - if string - Roo.get will be called
19634 * @cfg {Number} delay - delay before showing
19637 * Create a new Popover
19638 * @param {Object} config The config object
19641 Roo.bootstrap.Popover = function(config){
19642 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
19648 * After the popover show
19650 * @param {Roo.bootstrap.Popover} this
19655 * After the popover hide
19657 * @param {Roo.bootstrap.Popover} this
19663 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
19668 placement : 'right',
19669 trigger : 'hover', // hover
19675 can_build_overlaid : false,
19677 maskEl : false, // the mask element
19680 alignEl : false, // when show is called with an element - this get's stored.
19682 getChildContainer : function()
19684 return this.contentEl;
19687 getPopoverHeader : function()
19689 this.title = true; // flag not to hide it..
19690 this.headerEl.addClass('p-0');
19691 return this.headerEl
19695 getAutoCreate : function(){
19698 cls : 'popover roo-dynamic shadow roo-popover' + (this.modal ? '-modal' : ''),
19699 style: 'display:block',
19705 cls : 'popover-inner ',
19709 cls: 'popover-title popover-header',
19710 html : this.title === false ? '' : this.title
19713 cls : 'popover-content popover-body ' + (this.cls || ''),
19714 html : this.html || ''
19725 * @param {string} the title
19727 setTitle: function(str)
19731 this.headerEl.dom.innerHTML = str;
19736 * @param {string} the body content
19738 setContent: function(str)
19741 if (this.contentEl) {
19742 this.contentEl.dom.innerHTML = str;
19746 // as it get's added to the bottom of the page.
19747 onRender : function(ct, position)
19749 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
19754 var cfg = Roo.apply({}, this.getAutoCreate());
19758 cfg.cls += ' ' + this.cls;
19761 cfg.style = this.style;
19763 //Roo.log("adding to ");
19764 this.el = Roo.get(document.body).createChild(cfg, position);
19765 // Roo.log(this.el);
19768 this.contentEl = this.el.select('.popover-content',true).first();
19769 this.headerEl = this.el.select('.popover-title',true).first();
19772 if(typeof(this.items) != 'undefined'){
19773 var items = this.items;
19776 for(var i =0;i < items.length;i++) {
19777 nitems.push(this.addxtype(Roo.apply({}, items[i])));
19781 this.items = nitems;
19783 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
19784 Roo.EventManager.onWindowResize(this.resizeMask, this, true);
19791 resizeMask : function()
19793 this.maskEl.setSize(
19794 Roo.lib.Dom.getViewWidth(true),
19795 Roo.lib.Dom.getViewHeight(true)
19799 initEvents : function()
19803 Roo.bootstrap.Popover.register(this);
19806 this.arrowEl = this.el.select('.arrow',true).first();
19807 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY); // probably not needed as it's default in BS4
19808 this.el.enableDisplayMode('block');
19812 if (this.over === false && !this.parent()) {
19815 if (this.triggers === false) {
19820 var on_el = (this.over == 'parent' || this.over === false) ? this.parent().el : Roo.get(this.over);
19821 var triggers = this.trigger ? this.trigger.split(' ') : [];
19822 Roo.each(triggers, function(trigger) {
19824 if (trigger == 'click') {
19825 on_el.on('click', this.toggle, this);
19826 } else if (trigger != 'manual') {
19827 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
19828 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
19830 on_el.on(eventIn ,this.enter, this);
19831 on_el.on(eventOut, this.leave, this);
19841 toggle : function () {
19842 this.hoverState == 'in' ? this.leave() : this.enter();
19845 enter : function () {
19847 clearTimeout(this.timeout);
19849 this.hoverState = 'in';
19851 if (!this.delay || !this.delay.show) {
19856 this.timeout = setTimeout(function () {
19857 if (_t.hoverState == 'in') {
19860 }, this.delay.show)
19863 leave : function() {
19864 clearTimeout(this.timeout);
19866 this.hoverState = 'out';
19868 if (!this.delay || !this.delay.hide) {
19873 this.timeout = setTimeout(function () {
19874 if (_t.hoverState == 'out') {
19877 }, this.delay.hide)
19881 * @param {Roo.Element|string|Boolean} - element to align and point to. (set align to [ pos, offset ])
19882 * @param {string} (left|right|top|bottom) position
19884 show : function (on_el, placement)
19886 this.placement = typeof(placement) == 'undefined' ? this.placement : placement;
19887 on_el = on_el || false; // default to false
19890 if (this.parent() && (this.over == 'parent' || (this.over === false))) {
19891 on_el = this.parent().el;
19892 } else if (this.over) {
19893 Roo.get(this.over);
19898 this.alignEl = Roo.get( on_el );
19901 this.render(document.body);
19907 if (this.title === false) {
19908 this.headerEl.hide();
19913 this.el.dom.style.display = 'block';
19916 if (this.alignEl) {
19917 this.updatePosition(this.placement, true);
19920 // this is usually just done by the builder = to show the popoup in the middle of the scren.
19921 var es = this.el.getSize();
19922 var x = Roo.lib.Dom.getViewWidth()/2;
19923 var y = Roo.lib.Dom.getViewHeight()/2;
19924 this.el.setXY([ x-(es.width/2), y-(es.height/2)] );
19929 //var arrow = this.el.select('.arrow',true).first();
19930 //arrow.set(align[2],
19932 this.el.addClass('in');
19936 this.hoverState = 'in';
19939 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
19940 this.maskEl.setStyle('z-index', Roo.bootstrap.Popover.zIndex++);
19941 this.maskEl.dom.style.display = 'block';
19942 this.maskEl.addClass('show');
19944 this.el.setStyle('z-index', Roo.bootstrap.Popover.zIndex++);
19946 this.fireEvent('show', this);
19950 * fire this manually after loading a grid in the table for example
19951 * @param {string} (left|right|top|bottom) where to try and put it (use false to use the last one)
19952 * @param {Boolean} try and move it if we cant get right position.
19954 updatePosition : function(placement, try_move)
19956 // allow for calling with no parameters
19957 placement = placement ? placement : this.placement;
19958 try_move = typeof(try_move) == 'undefined' ? true : try_move;
19960 this.el.removeClass([
19961 'fade','top','bottom', 'left', 'right','in',
19962 'bs-popover-top','bs-popover-bottom', 'bs-popover-left', 'bs-popover-right'
19964 this.el.addClass(placement + ' bs-popover-' + placement);
19966 if (!this.alignEl ) {
19970 switch (placement) {
19972 var exact = this.el.getAlignToXY(this.alignEl, 'tl-tr', [10,0]);
19973 var offset = this.el.getAlignToXY(this.alignEl, 'tl-tr?',[10,0]);
19974 if (!try_move || exact.equals(offset) || exact[0] == offset[0] ) {
19975 //normal display... or moved up/down.
19976 this.el.setXY(offset);
19977 var xy = this.alignEl.getAnchorXY('tr', false);
19979 this.arrowEl.setXY(xy);
19982 // continue through...
19983 return this.updatePosition('left', false);
19987 var exact = this.el.getAlignToXY(this.alignEl, 'tr-tl', [-10,0]);
19988 var offset = this.el.getAlignToXY(this.alignEl, 'tr-tl?',[-10,0]);
19989 if (!try_move || exact.equals(offset) || exact[0] == offset[0] ) {
19990 //normal display... or moved up/down.
19991 this.el.setXY(offset);
19992 var xy = this.alignEl.getAnchorXY('tl', false);
19993 xy[0]-=10;xy[1]+=5; // << fix me
19994 this.arrowEl.setXY(xy);
19998 return this.updatePosition('right', false);
20001 var exact = this.el.getAlignToXY(this.alignEl, 'b-t', [0,-10]);
20002 var offset = this.el.getAlignToXY(this.alignEl, 'b-t?',[0,-10]);
20003 if (!try_move || exact.equals(offset) || exact[1] == offset[1] ) {
20004 //normal display... or moved up/down.
20005 this.el.setXY(offset);
20006 var xy = this.alignEl.getAnchorXY('t', false);
20007 xy[1]-=10; // << fix me
20008 this.arrowEl.setXY(xy);
20012 return this.updatePosition('bottom', false);
20015 var exact = this.el.getAlignToXY(this.alignEl, 't-b', [0,10]);
20016 var offset = this.el.getAlignToXY(this.alignEl, 't-b?',[0,10]);
20017 if (!try_move || exact.equals(offset) || exact[1] == offset[1] ) {
20018 //normal display... or moved up/down.
20019 this.el.setXY(offset);
20020 var xy = this.alignEl.getAnchorXY('b', false);
20021 xy[1]+=2; // << fix me
20022 this.arrowEl.setXY(xy);
20026 return this.updatePosition('top', false);
20037 this.el.setXY([0,0]);
20038 this.el.removeClass('in');
20040 this.hoverState = null;
20041 this.maskEl.hide(); // always..
20042 this.fireEvent('hide', this);
20048 Roo.apply(Roo.bootstrap.Popover, {
20051 'left' : ['r-l', [-10,0], 'left bs-popover-left'],
20052 'right' : ['l-br', [10,0], 'right bs-popover-right'],
20053 'bottom' : ['t-b', [0,10], 'top bs-popover-top'],
20054 'top' : [ 'b-t', [0,-10], 'bottom bs-popover-bottom']
20059 clickHander : false,
20062 onMouseDown : function(e)
20064 if (!e.getTarget(".roo-popover")) {
20072 register : function(popup)
20074 if (!Roo.bootstrap.Popover.clickHandler) {
20075 Roo.bootstrap.Popover.clickHandler = Roo.get(document).on("mousedown", Roo.bootstrap.Popover.onMouseDown, Roo.bootstrap.Popover);
20077 // hide other popups.
20079 this.popups.push(popup);
20081 hideAll : function()
20083 this.popups.forEach(function(p) {
20091 * Card header - holder for the card header elements.
20096 * @class Roo.bootstrap.PopoverNav
20097 * @extends Roo.bootstrap.NavGroup
20098 * Bootstrap Popover header navigation class
20100 * Create a new Popover Header Navigation
20101 * @param {Object} config The config object
20104 Roo.bootstrap.PopoverNav = function(config){
20105 Roo.bootstrap.PopoverNav.superclass.constructor.call(this, config);
20108 Roo.extend(Roo.bootstrap.PopoverNav, Roo.bootstrap.NavSimplebar, {
20111 container_method : 'getPopoverHeader'
20129 * @class Roo.bootstrap.Progress
20130 * @extends Roo.bootstrap.Component
20131 * Bootstrap Progress class
20132 * @cfg {Boolean} striped striped of the progress bar
20133 * @cfg {Boolean} active animated of the progress bar
20137 * Create a new Progress
20138 * @param {Object} config The config object
20141 Roo.bootstrap.Progress = function(config){
20142 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
20145 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
20150 getAutoCreate : function(){
20158 cfg.cls += ' progress-striped';
20162 cfg.cls += ' active';
20181 * @class Roo.bootstrap.ProgressBar
20182 * @extends Roo.bootstrap.Component
20183 * Bootstrap ProgressBar class
20184 * @cfg {Number} aria_valuenow aria-value now
20185 * @cfg {Number} aria_valuemin aria-value min
20186 * @cfg {Number} aria_valuemax aria-value max
20187 * @cfg {String} label label for the progress bar
20188 * @cfg {String} panel (success | info | warning | danger )
20189 * @cfg {String} role role of the progress bar
20190 * @cfg {String} sr_only text
20194 * Create a new ProgressBar
20195 * @param {Object} config The config object
20198 Roo.bootstrap.ProgressBar = function(config){
20199 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
20202 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
20206 aria_valuemax : 100,
20212 getAutoCreate : function()
20217 cls: 'progress-bar',
20218 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
20230 cfg.role = this.role;
20233 if(this.aria_valuenow){
20234 cfg['aria-valuenow'] = this.aria_valuenow;
20237 if(this.aria_valuemin){
20238 cfg['aria-valuemin'] = this.aria_valuemin;
20241 if(this.aria_valuemax){
20242 cfg['aria-valuemax'] = this.aria_valuemax;
20245 if(this.label && !this.sr_only){
20246 cfg.html = this.label;
20250 cfg.cls += ' progress-bar-' + this.panel;
20256 update : function(aria_valuenow)
20258 this.aria_valuenow = aria_valuenow;
20260 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
20275 * @class Roo.bootstrap.TabGroup
20276 * @extends Roo.bootstrap.Column
20277 * Bootstrap Column class
20278 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
20279 * @cfg {Boolean} carousel true to make the group behave like a carousel
20280 * @cfg {Boolean} bullets show bullets for the panels
20281 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
20282 * @cfg {Number} timer auto slide timer .. default 0 millisecond
20283 * @cfg {Boolean} showarrow (true|false) show arrow default true
20286 * Create a new TabGroup
20287 * @param {Object} config The config object
20290 Roo.bootstrap.TabGroup = function(config){
20291 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
20293 this.navId = Roo.id();
20296 Roo.bootstrap.TabGroup.register(this);
20300 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
20303 transition : false,
20308 slideOnTouch : false,
20311 getAutoCreate : function()
20313 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
20315 cfg.cls += ' tab-content';
20317 if (this.carousel) {
20318 cfg.cls += ' carousel slide';
20321 cls : 'carousel-inner',
20325 if(this.bullets && !Roo.isTouch){
20328 cls : 'carousel-bullets',
20332 if(this.bullets_cls){
20333 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
20340 cfg.cn[0].cn.push(bullets);
20343 if(this.showarrow){
20344 cfg.cn[0].cn.push({
20346 class : 'carousel-arrow',
20350 class : 'carousel-prev',
20354 class : 'fa fa-chevron-left'
20360 class : 'carousel-next',
20364 class : 'fa fa-chevron-right'
20377 initEvents: function()
20379 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
20380 // this.el.on("touchstart", this.onTouchStart, this);
20383 if(this.autoslide){
20386 this.slideFn = window.setInterval(function() {
20387 _this.showPanelNext();
20391 if(this.showarrow){
20392 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
20393 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
20399 // onTouchStart : function(e, el, o)
20401 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
20405 // this.showPanelNext();
20409 getChildContainer : function()
20411 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
20415 * register a Navigation item
20416 * @param {Roo.bootstrap.NavItem} the navitem to add
20418 register : function(item)
20420 this.tabs.push( item);
20421 item.navId = this.navId; // not really needed..
20426 getActivePanel : function()
20429 Roo.each(this.tabs, function(t) {
20439 getPanelByName : function(n)
20442 Roo.each(this.tabs, function(t) {
20443 if (t.tabId == n) {
20451 indexOfPanel : function(p)
20454 Roo.each(this.tabs, function(t,i) {
20455 if (t.tabId == p.tabId) {
20464 * show a specific panel
20465 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
20466 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
20468 showPanel : function (pan)
20470 if(this.transition || typeof(pan) == 'undefined'){
20471 Roo.log("waiting for the transitionend");
20475 if (typeof(pan) == 'number') {
20476 pan = this.tabs[pan];
20479 if (typeof(pan) == 'string') {
20480 pan = this.getPanelByName(pan);
20483 var cur = this.getActivePanel();
20486 Roo.log('pan or acitve pan is undefined');
20490 if (pan.tabId == this.getActivePanel().tabId) {
20494 if (false === cur.fireEvent('beforedeactivate')) {
20498 if(this.bullets > 0 && !Roo.isTouch){
20499 this.setActiveBullet(this.indexOfPanel(pan));
20502 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
20504 //class="carousel-item carousel-item-next carousel-item-left"
20506 this.transition = true;
20507 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
20508 var lr = dir == 'next' ? 'left' : 'right';
20509 pan.el.addClass(dir); // or prev
20510 pan.el.addClass('carousel-item-' + dir); // or prev
20511 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
20512 cur.el.addClass(lr); // or right
20513 pan.el.addClass(lr);
20514 cur.el.addClass('carousel-item-' +lr); // or right
20515 pan.el.addClass('carousel-item-' +lr);
20519 cur.el.on('transitionend', function() {
20520 Roo.log("trans end?");
20522 pan.el.removeClass([lr,dir, 'carousel-item-' + lr, 'carousel-item-' + dir]);
20523 pan.setActive(true);
20525 cur.el.removeClass([lr, 'carousel-item-' + lr]);
20526 cur.setActive(false);
20528 _this.transition = false;
20530 }, this, { single: true } );
20535 cur.setActive(false);
20536 pan.setActive(true);
20541 showPanelNext : function()
20543 var i = this.indexOfPanel(this.getActivePanel());
20545 if (i >= this.tabs.length - 1 && !this.autoslide) {
20549 if (i >= this.tabs.length - 1 && this.autoslide) {
20553 this.showPanel(this.tabs[i+1]);
20556 showPanelPrev : function()
20558 var i = this.indexOfPanel(this.getActivePanel());
20560 if (i < 1 && !this.autoslide) {
20564 if (i < 1 && this.autoslide) {
20565 i = this.tabs.length;
20568 this.showPanel(this.tabs[i-1]);
20572 addBullet: function()
20574 if(!this.bullets || Roo.isTouch){
20577 var ctr = this.el.select('.carousel-bullets',true).first();
20578 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
20579 var bullet = ctr.createChild({
20580 cls : 'bullet bullet-' + i
20581 },ctr.dom.lastChild);
20586 bullet.on('click', (function(e, el, o, ii, t){
20588 e.preventDefault();
20590 this.showPanel(ii);
20592 if(this.autoslide && this.slideFn){
20593 clearInterval(this.slideFn);
20594 this.slideFn = window.setInterval(function() {
20595 _this.showPanelNext();
20599 }).createDelegate(this, [i, bullet], true));
20604 setActiveBullet : function(i)
20610 Roo.each(this.el.select('.bullet', true).elements, function(el){
20611 el.removeClass('selected');
20614 var bullet = this.el.select('.bullet-' + i, true).first();
20620 bullet.addClass('selected');
20631 Roo.apply(Roo.bootstrap.TabGroup, {
20635 * register a Navigation Group
20636 * @param {Roo.bootstrap.NavGroup} the navgroup to add
20638 register : function(navgrp)
20640 this.groups[navgrp.navId] = navgrp;
20644 * fetch a Navigation Group based on the navigation ID
20645 * if one does not exist , it will get created.
20646 * @param {string} the navgroup to add
20647 * @returns {Roo.bootstrap.NavGroup} the navgroup
20649 get: function(navId) {
20650 if (typeof(this.groups[navId]) == 'undefined') {
20651 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
20653 return this.groups[navId] ;
20668 * @class Roo.bootstrap.TabPanel
20669 * @extends Roo.bootstrap.Component
20670 * Bootstrap TabPanel class
20671 * @cfg {Boolean} active panel active
20672 * @cfg {String} html panel content
20673 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
20674 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
20675 * @cfg {String} href click to link..
20676 * @cfg {Boolean} touchSlide if swiping slides tab to next panel (default off)
20680 * Create a new TabPanel
20681 * @param {Object} config The config object
20684 Roo.bootstrap.TabPanel = function(config){
20685 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
20689 * Fires when the active status changes
20690 * @param {Roo.bootstrap.TabPanel} this
20691 * @param {Boolean} state the new state
20696 * @event beforedeactivate
20697 * Fires before a tab is de-activated - can be used to do validation on a form.
20698 * @param {Roo.bootstrap.TabPanel} this
20699 * @return {Boolean} false if there is an error
20702 'beforedeactivate': true
20705 this.tabId = this.tabId || Roo.id();
20709 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
20716 touchSlide : false,
20717 getAutoCreate : function(){
20722 // item is needed for carousel - not sure if it has any effect otherwise
20723 cls: 'carousel-item tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
20724 html: this.html || ''
20728 cfg.cls += ' active';
20732 cfg.tabId = this.tabId;
20740 initEvents: function()
20742 var p = this.parent();
20744 this.navId = this.navId || p.navId;
20746 if (typeof(this.navId) != 'undefined') {
20747 // not really needed.. but just in case.. parent should be a NavGroup.
20748 var tg = Roo.bootstrap.TabGroup.get(this.navId);
20752 var i = tg.tabs.length - 1;
20754 if(this.active && tg.bullets > 0 && i < tg.bullets){
20755 tg.setActiveBullet(i);
20759 this.el.on('click', this.onClick, this);
20761 if(Roo.isTouch && this.touchSlide){
20762 this.el.on("touchstart", this.onTouchStart, this);
20763 this.el.on("touchmove", this.onTouchMove, this);
20764 this.el.on("touchend", this.onTouchEnd, this);
20769 onRender : function(ct, position)
20771 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
20774 setActive : function(state)
20776 Roo.log("panel - set active " + this.tabId + "=" + state);
20778 this.active = state;
20780 this.el.removeClass('active');
20782 } else if (!this.el.hasClass('active')) {
20783 this.el.addClass('active');
20786 this.fireEvent('changed', this, state);
20789 onClick : function(e)
20791 e.preventDefault();
20793 if(!this.href.length){
20797 window.location.href = this.href;
20806 onTouchStart : function(e)
20808 this.swiping = false;
20810 this.startX = e.browserEvent.touches[0].clientX;
20811 this.startY = e.browserEvent.touches[0].clientY;
20814 onTouchMove : function(e)
20816 this.swiping = true;
20818 this.endX = e.browserEvent.touches[0].clientX;
20819 this.endY = e.browserEvent.touches[0].clientY;
20822 onTouchEnd : function(e)
20829 var tabGroup = this.parent();
20831 if(this.endX > this.startX){ // swiping right
20832 tabGroup.showPanelPrev();
20836 if(this.startX > this.endX){ // swiping left
20837 tabGroup.showPanelNext();
20856 * @class Roo.bootstrap.DateField
20857 * @extends Roo.bootstrap.Input
20858 * Bootstrap DateField class
20859 * @cfg {Number} weekStart default 0
20860 * @cfg {String} viewMode default empty, (months|years)
20861 * @cfg {String} minViewMode default empty, (months|years)
20862 * @cfg {Number} startDate default -Infinity
20863 * @cfg {Number} endDate default Infinity
20864 * @cfg {Boolean} todayHighlight default false
20865 * @cfg {Boolean} todayBtn default false
20866 * @cfg {Boolean} calendarWeeks default false
20867 * @cfg {Object} daysOfWeekDisabled default empty
20868 * @cfg {Boolean} singleMode default false (true | false)
20870 * @cfg {Boolean} keyboardNavigation default true
20871 * @cfg {String} language default en
20874 * Create a new DateField
20875 * @param {Object} config The config object
20878 Roo.bootstrap.DateField = function(config){
20879 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
20883 * Fires when this field show.
20884 * @param {Roo.bootstrap.DateField} this
20885 * @param {Mixed} date The date value
20890 * Fires when this field hide.
20891 * @param {Roo.bootstrap.DateField} this
20892 * @param {Mixed} date The date value
20897 * Fires when select a date.
20898 * @param {Roo.bootstrap.DateField} this
20899 * @param {Mixed} date The date value
20903 * @event beforeselect
20904 * Fires when before select a date.
20905 * @param {Roo.bootstrap.DateField} this
20906 * @param {Mixed} date The date value
20908 beforeselect : true
20912 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
20915 * @cfg {String} format
20916 * The default date format string which can be overriden for localization support. The format must be
20917 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
20921 * @cfg {String} altFormats
20922 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
20923 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
20925 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
20933 todayHighlight : false,
20939 keyboardNavigation: true,
20941 calendarWeeks: false,
20943 startDate: -Infinity,
20947 daysOfWeekDisabled: [],
20951 singleMode : false,
20953 UTCDate: function()
20955 return new Date(Date.UTC.apply(Date, arguments));
20958 UTCToday: function()
20960 var today = new Date();
20961 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
20964 getDate: function() {
20965 var d = this.getUTCDate();
20966 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
20969 getUTCDate: function() {
20973 setDate: function(d) {
20974 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
20977 setUTCDate: function(d) {
20979 this.setValue(this.formatDate(this.date));
20982 onRender: function(ct, position)
20985 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
20987 this.language = this.language || 'en';
20988 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
20989 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
20991 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
20992 this.format = this.format || 'm/d/y';
20993 this.isInline = false;
20994 this.isInput = true;
20995 this.component = this.el.select('.add-on', true).first() || false;
20996 this.component = (this.component && this.component.length === 0) ? false : this.component;
20997 this.hasInput = this.component && this.inputEl().length;
20999 if (typeof(this.minViewMode === 'string')) {
21000 switch (this.minViewMode) {
21002 this.minViewMode = 1;
21005 this.minViewMode = 2;
21008 this.minViewMode = 0;
21013 if (typeof(this.viewMode === 'string')) {
21014 switch (this.viewMode) {
21027 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
21029 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
21031 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
21033 this.picker().on('mousedown', this.onMousedown, this);
21034 this.picker().on('click', this.onClick, this);
21036 this.picker().addClass('datepicker-dropdown');
21038 this.startViewMode = this.viewMode;
21040 if(this.singleMode){
21041 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
21042 v.setVisibilityMode(Roo.Element.DISPLAY);
21046 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
21047 v.setStyle('width', '189px');
21051 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
21052 if(!this.calendarWeeks){
21057 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
21058 v.attr('colspan', function(i, val){
21059 return parseInt(val) + 1;
21064 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
21066 this.setStartDate(this.startDate);
21067 this.setEndDate(this.endDate);
21069 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
21076 if(this.isInline) {
21081 picker : function()
21083 return this.pickerEl;
21084 // return this.el.select('.datepicker', true).first();
21087 fillDow: function()
21089 var dowCnt = this.weekStart;
21098 if(this.calendarWeeks){
21106 while (dowCnt < this.weekStart + 7) {
21110 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
21114 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
21117 fillMonths: function()
21120 var months = this.picker().select('>.datepicker-months td', true).first();
21122 months.dom.innerHTML = '';
21128 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
21131 months.createChild(month);
21138 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;
21140 if (this.date < this.startDate) {
21141 this.viewDate = new Date(this.startDate);
21142 } else if (this.date > this.endDate) {
21143 this.viewDate = new Date(this.endDate);
21145 this.viewDate = new Date(this.date);
21153 var d = new Date(this.viewDate),
21154 year = d.getUTCFullYear(),
21155 month = d.getUTCMonth(),
21156 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
21157 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
21158 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
21159 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
21160 currentDate = this.date && this.date.valueOf(),
21161 today = this.UTCToday();
21163 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
21165 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
21167 // this.picker.select('>tfoot th.today').
21168 // .text(dates[this.language].today)
21169 // .toggle(this.todayBtn !== false);
21171 this.updateNavArrows();
21174 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
21176 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
21178 prevMonth.setUTCDate(day);
21180 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
21182 var nextMonth = new Date(prevMonth);
21184 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
21186 nextMonth = nextMonth.valueOf();
21188 var fillMonths = false;
21190 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
21192 while(prevMonth.valueOf() <= nextMonth) {
21195 if (prevMonth.getUTCDay() === this.weekStart) {
21197 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
21205 if(this.calendarWeeks){
21206 // ISO 8601: First week contains first thursday.
21207 // ISO also states week starts on Monday, but we can be more abstract here.
21209 // Start of current week: based on weekstart/current date
21210 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
21211 // Thursday of this week
21212 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
21213 // First Thursday of year, year from thursday
21214 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
21215 // Calendar week: ms between thursdays, div ms per day, div 7 days
21216 calWeek = (th - yth) / 864e5 / 7 + 1;
21218 fillMonths.cn.push({
21226 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
21228 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
21231 if (this.todayHighlight &&
21232 prevMonth.getUTCFullYear() == today.getFullYear() &&
21233 prevMonth.getUTCMonth() == today.getMonth() &&
21234 prevMonth.getUTCDate() == today.getDate()) {
21235 clsName += ' today';
21238 if (currentDate && prevMonth.valueOf() === currentDate) {
21239 clsName += ' active';
21242 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
21243 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
21244 clsName += ' disabled';
21247 fillMonths.cn.push({
21249 cls: 'day ' + clsName,
21250 html: prevMonth.getDate()
21253 prevMonth.setDate(prevMonth.getDate()+1);
21256 var currentYear = this.date && this.date.getUTCFullYear();
21257 var currentMonth = this.date && this.date.getUTCMonth();
21259 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
21261 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
21262 v.removeClass('active');
21264 if(currentYear === year && k === currentMonth){
21265 v.addClass('active');
21268 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
21269 v.addClass('disabled');
21275 year = parseInt(year/10, 10) * 10;
21277 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
21279 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
21282 for (var i = -1; i < 11; i++) {
21283 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
21285 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
21293 showMode: function(dir)
21296 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
21299 Roo.each(this.picker().select('>div',true).elements, function(v){
21300 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
21303 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
21308 if(this.isInline) {
21312 this.picker().removeClass(['bottom', 'top']);
21314 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
21316 * place to the top of element!
21320 this.picker().addClass('top');
21321 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
21326 this.picker().addClass('bottom');
21328 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
21331 parseDate : function(value)
21333 if(!value || value instanceof Date){
21336 var v = Date.parseDate(value, this.format);
21337 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
21338 v = Date.parseDate(value, 'Y-m-d');
21340 if(!v && this.altFormats){
21341 if(!this.altFormatsArray){
21342 this.altFormatsArray = this.altFormats.split("|");
21344 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
21345 v = Date.parseDate(value, this.altFormatsArray[i]);
21351 formatDate : function(date, fmt)
21353 return (!date || !(date instanceof Date)) ?
21354 date : date.dateFormat(fmt || this.format);
21357 onFocus : function()
21359 Roo.bootstrap.DateField.superclass.onFocus.call(this);
21363 onBlur : function()
21365 Roo.bootstrap.DateField.superclass.onBlur.call(this);
21367 var d = this.inputEl().getValue();
21374 showPopup : function()
21376 this.picker().show();
21380 this.fireEvent('showpopup', this, this.date);
21383 hidePopup : function()
21385 if(this.isInline) {
21388 this.picker().hide();
21389 this.viewMode = this.startViewMode;
21392 this.fireEvent('hidepopup', this, this.date);
21396 onMousedown: function(e)
21398 e.stopPropagation();
21399 e.preventDefault();
21404 Roo.bootstrap.DateField.superclass.keyup.call(this);
21408 setValue: function(v)
21410 if(this.fireEvent('beforeselect', this, v) !== false){
21411 var d = new Date(this.parseDate(v) ).clearTime();
21413 if(isNaN(d.getTime())){
21414 this.date = this.viewDate = '';
21415 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
21419 v = this.formatDate(d);
21421 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
21423 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
21427 this.fireEvent('select', this, this.date);
21431 getValue: function()
21433 return this.formatDate(this.date);
21436 fireKey: function(e)
21438 if (!this.picker().isVisible()){
21439 if (e.keyCode == 27) { // allow escape to hide and re-show picker
21445 var dateChanged = false,
21447 newDate, newViewDate;
21452 e.preventDefault();
21456 if (!this.keyboardNavigation) {
21459 dir = e.keyCode == 37 ? -1 : 1;
21462 newDate = this.moveYear(this.date, dir);
21463 newViewDate = this.moveYear(this.viewDate, dir);
21464 } else if (e.shiftKey){
21465 newDate = this.moveMonth(this.date, dir);
21466 newViewDate = this.moveMonth(this.viewDate, dir);
21468 newDate = new Date(this.date);
21469 newDate.setUTCDate(this.date.getUTCDate() + dir);
21470 newViewDate = new Date(this.viewDate);
21471 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
21473 if (this.dateWithinRange(newDate)){
21474 this.date = newDate;
21475 this.viewDate = newViewDate;
21476 this.setValue(this.formatDate(this.date));
21478 e.preventDefault();
21479 dateChanged = true;
21484 if (!this.keyboardNavigation) {
21487 dir = e.keyCode == 38 ? -1 : 1;
21489 newDate = this.moveYear(this.date, dir);
21490 newViewDate = this.moveYear(this.viewDate, dir);
21491 } else if (e.shiftKey){
21492 newDate = this.moveMonth(this.date, dir);
21493 newViewDate = this.moveMonth(this.viewDate, dir);
21495 newDate = new Date(this.date);
21496 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
21497 newViewDate = new Date(this.viewDate);
21498 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
21500 if (this.dateWithinRange(newDate)){
21501 this.date = newDate;
21502 this.viewDate = newViewDate;
21503 this.setValue(this.formatDate(this.date));
21505 e.preventDefault();
21506 dateChanged = true;
21510 this.setValue(this.formatDate(this.date));
21512 e.preventDefault();
21515 this.setValue(this.formatDate(this.date));
21529 onClick: function(e)
21531 e.stopPropagation();
21532 e.preventDefault();
21534 var target = e.getTarget();
21536 if(target.nodeName.toLowerCase() === 'i'){
21537 target = Roo.get(target).dom.parentNode;
21540 var nodeName = target.nodeName;
21541 var className = target.className;
21542 var html = target.innerHTML;
21543 //Roo.log(nodeName);
21545 switch(nodeName.toLowerCase()) {
21547 switch(className) {
21553 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
21554 switch(this.viewMode){
21556 this.viewDate = this.moveMonth(this.viewDate, dir);
21560 this.viewDate = this.moveYear(this.viewDate, dir);
21566 var date = new Date();
21567 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
21569 this.setValue(this.formatDate(this.date));
21576 if (className.indexOf('disabled') < 0) {
21577 this.viewDate.setUTCDate(1);
21578 if (className.indexOf('month') > -1) {
21579 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
21581 var year = parseInt(html, 10) || 0;
21582 this.viewDate.setUTCFullYear(year);
21586 if(this.singleMode){
21587 this.setValue(this.formatDate(this.viewDate));
21598 //Roo.log(className);
21599 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
21600 var day = parseInt(html, 10) || 1;
21601 var year = (this.viewDate || new Date()).getUTCFullYear(),
21602 month = (this.viewDate || new Date()).getUTCMonth();
21604 if (className.indexOf('old') > -1) {
21611 } else if (className.indexOf('new') > -1) {
21619 //Roo.log([year,month,day]);
21620 this.date = this.UTCDate(year, month, day,0,0,0,0);
21621 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
21623 //Roo.log(this.formatDate(this.date));
21624 this.setValue(this.formatDate(this.date));
21631 setStartDate: function(startDate)
21633 this.startDate = startDate || -Infinity;
21634 if (this.startDate !== -Infinity) {
21635 this.startDate = this.parseDate(this.startDate);
21638 this.updateNavArrows();
21641 setEndDate: function(endDate)
21643 this.endDate = endDate || Infinity;
21644 if (this.endDate !== Infinity) {
21645 this.endDate = this.parseDate(this.endDate);
21648 this.updateNavArrows();
21651 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
21653 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
21654 if (typeof(this.daysOfWeekDisabled) !== 'object') {
21655 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
21657 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
21658 return parseInt(d, 10);
21661 this.updateNavArrows();
21664 updateNavArrows: function()
21666 if(this.singleMode){
21670 var d = new Date(this.viewDate),
21671 year = d.getUTCFullYear(),
21672 month = d.getUTCMonth();
21674 Roo.each(this.picker().select('.prev', true).elements, function(v){
21676 switch (this.viewMode) {
21679 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
21685 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
21692 Roo.each(this.picker().select('.next', true).elements, function(v){
21694 switch (this.viewMode) {
21697 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
21703 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
21711 moveMonth: function(date, dir)
21716 var new_date = new Date(date.valueOf()),
21717 day = new_date.getUTCDate(),
21718 month = new_date.getUTCMonth(),
21719 mag = Math.abs(dir),
21721 dir = dir > 0 ? 1 : -1;
21724 // If going back one month, make sure month is not current month
21725 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
21727 return new_date.getUTCMonth() == month;
21729 // If going forward one month, make sure month is as expected
21730 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
21732 return new_date.getUTCMonth() != new_month;
21734 new_month = month + dir;
21735 new_date.setUTCMonth(new_month);
21736 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
21737 if (new_month < 0 || new_month > 11) {
21738 new_month = (new_month + 12) % 12;
21741 // For magnitudes >1, move one month at a time...
21742 for (var i=0; i<mag; i++) {
21743 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
21744 new_date = this.moveMonth(new_date, dir);
21746 // ...then reset the day, keeping it in the new month
21747 new_month = new_date.getUTCMonth();
21748 new_date.setUTCDate(day);
21750 return new_month != new_date.getUTCMonth();
21753 // Common date-resetting loop -- if date is beyond end of month, make it
21756 new_date.setUTCDate(--day);
21757 new_date.setUTCMonth(new_month);
21762 moveYear: function(date, dir)
21764 return this.moveMonth(date, dir*12);
21767 dateWithinRange: function(date)
21769 return date >= this.startDate && date <= this.endDate;
21775 this.picker().remove();
21778 validateValue : function(value)
21780 if(this.getVisibilityEl().hasClass('hidden')){
21784 if(value.length < 1) {
21785 if(this.allowBlank){
21791 if(value.length < this.minLength){
21794 if(value.length > this.maxLength){
21798 var vt = Roo.form.VTypes;
21799 if(!vt[this.vtype](value, this)){
21803 if(typeof this.validator == "function"){
21804 var msg = this.validator(value);
21810 if(this.regex && !this.regex.test(value)){
21814 if(typeof(this.parseDate(value)) == 'undefined'){
21818 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
21822 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
21832 this.date = this.viewDate = '';
21834 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
21839 Roo.apply(Roo.bootstrap.DateField, {
21850 html: '<i class="fa fa-arrow-left"/>'
21860 html: '<i class="fa fa-arrow-right"/>'
21902 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
21903 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
21904 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
21905 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
21906 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
21919 navFnc: 'FullYear',
21924 navFnc: 'FullYear',
21929 Roo.apply(Roo.bootstrap.DateField, {
21933 cls: 'datepicker dropdown-menu roo-dynamic shadow',
21937 cls: 'datepicker-days',
21941 cls: 'table-condensed',
21943 Roo.bootstrap.DateField.head,
21947 Roo.bootstrap.DateField.footer
21954 cls: 'datepicker-months',
21958 cls: 'table-condensed',
21960 Roo.bootstrap.DateField.head,
21961 Roo.bootstrap.DateField.content,
21962 Roo.bootstrap.DateField.footer
21969 cls: 'datepicker-years',
21973 cls: 'table-condensed',
21975 Roo.bootstrap.DateField.head,
21976 Roo.bootstrap.DateField.content,
21977 Roo.bootstrap.DateField.footer
21996 * @class Roo.bootstrap.TimeField
21997 * @extends Roo.bootstrap.Input
21998 * Bootstrap DateField class
22002 * Create a new TimeField
22003 * @param {Object} config The config object
22006 Roo.bootstrap.TimeField = function(config){
22007 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
22011 * Fires when this field show.
22012 * @param {Roo.bootstrap.DateField} thisthis
22013 * @param {Mixed} date The date value
22018 * Fires when this field hide.
22019 * @param {Roo.bootstrap.DateField} this
22020 * @param {Mixed} date The date value
22025 * Fires when select a date.
22026 * @param {Roo.bootstrap.DateField} this
22027 * @param {Mixed} date The date value
22033 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
22036 * @cfg {String} format
22037 * The default time format string which can be overriden for localization support. The format must be
22038 * valid according to {@link Date#parseDate} (defaults to 'H:i').
22042 getAutoCreate : function()
22044 this.after = '<i class="fa far fa-clock"></i>';
22045 return Roo.bootstrap.TimeField.superclass.getAutoCreate.call(this);
22049 onRender: function(ct, position)
22052 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
22054 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.TimeField.template);
22056 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
22058 this.pop = this.picker().select('>.datepicker-time',true).first();
22059 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
22061 this.picker().on('mousedown', this.onMousedown, this);
22062 this.picker().on('click', this.onClick, this);
22064 this.picker().addClass('datepicker-dropdown');
22069 this.pop.select('.hours-up', true).first().on('click', this.onIncrementHours, this);
22070 this.pop.select('.hours-down', true).first().on('click', this.onDecrementHours, this);
22071 this.pop.select('.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
22072 this.pop.select('.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
22073 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
22074 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
22078 fireKey: function(e){
22079 if (!this.picker().isVisible()){
22080 if (e.keyCode == 27) { // allow escape to hide and re-show picker
22086 e.preventDefault();
22094 this.onTogglePeriod();
22097 this.onIncrementMinutes();
22100 this.onDecrementMinutes();
22109 onClick: function(e) {
22110 e.stopPropagation();
22111 e.preventDefault();
22114 picker : function()
22116 return this.pickerEl;
22119 fillTime: function()
22121 var time = this.pop.select('tbody', true).first();
22123 time.dom.innerHTML = '';
22138 cls: 'hours-up fa fas fa-chevron-up'
22158 cls: 'minutes-up fa fas fa-chevron-up'
22179 cls: 'timepicker-hour',
22194 cls: 'timepicker-minute',
22209 cls: 'btn btn-primary period',
22231 cls: 'hours-down fa fas fa-chevron-down'
22251 cls: 'minutes-down fa fas fa-chevron-down'
22269 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
22276 var hours = this.time.getHours();
22277 var minutes = this.time.getMinutes();
22290 hours = hours - 12;
22294 hours = '0' + hours;
22298 minutes = '0' + minutes;
22301 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
22302 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
22303 this.pop.select('button', true).first().dom.innerHTML = period;
22309 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
22311 var cls = ['bottom'];
22313 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
22320 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
22324 //this.picker().setXY(20000,20000);
22325 this.picker().addClass(cls.join('-'));
22329 Roo.each(cls, function(c){
22334 _this.picker().alignTo(_this.inputEl(), "tr-br", [0, 10], false);
22335 //_this.picker().setTop(_this.inputEl().getHeight());
22339 _this.picker().alignTo(_this.inputEl(), "br-tr", [0, 10], false);
22341 //_this.picker().setTop(0 - _this.picker().getHeight());
22346 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
22350 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
22358 onFocus : function()
22360 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
22364 onBlur : function()
22366 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
22372 this.picker().show();
22377 this.fireEvent('show', this, this.date);
22382 this.picker().hide();
22385 this.fireEvent('hide', this, this.date);
22388 setTime : function()
22391 this.setValue(this.time.format(this.format));
22393 this.fireEvent('select', this, this.date);
22398 onMousedown: function(e){
22399 e.stopPropagation();
22400 e.preventDefault();
22403 onIncrementHours: function()
22405 Roo.log('onIncrementHours');
22406 this.time = this.time.add(Date.HOUR, 1);
22411 onDecrementHours: function()
22413 Roo.log('onDecrementHours');
22414 this.time = this.time.add(Date.HOUR, -1);
22418 onIncrementMinutes: function()
22420 Roo.log('onIncrementMinutes');
22421 this.time = this.time.add(Date.MINUTE, 1);
22425 onDecrementMinutes: function()
22427 Roo.log('onDecrementMinutes');
22428 this.time = this.time.add(Date.MINUTE, -1);
22432 onTogglePeriod: function()
22434 Roo.log('onTogglePeriod');
22435 this.time = this.time.add(Date.HOUR, 12);
22443 Roo.apply(Roo.bootstrap.TimeField, {
22447 cls: 'datepicker dropdown-menu',
22451 cls: 'datepicker-time',
22455 cls: 'table-condensed',
22484 cls: 'btn btn-info ok',
22512 * @class Roo.bootstrap.MonthField
22513 * @extends Roo.bootstrap.Input
22514 * Bootstrap MonthField class
22516 * @cfg {String} language default en
22519 * Create a new MonthField
22520 * @param {Object} config The config object
22523 Roo.bootstrap.MonthField = function(config){
22524 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
22529 * Fires when this field show.
22530 * @param {Roo.bootstrap.MonthField} this
22531 * @param {Mixed} date The date value
22536 * Fires when this field hide.
22537 * @param {Roo.bootstrap.MonthField} this
22538 * @param {Mixed} date The date value
22543 * Fires when select a date.
22544 * @param {Roo.bootstrap.MonthField} this
22545 * @param {String} oldvalue The old value
22546 * @param {String} newvalue The new value
22552 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
22554 onRender: function(ct, position)
22557 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
22559 this.language = this.language || 'en';
22560 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
22561 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
22563 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
22564 this.isInline = false;
22565 this.isInput = true;
22566 this.component = this.el.select('.add-on', true).first() || false;
22567 this.component = (this.component && this.component.length === 0) ? false : this.component;
22568 this.hasInput = this.component && this.inputEL().length;
22570 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
22572 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
22574 this.picker().on('mousedown', this.onMousedown, this);
22575 this.picker().on('click', this.onClick, this);
22577 this.picker().addClass('datepicker-dropdown');
22579 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
22580 v.setStyle('width', '189px');
22587 if(this.isInline) {
22593 setValue: function(v, suppressEvent)
22595 var o = this.getValue();
22597 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
22601 if(suppressEvent !== true){
22602 this.fireEvent('select', this, o, v);
22607 getValue: function()
22612 onClick: function(e)
22614 e.stopPropagation();
22615 e.preventDefault();
22617 var target = e.getTarget();
22619 if(target.nodeName.toLowerCase() === 'i'){
22620 target = Roo.get(target).dom.parentNode;
22623 var nodeName = target.nodeName;
22624 var className = target.className;
22625 var html = target.innerHTML;
22627 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
22631 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
22633 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
22639 picker : function()
22641 return this.pickerEl;
22644 fillMonths: function()
22647 var months = this.picker().select('>.datepicker-months td', true).first();
22649 months.dom.innerHTML = '';
22655 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
22658 months.createChild(month);
22667 if(typeof(this.vIndex) == 'undefined' && this.value.length){
22668 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
22671 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
22672 e.removeClass('active');
22674 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
22675 e.addClass('active');
22682 if(this.isInline) {
22686 this.picker().removeClass(['bottom', 'top']);
22688 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
22690 * place to the top of element!
22694 this.picker().addClass('top');
22695 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
22700 this.picker().addClass('bottom');
22702 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
22705 onFocus : function()
22707 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
22711 onBlur : function()
22713 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
22715 var d = this.inputEl().getValue();
22724 this.picker().show();
22725 this.picker().select('>.datepicker-months', true).first().show();
22729 this.fireEvent('show', this, this.date);
22734 if(this.isInline) {
22737 this.picker().hide();
22738 this.fireEvent('hide', this, this.date);
22742 onMousedown: function(e)
22744 e.stopPropagation();
22745 e.preventDefault();
22750 Roo.bootstrap.MonthField.superclass.keyup.call(this);
22754 fireKey: function(e)
22756 if (!this.picker().isVisible()){
22757 if (e.keyCode == 27) {// allow escape to hide and re-show picker
22768 e.preventDefault();
22772 dir = e.keyCode == 37 ? -1 : 1;
22774 this.vIndex = this.vIndex + dir;
22776 if(this.vIndex < 0){
22780 if(this.vIndex > 11){
22784 if(isNaN(this.vIndex)){
22788 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
22794 dir = e.keyCode == 38 ? -1 : 1;
22796 this.vIndex = this.vIndex + dir * 4;
22798 if(this.vIndex < 0){
22802 if(this.vIndex > 11){
22806 if(isNaN(this.vIndex)){
22810 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
22815 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
22816 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
22820 e.preventDefault();
22823 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
22824 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
22840 this.picker().remove();
22845 Roo.apply(Roo.bootstrap.MonthField, {
22864 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
22865 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
22870 Roo.apply(Roo.bootstrap.MonthField, {
22874 cls: 'datepicker dropdown-menu roo-dynamic',
22878 cls: 'datepicker-months',
22882 cls: 'table-condensed',
22884 Roo.bootstrap.DateField.content
22904 * @class Roo.bootstrap.CheckBox
22905 * @extends Roo.bootstrap.Input
22906 * Bootstrap CheckBox class
22908 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
22909 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
22910 * @cfg {String} boxLabel The text that appears beside the checkbox
22911 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
22912 * @cfg {Boolean} checked initnal the element
22913 * @cfg {Boolean} inline inline the element (default false)
22914 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
22915 * @cfg {String} tooltip label tooltip
22918 * Create a new CheckBox
22919 * @param {Object} config The config object
22922 Roo.bootstrap.CheckBox = function(config){
22923 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
22928 * Fires when the element is checked or unchecked.
22929 * @param {Roo.bootstrap.CheckBox} this This input
22930 * @param {Boolean} checked The new checked value
22935 * Fires when the element is click.
22936 * @param {Roo.bootstrap.CheckBox} this This input
22943 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
22945 inputType: 'checkbox',
22954 // checkbox success does not make any sense really..
22959 getAutoCreate : function()
22961 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
22967 cfg.cls = 'form-group form-check ' + this.inputType; //input-group
22970 cfg.cls += ' ' + this.inputType + '-inline form-check-inline';
22976 type : this.inputType,
22977 value : this.inputValue,
22978 cls : 'roo-' + this.inputType, //'form-box',
22979 placeholder : this.placeholder || ''
22983 if(this.inputType != 'radio'){
22987 cls : 'roo-hidden-value',
22988 value : this.checked ? this.inputValue : this.valueOff
22993 if (this.weight) { // Validity check?
22994 cfg.cls += " " + this.inputType + "-" + this.weight;
22997 if (this.disabled) {
22998 input.disabled=true;
23002 input.checked = this.checked;
23007 input.name = this.name;
23009 if(this.inputType != 'radio'){
23010 hidden.name = this.name;
23011 input.name = '_hidden_' + this.name;
23016 input.cls += ' input-' + this.size;
23021 ['xs','sm','md','lg'].map(function(size){
23022 if (settings[size]) {
23023 cfg.cls += ' col-' + size + '-' + settings[size];
23027 var inputblock = input;
23029 if (this.before || this.after) {
23032 cls : 'input-group',
23037 inputblock.cn.push({
23039 cls : 'input-group-addon',
23044 inputblock.cn.push(input);
23046 if(this.inputType != 'radio'){
23047 inputblock.cn.push(hidden);
23051 inputblock.cn.push({
23053 cls : 'input-group-addon',
23059 var boxLabelCfg = false;
23065 //'for': id, // box label is handled by onclick - so no for...
23067 html: this.boxLabel
23070 boxLabelCfg.tooltip = this.tooltip;
23076 if (align ==='left' && this.fieldLabel.length) {
23077 // Roo.log("left and has label");
23082 cls : 'control-label',
23083 html : this.fieldLabel
23094 cfg.cn[1].cn.push(boxLabelCfg);
23097 if(this.labelWidth > 12){
23098 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
23101 if(this.labelWidth < 13 && this.labelmd == 0){
23102 this.labelmd = this.labelWidth;
23105 if(this.labellg > 0){
23106 cfg.cn[0].cls += ' col-lg-' + this.labellg;
23107 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
23110 if(this.labelmd > 0){
23111 cfg.cn[0].cls += ' col-md-' + this.labelmd;
23112 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
23115 if(this.labelsm > 0){
23116 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
23117 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
23120 if(this.labelxs > 0){
23121 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
23122 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
23125 } else if ( this.fieldLabel.length) {
23126 // Roo.log(" label");
23130 tag: this.boxLabel ? 'span' : 'label',
23132 cls: 'control-label box-input-label',
23133 //cls : 'input-group-addon',
23134 html : this.fieldLabel
23141 cfg.cn.push(boxLabelCfg);
23146 // Roo.log(" no label && no align");
23147 cfg.cn = [ inputblock ] ;
23149 cfg.cn.push(boxLabelCfg);
23157 if(this.inputType != 'radio'){
23158 cfg.cn.push(hidden);
23166 * return the real input element.
23168 inputEl: function ()
23170 return this.el.select('input.roo-' + this.inputType,true).first();
23172 hiddenEl: function ()
23174 return this.el.select('input.roo-hidden-value',true).first();
23177 labelEl: function()
23179 return this.el.select('label.control-label',true).first();
23181 /* depricated... */
23185 return this.labelEl();
23188 boxLabelEl: function()
23190 return this.el.select('label.box-label',true).first();
23193 initEvents : function()
23195 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
23197 this.inputEl().on('click', this.onClick, this);
23199 if (this.boxLabel) {
23200 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
23203 this.startValue = this.getValue();
23206 Roo.bootstrap.CheckBox.register(this);
23210 onClick : function(e)
23212 if(this.fireEvent('click', this, e) !== false){
23213 this.setChecked(!this.checked);
23218 setChecked : function(state,suppressEvent)
23220 this.startValue = this.getValue();
23222 if(this.inputType == 'radio'){
23224 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
23225 e.dom.checked = false;
23228 this.inputEl().dom.checked = true;
23230 this.inputEl().dom.value = this.inputValue;
23232 if(suppressEvent !== true){
23233 this.fireEvent('check', this, true);
23241 this.checked = state;
23243 this.inputEl().dom.checked = state;
23246 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
23248 if(suppressEvent !== true){
23249 this.fireEvent('check', this, state);
23255 getValue : function()
23257 if(this.inputType == 'radio'){
23258 return this.getGroupValue();
23261 return this.hiddenEl().dom.value;
23265 getGroupValue : function()
23267 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
23271 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
23274 setValue : function(v,suppressEvent)
23276 if(this.inputType == 'radio'){
23277 this.setGroupValue(v, suppressEvent);
23281 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
23286 setGroupValue : function(v, suppressEvent)
23288 this.startValue = this.getValue();
23290 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
23291 e.dom.checked = false;
23293 if(e.dom.value == v){
23294 e.dom.checked = true;
23298 if(suppressEvent !== true){
23299 this.fireEvent('check', this, true);
23307 validate : function()
23309 if(this.getVisibilityEl().hasClass('hidden')){
23315 (this.inputType == 'radio' && this.validateRadio()) ||
23316 (this.inputType == 'checkbox' && this.validateCheckbox())
23322 this.markInvalid();
23326 validateRadio : function()
23328 if(this.getVisibilityEl().hasClass('hidden')){
23332 if(this.allowBlank){
23338 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
23339 if(!e.dom.checked){
23351 validateCheckbox : function()
23354 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
23355 //return (this.getValue() == this.inputValue) ? true : false;
23358 var group = Roo.bootstrap.CheckBox.get(this.groupId);
23366 for(var i in group){
23367 if(group[i].el.isVisible(true)){
23375 for(var i in group){
23380 r = (group[i].getValue() == group[i].inputValue) ? true : false;
23387 * Mark this field as valid
23389 markValid : function()
23393 this.fireEvent('valid', this);
23395 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
23398 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
23405 if(this.inputType == 'radio'){
23406 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
23407 var fg = e.findParent('.form-group', false, true);
23408 if (Roo.bootstrap.version == 3) {
23409 fg.removeClass([_this.invalidClass, _this.validClass]);
23410 fg.addClass(_this.validClass);
23412 fg.removeClass(['is-valid', 'is-invalid']);
23413 fg.addClass('is-valid');
23421 var fg = this.el.findParent('.form-group', false, true);
23422 if (Roo.bootstrap.version == 3) {
23423 fg.removeClass([this.invalidClass, this.validClass]);
23424 fg.addClass(this.validClass);
23426 fg.removeClass(['is-valid', 'is-invalid']);
23427 fg.addClass('is-valid');
23432 var group = Roo.bootstrap.CheckBox.get(this.groupId);
23438 for(var i in group){
23439 var fg = group[i].el.findParent('.form-group', false, true);
23440 if (Roo.bootstrap.version == 3) {
23441 fg.removeClass([this.invalidClass, this.validClass]);
23442 fg.addClass(this.validClass);
23444 fg.removeClass(['is-valid', 'is-invalid']);
23445 fg.addClass('is-valid');
23451 * Mark this field as invalid
23452 * @param {String} msg The validation message
23454 markInvalid : function(msg)
23456 if(this.allowBlank){
23462 this.fireEvent('invalid', this, msg);
23464 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
23467 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
23471 label.markInvalid();
23474 if(this.inputType == 'radio'){
23476 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
23477 var fg = e.findParent('.form-group', false, true);
23478 if (Roo.bootstrap.version == 3) {
23479 fg.removeClass([_this.invalidClass, _this.validClass]);
23480 fg.addClass(_this.invalidClass);
23482 fg.removeClass(['is-invalid', 'is-valid']);
23483 fg.addClass('is-invalid');
23491 var fg = this.el.findParent('.form-group', false, true);
23492 if (Roo.bootstrap.version == 3) {
23493 fg.removeClass([_this.invalidClass, _this.validClass]);
23494 fg.addClass(_this.invalidClass);
23496 fg.removeClass(['is-invalid', 'is-valid']);
23497 fg.addClass('is-invalid');
23502 var group = Roo.bootstrap.CheckBox.get(this.groupId);
23508 for(var i in group){
23509 var fg = group[i].el.findParent('.form-group', false, true);
23510 if (Roo.bootstrap.version == 3) {
23511 fg.removeClass([_this.invalidClass, _this.validClass]);
23512 fg.addClass(_this.invalidClass);
23514 fg.removeClass(['is-invalid', 'is-valid']);
23515 fg.addClass('is-invalid');
23521 clearInvalid : function()
23523 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
23525 // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
23527 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
23529 if (label && label.iconEl) {
23530 label.iconEl.removeClass([ label.validClass, label.invalidClass ]);
23531 label.iconEl.removeClass(['is-invalid', 'is-valid']);
23535 disable : function()
23537 if(this.inputType != 'radio'){
23538 Roo.bootstrap.CheckBox.superclass.disable.call(this);
23545 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
23546 _this.getActionEl().addClass(this.disabledClass);
23547 e.dom.disabled = true;
23551 this.disabled = true;
23552 this.fireEvent("disable", this);
23556 enable : function()
23558 if(this.inputType != 'radio'){
23559 Roo.bootstrap.CheckBox.superclass.enable.call(this);
23566 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
23567 _this.getActionEl().removeClass(this.disabledClass);
23568 e.dom.disabled = false;
23572 this.disabled = false;
23573 this.fireEvent("enable", this);
23577 setBoxLabel : function(v)
23582 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
23588 Roo.apply(Roo.bootstrap.CheckBox, {
23593 * register a CheckBox Group
23594 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
23596 register : function(checkbox)
23598 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
23599 this.groups[checkbox.groupId] = {};
23602 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
23606 this.groups[checkbox.groupId][checkbox.name] = checkbox;
23610 * fetch a CheckBox Group based on the group ID
23611 * @param {string} the group ID
23612 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
23614 get: function(groupId) {
23615 if (typeof(this.groups[groupId]) == 'undefined') {
23619 return this.groups[groupId] ;
23632 * @class Roo.bootstrap.Radio
23633 * @extends Roo.bootstrap.Component
23634 * Bootstrap Radio class
23635 * @cfg {String} boxLabel - the label associated
23636 * @cfg {String} value - the value of radio
23639 * Create a new Radio
23640 * @param {Object} config The config object
23642 Roo.bootstrap.Radio = function(config){
23643 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
23647 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
23653 getAutoCreate : function()
23657 cls : 'form-group radio',
23662 html : this.boxLabel
23670 initEvents : function()
23672 this.parent().register(this);
23674 this.el.on('click', this.onClick, this);
23678 onClick : function(e)
23680 if(this.parent().fireEvent('click', this.parent(), this, e) !== false){
23681 this.setChecked(true);
23685 setChecked : function(state, suppressEvent)
23687 this.parent().setValue(this.value, suppressEvent);
23691 setBoxLabel : function(v)
23696 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
23711 * @class Roo.bootstrap.SecurePass
23712 * @extends Roo.bootstrap.Input
23713 * Bootstrap SecurePass class
23717 * Create a new SecurePass
23718 * @param {Object} config The config object
23721 Roo.bootstrap.SecurePass = function (config) {
23722 // these go here, so the translation tool can replace them..
23724 PwdEmpty: "Please type a password, and then retype it to confirm.",
23725 PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
23726 PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
23727 PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
23728 IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
23729 FNInPwd: "Your password can't contain your first name. Please type a different password.",
23730 LNInPwd: "Your password can't contain your last name. Please type a different password.",
23731 TooWeak: "Your password is Too Weak."
23733 this.meterLabel = "Password strength:";
23734 this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
23735 this.meterClass = [
23736 "roo-password-meter-tooweak",
23737 "roo-password-meter-weak",
23738 "roo-password-meter-medium",
23739 "roo-password-meter-strong",
23740 "roo-password-meter-grey"
23745 Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
23748 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
23750 * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
23752 * PwdEmpty: "Please type a password, and then retype it to confirm.",
23753 * PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
23754 * PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
23755 * PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
23756 * IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
23757 * FNInPwd: "Your password can't contain your first name. Please type a different password.",
23758 * LNInPwd: "Your password can't contain your last name. Please type a different password."
23768 * @cfg {String/Object} Label for the strength meter (defaults to
23769 * 'Password strength:')
23774 * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
23775 * ['Weak', 'Medium', 'Strong'])
23778 pwdStrengths: false,
23791 initEvents: function ()
23793 Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
23795 if (this.el.is('input[type=password]') && Roo.isSafari) {
23796 this.el.on('keydown', this.SafariOnKeyDown, this);
23799 this.el.on('keyup', this.checkStrength, this, {buffer: 50});
23802 onRender: function (ct, position)
23804 Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
23805 this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
23806 this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
23808 this.trigger.createChild({
23813 cls: 'roo-password-meter-grey col-xs-12',
23816 //width: this.meterWidth + 'px'
23820 cls: 'roo-password-meter-text'
23826 if (this.hideTrigger) {
23827 this.trigger.setDisplayed(false);
23829 this.setSize(this.width || '', this.height || '');
23832 onDestroy: function ()
23834 if (this.trigger) {
23835 this.trigger.removeAllListeners();
23836 this.trigger.remove();
23839 this.wrap.remove();
23841 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
23844 checkStrength: function ()
23846 var pwd = this.inputEl().getValue();
23847 if (pwd == this._lastPwd) {
23852 if (this.ClientSideStrongPassword(pwd)) {
23854 } else if (this.ClientSideMediumPassword(pwd)) {
23856 } else if (this.ClientSideWeakPassword(pwd)) {
23862 Roo.log('strength1: ' + strength);
23864 //var pm = this.trigger.child('div/div/div').dom;
23865 var pm = this.trigger.child('div/div');
23866 pm.removeClass(this.meterClass);
23867 pm.addClass(this.meterClass[strength]);
23870 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
23872 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
23874 this._lastPwd = pwd;
23878 Roo.bootstrap.SecurePass.superclass.reset.call(this);
23880 this._lastPwd = '';
23882 var pm = this.trigger.child('div/div');
23883 pm.removeClass(this.meterClass);
23884 pm.addClass('roo-password-meter-grey');
23887 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
23890 this.inputEl().dom.type='password';
23893 validateValue: function (value)
23895 if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
23898 if (value.length == 0) {
23899 if (this.allowBlank) {
23900 this.clearInvalid();
23904 this.markInvalid(this.errors.PwdEmpty);
23905 this.errorMsg = this.errors.PwdEmpty;
23913 if (!value.match(/[\x21-\x7e]+/)) {
23914 this.markInvalid(this.errors.PwdBadChar);
23915 this.errorMsg = this.errors.PwdBadChar;
23918 if (value.length < 6) {
23919 this.markInvalid(this.errors.PwdShort);
23920 this.errorMsg = this.errors.PwdShort;
23923 if (value.length > 16) {
23924 this.markInvalid(this.errors.PwdLong);
23925 this.errorMsg = this.errors.PwdLong;
23929 if (this.ClientSideStrongPassword(value)) {
23931 } else if (this.ClientSideMediumPassword(value)) {
23933 } else if (this.ClientSideWeakPassword(value)) {
23940 if (strength < 2) {
23941 //this.markInvalid(this.errors.TooWeak);
23942 this.errorMsg = this.errors.TooWeak;
23947 console.log('strength2: ' + strength);
23949 //var pm = this.trigger.child('div/div/div').dom;
23951 var pm = this.trigger.child('div/div');
23952 pm.removeClass(this.meterClass);
23953 pm.addClass(this.meterClass[strength]);
23955 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
23957 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
23959 this.errorMsg = '';
23963 CharacterSetChecks: function (type)
23966 this.fResult = false;
23969 isctype: function (character, type)
23972 case this.kCapitalLetter:
23973 if (character >= 'A' && character <= 'Z') {
23978 case this.kSmallLetter:
23979 if (character >= 'a' && character <= 'z') {
23985 if (character >= '0' && character <= '9') {
23990 case this.kPunctuation:
23991 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
24002 IsLongEnough: function (pwd, size)
24004 return !(pwd == null || isNaN(size) || pwd.length < size);
24007 SpansEnoughCharacterSets: function (word, nb)
24009 if (!this.IsLongEnough(word, nb))
24014 var characterSetChecks = new Array(
24015 new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
24016 new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
24019 for (var index = 0; index < word.length; ++index) {
24020 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
24021 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
24022 characterSetChecks[nCharSet].fResult = true;
24029 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
24030 if (characterSetChecks[nCharSet].fResult) {
24035 if (nCharSets < nb) {
24041 ClientSideStrongPassword: function (pwd)
24043 return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
24046 ClientSideMediumPassword: function (pwd)
24048 return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
24051 ClientSideWeakPassword: function (pwd)
24053 return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
24056 })//<script type="text/javascript">
24059 * Based Ext JS Library 1.1.1
24060 * Copyright(c) 2006-2007, Ext JS, LLC.
24066 * @class Roo.HtmlEditorCore
24067 * @extends Roo.Component
24068 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
24070 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
24073 Roo.HtmlEditorCore = function(config){
24076 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
24081 * @event initialize
24082 * Fires when the editor is fully initialized (including the iframe)
24083 * @param {Roo.HtmlEditorCore} this
24088 * Fires when the editor is first receives the focus. Any insertion must wait
24089 * until after this event.
24090 * @param {Roo.HtmlEditorCore} this
24094 * @event beforesync
24095 * Fires before the textarea is updated with content from the editor iframe. Return false
24096 * to cancel the sync.
24097 * @param {Roo.HtmlEditorCore} this
24098 * @param {String} html
24102 * @event beforepush
24103 * Fires before the iframe editor is updated with content from the textarea. Return false
24104 * to cancel the push.
24105 * @param {Roo.HtmlEditorCore} this
24106 * @param {String} html
24111 * Fires when the textarea is updated with content from the editor iframe.
24112 * @param {Roo.HtmlEditorCore} this
24113 * @param {String} html
24118 * Fires when the iframe editor is updated with content from the textarea.
24119 * @param {Roo.HtmlEditorCore} this
24120 * @param {String} html
24125 * @event editorevent
24126 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
24127 * @param {Roo.HtmlEditorCore} this
24133 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
24135 // defaults : white / black...
24136 this.applyBlacklists();
24143 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
24147 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
24153 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
24158 * @cfg {Number} height (in pixels)
24162 * @cfg {Number} width (in pixels)
24167 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
24170 stylesheets: false,
24175 // private properties
24176 validationEvent : false,
24178 initialized : false,
24180 sourceEditMode : false,
24181 onFocus : Roo.emptyFn,
24183 hideMode:'offsets',
24187 // blacklist + whitelisted elements..
24194 * Protected method that will not generally be called directly. It
24195 * is called when the editor initializes the iframe with HTML contents. Override this method if you
24196 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
24198 getDocMarkup : function(){
24202 // inherit styels from page...??
24203 if (this.stylesheets === false) {
24205 Roo.get(document.head).select('style').each(function(node) {
24206 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
24209 Roo.get(document.head).select('link').each(function(node) {
24210 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
24213 } else if (!this.stylesheets.length) {
24215 st = '<style type="text/css">' +
24216 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
24219 for (var i in this.stylesheets) {
24220 st += '<link rel="stylesheet" href="' + this.stylesheets[i] +'" type="text/css">';
24225 st += '<style type="text/css">' +
24226 'IMG { cursor: pointer } ' +
24229 var cls = 'roo-htmleditor-body';
24231 if(this.bodyCls.length){
24232 cls += ' ' + this.bodyCls;
24235 return '<html><head>' + st +
24236 //<style type="text/css">' +
24237 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
24239 ' </head><body contenteditable="true" data-enable-grammerly="true" class="' + cls + '"></body></html>';
24243 onRender : function(ct, position)
24246 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
24247 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
24250 this.el.dom.style.border = '0 none';
24251 this.el.dom.setAttribute('tabIndex', -1);
24252 this.el.addClass('x-hidden hide');
24256 if(Roo.isIE){ // fix IE 1px bogus margin
24257 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
24261 this.frameId = Roo.id();
24265 var iframe = this.owner.wrap.createChild({
24267 cls: 'form-control', // bootstrap..
24269 name: this.frameId,
24270 frameBorder : 'no',
24271 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
24276 this.iframe = iframe.dom;
24278 this.assignDocWin();
24280 this.doc.designMode = 'on';
24283 this.doc.write(this.getDocMarkup());
24287 var task = { // must defer to wait for browser to be ready
24289 //console.log("run task?" + this.doc.readyState);
24290 this.assignDocWin();
24291 if(this.doc.body || this.doc.readyState == 'complete'){
24293 this.doc.designMode="on";
24297 Roo.TaskMgr.stop(task);
24298 this.initEditor.defer(10, this);
24305 Roo.TaskMgr.start(task);
24310 onResize : function(w, h)
24312 Roo.log('resize: ' +w + ',' + h );
24313 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
24317 if(typeof w == 'number'){
24319 this.iframe.style.width = w + 'px';
24321 if(typeof h == 'number'){
24323 this.iframe.style.height = h + 'px';
24325 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
24332 * Toggles the editor between standard and source edit mode.
24333 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
24335 toggleSourceEdit : function(sourceEditMode){
24337 this.sourceEditMode = sourceEditMode === true;
24339 if(this.sourceEditMode){
24341 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
24344 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
24345 //this.iframe.className = '';
24348 //this.setSize(this.owner.wrap.getSize());
24349 //this.fireEvent('editmodechange', this, this.sourceEditMode);
24356 * Protected method that will not generally be called directly. If you need/want
24357 * custom HTML cleanup, this is the method you should override.
24358 * @param {String} html The HTML to be cleaned
24359 * return {String} The cleaned HTML
24361 cleanHtml : function(html){
24362 html = String(html);
24363 if(html.length > 5){
24364 if(Roo.isSafari){ // strip safari nonsense
24365 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
24368 if(html == ' '){
24375 * HTML Editor -> Textarea
24376 * Protected method that will not generally be called directly. Syncs the contents
24377 * of the editor iframe with the textarea.
24379 syncValue : function(){
24380 if(this.initialized){
24381 var bd = (this.doc.body || this.doc.documentElement);
24382 //this.cleanUpPaste(); -- this is done else where and causes havoc..
24383 var html = bd.innerHTML;
24385 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
24386 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
24388 html = '<div style="'+m[0]+'">' + html + '</div>';
24391 html = this.cleanHtml(html);
24392 // fix up the special chars.. normaly like back quotes in word...
24393 // however we do not want to do this with chinese..
24394 html = html.replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]|[\u0080-\uFFFF]/g, function(match) {
24396 var cc = match.charCodeAt();
24398 // Get the character value, handling surrogate pairs
24399 if (match.length == 2) {
24400 // It's a surrogate pair, calculate the Unicode code point
24401 var high = match.charCodeAt(0) - 0xD800;
24402 var low = match.charCodeAt(1) - 0xDC00;
24403 cc = (high * 0x400) + low + 0x10000;
24405 (cc >= 0x4E00 && cc < 0xA000 ) ||
24406 (cc >= 0x3400 && cc < 0x4E00 ) ||
24407 (cc >= 0xf900 && cc < 0xfb00 )
24412 // No, use a numeric entity. Here we brazenly (and possibly mistakenly)
24413 return "&#" + cc + ";";
24420 if(this.owner.fireEvent('beforesync', this, html) !== false){
24421 this.el.dom.value = html;
24422 this.owner.fireEvent('sync', this, html);
24428 * Protected method that will not generally be called directly. Pushes the value of the textarea
24429 * into the iframe editor.
24431 pushValue : function(){
24432 if(this.initialized){
24433 var v = this.el.dom.value.trim();
24435 // if(v.length < 1){
24439 if(this.owner.fireEvent('beforepush', this, v) !== false){
24440 var d = (this.doc.body || this.doc.documentElement);
24442 this.cleanUpPaste();
24443 this.el.dom.value = d.innerHTML;
24444 this.owner.fireEvent('push', this, v);
24450 deferFocus : function(){
24451 this.focus.defer(10, this);
24455 focus : function(){
24456 if(this.win && !this.sourceEditMode){
24463 assignDocWin: function()
24465 var iframe = this.iframe;
24468 this.doc = iframe.contentWindow.document;
24469 this.win = iframe.contentWindow;
24471 // if (!Roo.get(this.frameId)) {
24474 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
24475 // this.win = Roo.get(this.frameId).dom.contentWindow;
24477 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
24481 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
24482 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
24487 initEditor : function(){
24488 //console.log("INIT EDITOR");
24489 this.assignDocWin();
24493 this.doc.designMode="on";
24495 this.doc.write(this.getDocMarkup());
24498 var dbody = (this.doc.body || this.doc.documentElement);
24499 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
24500 // this copies styles from the containing element into thsi one..
24501 // not sure why we need all of this..
24502 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
24504 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
24505 //ss['background-attachment'] = 'fixed'; // w3c
24506 dbody.bgProperties = 'fixed'; // ie
24507 //Roo.DomHelper.applyStyles(dbody, ss);
24508 Roo.EventManager.on(this.doc, {
24509 //'mousedown': this.onEditorEvent,
24510 'mouseup': this.onEditorEvent,
24511 'dblclick': this.onEditorEvent,
24512 'click': this.onEditorEvent,
24513 'keyup': this.onEditorEvent,
24518 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
24520 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
24521 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
24523 this.initialized = true;
24525 this.owner.fireEvent('initialize', this);
24530 onDestroy : function(){
24536 //for (var i =0; i < this.toolbars.length;i++) {
24537 // // fixme - ask toolbars for heights?
24538 // this.toolbars[i].onDestroy();
24541 //this.wrap.dom.innerHTML = '';
24542 //this.wrap.remove();
24547 onFirstFocus : function(){
24549 this.assignDocWin();
24552 this.activated = true;
24555 if(Roo.isGecko){ // prevent silly gecko errors
24557 var s = this.win.getSelection();
24558 if(!s.focusNode || s.focusNode.nodeType != 3){
24559 var r = s.getRangeAt(0);
24560 r.selectNodeContents((this.doc.body || this.doc.documentElement));
24565 this.execCmd('useCSS', true);
24566 this.execCmd('styleWithCSS', false);
24569 this.owner.fireEvent('activate', this);
24573 adjustFont: function(btn){
24574 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
24575 //if(Roo.isSafari){ // safari
24578 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
24579 if(Roo.isSafari){ // safari
24580 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
24581 v = (v < 10) ? 10 : v;
24582 v = (v > 48) ? 48 : v;
24583 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
24588 v = Math.max(1, v+adjust);
24590 this.execCmd('FontSize', v );
24593 onEditorEvent : function(e)
24595 this.owner.fireEvent('editorevent', this, e);
24596 // this.updateToolbar();
24597 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
24600 insertTag : function(tg)
24602 // could be a bit smarter... -> wrap the current selected tRoo..
24603 if (tg.toLowerCase() == 'span' ||
24604 tg.toLowerCase() == 'code' ||
24605 tg.toLowerCase() == 'sup' ||
24606 tg.toLowerCase() == 'sub'
24609 range = this.createRange(this.getSelection());
24610 var wrappingNode = this.doc.createElement(tg.toLowerCase());
24611 wrappingNode.appendChild(range.extractContents());
24612 range.insertNode(wrappingNode);
24619 this.execCmd("formatblock", tg);
24623 insertText : function(txt)
24627 var range = this.createRange();
24628 range.deleteContents();
24629 //alert(Sender.getAttribute('label'));
24631 range.insertNode(this.doc.createTextNode(txt));
24637 * Executes a Midas editor command on the editor document and performs necessary focus and
24638 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
24639 * @param {String} cmd The Midas command
24640 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
24642 relayCmd : function(cmd, value){
24644 this.execCmd(cmd, value);
24645 this.owner.fireEvent('editorevent', this);
24646 //this.updateToolbar();
24647 this.owner.deferFocus();
24651 * Executes a Midas editor command directly on the editor document.
24652 * For visual commands, you should use {@link #relayCmd} instead.
24653 * <b>This should only be called after the editor is initialized.</b>
24654 * @param {String} cmd The Midas command
24655 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
24657 execCmd : function(cmd, value){
24658 this.doc.execCommand(cmd, false, value === undefined ? null : value);
24665 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
24667 * @param {String} text | dom node..
24669 insertAtCursor : function(text)
24672 if(!this.activated){
24678 var r = this.doc.selection.createRange();
24689 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
24693 // from jquery ui (MIT licenced)
24695 var win = this.win;
24697 if (win.getSelection && win.getSelection().getRangeAt) {
24698 range = win.getSelection().getRangeAt(0);
24699 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
24700 range.insertNode(node);
24701 } else if (win.document.selection && win.document.selection.createRange) {
24702 // no firefox support
24703 var txt = typeof(text) == 'string' ? text : text.outerHTML;
24704 win.document.selection.createRange().pasteHTML(txt);
24706 // no firefox support
24707 var txt = typeof(text) == 'string' ? text : text.outerHTML;
24708 this.execCmd('InsertHTML', txt);
24717 mozKeyPress : function(e){
24719 var c = e.getCharCode(), cmd;
24722 c = String.fromCharCode(c).toLowerCase();
24736 this.cleanUpPaste.defer(100, this);
24744 e.preventDefault();
24752 fixKeys : function(){ // load time branching for fastest keydown performance
24754 return function(e){
24755 var k = e.getKey(), r;
24758 r = this.doc.selection.createRange();
24761 r.pasteHTML('    ');
24768 r = this.doc.selection.createRange();
24770 var target = r.parentElement();
24771 if(!target || target.tagName.toLowerCase() != 'li'){
24773 r.pasteHTML('<br />');
24779 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
24780 this.cleanUpPaste.defer(100, this);
24786 }else if(Roo.isOpera){
24787 return function(e){
24788 var k = e.getKey();
24792 this.execCmd('InsertHTML','    ');
24795 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
24796 this.cleanUpPaste.defer(100, this);
24801 }else if(Roo.isSafari){
24802 return function(e){
24803 var k = e.getKey();
24807 this.execCmd('InsertText','\t');
24811 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
24812 this.cleanUpPaste.defer(100, this);
24820 getAllAncestors: function()
24822 var p = this.getSelectedNode();
24825 a.push(p); // push blank onto stack..
24826 p = this.getParentElement();
24830 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
24834 a.push(this.doc.body);
24838 lastSelNode : false,
24841 getSelection : function()
24843 this.assignDocWin();
24844 return Roo.isIE ? this.doc.selection : this.win.getSelection();
24847 getSelectedNode: function()
24849 // this may only work on Gecko!!!
24851 // should we cache this!!!!
24856 var range = this.createRange(this.getSelection()).cloneRange();
24859 var parent = range.parentElement();
24861 var testRange = range.duplicate();
24862 testRange.moveToElementText(parent);
24863 if (testRange.inRange(range)) {
24866 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
24869 parent = parent.parentElement;
24874 // is ancestor a text element.
24875 var ac = range.commonAncestorContainer;
24876 if (ac.nodeType == 3) {
24877 ac = ac.parentNode;
24880 var ar = ac.childNodes;
24883 var other_nodes = [];
24884 var has_other_nodes = false;
24885 for (var i=0;i<ar.length;i++) {
24886 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
24889 // fullly contained node.
24891 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
24896 // probably selected..
24897 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
24898 other_nodes.push(ar[i]);
24902 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
24907 has_other_nodes = true;
24909 if (!nodes.length && other_nodes.length) {
24910 nodes= other_nodes;
24912 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
24918 createRange: function(sel)
24920 // this has strange effects when using with
24921 // top toolbar - not sure if it's a great idea.
24922 //this.editor.contentWindow.focus();
24923 if (typeof sel != "undefined") {
24925 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
24927 return this.doc.createRange();
24930 return this.doc.createRange();
24933 getParentElement: function()
24936 this.assignDocWin();
24937 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
24939 var range = this.createRange(sel);
24942 var p = range.commonAncestorContainer;
24943 while (p.nodeType == 3) { // text node
24954 * Range intersection.. the hard stuff...
24958 * [ -- selected range --- ]
24962 * if end is before start or hits it. fail.
24963 * if start is after end or hits it fail.
24965 * if either hits (but other is outside. - then it's not
24971 // @see http://www.thismuchiknow.co.uk/?p=64.
24972 rangeIntersectsNode : function(range, node)
24974 var nodeRange = node.ownerDocument.createRange();
24976 nodeRange.selectNode(node);
24978 nodeRange.selectNodeContents(node);
24981 var rangeStartRange = range.cloneRange();
24982 rangeStartRange.collapse(true);
24984 var rangeEndRange = range.cloneRange();
24985 rangeEndRange.collapse(false);
24987 var nodeStartRange = nodeRange.cloneRange();
24988 nodeStartRange.collapse(true);
24990 var nodeEndRange = nodeRange.cloneRange();
24991 nodeEndRange.collapse(false);
24993 return rangeStartRange.compareBoundaryPoints(
24994 Range.START_TO_START, nodeEndRange) == -1 &&
24995 rangeEndRange.compareBoundaryPoints(
24996 Range.START_TO_START, nodeStartRange) == 1;
25000 rangeCompareNode : function(range, node)
25002 var nodeRange = node.ownerDocument.createRange();
25004 nodeRange.selectNode(node);
25006 nodeRange.selectNodeContents(node);
25010 range.collapse(true);
25012 nodeRange.collapse(true);
25014 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
25015 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
25017 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
25019 var nodeIsBefore = ss == 1;
25020 var nodeIsAfter = ee == -1;
25022 if (nodeIsBefore && nodeIsAfter) {
25025 if (!nodeIsBefore && nodeIsAfter) {
25026 return 1; //right trailed.
25029 if (nodeIsBefore && !nodeIsAfter) {
25030 return 2; // left trailed.
25036 // private? - in a new class?
25037 cleanUpPaste : function()
25039 // cleans up the whole document..
25040 Roo.log('cleanuppaste');
25042 this.cleanUpChildren(this.doc.body);
25043 var clean = this.cleanWordChars(this.doc.body.innerHTML);
25044 if (clean != this.doc.body.innerHTML) {
25045 this.doc.body.innerHTML = clean;
25050 cleanWordChars : function(input) {// change the chars to hex code
25051 var he = Roo.HtmlEditorCore;
25053 var output = input;
25054 Roo.each(he.swapCodes, function(sw) {
25055 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
25057 output = output.replace(swapper, sw[1]);
25064 cleanUpChildren : function (n)
25066 if (!n.childNodes.length) {
25069 for (var i = n.childNodes.length-1; i > -1 ; i--) {
25070 this.cleanUpChild(n.childNodes[i]);
25077 cleanUpChild : function (node)
25080 //console.log(node);
25081 if (node.nodeName == "#text") {
25082 // clean up silly Windows -- stuff?
25085 if (node.nodeName == "#comment") {
25086 node.parentNode.removeChild(node);
25087 // clean up silly Windows -- stuff?
25090 var lcname = node.tagName.toLowerCase();
25091 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
25092 // whitelist of tags..
25094 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
25096 node.parentNode.removeChild(node);
25101 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
25103 // spans with no attributes - just remove them..
25104 if ((!node.attributes || !node.attributes.length) && lcname == 'span') {
25105 remove_keep_children = true;
25108 // remove <a name=....> as rendering on yahoo mailer is borked with this.
25109 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
25111 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
25112 // remove_keep_children = true;
25115 if (remove_keep_children) {
25116 this.cleanUpChildren(node);
25117 // inserts everything just before this node...
25118 while (node.childNodes.length) {
25119 var cn = node.childNodes[0];
25120 node.removeChild(cn);
25121 node.parentNode.insertBefore(cn, node);
25123 node.parentNode.removeChild(node);
25127 if (!node.attributes || !node.attributes.length) {
25132 this.cleanUpChildren(node);
25136 function cleanAttr(n,v)
25139 if (v.match(/^\./) || v.match(/^\//)) {
25142 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/) || v.match(/^ftp:/)) {
25145 if (v.match(/^#/)) {
25148 if (v.match(/^\{/)) { // allow template editing.
25151 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
25152 node.removeAttribute(n);
25156 var cwhite = this.cwhite;
25157 var cblack = this.cblack;
25159 function cleanStyle(n,v)
25161 if (v.match(/expression/)) { //XSS?? should we even bother..
25162 node.removeAttribute(n);
25166 var parts = v.split(/;/);
25169 Roo.each(parts, function(p) {
25170 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
25174 var l = p.split(':').shift().replace(/\s+/g,'');
25175 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
25177 if ( cwhite.length && cblack.indexOf(l) > -1) {
25178 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
25179 //node.removeAttribute(n);
25183 // only allow 'c whitelisted system attributes'
25184 if ( cwhite.length && cwhite.indexOf(l) < 0) {
25185 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
25186 //node.removeAttribute(n);
25196 if (clean.length) {
25197 node.setAttribute(n, clean.join(';'));
25199 node.removeAttribute(n);
25205 for (var i = node.attributes.length-1; i > -1 ; i--) {
25206 var a = node.attributes[i];
25209 if (a.name.toLowerCase().substr(0,2)=='on') {
25210 node.removeAttribute(a.name);
25213 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
25214 node.removeAttribute(a.name);
25217 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
25218 cleanAttr(a.name,a.value); // fixme..
25221 if (a.name == 'style') {
25222 cleanStyle(a.name,a.value);
25225 /// clean up MS crap..
25226 // tecnically this should be a list of valid class'es..
25229 if (a.name == 'class') {
25230 if (a.value.match(/^Mso/)) {
25231 node.removeAttribute('class');
25234 if (a.value.match(/^body$/)) {
25235 node.removeAttribute('class');
25246 this.cleanUpChildren(node);
25252 * Clean up MS wordisms...
25254 cleanWord : function(node)
25257 this.cleanWord(this.doc.body);
25262 node.nodeName == 'SPAN' &&
25263 !node.hasAttributes() &&
25264 node.childNodes.length == 1 &&
25265 node.firstChild.nodeName == "#text"
25267 var textNode = node.firstChild;
25268 node.removeChild(textNode);
25269 if (node.getAttribute('lang') != 'zh-CN') { // do not space pad on chinese characters..
25270 node.parentNode.insertBefore(node.ownerDocument.createTextNode(" "), node);
25272 node.parentNode.insertBefore(textNode, node);
25273 if (node.getAttribute('lang') != 'zh-CN') { // do not space pad on chinese characters..
25274 node.parentNode.insertBefore(node.ownerDocument.createTextNode(" ") , node);
25276 node.parentNode.removeChild(node);
25279 if (node.nodeName == "#text") {
25280 // clean up silly Windows -- stuff?
25283 if (node.nodeName == "#comment") {
25284 node.parentNode.removeChild(node);
25285 // clean up silly Windows -- stuff?
25289 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
25290 node.parentNode.removeChild(node);
25293 //Roo.log(node.tagName);
25294 // remove - but keep children..
25295 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|v:|font)/)) {
25296 //Roo.log('-- removed');
25297 while (node.childNodes.length) {
25298 var cn = node.childNodes[0];
25299 node.removeChild(cn);
25300 node.parentNode.insertBefore(cn, node);
25301 // move node to parent - and clean it..
25302 this.cleanWord(cn);
25304 node.parentNode.removeChild(node);
25305 /// no need to iterate chidlren = it's got none..
25306 //this.iterateChildren(node, this.cleanWord);
25310 if (node.className.length) {
25312 var cn = node.className.split(/\W+/);
25314 Roo.each(cn, function(cls) {
25315 if (cls.match(/Mso[a-zA-Z]+/)) {
25320 node.className = cna.length ? cna.join(' ') : '';
25322 node.removeAttribute("class");
25326 if (node.hasAttribute("lang")) {
25327 node.removeAttribute("lang");
25330 if (node.hasAttribute("style")) {
25332 var styles = node.getAttribute("style").split(";");
25334 Roo.each(styles, function(s) {
25335 if (!s.match(/:/)) {
25338 var kv = s.split(":");
25339 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
25342 // what ever is left... we allow.
25345 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
25346 if (!nstyle.length) {
25347 node.removeAttribute('style');
25350 this.iterateChildren(node, this.cleanWord);
25356 * iterateChildren of a Node, calling fn each time, using this as the scole..
25357 * @param {DomNode} node node to iterate children of.
25358 * @param {Function} fn method of this class to call on each item.
25360 iterateChildren : function(node, fn)
25362 if (!node.childNodes.length) {
25365 for (var i = node.childNodes.length-1; i > -1 ; i--) {
25366 fn.call(this, node.childNodes[i])
25372 * cleanTableWidths.
25374 * Quite often pasting from word etc.. results in tables with column and widths.
25375 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
25378 cleanTableWidths : function(node)
25383 this.cleanTableWidths(this.doc.body);
25388 if (node.nodeName == "#text" || node.nodeName == "#comment") {
25391 Roo.log(node.tagName);
25392 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
25393 this.iterateChildren(node, this.cleanTableWidths);
25396 if (node.hasAttribute('width')) {
25397 node.removeAttribute('width');
25401 if (node.hasAttribute("style")) {
25404 var styles = node.getAttribute("style").split(";");
25406 Roo.each(styles, function(s) {
25407 if (!s.match(/:/)) {
25410 var kv = s.split(":");
25411 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
25414 // what ever is left... we allow.
25417 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
25418 if (!nstyle.length) {
25419 node.removeAttribute('style');
25423 this.iterateChildren(node, this.cleanTableWidths);
25431 domToHTML : function(currentElement, depth, nopadtext) {
25433 depth = depth || 0;
25434 nopadtext = nopadtext || false;
25436 if (!currentElement) {
25437 return this.domToHTML(this.doc.body);
25440 //Roo.log(currentElement);
25442 var allText = false;
25443 var nodeName = currentElement.nodeName;
25444 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
25446 if (nodeName == '#text') {
25448 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
25453 if (nodeName != 'BODY') {
25456 // Prints the node tagName, such as <A>, <IMG>, etc
25459 for(i = 0; i < currentElement.attributes.length;i++) {
25461 var aname = currentElement.attributes.item(i).name;
25462 if (!currentElement.attributes.item(i).value.length) {
25465 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
25468 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
25477 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
25480 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
25485 // Traverse the tree
25487 var currentElementChild = currentElement.childNodes.item(i);
25488 var allText = true;
25489 var innerHTML = '';
25491 while (currentElementChild) {
25492 // Formatting code (indent the tree so it looks nice on the screen)
25493 var nopad = nopadtext;
25494 if (lastnode == 'SPAN') {
25498 if (currentElementChild.nodeName == '#text') {
25499 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
25500 toadd = nopadtext ? toadd : toadd.trim();
25501 if (!nopad && toadd.length > 80) {
25502 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
25504 innerHTML += toadd;
25507 currentElementChild = currentElement.childNodes.item(i);
25513 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
25515 // Recursively traverse the tree structure of the child node
25516 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
25517 lastnode = currentElementChild.nodeName;
25519 currentElementChild=currentElement.childNodes.item(i);
25525 // The remaining code is mostly for formatting the tree
25526 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
25531 ret+= "</"+tagName+">";
25537 applyBlacklists : function()
25539 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
25540 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
25544 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
25545 if (b.indexOf(tag) > -1) {
25548 this.white.push(tag);
25552 Roo.each(w, function(tag) {
25553 if (b.indexOf(tag) > -1) {
25556 if (this.white.indexOf(tag) > -1) {
25559 this.white.push(tag);
25564 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
25565 if (w.indexOf(tag) > -1) {
25568 this.black.push(tag);
25572 Roo.each(b, function(tag) {
25573 if (w.indexOf(tag) > -1) {
25576 if (this.black.indexOf(tag) > -1) {
25579 this.black.push(tag);
25584 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
25585 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
25589 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
25590 if (b.indexOf(tag) > -1) {
25593 this.cwhite.push(tag);
25597 Roo.each(w, function(tag) {
25598 if (b.indexOf(tag) > -1) {
25601 if (this.cwhite.indexOf(tag) > -1) {
25604 this.cwhite.push(tag);
25609 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
25610 if (w.indexOf(tag) > -1) {
25613 this.cblack.push(tag);
25617 Roo.each(b, function(tag) {
25618 if (w.indexOf(tag) > -1) {
25621 if (this.cblack.indexOf(tag) > -1) {
25624 this.cblack.push(tag);
25629 setStylesheets : function(stylesheets)
25631 if(typeof(stylesheets) == 'string'){
25632 Roo.get(this.iframe.contentDocument.head).createChild({
25634 rel : 'stylesheet',
25643 Roo.each(stylesheets, function(s) {
25648 Roo.get(_this.iframe.contentDocument.head).createChild({
25650 rel : 'stylesheet',
25659 removeStylesheets : function()
25663 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
25668 setStyle : function(style)
25670 Roo.get(this.iframe.contentDocument.head).createChild({
25679 // hide stuff that is not compatible
25693 * @event specialkey
25697 * @cfg {String} fieldClass @hide
25700 * @cfg {String} focusClass @hide
25703 * @cfg {String} autoCreate @hide
25706 * @cfg {String} inputType @hide
25709 * @cfg {String} invalidClass @hide
25712 * @cfg {String} invalidText @hide
25715 * @cfg {String} msgFx @hide
25718 * @cfg {String} validateOnBlur @hide
25722 Roo.HtmlEditorCore.white = [
25723 'area', 'br', 'img', 'input', 'hr', 'wbr',
25725 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
25726 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
25727 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
25728 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
25729 'table', 'ul', 'xmp',
25731 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
25734 'dir', 'menu', 'ol', 'ul', 'dl',
25740 Roo.HtmlEditorCore.black = [
25741 // 'embed', 'object', // enable - backend responsiblity to clean thiese
25743 'base', 'basefont', 'bgsound', 'blink', 'body',
25744 'frame', 'frameset', 'head', 'html', 'ilayer',
25745 'iframe', 'layer', 'link', 'meta', 'object',
25746 'script', 'style' ,'title', 'xml' // clean later..
25748 Roo.HtmlEditorCore.clean = [
25749 'script', 'style', 'title', 'xml'
25751 Roo.HtmlEditorCore.remove = [
25756 Roo.HtmlEditorCore.ablack = [
25760 Roo.HtmlEditorCore.aclean = [
25761 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
25765 Roo.HtmlEditorCore.pwhite= [
25766 'http', 'https', 'mailto'
25769 // white listed style attributes.
25770 Roo.HtmlEditorCore.cwhite= [
25771 // 'text-align', /// default is to allow most things..
25777 // black listed style attributes.
25778 Roo.HtmlEditorCore.cblack= [
25779 // 'font-size' -- this can be set by the project
25783 Roo.HtmlEditorCore.swapCodes =[
25802 * @class Roo.bootstrap.HtmlEditor
25803 * @extends Roo.bootstrap.TextArea
25804 * Bootstrap HtmlEditor class
25807 * Create a new HtmlEditor
25808 * @param {Object} config The config object
25811 Roo.bootstrap.HtmlEditor = function(config){
25812 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
25813 if (!this.toolbars) {
25814 this.toolbars = [];
25817 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
25820 * @event initialize
25821 * Fires when the editor is fully initialized (including the iframe)
25822 * @param {HtmlEditor} this
25827 * Fires when the editor is first receives the focus. Any insertion must wait
25828 * until after this event.
25829 * @param {HtmlEditor} this
25833 * @event beforesync
25834 * Fires before the textarea is updated with content from the editor iframe. Return false
25835 * to cancel the sync.
25836 * @param {HtmlEditor} this
25837 * @param {String} html
25841 * @event beforepush
25842 * Fires before the iframe editor is updated with content from the textarea. Return false
25843 * to cancel the push.
25844 * @param {HtmlEditor} this
25845 * @param {String} html
25850 * Fires when the textarea is updated with content from the editor iframe.
25851 * @param {HtmlEditor} this
25852 * @param {String} html
25857 * Fires when the iframe editor is updated with content from the textarea.
25858 * @param {HtmlEditor} this
25859 * @param {String} html
25863 * @event editmodechange
25864 * Fires when the editor switches edit modes
25865 * @param {HtmlEditor} this
25866 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
25868 editmodechange: true,
25870 * @event editorevent
25871 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
25872 * @param {HtmlEditor} this
25876 * @event firstfocus
25877 * Fires when on first focus - needed by toolbars..
25878 * @param {HtmlEditor} this
25883 * Auto save the htmlEditor value as a file into Events
25884 * @param {HtmlEditor} this
25888 * @event savedpreview
25889 * preview the saved version of htmlEditor
25890 * @param {HtmlEditor} this
25897 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
25901 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
25906 * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
25911 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
25916 * @cfg {Number} height (in pixels)
25920 * @cfg {Number} width (in pixels)
25925 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
25928 stylesheets: false,
25933 // private properties
25934 validationEvent : false,
25936 initialized : false,
25939 onFocus : Roo.emptyFn,
25941 hideMode:'offsets',
25943 tbContainer : false,
25947 toolbarContainer :function() {
25948 return this.wrap.select('.x-html-editor-tb',true).first();
25952 * Protected method that will not generally be called directly. It
25953 * is called when the editor creates its toolbar. Override this method if you need to
25954 * add custom toolbar buttons.
25955 * @param {HtmlEditor} editor
25957 createToolbar : function(){
25958 Roo.log('renewing');
25959 Roo.log("create toolbars");
25961 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
25962 this.toolbars[0].render(this.toolbarContainer());
25966 // if (!editor.toolbars || !editor.toolbars.length) {
25967 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
25970 // for (var i =0 ; i < editor.toolbars.length;i++) {
25971 // editor.toolbars[i] = Roo.factory(
25972 // typeof(editor.toolbars[i]) == 'string' ?
25973 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
25974 // Roo.bootstrap.HtmlEditor);
25975 // editor.toolbars[i].init(editor);
25981 onRender : function(ct, position)
25983 // Roo.log("Call onRender: " + this.xtype);
25985 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
25987 this.wrap = this.inputEl().wrap({
25988 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
25991 this.editorcore.onRender(ct, position);
25993 if (this.resizable) {
25994 this.resizeEl = new Roo.Resizable(this.wrap, {
25998 minHeight : this.height,
25999 height: this.height,
26000 handles : this.resizable,
26003 resize : function(r, w, h) {
26004 _t.onResize(w,h); // -something
26010 this.createToolbar(this);
26013 if(!this.width && this.resizable){
26014 this.setSize(this.wrap.getSize());
26016 if (this.resizeEl) {
26017 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
26018 // should trigger onReize..
26024 onResize : function(w, h)
26026 Roo.log('resize: ' +w + ',' + h );
26027 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
26031 if(this.inputEl() ){
26032 if(typeof w == 'number'){
26033 var aw = w - this.wrap.getFrameWidth('lr');
26034 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
26037 if(typeof h == 'number'){
26038 var tbh = -11; // fixme it needs to tool bar size!
26039 for (var i =0; i < this.toolbars.length;i++) {
26040 // fixme - ask toolbars for heights?
26041 tbh += this.toolbars[i].el.getHeight();
26042 //if (this.toolbars[i].footer) {
26043 // tbh += this.toolbars[i].footer.el.getHeight();
26051 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
26052 ah -= 5; // knock a few pixes off for look..
26053 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
26057 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
26058 this.editorcore.onResize(ew,eh);
26063 * Toggles the editor between standard and source edit mode.
26064 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
26066 toggleSourceEdit : function(sourceEditMode)
26068 this.editorcore.toggleSourceEdit(sourceEditMode);
26070 if(this.editorcore.sourceEditMode){
26071 Roo.log('editor - showing textarea');
26074 // Roo.log(this.syncValue());
26076 this.inputEl().removeClass(['hide', 'x-hidden']);
26077 this.inputEl().dom.removeAttribute('tabIndex');
26078 this.inputEl().focus();
26080 Roo.log('editor - hiding textarea');
26082 // Roo.log(this.pushValue());
26085 this.inputEl().addClass(['hide', 'x-hidden']);
26086 this.inputEl().dom.setAttribute('tabIndex', -1);
26087 //this.deferFocus();
26090 if(this.resizable){
26091 this.setSize(this.wrap.getSize());
26094 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
26097 // private (for BoxComponent)
26098 adjustSize : Roo.BoxComponent.prototype.adjustSize,
26100 // private (for BoxComponent)
26101 getResizeEl : function(){
26105 // private (for BoxComponent)
26106 getPositionEl : function(){
26111 initEvents : function(){
26112 this.originalValue = this.getValue();
26116 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
26119 // markInvalid : Roo.emptyFn,
26121 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
26124 // clearInvalid : Roo.emptyFn,
26126 setValue : function(v){
26127 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
26128 this.editorcore.pushValue();
26133 deferFocus : function(){
26134 this.focus.defer(10, this);
26138 focus : function(){
26139 this.editorcore.focus();
26145 onDestroy : function(){
26151 for (var i =0; i < this.toolbars.length;i++) {
26152 // fixme - ask toolbars for heights?
26153 this.toolbars[i].onDestroy();
26156 this.wrap.dom.innerHTML = '';
26157 this.wrap.remove();
26162 onFirstFocus : function(){
26163 //Roo.log("onFirstFocus");
26164 this.editorcore.onFirstFocus();
26165 for (var i =0; i < this.toolbars.length;i++) {
26166 this.toolbars[i].onFirstFocus();
26172 syncValue : function()
26174 this.editorcore.syncValue();
26177 pushValue : function()
26179 this.editorcore.pushValue();
26183 // hide stuff that is not compatible
26197 * @event specialkey
26201 * @cfg {String} fieldClass @hide
26204 * @cfg {String} focusClass @hide
26207 * @cfg {String} autoCreate @hide
26210 * @cfg {String} inputType @hide
26214 * @cfg {String} invalidText @hide
26217 * @cfg {String} msgFx @hide
26220 * @cfg {String} validateOnBlur @hide
26229 Roo.namespace('Roo.bootstrap.htmleditor');
26231 * @class Roo.bootstrap.HtmlEditorToolbar1
26237 new Roo.bootstrap.HtmlEditor({
26240 new Roo.bootstrap.HtmlEditorToolbar1({
26241 disable : { fonts: 1 , format: 1, ..., ... , ...],
26247 * @cfg {Object} disable List of elements to disable..
26248 * @cfg {Array} btns List of additional buttons.
26252 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
26255 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
26258 Roo.apply(this, config);
26260 // default disabled, based on 'good practice'..
26261 this.disable = this.disable || {};
26262 Roo.applyIf(this.disable, {
26265 specialElements : true
26267 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
26269 this.editor = config.editor;
26270 this.editorcore = config.editor.editorcore;
26272 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
26274 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
26275 // dont call parent... till later.
26277 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
26282 editorcore : false,
26287 "h1","h2","h3","h4","h5","h6",
26289 "abbr", "acronym", "address", "cite", "samp", "var",
26293 onRender : function(ct, position)
26295 // Roo.log("Call onRender: " + this.xtype);
26297 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
26299 this.el.dom.style.marginBottom = '0';
26301 var editorcore = this.editorcore;
26302 var editor= this.editor;
26305 var btn = function(id,cmd , toggle, handler, html){
26307 var event = toggle ? 'toggle' : 'click';
26312 xns: Roo.bootstrap,
26316 enableToggle:toggle !== false,
26318 pressed : toggle ? false : null,
26321 a.listeners[toggle ? 'toggle' : 'click'] = function() {
26322 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
26328 // var cb_box = function...
26333 xns: Roo.bootstrap,
26338 xns: Roo.bootstrap,
26342 Roo.each(this.formats, function(f) {
26343 style.menu.items.push({
26345 xns: Roo.bootstrap,
26346 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
26351 editorcore.insertTag(this.tagname);
26358 children.push(style);
26360 btn('bold',false,true);
26361 btn('italic',false,true);
26362 btn('align-left', 'justifyleft',true);
26363 btn('align-center', 'justifycenter',true);
26364 btn('align-right' , 'justifyright',true);
26365 btn('link', false, false, function(btn) {
26366 //Roo.log("create link?");
26367 var url = prompt(this.createLinkText, this.defaultLinkValue);
26368 if(url && url != 'http:/'+'/'){
26369 this.editorcore.relayCmd('createlink', url);
26372 btn('list','insertunorderedlist',true);
26373 btn('pencil', false,true, function(btn){
26375 this.toggleSourceEdit(btn.pressed);
26378 if (this.editor.btns.length > 0) {
26379 for (var i = 0; i<this.editor.btns.length; i++) {
26380 children.push(this.editor.btns[i]);
26388 xns: Roo.bootstrap,
26393 xns: Roo.bootstrap,
26398 cog.menu.items.push({
26400 xns: Roo.bootstrap,
26401 html : Clean styles,
26406 editorcore.insertTag(this.tagname);
26415 this.xtype = 'NavSimplebar';
26417 for(var i=0;i< children.length;i++) {
26419 this.buttons.add(this.addxtypeChild(children[i]));
26423 editor.on('editorevent', this.updateToolbar, this);
26425 onBtnClick : function(id)
26427 this.editorcore.relayCmd(id);
26428 this.editorcore.focus();
26432 * Protected method that will not generally be called directly. It triggers
26433 * a toolbar update by reading the markup state of the current selection in the editor.
26435 updateToolbar: function(){
26437 if(!this.editorcore.activated){
26438 this.editor.onFirstFocus(); // is this neeed?
26442 var btns = this.buttons;
26443 var doc = this.editorcore.doc;
26444 btns.get('bold').setActive(doc.queryCommandState('bold'));
26445 btns.get('italic').setActive(doc.queryCommandState('italic'));
26446 //btns.get('underline').setActive(doc.queryCommandState('underline'));
26448 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
26449 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
26450 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
26452 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
26453 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
26456 var ans = this.editorcore.getAllAncestors();
26457 if (this.formatCombo) {
26460 var store = this.formatCombo.store;
26461 this.formatCombo.setValue("");
26462 for (var i =0; i < ans.length;i++) {
26463 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
26465 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
26473 // hides menus... - so this cant be on a menu...
26474 Roo.bootstrap.MenuMgr.hideAll();
26476 Roo.bootstrap.MenuMgr.hideAll();
26477 //this.editorsyncValue();
26479 onFirstFocus: function() {
26480 this.buttons.each(function(item){
26484 toggleSourceEdit : function(sourceEditMode){
26487 if(sourceEditMode){
26488 Roo.log("disabling buttons");
26489 this.buttons.each( function(item){
26490 if(item.cmd != 'pencil'){
26496 Roo.log("enabling buttons");
26497 if(this.editorcore.initialized){
26498 this.buttons.each( function(item){
26504 Roo.log("calling toggole on editor");
26505 // tell the editor that it's been pressed..
26506 this.editor.toggleSourceEdit(sourceEditMode);
26520 * @class Roo.bootstrap.Markdown
26521 * @extends Roo.bootstrap.TextArea
26522 * Bootstrap Showdown editable area
26523 * @cfg {string} content
26526 * Create a new Showdown
26529 Roo.bootstrap.Markdown = function(config){
26530 Roo.bootstrap.Markdown.superclass.constructor.call(this, config);
26534 Roo.extend(Roo.bootstrap.Markdown, Roo.bootstrap.TextArea, {
26538 initEvents : function()
26541 Roo.bootstrap.TextArea.prototype.initEvents.call(this);
26542 this.markdownEl = this.el.createChild({
26543 cls : 'roo-markdown-area'
26545 this.inputEl().addClass('d-none');
26546 if (this.getValue() == '') {
26547 this.markdownEl.dom.innerHTML = String.format('<span class="roo-placeholder">{0}</span>', this.placeholder || '');
26550 this.markdownEl.dom.innerHTML = Roo.Markdown.toHtml(Roo.util.Format.htmlEncode(this.getValue()));
26552 this.markdownEl.on('click', this.toggleTextEdit, this);
26553 this.on('blur', this.toggleTextEdit, this);
26554 this.on('specialkey', this.resizeTextArea, this);
26557 toggleTextEdit : function()
26559 var sh = this.markdownEl.getHeight();
26560 this.inputEl().addClass('d-none');
26561 this.markdownEl.addClass('d-none');
26562 if (!this.editing) {
26564 this.inputEl().setHeight(Math.min(500, Math.max(sh,(this.getValue().split("\n").length+1) * 30)));
26565 this.inputEl().removeClass('d-none');
26566 this.inputEl().focus();
26567 this.editing = true;
26570 // show showdown...
26571 this.updateMarkdown();
26572 this.markdownEl.removeClass('d-none');
26573 this.editing = false;
26576 updateMarkdown : function()
26578 if (this.getValue() == '') {
26579 this.markdownEl.dom.innerHTML = String.format('<span class="roo-placeholder">{0}</span>', this.placeholder || '');
26583 this.markdownEl.dom.innerHTML = Roo.Markdown.toHtml(Roo.util.Format.htmlEncode(this.getValue()));
26586 resizeTextArea: function () {
26589 Roo.log([sh, this.getValue().split("\n").length * 30]);
26590 this.inputEl().setHeight(Math.min(500, Math.max(sh, (this.getValue().split("\n").length +1) * 30)));
26592 setValue : function(val)
26594 Roo.bootstrap.TextArea.prototype.setValue.call(this,val);
26595 if (!this.editing) {
26596 this.updateMarkdown();
26602 if (!this.editing) {
26603 this.toggleTextEdit();
26611 * @class Roo.bootstrap.Table.AbstractSelectionModel
26612 * @extends Roo.util.Observable
26613 * Abstract base class for grid SelectionModels. It provides the interface that should be
26614 * implemented by descendant classes. This class should not be directly instantiated.
26617 Roo.bootstrap.Table.AbstractSelectionModel = function(){
26618 this.locked = false;
26619 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
26623 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
26624 /** @ignore Called by the grid automatically. Do not call directly. */
26625 init : function(grid){
26631 * Locks the selections.
26634 this.locked = true;
26638 * Unlocks the selections.
26640 unlock : function(){
26641 this.locked = false;
26645 * Returns true if the selections are locked.
26646 * @return {Boolean}
26648 isLocked : function(){
26649 return this.locked;
26653 initEvents : function ()
26659 * @extends Roo.bootstrap.Table.AbstractSelectionModel
26660 * @class Roo.bootstrap.Table.RowSelectionModel
26661 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
26662 * It supports multiple selections and keyboard selection/navigation.
26664 * @param {Object} config
26667 Roo.bootstrap.Table.RowSelectionModel = function(config){
26668 Roo.apply(this, config);
26669 this.selections = new Roo.util.MixedCollection(false, function(o){
26674 this.lastActive = false;
26678 * @event selectionchange
26679 * Fires when the selection changes
26680 * @param {SelectionModel} this
26682 "selectionchange" : true,
26684 * @event afterselectionchange
26685 * Fires after the selection changes (eg. by key press or clicking)
26686 * @param {SelectionModel} this
26688 "afterselectionchange" : true,
26690 * @event beforerowselect
26691 * Fires when a row is selected being selected, return false to cancel.
26692 * @param {SelectionModel} this
26693 * @param {Number} rowIndex The selected index
26694 * @param {Boolean} keepExisting False if other selections will be cleared
26696 "beforerowselect" : true,
26699 * Fires when a row is selected.
26700 * @param {SelectionModel} this
26701 * @param {Number} rowIndex The selected index
26702 * @param {Roo.data.Record} r The record
26704 "rowselect" : true,
26706 * @event rowdeselect
26707 * Fires when a row is deselected.
26708 * @param {SelectionModel} this
26709 * @param {Number} rowIndex The selected index
26711 "rowdeselect" : true
26713 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
26714 this.locked = false;
26717 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
26719 * @cfg {Boolean} singleSelect
26720 * True to allow selection of only one row at a time (defaults to false)
26722 singleSelect : false,
26725 initEvents : function()
26728 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
26729 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
26730 //}else{ // allow click to work like normal
26731 // this.grid.on("rowclick", this.handleDragableRowClick, this);
26733 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
26734 this.grid.on("rowclick", this.handleMouseDown, this);
26736 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
26737 "up" : function(e){
26739 this.selectPrevious(e.shiftKey);
26740 }else if(this.last !== false && this.lastActive !== false){
26741 var last = this.last;
26742 this.selectRange(this.last, this.lastActive-1);
26743 this.grid.getView().focusRow(this.lastActive);
26744 if(last !== false){
26748 this.selectFirstRow();
26750 this.fireEvent("afterselectionchange", this);
26752 "down" : function(e){
26754 this.selectNext(e.shiftKey);
26755 }else if(this.last !== false && this.lastActive !== false){
26756 var last = this.last;
26757 this.selectRange(this.last, this.lastActive+1);
26758 this.grid.getView().focusRow(this.lastActive);
26759 if(last !== false){
26763 this.selectFirstRow();
26765 this.fireEvent("afterselectionchange", this);
26769 this.grid.store.on('load', function(){
26770 this.selections.clear();
26773 var view = this.grid.view;
26774 view.on("refresh", this.onRefresh, this);
26775 view.on("rowupdated", this.onRowUpdated, this);
26776 view.on("rowremoved", this.onRemove, this);
26781 onRefresh : function()
26783 var ds = this.grid.store, i, v = this.grid.view;
26784 var s = this.selections;
26785 s.each(function(r){
26786 if((i = ds.indexOfId(r.id)) != -1){
26795 onRemove : function(v, index, r){
26796 this.selections.remove(r);
26800 onRowUpdated : function(v, index, r){
26801 if(this.isSelected(r)){
26802 v.onRowSelect(index);
26808 * @param {Array} records The records to select
26809 * @param {Boolean} keepExisting (optional) True to keep existing selections
26811 selectRecords : function(records, keepExisting)
26814 this.clearSelections();
26816 var ds = this.grid.store;
26817 for(var i = 0, len = records.length; i < len; i++){
26818 this.selectRow(ds.indexOf(records[i]), true);
26823 * Gets the number of selected rows.
26826 getCount : function(){
26827 return this.selections.length;
26831 * Selects the first row in the grid.
26833 selectFirstRow : function(){
26838 * Select the last row.
26839 * @param {Boolean} keepExisting (optional) True to keep existing selections
26841 selectLastRow : function(keepExisting){
26842 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
26843 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
26847 * Selects the row immediately following the last selected row.
26848 * @param {Boolean} keepExisting (optional) True to keep existing selections
26850 selectNext : function(keepExisting)
26852 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
26853 this.selectRow(this.last+1, keepExisting);
26854 this.grid.getView().focusRow(this.last);
26859 * Selects the row that precedes the last selected row.
26860 * @param {Boolean} keepExisting (optional) True to keep existing selections
26862 selectPrevious : function(keepExisting){
26864 this.selectRow(this.last-1, keepExisting);
26865 this.grid.getView().focusRow(this.last);
26870 * Returns the selected records
26871 * @return {Array} Array of selected records
26873 getSelections : function(){
26874 return [].concat(this.selections.items);
26878 * Returns the first selected record.
26881 getSelected : function(){
26882 return this.selections.itemAt(0);
26887 * Clears all selections.
26889 clearSelections : function(fast)
26895 var ds = this.grid.store;
26896 var s = this.selections;
26897 s.each(function(r){
26898 this.deselectRow(ds.indexOfId(r.id));
26902 this.selections.clear();
26909 * Selects all rows.
26911 selectAll : function(){
26915 this.selections.clear();
26916 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
26917 this.selectRow(i, true);
26922 * Returns True if there is a selection.
26923 * @return {Boolean}
26925 hasSelection : function(){
26926 return this.selections.length > 0;
26930 * Returns True if the specified row is selected.
26931 * @param {Number/Record} record The record or index of the record to check
26932 * @return {Boolean}
26934 isSelected : function(index){
26935 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
26936 return (r && this.selections.key(r.id) ? true : false);
26940 * Returns True if the specified record id is selected.
26941 * @param {String} id The id of record to check
26942 * @return {Boolean}
26944 isIdSelected : function(id){
26945 return (this.selections.key(id) ? true : false);
26950 handleMouseDBClick : function(e, t){
26954 handleMouseDown : function(e, t)
26956 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
26957 if(this.isLocked() || rowIndex < 0 ){
26960 if(e.shiftKey && this.last !== false){
26961 var last = this.last;
26962 this.selectRange(last, rowIndex, e.ctrlKey);
26963 this.last = last; // reset the last
26967 var isSelected = this.isSelected(rowIndex);
26968 //Roo.log("select row:" + rowIndex);
26970 this.deselectRow(rowIndex);
26972 this.selectRow(rowIndex, true);
26976 if(e.button !== 0 && isSelected){
26977 alert('rowIndex 2: ' + rowIndex);
26978 view.focusRow(rowIndex);
26979 }else if(e.ctrlKey && isSelected){
26980 this.deselectRow(rowIndex);
26981 }else if(!isSelected){
26982 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
26983 view.focusRow(rowIndex);
26987 this.fireEvent("afterselectionchange", this);
26990 handleDragableRowClick : function(grid, rowIndex, e)
26992 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
26993 this.selectRow(rowIndex, false);
26994 grid.view.focusRow(rowIndex);
26995 this.fireEvent("afterselectionchange", this);
27000 * Selects multiple rows.
27001 * @param {Array} rows Array of the indexes of the row to select
27002 * @param {Boolean} keepExisting (optional) True to keep existing selections
27004 selectRows : function(rows, keepExisting){
27006 this.clearSelections();
27008 for(var i = 0, len = rows.length; i < len; i++){
27009 this.selectRow(rows[i], true);
27014 * Selects a range of rows. All rows in between startRow and endRow are also selected.
27015 * @param {Number} startRow The index of the first row in the range
27016 * @param {Number} endRow The index of the last row in the range
27017 * @param {Boolean} keepExisting (optional) True to retain existing selections
27019 selectRange : function(startRow, endRow, keepExisting){
27024 this.clearSelections();
27026 if(startRow <= endRow){
27027 for(var i = startRow; i <= endRow; i++){
27028 this.selectRow(i, true);
27031 for(var i = startRow; i >= endRow; i--){
27032 this.selectRow(i, true);
27038 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
27039 * @param {Number} startRow The index of the first row in the range
27040 * @param {Number} endRow The index of the last row in the range
27042 deselectRange : function(startRow, endRow, preventViewNotify){
27046 for(var i = startRow; i <= endRow; i++){
27047 this.deselectRow(i, preventViewNotify);
27053 * @param {Number} row The index of the row to select
27054 * @param {Boolean} keepExisting (optional) True to keep existing selections
27056 selectRow : function(index, keepExisting, preventViewNotify)
27058 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
27061 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
27062 if(!keepExisting || this.singleSelect){
27063 this.clearSelections();
27066 var r = this.grid.store.getAt(index);
27067 //console.log('selectRow - record id :' + r.id);
27069 this.selections.add(r);
27070 this.last = this.lastActive = index;
27071 if(!preventViewNotify){
27072 var proxy = new Roo.Element(
27073 this.grid.getRowDom(index)
27075 proxy.addClass('bg-info info');
27077 this.fireEvent("rowselect", this, index, r);
27078 this.fireEvent("selectionchange", this);
27084 * @param {Number} row The index of the row to deselect
27086 deselectRow : function(index, preventViewNotify)
27091 if(this.last == index){
27094 if(this.lastActive == index){
27095 this.lastActive = false;
27098 var r = this.grid.store.getAt(index);
27103 this.selections.remove(r);
27104 //.console.log('deselectRow - record id :' + r.id);
27105 if(!preventViewNotify){
27107 var proxy = new Roo.Element(
27108 this.grid.getRowDom(index)
27110 proxy.removeClass('bg-info info');
27112 this.fireEvent("rowdeselect", this, index);
27113 this.fireEvent("selectionchange", this);
27117 restoreLast : function(){
27119 this.last = this._last;
27124 acceptsNav : function(row, col, cm){
27125 return !cm.isHidden(col) && cm.isCellEditable(col, row);
27129 onEditorKey : function(field, e){
27130 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
27135 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
27137 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
27139 }else if(k == e.ENTER && !e.ctrlKey){
27143 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
27145 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
27147 }else if(k == e.ESC){
27151 g.startEditing(newCell[0], newCell[1]);
27157 * Ext JS Library 1.1.1
27158 * Copyright(c) 2006-2007, Ext JS, LLC.
27160 * Originally Released Under LGPL - original licence link has changed is not relivant.
27163 * <script type="text/javascript">
27167 * @class Roo.bootstrap.PagingToolbar
27168 * @extends Roo.bootstrap.NavSimplebar
27169 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
27171 * Create a new PagingToolbar
27172 * @param {Object} config The config object
27173 * @param {Roo.data.Store} store
27175 Roo.bootstrap.PagingToolbar = function(config)
27177 // old args format still supported... - xtype is prefered..
27178 // created from xtype...
27180 this.ds = config.dataSource;
27182 if (config.store && !this.ds) {
27183 this.store= Roo.factory(config.store, Roo.data);
27184 this.ds = this.store;
27185 this.ds.xmodule = this.xmodule || false;
27188 this.toolbarItems = [];
27189 if (config.items) {
27190 this.toolbarItems = config.items;
27193 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
27198 this.bind(this.ds);
27201 if (Roo.bootstrap.version == 4) {
27202 this.navgroup = new Roo.bootstrap.ButtonGroup({ cls: 'pagination' });
27204 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
27209 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
27211 * @cfg {Roo.data.Store} dataSource
27212 * The underlying data store providing the paged data
27215 * @cfg {String/HTMLElement/Element} container
27216 * container The id or element that will contain the toolbar
27219 * @cfg {Boolean} displayInfo
27220 * True to display the displayMsg (defaults to false)
27223 * @cfg {Number} pageSize
27224 * The number of records to display per page (defaults to 20)
27228 * @cfg {String} displayMsg
27229 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
27231 displayMsg : 'Displaying {0} - {1} of {2}',
27233 * @cfg {String} emptyMsg
27234 * The message to display when no records are found (defaults to "No data to display")
27236 emptyMsg : 'No data to display',
27238 * Customizable piece of the default paging text (defaults to "Page")
27241 beforePageText : "Page",
27243 * Customizable piece of the default paging text (defaults to "of %0")
27246 afterPageText : "of {0}",
27248 * Customizable piece of the default paging text (defaults to "First Page")
27251 firstText : "First Page",
27253 * Customizable piece of the default paging text (defaults to "Previous Page")
27256 prevText : "Previous Page",
27258 * Customizable piece of the default paging text (defaults to "Next Page")
27261 nextText : "Next Page",
27263 * Customizable piece of the default paging text (defaults to "Last Page")
27266 lastText : "Last Page",
27268 * Customizable piece of the default paging text (defaults to "Refresh")
27271 refreshText : "Refresh",
27275 onRender : function(ct, position)
27277 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
27278 this.navgroup.parentId = this.id;
27279 this.navgroup.onRender(this.el, null);
27280 // add the buttons to the navgroup
27282 if(this.displayInfo){
27283 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
27284 this.displayEl = this.el.select('.x-paging-info', true).first();
27285 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
27286 // this.displayEl = navel.el.select('span',true).first();
27292 Roo.each(_this.buttons, function(e){ // this might need to use render????
27293 Roo.factory(e).render(_this.el);
27297 Roo.each(_this.toolbarItems, function(e) {
27298 _this.navgroup.addItem(e);
27302 this.first = this.navgroup.addItem({
27303 tooltip: this.firstText,
27304 cls: "prev btn-outline-secondary",
27305 html : ' <i class="fa fa-step-backward"></i>',
27307 preventDefault: true,
27308 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
27311 this.prev = this.navgroup.addItem({
27312 tooltip: this.prevText,
27313 cls: "prev btn-outline-secondary",
27314 html : ' <i class="fa fa-backward"></i>',
27316 preventDefault: true,
27317 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
27319 //this.addSeparator();
27322 var field = this.navgroup.addItem( {
27324 cls : 'x-paging-position btn-outline-secondary',
27326 html : this.beforePageText +
27327 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
27328 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
27331 this.field = field.el.select('input', true).first();
27332 this.field.on("keydown", this.onPagingKeydown, this);
27333 this.field.on("focus", function(){this.dom.select();});
27336 this.afterTextEl = field.el.select('.x-paging-after',true).first();
27337 //this.field.setHeight(18);
27338 //this.addSeparator();
27339 this.next = this.navgroup.addItem({
27340 tooltip: this.nextText,
27341 cls: "next btn-outline-secondary",
27342 html : ' <i class="fa fa-forward"></i>',
27344 preventDefault: true,
27345 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
27347 this.last = this.navgroup.addItem({
27348 tooltip: this.lastText,
27349 html : ' <i class="fa fa-step-forward"></i>',
27350 cls: "next btn-outline-secondary",
27352 preventDefault: true,
27353 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
27355 //this.addSeparator();
27356 this.loading = this.navgroup.addItem({
27357 tooltip: this.refreshText,
27358 cls: "btn-outline-secondary",
27359 html : ' <i class="fa fa-refresh"></i>',
27360 preventDefault: true,
27361 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
27367 updateInfo : function(){
27368 if(this.displayEl){
27369 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
27370 var msg = count == 0 ?
27374 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
27376 this.displayEl.update(msg);
27381 onLoad : function(ds, r, o)
27383 this.cursor = o.params && o.params.start ? o.params.start : 0;
27385 var d = this.getPageData(),
27390 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
27391 this.field.dom.value = ap;
27392 this.first.setDisabled(ap == 1);
27393 this.prev.setDisabled(ap == 1);
27394 this.next.setDisabled(ap == ps);
27395 this.last.setDisabled(ap == ps);
27396 this.loading.enable();
27401 getPageData : function(){
27402 var total = this.ds.getTotalCount();
27405 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
27406 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
27411 onLoadError : function(){
27412 this.loading.enable();
27416 onPagingKeydown : function(e){
27417 var k = e.getKey();
27418 var d = this.getPageData();
27420 var v = this.field.dom.value, pageNum;
27421 if(!v || isNaN(pageNum = parseInt(v, 10))){
27422 this.field.dom.value = d.activePage;
27425 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
27426 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
27429 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))
27431 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
27432 this.field.dom.value = pageNum;
27433 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
27436 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
27438 var v = this.field.dom.value, pageNum;
27439 var increment = (e.shiftKey) ? 10 : 1;
27440 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
27443 if(!v || isNaN(pageNum = parseInt(v, 10))) {
27444 this.field.dom.value = d.activePage;
27447 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
27449 this.field.dom.value = parseInt(v, 10) + increment;
27450 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
27451 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
27458 beforeLoad : function(){
27460 this.loading.disable();
27465 onClick : function(which){
27474 ds.load({params:{start: 0, limit: this.pageSize}});
27477 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
27480 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
27483 var total = ds.getTotalCount();
27484 var extra = total % this.pageSize;
27485 var lastStart = extra ? (total - extra) : total-this.pageSize;
27486 ds.load({params:{start: lastStart, limit: this.pageSize}});
27489 ds.load({params:{start: this.cursor, limit: this.pageSize}});
27495 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
27496 * @param {Roo.data.Store} store The data store to unbind
27498 unbind : function(ds){
27499 ds.un("beforeload", this.beforeLoad, this);
27500 ds.un("load", this.onLoad, this);
27501 ds.un("loadexception", this.onLoadError, this);
27502 ds.un("remove", this.updateInfo, this);
27503 ds.un("add", this.updateInfo, this);
27504 this.ds = undefined;
27508 * Binds the paging toolbar to the specified {@link Roo.data.Store}
27509 * @param {Roo.data.Store} store The data store to bind
27511 bind : function(ds){
27512 ds.on("beforeload", this.beforeLoad, this);
27513 ds.on("load", this.onLoad, this);
27514 ds.on("loadexception", this.onLoadError, this);
27515 ds.on("remove", this.updateInfo, this);
27516 ds.on("add", this.updateInfo, this);
27527 * @class Roo.bootstrap.MessageBar
27528 * @extends Roo.bootstrap.Component
27529 * Bootstrap MessageBar class
27530 * @cfg {String} html contents of the MessageBar
27531 * @cfg {String} weight (info | success | warning | danger) default info
27532 * @cfg {String} beforeClass insert the bar before the given class
27533 * @cfg {Boolean} closable (true | false) default false
27534 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
27537 * Create a new Element
27538 * @param {Object} config The config object
27541 Roo.bootstrap.MessageBar = function(config){
27542 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
27545 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
27551 beforeClass: 'bootstrap-sticky-wrap',
27553 getAutoCreate : function(){
27557 cls: 'alert alert-dismissable alert-' + this.weight,
27562 html: this.html || ''
27568 cfg.cls += ' alert-messages-fixed';
27582 onRender : function(ct, position)
27584 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
27587 var cfg = Roo.apply({}, this.getAutoCreate());
27591 cfg.cls += ' ' + this.cls;
27594 cfg.style = this.style;
27596 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
27598 this.el.setVisibilityMode(Roo.Element.DISPLAY);
27601 this.el.select('>button.close').on('click', this.hide, this);
27607 if (!this.rendered) {
27613 this.fireEvent('show', this);
27619 if (!this.rendered) {
27625 this.fireEvent('hide', this);
27628 update : function()
27630 // var e = this.el.dom.firstChild;
27632 // if(this.closable){
27633 // e = e.nextSibling;
27636 // e.data = this.html || '';
27638 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
27654 * @class Roo.bootstrap.Graph
27655 * @extends Roo.bootstrap.Component
27656 * Bootstrap Graph class
27660 @cfg {String} graphtype bar | vbar | pie
27661 @cfg {number} g_x coodinator | centre x (pie)
27662 @cfg {number} g_y coodinator | centre y (pie)
27663 @cfg {number} g_r radius (pie)
27664 @cfg {number} g_height height of the chart (respected by all elements in the set)
27665 @cfg {number} g_width width of the chart (respected by all elements in the set)
27666 @cfg {Object} title The title of the chart
27669 -opts (object) options for the chart
27671 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
27672 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
27674 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.
27675 o stacked (boolean) whether or not to tread values as in a stacked bar chart
27677 o stretch (boolean)
27679 -opts (object) options for the pie
27682 o startAngle (number)
27683 o endAngle (number)
27687 * Create a new Input
27688 * @param {Object} config The config object
27691 Roo.bootstrap.Graph = function(config){
27692 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
27698 * The img click event for the img.
27699 * @param {Roo.EventObject} e
27705 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
27716 //g_colors: this.colors,
27723 getAutoCreate : function(){
27734 onRender : function(ct,position){
27737 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
27739 if (typeof(Raphael) == 'undefined') {
27740 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
27744 this.raphael = Raphael(this.el.dom);
27746 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
27747 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
27748 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
27749 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
27751 r.text(160, 10, "Single Series Chart").attr(txtattr);
27752 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
27753 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
27754 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
27756 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
27757 r.barchart(330, 10, 300, 220, data1);
27758 r.barchart(10, 250, 300, 220, data2, {stacked: true});
27759 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
27762 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
27763 // r.barchart(30, 30, 560, 250, xdata, {
27764 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
27765 // axis : "0 0 1 1",
27766 // axisxlabels : xdata
27767 // //yvalues : cols,
27770 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
27772 // this.load(null,xdata,{
27773 // axis : "0 0 1 1",
27774 // axisxlabels : xdata
27779 load : function(graphtype,xdata,opts)
27781 this.raphael.clear();
27783 graphtype = this.graphtype;
27788 var r = this.raphael,
27789 fin = function () {
27790 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
27792 fout = function () {
27793 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
27795 pfin = function() {
27796 this.sector.stop();
27797 this.sector.scale(1.1, 1.1, this.cx, this.cy);
27800 this.label[0].stop();
27801 this.label[0].attr({ r: 7.5 });
27802 this.label[1].attr({ "font-weight": 800 });
27805 pfout = function() {
27806 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
27809 this.label[0].animate({ r: 5 }, 500, "bounce");
27810 this.label[1].attr({ "font-weight": 400 });
27816 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
27819 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
27822 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
27823 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
27825 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
27832 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
27837 setTitle: function(o)
27842 initEvents: function() {
27845 this.el.on('click', this.onClick, this);
27849 onClick : function(e)
27851 Roo.log('img onclick');
27852 this.fireEvent('click', this, e);
27864 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
27867 * @class Roo.bootstrap.dash.NumberBox
27868 * @extends Roo.bootstrap.Component
27869 * Bootstrap NumberBox class
27870 * @cfg {String} headline Box headline
27871 * @cfg {String} content Box content
27872 * @cfg {String} icon Box icon
27873 * @cfg {String} footer Footer text
27874 * @cfg {String} fhref Footer href
27877 * Create a new NumberBox
27878 * @param {Object} config The config object
27882 Roo.bootstrap.dash.NumberBox = function(config){
27883 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
27887 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
27896 getAutoCreate : function(){
27900 cls : 'small-box ',
27908 cls : 'roo-headline',
27909 html : this.headline
27913 cls : 'roo-content',
27914 html : this.content
27928 cls : 'ion ' + this.icon
27937 cls : 'small-box-footer',
27938 href : this.fhref || '#',
27942 cfg.cn.push(footer);
27949 onRender : function(ct,position){
27950 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
27957 setHeadline: function (value)
27959 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
27962 setFooter: function (value, href)
27964 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
27967 this.el.select('a.small-box-footer',true).first().attr('href', href);
27972 setContent: function (value)
27974 this.el.select('.roo-content',true).first().dom.innerHTML = value;
27977 initEvents: function()
27991 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
27994 * @class Roo.bootstrap.dash.TabBox
27995 * @extends Roo.bootstrap.Component
27996 * Bootstrap TabBox class
27997 * @cfg {String} title Title of the TabBox
27998 * @cfg {String} icon Icon of the TabBox
27999 * @cfg {Boolean} showtabs (true|false) show the tabs default true
28000 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
28003 * Create a new TabBox
28004 * @param {Object} config The config object
28008 Roo.bootstrap.dash.TabBox = function(config){
28009 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
28014 * When a pane is added
28015 * @param {Roo.bootstrap.dash.TabPane} pane
28019 * @event activatepane
28020 * When a pane is activated
28021 * @param {Roo.bootstrap.dash.TabPane} pane
28023 "activatepane" : true
28031 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
28036 tabScrollable : false,
28038 getChildContainer : function()
28040 return this.el.select('.tab-content', true).first();
28043 getAutoCreate : function(){
28047 cls: 'pull-left header',
28055 cls: 'fa ' + this.icon
28061 cls: 'nav nav-tabs pull-right',
28067 if(this.tabScrollable){
28074 cls: 'nav nav-tabs pull-right',
28085 cls: 'nav-tabs-custom',
28090 cls: 'tab-content no-padding',
28098 initEvents : function()
28100 //Roo.log('add add pane handler');
28101 this.on('addpane', this.onAddPane, this);
28104 * Updates the box title
28105 * @param {String} html to set the title to.
28107 setTitle : function(value)
28109 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
28111 onAddPane : function(pane)
28113 this.panes.push(pane);
28114 //Roo.log('addpane');
28116 // tabs are rendere left to right..
28117 if(!this.showtabs){
28121 var ctr = this.el.select('.nav-tabs', true).first();
28124 var existing = ctr.select('.nav-tab',true);
28125 var qty = existing.getCount();;
28128 var tab = ctr.createChild({
28130 cls : 'nav-tab' + (qty ? '' : ' active'),
28138 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
28141 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
28143 pane.el.addClass('active');
28148 onTabClick : function(ev,un,ob,pane)
28150 //Roo.log('tab - prev default');
28151 ev.preventDefault();
28154 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
28155 pane.tab.addClass('active');
28156 //Roo.log(pane.title);
28157 this.getChildContainer().select('.tab-pane',true).removeClass('active');
28158 // technically we should have a deactivate event.. but maybe add later.
28159 // and it should not de-activate the selected tab...
28160 this.fireEvent('activatepane', pane);
28161 pane.el.addClass('active');
28162 pane.fireEvent('activate');
28167 getActivePane : function()
28170 Roo.each(this.panes, function(p) {
28171 if(p.el.hasClass('active')){
28192 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
28194 * @class Roo.bootstrap.TabPane
28195 * @extends Roo.bootstrap.Component
28196 * Bootstrap TabPane class
28197 * @cfg {Boolean} active (false | true) Default false
28198 * @cfg {String} title title of panel
28202 * Create a new TabPane
28203 * @param {Object} config The config object
28206 Roo.bootstrap.dash.TabPane = function(config){
28207 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
28213 * When a pane is activated
28214 * @param {Roo.bootstrap.dash.TabPane} pane
28221 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
28226 // the tabBox that this is attached to.
28229 getAutoCreate : function()
28237 cfg.cls += ' active';
28242 initEvents : function()
28244 //Roo.log('trigger add pane handler');
28245 this.parent().fireEvent('addpane', this)
28249 * Updates the tab title
28250 * @param {String} html to set the title to.
28252 setTitle: function(str)
28258 this.tab.select('a', true).first().dom.innerHTML = str;
28275 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
28278 * @class Roo.bootstrap.menu.Menu
28279 * @extends Roo.bootstrap.Component
28280 * Bootstrap Menu class - container for Menu
28281 * @cfg {String} html Text of the menu
28282 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
28283 * @cfg {String} icon Font awesome icon
28284 * @cfg {String} pos Menu align to (top | bottom) default bottom
28288 * Create a new Menu
28289 * @param {Object} config The config object
28293 Roo.bootstrap.menu.Menu = function(config){
28294 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
28298 * @event beforeshow
28299 * Fires before this menu is displayed
28300 * @param {Roo.bootstrap.menu.Menu} this
28304 * @event beforehide
28305 * Fires before this menu is hidden
28306 * @param {Roo.bootstrap.menu.Menu} this
28311 * Fires after this menu is displayed
28312 * @param {Roo.bootstrap.menu.Menu} this
28317 * Fires after this menu is hidden
28318 * @param {Roo.bootstrap.menu.Menu} this
28323 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
28324 * @param {Roo.bootstrap.menu.Menu} this
28325 * @param {Roo.EventObject} e
28332 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
28336 weight : 'default',
28341 getChildContainer : function() {
28342 if(this.isSubMenu){
28346 return this.el.select('ul.dropdown-menu', true).first();
28349 getAutoCreate : function()
28354 cls : 'roo-menu-text',
28362 cls : 'fa ' + this.icon
28373 cls : 'dropdown-button btn btn-' + this.weight,
28378 cls : 'dropdown-toggle btn btn-' + this.weight,
28388 cls : 'dropdown-menu'
28394 if(this.pos == 'top'){
28395 cfg.cls += ' dropup';
28398 if(this.isSubMenu){
28401 cls : 'dropdown-menu'
28408 onRender : function(ct, position)
28410 this.isSubMenu = ct.hasClass('dropdown-submenu');
28412 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
28415 initEvents : function()
28417 if(this.isSubMenu){
28421 this.hidden = true;
28423 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
28424 this.triggerEl.on('click', this.onTriggerPress, this);
28426 this.buttonEl = this.el.select('button.dropdown-button', true).first();
28427 this.buttonEl.on('click', this.onClick, this);
28433 if(this.isSubMenu){
28437 return this.el.select('ul.dropdown-menu', true).first();
28440 onClick : function(e)
28442 this.fireEvent("click", this, e);
28445 onTriggerPress : function(e)
28447 if (this.isVisible()) {
28454 isVisible : function(){
28455 return !this.hidden;
28460 this.fireEvent("beforeshow", this);
28462 this.hidden = false;
28463 this.el.addClass('open');
28465 Roo.get(document).on("mouseup", this.onMouseUp, this);
28467 this.fireEvent("show", this);
28474 this.fireEvent("beforehide", this);
28476 this.hidden = true;
28477 this.el.removeClass('open');
28479 Roo.get(document).un("mouseup", this.onMouseUp);
28481 this.fireEvent("hide", this);
28484 onMouseUp : function()
28498 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
28501 * @class Roo.bootstrap.menu.Item
28502 * @extends Roo.bootstrap.Component
28503 * Bootstrap MenuItem class
28504 * @cfg {Boolean} submenu (true | false) default false
28505 * @cfg {String} html text of the item
28506 * @cfg {String} href the link
28507 * @cfg {Boolean} disable (true | false) default false
28508 * @cfg {Boolean} preventDefault (true | false) default true
28509 * @cfg {String} icon Font awesome icon
28510 * @cfg {String} pos Submenu align to (left | right) default right
28514 * Create a new Item
28515 * @param {Object} config The config object
28519 Roo.bootstrap.menu.Item = function(config){
28520 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
28524 * Fires when the mouse is hovering over this menu
28525 * @param {Roo.bootstrap.menu.Item} this
28526 * @param {Roo.EventObject} e
28531 * Fires when the mouse exits this menu
28532 * @param {Roo.bootstrap.menu.Item} this
28533 * @param {Roo.EventObject} e
28539 * The raw click event for the entire grid.
28540 * @param {Roo.EventObject} e
28546 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
28551 preventDefault: true,
28556 getAutoCreate : function()
28561 cls : 'roo-menu-item-text',
28569 cls : 'fa ' + this.icon
28578 href : this.href || '#',
28585 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
28589 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
28591 if(this.pos == 'left'){
28592 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
28599 initEvents : function()
28601 this.el.on('mouseover', this.onMouseOver, this);
28602 this.el.on('mouseout', this.onMouseOut, this);
28604 this.el.select('a', true).first().on('click', this.onClick, this);
28608 onClick : function(e)
28610 if(this.preventDefault){
28611 e.preventDefault();
28614 this.fireEvent("click", this, e);
28617 onMouseOver : function(e)
28619 if(this.submenu && this.pos == 'left'){
28620 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
28623 this.fireEvent("mouseover", this, e);
28626 onMouseOut : function(e)
28628 this.fireEvent("mouseout", this, e);
28640 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
28643 * @class Roo.bootstrap.menu.Separator
28644 * @extends Roo.bootstrap.Component
28645 * Bootstrap Separator class
28648 * Create a new Separator
28649 * @param {Object} config The config object
28653 Roo.bootstrap.menu.Separator = function(config){
28654 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
28657 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
28659 getAutoCreate : function(){
28680 * @class Roo.bootstrap.Tooltip
28681 * Bootstrap Tooltip class
28682 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
28683 * to determine which dom element triggers the tooltip.
28685 * It needs to add support for additional attributes like tooltip-position
28688 * Create a new Toolti
28689 * @param {Object} config The config object
28692 Roo.bootstrap.Tooltip = function(config){
28693 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
28695 this.alignment = Roo.bootstrap.Tooltip.alignment;
28697 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
28698 this.alignment = config.alignment;
28703 Roo.apply(Roo.bootstrap.Tooltip, {
28705 * @function init initialize tooltip monitoring.
28709 currentTip : false,
28710 currentRegion : false,
28716 Roo.get(document).on('mouseover', this.enter ,this);
28717 Roo.get(document).on('mouseout', this.leave, this);
28720 this.currentTip = new Roo.bootstrap.Tooltip();
28723 enter : function(ev)
28725 var dom = ev.getTarget();
28727 //Roo.log(['enter',dom]);
28728 var el = Roo.fly(dom);
28729 if (this.currentEl) {
28731 //Roo.log(this.currentEl);
28732 //Roo.log(this.currentEl.contains(dom));
28733 if (this.currentEl == el) {
28736 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
28742 if (this.currentTip.el) {
28743 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
28747 if(!el || el.dom == document){
28753 // you can not look for children, as if el is the body.. then everythign is the child..
28754 if (!el.attr('tooltip')) { //
28755 if (!el.select("[tooltip]").elements.length) {
28758 // is the mouse over this child...?
28759 bindEl = el.select("[tooltip]").first();
28760 var xy = ev.getXY();
28761 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
28762 //Roo.log("not in region.");
28765 //Roo.log("child element over..");
28768 this.currentEl = bindEl;
28769 this.currentTip.bind(bindEl);
28770 this.currentRegion = Roo.lib.Region.getRegion(dom);
28771 this.currentTip.enter();
28774 leave : function(ev)
28776 var dom = ev.getTarget();
28777 //Roo.log(['leave',dom]);
28778 if (!this.currentEl) {
28783 if (dom != this.currentEl.dom) {
28786 var xy = ev.getXY();
28787 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
28790 // only activate leave if mouse cursor is outside... bounding box..
28795 if (this.currentTip) {
28796 this.currentTip.leave();
28798 //Roo.log('clear currentEl');
28799 this.currentEl = false;
28804 'left' : ['r-l', [-2,0], 'right'],
28805 'right' : ['l-r', [2,0], 'left'],
28806 'bottom' : ['t-b', [0,2], 'top'],
28807 'top' : [ 'b-t', [0,-2], 'bottom']
28813 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
28818 delay : null, // can be { show : 300 , hide: 500}
28822 hoverState : null, //???
28824 placement : 'bottom',
28828 getAutoCreate : function(){
28835 cls : 'tooltip-arrow arrow'
28838 cls : 'tooltip-inner'
28845 bind : function(el)
28850 initEvents : function()
28852 this.arrowEl = this.el.select('.arrow', true).first();
28853 this.innerEl = this.el.select('.tooltip-inner', true).first();
28856 enter : function () {
28858 if (this.timeout != null) {
28859 clearTimeout(this.timeout);
28862 this.hoverState = 'in';
28863 //Roo.log("enter - show");
28864 if (!this.delay || !this.delay.show) {
28869 this.timeout = setTimeout(function () {
28870 if (_t.hoverState == 'in') {
28873 }, this.delay.show);
28877 clearTimeout(this.timeout);
28879 this.hoverState = 'out';
28880 if (!this.delay || !this.delay.hide) {
28886 this.timeout = setTimeout(function () {
28887 //Roo.log("leave - timeout");
28889 if (_t.hoverState == 'out') {
28891 Roo.bootstrap.Tooltip.currentEl = false;
28896 show : function (msg)
28899 this.render(document.body);
28902 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
28904 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
28906 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
28908 this.el.removeClass(['fade','top','bottom', 'left', 'right','in',
28909 'bs-tooltip-top','bs-tooltip-bottom', 'bs-tooltip-left', 'bs-tooltip-right']);
28911 var placement = typeof this.placement == 'function' ?
28912 this.placement.call(this, this.el, on_el) :
28915 var autoToken = /\s?auto?\s?/i;
28916 var autoPlace = autoToken.test(placement);
28918 placement = placement.replace(autoToken, '') || 'top';
28922 //this.el.setXY([0,0]);
28924 //this.el.dom.style.display='block';
28926 //this.el.appendTo(on_el);
28928 var p = this.getPosition();
28929 var box = this.el.getBox();
28935 var align = this.alignment[placement];
28937 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
28939 if(placement == 'top' || placement == 'bottom'){
28941 placement = 'right';
28944 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
28945 placement = 'left';
28948 var scroll = Roo.select('body', true).first().getScroll();
28950 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
28954 align = this.alignment[placement];
28956 this.arrowEl.setLeft((this.innerEl.getWidth()/2) - 5);
28960 this.el.alignTo(this.bindEl, align[0],align[1]);
28961 //var arrow = this.el.select('.arrow',true).first();
28962 //arrow.set(align[2],
28964 this.el.addClass(placement);
28965 this.el.addClass("bs-tooltip-"+ placement);
28967 this.el.addClass('in fade show');
28969 this.hoverState = null;
28971 if (this.el.hasClass('fade')) {
28986 //this.el.setXY([0,0]);
28987 this.el.removeClass(['show', 'in']);
29003 * @class Roo.bootstrap.LocationPicker
29004 * @extends Roo.bootstrap.Component
29005 * Bootstrap LocationPicker class
29006 * @cfg {Number} latitude Position when init default 0
29007 * @cfg {Number} longitude Position when init default 0
29008 * @cfg {Number} zoom default 15
29009 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
29010 * @cfg {Boolean} mapTypeControl default false
29011 * @cfg {Boolean} disableDoubleClickZoom default false
29012 * @cfg {Boolean} scrollwheel default true
29013 * @cfg {Boolean} streetViewControl default false
29014 * @cfg {Number} radius default 0
29015 * @cfg {String} locationName
29016 * @cfg {Boolean} draggable default true
29017 * @cfg {Boolean} enableAutocomplete default false
29018 * @cfg {Boolean} enableReverseGeocode default true
29019 * @cfg {String} markerTitle
29022 * Create a new LocationPicker
29023 * @param {Object} config The config object
29027 Roo.bootstrap.LocationPicker = function(config){
29029 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
29034 * Fires when the picker initialized.
29035 * @param {Roo.bootstrap.LocationPicker} this
29036 * @param {Google Location} location
29040 * @event positionchanged
29041 * Fires when the picker position changed.
29042 * @param {Roo.bootstrap.LocationPicker} this
29043 * @param {Google Location} location
29045 positionchanged : true,
29048 * Fires when the map resize.
29049 * @param {Roo.bootstrap.LocationPicker} this
29054 * Fires when the map show.
29055 * @param {Roo.bootstrap.LocationPicker} this
29060 * Fires when the map hide.
29061 * @param {Roo.bootstrap.LocationPicker} this
29066 * Fires when click the map.
29067 * @param {Roo.bootstrap.LocationPicker} this
29068 * @param {Map event} e
29072 * @event mapRightClick
29073 * Fires when right click the map.
29074 * @param {Roo.bootstrap.LocationPicker} this
29075 * @param {Map event} e
29077 mapRightClick : true,
29079 * @event markerClick
29080 * Fires when click the marker.
29081 * @param {Roo.bootstrap.LocationPicker} this
29082 * @param {Map event} e
29084 markerClick : true,
29086 * @event markerRightClick
29087 * Fires when right click the marker.
29088 * @param {Roo.bootstrap.LocationPicker} this
29089 * @param {Map event} e
29091 markerRightClick : true,
29093 * @event OverlayViewDraw
29094 * Fires when OverlayView Draw
29095 * @param {Roo.bootstrap.LocationPicker} this
29097 OverlayViewDraw : true,
29099 * @event OverlayViewOnAdd
29100 * Fires when OverlayView Draw
29101 * @param {Roo.bootstrap.LocationPicker} this
29103 OverlayViewOnAdd : true,
29105 * @event OverlayViewOnRemove
29106 * Fires when OverlayView Draw
29107 * @param {Roo.bootstrap.LocationPicker} this
29109 OverlayViewOnRemove : true,
29111 * @event OverlayViewShow
29112 * Fires when OverlayView Draw
29113 * @param {Roo.bootstrap.LocationPicker} this
29114 * @param {Pixel} cpx
29116 OverlayViewShow : true,
29118 * @event OverlayViewHide
29119 * Fires when OverlayView Draw
29120 * @param {Roo.bootstrap.LocationPicker} this
29122 OverlayViewHide : true,
29124 * @event loadexception
29125 * Fires when load google lib failed.
29126 * @param {Roo.bootstrap.LocationPicker} this
29128 loadexception : true
29133 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
29135 gMapContext: false,
29141 mapTypeControl: false,
29142 disableDoubleClickZoom: false,
29144 streetViewControl: false,
29148 enableAutocomplete: false,
29149 enableReverseGeocode: true,
29152 getAutoCreate: function()
29157 cls: 'roo-location-picker'
29163 initEvents: function(ct, position)
29165 if(!this.el.getWidth() || this.isApplied()){
29169 this.el.setVisibilityMode(Roo.Element.DISPLAY);
29174 initial: function()
29176 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
29177 this.fireEvent('loadexception', this);
29181 if(!this.mapTypeId){
29182 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
29185 this.gMapContext = this.GMapContext();
29187 this.initOverlayView();
29189 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
29193 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
29194 _this.setPosition(_this.gMapContext.marker.position);
29197 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
29198 _this.fireEvent('mapClick', this, event);
29202 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
29203 _this.fireEvent('mapRightClick', this, event);
29207 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
29208 _this.fireEvent('markerClick', this, event);
29212 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
29213 _this.fireEvent('markerRightClick', this, event);
29217 this.setPosition(this.gMapContext.location);
29219 this.fireEvent('initial', this, this.gMapContext.location);
29222 initOverlayView: function()
29226 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
29230 _this.fireEvent('OverlayViewDraw', _this);
29235 _this.fireEvent('OverlayViewOnAdd', _this);
29238 onRemove: function()
29240 _this.fireEvent('OverlayViewOnRemove', _this);
29243 show: function(cpx)
29245 _this.fireEvent('OverlayViewShow', _this, cpx);
29250 _this.fireEvent('OverlayViewHide', _this);
29256 fromLatLngToContainerPixel: function(event)
29258 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
29261 isApplied: function()
29263 return this.getGmapContext() == false ? false : true;
29266 getGmapContext: function()
29268 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
29271 GMapContext: function()
29273 var position = new google.maps.LatLng(this.latitude, this.longitude);
29275 var _map = new google.maps.Map(this.el.dom, {
29278 mapTypeId: this.mapTypeId,
29279 mapTypeControl: this.mapTypeControl,
29280 disableDoubleClickZoom: this.disableDoubleClickZoom,
29281 scrollwheel: this.scrollwheel,
29282 streetViewControl: this.streetViewControl,
29283 locationName: this.locationName,
29284 draggable: this.draggable,
29285 enableAutocomplete: this.enableAutocomplete,
29286 enableReverseGeocode: this.enableReverseGeocode
29289 var _marker = new google.maps.Marker({
29290 position: position,
29292 title: this.markerTitle,
29293 draggable: this.draggable
29300 location: position,
29301 radius: this.radius,
29302 locationName: this.locationName,
29303 addressComponents: {
29304 formatted_address: null,
29305 addressLine1: null,
29306 addressLine2: null,
29308 streetNumber: null,
29312 stateOrProvince: null
29315 domContainer: this.el.dom,
29316 geodecoder: new google.maps.Geocoder()
29320 drawCircle: function(center, radius, options)
29322 if (this.gMapContext.circle != null) {
29323 this.gMapContext.circle.setMap(null);
29327 options = Roo.apply({}, options, {
29328 strokeColor: "#0000FF",
29329 strokeOpacity: .35,
29331 fillColor: "#0000FF",
29335 options.map = this.gMapContext.map;
29336 options.radius = radius;
29337 options.center = center;
29338 this.gMapContext.circle = new google.maps.Circle(options);
29339 return this.gMapContext.circle;
29345 setPosition: function(location)
29347 this.gMapContext.location = location;
29348 this.gMapContext.marker.setPosition(location);
29349 this.gMapContext.map.panTo(location);
29350 this.drawCircle(location, this.gMapContext.radius, {});
29354 if (this.gMapContext.settings.enableReverseGeocode) {
29355 this.gMapContext.geodecoder.geocode({
29356 latLng: this.gMapContext.location
29357 }, function(results, status) {
29359 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
29360 _this.gMapContext.locationName = results[0].formatted_address;
29361 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
29363 _this.fireEvent('positionchanged', this, location);
29370 this.fireEvent('positionchanged', this, location);
29375 google.maps.event.trigger(this.gMapContext.map, "resize");
29377 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
29379 this.fireEvent('resize', this);
29382 setPositionByLatLng: function(latitude, longitude)
29384 this.setPosition(new google.maps.LatLng(latitude, longitude));
29387 getCurrentPosition: function()
29390 latitude: this.gMapContext.location.lat(),
29391 longitude: this.gMapContext.location.lng()
29395 getAddressName: function()
29397 return this.gMapContext.locationName;
29400 getAddressComponents: function()
29402 return this.gMapContext.addressComponents;
29405 address_component_from_google_geocode: function(address_components)
29409 for (var i = 0; i < address_components.length; i++) {
29410 var component = address_components[i];
29411 if (component.types.indexOf("postal_code") >= 0) {
29412 result.postalCode = component.short_name;
29413 } else if (component.types.indexOf("street_number") >= 0) {
29414 result.streetNumber = component.short_name;
29415 } else if (component.types.indexOf("route") >= 0) {
29416 result.streetName = component.short_name;
29417 } else if (component.types.indexOf("neighborhood") >= 0) {
29418 result.city = component.short_name;
29419 } else if (component.types.indexOf("locality") >= 0) {
29420 result.city = component.short_name;
29421 } else if (component.types.indexOf("sublocality") >= 0) {
29422 result.district = component.short_name;
29423 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
29424 result.stateOrProvince = component.short_name;
29425 } else if (component.types.indexOf("country") >= 0) {
29426 result.country = component.short_name;
29430 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
29431 result.addressLine2 = "";
29435 setZoomLevel: function(zoom)
29437 this.gMapContext.map.setZoom(zoom);
29450 this.fireEvent('show', this);
29461 this.fireEvent('hide', this);
29466 Roo.apply(Roo.bootstrap.LocationPicker, {
29468 OverlayView : function(map, options)
29470 options = options || {};
29477 * @class Roo.bootstrap.Alert
29478 * @extends Roo.bootstrap.Component
29479 * Bootstrap Alert class - shows an alert area box
29481 * <div class="alert alert-danger" role="alert"><span class="fa fa-exclamation-triangle"></span><span class="sr-only">Error:</span>
29482 Enter a valid email address
29485 * @cfg {String} title The title of alert
29486 * @cfg {String} html The content of alert
29487 * @cfg {String} weight ( success | info | warning | danger )
29488 * @cfg {String} faicon font-awesomeicon
29491 * Create a new alert
29492 * @param {Object} config The config object
29496 Roo.bootstrap.Alert = function(config){
29497 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
29501 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
29508 getAutoCreate : function()
29517 cls : 'roo-alert-icon'
29522 cls : 'roo-alert-title',
29527 cls : 'roo-alert-text',
29534 cfg.cn[0].cls += ' fa ' + this.faicon;
29538 cfg.cls += ' alert-' + this.weight;
29544 initEvents: function()
29546 this.el.setVisibilityMode(Roo.Element.DISPLAY);
29549 setTitle : function(str)
29551 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
29554 setText : function(str)
29556 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
29559 setWeight : function(weight)
29562 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
29565 this.weight = weight;
29567 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
29570 setIcon : function(icon)
29573 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
29576 this.faicon = icon;
29578 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
29599 * @class Roo.bootstrap.UploadCropbox
29600 * @extends Roo.bootstrap.Component
29601 * Bootstrap UploadCropbox class
29602 * @cfg {String} emptyText show when image has been loaded
29603 * @cfg {String} rotateNotify show when image too small to rotate
29604 * @cfg {Number} errorTimeout default 3000
29605 * @cfg {Number} minWidth default 300
29606 * @cfg {Number} minHeight default 300
29607 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
29608 * @cfg {Boolean} isDocument (true|false) default false
29609 * @cfg {String} url action url
29610 * @cfg {String} paramName default 'imageUpload'
29611 * @cfg {String} method default POST
29612 * @cfg {Boolean} loadMask (true|false) default true
29613 * @cfg {Boolean} loadingText default 'Loading...'
29616 * Create a new UploadCropbox
29617 * @param {Object} config The config object
29620 Roo.bootstrap.UploadCropbox = function(config){
29621 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
29625 * @event beforeselectfile
29626 * Fire before select file
29627 * @param {Roo.bootstrap.UploadCropbox} this
29629 "beforeselectfile" : true,
29632 * Fire after initEvent
29633 * @param {Roo.bootstrap.UploadCropbox} this
29638 * Fire after initEvent
29639 * @param {Roo.bootstrap.UploadCropbox} this
29640 * @param {String} data
29645 * Fire when preparing the file data
29646 * @param {Roo.bootstrap.UploadCropbox} this
29647 * @param {Object} file
29652 * Fire when get exception
29653 * @param {Roo.bootstrap.UploadCropbox} this
29654 * @param {XMLHttpRequest} xhr
29656 "exception" : true,
29658 * @event beforeloadcanvas
29659 * Fire before load the canvas
29660 * @param {Roo.bootstrap.UploadCropbox} this
29661 * @param {String} src
29663 "beforeloadcanvas" : true,
29666 * Fire when trash image
29667 * @param {Roo.bootstrap.UploadCropbox} this
29672 * Fire when download the image
29673 * @param {Roo.bootstrap.UploadCropbox} this
29677 * @event footerbuttonclick
29678 * Fire when footerbuttonclick
29679 * @param {Roo.bootstrap.UploadCropbox} this
29680 * @param {String} type
29682 "footerbuttonclick" : true,
29686 * @param {Roo.bootstrap.UploadCropbox} this
29691 * Fire when rotate the image
29692 * @param {Roo.bootstrap.UploadCropbox} this
29693 * @param {String} pos
29698 * Fire when inspect the file
29699 * @param {Roo.bootstrap.UploadCropbox} this
29700 * @param {Object} file
29705 * Fire when xhr upload the file
29706 * @param {Roo.bootstrap.UploadCropbox} this
29707 * @param {Object} data
29712 * Fire when arrange the file data
29713 * @param {Roo.bootstrap.UploadCropbox} this
29714 * @param {Object} formData
29719 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
29722 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
29724 emptyText : 'Click to upload image',
29725 rotateNotify : 'Image is too small to rotate',
29726 errorTimeout : 3000,
29740 cropType : 'image/jpeg',
29742 canvasLoaded : false,
29743 isDocument : false,
29745 paramName : 'imageUpload',
29747 loadingText : 'Loading...',
29750 getAutoCreate : function()
29754 cls : 'roo-upload-cropbox',
29758 cls : 'roo-upload-cropbox-selector',
29763 cls : 'roo-upload-cropbox-body',
29764 style : 'cursor:pointer',
29768 cls : 'roo-upload-cropbox-preview'
29772 cls : 'roo-upload-cropbox-thumb'
29776 cls : 'roo-upload-cropbox-empty-notify',
29777 html : this.emptyText
29781 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
29782 html : this.rotateNotify
29788 cls : 'roo-upload-cropbox-footer',
29791 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
29801 onRender : function(ct, position)
29803 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
29805 if (this.buttons.length) {
29807 Roo.each(this.buttons, function(bb) {
29809 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
29811 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
29817 this.maskEl = this.el;
29821 initEvents : function()
29823 this.urlAPI = (window.createObjectURL && window) ||
29824 (window.URL && URL.revokeObjectURL && URL) ||
29825 (window.webkitURL && webkitURL);
29827 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
29828 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29830 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
29831 this.selectorEl.hide();
29833 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
29834 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29836 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
29837 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29838 this.thumbEl.hide();
29840 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
29841 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29843 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
29844 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29845 this.errorEl.hide();
29847 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
29848 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29849 this.footerEl.hide();
29851 this.setThumbBoxSize();
29857 this.fireEvent('initial', this);
29864 window.addEventListener("resize", function() { _this.resize(); } );
29866 this.bodyEl.on('click', this.beforeSelectFile, this);
29869 this.bodyEl.on('touchstart', this.onTouchStart, this);
29870 this.bodyEl.on('touchmove', this.onTouchMove, this);
29871 this.bodyEl.on('touchend', this.onTouchEnd, this);
29875 this.bodyEl.on('mousedown', this.onMouseDown, this);
29876 this.bodyEl.on('mousemove', this.onMouseMove, this);
29877 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
29878 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
29879 Roo.get(document).on('mouseup', this.onMouseUp, this);
29882 this.selectorEl.on('change', this.onFileSelected, this);
29888 this.baseScale = 1;
29890 this.baseRotate = 1;
29891 this.dragable = false;
29892 this.pinching = false;
29895 this.cropData = false;
29896 this.notifyEl.dom.innerHTML = this.emptyText;
29898 this.selectorEl.dom.value = '';
29902 resize : function()
29904 if(this.fireEvent('resize', this) != false){
29905 this.setThumbBoxPosition();
29906 this.setCanvasPosition();
29910 onFooterButtonClick : function(e, el, o, type)
29913 case 'rotate-left' :
29914 this.onRotateLeft(e);
29916 case 'rotate-right' :
29917 this.onRotateRight(e);
29920 this.beforeSelectFile(e);
29935 this.fireEvent('footerbuttonclick', this, type);
29938 beforeSelectFile : function(e)
29940 e.preventDefault();
29942 if(this.fireEvent('beforeselectfile', this) != false){
29943 this.selectorEl.dom.click();
29947 onFileSelected : function(e)
29949 e.preventDefault();
29951 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
29955 var file = this.selectorEl.dom.files[0];
29957 if(this.fireEvent('inspect', this, file) != false){
29958 this.prepare(file);
29963 trash : function(e)
29965 this.fireEvent('trash', this);
29968 download : function(e)
29970 this.fireEvent('download', this);
29973 loadCanvas : function(src)
29975 if(this.fireEvent('beforeloadcanvas', this, src) != false){
29979 this.imageEl = document.createElement('img');
29983 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
29985 this.imageEl.src = src;
29989 onLoadCanvas : function()
29991 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
29992 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
29994 this.bodyEl.un('click', this.beforeSelectFile, this);
29996 this.notifyEl.hide();
29997 this.thumbEl.show();
29998 this.footerEl.show();
30000 this.baseRotateLevel();
30002 if(this.isDocument){
30003 this.setThumbBoxSize();
30006 this.setThumbBoxPosition();
30008 this.baseScaleLevel();
30014 this.canvasLoaded = true;
30017 this.maskEl.unmask();
30022 setCanvasPosition : function()
30024 if(!this.canvasEl){
30028 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
30029 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
30031 this.previewEl.setLeft(pw);
30032 this.previewEl.setTop(ph);
30036 onMouseDown : function(e)
30040 this.dragable = true;
30041 this.pinching = false;
30043 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
30044 this.dragable = false;
30048 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
30049 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
30053 onMouseMove : function(e)
30057 if(!this.canvasLoaded){
30061 if (!this.dragable){
30065 var minX = Math.ceil(this.thumbEl.getLeft(true));
30066 var minY = Math.ceil(this.thumbEl.getTop(true));
30068 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
30069 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
30071 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
30072 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
30074 x = x - this.mouseX;
30075 y = y - this.mouseY;
30077 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
30078 var bgY = Math.ceil(y + this.previewEl.getTop(true));
30080 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
30081 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
30083 this.previewEl.setLeft(bgX);
30084 this.previewEl.setTop(bgY);
30086 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
30087 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
30090 onMouseUp : function(e)
30094 this.dragable = false;
30097 onMouseWheel : function(e)
30101 this.startScale = this.scale;
30103 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
30105 if(!this.zoomable()){
30106 this.scale = this.startScale;
30115 zoomable : function()
30117 var minScale = this.thumbEl.getWidth() / this.minWidth;
30119 if(this.minWidth < this.minHeight){
30120 minScale = this.thumbEl.getHeight() / this.minHeight;
30123 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
30124 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
30128 (this.rotate == 0 || this.rotate == 180) &&
30130 width > this.imageEl.OriginWidth ||
30131 height > this.imageEl.OriginHeight ||
30132 (width < this.minWidth && height < this.minHeight)
30140 (this.rotate == 90 || this.rotate == 270) &&
30142 width > this.imageEl.OriginWidth ||
30143 height > this.imageEl.OriginHeight ||
30144 (width < this.minHeight && height < this.minWidth)
30151 !this.isDocument &&
30152 (this.rotate == 0 || this.rotate == 180) &&
30154 width < this.minWidth ||
30155 width > this.imageEl.OriginWidth ||
30156 height < this.minHeight ||
30157 height > this.imageEl.OriginHeight
30164 !this.isDocument &&
30165 (this.rotate == 90 || this.rotate == 270) &&
30167 width < this.minHeight ||
30168 width > this.imageEl.OriginWidth ||
30169 height < this.minWidth ||
30170 height > this.imageEl.OriginHeight
30180 onRotateLeft : function(e)
30182 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
30184 var minScale = this.thumbEl.getWidth() / this.minWidth;
30186 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
30187 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
30189 this.startScale = this.scale;
30191 while (this.getScaleLevel() < minScale){
30193 this.scale = this.scale + 1;
30195 if(!this.zoomable()){
30200 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
30201 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
30206 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
30213 this.scale = this.startScale;
30215 this.onRotateFail();
30220 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
30222 if(this.isDocument){
30223 this.setThumbBoxSize();
30224 this.setThumbBoxPosition();
30225 this.setCanvasPosition();
30230 this.fireEvent('rotate', this, 'left');
30234 onRotateRight : function(e)
30236 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
30238 var minScale = this.thumbEl.getWidth() / this.minWidth;
30240 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
30241 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
30243 this.startScale = this.scale;
30245 while (this.getScaleLevel() < minScale){
30247 this.scale = this.scale + 1;
30249 if(!this.zoomable()){
30254 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
30255 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
30260 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
30267 this.scale = this.startScale;
30269 this.onRotateFail();
30274 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
30276 if(this.isDocument){
30277 this.setThumbBoxSize();
30278 this.setThumbBoxPosition();
30279 this.setCanvasPosition();
30284 this.fireEvent('rotate', this, 'right');
30287 onRotateFail : function()
30289 this.errorEl.show(true);
30293 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
30298 this.previewEl.dom.innerHTML = '';
30300 var canvasEl = document.createElement("canvas");
30302 var contextEl = canvasEl.getContext("2d");
30304 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
30305 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
30306 var center = this.imageEl.OriginWidth / 2;
30308 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
30309 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
30310 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
30311 center = this.imageEl.OriginHeight / 2;
30314 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
30316 contextEl.translate(center, center);
30317 contextEl.rotate(this.rotate * Math.PI / 180);
30319 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
30321 this.canvasEl = document.createElement("canvas");
30323 this.contextEl = this.canvasEl.getContext("2d");
30325 switch (this.rotate) {
30328 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
30329 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
30331 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
30336 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
30337 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
30339 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
30340 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);
30344 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
30349 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
30350 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
30352 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
30353 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);
30357 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);
30362 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
30363 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
30365 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
30366 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
30370 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);
30377 this.previewEl.appendChild(this.canvasEl);
30379 this.setCanvasPosition();
30384 if(!this.canvasLoaded){
30388 var imageCanvas = document.createElement("canvas");
30390 var imageContext = imageCanvas.getContext("2d");
30392 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
30393 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
30395 var center = imageCanvas.width / 2;
30397 imageContext.translate(center, center);
30399 imageContext.rotate(this.rotate * Math.PI / 180);
30401 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
30403 var canvas = document.createElement("canvas");
30405 var context = canvas.getContext("2d");
30407 canvas.width = this.minWidth;
30408 canvas.height = this.minHeight;
30410 switch (this.rotate) {
30413 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
30414 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
30416 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
30417 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
30419 var targetWidth = this.minWidth - 2 * x;
30420 var targetHeight = this.minHeight - 2 * y;
30424 if((x == 0 && y == 0) || (x == 0 && y > 0)){
30425 scale = targetWidth / width;
30428 if(x > 0 && y == 0){
30429 scale = targetHeight / height;
30432 if(x > 0 && y > 0){
30433 scale = targetWidth / width;
30435 if(width < height){
30436 scale = targetHeight / height;
30440 context.scale(scale, scale);
30442 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
30443 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
30445 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
30446 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
30448 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
30453 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
30454 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
30456 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
30457 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
30459 var targetWidth = this.minWidth - 2 * x;
30460 var targetHeight = this.minHeight - 2 * y;
30464 if((x == 0 && y == 0) || (x == 0 && y > 0)){
30465 scale = targetWidth / width;
30468 if(x > 0 && y == 0){
30469 scale = targetHeight / height;
30472 if(x > 0 && y > 0){
30473 scale = targetWidth / width;
30475 if(width < height){
30476 scale = targetHeight / height;
30480 context.scale(scale, scale);
30482 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
30483 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
30485 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
30486 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
30488 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
30490 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
30495 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
30496 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
30498 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
30499 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
30501 var targetWidth = this.minWidth - 2 * x;
30502 var targetHeight = this.minHeight - 2 * y;
30506 if((x == 0 && y == 0) || (x == 0 && y > 0)){
30507 scale = targetWidth / width;
30510 if(x > 0 && y == 0){
30511 scale = targetHeight / height;
30514 if(x > 0 && y > 0){
30515 scale = targetWidth / width;
30517 if(width < height){
30518 scale = targetHeight / height;
30522 context.scale(scale, scale);
30524 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
30525 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
30527 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
30528 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
30530 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
30531 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
30533 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
30538 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
30539 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
30541 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
30542 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
30544 var targetWidth = this.minWidth - 2 * x;
30545 var targetHeight = this.minHeight - 2 * y;
30549 if((x == 0 && y == 0) || (x == 0 && y > 0)){
30550 scale = targetWidth / width;
30553 if(x > 0 && y == 0){
30554 scale = targetHeight / height;
30557 if(x > 0 && y > 0){
30558 scale = targetWidth / width;
30560 if(width < height){
30561 scale = targetHeight / height;
30565 context.scale(scale, scale);
30567 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
30568 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
30570 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
30571 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
30573 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
30575 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
30582 this.cropData = canvas.toDataURL(this.cropType);
30584 if(this.fireEvent('crop', this, this.cropData) !== false){
30585 this.process(this.file, this.cropData);
30592 setThumbBoxSize : function()
30596 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
30597 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
30598 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
30600 this.minWidth = width;
30601 this.minHeight = height;
30603 if(this.rotate == 90 || this.rotate == 270){
30604 this.minWidth = height;
30605 this.minHeight = width;
30610 width = Math.ceil(this.minWidth * height / this.minHeight);
30612 if(this.minWidth > this.minHeight){
30614 height = Math.ceil(this.minHeight * width / this.minWidth);
30617 this.thumbEl.setStyle({
30618 width : width + 'px',
30619 height : height + 'px'
30626 setThumbBoxPosition : function()
30628 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
30629 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
30631 this.thumbEl.setLeft(x);
30632 this.thumbEl.setTop(y);
30636 baseRotateLevel : function()
30638 this.baseRotate = 1;
30641 typeof(this.exif) != 'undefined' &&
30642 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
30643 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
30645 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
30648 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
30652 baseScaleLevel : function()
30656 if(this.isDocument){
30658 if(this.baseRotate == 6 || this.baseRotate == 8){
30660 height = this.thumbEl.getHeight();
30661 this.baseScale = height / this.imageEl.OriginWidth;
30663 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
30664 width = this.thumbEl.getWidth();
30665 this.baseScale = width / this.imageEl.OriginHeight;
30671 height = this.thumbEl.getHeight();
30672 this.baseScale = height / this.imageEl.OriginHeight;
30674 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
30675 width = this.thumbEl.getWidth();
30676 this.baseScale = width / this.imageEl.OriginWidth;
30682 if(this.baseRotate == 6 || this.baseRotate == 8){
30684 width = this.thumbEl.getHeight();
30685 this.baseScale = width / this.imageEl.OriginHeight;
30687 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
30688 height = this.thumbEl.getWidth();
30689 this.baseScale = height / this.imageEl.OriginHeight;
30692 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
30693 height = this.thumbEl.getWidth();
30694 this.baseScale = height / this.imageEl.OriginHeight;
30696 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
30697 width = this.thumbEl.getHeight();
30698 this.baseScale = width / this.imageEl.OriginWidth;
30705 width = this.thumbEl.getWidth();
30706 this.baseScale = width / this.imageEl.OriginWidth;
30708 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
30709 height = this.thumbEl.getHeight();
30710 this.baseScale = height / this.imageEl.OriginHeight;
30713 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
30715 height = this.thumbEl.getHeight();
30716 this.baseScale = height / this.imageEl.OriginHeight;
30718 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
30719 width = this.thumbEl.getWidth();
30720 this.baseScale = width / this.imageEl.OriginWidth;
30728 getScaleLevel : function()
30730 return this.baseScale * Math.pow(1.1, this.scale);
30733 onTouchStart : function(e)
30735 if(!this.canvasLoaded){
30736 this.beforeSelectFile(e);
30740 var touches = e.browserEvent.touches;
30746 if(touches.length == 1){
30747 this.onMouseDown(e);
30751 if(touches.length != 2){
30757 for(var i = 0, finger; finger = touches[i]; i++){
30758 coords.push(finger.pageX, finger.pageY);
30761 var x = Math.pow(coords[0] - coords[2], 2);
30762 var y = Math.pow(coords[1] - coords[3], 2);
30764 this.startDistance = Math.sqrt(x + y);
30766 this.startScale = this.scale;
30768 this.pinching = true;
30769 this.dragable = false;
30773 onTouchMove : function(e)
30775 if(!this.pinching && !this.dragable){
30779 var touches = e.browserEvent.touches;
30786 this.onMouseMove(e);
30792 for(var i = 0, finger; finger = touches[i]; i++){
30793 coords.push(finger.pageX, finger.pageY);
30796 var x = Math.pow(coords[0] - coords[2], 2);
30797 var y = Math.pow(coords[1] - coords[3], 2);
30799 this.endDistance = Math.sqrt(x + y);
30801 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
30803 if(!this.zoomable()){
30804 this.scale = this.startScale;
30812 onTouchEnd : function(e)
30814 this.pinching = false;
30815 this.dragable = false;
30819 process : function(file, crop)
30822 this.maskEl.mask(this.loadingText);
30825 this.xhr = new XMLHttpRequest();
30827 file.xhr = this.xhr;
30829 this.xhr.open(this.method, this.url, true);
30832 "Accept": "application/json",
30833 "Cache-Control": "no-cache",
30834 "X-Requested-With": "XMLHttpRequest"
30837 for (var headerName in headers) {
30838 var headerValue = headers[headerName];
30840 this.xhr.setRequestHeader(headerName, headerValue);
30846 this.xhr.onload = function()
30848 _this.xhrOnLoad(_this.xhr);
30851 this.xhr.onerror = function()
30853 _this.xhrOnError(_this.xhr);
30856 var formData = new FormData();
30858 formData.append('returnHTML', 'NO');
30861 formData.append('crop', crop);
30864 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
30865 formData.append(this.paramName, file, file.name);
30868 if(typeof(file.filename) != 'undefined'){
30869 formData.append('filename', file.filename);
30872 if(typeof(file.mimetype) != 'undefined'){
30873 formData.append('mimetype', file.mimetype);
30876 if(this.fireEvent('arrange', this, formData) != false){
30877 this.xhr.send(formData);
30881 xhrOnLoad : function(xhr)
30884 this.maskEl.unmask();
30887 if (xhr.readyState !== 4) {
30888 this.fireEvent('exception', this, xhr);
30892 var response = Roo.decode(xhr.responseText);
30894 if(!response.success){
30895 this.fireEvent('exception', this, xhr);
30899 var response = Roo.decode(xhr.responseText);
30901 this.fireEvent('upload', this, response);
30905 xhrOnError : function()
30908 this.maskEl.unmask();
30911 Roo.log('xhr on error');
30913 var response = Roo.decode(xhr.responseText);
30919 prepare : function(file)
30922 this.maskEl.mask(this.loadingText);
30928 if(typeof(file) === 'string'){
30929 this.loadCanvas(file);
30933 if(!file || !this.urlAPI){
30938 this.cropType = file.type;
30942 if(this.fireEvent('prepare', this, this.file) != false){
30944 var reader = new FileReader();
30946 reader.onload = function (e) {
30947 if (e.target.error) {
30948 Roo.log(e.target.error);
30952 var buffer = e.target.result,
30953 dataView = new DataView(buffer),
30955 maxOffset = dataView.byteLength - 4,
30959 if (dataView.getUint16(0) === 0xffd8) {
30960 while (offset < maxOffset) {
30961 markerBytes = dataView.getUint16(offset);
30963 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
30964 markerLength = dataView.getUint16(offset + 2) + 2;
30965 if (offset + markerLength > dataView.byteLength) {
30966 Roo.log('Invalid meta data: Invalid segment size.');
30970 if(markerBytes == 0xffe1){
30971 _this.parseExifData(
30978 offset += markerLength;
30988 var url = _this.urlAPI.createObjectURL(_this.file);
30990 _this.loadCanvas(url);
30995 reader.readAsArrayBuffer(this.file);
31001 parseExifData : function(dataView, offset, length)
31003 var tiffOffset = offset + 10,
31007 if (dataView.getUint32(offset + 4) !== 0x45786966) {
31008 // No Exif data, might be XMP data instead
31012 // Check for the ASCII code for "Exif" (0x45786966):
31013 if (dataView.getUint32(offset + 4) !== 0x45786966) {
31014 // No Exif data, might be XMP data instead
31017 if (tiffOffset + 8 > dataView.byteLength) {
31018 Roo.log('Invalid Exif data: Invalid segment size.');
31021 // Check for the two null bytes:
31022 if (dataView.getUint16(offset + 8) !== 0x0000) {
31023 Roo.log('Invalid Exif data: Missing byte alignment offset.');
31026 // Check the byte alignment:
31027 switch (dataView.getUint16(tiffOffset)) {
31029 littleEndian = true;
31032 littleEndian = false;
31035 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
31038 // Check for the TIFF tag marker (0x002A):
31039 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
31040 Roo.log('Invalid Exif data: Missing TIFF marker.');
31043 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
31044 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
31046 this.parseExifTags(
31049 tiffOffset + dirOffset,
31054 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
31059 if (dirOffset + 6 > dataView.byteLength) {
31060 Roo.log('Invalid Exif data: Invalid directory offset.');
31063 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
31064 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
31065 if (dirEndOffset + 4 > dataView.byteLength) {
31066 Roo.log('Invalid Exif data: Invalid directory size.');
31069 for (i = 0; i < tagsNumber; i += 1) {
31073 dirOffset + 2 + 12 * i, // tag offset
31077 // Return the offset to the next directory:
31078 return dataView.getUint32(dirEndOffset, littleEndian);
31081 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
31083 var tag = dataView.getUint16(offset, littleEndian);
31085 this.exif[tag] = this.getExifValue(
31089 dataView.getUint16(offset + 2, littleEndian), // tag type
31090 dataView.getUint32(offset + 4, littleEndian), // tag length
31095 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
31097 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
31106 Roo.log('Invalid Exif data: Invalid tag type.');
31110 tagSize = tagType.size * length;
31111 // Determine if the value is contained in the dataOffset bytes,
31112 // or if the value at the dataOffset is a pointer to the actual data:
31113 dataOffset = tagSize > 4 ?
31114 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
31115 if (dataOffset + tagSize > dataView.byteLength) {
31116 Roo.log('Invalid Exif data: Invalid data offset.');
31119 if (length === 1) {
31120 return tagType.getValue(dataView, dataOffset, littleEndian);
31123 for (i = 0; i < length; i += 1) {
31124 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
31127 if (tagType.ascii) {
31129 // Concatenate the chars:
31130 for (i = 0; i < values.length; i += 1) {
31132 // Ignore the terminating NULL byte(s):
31133 if (c === '\u0000') {
31145 Roo.apply(Roo.bootstrap.UploadCropbox, {
31147 'Orientation': 0x0112
31151 1: 0, //'top-left',
31153 3: 180, //'bottom-right',
31154 // 4: 'bottom-left',
31156 6: 90, //'right-top',
31157 // 7: 'right-bottom',
31158 8: 270 //'left-bottom'
31162 // byte, 8-bit unsigned int:
31164 getValue: function (dataView, dataOffset) {
31165 return dataView.getUint8(dataOffset);
31169 // ascii, 8-bit byte:
31171 getValue: function (dataView, dataOffset) {
31172 return String.fromCharCode(dataView.getUint8(dataOffset));
31177 // short, 16 bit int:
31179 getValue: function (dataView, dataOffset, littleEndian) {
31180 return dataView.getUint16(dataOffset, littleEndian);
31184 // long, 32 bit int:
31186 getValue: function (dataView, dataOffset, littleEndian) {
31187 return dataView.getUint32(dataOffset, littleEndian);
31191 // rational = two long values, first is numerator, second is denominator:
31193 getValue: function (dataView, dataOffset, littleEndian) {
31194 return dataView.getUint32(dataOffset, littleEndian) /
31195 dataView.getUint32(dataOffset + 4, littleEndian);
31199 // slong, 32 bit signed int:
31201 getValue: function (dataView, dataOffset, littleEndian) {
31202 return dataView.getInt32(dataOffset, littleEndian);
31206 // srational, two slongs, first is numerator, second is denominator:
31208 getValue: function (dataView, dataOffset, littleEndian) {
31209 return dataView.getInt32(dataOffset, littleEndian) /
31210 dataView.getInt32(dataOffset + 4, littleEndian);
31220 cls : 'btn-group roo-upload-cropbox-rotate-left',
31221 action : 'rotate-left',
31225 cls : 'btn btn-default',
31226 html : '<i class="fa fa-undo"></i>'
31232 cls : 'btn-group roo-upload-cropbox-picture',
31233 action : 'picture',
31237 cls : 'btn btn-default',
31238 html : '<i class="fa fa-picture-o"></i>'
31244 cls : 'btn-group roo-upload-cropbox-rotate-right',
31245 action : 'rotate-right',
31249 cls : 'btn btn-default',
31250 html : '<i class="fa fa-repeat"></i>'
31258 cls : 'btn-group roo-upload-cropbox-rotate-left',
31259 action : 'rotate-left',
31263 cls : 'btn btn-default',
31264 html : '<i class="fa fa-undo"></i>'
31270 cls : 'btn-group roo-upload-cropbox-download',
31271 action : 'download',
31275 cls : 'btn btn-default',
31276 html : '<i class="fa fa-download"></i>'
31282 cls : 'btn-group roo-upload-cropbox-crop',
31287 cls : 'btn btn-default',
31288 html : '<i class="fa fa-crop"></i>'
31294 cls : 'btn-group roo-upload-cropbox-trash',
31299 cls : 'btn btn-default',
31300 html : '<i class="fa fa-trash"></i>'
31306 cls : 'btn-group roo-upload-cropbox-rotate-right',
31307 action : 'rotate-right',
31311 cls : 'btn btn-default',
31312 html : '<i class="fa fa-repeat"></i>'
31320 cls : 'btn-group roo-upload-cropbox-rotate-left',
31321 action : 'rotate-left',
31325 cls : 'btn btn-default',
31326 html : '<i class="fa fa-undo"></i>'
31332 cls : 'btn-group roo-upload-cropbox-rotate-right',
31333 action : 'rotate-right',
31337 cls : 'btn btn-default',
31338 html : '<i class="fa fa-repeat"></i>'
31351 * @class Roo.bootstrap.DocumentManager
31352 * @extends Roo.bootstrap.Component
31353 * Bootstrap DocumentManager class
31354 * @cfg {String} paramName default 'imageUpload'
31355 * @cfg {String} toolTipName default 'filename'
31356 * @cfg {String} method default POST
31357 * @cfg {String} url action url
31358 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
31359 * @cfg {Boolean} multiple multiple upload default true
31360 * @cfg {Number} thumbSize default 300
31361 * @cfg {String} fieldLabel
31362 * @cfg {Number} labelWidth default 4
31363 * @cfg {String} labelAlign (left|top) default left
31364 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
31365 * @cfg {Number} labellg set the width of label (1-12)
31366 * @cfg {Number} labelmd set the width of label (1-12)
31367 * @cfg {Number} labelsm set the width of label (1-12)
31368 * @cfg {Number} labelxs set the width of label (1-12)
31371 * Create a new DocumentManager
31372 * @param {Object} config The config object
31375 Roo.bootstrap.DocumentManager = function(config){
31376 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
31379 this.delegates = [];
31384 * Fire when initial the DocumentManager
31385 * @param {Roo.bootstrap.DocumentManager} this
31390 * inspect selected file
31391 * @param {Roo.bootstrap.DocumentManager} this
31392 * @param {File} file
31397 * Fire when xhr load exception
31398 * @param {Roo.bootstrap.DocumentManager} this
31399 * @param {XMLHttpRequest} xhr
31401 "exception" : true,
31403 * @event afterupload
31404 * Fire when xhr load exception
31405 * @param {Roo.bootstrap.DocumentManager} this
31406 * @param {XMLHttpRequest} xhr
31408 "afterupload" : true,
31411 * prepare the form data
31412 * @param {Roo.bootstrap.DocumentManager} this
31413 * @param {Object} formData
31418 * Fire when remove the file
31419 * @param {Roo.bootstrap.DocumentManager} this
31420 * @param {Object} file
31425 * Fire after refresh the file
31426 * @param {Roo.bootstrap.DocumentManager} this
31431 * Fire after click the image
31432 * @param {Roo.bootstrap.DocumentManager} this
31433 * @param {Object} file
31438 * Fire when upload a image and editable set to true
31439 * @param {Roo.bootstrap.DocumentManager} this
31440 * @param {Object} file
31444 * @event beforeselectfile
31445 * Fire before select file
31446 * @param {Roo.bootstrap.DocumentManager} this
31448 "beforeselectfile" : true,
31451 * Fire before process file
31452 * @param {Roo.bootstrap.DocumentManager} this
31453 * @param {Object} file
31457 * @event previewrendered
31458 * Fire when preview rendered
31459 * @param {Roo.bootstrap.DocumentManager} this
31460 * @param {Object} file
31462 "previewrendered" : true,
31465 "previewResize" : true
31470 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
31479 paramName : 'imageUpload',
31480 toolTipName : 'filename',
31483 labelAlign : 'left',
31493 getAutoCreate : function()
31495 var managerWidget = {
31497 cls : 'roo-document-manager',
31501 cls : 'roo-document-manager-selector',
31506 cls : 'roo-document-manager-uploader',
31510 cls : 'roo-document-manager-upload-btn',
31511 html : '<i class="fa fa-plus"></i>'
31522 cls : 'column col-md-12',
31527 if(this.fieldLabel.length){
31532 cls : 'column col-md-12',
31533 html : this.fieldLabel
31537 cls : 'column col-md-12',
31542 if(this.labelAlign == 'left'){
31547 html : this.fieldLabel
31556 if(this.labelWidth > 12){
31557 content[0].style = "width: " + this.labelWidth + 'px';
31560 if(this.labelWidth < 13 && this.labelmd == 0){
31561 this.labelmd = this.labelWidth;
31564 if(this.labellg > 0){
31565 content[0].cls += ' col-lg-' + this.labellg;
31566 content[1].cls += ' col-lg-' + (12 - this.labellg);
31569 if(this.labelmd > 0){
31570 content[0].cls += ' col-md-' + this.labelmd;
31571 content[1].cls += ' col-md-' + (12 - this.labelmd);
31574 if(this.labelsm > 0){
31575 content[0].cls += ' col-sm-' + this.labelsm;
31576 content[1].cls += ' col-sm-' + (12 - this.labelsm);
31579 if(this.labelxs > 0){
31580 content[0].cls += ' col-xs-' + this.labelxs;
31581 content[1].cls += ' col-xs-' + (12 - this.labelxs);
31589 cls : 'row clearfix',
31597 initEvents : function()
31599 this.managerEl = this.el.select('.roo-document-manager', true).first();
31600 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
31602 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
31603 this.selectorEl.hide();
31606 this.selectorEl.attr('multiple', 'multiple');
31609 this.selectorEl.on('change', this.onFileSelected, this);
31611 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
31612 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
31614 this.uploader.on('click', this.onUploaderClick, this);
31616 this.renderProgressDialog();
31620 window.addEventListener("resize", function() { _this.refresh(); } );
31622 this.fireEvent('initial', this);
31625 renderProgressDialog : function()
31629 this.progressDialog = new Roo.bootstrap.Modal({
31630 cls : 'roo-document-manager-progress-dialog',
31631 allow_close : false,
31642 btnclick : function() {
31643 _this.uploadCancel();
31649 this.progressDialog.render(Roo.get(document.body));
31651 this.progress = new Roo.bootstrap.Progress({
31652 cls : 'roo-document-manager-progress',
31657 this.progress.render(this.progressDialog.getChildContainer());
31659 this.progressBar = new Roo.bootstrap.ProgressBar({
31660 cls : 'roo-document-manager-progress-bar',
31663 aria_valuemax : 12,
31667 this.progressBar.render(this.progress.getChildContainer());
31670 onUploaderClick : function(e)
31672 e.preventDefault();
31674 if(this.fireEvent('beforeselectfile', this) != false){
31675 this.selectorEl.dom.click();
31680 onFileSelected : function(e)
31682 e.preventDefault();
31684 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
31688 Roo.each(this.selectorEl.dom.files, function(file){
31689 if(this.fireEvent('inspect', this, file) != false){
31690 this.files.push(file);
31700 this.selectorEl.dom.value = '';
31702 if(!this.files || !this.files.length){
31706 if(this.boxes > 0 && this.files.length > this.boxes){
31707 this.files = this.files.slice(0, this.boxes);
31710 this.uploader.show();
31712 if(this.boxes > 0 && this.files.length > this.boxes - 1){
31713 this.uploader.hide();
31722 Roo.each(this.files, function(file){
31724 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
31725 var f = this.renderPreview(file);
31730 if(file.type.indexOf('image') != -1){
31731 this.delegates.push(
31733 _this.process(file);
31734 }).createDelegate(this)
31742 _this.process(file);
31743 }).createDelegate(this)
31748 this.files = files;
31750 this.delegates = this.delegates.concat(docs);
31752 if(!this.delegates.length){
31757 this.progressBar.aria_valuemax = this.delegates.length;
31764 arrange : function()
31766 if(!this.delegates.length){
31767 this.progressDialog.hide();
31772 var delegate = this.delegates.shift();
31774 this.progressDialog.show();
31776 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
31778 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
31783 refresh : function()
31785 this.uploader.show();
31787 if(this.boxes > 0 && this.files.length > this.boxes - 1){
31788 this.uploader.hide();
31791 Roo.isTouch ? this.closable(false) : this.closable(true);
31793 this.fireEvent('refresh', this);
31796 onRemove : function(e, el, o)
31798 e.preventDefault();
31800 this.fireEvent('remove', this, o);
31804 remove : function(o)
31808 Roo.each(this.files, function(file){
31809 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
31818 this.files = files;
31825 Roo.each(this.files, function(file){
31830 file.target.remove();
31839 onClick : function(e, el, o)
31841 e.preventDefault();
31843 this.fireEvent('click', this, o);
31847 closable : function(closable)
31849 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
31851 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
31863 xhrOnLoad : function(xhr)
31865 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
31869 if (xhr.readyState !== 4) {
31871 this.fireEvent('exception', this, xhr);
31875 var response = Roo.decode(xhr.responseText);
31877 if(!response.success){
31879 this.fireEvent('exception', this, xhr);
31883 var file = this.renderPreview(response.data);
31885 this.files.push(file);
31889 this.fireEvent('afterupload', this, xhr);
31893 xhrOnError : function(xhr)
31895 Roo.log('xhr on error');
31897 var response = Roo.decode(xhr.responseText);
31904 process : function(file)
31906 if(this.fireEvent('process', this, file) !== false){
31907 if(this.editable && file.type.indexOf('image') != -1){
31908 this.fireEvent('edit', this, file);
31912 this.uploadStart(file, false);
31919 uploadStart : function(file, crop)
31921 this.xhr = new XMLHttpRequest();
31923 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
31928 file.xhr = this.xhr;
31930 this.managerEl.createChild({
31932 cls : 'roo-document-manager-loading',
31936 tooltip : file.name,
31937 cls : 'roo-document-manager-thumb',
31938 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
31944 this.xhr.open(this.method, this.url, true);
31947 "Accept": "application/json",
31948 "Cache-Control": "no-cache",
31949 "X-Requested-With": "XMLHttpRequest"
31952 for (var headerName in headers) {
31953 var headerValue = headers[headerName];
31955 this.xhr.setRequestHeader(headerName, headerValue);
31961 this.xhr.onload = function()
31963 _this.xhrOnLoad(_this.xhr);
31966 this.xhr.onerror = function()
31968 _this.xhrOnError(_this.xhr);
31971 var formData = new FormData();
31973 formData.append('returnHTML', 'NO');
31976 formData.append('crop', crop);
31979 formData.append(this.paramName, file, file.name);
31986 if(this.fireEvent('prepare', this, formData, options) != false){
31988 if(options.manually){
31992 this.xhr.send(formData);
31996 this.uploadCancel();
31999 uploadCancel : function()
32005 this.delegates = [];
32007 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
32014 renderPreview : function(file)
32016 if(typeof(file.target) != 'undefined' && file.target){
32020 var img_src = encodeURI(baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename);
32022 var previewEl = this.managerEl.createChild({
32024 cls : 'roo-document-manager-preview',
32028 tooltip : file[this.toolTipName],
32029 cls : 'roo-document-manager-thumb',
32030 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + img_src + '">'
32035 html : '<i class="fa fa-times-circle"></i>'
32040 var close = previewEl.select('button.close', true).first();
32042 close.on('click', this.onRemove, this, file);
32044 file.target = previewEl;
32046 var image = previewEl.select('img', true).first();
32050 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
32052 image.on('click', this.onClick, this, file);
32054 this.fireEvent('previewrendered', this, file);
32060 onPreviewLoad : function(file, image)
32062 if(typeof(file.target) == 'undefined' || !file.target){
32066 var width = image.dom.naturalWidth || image.dom.width;
32067 var height = image.dom.naturalHeight || image.dom.height;
32069 if(!this.previewResize) {
32073 if(width > height){
32074 file.target.addClass('wide');
32078 file.target.addClass('tall');
32083 uploadFromSource : function(file, crop)
32085 this.xhr = new XMLHttpRequest();
32087 this.managerEl.createChild({
32089 cls : 'roo-document-manager-loading',
32093 tooltip : file.name,
32094 cls : 'roo-document-manager-thumb',
32095 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
32101 this.xhr.open(this.method, this.url, true);
32104 "Accept": "application/json",
32105 "Cache-Control": "no-cache",
32106 "X-Requested-With": "XMLHttpRequest"
32109 for (var headerName in headers) {
32110 var headerValue = headers[headerName];
32112 this.xhr.setRequestHeader(headerName, headerValue);
32118 this.xhr.onload = function()
32120 _this.xhrOnLoad(_this.xhr);
32123 this.xhr.onerror = function()
32125 _this.xhrOnError(_this.xhr);
32128 var formData = new FormData();
32130 formData.append('returnHTML', 'NO');
32132 formData.append('crop', crop);
32134 if(typeof(file.filename) != 'undefined'){
32135 formData.append('filename', file.filename);
32138 if(typeof(file.mimetype) != 'undefined'){
32139 formData.append('mimetype', file.mimetype);
32144 if(this.fireEvent('prepare', this, formData) != false){
32145 this.xhr.send(formData);
32155 * @class Roo.bootstrap.DocumentViewer
32156 * @extends Roo.bootstrap.Component
32157 * Bootstrap DocumentViewer class
32158 * @cfg {Boolean} showDownload (true|false) show download button (default true)
32159 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
32162 * Create a new DocumentViewer
32163 * @param {Object} config The config object
32166 Roo.bootstrap.DocumentViewer = function(config){
32167 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
32172 * Fire after initEvent
32173 * @param {Roo.bootstrap.DocumentViewer} this
32179 * @param {Roo.bootstrap.DocumentViewer} this
32184 * Fire after download button
32185 * @param {Roo.bootstrap.DocumentViewer} this
32190 * Fire after trash button
32191 * @param {Roo.bootstrap.DocumentViewer} this
32198 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
32200 showDownload : true,
32204 getAutoCreate : function()
32208 cls : 'roo-document-viewer',
32212 cls : 'roo-document-viewer-body',
32216 cls : 'roo-document-viewer-thumb',
32220 cls : 'roo-document-viewer-image'
32228 cls : 'roo-document-viewer-footer',
32231 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
32235 cls : 'btn-group roo-document-viewer-download',
32239 cls : 'btn btn-default',
32240 html : '<i class="fa fa-download"></i>'
32246 cls : 'btn-group roo-document-viewer-trash',
32250 cls : 'btn btn-default',
32251 html : '<i class="fa fa-trash"></i>'
32264 initEvents : function()
32266 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
32267 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
32269 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
32270 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
32272 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
32273 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
32275 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
32276 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
32278 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
32279 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
32281 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
32282 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
32284 this.bodyEl.on('click', this.onClick, this);
32285 this.downloadBtn.on('click', this.onDownload, this);
32286 this.trashBtn.on('click', this.onTrash, this);
32288 this.downloadBtn.hide();
32289 this.trashBtn.hide();
32291 if(this.showDownload){
32292 this.downloadBtn.show();
32295 if(this.showTrash){
32296 this.trashBtn.show();
32299 if(!this.showDownload && !this.showTrash) {
32300 this.footerEl.hide();
32305 initial : function()
32307 this.fireEvent('initial', this);
32311 onClick : function(e)
32313 e.preventDefault();
32315 this.fireEvent('click', this);
32318 onDownload : function(e)
32320 e.preventDefault();
32322 this.fireEvent('download', this);
32325 onTrash : function(e)
32327 e.preventDefault();
32329 this.fireEvent('trash', this);
32341 * @class Roo.bootstrap.NavProgressBar
32342 * @extends Roo.bootstrap.Component
32343 * Bootstrap NavProgressBar class
32346 * Create a new nav progress bar
32347 * @param {Object} config The config object
32350 Roo.bootstrap.NavProgressBar = function(config){
32351 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
32353 this.bullets = this.bullets || [];
32355 // Roo.bootstrap.NavProgressBar.register(this);
32359 * Fires when the active item changes
32360 * @param {Roo.bootstrap.NavProgressBar} this
32361 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
32362 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
32369 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
32374 getAutoCreate : function()
32376 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
32380 cls : 'roo-navigation-bar-group',
32384 cls : 'roo-navigation-top-bar'
32388 cls : 'roo-navigation-bullets-bar',
32392 cls : 'roo-navigation-bar'
32399 cls : 'roo-navigation-bottom-bar'
32409 initEvents: function()
32414 onRender : function(ct, position)
32416 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
32418 if(this.bullets.length){
32419 Roo.each(this.bullets, function(b){
32428 addItem : function(cfg)
32430 var item = new Roo.bootstrap.NavProgressItem(cfg);
32432 item.parentId = this.id;
32433 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
32436 var top = new Roo.bootstrap.Element({
32438 cls : 'roo-navigation-bar-text'
32441 var bottom = new Roo.bootstrap.Element({
32443 cls : 'roo-navigation-bar-text'
32446 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
32447 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
32449 var topText = new Roo.bootstrap.Element({
32451 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
32454 var bottomText = new Roo.bootstrap.Element({
32456 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
32459 topText.onRender(top.el, null);
32460 bottomText.onRender(bottom.el, null);
32463 item.bottomEl = bottom;
32466 this.barItems.push(item);
32471 getActive : function()
32473 var active = false;
32475 Roo.each(this.barItems, function(v){
32477 if (!v.isActive()) {
32489 setActiveItem : function(item)
32493 Roo.each(this.barItems, function(v){
32494 if (v.rid == item.rid) {
32498 if (v.isActive()) {
32499 v.setActive(false);
32504 item.setActive(true);
32506 this.fireEvent('changed', this, item, prev);
32509 getBarItem: function(rid)
32513 Roo.each(this.barItems, function(e) {
32514 if (e.rid != rid) {
32525 indexOfItem : function(item)
32529 Roo.each(this.barItems, function(v, i){
32531 if (v.rid != item.rid) {
32542 setActiveNext : function()
32544 var i = this.indexOfItem(this.getActive());
32546 if (i > this.barItems.length) {
32550 this.setActiveItem(this.barItems[i+1]);
32553 setActivePrev : function()
32555 var i = this.indexOfItem(this.getActive());
32561 this.setActiveItem(this.barItems[i-1]);
32564 format : function()
32566 if(!this.barItems.length){
32570 var width = 100 / this.barItems.length;
32572 Roo.each(this.barItems, function(i){
32573 i.el.setStyle('width', width + '%');
32574 i.topEl.el.setStyle('width', width + '%');
32575 i.bottomEl.el.setStyle('width', width + '%');
32584 * Nav Progress Item
32589 * @class Roo.bootstrap.NavProgressItem
32590 * @extends Roo.bootstrap.Component
32591 * Bootstrap NavProgressItem class
32592 * @cfg {String} rid the reference id
32593 * @cfg {Boolean} active (true|false) Is item active default false
32594 * @cfg {Boolean} disabled (true|false) Is item active default false
32595 * @cfg {String} html
32596 * @cfg {String} position (top|bottom) text position default bottom
32597 * @cfg {String} icon show icon instead of number
32600 * Create a new NavProgressItem
32601 * @param {Object} config The config object
32603 Roo.bootstrap.NavProgressItem = function(config){
32604 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
32609 * The raw click event for the entire grid.
32610 * @param {Roo.bootstrap.NavProgressItem} this
32611 * @param {Roo.EventObject} e
32618 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
32624 position : 'bottom',
32627 getAutoCreate : function()
32629 var iconCls = 'roo-navigation-bar-item-icon';
32631 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
32635 cls: 'roo-navigation-bar-item',
32645 cfg.cls += ' active';
32648 cfg.cls += ' disabled';
32654 disable : function()
32656 this.setDisabled(true);
32659 enable : function()
32661 this.setDisabled(false);
32664 initEvents: function()
32666 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
32668 this.iconEl.on('click', this.onClick, this);
32671 onClick : function(e)
32673 e.preventDefault();
32679 if(this.fireEvent('click', this, e) === false){
32683 this.parent().setActiveItem(this);
32686 isActive: function ()
32688 return this.active;
32691 setActive : function(state)
32693 if(this.active == state){
32697 this.active = state;
32700 this.el.addClass('active');
32704 this.el.removeClass('active');
32709 setDisabled : function(state)
32711 if(this.disabled == state){
32715 this.disabled = state;
32718 this.el.addClass('disabled');
32722 this.el.removeClass('disabled');
32725 tooltipEl : function()
32727 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
32740 * @class Roo.bootstrap.FieldLabel
32741 * @extends Roo.bootstrap.Component
32742 * Bootstrap FieldLabel class
32743 * @cfg {String} html contents of the element
32744 * @cfg {String} tag tag of the element default label
32745 * @cfg {String} cls class of the element
32746 * @cfg {String} target label target
32747 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
32748 * @cfg {String} invalidClass DEPRICATED - BS4 uses is-invalid
32749 * @cfg {String} validClass DEPRICATED - BS4 uses is-valid
32750 * @cfg {String} iconTooltip default "This field is required"
32751 * @cfg {String} indicatorpos (left|right) default left
32754 * Create a new FieldLabel
32755 * @param {Object} config The config object
32758 Roo.bootstrap.FieldLabel = function(config){
32759 Roo.bootstrap.Element.superclass.constructor.call(this, config);
32764 * Fires after the field has been marked as invalid.
32765 * @param {Roo.form.FieldLabel} this
32766 * @param {String} msg The validation message
32771 * Fires after the field has been validated with no errors.
32772 * @param {Roo.form.FieldLabel} this
32778 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
32785 invalidClass : 'has-warning',
32786 validClass : 'has-success',
32787 iconTooltip : 'This field is required',
32788 indicatorpos : 'left',
32790 getAutoCreate : function(){
32793 if (!this.allowBlank) {
32799 cls : 'roo-bootstrap-field-label ' + this.cls,
32804 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star ' + cls,
32805 tooltip : this.iconTooltip
32814 if(this.indicatorpos == 'right'){
32817 cls : 'roo-bootstrap-field-label ' + this.cls,
32826 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star '+ cls,
32827 tooltip : this.iconTooltip
32836 initEvents: function()
32838 Roo.bootstrap.Element.superclass.initEvents.call(this);
32840 this.indicator = this.indicatorEl();
32842 if(this.indicator){
32843 this.indicator.removeClass('visible');
32844 this.indicator.addClass('invisible');
32847 Roo.bootstrap.FieldLabel.register(this);
32850 indicatorEl : function()
32852 var indicator = this.el.select('i.roo-required-indicator',true).first();
32863 * Mark this field as valid
32865 markValid : function()
32867 if(this.indicator){
32868 this.indicator.removeClass('visible');
32869 this.indicator.addClass('invisible');
32871 if (Roo.bootstrap.version == 3) {
32872 this.el.removeClass(this.invalidClass);
32873 this.el.addClass(this.validClass);
32875 this.el.removeClass('is-invalid');
32876 this.el.addClass('is-valid');
32880 this.fireEvent('valid', this);
32884 * Mark this field as invalid
32885 * @param {String} msg The validation message
32887 markInvalid : function(msg)
32889 if(this.indicator){
32890 this.indicator.removeClass('invisible');
32891 this.indicator.addClass('visible');
32893 if (Roo.bootstrap.version == 3) {
32894 this.el.removeClass(this.validClass);
32895 this.el.addClass(this.invalidClass);
32897 this.el.removeClass('is-valid');
32898 this.el.addClass('is-invalid');
32902 this.fireEvent('invalid', this, msg);
32908 Roo.apply(Roo.bootstrap.FieldLabel, {
32913 * register a FieldLabel Group
32914 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
32916 register : function(label)
32918 if(this.groups.hasOwnProperty(label.target)){
32922 this.groups[label.target] = label;
32926 * fetch a FieldLabel Group based on the target
32927 * @param {string} target
32928 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
32930 get: function(target) {
32931 if (typeof(this.groups[target]) == 'undefined') {
32935 return this.groups[target] ;
32944 * page DateSplitField.
32950 * @class Roo.bootstrap.DateSplitField
32951 * @extends Roo.bootstrap.Component
32952 * Bootstrap DateSplitField class
32953 * @cfg {string} fieldLabel - the label associated
32954 * @cfg {Number} labelWidth set the width of label (0-12)
32955 * @cfg {String} labelAlign (top|left)
32956 * @cfg {Boolean} dayAllowBlank (true|false) default false
32957 * @cfg {Boolean} monthAllowBlank (true|false) default false
32958 * @cfg {Boolean} yearAllowBlank (true|false) default false
32959 * @cfg {string} dayPlaceholder
32960 * @cfg {string} monthPlaceholder
32961 * @cfg {string} yearPlaceholder
32962 * @cfg {string} dayFormat default 'd'
32963 * @cfg {string} monthFormat default 'm'
32964 * @cfg {string} yearFormat default 'Y'
32965 * @cfg {Number} labellg set the width of label (1-12)
32966 * @cfg {Number} labelmd set the width of label (1-12)
32967 * @cfg {Number} labelsm set the width of label (1-12)
32968 * @cfg {Number} labelxs set the width of label (1-12)
32972 * Create a new DateSplitField
32973 * @param {Object} config The config object
32976 Roo.bootstrap.DateSplitField = function(config){
32977 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
32983 * getting the data of years
32984 * @param {Roo.bootstrap.DateSplitField} this
32985 * @param {Object} years
32990 * getting the data of days
32991 * @param {Roo.bootstrap.DateSplitField} this
32992 * @param {Object} days
32997 * Fires after the field has been marked as invalid.
32998 * @param {Roo.form.Field} this
32999 * @param {String} msg The validation message
33004 * Fires after the field has been validated with no errors.
33005 * @param {Roo.form.Field} this
33011 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
33014 labelAlign : 'top',
33016 dayAllowBlank : false,
33017 monthAllowBlank : false,
33018 yearAllowBlank : false,
33019 dayPlaceholder : '',
33020 monthPlaceholder : '',
33021 yearPlaceholder : '',
33025 isFormField : true,
33031 getAutoCreate : function()
33035 cls : 'row roo-date-split-field-group',
33040 cls : 'form-hidden-field roo-date-split-field-group-value',
33046 var labelCls = 'col-md-12';
33047 var contentCls = 'col-md-4';
33049 if(this.fieldLabel){
33053 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
33057 html : this.fieldLabel
33062 if(this.labelAlign == 'left'){
33064 if(this.labelWidth > 12){
33065 label.style = "width: " + this.labelWidth + 'px';
33068 if(this.labelWidth < 13 && this.labelmd == 0){
33069 this.labelmd = this.labelWidth;
33072 if(this.labellg > 0){
33073 labelCls = ' col-lg-' + this.labellg;
33074 contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
33077 if(this.labelmd > 0){
33078 labelCls = ' col-md-' + this.labelmd;
33079 contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
33082 if(this.labelsm > 0){
33083 labelCls = ' col-sm-' + this.labelsm;
33084 contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
33087 if(this.labelxs > 0){
33088 labelCls = ' col-xs-' + this.labelxs;
33089 contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
33093 label.cls += ' ' + labelCls;
33095 cfg.cn.push(label);
33098 Roo.each(['day', 'month', 'year'], function(t){
33101 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
33108 inputEl: function ()
33110 return this.el.select('.roo-date-split-field-group-value', true).first();
33113 onRender : function(ct, position)
33117 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
33119 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
33121 this.dayField = new Roo.bootstrap.ComboBox({
33122 allowBlank : this.dayAllowBlank,
33123 alwaysQuery : true,
33124 displayField : 'value',
33127 forceSelection : true,
33129 placeholder : this.dayPlaceholder,
33130 selectOnFocus : true,
33131 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
33132 triggerAction : 'all',
33134 valueField : 'value',
33135 store : new Roo.data.SimpleStore({
33136 data : (function() {
33138 _this.fireEvent('days', _this, days);
33141 fields : [ 'value' ]
33144 select : function (_self, record, index)
33146 _this.setValue(_this.getValue());
33151 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
33153 this.monthField = new Roo.bootstrap.MonthField({
33154 after : '<i class=\"fa fa-calendar\"></i>',
33155 allowBlank : this.monthAllowBlank,
33156 placeholder : this.monthPlaceholder,
33159 render : function (_self)
33161 this.el.select('span.input-group-addon', true).first().on('click', function(e){
33162 e.preventDefault();
33166 select : function (_self, oldvalue, newvalue)
33168 _this.setValue(_this.getValue());
33173 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
33175 this.yearField = new Roo.bootstrap.ComboBox({
33176 allowBlank : this.yearAllowBlank,
33177 alwaysQuery : true,
33178 displayField : 'value',
33181 forceSelection : true,
33183 placeholder : this.yearPlaceholder,
33184 selectOnFocus : true,
33185 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
33186 triggerAction : 'all',
33188 valueField : 'value',
33189 store : new Roo.data.SimpleStore({
33190 data : (function() {
33192 _this.fireEvent('years', _this, years);
33195 fields : [ 'value' ]
33198 select : function (_self, record, index)
33200 _this.setValue(_this.getValue());
33205 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
33208 setValue : function(v, format)
33210 this.inputEl.dom.value = v;
33212 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
33214 var d = Date.parseDate(v, f);
33221 this.setDay(d.format(this.dayFormat));
33222 this.setMonth(d.format(this.monthFormat));
33223 this.setYear(d.format(this.yearFormat));
33230 setDay : function(v)
33232 this.dayField.setValue(v);
33233 this.inputEl.dom.value = this.getValue();
33238 setMonth : function(v)
33240 this.monthField.setValue(v, true);
33241 this.inputEl.dom.value = this.getValue();
33246 setYear : function(v)
33248 this.yearField.setValue(v);
33249 this.inputEl.dom.value = this.getValue();
33254 getDay : function()
33256 return this.dayField.getValue();
33259 getMonth : function()
33261 return this.monthField.getValue();
33264 getYear : function()
33266 return this.yearField.getValue();
33269 getValue : function()
33271 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
33273 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
33283 this.inputEl.dom.value = '';
33288 validate : function()
33290 var d = this.dayField.validate();
33291 var m = this.monthField.validate();
33292 var y = this.yearField.validate();
33297 (!this.dayAllowBlank && !d) ||
33298 (!this.monthAllowBlank && !m) ||
33299 (!this.yearAllowBlank && !y)
33304 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
33313 this.markInvalid();
33318 markValid : function()
33321 var label = this.el.select('label', true).first();
33322 var icon = this.el.select('i.fa-star', true).first();
33328 this.fireEvent('valid', this);
33332 * Mark this field as invalid
33333 * @param {String} msg The validation message
33335 markInvalid : function(msg)
33338 var label = this.el.select('label', true).first();
33339 var icon = this.el.select('i.fa-star', true).first();
33341 if(label && !icon){
33342 this.el.select('.roo-date-split-field-label', true).createChild({
33344 cls : 'text-danger fa fa-lg fa-star',
33345 tooltip : 'This field is required',
33346 style : 'margin-right:5px;'
33350 this.fireEvent('invalid', this, msg);
33353 clearInvalid : function()
33355 var label = this.el.select('label', true).first();
33356 var icon = this.el.select('i.fa-star', true).first();
33362 this.fireEvent('valid', this);
33365 getName: function()
33375 * http://masonry.desandro.com
33377 * The idea is to render all the bricks based on vertical width...
33379 * The original code extends 'outlayer' - we might need to use that....
33385 * @class Roo.bootstrap.LayoutMasonry
33386 * @extends Roo.bootstrap.Component
33387 * Bootstrap Layout Masonry class
33390 * Create a new Element
33391 * @param {Object} config The config object
33394 Roo.bootstrap.LayoutMasonry = function(config){
33396 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
33400 Roo.bootstrap.LayoutMasonry.register(this);
33406 * Fire after layout the items
33407 * @param {Roo.bootstrap.LayoutMasonry} this
33408 * @param {Roo.EventObject} e
33415 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
33418 * @cfg {Boolean} isLayoutInstant = no animation?
33420 isLayoutInstant : false, // needed?
33423 * @cfg {Number} boxWidth width of the columns
33428 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
33433 * @cfg {Number} padWidth padding below box..
33438 * @cfg {Number} gutter gutter width..
33443 * @cfg {Number} maxCols maximum number of columns
33449 * @cfg {Boolean} isAutoInitial defalut true
33451 isAutoInitial : true,
33456 * @cfg {Boolean} isHorizontal defalut false
33458 isHorizontal : false,
33460 currentSize : null,
33466 bricks: null, //CompositeElement
33470 _isLayoutInited : false,
33472 // isAlternative : false, // only use for vertical layout...
33475 * @cfg {Number} alternativePadWidth padding below box..
33477 alternativePadWidth : 50,
33479 selectedBrick : [],
33481 getAutoCreate : function(){
33483 var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
33487 cls: 'blog-masonary-wrapper ' + this.cls,
33489 cls : 'mas-boxes masonary'
33496 getChildContainer: function( )
33498 if (this.boxesEl) {
33499 return this.boxesEl;
33502 this.boxesEl = this.el.select('.mas-boxes').first();
33504 return this.boxesEl;
33508 initEvents : function()
33512 if(this.isAutoInitial){
33513 Roo.log('hook children rendered');
33514 this.on('childrenrendered', function() {
33515 Roo.log('children rendered');
33521 initial : function()
33523 this.selectedBrick = [];
33525 this.currentSize = this.el.getBox(true);
33527 Roo.EventManager.onWindowResize(this.resize, this);
33529 if(!this.isAutoInitial){
33537 //this.layout.defer(500,this);
33541 resize : function()
33543 var cs = this.el.getBox(true);
33546 this.currentSize.width == cs.width &&
33547 this.currentSize.x == cs.x &&
33548 this.currentSize.height == cs.height &&
33549 this.currentSize.y == cs.y
33551 Roo.log("no change in with or X or Y");
33555 this.currentSize = cs;
33561 layout : function()
33563 this._resetLayout();
33565 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
33567 this.layoutItems( isInstant );
33569 this._isLayoutInited = true;
33571 this.fireEvent('layout', this);
33575 _resetLayout : function()
33577 if(this.isHorizontal){
33578 this.horizontalMeasureColumns();
33582 this.verticalMeasureColumns();
33586 verticalMeasureColumns : function()
33588 this.getContainerWidth();
33590 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
33591 // this.colWidth = Math.floor(this.containerWidth * 0.8);
33595 var boxWidth = this.boxWidth + this.padWidth;
33597 if(this.containerWidth < this.boxWidth){
33598 boxWidth = this.containerWidth
33601 var containerWidth = this.containerWidth;
33603 var cols = Math.floor(containerWidth / boxWidth);
33605 this.cols = Math.max( cols, 1 );
33607 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
33609 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
33611 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
33613 this.colWidth = boxWidth + avail - this.padWidth;
33615 this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
33616 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
33619 horizontalMeasureColumns : function()
33621 this.getContainerWidth();
33623 var boxWidth = this.boxWidth;
33625 if(this.containerWidth < boxWidth){
33626 boxWidth = this.containerWidth;
33629 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
33631 this.el.setHeight(boxWidth);
33635 getContainerWidth : function()
33637 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
33640 layoutItems : function( isInstant )
33642 Roo.log(this.bricks);
33644 var items = Roo.apply([], this.bricks);
33646 if(this.isHorizontal){
33647 this._horizontalLayoutItems( items , isInstant );
33651 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
33652 // this._verticalAlternativeLayoutItems( items , isInstant );
33656 this._verticalLayoutItems( items , isInstant );
33660 _verticalLayoutItems : function ( items , isInstant)
33662 if ( !items || !items.length ) {
33667 ['xs', 'xs', 'xs', 'tall'],
33668 ['xs', 'xs', 'tall'],
33669 ['xs', 'xs', 'sm'],
33670 ['xs', 'xs', 'xs'],
33676 ['sm', 'xs', 'xs'],
33680 ['tall', 'xs', 'xs', 'xs'],
33681 ['tall', 'xs', 'xs'],
33693 Roo.each(items, function(item, k){
33695 switch (item.size) {
33696 // these layouts take up a full box,
33707 boxes.push([item]);
33730 var filterPattern = function(box, length)
33738 var pattern = box.slice(0, length);
33742 Roo.each(pattern, function(i){
33743 format.push(i.size);
33746 Roo.each(standard, function(s){
33748 if(String(s) != String(format)){
33757 if(!match && length == 1){
33762 filterPattern(box, length - 1);
33766 queue.push(pattern);
33768 box = box.slice(length, box.length);
33770 filterPattern(box, 4);
33776 Roo.each(boxes, function(box, k){
33782 if(box.length == 1){
33787 filterPattern(box, 4);
33791 this._processVerticalLayoutQueue( queue, isInstant );
33795 // _verticalAlternativeLayoutItems : function( items , isInstant )
33797 // if ( !items || !items.length ) {
33801 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
33805 _horizontalLayoutItems : function ( items , isInstant)
33807 if ( !items || !items.length || items.length < 3) {
33813 var eItems = items.slice(0, 3);
33815 items = items.slice(3, items.length);
33818 ['xs', 'xs', 'xs', 'wide'],
33819 ['xs', 'xs', 'wide'],
33820 ['xs', 'xs', 'sm'],
33821 ['xs', 'xs', 'xs'],
33827 ['sm', 'xs', 'xs'],
33831 ['wide', 'xs', 'xs', 'xs'],
33832 ['wide', 'xs', 'xs'],
33845 Roo.each(items, function(item, k){
33847 switch (item.size) {
33858 boxes.push([item]);
33882 var filterPattern = function(box, length)
33890 var pattern = box.slice(0, length);
33894 Roo.each(pattern, function(i){
33895 format.push(i.size);
33898 Roo.each(standard, function(s){
33900 if(String(s) != String(format)){
33909 if(!match && length == 1){
33914 filterPattern(box, length - 1);
33918 queue.push(pattern);
33920 box = box.slice(length, box.length);
33922 filterPattern(box, 4);
33928 Roo.each(boxes, function(box, k){
33934 if(box.length == 1){
33939 filterPattern(box, 4);
33946 var pos = this.el.getBox(true);
33950 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
33952 var hit_end = false;
33954 Roo.each(queue, function(box){
33958 Roo.each(box, function(b){
33960 b.el.setVisibilityMode(Roo.Element.DISPLAY);
33970 Roo.each(box, function(b){
33972 b.el.setVisibilityMode(Roo.Element.DISPLAY);
33975 mx = Math.max(mx, b.x);
33979 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
33983 Roo.each(box, function(b){
33985 b.el.setVisibilityMode(Roo.Element.DISPLAY);
33999 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
34002 /** Sets position of item in DOM
34003 * @param {Element} item
34004 * @param {Number} x - horizontal position
34005 * @param {Number} y - vertical position
34006 * @param {Boolean} isInstant - disables transitions
34008 _processVerticalLayoutQueue : function( queue, isInstant )
34010 var pos = this.el.getBox(true);
34015 for (var i = 0; i < this.cols; i++){
34019 Roo.each(queue, function(box, k){
34021 var col = k % this.cols;
34023 Roo.each(box, function(b,kk){
34025 b.el.position('absolute');
34027 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
34028 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
34030 if(b.size == 'md-left' || b.size == 'md-right'){
34031 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
34032 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
34035 b.el.setWidth(width);
34036 b.el.setHeight(height);
34038 b.el.select('iframe',true).setSize(width,height);
34042 for (var i = 0; i < this.cols; i++){
34044 if(maxY[i] < maxY[col]){
34049 col = Math.min(col, i);
34053 x = pos.x + col * (this.colWidth + this.padWidth);
34057 var positions = [];
34059 switch (box.length){
34061 positions = this.getVerticalOneBoxColPositions(x, y, box);
34064 positions = this.getVerticalTwoBoxColPositions(x, y, box);
34067 positions = this.getVerticalThreeBoxColPositions(x, y, box);
34070 positions = this.getVerticalFourBoxColPositions(x, y, box);
34076 Roo.each(box, function(b,kk){
34078 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
34080 var sz = b.el.getSize();
34082 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
34090 for (var i = 0; i < this.cols; i++){
34091 mY = Math.max(mY, maxY[i]);
34094 this.el.setHeight(mY - pos.y);
34098 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
34100 // var pos = this.el.getBox(true);
34103 // var maxX = pos.right;
34105 // var maxHeight = 0;
34107 // Roo.each(items, function(item, k){
34111 // item.el.position('absolute');
34113 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
34115 // item.el.setWidth(width);
34117 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
34119 // item.el.setHeight(height);
34122 // item.el.setXY([x, y], isInstant ? false : true);
34124 // item.el.setXY([maxX - width, y], isInstant ? false : true);
34127 // y = y + height + this.alternativePadWidth;
34129 // maxHeight = maxHeight + height + this.alternativePadWidth;
34133 // this.el.setHeight(maxHeight);
34137 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
34139 var pos = this.el.getBox(true);
34144 var maxX = pos.right;
34146 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
34148 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
34150 Roo.each(queue, function(box, k){
34152 Roo.each(box, function(b, kk){
34154 b.el.position('absolute');
34156 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
34157 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
34159 if(b.size == 'md-left' || b.size == 'md-right'){
34160 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
34161 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
34164 b.el.setWidth(width);
34165 b.el.setHeight(height);
34173 var positions = [];
34175 switch (box.length){
34177 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
34180 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
34183 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
34186 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
34192 Roo.each(box, function(b,kk){
34194 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
34196 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
34204 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
34206 Roo.each(eItems, function(b,k){
34208 b.size = (k == 0) ? 'sm' : 'xs';
34209 b.x = (k == 0) ? 2 : 1;
34210 b.y = (k == 0) ? 2 : 1;
34212 b.el.position('absolute');
34214 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
34216 b.el.setWidth(width);
34218 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
34220 b.el.setHeight(height);
34224 var positions = [];
34227 x : maxX - this.unitWidth * 2 - this.gutter,
34232 x : maxX - this.unitWidth,
34233 y : minY + (this.unitWidth + this.gutter) * 2
34237 x : maxX - this.unitWidth * 3 - this.gutter * 2,
34241 Roo.each(eItems, function(b,k){
34243 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
34249 getVerticalOneBoxColPositions : function(x, y, box)
34253 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
34255 if(box[0].size == 'md-left'){
34259 if(box[0].size == 'md-right'){
34264 x : x + (this.unitWidth + this.gutter) * rand,
34271 getVerticalTwoBoxColPositions : function(x, y, box)
34275 if(box[0].size == 'xs'){
34279 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
34283 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
34297 x : x + (this.unitWidth + this.gutter) * 2,
34298 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
34305 getVerticalThreeBoxColPositions : function(x, y, box)
34309 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
34317 x : x + (this.unitWidth + this.gutter) * 1,
34322 x : x + (this.unitWidth + this.gutter) * 2,
34330 if(box[0].size == 'xs' && box[1].size == 'xs'){
34339 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
34343 x : x + (this.unitWidth + this.gutter) * 1,
34357 x : x + (this.unitWidth + this.gutter) * 2,
34362 x : x + (this.unitWidth + this.gutter) * 2,
34363 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
34370 getVerticalFourBoxColPositions : function(x, y, box)
34374 if(box[0].size == 'xs'){
34383 y : y + (this.unitHeight + this.gutter) * 1
34388 y : y + (this.unitHeight + this.gutter) * 2
34392 x : x + (this.unitWidth + this.gutter) * 1,
34406 x : x + (this.unitWidth + this.gutter) * 2,
34411 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
34412 y : y + (this.unitHeight + this.gutter) * 1
34416 x : x + (this.unitWidth + this.gutter) * 2,
34417 y : y + (this.unitWidth + this.gutter) * 2
34424 getHorizontalOneBoxColPositions : function(maxX, minY, box)
34428 if(box[0].size == 'md-left'){
34430 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
34437 if(box[0].size == 'md-right'){
34439 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
34440 y : minY + (this.unitWidth + this.gutter) * 1
34446 var rand = Math.floor(Math.random() * (4 - box[0].y));
34449 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
34450 y : minY + (this.unitWidth + this.gutter) * rand
34457 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
34461 if(box[0].size == 'xs'){
34464 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
34469 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
34470 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
34478 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
34483 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
34484 y : minY + (this.unitWidth + this.gutter) * 2
34491 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
34495 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
34498 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
34503 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
34504 y : minY + (this.unitWidth + this.gutter) * 1
34508 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
34509 y : minY + (this.unitWidth + this.gutter) * 2
34516 if(box[0].size == 'xs' && box[1].size == 'xs'){
34519 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
34524 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
34529 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
34530 y : minY + (this.unitWidth + this.gutter) * 1
34538 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
34543 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
34544 y : minY + (this.unitWidth + this.gutter) * 2
34548 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
34549 y : minY + (this.unitWidth + this.gutter) * 2
34556 getHorizontalFourBoxColPositions : function(maxX, minY, box)
34560 if(box[0].size == 'xs'){
34563 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
34568 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
34573 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),
34578 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
34579 y : minY + (this.unitWidth + this.gutter) * 1
34587 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
34592 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
34593 y : minY + (this.unitWidth + this.gutter) * 2
34597 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
34598 y : minY + (this.unitWidth + this.gutter) * 2
34602 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),
34603 y : minY + (this.unitWidth + this.gutter) * 2
34611 * remove a Masonry Brick
34612 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
34614 removeBrick : function(brick_id)
34620 for (var i = 0; i<this.bricks.length; i++) {
34621 if (this.bricks[i].id == brick_id) {
34622 this.bricks.splice(i,1);
34623 this.el.dom.removeChild(Roo.get(brick_id).dom);
34630 * adds a Masonry Brick
34631 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
34633 addBrick : function(cfg)
34635 var cn = new Roo.bootstrap.MasonryBrick(cfg);
34636 //this.register(cn);
34637 cn.parentId = this.id;
34638 cn.render(this.el);
34643 * register a Masonry Brick
34644 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
34647 register : function(brick)
34649 this.bricks.push(brick);
34650 brick.masonryId = this.id;
34654 * clear all the Masonry Brick
34656 clearAll : function()
34659 //this.getChildContainer().dom.innerHTML = "";
34660 this.el.dom.innerHTML = '';
34663 getSelected : function()
34665 if (!this.selectedBrick) {
34669 return this.selectedBrick;
34673 Roo.apply(Roo.bootstrap.LayoutMasonry, {
34677 * register a Masonry Layout
34678 * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
34681 register : function(layout)
34683 this.groups[layout.id] = layout;
34686 * fetch a Masonry Layout based on the masonry layout ID
34687 * @param {string} the masonry layout to add
34688 * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
34691 get: function(layout_id) {
34692 if (typeof(this.groups[layout_id]) == 'undefined') {
34695 return this.groups[layout_id] ;
34707 * http://masonry.desandro.com
34709 * The idea is to render all the bricks based on vertical width...
34711 * The original code extends 'outlayer' - we might need to use that....
34717 * @class Roo.bootstrap.LayoutMasonryAuto
34718 * @extends Roo.bootstrap.Component
34719 * Bootstrap Layout Masonry class
34722 * Create a new Element
34723 * @param {Object} config The config object
34726 Roo.bootstrap.LayoutMasonryAuto = function(config){
34727 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
34730 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
34733 * @cfg {Boolean} isFitWidth - resize the width..
34735 isFitWidth : false, // options..
34737 * @cfg {Boolean} isOriginLeft = left align?
34739 isOriginLeft : true,
34741 * @cfg {Boolean} isOriginTop = top align?
34743 isOriginTop : false,
34745 * @cfg {Boolean} isLayoutInstant = no animation?
34747 isLayoutInstant : false, // needed?
34749 * @cfg {Boolean} isResizingContainer = not sure if this is used..
34751 isResizingContainer : true,
34753 * @cfg {Number} columnWidth width of the columns
34759 * @cfg {Number} maxCols maximum number of columns
34764 * @cfg {Number} padHeight padding below box..
34770 * @cfg {Boolean} isAutoInitial defalut true
34773 isAutoInitial : true,
34779 initialColumnWidth : 0,
34780 currentSize : null,
34782 colYs : null, // array.
34789 bricks: null, //CompositeElement
34790 cols : 0, // array?
34791 // element : null, // wrapped now this.el
34792 _isLayoutInited : null,
34795 getAutoCreate : function(){
34799 cls: 'blog-masonary-wrapper ' + this.cls,
34801 cls : 'mas-boxes masonary'
34808 getChildContainer: function( )
34810 if (this.boxesEl) {
34811 return this.boxesEl;
34814 this.boxesEl = this.el.select('.mas-boxes').first();
34816 return this.boxesEl;
34820 initEvents : function()
34824 if(this.isAutoInitial){
34825 Roo.log('hook children rendered');
34826 this.on('childrenrendered', function() {
34827 Roo.log('children rendered');
34834 initial : function()
34836 this.reloadItems();
34838 this.currentSize = this.el.getBox(true);
34840 /// was window resize... - let's see if this works..
34841 Roo.EventManager.onWindowResize(this.resize, this);
34843 if(!this.isAutoInitial){
34848 this.layout.defer(500,this);
34851 reloadItems: function()
34853 this.bricks = this.el.select('.masonry-brick', true);
34855 this.bricks.each(function(b) {
34856 //Roo.log(b.getSize());
34857 if (!b.attr('originalwidth')) {
34858 b.attr('originalwidth', b.getSize().width);
34863 Roo.log(this.bricks.elements.length);
34866 resize : function()
34869 var cs = this.el.getBox(true);
34871 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
34872 Roo.log("no change in with or X");
34875 this.currentSize = cs;
34879 layout : function()
34882 this._resetLayout();
34883 //this._manageStamps();
34885 // don't animate first layout
34886 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
34887 this.layoutItems( isInstant );
34889 // flag for initalized
34890 this._isLayoutInited = true;
34893 layoutItems : function( isInstant )
34895 //var items = this._getItemsForLayout( this.items );
34896 // original code supports filtering layout items.. we just ignore it..
34898 this._layoutItems( this.bricks , isInstant );
34900 this._postLayout();
34902 _layoutItems : function ( items , isInstant)
34904 //this.fireEvent( 'layout', this, items );
34907 if ( !items || !items.elements.length ) {
34908 // no items, emit event with empty array
34913 items.each(function(item) {
34914 Roo.log("layout item");
34916 // get x/y object from method
34917 var position = this._getItemLayoutPosition( item );
34919 position.item = item;
34920 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
34921 queue.push( position );
34924 this._processLayoutQueue( queue );
34926 /** Sets position of item in DOM
34927 * @param {Element} item
34928 * @param {Number} x - horizontal position
34929 * @param {Number} y - vertical position
34930 * @param {Boolean} isInstant - disables transitions
34932 _processLayoutQueue : function( queue )
34934 for ( var i=0, len = queue.length; i < len; i++ ) {
34935 var obj = queue[i];
34936 obj.item.position('absolute');
34937 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
34943 * Any logic you want to do after each layout,
34944 * i.e. size the container
34946 _postLayout : function()
34948 this.resizeContainer();
34951 resizeContainer : function()
34953 if ( !this.isResizingContainer ) {
34956 var size = this._getContainerSize();
34958 this.el.setSize(size.width,size.height);
34959 this.boxesEl.setSize(size.width,size.height);
34965 _resetLayout : function()
34967 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
34968 this.colWidth = this.el.getWidth();
34969 //this.gutter = this.el.getWidth();
34971 this.measureColumns();
34977 this.colYs.push( 0 );
34983 measureColumns : function()
34985 this.getContainerWidth();
34986 // if columnWidth is 0, default to outerWidth of first item
34987 if ( !this.columnWidth ) {
34988 var firstItem = this.bricks.first();
34989 Roo.log(firstItem);
34990 this.columnWidth = this.containerWidth;
34991 if (firstItem && firstItem.attr('originalwidth') ) {
34992 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
34994 // columnWidth fall back to item of first element
34995 Roo.log("set column width?");
34996 this.initialColumnWidth = this.columnWidth ;
34998 // if first elem has no width, default to size of container
35003 if (this.initialColumnWidth) {
35004 this.columnWidth = this.initialColumnWidth;
35009 // column width is fixed at the top - however if container width get's smaller we should
35012 // this bit calcs how man columns..
35014 var columnWidth = this.columnWidth += this.gutter;
35016 // calculate columns
35017 var containerWidth = this.containerWidth + this.gutter;
35019 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
35020 // fix rounding errors, typically with gutters
35021 var excess = columnWidth - containerWidth % columnWidth;
35024 // if overshoot is less than a pixel, round up, otherwise floor it
35025 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
35026 cols = Math[ mathMethod ]( cols );
35027 this.cols = Math.max( cols, 1 );
35028 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
35030 // padding positioning..
35031 var totalColWidth = this.cols * this.columnWidth;
35032 var padavail = this.containerWidth - totalColWidth;
35033 // so for 2 columns - we need 3 'pads'
35035 var padNeeded = (1+this.cols) * this.padWidth;
35037 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
35039 this.columnWidth += padExtra
35040 //this.padWidth = Math.floor(padavail / ( this.cols));
35042 // adjust colum width so that padding is fixed??
35044 // we have 3 columns ... total = width * 3
35045 // we have X left over... that should be used by
35047 //if (this.expandC) {
35055 getContainerWidth : function()
35057 /* // container is parent if fit width
35058 var container = this.isFitWidth ? this.element.parentNode : this.element;
35059 // check that this.size and size are there
35060 // IE8 triggers resize on body size change, so they might not be
35062 var size = getSize( container ); //FIXME
35063 this.containerWidth = size && size.innerWidth; //FIXME
35066 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
35070 _getItemLayoutPosition : function( item ) // what is item?
35072 // we resize the item to our columnWidth..
35074 item.setWidth(this.columnWidth);
35075 item.autoBoxAdjust = false;
35077 var sz = item.getSize();
35079 // how many columns does this brick span
35080 var remainder = this.containerWidth % this.columnWidth;
35082 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
35083 // round if off by 1 pixel, otherwise use ceil
35084 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
35085 colSpan = Math.min( colSpan, this.cols );
35087 // normally this should be '1' as we dont' currently allow multi width columns..
35089 var colGroup = this._getColGroup( colSpan );
35090 // get the minimum Y value from the columns
35091 var minimumY = Math.min.apply( Math, colGroup );
35092 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
35094 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
35096 // position the brick
35098 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
35099 y: this.currentSize.y + minimumY + this.padHeight
35103 // apply setHeight to necessary columns
35104 var setHeight = minimumY + sz.height + this.padHeight;
35105 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
35107 var setSpan = this.cols + 1 - colGroup.length;
35108 for ( var i = 0; i < setSpan; i++ ) {
35109 this.colYs[ shortColIndex + i ] = setHeight ;
35116 * @param {Number} colSpan - number of columns the element spans
35117 * @returns {Array} colGroup
35119 _getColGroup : function( colSpan )
35121 if ( colSpan < 2 ) {
35122 // if brick spans only one column, use all the column Ys
35127 // how many different places could this brick fit horizontally
35128 var groupCount = this.cols + 1 - colSpan;
35129 // for each group potential horizontal position
35130 for ( var i = 0; i < groupCount; i++ ) {
35131 // make an array of colY values for that one group
35132 var groupColYs = this.colYs.slice( i, i + colSpan );
35133 // and get the max value of the array
35134 colGroup[i] = Math.max.apply( Math, groupColYs );
35139 _manageStamp : function( stamp )
35141 var stampSize = stamp.getSize();
35142 var offset = stamp.getBox();
35143 // get the columns that this stamp affects
35144 var firstX = this.isOriginLeft ? offset.x : offset.right;
35145 var lastX = firstX + stampSize.width;
35146 var firstCol = Math.floor( firstX / this.columnWidth );
35147 firstCol = Math.max( 0, firstCol );
35149 var lastCol = Math.floor( lastX / this.columnWidth );
35150 // lastCol should not go over if multiple of columnWidth #425
35151 lastCol -= lastX % this.columnWidth ? 0 : 1;
35152 lastCol = Math.min( this.cols - 1, lastCol );
35154 // set colYs to bottom of the stamp
35155 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
35158 for ( var i = firstCol; i <= lastCol; i++ ) {
35159 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
35164 _getContainerSize : function()
35166 this.maxY = Math.max.apply( Math, this.colYs );
35171 if ( this.isFitWidth ) {
35172 size.width = this._getContainerFitWidth();
35178 _getContainerFitWidth : function()
35180 var unusedCols = 0;
35181 // count unused columns
35184 if ( this.colYs[i] !== 0 ) {
35189 // fit container to columns that have been used
35190 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
35193 needsResizeLayout : function()
35195 var previousWidth = this.containerWidth;
35196 this.getContainerWidth();
35197 return previousWidth !== this.containerWidth;
35212 * @class Roo.bootstrap.MasonryBrick
35213 * @extends Roo.bootstrap.Component
35214 * Bootstrap MasonryBrick class
35217 * Create a new MasonryBrick
35218 * @param {Object} config The config object
35221 Roo.bootstrap.MasonryBrick = function(config){
35223 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
35225 Roo.bootstrap.MasonryBrick.register(this);
35231 * When a MasonryBrick is clcik
35232 * @param {Roo.bootstrap.MasonryBrick} this
35233 * @param {Roo.EventObject} e
35239 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
35242 * @cfg {String} title
35246 * @cfg {String} html
35250 * @cfg {String} bgimage
35254 * @cfg {String} videourl
35258 * @cfg {String} cls
35262 * @cfg {String} href
35266 * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
35271 * @cfg {String} placetitle (center|bottom)
35276 * @cfg {Boolean} isFitContainer defalut true
35278 isFitContainer : true,
35281 * @cfg {Boolean} preventDefault defalut false
35283 preventDefault : false,
35286 * @cfg {Boolean} inverse defalut false
35288 maskInverse : false,
35290 getAutoCreate : function()
35292 if(!this.isFitContainer){
35293 return this.getSplitAutoCreate();
35296 var cls = 'masonry-brick masonry-brick-full';
35298 if(this.href.length){
35299 cls += ' masonry-brick-link';
35302 if(this.bgimage.length){
35303 cls += ' masonry-brick-image';
35306 if(this.maskInverse){
35307 cls += ' mask-inverse';
35310 if(!this.html.length && !this.maskInverse && !this.videourl.length){
35311 cls += ' enable-mask';
35315 cls += ' masonry-' + this.size + '-brick';
35318 if(this.placetitle.length){
35320 switch (this.placetitle) {
35322 cls += ' masonry-center-title';
35325 cls += ' masonry-bottom-title';
35332 if(!this.html.length && !this.bgimage.length){
35333 cls += ' masonry-center-title';
35336 if(!this.html.length && this.bgimage.length){
35337 cls += ' masonry-bottom-title';
35342 cls += ' ' + this.cls;
35346 tag: (this.href.length) ? 'a' : 'div',
35351 cls: 'masonry-brick-mask'
35355 cls: 'masonry-brick-paragraph',
35361 if(this.href.length){
35362 cfg.href = this.href;
35365 var cn = cfg.cn[1].cn;
35367 if(this.title.length){
35370 cls: 'masonry-brick-title',
35375 if(this.html.length){
35378 cls: 'masonry-brick-text',
35383 if (!this.title.length && !this.html.length) {
35384 cfg.cn[1].cls += ' hide';
35387 if(this.bgimage.length){
35390 cls: 'masonry-brick-image-view',
35395 if(this.videourl.length){
35396 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
35397 // youtube support only?
35400 cls: 'masonry-brick-image-view',
35403 allowfullscreen : true
35411 getSplitAutoCreate : function()
35413 var cls = 'masonry-brick masonry-brick-split';
35415 if(this.href.length){
35416 cls += ' masonry-brick-link';
35419 if(this.bgimage.length){
35420 cls += ' masonry-brick-image';
35424 cls += ' masonry-' + this.size + '-brick';
35427 switch (this.placetitle) {
35429 cls += ' masonry-center-title';
35432 cls += ' masonry-bottom-title';
35435 if(!this.bgimage.length){
35436 cls += ' masonry-center-title';
35439 if(this.bgimage.length){
35440 cls += ' masonry-bottom-title';
35446 cls += ' ' + this.cls;
35450 tag: (this.href.length) ? 'a' : 'div',
35455 cls: 'masonry-brick-split-head',
35459 cls: 'masonry-brick-paragraph',
35466 cls: 'masonry-brick-split-body',
35472 if(this.href.length){
35473 cfg.href = this.href;
35476 if(this.title.length){
35477 cfg.cn[0].cn[0].cn.push({
35479 cls: 'masonry-brick-title',
35484 if(this.html.length){
35485 cfg.cn[1].cn.push({
35487 cls: 'masonry-brick-text',
35492 if(this.bgimage.length){
35493 cfg.cn[0].cn.push({
35495 cls: 'masonry-brick-image-view',
35500 if(this.videourl.length){
35501 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
35502 // youtube support only?
35503 cfg.cn[0].cn.cn.push({
35505 cls: 'masonry-brick-image-view',
35508 allowfullscreen : true
35515 initEvents: function()
35517 switch (this.size) {
35550 this.el.on('touchstart', this.onTouchStart, this);
35551 this.el.on('touchmove', this.onTouchMove, this);
35552 this.el.on('touchend', this.onTouchEnd, this);
35553 this.el.on('contextmenu', this.onContextMenu, this);
35555 this.el.on('mouseenter' ,this.enter, this);
35556 this.el.on('mouseleave', this.leave, this);
35557 this.el.on('click', this.onClick, this);
35560 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
35561 this.parent().bricks.push(this);
35566 onClick: function(e, el)
35568 var time = this.endTimer - this.startTimer;
35569 // Roo.log(e.preventDefault());
35572 e.preventDefault();
35577 if(!this.preventDefault){
35581 e.preventDefault();
35583 if (this.activeClass != '') {
35584 this.selectBrick();
35587 this.fireEvent('click', this, e);
35590 enter: function(e, el)
35592 e.preventDefault();
35594 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
35598 if(this.bgimage.length && this.html.length){
35599 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
35603 leave: function(e, el)
35605 e.preventDefault();
35607 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
35611 if(this.bgimage.length && this.html.length){
35612 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
35616 onTouchStart: function(e, el)
35618 // e.preventDefault();
35620 this.touchmoved = false;
35622 if(!this.isFitContainer){
35626 if(!this.bgimage.length || !this.html.length){
35630 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
35632 this.timer = new Date().getTime();
35636 onTouchMove: function(e, el)
35638 this.touchmoved = true;
35641 onContextMenu : function(e,el)
35643 e.preventDefault();
35644 e.stopPropagation();
35648 onTouchEnd: function(e, el)
35650 // e.preventDefault();
35652 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
35659 if(!this.bgimage.length || !this.html.length){
35661 if(this.href.length){
35662 window.location.href = this.href;
35668 if(!this.isFitContainer){
35672 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
35674 window.location.href = this.href;
35677 //selection on single brick only
35678 selectBrick : function() {
35680 if (!this.parentId) {
35684 var m = Roo.bootstrap.LayoutMasonry.get(this.parentId);
35685 var index = m.selectedBrick.indexOf(this.id);
35688 m.selectedBrick.splice(index,1);
35689 this.el.removeClass(this.activeClass);
35693 for(var i = 0; i < m.selectedBrick.length; i++) {
35694 var b = Roo.bootstrap.MasonryBrick.get(m.selectedBrick[i]);
35695 b.el.removeClass(b.activeClass);
35698 m.selectedBrick = [];
35700 m.selectedBrick.push(this.id);
35701 this.el.addClass(this.activeClass);
35705 isSelected : function(){
35706 return this.el.hasClass(this.activeClass);
35711 Roo.apply(Roo.bootstrap.MasonryBrick, {
35714 groups : new Roo.util.MixedCollection(false, function(o) { return o.el.id; }),
35716 * register a Masonry Brick
35717 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
35720 register : function(brick)
35722 //this.groups[brick.id] = brick;
35723 this.groups.add(brick.id, brick);
35726 * fetch a masonry brick based on the masonry brick ID
35727 * @param {string} the masonry brick to add
35728 * @returns {Roo.bootstrap.MasonryBrick} the masonry brick
35731 get: function(brick_id)
35733 // if (typeof(this.groups[brick_id]) == 'undefined') {
35736 // return this.groups[brick_id] ;
35738 if(this.groups.key(brick_id)) {
35739 return this.groups.key(brick_id);
35757 * @class Roo.bootstrap.Brick
35758 * @extends Roo.bootstrap.Component
35759 * Bootstrap Brick class
35762 * Create a new Brick
35763 * @param {Object} config The config object
35766 Roo.bootstrap.Brick = function(config){
35767 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
35773 * When a Brick is click
35774 * @param {Roo.bootstrap.Brick} this
35775 * @param {Roo.EventObject} e
35781 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
35784 * @cfg {String} title
35788 * @cfg {String} html
35792 * @cfg {String} bgimage
35796 * @cfg {String} cls
35800 * @cfg {String} href
35804 * @cfg {String} video
35808 * @cfg {Boolean} square
35812 getAutoCreate : function()
35814 var cls = 'roo-brick';
35816 if(this.href.length){
35817 cls += ' roo-brick-link';
35820 if(this.bgimage.length){
35821 cls += ' roo-brick-image';
35824 if(!this.html.length && !this.bgimage.length){
35825 cls += ' roo-brick-center-title';
35828 if(!this.html.length && this.bgimage.length){
35829 cls += ' roo-brick-bottom-title';
35833 cls += ' ' + this.cls;
35837 tag: (this.href.length) ? 'a' : 'div',
35842 cls: 'roo-brick-paragraph',
35848 if(this.href.length){
35849 cfg.href = this.href;
35852 var cn = cfg.cn[0].cn;
35854 if(this.title.length){
35857 cls: 'roo-brick-title',
35862 if(this.html.length){
35865 cls: 'roo-brick-text',
35872 if(this.bgimage.length){
35875 cls: 'roo-brick-image-view',
35883 initEvents: function()
35885 if(this.title.length || this.html.length){
35886 this.el.on('mouseenter' ,this.enter, this);
35887 this.el.on('mouseleave', this.leave, this);
35890 Roo.EventManager.onWindowResize(this.resize, this);
35892 if(this.bgimage.length){
35893 this.imageEl = this.el.select('.roo-brick-image-view', true).first();
35894 this.imageEl.on('load', this.onImageLoad, this);
35901 onImageLoad : function()
35906 resize : function()
35908 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
35910 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
35912 if(this.bgimage.length){
35913 var image = this.el.select('.roo-brick-image-view', true).first();
35915 image.setWidth(paragraph.getWidth());
35918 image.setHeight(paragraph.getWidth());
35921 this.el.setHeight(image.getHeight());
35922 paragraph.setHeight(image.getHeight());
35928 enter: function(e, el)
35930 e.preventDefault();
35932 if(this.bgimage.length){
35933 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
35934 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
35938 leave: function(e, el)
35940 e.preventDefault();
35942 if(this.bgimage.length){
35943 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
35944 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
35959 * @class Roo.bootstrap.NumberField
35960 * @extends Roo.bootstrap.Input
35961 * Bootstrap NumberField class
35967 * Create a new NumberField
35968 * @param {Object} config The config object
35971 Roo.bootstrap.NumberField = function(config){
35972 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
35975 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
35978 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
35980 allowDecimals : true,
35982 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
35984 decimalSeparator : ".",
35986 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
35988 decimalPrecision : 2,
35990 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
35992 allowNegative : true,
35995 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
35999 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
36001 minValue : Number.NEGATIVE_INFINITY,
36003 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
36005 maxValue : Number.MAX_VALUE,
36007 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
36009 minText : "The minimum value for this field is {0}",
36011 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
36013 maxText : "The maximum value for this field is {0}",
36015 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
36016 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
36018 nanText : "{0} is not a valid number",
36020 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
36022 thousandsDelimiter : false,
36024 * @cfg {String} valueAlign alignment of value
36026 valueAlign : "left",
36028 getAutoCreate : function()
36030 var hiddenInput = {
36034 cls: 'hidden-number-input'
36038 hiddenInput.name = this.name;
36043 var cfg = Roo.bootstrap.NumberField.superclass.getAutoCreate.call(this);
36045 this.name = hiddenInput.name;
36047 if(cfg.cn.length > 0) {
36048 cfg.cn.push(hiddenInput);
36055 initEvents : function()
36057 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
36059 var allowed = "0123456789";
36061 if(this.allowDecimals){
36062 allowed += this.decimalSeparator;
36065 if(this.allowNegative){
36069 if(this.thousandsDelimiter) {
36073 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
36075 var keyPress = function(e){
36077 var k = e.getKey();
36079 var c = e.getCharCode();
36082 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
36083 allowed.indexOf(String.fromCharCode(c)) === -1
36089 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
36093 if(allowed.indexOf(String.fromCharCode(c)) === -1){
36098 this.el.on("keypress", keyPress, this);
36101 validateValue : function(value)
36104 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
36108 var num = this.parseValue(value);
36111 this.markInvalid(String.format(this.nanText, value));
36115 if(num < this.minValue){
36116 this.markInvalid(String.format(this.minText, this.minValue));
36120 if(num > this.maxValue){
36121 this.markInvalid(String.format(this.maxText, this.maxValue));
36128 getValue : function()
36130 var v = this.hiddenEl().getValue();
36132 return this.fixPrecision(this.parseValue(v));
36135 parseValue : function(value)
36137 if(this.thousandsDelimiter) {
36139 r = new RegExp(",", "g");
36140 value = value.replace(r, "");
36143 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
36144 return isNaN(value) ? '' : value;
36147 fixPrecision : function(value)
36149 if(this.thousandsDelimiter) {
36151 r = new RegExp(",", "g");
36152 value = value.replace(r, "");
36155 var nan = isNaN(value);
36157 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
36158 return nan ? '' : value;
36160 return parseFloat(value).toFixed(this.decimalPrecision);
36163 setValue : function(v)
36165 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
36171 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
36173 this.inputEl().dom.value = (v == '') ? '' :
36174 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
36176 if(!this.allowZero && v === '0') {
36177 this.hiddenEl().dom.value = '';
36178 this.inputEl().dom.value = '';
36185 decimalPrecisionFcn : function(v)
36187 return Math.floor(v);
36190 beforeBlur : function()
36192 var v = this.parseValue(this.getRawValue());
36194 if(v || v === 0 || v === ''){
36199 hiddenEl : function()
36201 return this.el.select('input.hidden-number-input',true).first();
36213 * @class Roo.bootstrap.DocumentSlider
36214 * @extends Roo.bootstrap.Component
36215 * Bootstrap DocumentSlider class
36218 * Create a new DocumentViewer
36219 * @param {Object} config The config object
36222 Roo.bootstrap.DocumentSlider = function(config){
36223 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
36230 * Fire after initEvent
36231 * @param {Roo.bootstrap.DocumentSlider} this
36236 * Fire after update
36237 * @param {Roo.bootstrap.DocumentSlider} this
36243 * @param {Roo.bootstrap.DocumentSlider} this
36249 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
36255 getAutoCreate : function()
36259 cls : 'roo-document-slider',
36263 cls : 'roo-document-slider-header',
36267 cls : 'roo-document-slider-header-title'
36273 cls : 'roo-document-slider-body',
36277 cls : 'roo-document-slider-prev',
36281 cls : 'fa fa-chevron-left'
36287 cls : 'roo-document-slider-thumb',
36291 cls : 'roo-document-slider-image'
36297 cls : 'roo-document-slider-next',
36301 cls : 'fa fa-chevron-right'
36313 initEvents : function()
36315 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
36316 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
36318 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
36319 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
36321 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
36322 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
36324 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
36325 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
36327 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
36328 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
36330 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
36331 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
36333 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
36334 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
36336 this.thumbEl.on('click', this.onClick, this);
36338 this.prevIndicator.on('click', this.prev, this);
36340 this.nextIndicator.on('click', this.next, this);
36344 initial : function()
36346 if(this.files.length){
36347 this.indicator = 1;
36351 this.fireEvent('initial', this);
36354 update : function()
36356 this.imageEl.attr('src', this.files[this.indicator - 1]);
36358 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
36360 this.prevIndicator.show();
36362 if(this.indicator == 1){
36363 this.prevIndicator.hide();
36366 this.nextIndicator.show();
36368 if(this.indicator == this.files.length){
36369 this.nextIndicator.hide();
36372 this.thumbEl.scrollTo('top');
36374 this.fireEvent('update', this);
36377 onClick : function(e)
36379 e.preventDefault();
36381 this.fireEvent('click', this);
36386 e.preventDefault();
36388 this.indicator = Math.max(1, this.indicator - 1);
36395 e.preventDefault();
36397 this.indicator = Math.min(this.files.length, this.indicator + 1);
36411 * @class Roo.bootstrap.RadioSet
36412 * @extends Roo.bootstrap.Input
36413 * Bootstrap RadioSet class
36414 * @cfg {String} indicatorpos (left|right) default left
36415 * @cfg {Boolean} inline (true|false) inline the element (default true)
36416 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
36418 * Create a new RadioSet
36419 * @param {Object} config The config object
36422 Roo.bootstrap.RadioSet = function(config){
36424 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
36428 Roo.bootstrap.RadioSet.register(this);
36433 * Fires when the element is checked or unchecked.
36434 * @param {Roo.bootstrap.RadioSet} this This radio
36435 * @param {Roo.bootstrap.Radio} item The checked item
36440 * Fires when the element is click.
36441 * @param {Roo.bootstrap.RadioSet} this This radio set
36442 * @param {Roo.bootstrap.Radio} item The checked item
36443 * @param {Roo.EventObject} e The event object
36450 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
36458 indicatorpos : 'left',
36460 getAutoCreate : function()
36464 cls : 'roo-radio-set-label',
36468 html : this.fieldLabel
36472 if (Roo.bootstrap.version == 3) {
36475 if(this.indicatorpos == 'left'){
36478 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
36479 tooltip : 'This field is required'
36484 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
36485 tooltip : 'This field is required'
36491 cls : 'roo-radio-set-items'
36494 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
36496 if (align === 'left' && this.fieldLabel.length) {
36499 cls : "roo-radio-set-right",
36505 if(this.labelWidth > 12){
36506 label.style = "width: " + this.labelWidth + 'px';
36509 if(this.labelWidth < 13 && this.labelmd == 0){
36510 this.labelmd = this.labelWidth;
36513 if(this.labellg > 0){
36514 label.cls += ' col-lg-' + this.labellg;
36515 items.cls += ' col-lg-' + (12 - this.labellg);
36518 if(this.labelmd > 0){
36519 label.cls += ' col-md-' + this.labelmd;
36520 items.cls += ' col-md-' + (12 - this.labelmd);
36523 if(this.labelsm > 0){
36524 label.cls += ' col-sm-' + this.labelsm;
36525 items.cls += ' col-sm-' + (12 - this.labelsm);
36528 if(this.labelxs > 0){
36529 label.cls += ' col-xs-' + this.labelxs;
36530 items.cls += ' col-xs-' + (12 - this.labelxs);
36536 cls : 'roo-radio-set',
36540 cls : 'roo-radio-set-input',
36543 value : this.value ? this.value : ''
36550 if(this.weight.length){
36551 cfg.cls += ' roo-radio-' + this.weight;
36555 cfg.cls += ' roo-radio-set-inline';
36559 ['xs','sm','md','lg'].map(function(size){
36560 if (settings[size]) {
36561 cfg.cls += ' col-' + size + '-' + settings[size];
36569 initEvents : function()
36571 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
36572 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
36574 if(!this.fieldLabel.length){
36575 this.labelEl.hide();
36578 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
36579 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
36581 this.indicator = this.indicatorEl();
36583 if(this.indicator){
36584 this.indicator.addClass('invisible');
36587 this.originalValue = this.getValue();
36591 inputEl: function ()
36593 return this.el.select('.roo-radio-set-input', true).first();
36596 getChildContainer : function()
36598 return this.itemsEl;
36601 register : function(item)
36603 this.radioes.push(item);
36607 validate : function()
36609 if(this.getVisibilityEl().hasClass('hidden')){
36615 Roo.each(this.radioes, function(i){
36624 if(this.allowBlank) {
36628 if(this.disabled || valid){
36633 this.markInvalid();
36638 markValid : function()
36640 if(this.labelEl.isVisible(true) && this.indicatorEl()){
36641 this.indicatorEl().removeClass('visible');
36642 this.indicatorEl().addClass('invisible');
36646 if (Roo.bootstrap.version == 3) {
36647 this.el.removeClass([this.invalidClass, this.validClass]);
36648 this.el.addClass(this.validClass);
36650 this.el.removeClass(['is-invalid','is-valid']);
36651 this.el.addClass(['is-valid']);
36653 this.fireEvent('valid', this);
36656 markInvalid : function(msg)
36658 if(this.allowBlank || this.disabled){
36662 if(this.labelEl.isVisible(true) && this.indicatorEl()){
36663 this.indicatorEl().removeClass('invisible');
36664 this.indicatorEl().addClass('visible');
36666 if (Roo.bootstrap.version == 3) {
36667 this.el.removeClass([this.invalidClass, this.validClass]);
36668 this.el.addClass(this.invalidClass);
36670 this.el.removeClass(['is-invalid','is-valid']);
36671 this.el.addClass(['is-invalid']);
36674 this.fireEvent('invalid', this, msg);
36678 setValue : function(v, suppressEvent)
36680 if(this.value === v){
36687 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
36690 Roo.each(this.radioes, function(i){
36692 i.el.removeClass('checked');
36695 Roo.each(this.radioes, function(i){
36697 if(i.value === v || i.value.toString() === v.toString()){
36699 i.el.addClass('checked');
36701 if(suppressEvent !== true){
36702 this.fireEvent('check', this, i);
36713 clearInvalid : function(){
36715 if(!this.el || this.preventMark){
36719 this.el.removeClass([this.invalidClass]);
36721 this.fireEvent('valid', this);
36726 Roo.apply(Roo.bootstrap.RadioSet, {
36730 register : function(set)
36732 this.groups[set.name] = set;
36735 get: function(name)
36737 if (typeof(this.groups[name]) == 'undefined') {
36741 return this.groups[name] ;
36747 * Ext JS Library 1.1.1
36748 * Copyright(c) 2006-2007, Ext JS, LLC.
36750 * Originally Released Under LGPL - original licence link has changed is not relivant.
36753 * <script type="text/javascript">
36758 * @class Roo.bootstrap.SplitBar
36759 * @extends Roo.util.Observable
36760 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
36764 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
36765 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
36766 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
36767 split.minSize = 100;
36768 split.maxSize = 600;
36769 split.animate = true;
36770 split.on('moved', splitterMoved);
36773 * Create a new SplitBar
36774 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
36775 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
36776 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
36777 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
36778 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
36779 position of the SplitBar).
36781 Roo.bootstrap.SplitBar = function(cfg){
36786 // dragElement : elm
36787 // resizingElement: el,
36789 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
36790 // placement : Roo.bootstrap.SplitBar.LEFT ,
36791 // existingProxy ???
36794 this.el = Roo.get(cfg.dragElement, true);
36795 this.el.dom.unselectable = "on";
36797 this.resizingEl = Roo.get(cfg.resizingElement, true);
36801 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
36802 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
36805 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
36808 * The minimum size of the resizing element. (Defaults to 0)
36814 * The maximum size of the resizing element. (Defaults to 2000)
36817 this.maxSize = 2000;
36820 * Whether to animate the transition to the new size
36823 this.animate = false;
36826 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
36829 this.useShim = false;
36834 if(!cfg.existingProxy){
36836 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
36838 this.proxy = Roo.get(cfg.existingProxy).dom;
36841 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
36844 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
36847 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
36850 this.dragSpecs = {};
36853 * @private The adapter to use to positon and resize elements
36855 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
36856 this.adapter.init(this);
36858 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
36860 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
36861 this.el.addClass("roo-splitbar-h");
36864 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
36865 this.el.addClass("roo-splitbar-v");
36871 * Fires when the splitter is moved (alias for {@link #event-moved})
36872 * @param {Roo.bootstrap.SplitBar} this
36873 * @param {Number} newSize the new width or height
36878 * Fires when the splitter is moved
36879 * @param {Roo.bootstrap.SplitBar} this
36880 * @param {Number} newSize the new width or height
36884 * @event beforeresize
36885 * Fires before the splitter is dragged
36886 * @param {Roo.bootstrap.SplitBar} this
36888 "beforeresize" : true,
36890 "beforeapply" : true
36893 Roo.util.Observable.call(this);
36896 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
36897 onStartProxyDrag : function(x, y){
36898 this.fireEvent("beforeresize", this);
36900 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
36902 o.enableDisplayMode("block");
36903 // all splitbars share the same overlay
36904 Roo.bootstrap.SplitBar.prototype.overlay = o;
36906 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
36907 this.overlay.show();
36908 Roo.get(this.proxy).setDisplayed("block");
36909 var size = this.adapter.getElementSize(this);
36910 this.activeMinSize = this.getMinimumSize();;
36911 this.activeMaxSize = this.getMaximumSize();;
36912 var c1 = size - this.activeMinSize;
36913 var c2 = Math.max(this.activeMaxSize - size, 0);
36914 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
36915 this.dd.resetConstraints();
36916 this.dd.setXConstraint(
36917 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
36918 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
36920 this.dd.setYConstraint(0, 0);
36922 this.dd.resetConstraints();
36923 this.dd.setXConstraint(0, 0);
36924 this.dd.setYConstraint(
36925 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
36926 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
36929 this.dragSpecs.startSize = size;
36930 this.dragSpecs.startPoint = [x, y];
36931 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
36935 * @private Called after the drag operation by the DDProxy
36937 onEndProxyDrag : function(e){
36938 Roo.get(this.proxy).setDisplayed(false);
36939 var endPoint = Roo.lib.Event.getXY(e);
36941 this.overlay.hide();
36944 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
36945 newSize = this.dragSpecs.startSize +
36946 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
36947 endPoint[0] - this.dragSpecs.startPoint[0] :
36948 this.dragSpecs.startPoint[0] - endPoint[0]
36951 newSize = this.dragSpecs.startSize +
36952 (this.placement == Roo.bootstrap.SplitBar.TOP ?
36953 endPoint[1] - this.dragSpecs.startPoint[1] :
36954 this.dragSpecs.startPoint[1] - endPoint[1]
36957 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
36958 if(newSize != this.dragSpecs.startSize){
36959 if(this.fireEvent('beforeapply', this, newSize) !== false){
36960 this.adapter.setElementSize(this, newSize);
36961 this.fireEvent("moved", this, newSize);
36962 this.fireEvent("resize", this, newSize);
36968 * Get the adapter this SplitBar uses
36969 * @return The adapter object
36971 getAdapter : function(){
36972 return this.adapter;
36976 * Set the adapter this SplitBar uses
36977 * @param {Object} adapter A SplitBar adapter object
36979 setAdapter : function(adapter){
36980 this.adapter = adapter;
36981 this.adapter.init(this);
36985 * Gets the minimum size for the resizing element
36986 * @return {Number} The minimum size
36988 getMinimumSize : function(){
36989 return this.minSize;
36993 * Sets the minimum size for the resizing element
36994 * @param {Number} minSize The minimum size
36996 setMinimumSize : function(minSize){
36997 this.minSize = minSize;
37001 * Gets the maximum size for the resizing element
37002 * @return {Number} The maximum size
37004 getMaximumSize : function(){
37005 return this.maxSize;
37009 * Sets the maximum size for the resizing element
37010 * @param {Number} maxSize The maximum size
37012 setMaximumSize : function(maxSize){
37013 this.maxSize = maxSize;
37017 * Sets the initialize size for the resizing element
37018 * @param {Number} size The initial size
37020 setCurrentSize : function(size){
37021 var oldAnimate = this.animate;
37022 this.animate = false;
37023 this.adapter.setElementSize(this, size);
37024 this.animate = oldAnimate;
37028 * Destroy this splitbar.
37029 * @param {Boolean} removeEl True to remove the element
37031 destroy : function(removeEl){
37033 this.shim.remove();
37036 this.proxy.parentNode.removeChild(this.proxy);
37044 * @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.
37046 Roo.bootstrap.SplitBar.createProxy = function(dir){
37047 var proxy = new Roo.Element(document.createElement("div"));
37048 proxy.unselectable();
37049 var cls = 'roo-splitbar-proxy';
37050 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
37051 document.body.appendChild(proxy.dom);
37056 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
37057 * Default Adapter. It assumes the splitter and resizing element are not positioned
37058 * elements and only gets/sets the width of the element. Generally used for table based layouts.
37060 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
37063 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
37064 // do nothing for now
37065 init : function(s){
37069 * Called before drag operations to get the current size of the resizing element.
37070 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
37072 getElementSize : function(s){
37073 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
37074 return s.resizingEl.getWidth();
37076 return s.resizingEl.getHeight();
37081 * Called after drag operations to set the size of the resizing element.
37082 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
37083 * @param {Number} newSize The new size to set
37084 * @param {Function} onComplete A function to be invoked when resizing is complete
37086 setElementSize : function(s, newSize, onComplete){
37087 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
37089 s.resizingEl.setWidth(newSize);
37091 onComplete(s, newSize);
37094 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
37099 s.resizingEl.setHeight(newSize);
37101 onComplete(s, newSize);
37104 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
37111 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
37112 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
37113 * Adapter that moves the splitter element to align with the resized sizing element.
37114 * Used with an absolute positioned SplitBar.
37115 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
37116 * document.body, make sure you assign an id to the body element.
37118 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
37119 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
37120 this.container = Roo.get(container);
37123 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
37124 init : function(s){
37125 this.basic.init(s);
37128 getElementSize : function(s){
37129 return this.basic.getElementSize(s);
37132 setElementSize : function(s, newSize, onComplete){
37133 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
37136 moveSplitter : function(s){
37137 var yes = Roo.bootstrap.SplitBar;
37138 switch(s.placement){
37140 s.el.setX(s.resizingEl.getRight());
37143 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
37146 s.el.setY(s.resizingEl.getBottom());
37149 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
37156 * Orientation constant - Create a vertical SplitBar
37160 Roo.bootstrap.SplitBar.VERTICAL = 1;
37163 * Orientation constant - Create a horizontal SplitBar
37167 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
37170 * Placement constant - The resizing element is to the left of the splitter element
37174 Roo.bootstrap.SplitBar.LEFT = 1;
37177 * Placement constant - The resizing element is to the right of the splitter element
37181 Roo.bootstrap.SplitBar.RIGHT = 2;
37184 * Placement constant - The resizing element is positioned above the splitter element
37188 Roo.bootstrap.SplitBar.TOP = 3;
37191 * Placement constant - The resizing element is positioned under splitter element
37195 Roo.bootstrap.SplitBar.BOTTOM = 4;
37196 Roo.namespace("Roo.bootstrap.layout");/*
37198 * Ext JS Library 1.1.1
37199 * Copyright(c) 2006-2007, Ext JS, LLC.
37201 * Originally Released Under LGPL - original licence link has changed is not relivant.
37204 * <script type="text/javascript">
37208 * @class Roo.bootstrap.layout.Manager
37209 * @extends Roo.bootstrap.Component
37210 * Base class for layout managers.
37212 Roo.bootstrap.layout.Manager = function(config)
37214 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
37220 /** false to disable window resize monitoring @type Boolean */
37221 this.monitorWindowResize = true;
37226 * Fires when a layout is performed.
37227 * @param {Roo.LayoutManager} this
37231 * @event regionresized
37232 * Fires when the user resizes a region.
37233 * @param {Roo.LayoutRegion} region The resized region
37234 * @param {Number} newSize The new size (width for east/west, height for north/south)
37236 "regionresized" : true,
37238 * @event regioncollapsed
37239 * Fires when a region is collapsed.
37240 * @param {Roo.LayoutRegion} region The collapsed region
37242 "regioncollapsed" : true,
37244 * @event regionexpanded
37245 * Fires when a region is expanded.
37246 * @param {Roo.LayoutRegion} region The expanded region
37248 "regionexpanded" : true
37250 this.updating = false;
37253 this.el = Roo.get(config.el);
37259 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
37264 monitorWindowResize : true,
37270 onRender : function(ct, position)
37273 this.el = Roo.get(ct);
37276 //this.fireEvent('render',this);
37280 initEvents: function()
37284 // ie scrollbar fix
37285 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
37286 document.body.scroll = "no";
37287 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
37288 this.el.position('relative');
37290 this.id = this.el.id;
37291 this.el.addClass("roo-layout-container");
37292 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
37293 if(this.el.dom != document.body ) {
37294 this.el.on('resize', this.layout,this);
37295 this.el.on('show', this.layout,this);
37301 * Returns true if this layout is currently being updated
37302 * @return {Boolean}
37304 isUpdating : function(){
37305 return this.updating;
37309 * Suspend the LayoutManager from doing auto-layouts while
37310 * making multiple add or remove calls
37312 beginUpdate : function(){
37313 this.updating = true;
37317 * Restore auto-layouts and optionally disable the manager from performing a layout
37318 * @param {Boolean} noLayout true to disable a layout update
37320 endUpdate : function(noLayout){
37321 this.updating = false;
37327 layout: function(){
37331 onRegionResized : function(region, newSize){
37332 this.fireEvent("regionresized", region, newSize);
37336 onRegionCollapsed : function(region){
37337 this.fireEvent("regioncollapsed", region);
37340 onRegionExpanded : function(region){
37341 this.fireEvent("regionexpanded", region);
37345 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
37346 * performs box-model adjustments.
37347 * @return {Object} The size as an object {width: (the width), height: (the height)}
37349 getViewSize : function()
37352 if(this.el.dom != document.body){
37353 size = this.el.getSize();
37355 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
37357 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
37358 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
37363 * Returns the Element this layout is bound to.
37364 * @return {Roo.Element}
37366 getEl : function(){
37371 * Returns the specified region.
37372 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
37373 * @return {Roo.LayoutRegion}
37375 getRegion : function(target){
37376 return this.regions[target.toLowerCase()];
37379 onWindowResize : function(){
37380 if(this.monitorWindowResize){
37387 * Ext JS Library 1.1.1
37388 * Copyright(c) 2006-2007, Ext JS, LLC.
37390 * Originally Released Under LGPL - original licence link has changed is not relivant.
37393 * <script type="text/javascript">
37396 * @class Roo.bootstrap.layout.Border
37397 * @extends Roo.bootstrap.layout.Manager
37398 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
37399 * please see: examples/bootstrap/nested.html<br><br>
37401 <b>The container the layout is rendered into can be either the body element or any other element.
37402 If it is not the body element, the container needs to either be an absolute positioned element,
37403 or you will need to add "position:relative" to the css of the container. You will also need to specify
37404 the container size if it is not the body element.</b>
37407 * Create a new Border
37408 * @param {Object} config Configuration options
37410 Roo.bootstrap.layout.Border = function(config){
37411 config = config || {};
37412 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
37416 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
37417 if(config[region]){
37418 config[region].region = region;
37419 this.addRegion(config[region]);
37425 Roo.bootstrap.layout.Border.regions = ["center", "north","south","east","west"];
37427 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
37429 parent : false, // this might point to a 'nest' or a ???
37432 * Creates and adds a new region if it doesn't already exist.
37433 * @param {String} target The target region key (north, south, east, west or center).
37434 * @param {Object} config The regions config object
37435 * @return {BorderLayoutRegion} The new region
37437 addRegion : function(config)
37439 if(!this.regions[config.region]){
37440 var r = this.factory(config);
37441 this.bindRegion(r);
37443 return this.regions[config.region];
37447 bindRegion : function(r){
37448 this.regions[r.config.region] = r;
37450 r.on("visibilitychange", this.layout, this);
37451 r.on("paneladded", this.layout, this);
37452 r.on("panelremoved", this.layout, this);
37453 r.on("invalidated", this.layout, this);
37454 r.on("resized", this.onRegionResized, this);
37455 r.on("collapsed", this.onRegionCollapsed, this);
37456 r.on("expanded", this.onRegionExpanded, this);
37460 * Performs a layout update.
37462 layout : function()
37464 if(this.updating) {
37468 // render all the rebions if they have not been done alreayd?
37469 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
37470 if(this.regions[region] && !this.regions[region].bodyEl){
37471 this.regions[region].onRender(this.el)
37475 var size = this.getViewSize();
37476 var w = size.width;
37477 var h = size.height;
37482 //var x = 0, y = 0;
37484 var rs = this.regions;
37485 var north = rs["north"];
37486 var south = rs["south"];
37487 var west = rs["west"];
37488 var east = rs["east"];
37489 var center = rs["center"];
37490 //if(this.hideOnLayout){ // not supported anymore
37491 //c.el.setStyle("display", "none");
37493 if(north && north.isVisible()){
37494 var b = north.getBox();
37495 var m = north.getMargins();
37496 b.width = w - (m.left+m.right);
37499 centerY = b.height + b.y + m.bottom;
37500 centerH -= centerY;
37501 north.updateBox(this.safeBox(b));
37503 if(south && south.isVisible()){
37504 var b = south.getBox();
37505 var m = south.getMargins();
37506 b.width = w - (m.left+m.right);
37508 var totalHeight = (b.height + m.top + m.bottom);
37509 b.y = h - totalHeight + m.top;
37510 centerH -= totalHeight;
37511 south.updateBox(this.safeBox(b));
37513 if(west && west.isVisible()){
37514 var b = west.getBox();
37515 var m = west.getMargins();
37516 b.height = centerH - (m.top+m.bottom);
37518 b.y = centerY + m.top;
37519 var totalWidth = (b.width + m.left + m.right);
37520 centerX += totalWidth;
37521 centerW -= totalWidth;
37522 west.updateBox(this.safeBox(b));
37524 if(east && east.isVisible()){
37525 var b = east.getBox();
37526 var m = east.getMargins();
37527 b.height = centerH - (m.top+m.bottom);
37528 var totalWidth = (b.width + m.left + m.right);
37529 b.x = w - totalWidth + m.left;
37530 b.y = centerY + m.top;
37531 centerW -= totalWidth;
37532 east.updateBox(this.safeBox(b));
37535 var m = center.getMargins();
37537 x: centerX + m.left,
37538 y: centerY + m.top,
37539 width: centerW - (m.left+m.right),
37540 height: centerH - (m.top+m.bottom)
37542 //if(this.hideOnLayout){
37543 //center.el.setStyle("display", "block");
37545 center.updateBox(this.safeBox(centerBox));
37548 this.fireEvent("layout", this);
37552 safeBox : function(box){
37553 box.width = Math.max(0, box.width);
37554 box.height = Math.max(0, box.height);
37559 * Adds a ContentPanel (or subclass) to this layout.
37560 * @param {String} target The target region key (north, south, east, west or center).
37561 * @param {Roo.ContentPanel} panel The panel to add
37562 * @return {Roo.ContentPanel} The added panel
37564 add : function(target, panel){
37566 target = target.toLowerCase();
37567 return this.regions[target].add(panel);
37571 * Remove a ContentPanel (or subclass) to this layout.
37572 * @param {String} target The target region key (north, south, east, west or center).
37573 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
37574 * @return {Roo.ContentPanel} The removed panel
37576 remove : function(target, panel){
37577 target = target.toLowerCase();
37578 return this.regions[target].remove(panel);
37582 * Searches all regions for a panel with the specified id
37583 * @param {String} panelId
37584 * @return {Roo.ContentPanel} The panel or null if it wasn't found
37586 findPanel : function(panelId){
37587 var rs = this.regions;
37588 for(var target in rs){
37589 if(typeof rs[target] != "function"){
37590 var p = rs[target].getPanel(panelId);
37600 * Searches all regions for a panel with the specified id and activates (shows) it.
37601 * @param {String/ContentPanel} panelId The panels id or the panel itself
37602 * @return {Roo.ContentPanel} The shown panel or null
37604 showPanel : function(panelId) {
37605 var rs = this.regions;
37606 for(var target in rs){
37607 var r = rs[target];
37608 if(typeof r != "function"){
37609 if(r.hasPanel(panelId)){
37610 return r.showPanel(panelId);
37618 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
37619 * @param {Roo.state.Provider} provider (optional) An alternate state provider
37622 restoreState : function(provider){
37624 provider = Roo.state.Manager;
37626 var sm = new Roo.LayoutStateManager();
37627 sm.init(this, provider);
37633 * Adds a xtype elements to the layout.
37637 xtype : 'ContentPanel',
37644 xtype : 'NestedLayoutPanel',
37650 items : [ ... list of content panels or nested layout panels.. ]
37654 * @param {Object} cfg Xtype definition of item to add.
37656 addxtype : function(cfg)
37658 // basically accepts a pannel...
37659 // can accept a layout region..!?!?
37660 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
37663 // theory? children can only be panels??
37665 //if (!cfg.xtype.match(/Panel$/)) {
37670 if (typeof(cfg.region) == 'undefined') {
37671 Roo.log("Failed to add Panel, region was not set");
37675 var region = cfg.region;
37681 xitems = cfg.items;
37686 if ( region == 'center') {
37687 Roo.log("Center: " + cfg.title);
37693 case 'Content': // ContentPanel (el, cfg)
37694 case 'Scroll': // ContentPanel (el, cfg)
37696 cfg.autoCreate = cfg.autoCreate || true;
37697 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
37699 // var el = this.el.createChild();
37700 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
37703 this.add(region, ret);
37707 case 'TreePanel': // our new panel!
37708 cfg.el = this.el.createChild();
37709 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
37710 this.add(region, ret);
37715 // create a new Layout (which is a Border Layout...
37717 var clayout = cfg.layout;
37718 clayout.el = this.el.createChild();
37719 clayout.items = clayout.items || [];
37723 // replace this exitems with the clayout ones..
37724 xitems = clayout.items;
37726 // force background off if it's in center...
37727 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
37728 cfg.background = false;
37730 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
37733 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
37734 //console.log('adding nested layout panel ' + cfg.toSource());
37735 this.add(region, ret);
37736 nb = {}; /// find first...
37741 // needs grid and region
37743 //var el = this.getRegion(region).el.createChild();
37745 *var el = this.el.createChild();
37746 // create the grid first...
37747 cfg.grid.container = el;
37748 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
37751 if (region == 'center' && this.active ) {
37752 cfg.background = false;
37755 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
37757 this.add(region, ret);
37759 if (cfg.background) {
37760 // render grid on panel activation (if panel background)
37761 ret.on('activate', function(gp) {
37762 if (!gp.grid.rendered) {
37763 // gp.grid.render(el);
37767 // cfg.grid.render(el);
37773 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
37774 // it was the old xcomponent building that caused this before.
37775 // espeically if border is the top element in the tree.
37785 if (typeof(Roo[cfg.xtype]) != 'undefined') {
37787 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
37788 this.add(region, ret);
37792 throw "Can not add '" + cfg.xtype + "' to Border";
37798 this.beginUpdate();
37802 Roo.each(xitems, function(i) {
37803 region = nb && i.region ? i.region : false;
37805 var add = ret.addxtype(i);
37808 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
37809 if (!i.background) {
37810 abn[region] = nb[region] ;
37817 // make the last non-background panel active..
37818 //if (nb) { Roo.log(abn); }
37821 for(var r in abn) {
37822 region = this.getRegion(r);
37824 // tried using nb[r], but it does not work..
37826 region.showPanel(abn[r]);
37837 factory : function(cfg)
37840 var validRegions = Roo.bootstrap.layout.Border.regions;
37842 var target = cfg.region;
37845 var r = Roo.bootstrap.layout;
37849 return new r.North(cfg);
37851 return new r.South(cfg);
37853 return new r.East(cfg);
37855 return new r.West(cfg);
37857 return new r.Center(cfg);
37859 throw 'Layout region "'+target+'" not supported.';
37866 * Ext JS Library 1.1.1
37867 * Copyright(c) 2006-2007, Ext JS, LLC.
37869 * Originally Released Under LGPL - original licence link has changed is not relivant.
37872 * <script type="text/javascript">
37876 * @class Roo.bootstrap.layout.Basic
37877 * @extends Roo.util.Observable
37878 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
37879 * and does not have a titlebar, tabs or any other features. All it does is size and position
37880 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
37881 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
37882 * @cfg {string} region the region that it inhabits..
37883 * @cfg {bool} skipConfig skip config?
37887 Roo.bootstrap.layout.Basic = function(config){
37889 this.mgr = config.mgr;
37891 this.position = config.region;
37893 var skipConfig = config.skipConfig;
37897 * @scope Roo.BasicLayoutRegion
37901 * @event beforeremove
37902 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
37903 * @param {Roo.LayoutRegion} this
37904 * @param {Roo.ContentPanel} panel The panel
37905 * @param {Object} e The cancel event object
37907 "beforeremove" : true,
37909 * @event invalidated
37910 * Fires when the layout for this region is changed.
37911 * @param {Roo.LayoutRegion} this
37913 "invalidated" : true,
37915 * @event visibilitychange
37916 * Fires when this region is shown or hidden
37917 * @param {Roo.LayoutRegion} this
37918 * @param {Boolean} visibility true or false
37920 "visibilitychange" : true,
37922 * @event paneladded
37923 * Fires when a panel is added.
37924 * @param {Roo.LayoutRegion} this
37925 * @param {Roo.ContentPanel} panel The panel
37927 "paneladded" : true,
37929 * @event panelremoved
37930 * Fires when a panel is removed.
37931 * @param {Roo.LayoutRegion} this
37932 * @param {Roo.ContentPanel} panel The panel
37934 "panelremoved" : true,
37936 * @event beforecollapse
37937 * Fires when this region before collapse.
37938 * @param {Roo.LayoutRegion} this
37940 "beforecollapse" : true,
37943 * Fires when this region is collapsed.
37944 * @param {Roo.LayoutRegion} this
37946 "collapsed" : true,
37949 * Fires when this region is expanded.
37950 * @param {Roo.LayoutRegion} this
37955 * Fires when this region is slid into view.
37956 * @param {Roo.LayoutRegion} this
37958 "slideshow" : true,
37961 * Fires when this region slides out of view.
37962 * @param {Roo.LayoutRegion} this
37964 "slidehide" : true,
37966 * @event panelactivated
37967 * Fires when a panel is activated.
37968 * @param {Roo.LayoutRegion} this
37969 * @param {Roo.ContentPanel} panel The activated panel
37971 "panelactivated" : true,
37974 * Fires when the user resizes this region.
37975 * @param {Roo.LayoutRegion} this
37976 * @param {Number} newSize The new size (width for east/west, height for north/south)
37980 /** A collection of panels in this region. @type Roo.util.MixedCollection */
37981 this.panels = new Roo.util.MixedCollection();
37982 this.panels.getKey = this.getPanelId.createDelegate(this);
37984 this.activePanel = null;
37985 // ensure listeners are added...
37987 if (config.listeners || config.events) {
37988 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
37989 listeners : config.listeners || {},
37990 events : config.events || {}
37994 if(skipConfig !== true){
37995 this.applyConfig(config);
37999 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
38001 getPanelId : function(p){
38005 applyConfig : function(config){
38006 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
38007 this.config = config;
38012 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
38013 * the width, for horizontal (north, south) the height.
38014 * @param {Number} newSize The new width or height
38016 resizeTo : function(newSize){
38017 var el = this.el ? this.el :
38018 (this.activePanel ? this.activePanel.getEl() : null);
38020 switch(this.position){
38023 el.setWidth(newSize);
38024 this.fireEvent("resized", this, newSize);
38028 el.setHeight(newSize);
38029 this.fireEvent("resized", this, newSize);
38035 getBox : function(){
38036 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
38039 getMargins : function(){
38040 return this.margins;
38043 updateBox : function(box){
38045 var el = this.activePanel.getEl();
38046 el.dom.style.left = box.x + "px";
38047 el.dom.style.top = box.y + "px";
38048 this.activePanel.setSize(box.width, box.height);
38052 * Returns the container element for this region.
38053 * @return {Roo.Element}
38055 getEl : function(){
38056 return this.activePanel;
38060 * Returns true if this region is currently visible.
38061 * @return {Boolean}
38063 isVisible : function(){
38064 return this.activePanel ? true : false;
38067 setActivePanel : function(panel){
38068 panel = this.getPanel(panel);
38069 if(this.activePanel && this.activePanel != panel){
38070 this.activePanel.setActiveState(false);
38071 this.activePanel.getEl().setLeftTop(-10000,-10000);
38073 this.activePanel = panel;
38074 panel.setActiveState(true);
38076 panel.setSize(this.box.width, this.box.height);
38078 this.fireEvent("panelactivated", this, panel);
38079 this.fireEvent("invalidated");
38083 * Show the specified panel.
38084 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
38085 * @return {Roo.ContentPanel} The shown panel or null
38087 showPanel : function(panel){
38088 panel = this.getPanel(panel);
38090 this.setActivePanel(panel);
38096 * Get the active panel for this region.
38097 * @return {Roo.ContentPanel} The active panel or null
38099 getActivePanel : function(){
38100 return this.activePanel;
38104 * Add the passed ContentPanel(s)
38105 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
38106 * @return {Roo.ContentPanel} The panel added (if only one was added)
38108 add : function(panel){
38109 if(arguments.length > 1){
38110 for(var i = 0, len = arguments.length; i < len; i++) {
38111 this.add(arguments[i]);
38115 if(this.hasPanel(panel)){
38116 this.showPanel(panel);
38119 var el = panel.getEl();
38120 if(el.dom.parentNode != this.mgr.el.dom){
38121 this.mgr.el.dom.appendChild(el.dom);
38123 if(panel.setRegion){
38124 panel.setRegion(this);
38126 this.panels.add(panel);
38127 el.setStyle("position", "absolute");
38128 if(!panel.background){
38129 this.setActivePanel(panel);
38130 if(this.config.initialSize && this.panels.getCount()==1){
38131 this.resizeTo(this.config.initialSize);
38134 this.fireEvent("paneladded", this, panel);
38139 * Returns true if the panel is in this region.
38140 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
38141 * @return {Boolean}
38143 hasPanel : function(panel){
38144 if(typeof panel == "object"){ // must be panel obj
38145 panel = panel.getId();
38147 return this.getPanel(panel) ? true : false;
38151 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
38152 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
38153 * @param {Boolean} preservePanel Overrides the config preservePanel option
38154 * @return {Roo.ContentPanel} The panel that was removed
38156 remove : function(panel, preservePanel){
38157 panel = this.getPanel(panel);
38162 this.fireEvent("beforeremove", this, panel, e);
38163 if(e.cancel === true){
38166 var panelId = panel.getId();
38167 this.panels.removeKey(panelId);
38172 * Returns the panel specified or null if it's not in this region.
38173 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
38174 * @return {Roo.ContentPanel}
38176 getPanel : function(id){
38177 if(typeof id == "object"){ // must be panel obj
38180 return this.panels.get(id);
38184 * Returns this regions position (north/south/east/west/center).
38187 getPosition: function(){
38188 return this.position;
38192 * Ext JS Library 1.1.1
38193 * Copyright(c) 2006-2007, Ext JS, LLC.
38195 * Originally Released Under LGPL - original licence link has changed is not relivant.
38198 * <script type="text/javascript">
38202 * @class Roo.bootstrap.layout.Region
38203 * @extends Roo.bootstrap.layout.Basic
38204 * This class represents a region in a layout manager.
38206 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
38207 * @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})
38208 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
38209 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
38210 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
38211 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
38212 * @cfg {String} title The title for the region (overrides panel titles)
38213 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
38214 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
38215 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
38216 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
38217 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
38218 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
38219 * the space available, similar to FireFox 1.5 tabs (defaults to false)
38220 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
38221 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
38222 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
38224 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
38225 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
38226 * @cfg {Boolean} disableTabTips True to disable tab tooltips
38227 * @cfg {Number} width For East/West panels
38228 * @cfg {Number} height For North/South panels
38229 * @cfg {Boolean} split To show the splitter
38230 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
38232 * @cfg {string} cls Extra CSS classes to add to region
38234 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
38235 * @cfg {string} region the region that it inhabits..
38238 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
38239 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
38241 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
38242 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
38243 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
38245 Roo.bootstrap.layout.Region = function(config)
38247 this.applyConfig(config);
38249 var mgr = config.mgr;
38250 var pos = config.region;
38251 config.skipConfig = true;
38252 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
38255 this.onRender(mgr.el);
38258 this.visible = true;
38259 this.collapsed = false;
38260 this.unrendered_panels = [];
38263 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
38265 position: '', // set by wrapper (eg. north/south etc..)
38266 unrendered_panels : null, // unrendered panels.
38268 tabPosition : false,
38270 mgr: false, // points to 'Border'
38273 createBody : function(){
38274 /** This region's body element
38275 * @type Roo.Element */
38276 this.bodyEl = this.el.createChild({
38278 cls: "roo-layout-panel-body tab-content" // bootstrap added...
38282 onRender: function(ctr, pos)
38284 var dh = Roo.DomHelper;
38285 /** This region's container element
38286 * @type Roo.Element */
38287 this.el = dh.append(ctr.dom, {
38289 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
38291 /** This region's title element
38292 * @type Roo.Element */
38294 this.titleEl = dh.append(this.el.dom, {
38296 unselectable: "on",
38297 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
38299 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
38300 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
38304 this.titleEl.enableDisplayMode();
38305 /** This region's title text element
38306 * @type HTMLElement */
38307 this.titleTextEl = this.titleEl.dom.firstChild;
38308 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
38310 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
38311 this.closeBtn.enableDisplayMode();
38312 this.closeBtn.on("click", this.closeClicked, this);
38313 this.closeBtn.hide();
38315 this.createBody(this.config);
38316 if(this.config.hideWhenEmpty){
38318 this.on("paneladded", this.validateVisibility, this);
38319 this.on("panelremoved", this.validateVisibility, this);
38321 if(this.autoScroll){
38322 this.bodyEl.setStyle("overflow", "auto");
38324 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
38326 //if(c.titlebar !== false){
38327 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
38328 this.titleEl.hide();
38330 this.titleEl.show();
38331 if(this.config.title){
38332 this.titleTextEl.innerHTML = this.config.title;
38336 if(this.config.collapsed){
38337 this.collapse(true);
38339 if(this.config.hidden){
38343 if (this.unrendered_panels && this.unrendered_panels.length) {
38344 for (var i =0;i< this.unrendered_panels.length; i++) {
38345 this.add(this.unrendered_panels[i]);
38347 this.unrendered_panels = null;
38353 applyConfig : function(c)
38356 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
38357 var dh = Roo.DomHelper;
38358 if(c.titlebar !== false){
38359 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
38360 this.collapseBtn.on("click", this.collapse, this);
38361 this.collapseBtn.enableDisplayMode();
38363 if(c.showPin === true || this.showPin){
38364 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
38365 this.stickBtn.enableDisplayMode();
38366 this.stickBtn.on("click", this.expand, this);
38367 this.stickBtn.hide();
38372 /** This region's collapsed element
38373 * @type Roo.Element */
38376 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
38377 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
38380 if(c.floatable !== false){
38381 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
38382 this.collapsedEl.on("click", this.collapseClick, this);
38385 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
38386 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
38387 id: "message", unselectable: "on", style:{"float":"left"}});
38388 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
38390 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
38391 this.expandBtn.on("click", this.expand, this);
38395 if(this.collapseBtn){
38396 this.collapseBtn.setVisible(c.collapsible == true);
38399 this.cmargins = c.cmargins || this.cmargins ||
38400 (this.position == "west" || this.position == "east" ?
38401 {top: 0, left: 2, right:2, bottom: 0} :
38402 {top: 2, left: 0, right:0, bottom: 2});
38404 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
38407 this.tabPosition = [ 'top','bottom', 'west'].indexOf(c.tabPosition) > -1 ? c.tabPosition : "top";
38409 this.autoScroll = c.autoScroll || false;
38414 this.duration = c.duration || .30;
38415 this.slideDuration = c.slideDuration || .45;
38420 * Returns true if this region is currently visible.
38421 * @return {Boolean}
38423 isVisible : function(){
38424 return this.visible;
38428 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
38429 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
38431 //setCollapsedTitle : function(title){
38432 // title = title || " ";
38433 // if(this.collapsedTitleTextEl){
38434 // this.collapsedTitleTextEl.innerHTML = title;
38438 getBox : function(){
38440 // if(!this.collapsed){
38441 b = this.el.getBox(false, true);
38443 // b = this.collapsedEl.getBox(false, true);
38448 getMargins : function(){
38449 return this.margins;
38450 //return this.collapsed ? this.cmargins : this.margins;
38453 highlight : function(){
38454 this.el.addClass("x-layout-panel-dragover");
38457 unhighlight : function(){
38458 this.el.removeClass("x-layout-panel-dragover");
38461 updateBox : function(box)
38463 if (!this.bodyEl) {
38464 return; // not rendered yet..
38468 if(!this.collapsed){
38469 this.el.dom.style.left = box.x + "px";
38470 this.el.dom.style.top = box.y + "px";
38471 this.updateBody(box.width, box.height);
38473 this.collapsedEl.dom.style.left = box.x + "px";
38474 this.collapsedEl.dom.style.top = box.y + "px";
38475 this.collapsedEl.setSize(box.width, box.height);
38478 this.tabs.autoSizeTabs();
38482 updateBody : function(w, h)
38485 this.el.setWidth(w);
38486 w -= this.el.getBorderWidth("rl");
38487 if(this.config.adjustments){
38488 w += this.config.adjustments[0];
38491 if(h !== null && h > 0){
38492 this.el.setHeight(h);
38493 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
38494 h -= this.el.getBorderWidth("tb");
38495 if(this.config.adjustments){
38496 h += this.config.adjustments[1];
38498 this.bodyEl.setHeight(h);
38500 h = this.tabs.syncHeight(h);
38503 if(this.panelSize){
38504 w = w !== null ? w : this.panelSize.width;
38505 h = h !== null ? h : this.panelSize.height;
38507 if(this.activePanel){
38508 var el = this.activePanel.getEl();
38509 w = w !== null ? w : el.getWidth();
38510 h = h !== null ? h : el.getHeight();
38511 this.panelSize = {width: w, height: h};
38512 this.activePanel.setSize(w, h);
38514 if(Roo.isIE && this.tabs){
38515 this.tabs.el.repaint();
38520 * Returns the container element for this region.
38521 * @return {Roo.Element}
38523 getEl : function(){
38528 * Hides this region.
38531 //if(!this.collapsed){
38532 this.el.dom.style.left = "-2000px";
38535 // this.collapsedEl.dom.style.left = "-2000px";
38536 // this.collapsedEl.hide();
38538 this.visible = false;
38539 this.fireEvent("visibilitychange", this, false);
38543 * Shows this region if it was previously hidden.
38546 //if(!this.collapsed){
38549 // this.collapsedEl.show();
38551 this.visible = true;
38552 this.fireEvent("visibilitychange", this, true);
38555 closeClicked : function(){
38556 if(this.activePanel){
38557 this.remove(this.activePanel);
38561 collapseClick : function(e){
38563 e.stopPropagation();
38566 e.stopPropagation();
38572 * Collapses this region.
38573 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
38576 collapse : function(skipAnim, skipCheck = false){
38577 if(this.collapsed) {
38581 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
38583 this.collapsed = true;
38585 this.split.el.hide();
38587 if(this.config.animate && skipAnim !== true){
38588 this.fireEvent("invalidated", this);
38589 this.animateCollapse();
38591 this.el.setLocation(-20000,-20000);
38593 this.collapsedEl.show();
38594 this.fireEvent("collapsed", this);
38595 this.fireEvent("invalidated", this);
38601 animateCollapse : function(){
38606 * Expands this region if it was previously collapsed.
38607 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
38608 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
38611 expand : function(e, skipAnim){
38613 e.stopPropagation();
38615 if(!this.collapsed || this.el.hasActiveFx()) {
38619 this.afterSlideIn();
38622 this.collapsed = false;
38623 if(this.config.animate && skipAnim !== true){
38624 this.animateExpand();
38628 this.split.el.show();
38630 this.collapsedEl.setLocation(-2000,-2000);
38631 this.collapsedEl.hide();
38632 this.fireEvent("invalidated", this);
38633 this.fireEvent("expanded", this);
38637 animateExpand : function(){
38641 initTabs : function()
38643 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
38645 var ts = new Roo.bootstrap.panel.Tabs({
38646 el: this.bodyEl.dom,
38648 tabPosition: this.tabPosition ? this.tabPosition : 'top',
38649 disableTooltips: this.config.disableTabTips,
38650 toolbar : this.config.toolbar
38653 if(this.config.hideTabs){
38654 ts.stripWrap.setDisplayed(false);
38657 ts.resizeTabs = this.config.resizeTabs === true;
38658 ts.minTabWidth = this.config.minTabWidth || 40;
38659 ts.maxTabWidth = this.config.maxTabWidth || 250;
38660 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
38661 ts.monitorResize = false;
38662 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
38663 ts.bodyEl.addClass('roo-layout-tabs-body');
38664 this.panels.each(this.initPanelAsTab, this);
38667 initPanelAsTab : function(panel){
38668 var ti = this.tabs.addTab(
38672 this.config.closeOnTab && panel.isClosable(),
38675 if(panel.tabTip !== undefined){
38676 ti.setTooltip(panel.tabTip);
38678 ti.on("activate", function(){
38679 this.setActivePanel(panel);
38682 if(this.config.closeOnTab){
38683 ti.on("beforeclose", function(t, e){
38685 this.remove(panel);
38689 panel.tabItem = ti;
38694 updatePanelTitle : function(panel, title)
38696 if(this.activePanel == panel){
38697 this.updateTitle(title);
38700 var ti = this.tabs.getTab(panel.getEl().id);
38702 if(panel.tabTip !== undefined){
38703 ti.setTooltip(panel.tabTip);
38708 updateTitle : function(title){
38709 if(this.titleTextEl && !this.config.title){
38710 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
38714 setActivePanel : function(panel)
38716 panel = this.getPanel(panel);
38717 if(this.activePanel && this.activePanel != panel){
38718 if(this.activePanel.setActiveState(false) === false){
38722 this.activePanel = panel;
38723 panel.setActiveState(true);
38724 if(this.panelSize){
38725 panel.setSize(this.panelSize.width, this.panelSize.height);
38728 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
38730 this.updateTitle(panel.getTitle());
38732 this.fireEvent("invalidated", this);
38734 this.fireEvent("panelactivated", this, panel);
38738 * Shows the specified panel.
38739 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
38740 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
38742 showPanel : function(panel)
38744 panel = this.getPanel(panel);
38747 var tab = this.tabs.getTab(panel.getEl().id);
38748 if(tab.isHidden()){
38749 this.tabs.unhideTab(tab.id);
38753 this.setActivePanel(panel);
38760 * Get the active panel for this region.
38761 * @return {Roo.ContentPanel} The active panel or null
38763 getActivePanel : function(){
38764 return this.activePanel;
38767 validateVisibility : function(){
38768 if(this.panels.getCount() < 1){
38769 this.updateTitle(" ");
38770 this.closeBtn.hide();
38773 if(!this.isVisible()){
38780 * Adds the passed ContentPanel(s) to this region.
38781 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
38782 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
38784 add : function(panel)
38786 if(arguments.length > 1){
38787 for(var i = 0, len = arguments.length; i < len; i++) {
38788 this.add(arguments[i]);
38793 // if we have not been rendered yet, then we can not really do much of this..
38794 if (!this.bodyEl) {
38795 this.unrendered_panels.push(panel);
38802 if(this.hasPanel(panel)){
38803 this.showPanel(panel);
38806 panel.setRegion(this);
38807 this.panels.add(panel);
38808 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
38809 // sinle panel - no tab...?? would it not be better to render it with the tabs,
38810 // and hide them... ???
38811 this.bodyEl.dom.appendChild(panel.getEl().dom);
38812 if(panel.background !== true){
38813 this.setActivePanel(panel);
38815 this.fireEvent("paneladded", this, panel);
38822 this.initPanelAsTab(panel);
38826 if(panel.background !== true){
38827 this.tabs.activate(panel.getEl().id);
38829 this.fireEvent("paneladded", this, panel);
38834 * Hides the tab for the specified panel.
38835 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
38837 hidePanel : function(panel){
38838 if(this.tabs && (panel = this.getPanel(panel))){
38839 this.tabs.hideTab(panel.getEl().id);
38844 * Unhides the tab for a previously hidden panel.
38845 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
38847 unhidePanel : function(panel){
38848 if(this.tabs && (panel = this.getPanel(panel))){
38849 this.tabs.unhideTab(panel.getEl().id);
38853 clearPanels : function(){
38854 while(this.panels.getCount() > 0){
38855 this.remove(this.panels.first());
38860 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
38861 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
38862 * @param {Boolean} preservePanel Overrides the config preservePanel option
38863 * @return {Roo.ContentPanel} The panel that was removed
38865 remove : function(panel, preservePanel)
38867 panel = this.getPanel(panel);
38872 this.fireEvent("beforeremove", this, panel, e);
38873 if(e.cancel === true){
38876 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
38877 var panelId = panel.getId();
38878 this.panels.removeKey(panelId);
38880 document.body.appendChild(panel.getEl().dom);
38883 this.tabs.removeTab(panel.getEl().id);
38884 }else if (!preservePanel){
38885 this.bodyEl.dom.removeChild(panel.getEl().dom);
38887 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
38888 var p = this.panels.first();
38889 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
38890 tempEl.appendChild(p.getEl().dom);
38891 this.bodyEl.update("");
38892 this.bodyEl.dom.appendChild(p.getEl().dom);
38894 this.updateTitle(p.getTitle());
38896 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
38897 this.setActivePanel(p);
38899 panel.setRegion(null);
38900 if(this.activePanel == panel){
38901 this.activePanel = null;
38903 if(this.config.autoDestroy !== false && preservePanel !== true){
38904 try{panel.destroy();}catch(e){}
38906 this.fireEvent("panelremoved", this, panel);
38911 * Returns the TabPanel component used by this region
38912 * @return {Roo.TabPanel}
38914 getTabs : function(){
38918 createTool : function(parentEl, className){
38919 var btn = Roo.DomHelper.append(parentEl, {
38921 cls: "x-layout-tools-button",
38924 cls: "roo-layout-tools-button-inner " + className,
38928 btn.addClassOnOver("roo-layout-tools-button-over");
38933 * Ext JS Library 1.1.1
38934 * Copyright(c) 2006-2007, Ext JS, LLC.
38936 * Originally Released Under LGPL - original licence link has changed is not relivant.
38939 * <script type="text/javascript">
38945 * @class Roo.SplitLayoutRegion
38946 * @extends Roo.LayoutRegion
38947 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
38949 Roo.bootstrap.layout.Split = function(config){
38950 this.cursor = config.cursor;
38951 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
38954 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
38956 splitTip : "Drag to resize.",
38957 collapsibleSplitTip : "Drag to resize. Double click to hide.",
38958 useSplitTips : false,
38960 applyConfig : function(config){
38961 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
38964 onRender : function(ctr,pos) {
38966 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
38967 if(!this.config.split){
38972 var splitEl = Roo.DomHelper.append(ctr.dom, {
38974 id: this.el.id + "-split",
38975 cls: "roo-layout-split roo-layout-split-"+this.position,
38978 /** The SplitBar for this region
38979 * @type Roo.SplitBar */
38980 // does not exist yet...
38981 Roo.log([this.position, this.orientation]);
38983 this.split = new Roo.bootstrap.SplitBar({
38984 dragElement : splitEl,
38985 resizingElement: this.el,
38986 orientation : this.orientation
38989 this.split.on("moved", this.onSplitMove, this);
38990 this.split.useShim = this.config.useShim === true;
38991 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
38992 if(this.useSplitTips){
38993 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
38995 //if(config.collapsible){
38996 // this.split.el.on("dblclick", this.collapse, this);
38999 if(typeof this.config.minSize != "undefined"){
39000 this.split.minSize = this.config.minSize;
39002 if(typeof this.config.maxSize != "undefined"){
39003 this.split.maxSize = this.config.maxSize;
39005 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
39006 this.hideSplitter();
39011 getHMaxSize : function(){
39012 var cmax = this.config.maxSize || 10000;
39013 var center = this.mgr.getRegion("center");
39014 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
39017 getVMaxSize : function(){
39018 var cmax = this.config.maxSize || 10000;
39019 var center = this.mgr.getRegion("center");
39020 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
39023 onSplitMove : function(split, newSize){
39024 this.fireEvent("resized", this, newSize);
39028 * Returns the {@link Roo.SplitBar} for this region.
39029 * @return {Roo.SplitBar}
39031 getSplitBar : function(){
39036 this.hideSplitter();
39037 Roo.bootstrap.layout.Split.superclass.hide.call(this);
39040 hideSplitter : function(){
39042 this.split.el.setLocation(-2000,-2000);
39043 this.split.el.hide();
39049 this.split.el.show();
39051 Roo.bootstrap.layout.Split.superclass.show.call(this);
39054 beforeSlide: function(){
39055 if(Roo.isGecko){// firefox overflow auto bug workaround
39056 this.bodyEl.clip();
39058 this.tabs.bodyEl.clip();
39060 if(this.activePanel){
39061 this.activePanel.getEl().clip();
39063 if(this.activePanel.beforeSlide){
39064 this.activePanel.beforeSlide();
39070 afterSlide : function(){
39071 if(Roo.isGecko){// firefox overflow auto bug workaround
39072 this.bodyEl.unclip();
39074 this.tabs.bodyEl.unclip();
39076 if(this.activePanel){
39077 this.activePanel.getEl().unclip();
39078 if(this.activePanel.afterSlide){
39079 this.activePanel.afterSlide();
39085 initAutoHide : function(){
39086 if(this.autoHide !== false){
39087 if(!this.autoHideHd){
39088 var st = new Roo.util.DelayedTask(this.slideIn, this);
39089 this.autoHideHd = {
39090 "mouseout": function(e){
39091 if(!e.within(this.el, true)){
39095 "mouseover" : function(e){
39101 this.el.on(this.autoHideHd);
39105 clearAutoHide : function(){
39106 if(this.autoHide !== false){
39107 this.el.un("mouseout", this.autoHideHd.mouseout);
39108 this.el.un("mouseover", this.autoHideHd.mouseover);
39112 clearMonitor : function(){
39113 Roo.get(document).un("click", this.slideInIf, this);
39116 // these names are backwards but not changed for compat
39117 slideOut : function(){
39118 if(this.isSlid || this.el.hasActiveFx()){
39121 this.isSlid = true;
39122 if(this.collapseBtn){
39123 this.collapseBtn.hide();
39125 this.closeBtnState = this.closeBtn.getStyle('display');
39126 this.closeBtn.hide();
39128 this.stickBtn.show();
39131 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
39132 this.beforeSlide();
39133 this.el.setStyle("z-index", 10001);
39134 this.el.slideIn(this.getSlideAnchor(), {
39135 callback: function(){
39137 this.initAutoHide();
39138 Roo.get(document).on("click", this.slideInIf, this);
39139 this.fireEvent("slideshow", this);
39146 afterSlideIn : function(){
39147 this.clearAutoHide();
39148 this.isSlid = false;
39149 this.clearMonitor();
39150 this.el.setStyle("z-index", "");
39151 if(this.collapseBtn){
39152 this.collapseBtn.show();
39154 this.closeBtn.setStyle('display', this.closeBtnState);
39156 this.stickBtn.hide();
39158 this.fireEvent("slidehide", this);
39161 slideIn : function(cb){
39162 if(!this.isSlid || this.el.hasActiveFx()){
39166 this.isSlid = false;
39167 this.beforeSlide();
39168 this.el.slideOut(this.getSlideAnchor(), {
39169 callback: function(){
39170 this.el.setLeftTop(-10000, -10000);
39172 this.afterSlideIn();
39180 slideInIf : function(e){
39181 if(!e.within(this.el)){
39186 animateCollapse : function(){
39187 this.beforeSlide();
39188 this.el.setStyle("z-index", 20000);
39189 var anchor = this.getSlideAnchor();
39190 this.el.slideOut(anchor, {
39191 callback : function(){
39192 this.el.setStyle("z-index", "");
39193 this.collapsedEl.slideIn(anchor, {duration:.3});
39195 this.el.setLocation(-10000,-10000);
39197 this.fireEvent("collapsed", this);
39204 animateExpand : function(){
39205 this.beforeSlide();
39206 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
39207 this.el.setStyle("z-index", 20000);
39208 this.collapsedEl.hide({
39211 this.el.slideIn(this.getSlideAnchor(), {
39212 callback : function(){
39213 this.el.setStyle("z-index", "");
39216 this.split.el.show();
39218 this.fireEvent("invalidated", this);
39219 this.fireEvent("expanded", this);
39247 getAnchor : function(){
39248 return this.anchors[this.position];
39251 getCollapseAnchor : function(){
39252 return this.canchors[this.position];
39255 getSlideAnchor : function(){
39256 return this.sanchors[this.position];
39259 getAlignAdj : function(){
39260 var cm = this.cmargins;
39261 switch(this.position){
39277 getExpandAdj : function(){
39278 var c = this.collapsedEl, cm = this.cmargins;
39279 switch(this.position){
39281 return [-(cm.right+c.getWidth()+cm.left), 0];
39284 return [cm.right+c.getWidth()+cm.left, 0];
39287 return [0, -(cm.top+cm.bottom+c.getHeight())];
39290 return [0, cm.top+cm.bottom+c.getHeight()];
39296 * Ext JS Library 1.1.1
39297 * Copyright(c) 2006-2007, Ext JS, LLC.
39299 * Originally Released Under LGPL - original licence link has changed is not relivant.
39302 * <script type="text/javascript">
39305 * These classes are private internal classes
39307 Roo.bootstrap.layout.Center = function(config){
39308 config.region = "center";
39309 Roo.bootstrap.layout.Region.call(this, config);
39310 this.visible = true;
39311 this.minWidth = config.minWidth || 20;
39312 this.minHeight = config.minHeight || 20;
39315 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
39317 // center panel can't be hidden
39321 // center panel can't be hidden
39324 getMinWidth: function(){
39325 return this.minWidth;
39328 getMinHeight: function(){
39329 return this.minHeight;
39343 Roo.bootstrap.layout.North = function(config)
39345 config.region = 'north';
39346 config.cursor = 'n-resize';
39348 Roo.bootstrap.layout.Split.call(this, config);
39352 this.split.placement = Roo.bootstrap.SplitBar.TOP;
39353 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
39354 this.split.el.addClass("roo-layout-split-v");
39356 //var size = config.initialSize || config.height;
39357 //if(this.el && typeof size != "undefined"){
39358 // this.el.setHeight(size);
39361 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
39363 orientation: Roo.bootstrap.SplitBar.VERTICAL,
39366 onRender : function(ctr, pos)
39368 Roo.bootstrap.layout.Split.prototype.onRender.call(this, ctr, pos);
39369 var size = this.config.initialSize || this.config.height;
39370 if(this.el && typeof size != "undefined"){
39371 this.el.setHeight(size);
39376 getBox : function(){
39377 if(this.collapsed){
39378 return this.collapsedEl.getBox();
39380 var box = this.el.getBox();
39382 box.height += this.split.el.getHeight();
39387 updateBox : function(box){
39388 if(this.split && !this.collapsed){
39389 box.height -= this.split.el.getHeight();
39390 this.split.el.setLeft(box.x);
39391 this.split.el.setTop(box.y+box.height);
39392 this.split.el.setWidth(box.width);
39394 if(this.collapsed){
39395 this.updateBody(box.width, null);
39397 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
39405 Roo.bootstrap.layout.South = function(config){
39406 config.region = 'south';
39407 config.cursor = 's-resize';
39408 Roo.bootstrap.layout.Split.call(this, config);
39410 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
39411 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
39412 this.split.el.addClass("roo-layout-split-v");
39417 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
39418 orientation: Roo.bootstrap.SplitBar.VERTICAL,
39420 onRender : function(ctr, pos)
39422 Roo.bootstrap.layout.Split.prototype.onRender.call(this, ctr, pos);
39423 var size = this.config.initialSize || this.config.height;
39424 if(this.el && typeof size != "undefined"){
39425 this.el.setHeight(size);
39430 getBox : function(){
39431 if(this.collapsed){
39432 return this.collapsedEl.getBox();
39434 var box = this.el.getBox();
39436 var sh = this.split.el.getHeight();
39443 updateBox : function(box){
39444 if(this.split && !this.collapsed){
39445 var sh = this.split.el.getHeight();
39448 this.split.el.setLeft(box.x);
39449 this.split.el.setTop(box.y-sh);
39450 this.split.el.setWidth(box.width);
39452 if(this.collapsed){
39453 this.updateBody(box.width, null);
39455 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
39459 Roo.bootstrap.layout.East = function(config){
39460 config.region = "east";
39461 config.cursor = "e-resize";
39462 Roo.bootstrap.layout.Split.call(this, config);
39464 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
39465 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
39466 this.split.el.addClass("roo-layout-split-h");
39470 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
39471 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
39473 onRender : function(ctr, pos)
39475 Roo.bootstrap.layout.Split.prototype.onRender.call(this, ctr, pos);
39476 var size = this.config.initialSize || this.config.width;
39477 if(this.el && typeof size != "undefined"){
39478 this.el.setWidth(size);
39483 getBox : function(){
39484 if(this.collapsed){
39485 return this.collapsedEl.getBox();
39487 var box = this.el.getBox();
39489 var sw = this.split.el.getWidth();
39496 updateBox : function(box){
39497 if(this.split && !this.collapsed){
39498 var sw = this.split.el.getWidth();
39500 this.split.el.setLeft(box.x);
39501 this.split.el.setTop(box.y);
39502 this.split.el.setHeight(box.height);
39505 if(this.collapsed){
39506 this.updateBody(null, box.height);
39508 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
39512 Roo.bootstrap.layout.West = function(config){
39513 config.region = "west";
39514 config.cursor = "w-resize";
39516 Roo.bootstrap.layout.Split.call(this, config);
39518 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
39519 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
39520 this.split.el.addClass("roo-layout-split-h");
39524 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
39525 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
39527 onRender: function(ctr, pos)
39529 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
39530 var size = this.config.initialSize || this.config.width;
39531 if(typeof size != "undefined"){
39532 this.el.setWidth(size);
39536 getBox : function(){
39537 if(this.collapsed){
39538 return this.collapsedEl.getBox();
39540 var box = this.el.getBox();
39541 if (box.width == 0) {
39542 box.width = this.config.width; // kludge?
39545 box.width += this.split.el.getWidth();
39550 updateBox : function(box){
39551 if(this.split && !this.collapsed){
39552 var sw = this.split.el.getWidth();
39554 this.split.el.setLeft(box.x+box.width);
39555 this.split.el.setTop(box.y);
39556 this.split.el.setHeight(box.height);
39558 if(this.collapsed){
39559 this.updateBody(null, box.height);
39561 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
39563 });Roo.namespace("Roo.bootstrap.panel");/*
39565 * Ext JS Library 1.1.1
39566 * Copyright(c) 2006-2007, Ext JS, LLC.
39568 * Originally Released Under LGPL - original licence link has changed is not relivant.
39571 * <script type="text/javascript">
39574 * @class Roo.ContentPanel
39575 * @extends Roo.util.Observable
39576 * A basic ContentPanel element.
39577 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
39578 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
39579 * @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
39580 * @cfg {Boolean} closable True if the panel can be closed/removed
39581 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
39582 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
39583 * @cfg {Toolbar} toolbar A toolbar for this panel
39584 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
39585 * @cfg {String} title The title for this panel
39586 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
39587 * @cfg {String} url Calls {@link #setUrl} with this value
39588 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
39589 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
39590 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
39591 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
39592 * @cfg {Boolean} iframe contents are an iframe - makes showing remote sources/CSS feasible..
39593 * @cfg {Boolean} badges render the badges
39594 * @cfg {String} cls extra classes to use
39595 * @cfg {String} background (primary|secondary|success|info|warning|danger|light|dark)
39598 * Create a new ContentPanel.
39599 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
39600 * @param {String/Object} config A string to set only the title or a config object
39601 * @param {String} content (optional) Set the HTML content for this panel
39602 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
39604 Roo.bootstrap.panel.Content = function( config){
39606 this.tpl = config.tpl || false;
39608 var el = config.el;
39609 var content = config.content;
39611 if(config.autoCreate){ // xtype is available if this is called from factory
39614 this.el = Roo.get(el);
39615 if(!this.el && config && config.autoCreate){
39616 if(typeof config.autoCreate == "object"){
39617 if(!config.autoCreate.id){
39618 config.autoCreate.id = config.id||el;
39620 this.el = Roo.DomHelper.append(document.body,
39621 config.autoCreate, true);
39625 cls: (config.cls || '') +
39626 (config.background ? ' bg-' + config.background : '') +
39627 " roo-layout-inactive-content",
39630 if (config.iframe) {
39634 style : 'border: 0px',
39635 src : 'about:blank'
39641 elcfg.html = config.html;
39645 this.el = Roo.DomHelper.append(document.body, elcfg , true);
39646 if (config.iframe) {
39647 this.iframeEl = this.el.select('iframe',true).first();
39652 this.closable = false;
39653 this.loaded = false;
39654 this.active = false;
39657 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
39659 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
39661 this.wrapEl = this.el; //this.el.wrap();
39663 if (config.toolbar.items) {
39664 ti = config.toolbar.items ;
39665 delete config.toolbar.items ;
39669 this.toolbar.render(this.wrapEl, 'before');
39670 for(var i =0;i < ti.length;i++) {
39671 // Roo.log(['add child', items[i]]);
39672 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
39674 this.toolbar.items = nitems;
39675 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
39676 delete config.toolbar;
39680 // xtype created footer. - not sure if will work as we normally have to render first..
39681 if (this.footer && !this.footer.el && this.footer.xtype) {
39682 if (!this.wrapEl) {
39683 this.wrapEl = this.el.wrap();
39686 this.footer.container = this.wrapEl.createChild();
39688 this.footer = Roo.factory(this.footer, Roo);
39693 if(typeof config == "string"){
39694 this.title = config;
39696 Roo.apply(this, config);
39700 this.resizeEl = Roo.get(this.resizeEl, true);
39702 this.resizeEl = this.el;
39704 // handle view.xtype
39712 * Fires when this panel is activated.
39713 * @param {Roo.ContentPanel} this
39717 * @event deactivate
39718 * Fires when this panel is activated.
39719 * @param {Roo.ContentPanel} this
39721 "deactivate" : true,
39725 * Fires when this panel is resized if fitToFrame is true.
39726 * @param {Roo.ContentPanel} this
39727 * @param {Number} width The width after any component adjustments
39728 * @param {Number} height The height after any component adjustments
39734 * Fires when this tab is created
39735 * @param {Roo.ContentPanel} this
39746 if(this.autoScroll && !this.iframe){
39747 this.resizeEl.setStyle("overflow", "auto");
39749 // fix randome scrolling
39750 //this.el.on('scroll', function() {
39751 // Roo.log('fix random scolling');
39752 // this.scrollTo('top',0);
39755 content = content || this.content;
39757 this.setContent(content);
39759 if(config && config.url){
39760 this.setUrl(this.url, this.params, this.loadOnce);
39765 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
39767 if (this.view && typeof(this.view.xtype) != 'undefined') {
39768 this.view.el = this.el.appendChild(document.createElement("div"));
39769 this.view = Roo.factory(this.view);
39770 this.view.render && this.view.render(false, '');
39774 this.fireEvent('render', this);
39777 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
39787 setRegion : function(region){
39788 this.region = region;
39789 this.setActiveClass(region && !this.background);
39793 setActiveClass: function(state)
39796 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
39797 this.el.setStyle('position','relative');
39799 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
39800 this.el.setStyle('position', 'absolute');
39805 * Returns the toolbar for this Panel if one was configured.
39806 * @return {Roo.Toolbar}
39808 getToolbar : function(){
39809 return this.toolbar;
39812 setActiveState : function(active)
39814 this.active = active;
39815 this.setActiveClass(active);
39817 if(this.fireEvent("deactivate", this) === false){
39822 this.fireEvent("activate", this);
39826 * Updates this panel's element (not for iframe)
39827 * @param {String} content The new content
39828 * @param {Boolean} loadScripts (optional) true to look for and process scripts
39830 setContent : function(content, loadScripts){
39835 this.el.update(content, loadScripts);
39838 ignoreResize : function(w, h){
39839 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
39842 this.lastSize = {width: w, height: h};
39847 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
39848 * @return {Roo.UpdateManager} The UpdateManager
39850 getUpdateManager : function(){
39854 return this.el.getUpdateManager();
39857 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
39858 * Does not work with IFRAME contents
39859 * @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:
39862 url: "your-url.php",
39863 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
39864 callback: yourFunction,
39865 scope: yourObject, //(optional scope)
39868 text: "Loading...",
39874 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
39875 * 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.
39876 * @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}
39877 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
39878 * @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.
39879 * @return {Roo.ContentPanel} this
39887 var um = this.el.getUpdateManager();
39888 um.update.apply(um, arguments);
39894 * 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.
39895 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
39896 * @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)
39897 * @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)
39898 * @return {Roo.UpdateManager|Boolean} The UpdateManager or false if IFRAME
39900 setUrl : function(url, params, loadOnce){
39902 this.iframeEl.dom.src = url;
39906 if(this.refreshDelegate){
39907 this.removeListener("activate", this.refreshDelegate);
39909 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
39910 this.on("activate", this.refreshDelegate);
39911 return this.el.getUpdateManager();
39914 _handleRefresh : function(url, params, loadOnce){
39915 if(!loadOnce || !this.loaded){
39916 var updater = this.el.getUpdateManager();
39917 updater.update(url, params, this._setLoaded.createDelegate(this));
39921 _setLoaded : function(){
39922 this.loaded = true;
39926 * Returns this panel's id
39929 getId : function(){
39934 * Returns this panel's element - used by regiosn to add.
39935 * @return {Roo.Element}
39937 getEl : function(){
39938 return this.wrapEl || this.el;
39943 adjustForComponents : function(width, height)
39945 //Roo.log('adjustForComponents ');
39946 if(this.resizeEl != this.el){
39947 width -= this.el.getFrameWidth('lr');
39948 height -= this.el.getFrameWidth('tb');
39951 var te = this.toolbar.getEl();
39952 te.setWidth(width);
39953 height -= te.getHeight();
39956 var te = this.footer.getEl();
39957 te.setWidth(width);
39958 height -= te.getHeight();
39962 if(this.adjustments){
39963 width += this.adjustments[0];
39964 height += this.adjustments[1];
39966 return {"width": width, "height": height};
39969 setSize : function(width, height){
39970 if(this.fitToFrame && !this.ignoreResize(width, height)){
39971 if(this.fitContainer && this.resizeEl != this.el){
39972 this.el.setSize(width, height);
39974 var size = this.adjustForComponents(width, height);
39976 this.iframeEl.setSize(width,height);
39979 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
39980 this.fireEvent('resize', this, size.width, size.height);
39987 * Returns this panel's title
39990 getTitle : function(){
39992 if (typeof(this.title) != 'object') {
39997 for (var k in this.title) {
39998 if (!this.title.hasOwnProperty(k)) {
40002 if (k.indexOf('-') >= 0) {
40003 var s = k.split('-');
40004 for (var i = 0; i<s.length; i++) {
40005 t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
40008 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
40015 * Set this panel's title
40016 * @param {String} title
40018 setTitle : function(title){
40019 this.title = title;
40021 this.region.updatePanelTitle(this, title);
40026 * Returns true is this panel was configured to be closable
40027 * @return {Boolean}
40029 isClosable : function(){
40030 return this.closable;
40033 beforeSlide : function(){
40035 this.resizeEl.clip();
40038 afterSlide : function(){
40040 this.resizeEl.unclip();
40044 * Force a content refresh from the URL specified in the {@link #setUrl} method.
40045 * Will fail silently if the {@link #setUrl} method has not been called.
40046 * This does not activate the panel, just updates its content.
40048 refresh : function(){
40049 if(this.refreshDelegate){
40050 this.loaded = false;
40051 this.refreshDelegate();
40056 * Destroys this panel
40058 destroy : function(){
40059 this.el.removeAllListeners();
40060 var tempEl = document.createElement("span");
40061 tempEl.appendChild(this.el.dom);
40062 tempEl.innerHTML = "";
40068 * form - if the content panel contains a form - this is a reference to it.
40069 * @type {Roo.form.Form}
40073 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
40074 * This contains a reference to it.
40080 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
40090 * @param {Object} cfg Xtype definition of item to add.
40094 getChildContainer: function () {
40095 return this.getEl();
40100 var ret = new Roo.factory(cfg);
40105 if (cfg.xtype.match(/^Form$/)) {
40108 //if (this.footer) {
40109 // el = this.footer.container.insertSibling(false, 'before');
40111 el = this.el.createChild();
40114 this.form = new Roo.form.Form(cfg);
40117 if ( this.form.allItems.length) {
40118 this.form.render(el.dom);
40122 // should only have one of theses..
40123 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
40124 // views.. should not be just added - used named prop 'view''
40126 cfg.el = this.el.appendChild(document.createElement("div"));
40129 var ret = new Roo.factory(cfg);
40131 ret.render && ret.render(false, ''); // render blank..
40141 * @class Roo.bootstrap.panel.Grid
40142 * @extends Roo.bootstrap.panel.Content
40144 * Create a new GridPanel.
40145 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
40146 * @param {Object} config A the config object
40152 Roo.bootstrap.panel.Grid = function(config)
40156 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
40157 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
40159 config.el = this.wrapper;
40160 //this.el = this.wrapper;
40162 if (config.container) {
40163 // ctor'ed from a Border/panel.grid
40166 this.wrapper.setStyle("overflow", "hidden");
40167 this.wrapper.addClass('roo-grid-container');
40172 if(config.toolbar){
40173 var tool_el = this.wrapper.createChild();
40174 this.toolbar = Roo.factory(config.toolbar);
40176 if (config.toolbar.items) {
40177 ti = config.toolbar.items ;
40178 delete config.toolbar.items ;
40182 this.toolbar.render(tool_el);
40183 for(var i =0;i < ti.length;i++) {
40184 // Roo.log(['add child', items[i]]);
40185 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
40187 this.toolbar.items = nitems;
40189 delete config.toolbar;
40192 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
40193 config.grid.scrollBody = true;;
40194 config.grid.monitorWindowResize = false; // turn off autosizing
40195 config.grid.autoHeight = false;
40196 config.grid.autoWidth = false;
40198 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
40200 if (config.background) {
40201 // render grid on panel activation (if panel background)
40202 this.on('activate', function(gp) {
40203 if (!gp.grid.rendered) {
40204 gp.grid.render(this.wrapper);
40205 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
40210 this.grid.render(this.wrapper);
40211 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
40214 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
40215 // ??? needed ??? config.el = this.wrapper;
40220 // xtype created footer. - not sure if will work as we normally have to render first..
40221 if (this.footer && !this.footer.el && this.footer.xtype) {
40223 var ctr = this.grid.getView().getFooterPanel(true);
40224 this.footer.dataSource = this.grid.dataSource;
40225 this.footer = Roo.factory(this.footer, Roo);
40226 this.footer.render(ctr);
40236 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
40237 getId : function(){
40238 return this.grid.id;
40242 * Returns the grid for this panel
40243 * @return {Roo.bootstrap.Table}
40245 getGrid : function(){
40249 setSize : function(width, height){
40250 if(!this.ignoreResize(width, height)){
40251 var grid = this.grid;
40252 var size = this.adjustForComponents(width, height);
40253 // tfoot is not a footer?
40256 var gridel = grid.getGridEl();
40257 gridel.setSize(size.width, size.height);
40259 var tbd = grid.getGridEl().select('tbody', true).first();
40260 var thd = grid.getGridEl().select('thead',true).first();
40261 var tbf= grid.getGridEl().select('tfoot', true).first();
40264 size.height -= tbf.getHeight();
40267 size.height -= thd.getHeight();
40270 tbd.setSize(size.width, size.height );
40271 // this is for the account management tab -seems to work there.
40272 var thd = grid.getGridEl().select('thead',true).first();
40274 // tbd.setSize(size.width, size.height - thd.getHeight());
40283 beforeSlide : function(){
40284 this.grid.getView().scroller.clip();
40287 afterSlide : function(){
40288 this.grid.getView().scroller.unclip();
40291 destroy : function(){
40292 this.grid.destroy();
40294 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
40299 * @class Roo.bootstrap.panel.Nest
40300 * @extends Roo.bootstrap.panel.Content
40302 * Create a new Panel, that can contain a layout.Border.
40305 * @param {Roo.BorderLayout} layout The layout for this panel
40306 * @param {String/Object} config A string to set only the title or a config object
40308 Roo.bootstrap.panel.Nest = function(config)
40310 // construct with only one argument..
40311 /* FIXME - implement nicer consturctors
40312 if (layout.layout) {
40314 layout = config.layout;
40315 delete config.layout;
40317 if (layout.xtype && !layout.getEl) {
40318 // then layout needs constructing..
40319 layout = Roo.factory(layout, Roo);
40323 config.el = config.layout.getEl();
40325 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
40327 config.layout.monitorWindowResize = false; // turn off autosizing
40328 this.layout = config.layout;
40329 this.layout.getEl().addClass("roo-layout-nested-layout");
40330 this.layout.parent = this;
40337 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
40339 setSize : function(width, height){
40340 if(!this.ignoreResize(width, height)){
40341 var size = this.adjustForComponents(width, height);
40342 var el = this.layout.getEl();
40343 if (size.height < 1) {
40344 el.setWidth(size.width);
40346 el.setSize(size.width, size.height);
40348 var touch = el.dom.offsetWidth;
40349 this.layout.layout();
40350 // ie requires a double layout on the first pass
40351 if(Roo.isIE && !this.initialized){
40352 this.initialized = true;
40353 this.layout.layout();
40358 // activate all subpanels if not currently active..
40360 setActiveState : function(active){
40361 this.active = active;
40362 this.setActiveClass(active);
40365 this.fireEvent("deactivate", this);
40369 this.fireEvent("activate", this);
40370 // not sure if this should happen before or after..
40371 if (!this.layout) {
40372 return; // should not happen..
40375 for (var r in this.layout.regions) {
40376 reg = this.layout.getRegion(r);
40377 if (reg.getActivePanel()) {
40378 //reg.showPanel(reg.getActivePanel()); // force it to activate..
40379 reg.setActivePanel(reg.getActivePanel());
40382 if (!reg.panels.length) {
40385 reg.showPanel(reg.getPanel(0));
40394 * Returns the nested BorderLayout for this panel
40395 * @return {Roo.BorderLayout}
40397 getLayout : function(){
40398 return this.layout;
40402 * Adds a xtype elements to the layout of the nested panel
40406 xtype : 'ContentPanel',
40413 xtype : 'NestedLayoutPanel',
40419 items : [ ... list of content panels or nested layout panels.. ]
40423 * @param {Object} cfg Xtype definition of item to add.
40425 addxtype : function(cfg) {
40426 return this.layout.addxtype(cfg);
40431 * Ext JS Library 1.1.1
40432 * Copyright(c) 2006-2007, Ext JS, LLC.
40434 * Originally Released Under LGPL - original licence link has changed is not relivant.
40437 * <script type="text/javascript">
40440 * @class Roo.TabPanel
40441 * @extends Roo.util.Observable
40442 * A lightweight tab container.
40446 // basic tabs 1, built from existing content
40447 var tabs = new Roo.TabPanel("tabs1");
40448 tabs.addTab("script", "View Script");
40449 tabs.addTab("markup", "View Markup");
40450 tabs.activate("script");
40452 // more advanced tabs, built from javascript
40453 var jtabs = new Roo.TabPanel("jtabs");
40454 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
40456 // set up the UpdateManager
40457 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
40458 var updater = tab2.getUpdateManager();
40459 updater.setDefaultUrl("ajax1.htm");
40460 tab2.on('activate', updater.refresh, updater, true);
40462 // Use setUrl for Ajax loading
40463 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
40464 tab3.setUrl("ajax2.htm", null, true);
40467 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
40470 jtabs.activate("jtabs-1");
40473 * Create a new TabPanel.
40474 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
40475 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
40477 Roo.bootstrap.panel.Tabs = function(config){
40479 * The container element for this TabPanel.
40480 * @type Roo.Element
40482 this.el = Roo.get(config.el);
40485 if(typeof config == "boolean"){
40486 this.tabPosition = config ? "bottom" : "top";
40488 Roo.apply(this, config);
40492 if(this.tabPosition == "bottom"){
40493 // if tabs are at the bottom = create the body first.
40494 this.bodyEl = Roo.get(this.createBody(this.el.dom));
40495 this.el.addClass("roo-tabs-bottom");
40497 // next create the tabs holders
40499 if (this.tabPosition == "west"){
40501 var reg = this.region; // fake it..
40503 if (!reg.mgr.parent) {
40506 reg = reg.mgr.parent.region;
40508 Roo.log("got nest?");
40510 if (reg.mgr.getRegion('west')) {
40511 var ctrdom = reg.mgr.getRegion('west').bodyEl.dom;
40512 this.stripWrap = Roo.get(this.createStrip(ctrdom ), true);
40513 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
40514 this.stripEl.setVisibilityMode(Roo.Element.DISPLAY);
40515 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
40523 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
40524 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
40525 this.stripEl.setVisibilityMode(Roo.Element.DISPLAY);
40526 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
40531 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
40534 // finally - if tabs are at the top, then create the body last..
40535 if(this.tabPosition != "bottom"){
40536 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
40537 * @type Roo.Element
40539 this.bodyEl = Roo.get(this.createBody(this.el.dom));
40540 this.el.addClass("roo-tabs-top");
40544 this.bodyEl.setStyle("position", "relative");
40546 this.active = null;
40547 this.activateDelegate = this.activate.createDelegate(this);
40552 * Fires when the active tab changes
40553 * @param {Roo.TabPanel} this
40554 * @param {Roo.TabPanelItem} activePanel The new active tab
40558 * @event beforetabchange
40559 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
40560 * @param {Roo.TabPanel} this
40561 * @param {Object} e Set cancel to true on this object to cancel the tab change
40562 * @param {Roo.TabPanelItem} tab The tab being changed to
40564 "beforetabchange" : true
40567 Roo.EventManager.onWindowResize(this.onResize, this);
40568 this.cpad = this.el.getPadding("lr");
40569 this.hiddenCount = 0;
40572 // toolbar on the tabbar support...
40573 if (this.toolbar) {
40574 alert("no toolbar support yet");
40575 this.toolbar = false;
40577 var tcfg = this.toolbar;
40578 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
40579 this.toolbar = new Roo.Toolbar(tcfg);
40580 if (Roo.isSafari) {
40581 var tbl = tcfg.container.child('table', true);
40582 tbl.setAttribute('width', '100%');
40590 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
40593 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
40595 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
40597 tabPosition : "top",
40599 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
40601 currentTabWidth : 0,
40603 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
40607 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
40611 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
40613 preferredTabWidth : 175,
40615 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
40617 resizeTabs : false,
40619 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
40621 monitorResize : true,
40623 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
40625 toolbar : false, // set by caller..
40627 region : false, /// set by caller
40629 disableTooltips : true, // not used yet...
40632 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
40633 * @param {String} id The id of the div to use <b>or create</b>
40634 * @param {String} text The text for the tab
40635 * @param {String} content (optional) Content to put in the TabPanelItem body
40636 * @param {Boolean} closable (optional) True to create a close icon on the tab
40637 * @return {Roo.TabPanelItem} The created TabPanelItem
40639 addTab : function(id, text, content, closable, tpl)
40641 var item = new Roo.bootstrap.panel.TabItem({
40645 closable : closable,
40648 this.addTabItem(item);
40650 item.setContent(content);
40656 * Returns the {@link Roo.TabPanelItem} with the specified id/index
40657 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
40658 * @return {Roo.TabPanelItem}
40660 getTab : function(id){
40661 return this.items[id];
40665 * Hides the {@link Roo.TabPanelItem} with the specified id/index
40666 * @param {String/Number} id The id or index of the TabPanelItem to hide.
40668 hideTab : function(id){
40669 var t = this.items[id];
40672 this.hiddenCount++;
40673 this.autoSizeTabs();
40678 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
40679 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
40681 unhideTab : function(id){
40682 var t = this.items[id];
40684 t.setHidden(false);
40685 this.hiddenCount--;
40686 this.autoSizeTabs();
40691 * Adds an existing {@link Roo.TabPanelItem}.
40692 * @param {Roo.TabPanelItem} item The TabPanelItem to add
40694 addTabItem : function(item)
40696 this.items[item.id] = item;
40697 this.items.push(item);
40698 this.autoSizeTabs();
40699 // if(this.resizeTabs){
40700 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
40701 // this.autoSizeTabs();
40703 // item.autoSize();
40708 * Removes a {@link Roo.TabPanelItem}.
40709 * @param {String/Number} id The id or index of the TabPanelItem to remove.
40711 removeTab : function(id){
40712 var items = this.items;
40713 var tab = items[id];
40714 if(!tab) { return; }
40715 var index = items.indexOf(tab);
40716 if(this.active == tab && items.length > 1){
40717 var newTab = this.getNextAvailable(index);
40722 this.stripEl.dom.removeChild(tab.pnode.dom);
40723 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
40724 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
40726 items.splice(index, 1);
40727 delete this.items[tab.id];
40728 tab.fireEvent("close", tab);
40729 tab.purgeListeners();
40730 this.autoSizeTabs();
40733 getNextAvailable : function(start){
40734 var items = this.items;
40736 // look for a next tab that will slide over to
40737 // replace the one being removed
40738 while(index < items.length){
40739 var item = items[++index];
40740 if(item && !item.isHidden()){
40744 // if one isn't found select the previous tab (on the left)
40747 var item = items[--index];
40748 if(item && !item.isHidden()){
40756 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
40757 * @param {String/Number} id The id or index of the TabPanelItem to disable.
40759 disableTab : function(id){
40760 var tab = this.items[id];
40761 if(tab && this.active != tab){
40767 * Enables a {@link Roo.TabPanelItem} that is disabled.
40768 * @param {String/Number} id The id or index of the TabPanelItem to enable.
40770 enableTab : function(id){
40771 var tab = this.items[id];
40776 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
40777 * @param {String/Number} id The id or index of the TabPanelItem to activate.
40778 * @return {Roo.TabPanelItem} The TabPanelItem.
40780 activate : function(id)
40782 //Roo.log('activite:' + id);
40784 var tab = this.items[id];
40788 if(tab == this.active || tab.disabled){
40792 this.fireEvent("beforetabchange", this, e, tab);
40793 if(e.cancel !== true && !tab.disabled){
40795 this.active.hide();
40797 this.active = this.items[id];
40798 this.active.show();
40799 this.fireEvent("tabchange", this, this.active);
40805 * Gets the active {@link Roo.TabPanelItem}.
40806 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
40808 getActiveTab : function(){
40809 return this.active;
40813 * Updates the tab body element to fit the height of the container element
40814 * for overflow scrolling
40815 * @param {Number} targetHeight (optional) Override the starting height from the elements height
40817 syncHeight : function(targetHeight){
40818 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
40819 var bm = this.bodyEl.getMargins();
40820 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
40821 this.bodyEl.setHeight(newHeight);
40825 onResize : function(){
40826 if(this.monitorResize){
40827 this.autoSizeTabs();
40832 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
40834 beginUpdate : function(){
40835 this.updating = true;
40839 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
40841 endUpdate : function(){
40842 this.updating = false;
40843 this.autoSizeTabs();
40847 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
40849 autoSizeTabs : function()
40851 var count = this.items.length;
40852 var vcount = count - this.hiddenCount;
40855 this.stripEl.hide();
40857 this.stripEl.show();
40860 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
40865 var w = Math.max(this.el.getWidth() - this.cpad, 10);
40866 var availWidth = Math.floor(w / vcount);
40867 var b = this.stripBody;
40868 if(b.getWidth() > w){
40869 var tabs = this.items;
40870 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
40871 if(availWidth < this.minTabWidth){
40872 /*if(!this.sleft){ // incomplete scrolling code
40873 this.createScrollButtons();
40876 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
40879 if(this.currentTabWidth < this.preferredTabWidth){
40880 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
40886 * Returns the number of tabs in this TabPanel.
40889 getCount : function(){
40890 return this.items.length;
40894 * Resizes all the tabs to the passed width
40895 * @param {Number} The new width
40897 setTabWidth : function(width){
40898 this.currentTabWidth = width;
40899 for(var i = 0, len = this.items.length; i < len; i++) {
40900 if(!this.items[i].isHidden()) {
40901 this.items[i].setWidth(width);
40907 * Destroys this TabPanel
40908 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
40910 destroy : function(removeEl){
40911 Roo.EventManager.removeResizeListener(this.onResize, this);
40912 for(var i = 0, len = this.items.length; i < len; i++){
40913 this.items[i].purgeListeners();
40915 if(removeEl === true){
40916 this.el.update("");
40921 createStrip : function(container)
40923 var strip = document.createElement("nav");
40924 strip.className = Roo.bootstrap.version == 4 ?
40925 "navbar-light bg-light" :
40926 "navbar navbar-default"; //"x-tabs-wrap";
40927 container.appendChild(strip);
40931 createStripList : function(strip)
40933 // div wrapper for retard IE
40934 // returns the "tr" element.
40935 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
40936 //'<div class="x-tabs-strip-wrap">'+
40937 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
40938 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
40939 return strip.firstChild; //.firstChild.firstChild.firstChild;
40941 createBody : function(container)
40943 var body = document.createElement("div");
40944 Roo.id(body, "tab-body");
40945 //Roo.fly(body).addClass("x-tabs-body");
40946 Roo.fly(body).addClass("tab-content");
40947 container.appendChild(body);
40950 createItemBody :function(bodyEl, id){
40951 var body = Roo.getDom(id);
40953 body = document.createElement("div");
40956 //Roo.fly(body).addClass("x-tabs-item-body");
40957 Roo.fly(body).addClass("tab-pane");
40958 bodyEl.insertBefore(body, bodyEl.firstChild);
40962 createStripElements : function(stripEl, text, closable, tpl)
40964 var td = document.createElement("li"); // was td..
40965 td.className = 'nav-item';
40967 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
40970 stripEl.appendChild(td);
40972 td.className = "x-tabs-closable";
40973 if(!this.closeTpl){
40974 this.closeTpl = new Roo.Template(
40975 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
40976 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
40977 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
40980 var el = this.closeTpl.overwrite(td, {"text": text});
40981 var close = el.getElementsByTagName("div")[0];
40982 var inner = el.getElementsByTagName("em")[0];
40983 return {"el": el, "close": close, "inner": inner};
40986 // not sure what this is..
40987 // if(!this.tabTpl){
40988 //this.tabTpl = new Roo.Template(
40989 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
40990 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
40992 // this.tabTpl = new Roo.Template(
40993 // '<a href="#">' +
40994 // '<span unselectable="on"' +
40995 // (this.disableTooltips ? '' : ' title="{text}"') +
40996 // ' >{text}</span></a>'
41002 var template = tpl || this.tabTpl || false;
41005 template = new Roo.Template(
41006 Roo.bootstrap.version == 4 ?
41008 '<a class="nav-link" href="#" unselectable="on"' +
41009 (this.disableTooltips ? '' : ' title="{text}"') +
41012 '<a class="nav-link" href="#">' +
41013 '<span unselectable="on"' +
41014 (this.disableTooltips ? '' : ' title="{text}"') +
41015 ' >{text}</span></a>'
41020 switch (typeof(template)) {
41024 template = new Roo.Template(template);
41030 var el = template.overwrite(td, {"text": text});
41032 var inner = el.getElementsByTagName("span")[0];
41034 return {"el": el, "inner": inner};
41042 * @class Roo.TabPanelItem
41043 * @extends Roo.util.Observable
41044 * Represents an individual item (tab plus body) in a TabPanel.
41045 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
41046 * @param {String} id The id of this TabPanelItem
41047 * @param {String} text The text for the tab of this TabPanelItem
41048 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
41050 Roo.bootstrap.panel.TabItem = function(config){
41052 * The {@link Roo.TabPanel} this TabPanelItem belongs to
41053 * @type Roo.TabPanel
41055 this.tabPanel = config.panel;
41057 * The id for this TabPanelItem
41060 this.id = config.id;
41062 this.disabled = false;
41064 this.text = config.text;
41066 this.loaded = false;
41067 this.closable = config.closable;
41070 * The body element for this TabPanelItem.
41071 * @type Roo.Element
41073 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
41074 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
41075 this.bodyEl.setStyle("display", "block");
41076 this.bodyEl.setStyle("zoom", "1");
41077 //this.hideAction();
41079 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
41081 this.el = Roo.get(els.el);
41082 this.inner = Roo.get(els.inner, true);
41083 this.textEl = Roo.bootstrap.version == 4 ?
41084 this.el : Roo.get(this.el.dom.firstChild, true);
41086 this.pnode = this.linode = Roo.get(els.el.parentNode, true);
41087 this.status_node = Roo.bootstrap.version == 4 ? this.el : this.linode;
41090 // this.el.on("mousedown", this.onTabMouseDown, this);
41091 this.el.on("click", this.onTabClick, this);
41093 if(config.closable){
41094 var c = Roo.get(els.close, true);
41095 c.dom.title = this.closeText;
41096 c.addClassOnOver("close-over");
41097 c.on("click", this.closeClick, this);
41103 * Fires when this tab becomes the active tab.
41104 * @param {Roo.TabPanel} tabPanel The parent TabPanel
41105 * @param {Roo.TabPanelItem} this
41109 * @event beforeclose
41110 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
41111 * @param {Roo.TabPanelItem} this
41112 * @param {Object} e Set cancel to true on this object to cancel the close.
41114 "beforeclose": true,
41117 * Fires when this tab is closed.
41118 * @param {Roo.TabPanelItem} this
41122 * @event deactivate
41123 * Fires when this tab is no longer the active tab.
41124 * @param {Roo.TabPanel} tabPanel The parent TabPanel
41125 * @param {Roo.TabPanelItem} this
41127 "deactivate" : true
41129 this.hidden = false;
41131 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
41134 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
41136 purgeListeners : function(){
41137 Roo.util.Observable.prototype.purgeListeners.call(this);
41138 this.el.removeAllListeners();
41141 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
41144 this.status_node.addClass("active");
41147 this.tabPanel.stripWrap.repaint();
41149 this.fireEvent("activate", this.tabPanel, this);
41153 * Returns true if this tab is the active tab.
41154 * @return {Boolean}
41156 isActive : function(){
41157 return this.tabPanel.getActiveTab() == this;
41161 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
41164 this.status_node.removeClass("active");
41166 this.fireEvent("deactivate", this.tabPanel, this);
41169 hideAction : function(){
41170 this.bodyEl.hide();
41171 this.bodyEl.setStyle("position", "absolute");
41172 this.bodyEl.setLeft("-20000px");
41173 this.bodyEl.setTop("-20000px");
41176 showAction : function(){
41177 this.bodyEl.setStyle("position", "relative");
41178 this.bodyEl.setTop("");
41179 this.bodyEl.setLeft("");
41180 this.bodyEl.show();
41184 * Set the tooltip for the tab.
41185 * @param {String} tooltip The tab's tooltip
41187 setTooltip : function(text){
41188 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
41189 this.textEl.dom.qtip = text;
41190 this.textEl.dom.removeAttribute('title');
41192 this.textEl.dom.title = text;
41196 onTabClick : function(e){
41197 e.preventDefault();
41198 this.tabPanel.activate(this.id);
41201 onTabMouseDown : function(e){
41202 e.preventDefault();
41203 this.tabPanel.activate(this.id);
41206 getWidth : function(){
41207 return this.inner.getWidth();
41210 setWidth : function(width){
41211 var iwidth = width - this.linode.getPadding("lr");
41212 this.inner.setWidth(iwidth);
41213 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
41214 this.linode.setWidth(width);
41218 * Show or hide the tab
41219 * @param {Boolean} hidden True to hide or false to show.
41221 setHidden : function(hidden){
41222 this.hidden = hidden;
41223 this.linode.setStyle("display", hidden ? "none" : "");
41227 * Returns true if this tab is "hidden"
41228 * @return {Boolean}
41230 isHidden : function(){
41231 return this.hidden;
41235 * Returns the text for this tab
41238 getText : function(){
41242 autoSize : function(){
41243 //this.el.beginMeasure();
41244 this.textEl.setWidth(1);
41246 * #2804 [new] Tabs in Roojs
41247 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
41249 //this.setWidth(this.textEl.dom.scrollWidth+this.linode.getPadding("lr")+this.inner.getPadding("lr") + 2);
41250 //this.el.endMeasure();
41254 * Sets the text for the tab (Note: this also sets the tooltip text)
41255 * @param {String} text The tab's text and tooltip
41257 setText : function(text){
41259 this.textEl.update(text);
41260 this.setTooltip(text);
41261 //if(!this.tabPanel.resizeTabs){
41262 // this.autoSize();
41266 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
41268 activate : function(){
41269 this.tabPanel.activate(this.id);
41273 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
41275 disable : function(){
41276 if(this.tabPanel.active != this){
41277 this.disabled = true;
41278 this.status_node.addClass("disabled");
41283 * Enables this TabPanelItem if it was previously disabled.
41285 enable : function(){
41286 this.disabled = false;
41287 this.status_node.removeClass("disabled");
41291 * Sets the content for this TabPanelItem.
41292 * @param {String} content The content
41293 * @param {Boolean} loadScripts true to look for and load scripts
41295 setContent : function(content, loadScripts){
41296 this.bodyEl.update(content, loadScripts);
41300 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
41301 * @return {Roo.UpdateManager} The UpdateManager
41303 getUpdateManager : function(){
41304 return this.bodyEl.getUpdateManager();
41308 * Set a URL to be used to load the content for this TabPanelItem.
41309 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
41310 * @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)
41311 * @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)
41312 * @return {Roo.UpdateManager} The UpdateManager
41314 setUrl : function(url, params, loadOnce){
41315 if(this.refreshDelegate){
41316 this.un('activate', this.refreshDelegate);
41318 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
41319 this.on("activate", this.refreshDelegate);
41320 return this.bodyEl.getUpdateManager();
41324 _handleRefresh : function(url, params, loadOnce){
41325 if(!loadOnce || !this.loaded){
41326 var updater = this.bodyEl.getUpdateManager();
41327 updater.update(url, params, this._setLoaded.createDelegate(this));
41332 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
41333 * Will fail silently if the setUrl method has not been called.
41334 * This does not activate the panel, just updates its content.
41336 refresh : function(){
41337 if(this.refreshDelegate){
41338 this.loaded = false;
41339 this.refreshDelegate();
41344 _setLoaded : function(){
41345 this.loaded = true;
41349 closeClick : function(e){
41352 this.fireEvent("beforeclose", this, o);
41353 if(o.cancel !== true){
41354 this.tabPanel.removeTab(this.id);
41358 * The text displayed in the tooltip for the close icon.
41361 closeText : "Close this tab"
41364 * This script refer to:
41365 * Title: International Telephone Input
41366 * Author: Jack O'Connor
41367 * Code version: v12.1.12
41368 * Availability: https://github.com/jackocnr/intl-tel-input.git
41371 Roo.bootstrap.PhoneInputData = function() {
41374 "Afghanistan (افغانستان)",
41379 "Albania (Shqipëri)",
41384 "Algeria (الجزائر)",
41409 "Antigua and Barbuda",
41419 "Armenia (Հայաստան)",
41435 "Austria (Österreich)",
41440 "Azerbaijan (Azərbaycan)",
41450 "Bahrain (البحرين)",
41455 "Bangladesh (বাংলাদেশ)",
41465 "Belarus (Беларусь)",
41470 "Belgium (België)",
41500 "Bosnia and Herzegovina (Босна и Херцеговина)",
41515 "British Indian Ocean Territory",
41520 "British Virgin Islands",
41530 "Bulgaria (България)",
41540 "Burundi (Uburundi)",
41545 "Cambodia (កម្ពុជា)",
41550 "Cameroon (Cameroun)",
41559 ["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"]
41562 "Cape Verde (Kabu Verdi)",
41567 "Caribbean Netherlands",
41578 "Central African Republic (République centrafricaine)",
41598 "Christmas Island",
41604 "Cocos (Keeling) Islands",
41615 "Comoros (جزر القمر)",
41620 "Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)",
41625 "Congo (Republic) (Congo-Brazzaville)",
41645 "Croatia (Hrvatska)",
41666 "Czech Republic (Česká republika)",
41671 "Denmark (Danmark)",
41686 "Dominican Republic (República Dominicana)",
41690 ["809", "829", "849"]
41708 "Equatorial Guinea (Guinea Ecuatorial)",
41728 "Falkland Islands (Islas Malvinas)",
41733 "Faroe Islands (Føroyar)",
41754 "French Guiana (Guyane française)",
41759 "French Polynesia (Polynésie française)",
41774 "Georgia (საქართველო)",
41779 "Germany (Deutschland)",
41799 "Greenland (Kalaallit Nunaat)",
41836 "Guinea-Bissau (Guiné Bissau)",
41861 "Hungary (Magyarország)",
41866 "Iceland (Ísland)",
41886 "Iraq (العراق)",
41902 "Israel (ישראל)",
41929 "Jordan (الأردن)",
41934 "Kazakhstan (Казахстан)",
41955 "Kuwait (الكويت)",
41960 "Kyrgyzstan (Кыргызстан)",
41970 "Latvia (Latvija)",
41975 "Lebanon (لبنان)",
41990 "Libya (ليبيا)",
42000 "Lithuania (Lietuva)",
42015 "Macedonia (FYROM) (Македонија)",
42020 "Madagascar (Madagasikara)",
42050 "Marshall Islands",
42060 "Mauritania (موريتانيا)",
42065 "Mauritius (Moris)",
42086 "Moldova (Republica Moldova)",
42096 "Mongolia (Монгол)",
42101 "Montenegro (Crna Gora)",
42111 "Morocco (المغرب)",
42117 "Mozambique (Moçambique)",
42122 "Myanmar (Burma) (မြန်မာ)",
42127 "Namibia (Namibië)",
42142 "Netherlands (Nederland)",
42147 "New Caledonia (Nouvelle-Calédonie)",
42182 "North Korea (조선 민주주의 인민 공화국)",
42187 "Northern Mariana Islands",
42203 "Pakistan (پاکستان)",
42213 "Palestine (فلسطين)",
42223 "Papua New Guinea",
42265 "Réunion (La Réunion)",
42271 "Romania (România)",
42287 "Saint Barthélemy",
42298 "Saint Kitts and Nevis",
42308 "Saint Martin (Saint-Martin (partie française))",
42314 "Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)",
42319 "Saint Vincent and the Grenadines",
42334 "São Tomé and Príncipe (São Tomé e Príncipe)",
42339 "Saudi Arabia (المملكة العربية السعودية)",
42344 "Senegal (Sénégal)",
42374 "Slovakia (Slovensko)",
42379 "Slovenia (Slovenija)",
42389 "Somalia (Soomaaliya)",
42399 "South Korea (대한민국)",
42404 "South Sudan (جنوب السودان)",
42414 "Sri Lanka (ශ්රී ලංකාව)",
42419 "Sudan (السودان)",
42429 "Svalbard and Jan Mayen",
42440 "Sweden (Sverige)",
42445 "Switzerland (Schweiz)",
42450 "Syria (سوريا)",
42495 "Trinidad and Tobago",
42500 "Tunisia (تونس)",
42505 "Turkey (Türkiye)",
42515 "Turks and Caicos Islands",
42525 "U.S. Virgin Islands",
42535 "Ukraine (Україна)",
42540 "United Arab Emirates (الإمارات العربية المتحدة)",
42562 "Uzbekistan (Oʻzbekiston)",
42572 "Vatican City (Città del Vaticano)",
42583 "Vietnam (Việt Nam)",
42588 "Wallis and Futuna (Wallis-et-Futuna)",
42593 "Western Sahara (الصحراء الغربية)",
42599 "Yemen (اليمن)",
42623 * This script refer to:
42624 * Title: International Telephone Input
42625 * Author: Jack O'Connor
42626 * Code version: v12.1.12
42627 * Availability: https://github.com/jackocnr/intl-tel-input.git
42631 * @class Roo.bootstrap.PhoneInput
42632 * @extends Roo.bootstrap.TriggerField
42633 * An input with International dial-code selection
42635 * @cfg {String} defaultDialCode default '+852'
42636 * @cfg {Array} preferedCountries default []
42639 * Create a new PhoneInput.
42640 * @param {Object} config Configuration options
42643 Roo.bootstrap.PhoneInput = function(config) {
42644 Roo.bootstrap.PhoneInput.superclass.constructor.call(this, config);
42647 Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
42649 listWidth: undefined,
42651 selectedClass: 'active',
42653 invalidClass : "has-warning",
42655 validClass: 'has-success',
42657 allowed: '0123456789',
42662 * @cfg {String} defaultDialCode The default dial code when initializing the input
42664 defaultDialCode: '+852',
42667 * @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
42669 preferedCountries: false,
42671 getAutoCreate : function()
42673 var data = Roo.bootstrap.PhoneInputData();
42674 var align = this.labelAlign || this.parentLabelAlign();
42677 this.allCountries = [];
42678 this.dialCodeMapping = [];
42680 for (var i = 0; i < data.length; i++) {
42682 this.allCountries[i] = {
42686 priority: c[3] || 0,
42687 areaCodes: c[4] || null
42689 this.dialCodeMapping[c[2]] = {
42692 priority: c[3] || 0,
42693 areaCodes: c[4] || null
42705 // type: 'number', -- do not use number - we get the flaky up/down arrows.
42706 maxlength: this.max_length,
42707 cls : 'form-control tel-input',
42708 autocomplete: 'new-password'
42711 var hiddenInput = {
42714 cls: 'hidden-tel-input'
42718 hiddenInput.name = this.name;
42721 if (this.disabled) {
42722 input.disabled = true;
42725 var flag_container = {
42742 cls: this.hasFeedback ? 'has-feedback' : '',
42748 cls: 'dial-code-holder',
42755 cls: 'roo-select2-container input-group',
42762 if (this.fieldLabel.length) {
42765 tooltip: 'This field is required'
42771 cls: 'control-label',
42777 html: this.fieldLabel
42780 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
42786 if(this.indicatorpos == 'right') {
42787 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
42794 if(align == 'left') {
42802 if(this.labelWidth > 12){
42803 label.style = "width: " + this.labelWidth + 'px';
42805 if(this.labelWidth < 13 && this.labelmd == 0){
42806 this.labelmd = this.labelWidth;
42808 if(this.labellg > 0){
42809 label.cls += ' col-lg-' + this.labellg;
42810 input.cls += ' col-lg-' + (12 - this.labellg);
42812 if(this.labelmd > 0){
42813 label.cls += ' col-md-' + this.labelmd;
42814 container.cls += ' col-md-' + (12 - this.labelmd);
42816 if(this.labelsm > 0){
42817 label.cls += ' col-sm-' + this.labelsm;
42818 container.cls += ' col-sm-' + (12 - this.labelsm);
42820 if(this.labelxs > 0){
42821 label.cls += ' col-xs-' + this.labelxs;
42822 container.cls += ' col-xs-' + (12 - this.labelxs);
42832 var settings = this;
42834 ['xs','sm','md','lg'].map(function(size){
42835 if (settings[size]) {
42836 cfg.cls += ' col-' + size + '-' + settings[size];
42840 this.store = new Roo.data.Store({
42841 proxy : new Roo.data.MemoryProxy({}),
42842 reader : new Roo.data.JsonReader({
42853 'name' : 'dialCode',
42857 'name' : 'priority',
42861 'name' : 'areaCodes',
42868 if(!this.preferedCountries) {
42869 this.preferedCountries = [
42876 var p = this.preferedCountries.reverse();
42879 for (var i = 0; i < p.length; i++) {
42880 for (var j = 0; j < this.allCountries.length; j++) {
42881 if(this.allCountries[j].iso2 == p[i]) {
42882 var t = this.allCountries[j];
42883 this.allCountries.splice(j,1);
42884 this.allCountries.unshift(t);
42890 this.store.proxy.data = {
42892 data: this.allCountries
42898 initEvents : function()
42901 Roo.bootstrap.PhoneInput.superclass.initEvents.call(this);
42903 this.indicator = this.indicatorEl();
42904 this.flag = this.flagEl();
42905 this.dialCodeHolder = this.dialCodeHolderEl();
42907 this.trigger = this.el.select('div.flag-box',true).first();
42908 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
42913 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
42914 _this.list.setWidth(lw);
42917 this.list.on('mouseover', this.onViewOver, this);
42918 this.list.on('mousemove', this.onViewMove, this);
42919 this.inputEl().on("keyup", this.onKeyUp, this);
42920 this.inputEl().on("keypress", this.onKeyPress, this);
42922 this.tpl = '<li><a href="#"><div class="flag {iso2}"></div>{name} <span class="dial-code">+{dialCode}</span></a></li>';
42924 this.view = new Roo.View(this.list, this.tpl, {
42925 singleSelect:true, store: this.store, selectedClass: this.selectedClass
42928 this.view.on('click', this.onViewClick, this);
42929 this.setValue(this.defaultDialCode);
42932 onTriggerClick : function(e)
42934 Roo.log('trigger click');
42939 if(this.isExpanded()){
42941 this.hasFocus = false;
42943 this.store.load({});
42944 this.hasFocus = true;
42949 isExpanded : function()
42951 return this.list.isVisible();
42954 collapse : function()
42956 if(!this.isExpanded()){
42960 Roo.get(document).un('mousedown', this.collapseIf, this);
42961 Roo.get(document).un('mousewheel', this.collapseIf, this);
42962 this.fireEvent('collapse', this);
42966 expand : function()
42970 if(this.isExpanded() || !this.hasFocus){
42974 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
42975 this.list.setWidth(lw);
42978 this.restrictHeight();
42980 Roo.get(document).on('mousedown', this.collapseIf, this);
42981 Roo.get(document).on('mousewheel', this.collapseIf, this);
42983 this.fireEvent('expand', this);
42986 restrictHeight : function()
42988 this.list.alignTo(this.inputEl(), this.listAlign);
42989 this.list.alignTo(this.inputEl(), this.listAlign);
42992 onViewOver : function(e, t)
42994 if(this.inKeyMode){
42997 var item = this.view.findItemFromChild(t);
43000 var index = this.view.indexOf(item);
43001 this.select(index, false);
43006 onViewClick : function(view, doFocus, el, e)
43008 var index = this.view.getSelectedIndexes()[0];
43010 var r = this.store.getAt(index);
43013 this.onSelect(r, index);
43015 if(doFocus !== false && !this.blockFocus){
43016 this.inputEl().focus();
43020 onViewMove : function(e, t)
43022 this.inKeyMode = false;
43025 select : function(index, scrollIntoView)
43027 this.selectedIndex = index;
43028 this.view.select(index);
43029 if(scrollIntoView !== false){
43030 var el = this.view.getNode(index);
43032 this.list.scrollChildIntoView(el, false);
43037 createList : function()
43039 this.list = Roo.get(document.body).createChild({
43041 cls: 'typeahead typeahead-long dropdown-menu tel-list',
43042 style: 'display:none'
43045 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
43048 collapseIf : function(e)
43050 var in_combo = e.within(this.el);
43051 var in_list = e.within(this.list);
43052 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
43054 if (in_combo || in_list || is_list) {
43060 onSelect : function(record, index)
43062 if(this.fireEvent('beforeselect', this, record, index) !== false){
43064 this.setFlagClass(record.data.iso2);
43065 this.setDialCode(record.data.dialCode);
43066 this.hasFocus = false;
43068 this.fireEvent('select', this, record, index);
43072 flagEl : function()
43074 var flag = this.el.select('div.flag',true).first();
43081 dialCodeHolderEl : function()
43083 var d = this.el.select('input.dial-code-holder',true).first();
43090 setDialCode : function(v)
43092 this.dialCodeHolder.dom.value = '+'+v;
43095 setFlagClass : function(n)
43097 this.flag.dom.className = 'flag '+n;
43100 getValue : function()
43102 var v = this.inputEl().getValue();
43103 if(this.dialCodeHolder) {
43104 v = this.dialCodeHolder.dom.value+this.inputEl().getValue();
43109 setValue : function(v)
43111 var d = this.getDialCode(v);
43113 //invalid dial code
43114 if(v.length == 0 || !d || d.length == 0) {
43116 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
43117 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
43123 this.setFlagClass(this.dialCodeMapping[d].iso2);
43124 this.setDialCode(d);
43125 this.inputEl().dom.value = v.replace('+'+d,'');
43126 this.hiddenEl().dom.value = this.getValue();
43131 getDialCode : function(v)
43135 if (v.length == 0) {
43136 return this.dialCodeHolder.dom.value;
43140 if (v.charAt(0) != "+") {
43143 var numericChars = "";
43144 for (var i = 1; i < v.length; i++) {
43145 var c = v.charAt(i);
43148 if (this.dialCodeMapping[numericChars]) {
43149 dialCode = v.substr(1, i);
43151 if (numericChars.length == 4) {
43161 this.setValue(this.defaultDialCode);
43165 hiddenEl : function()
43167 return this.el.select('input.hidden-tel-input',true).first();
43170 // after setting val
43171 onKeyUp : function(e){
43172 this.setValue(this.getValue());
43175 onKeyPress : function(e){
43176 if(this.allowed.indexOf(String.fromCharCode(e.getCharCode())) === -1){
43183 * @class Roo.bootstrap.MoneyField
43184 * @extends Roo.bootstrap.ComboBox
43185 * Bootstrap MoneyField class
43188 * Create a new MoneyField.
43189 * @param {Object} config Configuration options
43192 Roo.bootstrap.MoneyField = function(config) {
43194 Roo.bootstrap.MoneyField.superclass.constructor.call(this, config);
43198 Roo.extend(Roo.bootstrap.MoneyField, Roo.bootstrap.ComboBox, {
43201 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
43203 allowDecimals : true,
43205 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
43207 decimalSeparator : ".",
43209 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
43211 decimalPrecision : 0,
43213 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
43215 allowNegative : true,
43217 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
43221 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
43223 minValue : Number.NEGATIVE_INFINITY,
43225 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
43227 maxValue : Number.MAX_VALUE,
43229 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
43231 minText : "The minimum value for this field is {0}",
43233 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
43235 maxText : "The maximum value for this field is {0}",
43237 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
43238 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
43240 nanText : "{0} is not a valid number",
43242 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
43246 * @cfg {String} defaults currency of the MoneyField
43247 * value should be in lkey
43249 defaultCurrency : false,
43251 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
43253 thousandsDelimiter : false,
43255 * @cfg {Number} max_length Maximum input field length allowed (defaults to Number.MAX_VALUE)
43266 getAutoCreate : function()
43268 var align = this.labelAlign || this.parentLabelAlign();
43280 cls : 'form-control roo-money-amount-input',
43281 autocomplete: 'new-password'
43284 var hiddenInput = {
43288 cls: 'hidden-number-input'
43291 if(this.max_length) {
43292 input.maxlength = this.max_length;
43296 hiddenInput.name = this.name;
43299 if (this.disabled) {
43300 input.disabled = true;
43303 var clg = 12 - this.inputlg;
43304 var cmd = 12 - this.inputmd;
43305 var csm = 12 - this.inputsm;
43306 var cxs = 12 - this.inputxs;
43310 cls : 'row roo-money-field',
43314 cls : 'roo-money-currency column col-lg-' + clg + ' col-md-' + cmd + ' col-sm-' + csm + ' col-xs-' + cxs,
43318 cls: 'roo-select2-container input-group',
43322 cls : 'form-control roo-money-currency-input',
43323 autocomplete: 'new-password',
43325 name : this.currencyName
43329 cls : 'input-group-addon',
43343 cls : 'roo-money-amount column col-lg-' + this.inputlg + ' col-md-' + this.inputmd + ' col-sm-' + this.inputsm + ' col-xs-' + this.inputxs,
43347 cls: this.hasFeedback ? 'has-feedback' : '',
43358 if (this.fieldLabel.length) {
43361 tooltip: 'This field is required'
43367 cls: 'control-label',
43373 html: this.fieldLabel
43376 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
43382 if(this.indicatorpos == 'right') {
43383 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
43390 if(align == 'left') {
43398 if(this.labelWidth > 12){
43399 label.style = "width: " + this.labelWidth + 'px';
43401 if(this.labelWidth < 13 && this.labelmd == 0){
43402 this.labelmd = this.labelWidth;
43404 if(this.labellg > 0){
43405 label.cls += ' col-lg-' + this.labellg;
43406 input.cls += ' col-lg-' + (12 - this.labellg);
43408 if(this.labelmd > 0){
43409 label.cls += ' col-md-' + this.labelmd;
43410 container.cls += ' col-md-' + (12 - this.labelmd);
43412 if(this.labelsm > 0){
43413 label.cls += ' col-sm-' + this.labelsm;
43414 container.cls += ' col-sm-' + (12 - this.labelsm);
43416 if(this.labelxs > 0){
43417 label.cls += ' col-xs-' + this.labelxs;
43418 container.cls += ' col-xs-' + (12 - this.labelxs);
43429 var settings = this;
43431 ['xs','sm','md','lg'].map(function(size){
43432 if (settings[size]) {
43433 cfg.cls += ' col-' + size + '-' + settings[size];
43440 initEvents : function()
43442 this.indicator = this.indicatorEl();
43444 this.initCurrencyEvent();
43446 this.initNumberEvent();
43449 initCurrencyEvent : function()
43452 throw "can not find store for combo";
43455 this.store = Roo.factory(this.store, Roo.data);
43456 this.store.parent = this;
43460 this.triggerEl = this.el.select('.input-group-addon', true).first();
43462 this.triggerEl.on("click", this.onTriggerClick, this, { preventDefault : true });
43467 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
43468 _this.list.setWidth(lw);
43471 this.list.on('mouseover', this.onViewOver, this);
43472 this.list.on('mousemove', this.onViewMove, this);
43473 this.list.on('scroll', this.onViewScroll, this);
43476 this.tpl = '<li><a href="#">{' + this.currencyField + '}</a></li>';
43479 this.view = new Roo.View(this.list, this.tpl, {
43480 singleSelect:true, store: this.store, selectedClass: this.selectedClass
43483 this.view.on('click', this.onViewClick, this);
43485 this.store.on('beforeload', this.onBeforeLoad, this);
43486 this.store.on('load', this.onLoad, this);
43487 this.store.on('loadexception', this.onLoadException, this);
43489 this.keyNav = new Roo.KeyNav(this.currencyEl(), {
43490 "up" : function(e){
43491 this.inKeyMode = true;
43495 "down" : function(e){
43496 if(!this.isExpanded()){
43497 this.onTriggerClick();
43499 this.inKeyMode = true;
43504 "enter" : function(e){
43507 if(this.fireEvent("specialkey", this, e)){
43508 this.onViewClick(false);
43514 "esc" : function(e){
43518 "tab" : function(e){
43521 if(this.fireEvent("specialkey", this, e)){
43522 this.onViewClick(false);
43530 doRelay : function(foo, bar, hname){
43531 if(hname == 'down' || this.scope.isExpanded()){
43532 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
43540 this.currencyEl().on("click", this.onTriggerClick, this, { preventDefault : true });
43544 initNumberEvent : function(e)
43546 this.inputEl().on("keydown" , this.fireKey, this);
43547 this.inputEl().on("focus", this.onFocus, this);
43548 this.inputEl().on("blur", this.onBlur, this);
43550 this.inputEl().relayEvent('keyup', this);
43552 if(this.indicator){
43553 this.indicator.addClass('invisible');
43556 this.originalValue = this.getValue();
43558 if(this.validationEvent == 'keyup'){
43559 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
43560 this.inputEl().on('keyup', this.filterValidation, this);
43562 else if(this.validationEvent !== false){
43563 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
43566 if(this.selectOnFocus){
43567 this.on("focus", this.preFocus, this);
43570 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
43571 this.inputEl().on("keypress", this.filterKeys, this);
43573 this.inputEl().relayEvent('keypress', this);
43576 var allowed = "0123456789";
43578 if(this.allowDecimals){
43579 allowed += this.decimalSeparator;
43582 if(this.allowNegative){
43586 if(this.thousandsDelimiter) {
43590 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
43592 var keyPress = function(e){
43594 var k = e.getKey();
43596 var c = e.getCharCode();
43599 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
43600 allowed.indexOf(String.fromCharCode(c)) === -1
43606 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
43610 if(allowed.indexOf(String.fromCharCode(c)) === -1){
43615 this.inputEl().on("keypress", keyPress, this);
43619 onTriggerClick : function(e)
43626 this.loadNext = false;
43628 if(this.isExpanded()){
43633 this.hasFocus = true;
43635 if(this.triggerAction == 'all') {
43636 this.doQuery(this.allQuery, true);
43640 this.doQuery(this.getRawValue());
43643 getCurrency : function()
43645 var v = this.currencyEl().getValue();
43650 restrictHeight : function()
43652 this.list.alignTo(this.currencyEl(), this.listAlign);
43653 this.list.alignTo(this.currencyEl(), this.listAlign);
43656 onViewClick : function(view, doFocus, el, e)
43658 var index = this.view.getSelectedIndexes()[0];
43660 var r = this.store.getAt(index);
43663 this.onSelect(r, index);
43667 onSelect : function(record, index){
43669 if(this.fireEvent('beforeselect', this, record, index) !== false){
43671 this.setFromCurrencyData(index > -1 ? record.data : false);
43675 this.fireEvent('select', this, record, index);
43679 setFromCurrencyData : function(o)
43683 this.lastCurrency = o;
43685 if (this.currencyField) {
43686 currency = !o || typeof(o[this.currencyField]) == 'undefined' ? '' : o[this.currencyField];
43688 Roo.log('no currencyField value set for '+ (this.name ? this.name : this.id));
43691 this.lastSelectionText = currency;
43693 //setting default currency
43694 if(o[this.currencyField] * 1 == 0 && this.defaultCurrency) {
43695 this.setCurrency(this.defaultCurrency);
43699 this.setCurrency(currency);
43702 setFromData : function(o)
43706 c[this.currencyField] = !o || typeof(o[this.currencyName]) == 'undefined' ? '' : o[this.currencyName];
43708 this.setFromCurrencyData(c);
43713 value = !o || typeof(o[this.name]) == 'undefined' ? '' : o[this.name];
43715 Roo.log('no value set for '+ (this.name ? this.name : this.id));
43718 this.setValue(value);
43722 setCurrency : function(v)
43724 this.currencyValue = v;
43727 this.currencyEl().dom.value = (v === null || v === undefined ? '' : v);
43732 setValue : function(v)
43734 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
43740 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
43742 this.inputEl().dom.value = (v == '') ? '' :
43743 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
43745 if(!this.allowZero && v === '0') {
43746 this.hiddenEl().dom.value = '';
43747 this.inputEl().dom.value = '';
43754 getRawValue : function()
43756 var v = this.inputEl().getValue();
43761 getValue : function()
43763 return this.fixPrecision(this.parseValue(this.getRawValue()));
43766 parseValue : function(value)
43768 if(this.thousandsDelimiter) {
43770 r = new RegExp(",", "g");
43771 value = value.replace(r, "");
43774 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
43775 return isNaN(value) ? '' : value;
43779 fixPrecision : function(value)
43781 if(this.thousandsDelimiter) {
43783 r = new RegExp(",", "g");
43784 value = value.replace(r, "");
43787 var nan = isNaN(value);
43789 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
43790 return nan ? '' : value;
43792 return parseFloat(value).toFixed(this.decimalPrecision);
43795 decimalPrecisionFcn : function(v)
43797 return Math.floor(v);
43800 validateValue : function(value)
43802 if(!Roo.bootstrap.MoneyField.superclass.validateValue.call(this, value)){
43806 var num = this.parseValue(value);
43809 this.markInvalid(String.format(this.nanText, value));
43813 if(num < this.minValue){
43814 this.markInvalid(String.format(this.minText, this.minValue));
43818 if(num > this.maxValue){
43819 this.markInvalid(String.format(this.maxText, this.maxValue));
43826 validate : function()
43828 if(this.disabled || this.allowBlank){
43833 var currency = this.getCurrency();
43835 if(this.validateValue(this.getRawValue()) && currency.length){
43840 this.markInvalid();
43844 getName: function()
43849 beforeBlur : function()
43855 var v = this.parseValue(this.getRawValue());
43862 onBlur : function()
43866 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
43867 //this.el.removeClass(this.focusClass);
43870 this.hasFocus = false;
43872 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
43876 var v = this.getValue();
43878 if(String(v) !== String(this.startValue)){
43879 this.fireEvent('change', this, v, this.startValue);
43882 this.fireEvent("blur", this);
43885 inputEl : function()
43887 return this.el.select('.roo-money-amount-input', true).first();
43890 currencyEl : function()
43892 return this.el.select('.roo-money-currency-input', true).first();
43895 hiddenEl : function()
43897 return this.el.select('input.hidden-number-input',true).first();
43901 * @class Roo.bootstrap.BezierSignature
43902 * @extends Roo.bootstrap.Component
43903 * Bootstrap BezierSignature class
43904 * This script refer to:
43905 * Title: Signature Pad
43907 * Availability: https://github.com/szimek/signature_pad
43910 * Create a new BezierSignature
43911 * @param {Object} config The config object
43914 Roo.bootstrap.BezierSignature = function(config){
43915 Roo.bootstrap.BezierSignature.superclass.constructor.call(this, config);
43921 Roo.extend(Roo.bootstrap.BezierSignature, Roo.bootstrap.Component,
43928 mouse_btn_down: true,
43931 * @cfg {int} canvas height
43933 canvas_height: '200px',
43936 * @cfg {float|function} Radius of a single dot.
43941 * @cfg {float} Minimum width of a line. Defaults to 0.5.
43946 * @cfg {float} Maximum width of a line. Defaults to 2.5.
43951 * @cfg {integer} Draw the next point at most once per every x milliseconds. Set it to 0 to turn off throttling. Defaults to 16.
43956 * @cfg {integer} Add the next point only if the previous one is farther than x pixels. Defaults to 5.
43961 * @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.
43963 bg_color: 'rgba(0, 0, 0, 0)',
43966 * @cfg {string} Color used to draw the lines. Can be any color format accepted by context.fillStyle. Defaults to "black".
43968 dot_color: 'black',
43971 * @cfg {float} Weight used to modify new velocity based on the previous velocity. Defaults to 0.7.
43973 velocity_filter_weight: 0.7,
43976 * @cfg {function} Callback when stroke begin.
43981 * @cfg {function} Callback when stroke end.
43985 getAutoCreate : function()
43987 var cls = 'roo-signature column';
43990 cls += ' ' + this.cls;
44000 for(var i = 0; i < col_sizes.length; i++) {
44001 if(this[col_sizes[i]]) {
44002 cls += " col-"+col_sizes[i]+"-"+this[col_sizes[i]];
44012 cls: 'roo-signature-body',
44016 cls: 'roo-signature-body-canvas',
44017 height: this.canvas_height,
44018 width: this.canvas_width
44025 style: 'display: none'
44033 initEvents: function()
44035 Roo.bootstrap.BezierSignature.superclass.initEvents.call(this);
44037 var canvas = this.canvasEl();
44039 // mouse && touch event swapping...
44040 canvas.dom.style.touchAction = 'none';
44041 canvas.dom.style.msTouchAction = 'none';
44043 this.mouse_btn_down = false;
44044 canvas.on('mousedown', this._handleMouseDown, this);
44045 canvas.on('mousemove', this._handleMouseMove, this);
44046 Roo.select('html').first().on('mouseup', this._handleMouseUp, this);
44048 if (window.PointerEvent) {
44049 canvas.on('pointerdown', this._handleMouseDown, this);
44050 canvas.on('pointermove', this._handleMouseMove, this);
44051 Roo.select('html').first().on('pointerup', this._handleMouseUp, this);
44054 if ('ontouchstart' in window) {
44055 canvas.on('touchstart', this._handleTouchStart, this);
44056 canvas.on('touchmove', this._handleTouchMove, this);
44057 canvas.on('touchend', this._handleTouchEnd, this);
44060 Roo.EventManager.onWindowResize(this.resize, this, true);
44062 // file input event
44063 this.fileEl().on('change', this.uploadImage, this);
44070 resize: function(){
44072 var canvas = this.canvasEl().dom;
44073 var ctx = this.canvasElCtx();
44074 var img_data = false;
44076 if(canvas.width > 0) {
44077 var img_data = ctx.getImageData(0, 0, canvas.width, canvas.height);
44079 // setting canvas width will clean img data
44082 var style = window.getComputedStyle ?
44083 getComputedStyle(this.el.dom, null) : this.el.dom.currentStyle;
44085 var padding_left = parseInt(style.paddingLeft) || 0;
44086 var padding_right = parseInt(style.paddingRight) || 0;
44088 canvas.width = this.el.dom.clientWidth - padding_left - padding_right;
44091 ctx.putImageData(img_data, 0, 0);
44095 _handleMouseDown: function(e)
44097 if (e.browserEvent.which === 1) {
44098 this.mouse_btn_down = true;
44099 this.strokeBegin(e);
44103 _handleMouseMove: function (e)
44105 if (this.mouse_btn_down) {
44106 this.strokeMoveUpdate(e);
44110 _handleMouseUp: function (e)
44112 if (e.browserEvent.which === 1 && this.mouse_btn_down) {
44113 this.mouse_btn_down = false;
44118 _handleTouchStart: function (e) {
44120 e.preventDefault();
44121 if (e.browserEvent.targetTouches.length === 1) {
44122 // var touch = e.browserEvent.changedTouches[0];
44123 // this.strokeBegin(touch);
44125 this.strokeBegin(e); // assume e catching the correct xy...
44129 _handleTouchMove: function (e) {
44130 e.preventDefault();
44131 // var touch = event.targetTouches[0];
44132 // _this._strokeMoveUpdate(touch);
44133 this.strokeMoveUpdate(e);
44136 _handleTouchEnd: function (e) {
44137 var wasCanvasTouched = e.target === this.canvasEl().dom;
44138 if (wasCanvasTouched) {
44139 e.preventDefault();
44140 // var touch = event.changedTouches[0];
44141 // _this._strokeEnd(touch);
44146 reset: function () {
44147 this._lastPoints = [];
44148 this._lastVelocity = 0;
44149 this._lastWidth = (this.min_width + this.max_width) / 2;
44150 this.canvasElCtx().fillStyle = this.dot_color;
44153 strokeMoveUpdate: function(e)
44155 this.strokeUpdate(e);
44157 if (this.throttle) {
44158 this.throttleStroke(this.strokeUpdate, this.throttle);
44161 this.strokeUpdate(e);
44165 strokeBegin: function(e)
44167 var newPointGroup = {
44168 color: this.dot_color,
44172 if (typeof this.onBegin === 'function') {
44176 this.curve_data.push(newPointGroup);
44178 this.strokeUpdate(e);
44181 strokeUpdate: function(e)
44183 var rect = this.canvasEl().dom.getBoundingClientRect();
44184 var point = new this.Point(e.xy[0] - rect.left, e.xy[1] - rect.top, new Date().getTime());
44185 var lastPointGroup = this.curve_data[this.curve_data.length - 1];
44186 var lastPoints = lastPointGroup.points;
44187 var lastPoint = lastPoints.length > 0 && lastPoints[lastPoints.length - 1];
44188 var isLastPointTooClose = lastPoint
44189 ? point.distanceTo(lastPoint) <= this.min_distance
44191 var color = lastPointGroup.color;
44192 if (!lastPoint || !(lastPoint && isLastPointTooClose)) {
44193 var curve = this.addPoint(point);
44195 this.drawDot({color: color, point: point});
44198 this.drawCurve({color: color, curve: curve});
44208 strokeEnd: function(e)
44210 this.strokeUpdate(e);
44211 if (typeof this.onEnd === 'function') {
44216 addPoint: function (point) {
44217 var _lastPoints = this._lastPoints;
44218 _lastPoints.push(point);
44219 if (_lastPoints.length > 2) {
44220 if (_lastPoints.length === 3) {
44221 _lastPoints.unshift(_lastPoints[0]);
44223 var widths = this.calculateCurveWidths(_lastPoints[1], _lastPoints[2]);
44224 var curve = this.Bezier.fromPoints(_lastPoints, widths, this);
44225 _lastPoints.shift();
44231 calculateCurveWidths: function (startPoint, endPoint) {
44232 var velocity = this.velocity_filter_weight * endPoint.velocityFrom(startPoint) +
44233 (1 - this.velocity_filter_weight) * this._lastVelocity;
44235 var newWidth = Math.max(this.max_width / (velocity + 1), this.min_width);
44238 start: this._lastWidth
44241 this._lastVelocity = velocity;
44242 this._lastWidth = newWidth;
44246 drawDot: function (_a) {
44247 var color = _a.color, point = _a.point;
44248 var ctx = this.canvasElCtx();
44249 var width = typeof this.dot_size === 'function' ? this.dot_size() : this.dot_size;
44251 this.drawCurveSegment(point.x, point.y, width);
44253 ctx.fillStyle = color;
44257 drawCurve: function (_a) {
44258 var color = _a.color, curve = _a.curve;
44259 var ctx = this.canvasElCtx();
44260 var widthDelta = curve.endWidth - curve.startWidth;
44261 var drawSteps = Math.floor(curve.length()) * 2;
44263 ctx.fillStyle = color;
44264 for (var i = 0; i < drawSteps; i += 1) {
44265 var t = i / drawSteps;
44271 var x = uuu * curve.startPoint.x;
44272 x += 3 * uu * t * curve.control1.x;
44273 x += 3 * u * tt * curve.control2.x;
44274 x += ttt * curve.endPoint.x;
44275 var y = uuu * curve.startPoint.y;
44276 y += 3 * uu * t * curve.control1.y;
44277 y += 3 * u * tt * curve.control2.y;
44278 y += ttt * curve.endPoint.y;
44279 var width = curve.startWidth + ttt * widthDelta;
44280 this.drawCurveSegment(x, y, width);
44286 drawCurveSegment: function (x, y, width) {
44287 var ctx = this.canvasElCtx();
44289 ctx.arc(x, y, width, 0, 2 * Math.PI, false);
44290 this.is_empty = false;
44295 var ctx = this.canvasElCtx();
44296 var canvas = this.canvasEl().dom;
44297 ctx.fillStyle = this.bg_color;
44298 ctx.clearRect(0, 0, canvas.width, canvas.height);
44299 ctx.fillRect(0, 0, canvas.width, canvas.height);
44300 this.curve_data = [];
44302 this.is_empty = true;
44307 return this.el.select('input',true).first();
44310 canvasEl: function()
44312 return this.el.select('canvas',true).first();
44315 canvasElCtx: function()
44317 return this.el.select('canvas',true).first().dom.getContext('2d');
44320 getImage: function(type)
44322 if(this.is_empty) {
44327 return this.canvasEl().dom.toDataURL('image/'+type, 1);
44330 drawFromImage: function(img_src)
44332 var img = new Image();
44334 img.onload = function(){
44335 this.canvasElCtx().drawImage(img, 0, 0);
44340 this.is_empty = false;
44343 selectImage: function()
44345 this.fileEl().dom.click();
44348 uploadImage: function(e)
44350 var reader = new FileReader();
44352 reader.onload = function(e){
44353 var img = new Image();
44354 img.onload = function(){
44356 this.canvasElCtx().drawImage(img, 0, 0);
44358 img.src = e.target.result;
44361 reader.readAsDataURL(e.target.files[0]);
44364 // Bezier Point Constructor
44365 Point: (function () {
44366 function Point(x, y, time) {
44369 this.time = time || Date.now();
44371 Point.prototype.distanceTo = function (start) {
44372 return Math.sqrt(Math.pow(this.x - start.x, 2) + Math.pow(this.y - start.y, 2));
44374 Point.prototype.equals = function (other) {
44375 return this.x === other.x && this.y === other.y && this.time === other.time;
44377 Point.prototype.velocityFrom = function (start) {
44378 return this.time !== start.time
44379 ? this.distanceTo(start) / (this.time - start.time)
44386 // Bezier Constructor
44387 Bezier: (function () {
44388 function Bezier(startPoint, control2, control1, endPoint, startWidth, endWidth) {
44389 this.startPoint = startPoint;
44390 this.control2 = control2;
44391 this.control1 = control1;
44392 this.endPoint = endPoint;
44393 this.startWidth = startWidth;
44394 this.endWidth = endWidth;
44396 Bezier.fromPoints = function (points, widths, scope) {
44397 var c2 = this.calculateControlPoints(points[0], points[1], points[2], scope).c2;
44398 var c3 = this.calculateControlPoints(points[1], points[2], points[3], scope).c1;
44399 return new Bezier(points[1], c2, c3, points[2], widths.start, widths.end);
44401 Bezier.calculateControlPoints = function (s1, s2, s3, scope) {
44402 var dx1 = s1.x - s2.x;
44403 var dy1 = s1.y - s2.y;
44404 var dx2 = s2.x - s3.x;
44405 var dy2 = s2.y - s3.y;
44406 var m1 = { x: (s1.x + s2.x) / 2.0, y: (s1.y + s2.y) / 2.0 };
44407 var m2 = { x: (s2.x + s3.x) / 2.0, y: (s2.y + s3.y) / 2.0 };
44408 var l1 = Math.sqrt(dx1 * dx1 + dy1 * dy1);
44409 var l2 = Math.sqrt(dx2 * dx2 + dy2 * dy2);
44410 var dxm = m1.x - m2.x;
44411 var dym = m1.y - m2.y;
44412 var k = l2 / (l1 + l2);
44413 var cm = { x: m2.x + dxm * k, y: m2.y + dym * k };
44414 var tx = s2.x - cm.x;
44415 var ty = s2.y - cm.y;
44417 c1: new scope.Point(m1.x + tx, m1.y + ty),
44418 c2: new scope.Point(m2.x + tx, m2.y + ty)
44421 Bezier.prototype.length = function () {
44426 for (var i = 0; i <= steps; i += 1) {
44428 var cx = this.point(t, this.startPoint.x, this.control1.x, this.control2.x, this.endPoint.x);
44429 var cy = this.point(t, this.startPoint.y, this.control1.y, this.control2.y, this.endPoint.y);
44431 var xdiff = cx - px;
44432 var ydiff = cy - py;
44433 length += Math.sqrt(xdiff * xdiff + ydiff * ydiff);
44440 Bezier.prototype.point = function (t, start, c1, c2, end) {
44441 return (start * (1.0 - t) * (1.0 - t) * (1.0 - t))
44442 + (3.0 * c1 * (1.0 - t) * (1.0 - t) * t)
44443 + (3.0 * c2 * (1.0 - t) * t * t)
44444 + (end * t * t * t);
44449 throttleStroke: function(fn, wait) {
44450 if (wait === void 0) { wait = 250; }
44452 var timeout = null;
44456 var later = function () {
44457 previous = Date.now();
44459 result = fn.apply(storedContext, storedArgs);
44461 storedContext = null;
44465 return function wrapper() {
44467 for (var _i = 0; _i < arguments.length; _i++) {
44468 args[_i] = arguments[_i];
44470 var now = Date.now();
44471 var remaining = wait - (now - previous);
44472 storedContext = this;
44474 if (remaining <= 0 || remaining > wait) {
44476 clearTimeout(timeout);
44480 result = fn.apply(storedContext, storedArgs);
44482 storedContext = null;
44486 else if (!timeout) {
44487 timeout = window.setTimeout(later, remaining);